文章目录
1. 循环语句
1.1 简单循环
- 示例:现需要将受控机的postfix和crond两个服务开启,我们在主控机利用循环变量item和loop模块将两个任务合成一个任务
- 先把受控机的两个服务关闭
[root@localhost facts.d]# systemctl stop postfix
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.se>
Active: inactive (dead)
[root@localhost facts.d]# systemctl stop crond
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.serv>
Active: inactive (dead) since Sun 2020-09-06 21:48>
Process: 8157 ExecStart=/usr/sbin/crond -n $CRONDAR>
Main PID: 8157 (code=exited, status=0/SUCCESS)
Sep 06 21:36:23 localhost.localdomain systemd[1]: Sta>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:48:45 localhost.localdomain systemd[1]: Sto>
Sep 06 21:48:45 localhost.localdomain systemd[1]: Sto>
lines 1-13/13 (END)
- 在主控机中编写
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: kk
service:
name: "{{ item }}"
state: started
loop:
- postfix
- crond
- 检查语法是否错误并执行playbook
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml
playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [kk] **********************************************************************
changed: [192.168.50.136] => (item=postfix)
changed: [192.168.50.136] => (item=crond)
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 查看受控机的两个服务是否开启
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.serv>
Active: active (running) since Sun 2020-09-06 21:5>
Main PID: 8444 (crond)
......
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.se>
Active: active (running) since Sun 2020-09-06 21:3>
Process: 8013 ExecStart=/usr/sbin/postfix start (co
......
- 也可以把循环列表写到前面
- 查看受控机的两个服务状态(开启)
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.serv>
Active: active (running) since Sun 2020-09-06 21:5>
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.se>
Active: active (running) since Sun 2020-09-06 21:3>
- 编写myplay.yml
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
srvs:
- postfix 将这两个任务写在前面
- crond
tasks:
- name: kk
service:
name: "{{ item }}"
state: stopped
loop: "{{ srvs }}" srvs含有需要处于运行状态的服务的列表
- 查看受控机状态(关闭)
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.se>
Active: inactive (dead)
Sep 06 21:34:04 localhost.localdomain systemd[1]: Sta>
Sep 06 21:34:05 localhost.localdomain postfix/master[>
Sep 06 21:34:05 localhost.localdomain systemd[1]: Sta>
Sep 06 21:35:54 localhost.localdomain systemd[1]: Sto>
Sep 06 21:35:54 localhost.localdomain systemd[1]: Sto>
Sep 06 21:36:22 localhost.localdomain systemd[1]: Sta>
Sep 06 21:36:23 localhost.localdomain postfix/master[>
Sep 06 21:36:23 localhost.localdomain systemd[1]: Sta>
Sep 06 21:58:47 localhost.localdomain systemd[1]: Sto>
Sep 06 21:58:48 localhost.localdomain systemd[1]: Sto>
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.serv>
Active: inactive (dead) since Sun 2020-09-06 21:58>
Process: 8444 ExecStart=/usr/sbin/crond -n $CRONDAR>
Main PID: 8444 (code=exited, status=0/SUCCESS)
1.2 循环散列或字典列表
示例: 在受控机上创建两个用户wangqing,houyi。wangqing属于apache组,houyi属于root组
1.在主控机上编写
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: kk
user:
name: "{{ item.name }}"
state: present
group: "{{ item.group }}"
loop:
- name: wangqing
group: apache
- name: houyi
group: root
- 运行playbook
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [kk] **********************************************************************
changed: [192.168.50.136] => (item={'name': 'wangqing', 'group': 'apache'})
changed: [192.168.50.136] => (item={'name': 'houyi', 'group': 'root'})
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 受控机上查看两个用户
[root@localhost ~]# id wangqing
uid=1000(wangqing) gid=48(apache) groups=48(apache)
[root@localhost ~]# id houyi
uid=1001(houyi) gid=0(root) groups=0(root)
1.3 较早样式的循环关键字
较早样式的Ansible循环
循环关键字 | 描述 |
---|---|
with_items | 行为与简单列表的loop关键字相同,例如字符串列表或散列/字典列表。但与loop不同的是,如果为with_items提供了列表的列表,它们将被扁平化为单级列表。循环变量item保存每次迭代过程中使用的列表项。 |
with_file | 此关键字需要控制节点文件名列表。循环变量item在每次迭代过程中保存文件列表中相应文件的内容。 |
with_sequence | 此关键字不需要列表,而是需要参数来根据数字序列生成值列表。循环变量item在每次迭代过程中保存生成的序列中的一个生成项的值。 |
示例:
- 编写playbook
[root@localhost ~]# cd playbook/
[root@localhost playbook]# ls
! myplay.yml
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
data:
- 1
- 2
- 3
- 4
- 5
- 6
tasks:
- name: pp
debug:
msg: "{{ item }}" item代表data中的每一项
with_items: "{{ data }}" with_items代表迭代谁,这里就迭代data
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml 检查语法
playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml 打印结果
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [pp] **********************************************************************
ok: [192.168.50.136] => (item=1) => {
"msg": 1
}
ok: [192.168.50.136] => (item=2) => {
"msg": 2
}
ok: [192.168.50.136] => (item=3) => {
"msg": 3
}
ok: [192.168.50.136] => (item=4) => {
"msg": 4
}
ok: [192.168.50.136] => (item=5) => {
"msg": 5
}
ok: [192.168.50.136] => (item=6) => {
"msg": 6
}
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.4 将Register变量与Loop一起使用
示例: register关键字也可以捕获循环任务的输出。
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
gather_facts: no 关闭搜集功能
tasks:
- name: hh
shell: "echo jjyy {{ item }}"
loop:
- yom
- jerry
register: result 注册result这个结果里面去
- name: show result
debug:
var: result
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml
playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [hh] **********************************************************************
changed: [192.168.50.136] => (item=yom)
changed: [192.168.50.136] => (item=jerry)
TASK [show result] *************************************************************
ok: [192.168.50.136] => {
"result": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo jjyy yom",
"delta": "0:00:00.003770",
"end": "2020-09-07 09:26:09.697735",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo jjyy yom",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "yom",
"rc": 0,
"start": "2020-09-07 09:26:09.693965",
"stderr": "",
"stderr_lines": [],
"stdout": "jjyy yom",
"stdout_lines": [
"jjyy yom"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo jjyy jerry",
"delta": "0:00:00.003909",
"end": "2020-09-07 09:26:10.014186",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo jjyy jerry",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "jerry",
"rc": 0,
"start": "2020-09-07 09:26:10.010277",
"stderr": "",
"stderr_lines": [],
"stdout": "jjyy jerry",
"stdout_lines": [
"jjyy jerry"
]
}
]
}
}
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2. 条件判断
以下场景说明了在Ansible中使用条件的情况:
-
可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
-
Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
*可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
-
可以评估CPU的数量,来确定如何正确调节某一Web服务器。
-
将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
2.1 语法
when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。
- 示例: 现需要在受控机上安装阿帕奇。在写playbook时,my_condition为False,则直接跳过该任务,不会安装阿帕奇;若my_condition为True,则会安装阿帕奇
1.编写playbook,my_condition为False
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
my_condition: False
tasks:
- name: 安装阿帕奇
yum:
name: httpd
state: present
when: my_condition
- 查看受控机是否安装阿帕奇(没有安装)
[root@localhost ~]# rpm -qa|grep httpd
[root@localhost ~]#
- 编写playbook,my_condition为True
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
my_condition: True
tasks:
- name: 安装阿帕奇
yum:
name: httpd
state: present
when: my_condition
4.查看受控机是否安装阿帕奇(已安装)
[root@localhost ~]# rpm -qa|grep httpd
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
- 示例: my_service变量未被定义时,则不会安装
1 . 变量未被定义
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: 安装阿帕奇
yum:
name: "{{ my_service }}"
state: present
when: my_service is defined
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [安装阿帕奇] ******************************************************************* 变量未被定义,则无法识别安装什么东西,所以直接跳过安装
skipping: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
- 定义空变量
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
my_service: “ ” 这里定义空变量
tasks:
- name: 安装阿帕奇
yum:
name: "{{ my_service }}"
state: present
when: my_service is defined
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [安装阿帕奇] ******************************************************************* 无法识别安装什么东西,直接跳过安装
skipping: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
- 给变量定义httpd
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
vars:
my_service: httpd 给变量定义httpd
tasks:
- name: 安装阿帕奇
yum:
name: "{{ my_service }}"
state: present
when: my_service is defined
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [安装阿帕奇] *******************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看受控机是否安装
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
示例条件
操作 | 示例 |
---|---|
等于(值为字符串) | ansible_machine == “x86_64” |
等于(值为数字) | max_memory == 512 |
小于 | min_memory < 128 |
大于 | min_memory > 256 |
小于等于 | min_memory <= 256 |
大于等于 | min_memory >= 512 |
不等于 | min_memory != 512 |
变量存在 | min_memory is defined |
变量不存在 | min_memory is not defined |
布尔变量是True。1、True或yes的求值为True | memory_available |
布尔变量是False。0、False或no的求值为False | not memory_available |
第一个变量的值存在,作为第二个变量的列表中的值 | ansible_distribution in supported_distros |
- when语句不是模块变量,它必须通过缩进到任务的最高级别,放置在模块的外面。
- when关键字放在任务名称和模块(及模块参数)的后面。
2.2 测试多个条件
一个when语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。
示例: 使用and运算,两个条件都必须为真,才能满足整个条件语句。
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: sakdjla
yum:
name: httpd
state: present
when: ansible_facts['distribution'] == 'RedHat' and ansible_facts['distribution_version'] == '8.2'
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看受控机是否安装httpd
[root@localhost ~]# rpm -qa|grep httpd
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
- 也使用列表来描述条件列表
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: sakdjla
yum:
name: httpd
state: present
when:
- ansible_facts['distribution'] == 'RedHat'
- ansible_facts['distribution_version'] == '8.2'
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 使用or语句时,满足其中一个条件就可执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: sakdjla
yum:
name: httpd
state: present
when: >
ansible_facts['distribution'] == 'RedHat' 该条件成立
or
ansible_facts['distribution_version'] == '8.1' 我把'8.2' 改成‘8.1’ ,所以该条件不成立
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看受控机是否安装(已安装)
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
2.3 组合循环和有条件任务
示例: 需要卸载受控机的阿帕奇,当>那个值时,则会卸载;反之,不会执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: alkdjlak
yum:
name: httpd
state: absent 卸载受控机阿帕奇
loop: "{{ ansible_facts['mounts'] }}"
when:
- item.mount == '/'
- item.size_available > 913895410 这里是大于数值,则会执行任务
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [alkdjlak] ****************************************************************
changed: [192.168.50.136] => (item={'mount': '/', 'device': '/dev/mapper/rhel-root', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 18238930944, 'size_available': 16655716352, 'block_size': 4096, 'block_total': 4452864, 'block_available': 4066337, 'block_used': 386527, 'inode_total': 8910848, 'inode_available': 8876067, 'inode_used': 34781, 'uuid': '0579379e-7e27-495a-bb7b-a19916aa0929'})
skipping: [192.168.50.136] => (item={'mount': '/boot', 'device': '/dev/nvme0n1p1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 1063256064, 'size_available': 895655936, 'block_size': 4096, 'block_total': 259584, 'block_available': 218666, 'block_used': 40918, 'inode_total': 524288, 'inode_available': 523988, 'inode_used': 300, 'uuid': '81d21a3c-30eb-45e4-b99f-6536b0688395'})
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看受控机阿帕奇是否卸载
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
- 现在需要安装阿帕奇。用<数值,则条件语句不成立,任务不会执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: alkdjlak
yum:
name: httpd
state: present 安装阿帕奇
loop: "{{ ansible_facts['mounts'] }}"
when:
- item.mount == '/'
- item.size_available < 913895410 小于数值,条件语句不成立,任务不执行
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [alkdjlak] ****************************************************************
skipping: [192.168.50.136] => (item={'mount': '/', 'device': '/dev/mapper/rhel-root', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 18238930944, 'size_available': 16662544384, 'block_size': 4096, 'block_total': 4452864, 'block_available': 4068004, 'block_used': 384860, 'inode_total': 8910848, 'inode_available': 8876651, 'inode_used': 34197, 'uuid': '0579379e-7e27-495a-bb7b-a19916aa0929'})
skipping: [192.168.50.136] => (item={'mount': '/boot', 'device': '/dev/nvme0n1p1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 1063256064, 'size_available': 895655936, 'block_size': 4096, 'block_total': 259584, 'block_available': 218666, 'block_used': 40918, 'inode_total': 524288, 'inode_available': 523988, 'inode_used': 300, 'uuid': '81d21a3c-30eb-45e4-b99f-6536b0688395'})
PLAY RECAP *********************************************************************
192.168.50.136 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
查看受控机并没有安装阿帕奇
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
3. 实施处理程序
3.1 handlers
示例: 只有配置文件更新并且通知了该任务,restart apache处理程序才会重启Apache服务器
1.在受控机上把httpd.conf转移到主控机的root1下面去
[root@localhost ~]# cd /etc/httpd
[root@localhost httpd]# ls
conf conf.modules.d modules state
conf.d logs run
[root@localhost httpd]# cd conf
[root@localhost conf]# ls
httpd.conf httpd.conf.rpmsave magic
[root@localhost conf]# scp httpd.conf 192.168.50.135:/root/
root@192.168.50.135's password:
httpd.conf 100% 12KB 11.2MB/s 00:00
主控机上查看
[root@localhost playbook]# ls ~
anaconda-ks.cfg hosts playbook
ansible.cfg httpd.conf
- 创建一个files,与myplay.yml平级
[root@localhost playbook]# ls
! myplay.yml
[root@localhost playbook]# mkdir files
[root@localhost playbook]# ls
! files myplay.yml
[root@localhost playbook]# mv ~/httpd.conf files/ 把root下面的httpd.conf移到files
[root@localhost playbook]# tree .
.
├── !
├── files
│ └── httpd.conf
└── myplay.yml
1 directory, 3 files
- 编写playbook并运行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: installed httpd
yum:
name: httpd
state: present
- name: provides config
template:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
- name: start service
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [installed httpd] *********************************************************
ok: [192.168.50.136]
TASK [provides config] ********************************************************* 因为主控机和被控机的配置文件不一样(主控机的注释被取消),所以每次执行此步骤都会执行一遍
changed: [192.168.50.136]
TASK [start service] ***********************************************************
ok: [192.168.50.136]
RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 在主控机进入files将ServerName的注释取消,但被控机的注释存在,所以两台主机的配置文件不一样
[root@localhost playbook]# ls
! files myplay.yml
[root@localhost playbook]# cd files
[root@localhost files]# ls
httpd.conf
[root@localhost files]# vim httpd.conf
......
#ServerName www.example.com:80 将主控机的注释取消,被控机的注释依然存在
......
5.查看被控机的服务
[root@localhost ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; >
Active: active (running) since Mon 2020-09-07 16:31:37 >
[root@localhost ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; >
Active: active (running) since Mon 2020-09-07 16:42:53 > 因为两台主机的配置文件不一样,所以被控机的服务每次都会执行一次,所以时间会更新
3.2 使用处理程序的好处
使用处理程序时需要牢记几个重要事项:
-
处理程序始终按照play的handlers部分指定的顺序运行。它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行。
-
处理程序通常在相关play中的所有其他任务完成后运行。playbook的tasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行。
-
处理程序名称存在于各play命名空间中。如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
-
即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。
-
如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知。处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序。
4. 处理任务失败
4.1 忽略任务失败
- ignore_errors可以让playbook在任务失败时继续执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: SAKDJALKAJ
yum:
name: ndasdks 安装一个不存在的东西,所以该命令必定失败
state: present
ignore_errors: yes 可以忽略失败的任务使其他任务继续执行
- name: lakjdkasj 该任务必定成功
command: echo "hello world"
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [SAKDJALKAJ] ************************************************************** 该任务失败并没有影响其他任务的执行
fatal: [192.168.50.136]: FAILED! => {"changed": false, "failures": ["No package ndasdks available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring
TASK [lakjdkasj] ***************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
4.2 任务失败后强制执行
- 成功案例
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: install
yum:
name: httpd
state: present
- name: config
template:
src: files/httpd1.conf
dest: /etc/httpd/conf/httpd.conf
notify: 该任务若是失败,则会通知handlers任务不执行
- restart apache
- name: service
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml
playbook: myplay.yml
[root@localhost playbook]# ls
! files myplay.yml
[root@localhost playbook]# ls files/
httpd.conf
[root@localhost playbook]# echo '#' >> files/httpd.conf 改变配置文件,则会重新运行配置文件任务
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [install] *****************************************************************
ok: [192.168.50.136]
TASK [config] ******************************************************************
changed: [192.168.50.136]
TASK [service] *****************************************************************
ok: [192.168.50.136]
RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 失败案例
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: install
yum:
name: httpd
state: present
- name: config
template:
src: files/httpd1.conf httpd1.conf不存在,所以该任务会运行失败
dest: /etc/httpd/conf/httpd.conf
notify: 该任务失败后,后面的任务也不会执行
- restart apache
- name: service
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
[root@localhost playbook]# echo '#' >> files/httpd.conf
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [install] *****************************************************************
ok: [192.168.50.136]
TASK [config] ******************************************************************
fatal: [192.168.50.136]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/httpd1.conf'\nSearched in:\n\t/root/playbook/templates/files/httpd1.conf\n\t/root/playbook/files/httpd1.conf\n\t/root/playbook/templates/files/httpd1.conf\n\t/root/playbook/files/httpd1.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"}
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- force_handlers: yes,配置文件发生改变才会执行;没有改变则不会执行
第一遍配置文件发生改变,所以执行了
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [install] *****************************************************************
ok: [192.168.50.136]
TASK [config] ******************************************************************
changed: [192.168.50.136]
TASK [service] *****************************************************************
ok: [192.168.50.136]
RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
第二遍配置文件没有改变则没有执行
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [install] *****************************************************************
ok: [192.168.50.136]
TASK [config] ******************************************************************
ok: [192.168.50.136]
TASK [service] *****************************************************************
ok: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例: 验证重启服务失败不会影响handlers任务的执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
force_handlers: yes
tasks:
- name: install
yum:
name: httpd
state: present
- name: config
template:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
- name: service
service:
name: httpd
state: reloade 该任务必定不会执行,正确执行时应是reloaded
handlers:
- name: restart apache
service:
name: httpd
state: restarted
[root@localhost playbook]# echo '#' >> files/httpd.conf 改变配置文件
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [install] *****************************************************************
ok: [192.168.50.136]
TASK [config] ******************************************************************
changed: [192.168.50.136]
TASK [service] ***************************************************************** 重启服务任务没有执行
fatal: [192.168.50.136]: FAILED! => {"changed": false, "msg": "value of state must be one of: reloaded, restarted, started, stopped, got: reloade"}
RUNNING HANDLER [restart apache] *********************************************** hanglers任务已执行
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=4 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
4.3 指定任务失败条件
使用failed_when关键字来指定表示任务已失败的条件
示例:
编写一个脚本
[root@localhost playbook]# cd files/
[root@localhost files]# ls
httpd.conf
[root@localhost files]# vim test.sh
#!/bin/bash
ls jdkhaskda 不存在
ls 存在
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: command
script: files/test.sh
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [command] ***************************************************************** 这里看着成功运行了,其实并没有。脚本在这里看不出来是否运行成功
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查找报错信息
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
gather_facts: no
tasks:
- name: command
script: files/test.sh
register: result
failed_when: "'No such file or directory' in result.stdout"
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [command] ***************************************************************** 显示报错信息
fatal: [192.168.50.136]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to 192.168.50.136 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.50.136 closed."], "stdout": "ls: cannot access 'jdkhaskda': No such file or directory\r\nanaconda-ks.cfg\r\n", "stdout_lines": ["ls: cannot access 'jdkhaskda': No such file or directory", "anaconda-ks.cfg"]}
PLAY RECAP *********************************************************************
192.168.50.136 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
用一句话报错
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
gather_facts: no
tasks:
- name: command
script: files/test.sh
register: result
ignore_errors: yes
- name: error
fail: fail模块也可用于强制任务失败
msg: "哈哈哈,有错误"
failed_when: "'No such file or directory' in result.stdout"
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [command] *****************************************************************
changed: [192.168.50.136]
TASK [error] *******************************************************************
fatal: [192.168.50.136]: FAILED! => {"changed": false, "failed_when_result": true, "msg": "哈哈哈,有错误"}
PLAY RECAP *********************************************************************
192.168.50.136 : ok=1 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
4.4 指定任务报告何时出现“Changed” 结果
- changed_when: false 不管配置文件是否发生改变,运行结果都会显示ok(没改变)
先把hehe写入files文件里
[root@localhost playbook]# ls
! files myplay.yml
[root@localhost playbook]# cd files
[root@localhost files]# echo 'hehe' > abc
[root@localhost files]# ls
abc httpd.conf
这里我修改了配置文件,使用changed_when: false , 其结果依然显示ok(没改变)
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: ksahk
template:
src: files/abc
dest: /tmp/abc
changed_when: false
[root@localhost playbook]# echo '#' >> files/abc 修改了配置文件
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [ksahk] ******************************************************************* 运行结果显示OK
ok: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- changed_when: True 不管配置文件是否发生改变,其结果都会显示changed(发生改变)
这里我没有修改配置文件,使用changded_when: True,其结果会显示为changed
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: ksahk
template:
src: files/abc
dest: /tmp/abc
changed_when: True
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [ksahk] *******************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4.5 Ansible块和错误处理
- block:定义要运行的主要任务
- rescue:定义要在block子句中定义的任务失败时运行的任务
- always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败
示例: block执行失败,则rescue执行;block成功执行,则rescue不会执行;always始终执行
block执行失败,则rescue执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: test
block:
- name: block
command: echo "block" 执行必定成功
- name: failed task 该任务必定执行失败,所以rescue会执行
command: ls sajkdha
rescue:
- name: rescure
command: echo "rescue"
always:
- name: always
command: echo "always"
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml
playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [block] *******************************************************************
changed: [192.168.50.136]
TASK [failed task] ************************************************************* 执行失败
fatal: [192.168.50.136]: FAILED! => {"changed": true, "cmd": ["ls", "sajkdha"], "delta": "0:00:00.004438", "end": "2020-09-08 09:57:06.391297", "msg": "non-zero return code", "rc": 2, "start": "2020-09-08 09:57:06.386859", "stderr": "ls: cannot access 'sajkdha': No such file or directory", "stderr_lines": ["ls: cannot access 'sajkdha': No such file or directory"], "stdout": "", "stdout_lines": []}
TASK [rescure] ***************************************************************** 执行
changed: [192.168.50.136]
TASK [always] ******************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
block执行成功,则rescue不会执行
[root@localhost playbook]# vim myplay.yml
---
- hosts: all
tasks:
- name: test
block:
- name: block
command: echo "block" 执行必定成功
- name: failed task
command: ls 执行必定成功
rescue:
- name: rescure 所以rescue不会执行
command: echo "rescue"
always:
- name: always
command: echo "always"
[root@localhost playbook]# ansible-playbook myplay.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]
TASK [block] *******************************************************************
changed: [192.168.50.136]
TASK [failed task] *************************************************************
changed: [192.168.50.136]
TASK [always] ******************************************************************
changed: [192.168.50.136]
PLAY RECAP *********************************************************************
192.168.50.136 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0