目录
实施任务控制
一,循环(迭代)--- loop
1,利用loop----item循环迭代任务
2,item---loop循环案例
1,定义item循环列表
2,通过变量应用列表格式
3,字典列表(迭代嵌套子变量)
4,register变量与loop
二,when条件任务语法
1, when条件测试案例
2,when条件表达语法
3, 多条件表达and or语法
4,组合循环和有条件判断任务
三,实施处理程序
1,Handlers和notify触发条件
四,处理任务失败
1,ignore_errors 忽略错误继续任务
2, force_handlers: yes
3, failed_when
4, change_when 满足条件输出change状态
5,block、rescue、always块和错误处理
通过循环管理员不需要编写多个使用同一模块的任务。例:他们不需要编写五个任务来确保存在五个用户,而是只需要编写一个任务来对含有五个用户的列表迭代,从而确保他们都在。
ansible支持loop关键字对一组项目迭代任务,可以配置循环以利用各个项目、列表中各个文件的内容、生成数字序列化或更为复杂的结构来重复任务。
loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。 循环item保存每个迭代过程中使用的值。
确定多个服务运行
(1)查看node1主机上的httpd与named服务是否启动,发现没启动
[root@node1 ~]# systemctl status httpd
[root@node1 ~]# systemctl status named
(2)查看node2主机上的httpd与named服务是否启动,发现没启动
[root@node2 ~]# systemctl status httpd
[root@node2 ~]# systemctl status named
(3)编辑playbook4.yml文件
---
- name: play1
hosts: test
tasks:
- name: task1
service:
name: "{{ item }}"
state: started
loop:
- httpd //定义item循环列表
- named bind的服务名位named
(4)执行脚本文件playbook4.yml,使其启动httpd服务与bind服务
[root@server var_test]# ansible-playbook playbook4.yml
(5)查看node1主机上的httpd与named服务是否启动,发现此时已经启动
[root@node1 ~]# systemctl status httpd
[root@node1 ~]# systemctl status named
(6)查看node2主机上的httpd与named服务是否启动,发现此时已经启动
[root@node2 ~]# systemctl status httpd
[root@node2 ~]# systemctl status named
(1)此时node1上的httpd与named服务是关闭的
[root@node1 ~]# systemctl status httpd
[root@node1 ~]# systemctl status named
(2)此时node2上的httpd与named服务是关闭的
[root@node2 ~]# systemctl status httpd
[root@node2 ~]# systemctl status named
(3)编辑playbook4.yml文件
---
- name: play1
hosts: test
vars:
pkname:
- httpd
- named
tasks:
- name: task1
service:
name: "{{ item }}"
state: started
loop: "{{ pkname }}" //通过变量应用列表格式
(4)执行playbook4.yml剧本文件
[root@server var_test]# ansible-playbook playbook4.yml
(5)查看node1主机上的httpd与named服务是否启动,发现此时已经启动
[root@node1 ~]# systemctl status httpd
[root@node1 ~]# systemctl status named
(6)查看node2主机上的httpd与named服务是否启动,发现此时已经启动
[root@node2 ~]# systemctl status httpd
[root@node2 ~]# systemctl status named
(1)编辑剧本playbook4.yml
---
- name: play1
hosts: test
tasks:
- name: task1
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'jane',groups: 'wheel'}
- { name: 'joe', groups: 'root' }
(2)执行剧本playbook4.yml
[root@server var_test]# ansible-playbook playbook4.yml
(3)在node1上可以查看到playbook4中创建的用户以及附加组
[root@node1 ~]# id jane
[root@node1 ~]# id joe
(4)在node2上可以查看到playbook4中创建的用户以及附加组
[root@node2 ~]# id jane
[root@node2 ~]# id joe
(1)编写剧本文件playbook4.yml
- name: play1
gather_facts: no
hosts: localhost
tasks:
- name: task1
shell: "echo this is my item: {{ item }}"
loop:
- one
- two
register: echo_results //变量注册
- name: task2
debug:
var: echo_results //变量内容显示在屏幕上
(2)执行剧本文件
[root@server var_test]# ansible-playbook playbook4.yml
when语句用于有条件运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足则跳过任务。
案例一:可以测试当run_my_task 为true的时候执行否则不执行
(1)此时的node1主机上没有安装bind
[root@node1 ~]# rpm -q bind
(2)编辑playbool4.yml文件,使得当my_task为true,在node1安装bind
---
- name: play1
hosts: node1
vars:
my_test: true
tasks:
- name: task1
yum:
name: bind
when: my_test
(3)执行剧本playbool4.yml
[root@server var_test]# ansible-playbook playbook4.yml
(4)此时在node1主机上查看bind,发现已经被安装
[root@node1 ~]# rpm -q bind
案例2: 判断my_service是否有值,若有值则用作安装的软件包名称,若没有定义变量则跳过任务不显示错误
(1)此时的node1主机上没有vsftpd包
[root@node1 ~]# rpm -q vsftpd
(2)编辑playbook4.yml文件,在node1上安装vsftpd包
---
- name: play1
hosts: node1
vars:
my_package: vsftpd
tasks:
- name: task1
yum:
name: "{{ my_package }}"
when: my_package is defined
(3)执行剧本playbook4.yml
[root@server var_test]# ansible-playbook playbook4.yml
(4)此时在node1主机上查看vsftpd,发现已经被安装
[root@node1 ~]# rpm -q vsftpd
操作 |
示例 |
等于(值为字符串) |
ansible_machine == "x86_64" |
等于(值为数字) |
max_memory == 512 |
小于(小于等于) |
Min_memory <128 min_memory <= 512 |
大于 (大于等于) |
Min_memory > 256 max_memory >= 512 |
不等于 |
Min_memory != 512 |
变量存在 |
Min_memory is defined |
变量不存在 |
Min_memory is not defined |
布尔值变量是true. 1、True 或yes 的求值为true 变量Memory_available值存在为true则执行 |
Memory_available |
布尔值变量是false. 0、 False 或no的求值为false 变量Memory_available值存在为true则执行 |
Not memory_available |
第一个变量的值存在,在第二个变量的列表中条件满足 (事实变量在变量列表中满足要求) |
Ansible_distribution in supported_distros |
- name: Demonstrate the inkeyword
hosts: all
gather_facts: yes
Vars:
supperted_distros:
- Redhat
- Fedora
Tasks:
- name: Install httpd using yum, where supported
yum:
name: http
state: present
when: ansible_distribution in supperted_distros
注
When 语句的缩进,由于when语句不是模块变量,他必须通过缩进到任务的最高级别,放置在模块的外面。
任务是YAML散列/字典,when语句只是任务重的又一个键,就如任务的名称以及它所使用的模块一样。通常的惯例是将可能存在的任何when关键字放在任务名称和模块的后面。
语法一:
when:ansible_distribution == "Redhat" or ansible_distribution == "Fedora"
When: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"
语法二:
使用and语句时,则必须要所有条件为真时,才执行相应任务
when:
- ansible_distribution_version == "7.5"
- ansible_kernel == "3.10.0-327.el7.x86_64"
使用括号分组条件,可以更好的表达复制的条件语句
When: >
( ansible_distribution_version == "redhat" and
ansible_distribution_major_version == "7" )
or
( ansible_distribution_version == "fedora" and
ansible_distribution_major_version == "28" )
对某类任务结合使用when和loop时,将对每项检查when语句
yum安装软件包,只要/上挂载的文件系统有超过300M的可用空间。 Ansible_mounts 事实是一组字典,各自代表一个已挂在文件系统的相关事实。循环迭代每个字典,只要找到了代表两个条件都为真的已挂载文件系统的字典时,条件语句才得到满足。
- name: install mariadb-server if enough space on root
yum:
name: mariadb-server
state: latest
loop: "{ ansible_mounts }" //字典循环
when: item.mount == "/" and item.size_available > 300000000 //当两个条件都满足则执行安装
案例:实现只有修改了配置文件才会重启服务
(1)将/etc/httpd/conf/httpd.conf 复制到/目录下
[root@server var_test]# cp /etc/httpd/conf/httpd.conf /
(2)编辑文件/httpd.conf,将端口改为10000
#Listen 80
Listen 10000
(3)在受控主机node1与node2上关闭防火墙,并设置selinux为permissive
[root@node1 ~]# systemctl stop firewalld
[root@node1 ~]# setenforce 0
[root@node2 ~]# systemctl stop firewalld
[root@node2 ~]# setenforce 0
(4)创建playbook5.yml文件
- name: handlers test
hosts: all
tasks:
- name: install httpd service
yum:
name: httpd
state: installed
- name: copy config file
copy:
src: /httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart service
- name: start httpd service
service:
name: httpd
state: started
handlers:
- name: restart service
service:
name: httpd
state: restarted
(5)执行剧本playbook5.yml
因为控制端的端口号为10000,发生了修改,所以会重启服务
[root@server var_test]# ansible-playbook playbook5.yml
(6)再次执行剧本文件playbook5.yml,此时的配置文件并未发生任何改变,所以服务并未重新启动
[root@server var_test]# ansible-playbook playbook5.yml
(7)此时再将配置文件的端口号由10000改为80
Listen 80
(8)再次执行剧本playbook5.yml,发现又会重启服务,因为/etc/httpd文件发生改变
[root@server var_test]# ansible-playbook playbook5.yml
注意:handlers写在notify模块之后
tags标签: 通过此标签来指定playbook文件执行哪条命令
执行 :-t 标签名
案例:仅执行playbook5.yml中的安装httpd命令
(1)编辑playbook5.yml文件
- name: handlers test
hosts: all
tasks:
- name: install httpd service
yum:
name: httpd
state: installed
tags: yum_httpd
- name: copy config file
copy:
src: /httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart service
- name: start httpd service
service:
name: httpd
state: started
handlers:
- name: restart service
service:
name: httpd
state: restarted
(2)此时执行剧本文件playbook.yml会发现只执行了装包命令
[root@server var_test]# ansible-playbook -t yum_httpd playbook5.yml
默认情况下任务失败时play会终止。可以通过ingnore乎略失败,其他任务可以继续执行。
案例:
(1)编辑剧本文件playbook6.yml
- name: restart httpd is postfix is running
hosts: all
tasks:
- name: get postfix server status
command: /usr/bin/systemctl is-active postfix
# ignore_errors: yes
register: result
- name: restart apache httpd based on postfix status
service:
name: httpd
state: restarted
when: result.rc == 0
(2)此时受控端主机并未安装postfix,所以任务执行会失败
[root@server var_test]# ansible-playbook playbook6.yml
(3)编辑剧本文件playbook6.yml
- name: restart httpd is postfix is running
hosts: all
tasks:
- name: get postfix server status
command: /usr/bin/systemctl is-active postfix
ignore_errors: yes
register: result
- name: restart apache httpd based on postfix status
service:
name: httpd
state: restarted
when: result.rc == 3
(4)此时受控端主机虽然并未安装postfix,但是会跳过失败,继续执行下面的任务
[root@server var_test]# ansible-playbook playbook6.yml
如果任务失败并且play在该主机上终止,则收到play中早前任务通知的处理程序将不会运行。
(1)此时的/etc/http配置文件并未做任何改变,所以服务httpd不会自启
[root@server var_test]# ansible-playbook playbook5.yml
(2)将/etc/httpd配置文件进行修改,notify触发成功,但是后面的服务名错误,force_handlers: yes 关键字还是会执行handlers中的命令
Listen 1004
(3)编辑playbook5.yml文件
- name: handlers test
force_handlers: yes
hosts: all
tasks:
- name: install httpd service
yum:
name: httpd
state: installed
- name: copy config file
copy:
src: /httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart service
- name: start httpd service
service:
name: http
state: started
handlers:
- name: restart service
service:
name: httpd
state: restarted
(4)此时执行剧本文件playbook5.yml;即使后面的服务名写错了,也能执行handlers
[root@server var_test]# ansible-playbook playbook5.yml
failed_when其实是ansible的一种错误处理机制,是由fail模块使用了when条件语句的组合效果。
我们也可以直接通过fail模块和when条件语句,写成如下:
- name: run user
shell: /usr/local/bin/create_users.sh
register: result
ignore_errors: yes
- name: fail the play if the previous command did not succeed
fail:
msg: "please create user"
when: "'not' in result.stdout"
当我们控制一些远程主机执行某些任务时,当任务在远程主机上成功执行,状态发生更改时,会返回changed状态响应,状态未发生更改时,会返回OK状态响应,当任务被跳过时,会返回skipped状态响应。我们可以通过changed_when来手动更改changed响应状态。
(1)Playbook5.yml案例中,如果配置文件/httpd.conf并未发生改变,执行显示ok
[root@server var_test]# ansible-playbook playbook5.yml
(2)编辑playbook5.yml文件
- name: handlers test
hosts: all
tasks:
- name: install httpd service
yum:
name: httpd
state: installed
- name: copy config file
copy:
src: /httpd.conf
dest: /etc/httpd/conf/httpd.conf
register: cmd_v1
changed_when: not cmd_v1.changed
notify:
- restart service
- name: start httpd service
service:
name: httpd
state: started
handlers:
- name: restart service
service:
name: httpd
state: restarted
(3)修改后,此时来执行剧本文件playbook5.yml,已经由ok状态变为changed状态
[root@server var_test]# ansible-playbook playbook5.yml
通过块,也可结合rescue和always语句来处理错误,如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障)运行之后,always子句中的任务运行。
总结:
block有错才会执行rescue;always怎么都会执行
案例: 在playbook中实施块即使block子句中定义的任务失败,rescue和always子句中定义的任务也会执行。
创建目录文件和文本文件;注意如果默认路径下存在同名文件需要进一步处理才能创建该文件。
(1)编辑playbook7.yml文件
---
- name:
hosts: localhost
tasks:
- name: block module
block:
- name: create directory
file:
name: /aaa
state: directory
rescue:
- name: backup filenmae
shell: mv /aaa /aaa.backup
- name: create directory force
file:
name: /aaa
state: directory
force: yes
always:
- name: create file
file:
name: /newfile
state: touch
(2)执行剧本playbook7.yml文件
[root@server var_test]# ansible-playbook playbook7.yml
(3)目录/aaa与文件/newfile已经被创建
[root@server var_test]# ls -l /aaa
[root@server var_test]# ls -l /newfile
[root@server var_test]# cd /aaa