目录
一、循环
二、条件
三、handlers
四、失败的处理
一、循环
使用 loop 关键字对一组项目迭代任务,循环变量 item 保存每个迭代过程中使用的值。
[student@workstation ansible]$ vim loop.yml
---
- name: Test loop
hosts: dev
gather_facts: no
vars:
num:
- one
- two
- three
- four
- five
tasks:
- name: Echo some
shell: "echo This is {{ item }}"
loop: "{{ num }}"
register: echo_results
- name: Loop register var
debug:
msg: "{{ item.stdout }}"
loop: "{{ echo_results.results }}"
二、条件
when 语句用于有条件地运行任务。它取要测试的条件作为值。如果条件满足, 则运行任务。如果条件不满足,则跳过任务。举例,我们在 webservers 组添加了自定义事实,如果定义了那么安装一下自定义的包,否则跳过。
[student@workstation ansible]$ vim when.yml
---
- name: Install
hosts: all
tasks:
- name: Install db_pkg if db_pkg is defined
yum:
name: "{{ ansible_facts.ansible_local.myfact.packages.db_pkg }}"
state: present
when: ansible_facts.ansible_local.myfact is defined
[student@workstation ansible]$ ansible-playbook when.yml
......
TASK [Install db_pkg if db_pkg is defined] *************************************************
skipping: [servera.lab.example.com]
skipping: [serverb.lab.example.com]
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]
......
三、handlers
Ansible 模块设计为具有幂等性,playbook 及其任务可以运行多次而不会改变受管主机。
handlers 是由其他任务触发的通知的任务。仅当任务在受管主机上被更改,任务才通知handlers。
每个处理程序具有全局唯一的名称,在 playbook 中任务块的末尾触发。
处理程序可视为非活动任务,只有在使用 notify 语句调用时才会被触发。
handlers 在一个 playbook 里面和 tasks 是对齐的。
处理handlers的规范:
- 处理程序始终按照 play 的 handlers 部分指定的顺序运行。它们不按在任务中由 notify 语句列出的顺序运行,或按任务通知它们的顺序运行。
- 处理程序通常在相关 play 中的所有其他任务完成后运行。
- 如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
- 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。
比如,覆盖 /etc/httpd/conf/httpd.conf 配置文件,使 httpd 监听端口改为 8421。这就需要修改 selinux 端口上下文、重启 httpd 服务、配置防火墙入栈规则。顺序一定是先修改 selinux 端口上下文,再重启 httpd 服务,否则因为 selinux 重启 httpd 会失败。
[student@workstation ansible]$ vim handlers.yml
---
- name: Test handlers
hosts: webservers
tasks:
- name: Httpd listen 8421
copy:
src: httpd.conf.new
dest: /etc/httpd/conf/httpd.conf
notify:
- Allow Apache to listen on tcp port 8421
- Restart httpd
- Firewall permit 8421/tcp
handlers:
- name: Allow Apache to listen on tcp port 8421
seport:
ports: 8421
proto: tcp
setype: http_port_t
state: present
- name: Restart httpd
service:
name: httpd
state: restarted
- name: Firewall permit 8421/tcp
firewalld:
port: 8421/tcp
state: enabled
permanent: yes
immediate: yes
[student@workstation ansible]$ ansible-playbook handlers.yml
......
PLAY [Test handlers] ******************************************
TASK [Gathering Facts] ****************************************
ok: [serverc.lab.example.com]
ok: [serverd.lab.example.com]
TASK [Httpd listen 8421] **************************************
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]
RUNNING HANDLER [Allow Apache to listen on tcp port 8421] *****
changed: [serverc.lab.example.com]
changed: [serverd.lab.example.com]
RUNNING HANDLER [Restart httpd] *******************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
RUNNING HANDLER [Firewall permit 8421/tcp] ********************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
......
[student@workstation ansible]$ curl http://serverc.lab.example.com:8421
Added by ansible.
[student@workstation ansible]$ curl http://serverd.lab.example.com:8421
Added by ansible.
四、失败的处理
block-rescue-always 就类似 java 里面的 try-catch-finally 处理方式,block 升级一下,如果失败那么 rescue 一下,无论如何都有收尾工作放在 always里面。比如,webservers 组的两个服务器有 300 ~ 1000MiB 不同大小的卷组 vg_data,我们创建大小为 800MiB 的逻辑卷 lv_web,如果空间不够就创建大小 200MiB 的逻辑卷 lv_web,最后用 xfs 格式创建文件系统。
[student@workstation ansible]$ vim control.yml
---
- name: BlockRescueAlways
hosts: webservers
vars:
tasks:
- name: Create lvm
block:
- name: Check 0.8g
debug:
msg: "vg_data is less than 0.8g, not enough space"
when: ansible_facts.lvm.vgs.vg_data is defined and ansible_facts.lvm.vgs.vg_data.free_g | float < 0.8
failed_when: ansible_facts.lvm.vgs.vg_data is defined and ansible_facts.lvm.vgs.vg_data.free_g | float < 0.8
- name: Create a logical volume of 0.8g
lvol:
vg: vg_data
lv: lv_web
size: 800m
rescue:
- name: Create a logical volume of 0.2g
lvol:
vg: vg_data
lv: lv_web
size: 0.2g
always:
- name: Create a xfs filesystem
filesystem:
fstype: xfs
dev: /dev/vg_data/lv_web
执行过程
[student@workstation ansible]$ ansible-playbook control.yml
PLAY [BlockRescueAlways] **********************************************************************
TASK [Gathering Facts] ************************************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]
TASK [Check 0.8g] *****************************************************************************
fatal: [serverc.lab.example.com]: FAILED! => {
"msg": "vg_data is less than 0.8g, not enough space"
}
skipping: [serverd.lab.example.com]
TASK [Create a logical volume of 0.8g] ********************************************************
changed: [serverd.lab.example.com]
TASK [Create a logical volume of 0.2g] ********************************************************
changed: [serverc.lab.example.com]
TASK [Create a xfs filesystem] ****************************************************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
.......
检查结果,看到创建 lv_web 的大小是不同的。
[student@workstation ansible]$ ansible webservers -a "lvs"
serverd.lab.example.com | CHANGED | rc=0 >>
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root cl -wi-ao---- <17.00g
swap cl -wi-ao---- 2.00g
lv_web vg_data -wi-a----- 800.00m
serverc.lab.example.com | CHANGED | rc=0 >>
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root cl -wi-ao---- <17.00g
swap cl -wi-ao---- 2.00g
lv_web vg_data -wi-a----- 208.00m