RHCE8.0讲义:编写循环和条件任务
利用循环迭代任务
通过利用循环,管理员无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。
Ansible支持使用loop关键字对一组项目迭代任务。您可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。本节介绍迭代项目列表的简单循环。有关更高级的循环方案,请参阅文档。
简单循环
简单循环对一组项目迭代任务。loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。
请思考以下代码片段,它使用两次service模块来确保两个网络服务处于运行状态:
- name: Postfix is running service: name: postfix state: started - name: Dovecot is running service: name: dovecot state: started
这两个任务可以重新编写为使用一个简单循环,从而只需一个任务来确保两个服务都在运行:
- name: Postfix and Dovecot are running service: name: "{{ item })" state: started loop: - postfix - dovecot
可以通过一个变量提供丄oop所使用的列表。在以下示例中'变量mail_services含有需要处于 运行状态的服务的列表。
vars: mail_services: - postfix - dovecot tasks: - name: Postfix and Dovecot are running service: name: "{( item })" state: started loop: ”{{ mail_services }}*'
循环散列或字典列表
loop列表不需要是简单值列表。在以下示例中,列表中的每个项实际上是散列或字典。示例中的 每个散列或字典具有两个键,即name和groups,当前item循环变量中每个键的值可以分别通过 item. name 和 item. groups变量来检索。
- name: Users exist and are in the correct groups user: name: ”{{ item.name }}" state: present groups: "(( item.groups })" loop: - name: jane groups: wheel - name: joe groups: root
上一任务的结果是用户jane存在且为组wheel的成员,并且用户joe存在且为组root的成员。
较早样式的循环关键字
在Ansible 2.5之前,大多数playbook使用不同的循环语法。提供了多个循环关键字,前缀为 with_ ,后跟Ansible查找插件(一项高级功能,本课程中未加以详细介绍)的名称。这种循环语 法在现有playbook中很常见,但在将来的某个时候可能会被弃用。
下表列出了几个示例:
较早样式的Ansible循环
循环关键字 描述 with_items 行为与简单列表的loop关键字相同,例如字符串列表或散列/字典 列表。但与loop不同的是,如果为with_items提供了列表的列 表,它们将被扁平化为单级列表。循环变量item保存每次迭代过 程中使用的列表项。 with_file 此关键字需要控制节点文件名列表。循环变量item在每次迭代过 程中保存文件列表中相应文件的内容。 with_sequence 此关键字不需要列表,而是需要参数来根据数字序列生成值列表。 循环变量item在每次迭代过程中保存生成的序列中的一个生成项 的值。
playbook中的with_items的示例如下所示:
vars: data: - user0 - user1 - user2 tasks: - name: "with_items" debug: msg: "{{ item }}" with_items: "(( data }}"
重要
从Ansible 2.5开始,建议使用loop关键字编写循环。
但是,您仍然应该了解旧语法,尤其是with_items,因为它广泛用于现有 playbooko您可能会遇到继续使用with_*关键字进行循环的playbook和角色。
使用旧语法的任何任务都可以转换为结合使用loop和Ansible过滤器。您不需要知道如何使用 Ansible过滤器来执行此操作。有关如何将旧循环转换为新语法,以及如何循环不是简单列表的 项的示例,Ansible 用户指南第从 with_X迁移至循环[https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#migrating-from-with-x-to-loop]节中的 Ansible 文档提供了 良好 的参善。
您可能会遇到包含with_*关键字的旧playbook中的任务。
高级循环技术不在本课程的讨论范围内。本课程中的所有迭代任务都可以使用withjtems或 loop关键字实施。
将Register变量与Loop —起使用
register关键字也可以捕获循环任务的输岀。以下代码片段显示了循环任务中register变量的结 构:
[student@workstation loopdemo]$ cat loop_register.yml
- name: Loop Register Test
gather_facts: no hosts: localhost tasks: - name: Looping Echo Task shell: "echo This is my item: {{ item })" loop: - one - two register: echo_results (1) - name: Show echo_results variable debug: var: echo_results (2)
(1) echo_results变量已注册。
(2)echo_results变量的内容显示在屏幕上。
运行上面的playbook会产生以下输出:
[student@workstation loopdemo]$ ansible-playbook loop_register.yml play
[Loop Register Test] **************************************** TASK [Looping Echo Task] ************************** ... output omitted TASK [Show echo_results variable] ***************** ok: [localhost] => { "echo_results": {。 "changed": true, "msg": "All items completed", "results" : [O "_ansible_ignore_errors": null, ... output omitted "changed": true, "cmd": "echo This is my item: one", "delta": "0:00:00.011865", "end": "2018-11-01 16:32:56.080433", "failed": false, ...output omitted "item": "one", "re": 0, "start": "2018-11-01 16:32:56.068568", "stderr": "stderr_lines": "stdout": "This "stdout_lines": "This is my ] }, {O "_ansible_ignore_errors": null, ... output omitted "changed": true, "cmd": "echo This is my item: two", "delta": "0:00:00.011142"z "end": "2018-11-01 16:32:56.828196", "failed": false, ... output omitted "item": "two", "rc": 0, "start": "2018-11-01 16:32:56.817054", "stderr" : ,,n, "stderr_lines": "stdout": "This "stdout_lines": "This is my ] } [], is my item: one", item: one 口, is my item: two", item: two" ]❺ } } ... output omitted
{字符表示echo_results变量的开头由键值对组成。
results譴包含上一个任务的结果。[字符表示列表的开头。
第一项的任务元数据的开头(由item键表示)。echo命令的输出可在stdout键中找至U。 第二项的任务结果元数据的幵头。
]字符表示results列表的结尾。
在上面,results键包含一个列表。在下面,修改了 playbook,使第二个任务迭代此列表:
[student@workstation loopdemo]$ cat new_loop_register.yml
- name: Loop Register Test gather_facts: no hosts: localhost tasks: - name: Looping Echo Task shell: "echo This is my item: {{ item })" loop: - one - two register: echo_results - name: Show stdout from the previous task. debug: msg: "STDOUT from previous task: {( item.stdout })" loop: "{{ echo_results['results'] }}"
执行上述playbook后,输出为:
PLAY [Loop Register Test] ***************** TASK [Looping Echo Task] ***************************************************** …output omitted TASK [Show stdout from the previous task.] ******************** ok: [localhost]=> "msg": "STDOUT (item={...output omitted...=> { from previous task: This is my item: one } ok: [localhost]=> "msg": "STDOUT (item={...output omitted...)) => { from previous task: This is my item: two" } ... output omitted