实施任务控制
1. 编写循环和条件任务
1.1 利用循环迭代任务
通过利用循环,我们无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。
Ansible支持使用loop关键字对一组项目迭代任务。可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。
1.1.1 简单循环
简单循环对一组项目迭代任务。loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。
请思考以下代码片段,它使用两次service模块来确保两个网络服务处于运行状态:
[root@master project]# vim site.yml
---
- hosts: httpd
tasks:
- name: Apache is running
service:
name: httpd
state: started
- name: Php is runing
service:
name: php-fpm
state: started
[root@master project]# ansible-playbook site.yml
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [httpd]
TASK [Apache is running] **************************************************************************************
ok: [httpd]
TASK [Php is runing] ******************************************************************************************
ok: [httpd]
PLAY RECAP ****************************************************************************************************
httpd : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这两个任务可以重新编写为使用一个简单循环,从而只需一个任务来确保两个服务都在运行:
[root@master project]# vim site.yml
---
- hosts: httpd
tasks:
- name: Service is running
service:
name: "{
{ item }}"
state: started
loop:
- httpd
- php-fpm
[root@master project]# ansible-playbook site.yml
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [httpd]
TASK [Apache is running] **************************************************************************************
ok: [httpd] => (item=httpd)
ok: [httpd] => (item=php-fpm)
PLAY RECAP ****************************************************************************************************
httpd : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以通过一个变量提供loop所使用的列表。在以下示例中,变量mail_services含有需要处于运行状态的服务的列表。
[root@master project]# vim site.yml
---
- hosts: httpd
vars:
start_service:
- httpd
- php-fpm
tasks:
- name: Service is running
service:
name: "{
{ item }}"
state: started
loop: "{
{ start_service }}"
[root@master project]# ansible-playbook site.yml
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [httpd]
TASK [Service is running] *************************************************************************************
ok: [httpd] => (item=httpd)
ok: [httpd] => (item=php-fpm)
PLAY RECAP ****************************************************************************************************
httpd : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.1.2 循环散列或字典列表
loop列表不需要是简单值列表。在以下示例中,列表中的每个项实际上是散列或字典。示例中的每个散列或字典具有两个键,即name和groups,当前item循环变量中每个键的值可以分别通过item.name和item.groups变量来检索。
[root@master project]# vim site.yml
---
- hosts: httpd
tasks:
- name: Create groups
group:
name: "{
{ item }}"
state: present
system: yes
loop:
- jerry
- tom
- name: Users exist and are in the correct groups
user:
name: "{
{ item.name }}"
state: present
system: yes
groups: "{
{ item.groups }}"
loop:
- name: alice
groups: jerry #组jerry必须事先存在,否则会报错
- name: natasha
groups: tom #组tom必须事先存在,否则会报错
[root@master project]# ansible-playbook site.yml
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [httpd]
TASK [Create groups] ******************************************************************************************
changed: [httpd] => (item=jerry)
changed: [httpd] => (item=tom)
TASK [Users exist and are in the correct groups] **************************************************************
changed: [httpd] => (item={
'name': 'alice', 'groups': 'jerry'})
changed: [httpd] => (item={
'name': 'natasha', 'groups': 'tom'})
PLAY RECAP ****************************************************************************************************
httpd : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这一示例中结果是用户alice存在且为组jerry的成员,并且用户joe存在且为组tom的成员
1.1.3 较早样式的循环关键字
在Ansible2.5之前,大多数playbook使用不同的循环语法。提供了多个循环关键字,前缀为whth_,后面跟Ansible查找插件的名称。这种循环语法在现有playbook中很常见,但在将来的某个时候可能会被弃用。
较早样式的Ansible循环
循环关键字 | 描述 |
---|---|
with_items | 行为与简单列表的loop关键字相同,例如字符串列表或散列/字典列表。 但与loop不同的是,如果为with_items提供了列表的列表,它们将被扁平化为单级列表。循环变量item保存每次迭代过程中使用的列表项。 |
with_file | 此关键字需要控制节点文件名列表。循环变量item在每次迭代过程中保存文件列表中相应文件的内容。 |
with_sequence | 此关键字不需要列表,而是需要参数来根据数字序列生成值列表。 循环变量item在每次迭代过程中保存生成的序列中的一个生成项的值。 |
playbook中的with_items的示例如下所示:
[root@master project]# vim site1.yml
---
- hosts: httpd
tasks:
vars:
data:
- user1
- user2
- user3
tasks:
- name: "with_items "
debug:
msg: "{
{ item }} "
with_items: "{
{ data }}"
[root@master project]# ansible-playbook site1.yml
[WARNING]: While constructing a mapping from /opt/site1.yml, line 2, column 5, found a duplicate dict key
(tasks). Using last defined value only.
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [httpd]
TASK [with_items] *********************************************************************************************
ok: [httpd] => (item=user1) => {
"msg": "user1 "
}
ok: [httpd] => (item=user2) => {
"msg": "user2 "
}
ok: [httpd] => (item=user3) => {
"msg": "user3 "
}
PLAY RECAP ****************************************************************************************************
httpd : ok=2 changed=0 unreachable=0