使用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才行,还有好多过滤器.

上一篇 下一篇

猜你喜欢

热点阅读