Ansible:列表的漂亮打印元素
Ansible: pretty-print elements of a list
我想漂亮地打印上一个任务已注册的结果列表中的每一项。我天真的方法是这样的:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{item}}"
with_items: [1, 2, 3]
register: result
- debug:
msg: "=== {{ item.cmd|join(' ') }} ===\n{{ item.stdout|indent(first=true) }}"
with_items: "{{ result.results }}"
我在 ansible.cfg
中使用 stdout_callback = debug
以使输出更易于阅读。
以上作品几乎。输出看起来符合预期,但不幸的是 debug
模块除了记录我的 msg
表达式外还记录了完整的循环项,这使输出变得相当混乱:
TASK [debug] ************************************************************************************************************************************************************
ok: [localhost] => (item={'cmd': ['echo', 'number', '1'], 'stdout': 'number 1', 'stderr': '', 'rc': 0, 'start': '2021-12-20 13:36:29.488443', 'end': '2021-12-20 13:36:29.490032', 'delta': '0:00:00.001589', 'changed': True, 'invocation': {'module_args': {'_raw_params': 'echo number 1', 'warn': True, '_uses_shell': False, 'stdin_add_newline': True, 'strip_empty_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates': None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['number 1'], 'stderr_lines': [], 'failed': False, 'item': 1, 'ansible_loop_var': 'item'}) => {}
MSG:
=== echo number 1 ===
number 1
设置 no_log: true
会抑制所有输出,因此没有帮助。有没有办法只打印 msg
?
我已经尝试了很多,但唯一接近我的想法的解决方案是取消 debug
任务中的循环并使用自定义过滤器插件打印项目。
- debug:
msg: "{{ result.results | map('format_result', '=== {} ===\n{}') | join('\n\n') }}"
其中 filter_plugins/format_result.py
看起来像这样:
def format_result(res, pattern):
return (pattern.format(" ".join(res['cmd']), res['stdout']))
class FilterModule(object):
def filters(self):
return {
'format_result': format_result,
}
过滤器插件方法可以满足我的要求,但我问自己是否没有更简单的解决方案。
2021-12-21 更新:
感谢@Zeitounator 在下面的评论,我想到了这个:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{item}}"
with_items: [1, 2, 3]
register: result
loop_control:
label: "\nThe item is: {{ result.stdout|indent(first=true) }}\n"
我还没有想出如何在不使用 register
的情况下访问循环内的循环结果。
2022-02-03 更新:
试着总结一下我学到的东西(感谢大家并原谅我的无知,正如你所看到的,我几乎是一个 ansible noob):
- 我的第一种方法的错误是忽略了 ansible 为每个简单任务打印结果行,以及为带有循环的任务的每次迭代打印结果行。
- 具有循环的
debug
任务将为每次迭代打印结果行,然后是实际消息。
- 我想抑制的冗长输出只是这个结果行,而不是调试模块本身的输出。
- 由于上述原因,
debug
具有循环的任务通常不会为了漂亮的打印输出而削减它。
- 因此必须将循环移动到模板中,就像在 β.εηοιτ.βε 的解决方案中,或者在我最初的“自定义过滤器”方法中一样。
您实际上可以像在 debug
任务的模板中一样使用 Jinja 渲染,。
鉴于剧本:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{ item }}"
with_items: [1, 2, 3]
register: result
- debug:
msg: >-
{% for _result in result.results %}
=== {{ _result.invocation.module_args._raw_params }} ===
{{ _result.stdout }}
{% endfor %}
这会给你预期的结果:
ok: [localhost] => {}
MSG:
=== echo number 1 ===
number 1
=== echo number 2 ===
number 2
=== echo number 3 ===
number 3
我想漂亮地打印上一个任务已注册的结果列表中的每一项。我天真的方法是这样的:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{item}}"
with_items: [1, 2, 3]
register: result
- debug:
msg: "=== {{ item.cmd|join(' ') }} ===\n{{ item.stdout|indent(first=true) }}"
with_items: "{{ result.results }}"
我在 ansible.cfg
中使用 stdout_callback = debug
以使输出更易于阅读。
以上作品几乎。输出看起来符合预期,但不幸的是 debug
模块除了记录我的 msg
表达式外还记录了完整的循环项,这使输出变得相当混乱:
TASK [debug] ************************************************************************************************************************************************************
ok: [localhost] => (item={'cmd': ['echo', 'number', '1'], 'stdout': 'number 1', 'stderr': '', 'rc': 0, 'start': '2021-12-20 13:36:29.488443', 'end': '2021-12-20 13:36:29.490032', 'delta': '0:00:00.001589', 'changed': True, 'invocation': {'module_args': {'_raw_params': 'echo number 1', 'warn': True, '_uses_shell': False, 'stdin_add_newline': True, 'strip_empty_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates': None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['number 1'], 'stderr_lines': [], 'failed': False, 'item': 1, 'ansible_loop_var': 'item'}) => {}
MSG:
=== echo number 1 ===
number 1
设置 no_log: true
会抑制所有输出,因此没有帮助。有没有办法只打印 msg
?
我已经尝试了很多,但唯一接近我的想法的解决方案是取消 debug
任务中的循环并使用自定义过滤器插件打印项目。
- debug:
msg: "{{ result.results | map('format_result', '=== {} ===\n{}') | join('\n\n') }}"
其中 filter_plugins/format_result.py
看起来像这样:
def format_result(res, pattern):
return (pattern.format(" ".join(res['cmd']), res['stdout']))
class FilterModule(object):
def filters(self):
return {
'format_result': format_result,
}
过滤器插件方法可以满足我的要求,但我问自己是否没有更简单的解决方案。
2021-12-21 更新:
感谢@Zeitounator 在下面的评论,我想到了这个:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{item}}"
with_items: [1, 2, 3]
register: result
loop_control:
label: "\nThe item is: {{ result.stdout|indent(first=true) }}\n"
我还没有想出如何在不使用 register
的情况下访问循环内的循环结果。
2022-02-03 更新:
试着总结一下我学到的东西(感谢大家并原谅我的无知,正如你所看到的,我几乎是一个 ansible noob):
- 我的第一种方法的错误是忽略了 ansible 为每个简单任务打印结果行,以及为带有循环的任务的每次迭代打印结果行。
- 具有循环的
debug
任务将为每次迭代打印结果行,然后是实际消息。 - 我想抑制的冗长输出只是这个结果行,而不是调试模块本身的输出。
- 由于上述原因,
debug
具有循环的任务通常不会为了漂亮的打印输出而削减它。 - 因此必须将循环移动到模板中,就像在 β.εηοιτ.βε 的解决方案中,或者在我最初的“自定义过滤器”方法中一样。
您实际上可以像在 debug
任务的模板中一样使用 Jinja 渲染,
鉴于剧本:
- hosts: localhost
gather_facts: no
tasks:
- command: "echo number {{ item }}"
with_items: [1, 2, 3]
register: result
- debug:
msg: >-
{% for _result in result.results %}
=== {{ _result.invocation.module_args._raw_params }} ===
{{ _result.stdout }}
{% endfor %}
这会给你预期的结果:
ok: [localhost] => {}
MSG:
=== echo number 1 ===
number 1
=== echo number 2 ===
number 2
=== echo number 3 ===
number 3