使用json_query过滤输出内容
2021-03-26 本文已影响0人
super_pcm
我们都知道在使用ansible的shell模块执行命令或者运行脚本的时候是没有返回信息的,为了能够打印出执行的结果我们通常使用register来注册变量,然后使用debug模块来输出结果,如下:
---
- hosts: localhost
gather_facts: false
tasks:
- name: test shell
shell: "echo 112"
register: info
- debug: msg="{{ info }}"
上面playbook执行的结果如下所示:
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost]
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"changed": true,
"cmd": "echo 112",
"delta": "0:00:00.309961",
"end": "2021-03-26 18:04:47.401284",
"failed": false,
"rc": 0,
"start": "2021-03-26 18:04:47.091323",
"stderr": "",
"stderr_lines": [],
"stdout": "112",
"stdout_lines": [
"112"
]
}
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
为了简化输出,我们可以只输出stdout_lines部分,如下
---
...
- debug: msg="{{ info.stdout_lines }}"
上面的playbook只输出标准输出部分
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost]
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"112"
]
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这种场景下的输出问题不大,现在有个需求,我要执行很多的shell语句,通常我们会使用列表的方式书写playbook,如下:
---
- hosts: localhost
gather_facts: false
tasks:
- name: test shell
shell: "echo {{ item }}"
with_items:
- '123'
- '456'
- '789'
register: info
- debug: msg="{{ info.stdout_lines }}"
这时候我们希望获取stdout_lines部分的输出,看下能不能获取到:
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost] => (item=123)
changed: [localhost] => (item=456)
changed: [localhost] => (item=789)
TASK [debug] ********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to be in '/opt/everhomes-ansible/test.yml': line 13, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug: msg=\"{{ info.stdout_lines }}\"\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
发现报错了,提示字典对象里面没有stdout_lines这个key。我们改下playbook,看下输出所有的结果。
---
...
- debug: msg="{{ info }}"
输出结果很长
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost] => (item=123)
changed: [localhost] => (item=456)
changed: [localhost] => (item=789)
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo 123",
"delta": "0:00:00.285530",
"end": "2021-03-26 18:17:11.955852",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo 123",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "123",
"rc": 0,
"start": "2021-03-26 18:17:11.670322",
"stderr": "",
"stderr_lines": [],
"stdout": "123",
"stdout_lines": [
"123"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo 456",
"delta": "0:00:00.287871",
"end": "2021-03-26 18:17:12.403742",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo 456",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "456",
"rc": 0,
"start": "2021-03-26 18:17:12.115871",
"stderr": "",
"stderr_lines": [],
"stdout": "456",
"stdout_lines": [
"456"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo 789",
"delta": "0:00:00.287773",
"end": "2021-03-26 18:17:12.846252",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo 789",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "789",
"rc": 0,
"start": "2021-03-26 18:17:12.558479",
"stderr": "",
"stderr_lines": [],
"stdout": "789",
"stdout_lines": [
"789"
]
}
]
}
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到输出结果很长,其中我们想要的内容在 info.results 这个列表里面。如果要获取到第一个stdout_lines的值我们可以这样来:
---
...
- debug: msg="{{ info.results[0].stdout_lines }}"
可以得到我们想要的结果
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost] => (item=123)
changed: [localhost] => (item=456)
changed: [localhost] => (item=789)
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"123"
]
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
因为info.results是一个列表,也就是说我们可以使用 with_items的方式来循环输出所有我们想要的结果
---
...
- debug: msg="{{ item.stdout_lines }}"
with_items: "{{ info.results }}"
得到的输出结果
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost] => (item=123)
changed: [localhost] => (item=456)
changed: [localhost] => (item=789)
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-03-26 18:25:08.107230', u'stdout': u'123', u'item': u'123', u'changed': True, u'rc': 0, u'failed': False, u'cmd': u'echo 123', u'stderr': u'', u'delta': u'0:00:00.279638', u'invocation': {u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo 123', u'removes': None, u'argv': None, u'warn': True, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'123'], u'start': u'2021-03-26 18:25:07.827592'}) => {
"msg": [
"123"
]
}
ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-03-26 18:25:08.548255', u'stdout': u'456', u'item': u'456', u'changed': True, u'rc': 0, u'failed': False, u'cmd': u'echo 456', u'stderr': u'', u'delta': u'0:00:00.280673', u'invocation': {u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo 456', u'removes': None, u'argv': None, u'warn': True, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'456'], u'start': u'2021-03-26 18:25:08.267582'}) => {
"msg": [
"456"
]
}
ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-03-26 18:25:08.980572', u'stdout': u'789', u'item': u'789', u'changed': True, u'rc': 0, u'failed': False, u'cmd': u'echo 789', u'stderr': u'', u'delta': u'0:00:00.281573', u'invocation': {u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo 789', u'removes': None, u'argv': None, u'warn': True, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'789'], u'start': u'2021-03-26 18:25:08.698999'}) => {
"msg": [
"789"
]
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到我们除了得到我们想要的结果之外,还有很多我们不想看到的内容。比如,ansible会给我们加上每个item的内容。到这里,问题似乎无解了。除非修改ansible的配置,让它不显示item的内容,但是这样肯定会影响我们日常使用ansible。无解了。
不华丽的分割线
百度了好久,终于找到了json_query过滤器。通过json_query我们可以完成我们的目标。
---
...
- debug: msg="{{ info.results |json_query('[].stdout_lines []') }}"
终于得到我想要的结果了.
PLAY [localhost] ****************************************************************************************************************************************************************************
TASK [test shell] ***************************************************************************************************************************************************************************
changed: [localhost] => (item=123)
changed: [localhost] => (item=456)
changed: [localhost] => (item=789)
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"123",
"456",
"789"
]
}
PLAY RECAP **********************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
好了,问题解决了.找时间深入学习下ansible才行,还有好多过滤器.