限制 shell 命令结果列表的 ansible 输出

问题描述 投票:0回答:2

团队

如何避免这种巨大的输出并从结果列表中的每个项目中获取我想要的值?

我只想显示主机名的项目值,并且仅显示每个主机的标准输出行。

      - name: "Mount count on GPU Nodes"
        shell: "mount | grep -Ec '/dev/sd.*\\<csi' | awk '{ print $0,\"mounts found on $HOSTNAME\"($0>64? \" that are more than 64.\" : \".\") }'"
        register: mounts_count
        changed_when: false
        failed_when:
        delegate_to: "{{ item }}"
        with_items: "{{ groups['kube-gpu-node'] }}"

      - name: Check if csi related mounts are present on gpu nodes
        assert:
          that:
            - item.stdout is search('64')
          fail_msg: " mounts are present on this node"
          success_msg: "mounts are not present on this node"
        loop: "{{ mounts_count.results }}"
        loop_control:
          label: "{{ item.item }}"
        ignore_errors: yes

输出示例

   TASK [team-services-pre-install-checks : Check if csi related mounts are present on gpu nodes] ***
   Wednesday 18 December 2019  22:47:17 +0000 (0:00:07.012)       0:00:09.110 **** 
   failed: [localhost] (item=node1) => {
       "ansible_loop_var": "item", 
       "assertion": "item.stdout is search('0')", 
       "changed": false, 
       "evaluated_to": false, 
       "item": {
           "ansible_loop_var": "item", 
           "changed": false, 
           "cmd": "mount | grep -Ec '/dev/sd.*\\<csi' | awk '{ print $0,\"mounts found on hostname\"($0>64? \" that are more than 64.\" : \".\") }'", 
           "delta": "0:00:00.102618", 
           "end": "2019-12-18 22:47:12.566399", 
           "failed": false, 
           "invocation": {
               "module_args": {
                   "_raw_params": "mount | grep -Ec '/dev/sd.*\\<csi' | awk '{ print $0,\"mounts found on hostname\"($0>64? \" that are more than 64.\" : \".\") }'", 
                   "_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": "node1", 
           "rc": 0, 
           "start": "2019-12-18 22:47:12.463781", 
           "stderr": "", 
           "stderr_lines": [], 
           "stdout": "1 mounts found on hostname.", 
           "stdout_lines": [
               "1 mounts found on hostname."
           ]
       }, 
       "msg": " mounts are present on this node"
   }
ok: [localhost] => (item=node2) => {
       "ansible_loop_var": "item", 
       "changed": false, 
       "item": {
           "ansible_loop_var": "item", 
           "changed": false, 
           "cmd": "mount | grep -Ec '/dev/sd.*\\<csi' | awk '{ print $0,\"mounts found on hostname\"($0>64? \" that are more than 64.\" : \".\") }'", 
           "delta": "0:00:00.109244", 
           "end": "2019-12-18 22:47:14.303305", 
           "failed": false, 
           "invocation": {
               "module_args": {
                   "_raw_params": "mount | grep -Ec '/dev/sd.*\\<csi' | awk '{ print $0,\"mounts found on hostname\"($0>64? \" that are more than 64.\" : \".\") }'", 
                   "_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": "node2", 
           "rc": 0, 
           "start": "2019-12-18 22:47:14.194061", 
           "stderr": "", 
           "stderr_lines": [], 
           "stdout": "0 mounts found on hostname.", 
           "stdout_lines": [
               "0 mounts found on hostname."
           ]
       }, 
       "msg": "mounts are not present on this node"
   }

预期输出:下面只是我制作的手动示例,但任何显示主机名和 stdout_line 的东西都足够了。

"item": "node1"
0 mounts found on hostname.

"item": "node2"
0 mounts found on hostname.

ansible ansible-2.x ansible-inventory ansible-facts
2个回答
0
投票

Ansible 的设计初衷并不是为了在控制台上产生“漂亮”的输出。如果您希望以特定格式生成信息,最好从模板生成文件。

也就是说,

assert
模块主要被设计为调试工具并生成详细输出。我认为您可以使用
fail
模块获得您想要的行为:

      - name: Check if csi related mounts are present on gpu nodes
        fail:
          msg: " mounts are present on this node"
        when: item.stdout is not search('64')
        loop: "{{ mounts_count.results }}"
        loop_control:
          label: "{{ item.item }}"
        ignore_errors: yes

这将简单地“跳过”

when
条件为假的项目。


0
投票

聚会有点晚了,但还是有解决办法的。

虽然 @larsks 关于良好输出的声明默认情况下是正确的,但我们有多种方法可以改进它。

在循环中仅使用最少的数据

我们不需要循环处理整个字典 -

ansible.builtin.keep_keys()
过滤器允许我们只选择足够的数据部分:

    - name: Check if csi related mounts are present on gpu nodes
      assert:
        that:
          - item.stdout is search('64')
        fail_msg: " mounts are present on this node"
        success_msg: "mounts are not present on this node"
      loop: "{{ mounts_count.results | ansible.utils.keep_keys(['item', 'stdout']) }}"
      loop_control:
        label: "{{ item.item }}"
      ignore_errors: yes

这会产生:

TASK [Check if csi related mounts are present on gpu nodes (by the OP)] ***********************************************************************************************************************
failed: [localhost] (item=localhost) => {
    "ansible_loop_var": "item",
    "assertion": "item.stdout is not search('6')",
    "changed": false,
    "evaluated_to": false,
    "item": {
        "item": "localhost",
        "stdout": "7 mounts found on localhost that are more than 6."
    },
    "msg": " mounts are present on this node"
}
...ignoring

尽可能使用 Ansible 模块而不是 shell 脚本

没有断言的示例

无需使用 shell 脚本,因为 Ansible 收集事实,其中包括节点的安装情况,因此您可以处理它们以进行报告(确保您有

gather_facts: true
正在播放):

    - name: Check if csi related mounts are present on gpu nodes
      debug:
        msg: "{{ ansible_facts['ansible_mounts'] | length }} mounts found on {{ inventory_hostname }}"
      failed_when: ansible_facts['ansible_mounts'] | length != 64

这会产生:

TASK [List the number of mounts] **************************************************************************************************************************************************************
ok: [test1] => {
    "msg": "64 mounts found on test1"
}
fatal: [test2]: FAILED! => {
    "msg": "0 mounts found on test2"
}
fatal: [test3]: FAILED! => {
    "msg": "128 mounts found on test3"

请注意,这适用于 Linux 系统,不适用于 Mac OS。

带有断言的示例

此外,我们可以返回到

assert
模块,但它会比这更冗长一些:

    - name: Check if csi related mounts are present on gpu nodes (using assert module, quiet = false)
      vars:
        message: "{{ ansible_facts['ansible_mounts'] | length }} mounts are present on this node"
      assert:
        that:
          - ansible_facts['ansible_mounts'] | length != 64
        fail_msg: "{{ message }}"
        success_msg: "{{ message }}"

产生:

TASK [Check if csi related mounts are present on gpu nodes (using assert module, quiet = false)] **********************************************************************************************
fatal: [test1]: FAILED! => {
    "assertion": "ansible_facts['ansible_mounts'] | length != 64",
    "changed": false,
    "evaluated_to": false,
    "msg": "64 mounts are present on this node"
}
ok: [test2] => {
    "changed": false,
    "msg": "0 mounts are present on this node"
}
ok: [test3] => {
    "changed": false,
    "msg": "128 mounts are present on this node"
}

可以通过使用

quiet: true
来减少冗长:

    - name: Check if csi related mounts are present on gpu nodes (using assert module, quiet = true)
      vars:
        message: "{{ number_of_mounts }} mounts are present on this node"
      assert:
        that:
          - number_of_mounts | int != 64
        fail_msg: "{{ message }}"
        success_msg: "{{ message }}"
        quiet: true

仅针对失败条件生成输出,这在报告中很有用:

TASK [Check if csi related mounts are present on gpu nodes (using assert module, quiet = true)] ***********************************************************************************************
fatal: [test1]: FAILED! => {"assertion": "number_of_mounts | int != 64", "changed": false, "evaluated_to": false, "msg": "64 mounts are present on this node"}
ok: [test2]
ok: [test3]

使用回调插件设置控制 Ansible 日志输出

美化默认输出

甚至

default
回调也相当灵活。例如,您可以利用
callback_result_format
callback_format_pretty
参数来帮助您摆脱 JSON 带来的过多符号和/或修复缩进,使日志变得更具可读性。您可以找到最适合您的组合。考虑以下示例
ansible.cfg

[defaults]
callback_result_format = yaml
; callback_format_pretty is true by default when callback_result_format = yaml

无需对剧本进行任何修改,输出格式将得到改进:

TASK [Check if csi related mounts are present on gpu nodes (using debug module)] **************************************************************************************************************
ok: [test1] => 
    msg: 64 mounts found on test1
fatal: [test2]: FAILED! => 
    msg: 0 mounts found on test2
fatal: [test3]: FAILED! => 
    msg: 128 mounts found on test3

TASK [Check if csi related mounts are present on gpu nodes (using assert module, quiet = false)] **********************************************************************************************
ok: [test1] => 
    changed: false
    msg: 64 mounts are present on this node
fatal: [test2]: FAILED! => 
    assertion: ansible_facts['ansible_mounts'] | length == 64
    changed: false
    evaluated_to: false
    msg: 0 mounts are present on this node
fatal: [test3]: FAILED! => 
    assertion: ansible_facts['ansible_mounts'] | length == 64
    changed: false
    evaluated_to: false
    msg: 128 mounts are present on this node

TASK [Check if csi related mounts are present on gpu nodes (using assert module, quiet = true)] ***********************************************************************************************
ok: [test1]
fatal: [test2]: FAILED! => 
    assertion: ansible_facts['ansible_mounts'] | length == 64
    changed: false
    evaluated_to: false
    msg: 0 mounts are present on this node
fatal: [test3]: FAILED! => 
    assertion: ansible_facts['ansible_mounts'] | length == 64
    changed: false
    evaluated_to: false
    msg: 128 mounts are present on this node

使用自定义统计数据

最后,Ansible 提供了

show_custom_stats
回调参数来在比赛回顾中使用自定义统计数据。它们可以通过
set_stats
模块设置:

; ansible.cfg
callback_result_format = yaml
callback_format_pretty = true
show_custom_stats = true
# playbook.yaml
- name: Get the mount details using Ansible facts
  hosts: kube_gpu_node
  gather_facts: true
  tasks:
    - name: Set stats for mounts
      set_stats:
        data:
          number_of_mounts: "{{ ansible_facts['ansible_mounts'] | length }}"
        per_host: true
    
    - name: Check if csi related mounts are present on gpu nodes (using debug module)
      debug:
        msg: "{{ ansible_facts['ansible_mounts'] | length }} mounts found on {{ inventory_hostname }}"
      failed_when: ansible_facts['ansible_mounts'] | length != 64

请注意:

  • kube-gpu-node
    不是有效的组名称,应使用下划线而不是连字符
  • failed_when
    不应与
    set_stats
    一起使用,因为即使使用
    ignore_errors: true
    ,它也会在出现第一个错误时停止,并且不会为其他主机设置统计信息。因此,要进行正确的游戏回顾,您需要
    debug
    failed_when´ condition, or an 
    assert`。

输出将是这样的:

PLAY [Get the mount details using Ansible facts] **********************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************************************
ok: [test3]
ok: [test2]
ok: [test1]

TASK [Set stats for mounts] *******************************************************************************************************************************************************************************
ok: [test1]
ok: [test2]
ok: [test3]

TASK [Check if csi related mounts are present on gpu nodes (using assert module, quiet = false)] **********************************************************************************************************
ok: [test1] => 
    changed: false
    msg: 64 mounts are present on this node
fatal: [test2]: FAILED! => 
    assertion: number_of_mounts | int == 64
    changed: false
    evaluated_to: false
    msg: 0 mounts are present on this node
fatal: [test3]: FAILED! => 
    assertion: number_of_mounts | int == 64
    changed: false
    evaluated_to: false
    msg: 128 mounts are present on this node

PLAY RECAP ************************************************************************************************************************************************************************************************
test1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test2                      : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
test3                      : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   


CUSTOM STATS: *********************************************************************************************************************************************************************************************
        test1:  number_of_mounts: 64
        test2:  number_of_mounts: 0
        test3:  number_of_mounts: 128
© www.soinside.com 2019 - 2024. All rights reserved.