如何在 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"
}