实施任务控制
一、编写循环和条件任务
1、利用循环迭代任务
通过利用循环,我们无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。
Ansible支持使用loop关键字对一组项目迭代任务。可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。
1、简单循环
[root@ansible project]# cat playbook/test.yml
---
- hosts: httpd
gather_facts: no
tasks:
- name: create user {{ item }}
user:
name: "{{ item }}"
state: present
loop:
- tom1
- tom2
- tom3
这样就可以让他们进行逐一的创建用户,执行一下这个playbook看看效果:
[root@ansible project]# ansible-playbook playbook/test.yml
PLAY [httpd] ******************************************************************************************************************
TASK [create user {{ item }}] **************************************************************************************************************************************
changed: [192.168.129.135] => (item=tom1)
changed: [192.168.129.135] => (item=tom2)
changed: [192.168.129.135] => (item=tom3)
PLAY RECAP *****************************************************************************************
192.168.129.135 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
我们也可以通过一个变量提供loop所使用的列表。在以下示例中,变量users含有需要创建的用户:
[root@ansible project]# cat playbook/test.yml
---
- hosts: httpd
gather_facts: no
vars:
users:
- tom1
- tom2
- tom3
tasks:
- name: create user {{ item }}
user:
name: "{{ item }}"
state: present
loop:
"{{ user }}"
效果:
[root@httpd ~]# id tom1
uid=1002(tom1) gid=1002(tom1) 组=1002(tom1)
[root@httpd ~]# id tom2
uid=1003(tom2) gid=1003(tom2) 组=1003(tom2)
[root@httpd ~]# id tom3
uid=1004(tom3) gid=1004(tom3) 组=1004(tom3)
删除刚创建的用户
[root@ansible project]# cat playbook/vars/yonghu.yml
user:
- tom1
- tom2
- tom3
[root@ansible project]# cat playbook/test.yml
---
- hosts: httpd
gather_facts: no
vars_files:
- vars/yonghu.yml
tasks:
- name: create user {{ item }}
user:
name: "{{ item }}"
state: absent
loop:
"{{ user }}"
执行看效果
[root@ansible project]# ansible-playbook playbook/test.yml
PLAY [httpd] ************************************************************************************************************
TASK [create user {{ item }}] *******************************************************************************************
changed: [192.168.129.135] => (item=tom1)
changed: [192.168.129.135] => (item=tom2)
changed: [192.168.129.135] => (item=tom3)
PLAY RECAP **************************************************************************************************************
192.168.129.135 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看用户是否删除
[root@httpd ~]# id tom3
id: “tom3”:无此用户
[root@httpd ~]# id tom2
id: “tom2”:无此用户
[root@httpd ~]# id tom1
id: “tom1”:无此用户
2、循环散列或字典列表
loop列表不需要是简单值列表。在以下示例中,列表中的每个项实际上是散列或字典。示例中的每个散列或字典具有两个键,即name和groups,当前item循环变量中每个键的值可以分别通过item.name和item.groups变量来检索。
[root@ansible project]# cat playbook/vars/yonghu.yml
user:
- tom1
- tom2
- tom3
[root@ansible project]# cat playbook/test.yml
---
- hosts: httpd
gather_facts: no
vars_files:
- vars/yonghu.yml
tasks:
- name: create user {{item.name}}
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
state: present
loop:
- name: tom1
uid: 2000
- name: tom2
uid: 2001
- name: tom3
uid: 2002
运行查看效果
[root@ansible project]# ansible-playbook playbook/test.yml
PLAY [httpd] ************************************************************************************************************
TASK [create user {{item.name}}] ****************************************************************************************
changed: [192.168.129.135] => (item={'name': 'tom1', 'uid': 2000})
changed: [192.168.129.135] => (item={'name': 'tom2', 'uid': 2001})
changed: [192.168.129.135] => (item={'name': 'tom3', 'uid': 2002})
PLAY RECAP **************************************************************************************************************
192.168.129.135 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@httpd ~]# id tom1
uid=2000(tom1) gid=2000(tom1) 组=2000(tom1)
[root@httpd ~]# id tom2
uid=2001(tom2) gid=2001(tom2) 组=2001(tom2)
[root@httpd ~]# id tom3
uid=2002(tom3) gid=2002(tom3) 组=2002(tom3)
我们也可以通过配置文件
[root@ansible project]# cat playbook/vars/yonghu.yml
user:
- name: tom1
uid: 2000
- name: tom2
uid: 2001
- name: tom3
uid: 2002
[root@ansible project]# cat playbook/test.yml
---
- hosts: httpd
gather_facts: no
vars_files:
- vars/yonghu.yml
tasks:
- name: create user {{item.name}}
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
state: absent
loop: "{{ user }}"
运行查看效果
[root@ansible project]# ansible-playbook playbook/test.yml
PLAY [httpd] ************************************************************************************************************
TASK [create user {{item.name}}] ****************************************************************************************
changed: [192.168.129.135] => (item={'name': 'tom1', 'uid': 2000})
changed: [192.168.129.135] => (item={'name': 'tom2', 'uid': 2001})
changed: [192.168.129.135] => (item={'name': 'tom3', 'uid': 2002})
PLAY RECAP **************************************************************************************************************
192.168.129.135 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3、将Register变量与Loop一起使用
register关键字也可以捕获循环任务的输出。以下代码片段显示了循环任务中register变量的结构:
首先编辑一个变量文件
[root@ansible project]# cat playbook/vars/yonghu.yml
user:
- name: lisi
uid: 2000
- name: liubai
uid: 2002
其次编写循环语句
[root@ansible project]# cat playbook/uu.yml
---
- hosts: httpd
tasks:
- name: Looping Echo Task
command: "echo hello {{ item }},nice to meet you."
loop:
- lisi
- liubai
register: echo_results # 注册echo_results变量
- name: Show echo_results variable
debug:
var: echo_results # echo_results变量的内容显示在屏幕上
[root@httpd ~]# id lisi
uid=2000(lisi) gid=2000(lisi) 组=2000(lisi)
[root@httpd ~]# id liubai
uid=2002(liubai) gid=2002(liubai) 组=2002(liubai)
之后运行
[root@ansible project]# ansible-playbook playbook/uu.yml
PLAY [httpd] ************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************
ok: [192.168.129.135]
TASK [Looping Echo Task] ************************************************************************************************
changed: [192.168.129.135] => (item=lisi)
changed: [192.168.129.135] => (item=liubai)
TASK [Show echo_results variable] ***************************************************************************************
ok: [192.168.129.135] => {
"echo_results": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"cmd": [
"echo",
"hello",
"lisi,nice",
"to",
"meet",
"you."
],
"delta": "0:00:00.003232",
"end": "2021-07-25 13:35:41.991754",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo hello lisi,nice to meet you.",
"_uses_shell": false,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "lisi",
"rc": 0,
"start": "2021-07-25 13:35:41.988522",
"stderr": "",
"stderr_lines": [],
"stdout": "hello lisi,nice to meet you.",
"stdout_lines": [
"hello lisi,nice to meet you."
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": [
"echo",
"hello",
"liubai,nice",
"to",
"meet",
"you."
],
"delta": "0:00:00.002077",
"end": "2021-07-25 13:35:42.359590",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo hello liubai,nice to meet you.",
"_uses_shell": false,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "liubai",
"rc": 0,
"start": "2021-07-25 13:35:42.357513",
"stderr": "",
"stderr_lines": [],
"stdout": "hello liubai,nice to meet you.",
"stdout_lines": [
"hello liubai,nice to meet you."
]
}
]
}
}
PLAY RECAP **************************************************************************************************************
192.168.129.135 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2、有条件第运行任务
Ansible可使用conditionals在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。
我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
以下场景说明了在Ansible中使用条件的情况:
- 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
- Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
- 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
- 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
- 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
1、条件任务语法
when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。
可以测试的一个最简单条件是某一布尔变量是True还是False。以下示例中的when语句导致任务仅在run_my_task为True时运行: