Blocks (块)创建了逻辑上的任务集合,并且为处理任务错误提供了解决方法,功能类似于很多编程语言中的 “异常处理”。
把任务组成block
一个块中的所有任务都会继承和块同一级别的指令。当多个任务都需要满足同一个条件时,使用块来设置指令会更加方便。指令不会影响块本身,而是仅仅被块中包含的任务所继承了。例如:when条件判断语句只对块中的任务有效,对于块本身不起作用。
block例子
tasks:
- name: Install, configure, and start Apache
block:
- name: Install httpd and memcached
ansible.builtin.yum:
name:
- httpd
- memcached
state: present
- name: Apply the foo config template
ansible.builtin.template:
src: templates/src.j2
dest: /etc/foo.conf
- name: Start service bar and enable it
ansible.builtin.service:
name: bar
state: started
enabled: True
when: ansible_facts['distribution'] == 'CentOS'
become: true
become_user: root
ignore_errors: yes
block中一共有三个task,在执行这三个任务之前,ansible会先判断when后面的条件是否满足。因此如果主机不是centos,这三个任务都不会被执行。并且这三个任务都会以root的身份去执行。ignore_errors:yes 确保了即使block中有某个任务失败了,playbook仍然可以不受影响继续往下运行。
rescue和always
一般来说,playbook中的某个任务失败,接下来的任务就无法运行。但实际情况是,一个playbook可能会用于很多台主机,同样的任务可能有些主机成功,有些主机会失败,除了加上when条件判断,还可以使用block配合rescue和always来处理errors。
rescue:当block中的一个任务返回失败就执行rescue下面的任务,只要rescue后面的任务执行成功,后续其他任务就不会受影响,类似于纠正错误的意思
EXAMPLE
---
- hosts: webservers
tasks:
- name: Handle the error
block:
- name: Print a message
ansible.builtin.debug:
msg: 'I execute normally'
- name: Force a failure
command: /bin/false
- name: Never print this
ansible.builtin.debug:
msg: 'I never execute, due to the above task failing, :-('
rescue:
- name: Print when errors
ansible.builtin.debug:
msg: 'I caught an error, can do stuff here to fix it, :-)'
- name: wall hahaha
shell: wall hahaha
以上例子,block中有三个task,第二个task返回错误,那么第三个task不会被执行,并且同时触发了rescue后面的信息。所以结果只会打印两句话
"msg": "I execute normally"
"msg": "I caught an error, can do stuff here to fix it, :-)"
并且因为rescue中的任务执行成功,后面任务继续执行,主机上能看到wall广播。
always: 无论之前blcok中的任务是成功还是失败,always下的任务都会执行,即使接下来always中的任务执行成功,后面的其他任务也不会被执行
EXAMPLE
---
- hosts: webservers
tasks:
- name: Always do X
block:
- name: Print a message
ansible.builtin.debug:
msg: 'I execute normally'
- name: Force a failure
command: /bin/false
- name: Never print this
ansible.builtin.debug:
msg: 'I never execute :-('
always:
- name: Always do this
ansible.builtin.debug:
msg: "This always executes, :-)"
- name: wall hahaha
command: wall hahaha
以上例子,block中的第二个任务失败了,所以第三个任务不会继续执行下去。只执行always下面的任务。除了always中的任务,后续的任务不会继续执行,看不到wall广播。
"msg": "I execute normally"
"msg": "This always executes, :-)"
RHCE考题
创建一个名为 /home/student/ansible/lv.yml 的 playbook,它将在所有受管节点上运行以执行下列任务:
创建符合以下要求的逻辑卷:
• 逻辑卷创建在 research 卷组中
• 逻辑卷名称为 data
• 逻辑卷大小为 1500MiB
• 使用 ext4 文件系统格式化逻辑卷
• 如果无法创建请求的逻辑卷大小,应显示错误消息Could not create logical volume of that size并且应改为使用大小 800MiB
• 如果卷组 research 不存在 ,应显示错误消息Volume group does not exist
• 不要以任何方式挂载逻辑卷
我的解题思路
首先,先判断被控端有没有卷组,如果没有直接跳过显示卷组不存在。如果存在,先创建1500M的逻辑卷,如果遇到空间不够提示创建失败再创建800M的逻辑卷。并且无论空间够不够1500M都格式化成ext4。这题需要用到block配合rescue、always来写playbook。
参考答案
lv.yml
---
- hosts: all
tasks:
- name:
block:
- name:
lvol:
vg: research
lv: data
size: 1500m
rescue:
- name:
debug:
msg: Could not create logical volume of that size
- name:
lvol:
vg: research
lv: data
size: 800m
always:
- name:
filesystem:
fstype: ext4
dev: /dev/research/data
when: "'research' in ansible_lvm.vgs"
- name:
debug:
msg: Volume group does not exist
when: "'research' not in ansible_lvm.vgs"
模拟环境执行结果
![](https://frogvps.com/wp-content/uploads/2022/08/20220810a1-1024x455.jpg)
![](https://frogvps.com/wp-content/uploads/2022/08/20220810a2-1024x459.jpg)