任务控制
一、编写循环和条件任务
1. 循环简介
- name: Postfix is running
service:
name: postfix
state: started
- name: Dovecot is running
service:
name: dovecot
state: started
- name: Postfix and Dovecot are running
service:
name: "{{ item }}"
state: started
loop:
- postfix
- dovecot
---
- name:
vars:
mail_services:
- postfix
- dovecot
tasks:
- name: Postfix and Dovecot are running
service:
name: "{{ item }}"
state: started
loop: "{{ mail_services }}"
2. 循环字典列表
- 在上例中我们循环的是列表中的纯量
- loop列表中的项也可以是散列或字典,使用
item.xx 的形式调用 - 示例
- name: Users exist and are in the correct groups
user:
name: "{{ item.name }}"
state: present
group: "{{ item.groups }}"
loop:
- name: zhangsan
groups: wheel
- name: lisi
groups: root
3、将Register变量与Loop一起使用
- register关键字也可以捕获循环任务的输出
- 示例
vim loop_register.yml
---
- name: Loop Register Test
gather_facts: no
hosts: localhost
tasks:
- name: Looping Echo Task
shell: "echo This is my item: {{ item }}"
loop:
- one
- two
register: echo_results
- name: Show echo_results variable
debug:
var: echo_results
- 分析结果
- 查看
Task[Show echo_results variable] 下的"echo_results" 变量
- 常用字段
"注册变量.rc/注册变量['results'].rc" 、"注册变量.stdout/注册变量.['results'].stdout" 等
- 可利用循环
echo_results 字典中的results 列表来打印某些信息(虽然考试绝对不会考…不过也不难理解) - 示例打印输出结果
---
- name: Loop Register Test
gather_facts: no
hosts: localhost
tasks:
- name: Looping Echo Task
shell: "echo This is my item: {{ item }}"
loop:
- one
- two
register: echo_results
- name: Show echo_results variable
debug:
msg: "STDOUT from previous task: {{ item.stdout }}"
loop: "{{ echo_results['results'] }}"
4. 条件简介
- Ansible可使用
conditionals 在符合特定条件时执行任务或play - 可以作为条件的变量
- 可能的应用场景
- 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
- Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将跳过批处理。
- 可以利用 Ansible 事实来确定受管主机网络配置,并且决定要发送的模板文件〈如,网络绑定或中继)。
- 可以评估 CPU 的数量,来确定如何正确调节某一 Web 服务器。
- 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的 MD5 校验和以查看服务是否已更改。
5、条件任务
when 语句用于有条件的运行任务,类似if - 简单示例
---
- name: simple Boolean Task Demo
hosts: all
vars:
run_my_task: true
tasks:
- name: httpd package is installed
yum:
name: httpd
when: run_my_task
---
- name: Test Variable is Defined Demo
hosts: all
vars:
my_service: httpd
tasks:
- name: "{{ my_service }} package is installed"
yum:
name: "{{ my_service }}"
when: my_service is defind
-
最后一个条件成立的要求
- 第一个变量和第二个列表存在
- 第一个变量是第二个列表中的某个值
- 以上两个条件同时成立
-
简单示例
---
- name: Demonstrate the "in" keyword
hosts: all
gather_facts: yes
vars:
supported_distros:
- RedHat
- Fedora
tasks:
- name: Install httpd using yum,where supported
yum:
name: http
state: present
when: ansible_distribution in supported_distros
6. 多条件任务
- 一个when语句可用于评估多个条件。为此,可以使用and或 or关键字组合条件,并使用括号分组条件。
- when关键字还支持使用列表来描述条件列表,此时效果相当于and
- 使用大于字符(>),可以让长条件在playbook中分成多行,以便于阅读
when:
- ansible_distribution_version == "7.5"
- ansible_kernel == "3.10.0-327.el7.x86_64"
when: >
( ansible_distribution == "RedHat" and
ansible_distribution_major_version == "7" )
or
( ansible_distribution == "Fedora" and
ansible_distribution_major_version == "28" )
7. 结合循环和有条件任务
例1:
在下例中,yum模块将安装 mariadb-server软件包,只要/上挂载的文件系统具有超过300MB的可用空间。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
例2:
下面是组合使用条件和注册变量的另一个示例。下方标注的playbook只有在postfix服务处于运行状态时才会重新启动httpd服务。
- name: Restart HTTPD if 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
二、实施处理程序
1. 简介
- Ansible模块设计为具有幂等性。即在正确编写的playbook中,playbook及其任务可以运行多次而不会改变受管主机,除非需要进行更改使受管主机进入所需的状态。
- 处理程序是响应由其他任务触发的通知的任务。
- 仅当任务在受管主机上更改了某些内容时(changed),任务才通知其处理程序。
- 每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。
- 如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。
2. 语法
tasks:
- name: copy demo.example.conf configuration template
template:
src: /var/lib/templates/demo.example.conf.template
dest: letc/httpd/conf.d/demo.example.conf
notify:
- restart apache
handlers:
- name: restart apache
service:
name: httpd
state: restarted
3. 描述处理程序的好处
- 处理程序始终按照play的handlers部分指定的顺序运行。它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行。
- 处理程序通常在相关 play中的所有其他任务完成后运行。playbook的tasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行。
- 处理程序名称存在于各play命名空间中。如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
- 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。
- 如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知。处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序。
三、处理任务失败
1. 简介
- Ansible评估各任务的返回代码,从而确定任务是成功还是失败
- 通常而言,当任务失败时,Ansible将立即在该主机上中止 play的其余部分并且跳过所有后续任务
- 如果想即使在任务失败时也继续执行play。可以使用如下三种方法处理任务失败
- 相当于程序设计的异常处理
2. 忽略任务失败
- 通过忽略失败的任务覆盖中止的行为,在任务中使用
ignore_errors 来实现 - 简单示例
- name: Latest version of notapkg is installed
yum:
name: notapkg
state: latest
ignore_errors: yes
3. 任务失败后强制执行处理程序
---
- hosts: all
force_handlers: yes
tasks:
- name: a task which always notifies its handler
command: /bin/true
notify: restart the database
- name: a task which fails because the package doesn't exist
yum:
name: notapkg
state: latest
handlers:
- name : restart the database
service:
name: mariadb
state: restarted
4. 指定任务失败条件
failed_when :指定任务失败的条件效果同fail....when (可以理解为何时raise一个异常)
tasks:
- name: Run user creation script
shell: /usr/local/bin/create_users.sh
register: command_result
failed_when: "'Password missing' in command_result.stdout"
tasks:
- name: Run user creation script
shell: /usr/ local/bin/create_users.sh
register: command_result
ignore_errors: yes
- name: Report script failure
fail:
msg: "The password is missing in the output"
when: "'Password missing' in command_result.stdout"
5. 指定何时任务报告“Changed”结果
tasks:
- shell:
cmd: /usr/local/bin/upgrade-database
register: command_result
changed_when: " 'Success' in command_result.stdout"
notify:
- restart_database
handlers:
- name: restart_database
service:
name: mariadb
state: restarted
6. Ansible块和错误处理
-
非常类似程序的异常处理
- 方式一:使用when进行条件判断(类比if)
- 方式二:使用专门的错误处理语句(类比
try...catch/except...finally ) -
这里重点讲方式二
- block:定义要运行的主要任务。(类比try)
- rescue:定义要在block子句中定义的任务失败时运行的任务。(类比catch/except)
- always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败。(类比finally)
-
简单示例
tasks:
- name: upgrade DB
block:
- name: upgrade the database
shell:
cmd: /usr/loca1/lib/upgrade-database
rescue:
- name: revert the database upgrade
shell:
cmd: /usr/local/lib/revert-database
always:
- name: always restart the database
service:
name: mariadb
state: restarted
|