如何在 Ansible 中打破 `with_lines` 循环?
How to break `with_lines` cycle in Ansible?
我想在 Ansible 中使用以下处理程序:
- name: force ntp update
shell: ntpdate {{item}}
with_lines: /etc/ntpd.serverlist
但我希望它在第一次成功执行后结束执行(该列表包含您可以尝试与之同步的 ntpd 服务器。一个就足够了)。我该怎么做?
你的情况非常有趣。我没有亲自尝试过,但我想知道这样的事情是否可行:
- name: force ntp update
shell: ntpdate {{item}}
with_lines: /etc/ntpd.serverlist
register: ntp_result
when: ntp_result is not defined or ntp_result.rc != 0
ignore_errors: yes
所以简而言之,每次调用 ntpdate 都应该使用调用 ntpdate
的 return 代码填充 ntp_result
变量。如果变量不存在(因为在第一次迭代期间不会填充它),或者如果 ntpdate
调用失败(rc != 0),when
子句确保循环继续.告诉 Ansible 忽略任何错误确保它继续循环,如果对 ntpdate
的任何调用确实 return 一个错误。
唯一真正的缺点是,如果 none 对 ntpdate
的调用成功,它不会直接通知您。但是,您可能可以按照以下方式完成此任务:
- name: fail if ntpdate fails
fail: msg="All calls to ntpdate failed"
when: ntp_result.rc != 0
如果最后一次调用导致 ntpdate
的非零结果,则意味着 none 成功。
至少在 Ansible 2.2.1.0 上,一个 when
语句可以打破循环,以下工作在第一次成功后跳过所有评估:
---
# test.yml
# run this playbook with: ansible-playbook -i localhost, test.yml
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: check
shell: "[ {{item}} -ne 2 ]"
register: checks
ignore_errors: yes
changed_when: false
when: checks is not defined or checks.rc != 0
with_items: [2,3,2,4]
- name: set
set_fact: first_working={{ item.item }}
when: "'rc' in item and item.rc == 0"
with_items: "{{ checks.results }}"
- debug: var=first_working
# Note that first_working will be undefined if no check succeeded
这是输出:
PLAY [localhost] ***************************************************************
TASK [check] *******************************************************************
failed: [localhost] (item=2) => {"changed": false, "cmd": "[ 2 -ne 2 ]", "delta": "0:00:00.001735", "end": "2017-03-13 16:14:00.515372", "failed": true, "item": 2, "rc": 1, "start": "2017-03-13 16:14:00.513637", "stderr": "", "stdout": "", "stdout_lines": [], "warnings": []}
ok: [localhost] => (item=3)
skipping: [localhost] => (item=2)
skipping: [localhost] => (item=4)
...ignoring
TASK [set] *********************************************************************
skipping: [localhost] => (item={'_ansible_parsed': True, u'cmd': u'[ 2 -ne 2 ]', u'end': u'2017-03-13 16:14:00.515372', '_ansible_no_log': False, u'stdout': u'', '_ansible_item_result': True, u'changed': False, 'item': 2, u'delta': u'0:00:00.001735', u'stderr': u'', u'rc': 1, 'invocation': {'module_name': u'command', u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'_raw_params': u'[ 2 -ne 2 ]', u'removes': None, u'warn': True, u'chdir': None}}, 'stdout_lines': [], u'start': u'2017-03-13 16:14:00.513637', u'warnings': [], 'failed': True})
ok: [localhost] => (item={'_ansible_parsed': True, u'changed': False, u'stdout': u'', '_ansible_no_log': False, u'warnings': [], '_ansible_item_result': True, u'rc': 0, u'end': u'2017-03-13 16:14:00.615658', u'start': u'2017-03-13 16:14:00.613978', u'cmd': u'[ 3 -ne 2 ]', 'item': 3, u'delta': u'0:00:00.001680', 'invocation': {'module_name': u'command', u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'_raw_params': u'[ 3 -ne 2 ]', u'removes': None, u'warn': True, u'chdir': None}}, 'stdout_lines': [], u'stderr': u''})
skipping: [localhost] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': 2, 'changed': False})
skipping: [localhost] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': 4, 'changed': False})
TASK [debug] *******************************************************************
ok: [localhost] => {
"first_working": "3"
}
我想在 Ansible 中使用以下处理程序:
- name: force ntp update
shell: ntpdate {{item}}
with_lines: /etc/ntpd.serverlist
但我希望它在第一次成功执行后结束执行(该列表包含您可以尝试与之同步的 ntpd 服务器。一个就足够了)。我该怎么做?
你的情况非常有趣。我没有亲自尝试过,但我想知道这样的事情是否可行:
- name: force ntp update
shell: ntpdate {{item}}
with_lines: /etc/ntpd.serverlist
register: ntp_result
when: ntp_result is not defined or ntp_result.rc != 0
ignore_errors: yes
所以简而言之,每次调用 ntpdate 都应该使用调用 ntpdate
的 return 代码填充 ntp_result
变量。如果变量不存在(因为在第一次迭代期间不会填充它),或者如果 ntpdate
调用失败(rc != 0),when
子句确保循环继续.告诉 Ansible 忽略任何错误确保它继续循环,如果对 ntpdate
的任何调用确实 return 一个错误。
唯一真正的缺点是,如果 none 对 ntpdate
的调用成功,它不会直接通知您。但是,您可能可以按照以下方式完成此任务:
- name: fail if ntpdate fails
fail: msg="All calls to ntpdate failed"
when: ntp_result.rc != 0
如果最后一次调用导致 ntpdate
的非零结果,则意味着 none 成功。
至少在 Ansible 2.2.1.0 上,一个 when
语句可以打破循环,以下工作在第一次成功后跳过所有评估:
---
# test.yml
# run this playbook with: ansible-playbook -i localhost, test.yml
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: check
shell: "[ {{item}} -ne 2 ]"
register: checks
ignore_errors: yes
changed_when: false
when: checks is not defined or checks.rc != 0
with_items: [2,3,2,4]
- name: set
set_fact: first_working={{ item.item }}
when: "'rc' in item and item.rc == 0"
with_items: "{{ checks.results }}"
- debug: var=first_working
# Note that first_working will be undefined if no check succeeded
这是输出:
PLAY [localhost] ***************************************************************
TASK [check] *******************************************************************
failed: [localhost] (item=2) => {"changed": false, "cmd": "[ 2 -ne 2 ]", "delta": "0:00:00.001735", "end": "2017-03-13 16:14:00.515372", "failed": true, "item": 2, "rc": 1, "start": "2017-03-13 16:14:00.513637", "stderr": "", "stdout": "", "stdout_lines": [], "warnings": []}
ok: [localhost] => (item=3)
skipping: [localhost] => (item=2)
skipping: [localhost] => (item=4)
...ignoring
TASK [set] *********************************************************************
skipping: [localhost] => (item={'_ansible_parsed': True, u'cmd': u'[ 2 -ne 2 ]', u'end': u'2017-03-13 16:14:00.515372', '_ansible_no_log': False, u'stdout': u'', '_ansible_item_result': True, u'changed': False, 'item': 2, u'delta': u'0:00:00.001735', u'stderr': u'', u'rc': 1, 'invocation': {'module_name': u'command', u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'_raw_params': u'[ 2 -ne 2 ]', u'removes': None, u'warn': True, u'chdir': None}}, 'stdout_lines': [], u'start': u'2017-03-13 16:14:00.513637', u'warnings': [], 'failed': True})
ok: [localhost] => (item={'_ansible_parsed': True, u'changed': False, u'stdout': u'', '_ansible_no_log': False, u'warnings': [], '_ansible_item_result': True, u'rc': 0, u'end': u'2017-03-13 16:14:00.615658', u'start': u'2017-03-13 16:14:00.613978', u'cmd': u'[ 3 -ne 2 ]', 'item': 3, u'delta': u'0:00:00.001680', 'invocation': {'module_name': u'command', u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': True, u'_raw_params': u'[ 3 -ne 2 ]', u'removes': None, u'warn': True, u'chdir': None}}, 'stdout_lines': [], u'stderr': u''})
skipping: [localhost] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': 2, 'changed': False})
skipping: [localhost] => (item={'skipped': True, '_ansible_no_log': False, 'skip_reason': u'Conditional check failed', '_ansible_item_result': True, 'item': 4, 'changed': False})
TASK [debug] *******************************************************************
ok: [localhost] => {
"first_working": "3"
}