实施任务控制
编写循环和条件任务
##简单循环
1.不用循环
---
- name: test
hosts: web
tasks:
- name: Apache is runing
service:
name: httpd
state: started
- name: vsftpd is running
service:
name: vsftpd
state: started
2.使用循环
tasks:
- name: apache and vsftpd is running
service:
name: "{{ item }}" 循环变量 item
state: started
loop:
- httpd
- vsftpd
3.将变量放入列表
vars:
web_service:
- httpd
- vsftpd
tasks:
- name: apache and vsftpd is running
service:
name: "{{ item }}"
state: started
loop: "{{ web_service }}"
循环散列或字典列表
---
- name: test
hosts: web
user:
name: "{{ item.user }}"
state: present
group: "{{ item.group }}"
loop:
- name: westos
group: westos
- name: caoaoyuan
group: root
##早些版本的循环,使用 with_item
- name: test
hosts: web
vars:
data:
- user1
- user2
- user3
tasks:
- name: "with_item"
register 和 loop 一起使用
---
- name: loop register test
hosts: localhost
gather_facts: no
tasks:
- name: loop task
shell: "echo this is my {{ item }}"
loop:
- one
- two
register: echo_results #注册变量
- name: show results
debug:
var: echo_results #显示变量结果
##迭代上面 playbook 的结果(即使用上面 item 的结果)
---
- name: loop register test
hosts: localhost
gather_facts: no
tasks:
- name: loop task
shell: "echo this is my {{ item }}"
loop:
- one
- two
register: echo_results
- name: show results
debug:
msg: "STDOUT is : {{ item.stdout }}"
loop: "{{ echo_results['results'] }}"
条件任务语法
关键字:when
使用布尔值测试
- name: BOOL test
hosts: all
vars:
my_task: true
tasks:
- name: httpd is installed
yum:
name: httpd
when: my_task # 只有当变量为 true 时,才会执行
当值为false时
就跳过了这一步。
测试 my_service 变量是否有值,有值则安装
---
- name: BOOL test
hosts: all
vars:
my_service: httpd
tasks:
- name: "{{ my_service }} is installed”
yum:
name: "{{ my_service }}"
when: my_service is defined
没有问题,当没有定义变量时则会报错,编写有问题。
##条件
等于(字符串) | A == “B” |
等于(数字) | A == 100 |
小于 | < |
大于 | > |
小于等于 | <= |
大于等于 | >= |
不等于 | != |
变量存在 | xxx is defined |
变量不存在 | xxx is not defined |
布尔值 true | 1、true、yes |
布尔值 false | 0、false、no |
第一个变量的值存在,且在第二个变量的列表中 | A in B |
or | 两个条件一个为真即可 |
and | 两个条件必须都为真 |
##组合循环和有条件任务
示例1:
-
- name: keyword
hosts: all
tasks:
- name: install mariadb
yum:
name: mariadb-server
state: latest
loop: "{{ ansible_mounts }}" #这个变量是事实,已知的
when: item.mount == "/" and item.size_available > 300000000
当 item.mount 等于 / 且 size大小大于 3000000000k 时执行。
可见已经安装了mariadb。
示例 2:
当 vsftpd 正在运行时重启 httpd 服务。
---
- name: restart vsftpd if vsftpd is running
hosts: all
tasks:
- name: grt vsftpd status
commond: /usr/bin/systemctl is-active vsftpd 判断状态
ignore_errors: yes 如果 vsftpd 没运行或失败,则忽略错误,继续执行。
register: result 定义变量保存结果
- name: restart apache
service:
name: httpd
state: restarted
when: result.rc == 0 返回码为0代表正常运行,为1则代表有错误。
且httpd已经重新启动。当vsftpd关闭时:
##编写循环和条件任务:
vim db.yml
---
- name: mariadb is tunning
hosts: web2
vars:
mariadb_pkg:
- mariadb-server
- python3-PyMySql
tasks:
- name: mariadb is installed
yum:
name: "{{ item }}"
state: present
loop: "{{ mariadb_pkg }}"
when: ansible_distribution == "RedHat"
受管主机使用 rehdat 操作系统时才执行。
#检测 westos2 组的主机系统
#运行
实施处理程序
处理程序是响应由其他任务触发的通知的任务
#只有在 template 任务通知已发生更改时才会触发
即这块changed有数字的时候才触发。
---
- name: Tesy
hosts: web1
tasks:
- name: copy file
template:
src: files/example.conf
dest: /etc/httpd/conf.d/example.conf
notify: notify 语句指出该任务需要触发一个处理程序
- restart apache 程序名
- restart mysql
handlers: 表示处理程序任务列表的开头
- name: restart apache 被任务调用的处理程序名称
service: 处理该程序的模块
name: httpd
state: restarted
- name: restart mysql
service:
name: mariadb
state: restarted
#ansible 把 notify 语句当作数组
mkdir files
cat files/example.conf
执行:
#使用处理程序注意:
- 处理程序始终按照 play 的 handlers 部分指定的顺序运行,不按 notify 里的
- 处理程序通常在相关 play 中所有其他任务运行完后运行
- 处理程序名称存在于个 play 命名空间中(如果两个处理程序同名,只会运行一个)
- 如果多个任务通知处理程序,处理程序也只会运行一次
- 如果包含 notify 的语句任务没有报告 changed 结果,则处理程序不会获得通知
例如再次执行TTest.yml,
就没有执行处理程序,因为文件已经复制过了,没有changed了,所以没有调用处理程序。
处理任务失败
通常 playbook 遇到错误会中止执行,但是有时我们想要失败时也继续执行下面的play
忽略任务失败
关键字:ignore_errors
#举例
先不添加 ignore_errors
- name: test
hosts: all
tasks:
- name: tset
yum:
name: k8s
state: latest
执行:
会直接报错退出。
加上后:
---
- name: test
hosts: all
tasks:
- name: tset
yum:
name: k8s
state: latest
ignore_errors: yes
还会继续往下走。
任务失败后强制执行处理程序
通常任务失败,play 会中止,那么收到 play 中之前任务通知的处理程序将不会运行,如果要运
行,需要使用关键字:force_handlers:yes
#举例=
ts: all
# force_handlers: yes 先把它注释掉
tasks:
- name: always notify
command: /bin/true
notify: restart apache
- name: fail task
yum:
name: k8s
state: latest
handlers:
- name: restart apache
service:
name: httpd
state: restarted
执行:
执行到失败任务就直接退出了,不会执行 handlers 的内容,当我们去掉注释时:
强制执行handlers ,即使上面有错误。
指定任务失败条件
关键字:failed_when
tasks:
- name: Run Script
shell: /usr/local/bin/user.sh
register: command_result
failed_when: "'failure' in command_result.stdout" fail 模块可以实现此效果
---
- name: test
hosts: all
tasks:
- name: run script
shell: /user/local/bin/user.sh
register: command_result
ignore_errors: yes
- name: report failer
fail: fail 模块可以提供明确消息
msg: "Authentication failure"
when: "'failure' in command_result.stdout"
指定任务何时报告"Changed"结果
关键字:changed_when
- name: get time
shell: date
changed_when: false
当错误时才报告changed,由于date的输出每秒都在变化,我们加上changed_when 就可以不报告他的changed
ansible 块和错误处理
三种关键字:
block:定义要运行的主要任务
rescue:定义要在 block 子句中定义的任务失败时运行的任务
always:定义时中独立运行的任务
#练习:
故意制造错误
- name: Task Failure
hosts: webservers
vars:
web_pkg: http 这里有错误,应该为httpd
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: Install {{ web_pkg }} packages
yum:
name: "{{ web_pkg }}"
state: present
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
运行报错
可见第一个任务失败,第二个任务不运行。
#那我们可以添加忽略关键字 : ignore_errors: yes
tasks:
- name: Install {{ web_pkg }} packages
yum:
name: "{{ web_pkg }}"
state: present
ignore_errors: yes
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
这样即便安装apache报错,也会执行下面的任务
#还可以使用 block、rescue、always 将任务分开
---
- name: Task failure
hosts: web
vars:
web_pkg: http
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: test install
block:
- name: install "{{ web_pkg }}"
yum:
name: "{{ web_pkg }}"
state: present
rescue:
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
always:
- name: "{{ db_service }}"
service:
name: "{{ db_service }}"
state: started
意为如果block块执行失败,则会执行rescue,单always 部分内容总会执行。
执行结果有报错,但是 mariadb 正常启动
#再修改,将 http 的包改为正确的httpd
发现 rescue 部分被忽略,但是 always 总会执行。
#控制’changed’条件
--
- name: Task failure
hosts: web
vars:
web_pkg: httpd
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: check time 新添加的
command: date
register: command_result
- name: print time 新添加的
debug:
var: command_result.stdout
- name: test install
block:
- name: install "{{ web_pkg }}"
yum:
name: "{{ web_pkg }}"
state: present
rescue:
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
always:
- name: "{{ db_service }}"
service:
name: "{{ db_service }}"
state: started
运行发现 check time 任务每次执行是 changed
由于每次chenged都会触发处理程序,所以我们不想让他每次都为changed。
修改文件
再次运行,变为 ok
#使用 failed_when 关键字进行更改。
让httpd安装完成之后定义为失败,就可以让block和resuce中的任务都执行了。
运行
有报错,但是其实已经安装了 httpd 包,failed_when 关键字只是改变了任务的执行状态,没
有改变任务本身
但是失败的状态可以让 rescue 语句块执行
#总结:
1.循环迭代的方法
2.条件用于仅再符合特定条件时执行任务或 play
3.处理程序用法
4.只有任务报告受管主机做了更改,才会通知处理程序
5.处理任务失败,即使成功的任务也可以标记为失败
6.块用于将任务分组为单元,通过任务是否成功来确定执行其他任务与