Absible#Ansible-Playbook的任务控制
Ansible-Playbook的任务控制
文章目录
- 一、任务控制基本介绍
- 二、条件判断
- 三、循环控制
- 四、Tags属性
- 五、Handlers属性
- 六、Ansible中处理失败的任务
- 1、Ansible管理play中的任务错误的正常逻辑
- 2、忽略任务失败 ignore_errors: yes
- 3、任务失败也强制执行处理程序(handlers)
- 4、指定任务失败的条件
- 5、制定何时任务报告"changed"结果
- 6、Ansible块和错误处理
一、任务控制基本介绍
这里主要来介绍PlayBook中的任务控制。
任务控制类似于编程语言中的if … 、for … 等逻辑控制语句
1、Playbook示例
在下面的PlayBook中,我们创建了 tomcat、www 和 mysql 三个用户。安装了Nginx 软件包、并同时更新了 Nginx 主配置文件和虚拟主机配置文件,最后让Nginx 服务处于启动状态。
---
- name: task control playbook examplehosts: webserverstasks:- name: create tomcat useruser: name=tomcat state=present- name: create www useruser: name=www state=present- name: create mysql useruser: name=mysql state=present- name: yum nginx webserveryum: name=nginx state=present- name: update nginx main configcopy: src=nginx.conf dest=/etc/nginx/- name: add virtualhost configcopy: src=www.qfedu.com.conf dest=/etc/nginx/conf.d/- name: start nginx serverservice: name=nginx state=started
下面针对上面的playbook的问题,进行优化
二、条件判断
问题一、Nginx启动逻辑欠缺考虑
启动Nginx之前需要进行配置文件语法检测
检验通过之后再进行启动Nginx
Nginx 语法校验
- name: check nginx syntax
shell: nginx -t
通过注册变量将Nginx检查语法的Tasks结果与Nginx的启动Tasks关联起来,根据这个结果去判断“启动NGINX的TASK”是否执行
获取Task任务结果
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxsyntax
获取到任务结果,但是结果里面的内容是个什么样子, 我如何根据内容在后续的PlayBook中使用呢?
通过debug模块去确认返回结果的数据结构
- name: print nginx syntax result
debug: var=nginxsyntax
通过debug 模块,打印出来的返回结果。 当nginxsyntax.rc 为 0 时语法校验正确
用到的nginx配置文件
主配置文件
# cat nginx.conf
user www;
worker_processes 2;error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;events {worker_connections 1024;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';sendfile on;tcp_nopush on;keepalive_timeout 0;gzip on;gzip_min_length 1k;gzip_buffers 8 64k;gzip_http_version 1.0;gzip_comp_level 5;gzip_types text/plain application/x-javascript text/css application/json application/xml application/x-shockwave-flash application/javascript image/svg+xml image/x-icon;gzip_vary on;include /etc/nginx/conf.d/*.conf;
}
nginx子配置文件
server {listen 80;server_name www.qfedu.com;root /usr/share/nginx/html;access_log /var/log/nginx/www.qfedu.com-access_log main;error_log /var/log/nginx/www.qfedu.com-error_log;add_header Access-Control-Allow-Origin *;location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {expires 1d;}location ~ .*\.(js|css)?$ {expires 1d;}
}
通过条件判断(when) 指令去使用语法校验的结果
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxsyntax
- name: print nginx syntaxdebug: var=nginxsyntax- name: start nginx serverservice: name=nginx state=startedwhen: nginxsyntax.rc == 0
改进后的playbook
---
- name: task control palybook examlehosts: 10.11.67.32gather_facts: noremote_user: roottasks:- name: create tomcat useruser: name=tomcat state=present- name: create www useruser: name=www state=present- name: create mysql useruser: name=mysql state=present- name: yum nginx webserveryum: name=nginx state=present- name: update nginx configcopy: src=nginx.conf dest=/etc/nginx/conf.d/- name: check nginx configshell: lsregister: nginxsyncheck- name: print nginxsyncheckdebug: var=nginxsyncheck- name: start nginx serversystemd: name=nginx state=startedwhen: nginxsyncheck.rc == 0
以上的逻辑,只要语法检查通过都会去执行 "start nginx server"这个TASK。在这个问题的解决里,我们学习了when 条件判断和注册变量的结合使用。学习了when条件判断中是可以支持复杂逻辑的。比如现在用到的逻辑运算符 and
==
!=
> >=
< <=
is defined
is not defined
true
false
支持逻辑运算符: and or
三、循环控制
三、循环控制
playbook也存在循环控制,我们也可以像写shell一样简单的去完成多用户创建工作,在PlayBook中使用 with_items 去实现循环控制,且循环时的中间变量循环变量只能是关键字 item,而不能随意自定义
with_items:实现循环控制
item:定义循环变量
使用定义了剧本变量 createuser(一个列表) ,然后通过 with_items 循环遍历变量这个变量来达到创建用户的目的。
- name: variable playbook examplehosts: webserversgather_facts: novars:createuser:- tomcat- www- mysqltasks:- name: create useruser: name="{{ item }}" state=presentwith_items: "{{ createuser }}"# createuser 是被循环的对象# item 每次循环被赋值的变量
- name: variable playbook examplehosts: webserversgather_facts: novars:createuser:- tomcat- www- mysqltasks:- name: create useruser: name="{{ item }}" state=presentwith_items: "{{ createuser }}"# createuser 是被循环的对象# item 每次循环被赋值的变量- name: yum nginx webserveryum: name=nginx state=present- name: update nginx main configcopy: src=nginx.conf dest=/etc/nginx/- name: add virtualhost configcopy: src=www.qfedu.com.conf dest=/etc/nginx/conf.d/- name: check nginx syntaxshell: /usr/sbin/nginx -tregister: nginxsyntax- name: print nginx syntaxdebug: var=nginxsyntax- name: start nginx serverservice: name=nginx state=startedwhen: nginxsyntax.rc == 0
新版本的loop循环
- name: loop itemhosts: allgather_facts: novars:some_list:- "a"- "b"- "c"num_list:- 1- 2- 3- 5tasks:- name: show itemdebug:var: itemloop: "{{ some_list }}"- name: show item when item > 3debug:var: itemloop: "{{ num_list }}"when: item > 3# 循环中还可以加判断,这里是当循环的数据是大于 3 的,# 才赋值个 var ,从而打印出来
[kakaops@ka ansible]$ sudo ansible-playbook loop.yaml
[sudo] kakaops 的密码:__________________
< PLAY [loop item] >------------------\ ^__^\ (oo)\_______(__)\ )\/\||----w ||| ||_______________________
< TASK [show some_list] >-----------------------\ ^__^\ (oo)\_______(__)\ )\/\||----w ||| ||Saturday 07 November 2020 09:14:32 +0800 (0:00:00.111) 0:00:00.112 *****
ok: [10.11.67.32] => (item=a) => {"ansible_loop_var": "item", "item": "a"
}
ok: [10.11.67.32] => (item=b) => {"ansible_loop_var": "item", "item": "b"
}
ok: [10.11.67.32] => (item=c) => {"ansible_loop_var": "item", "item": "c"
}____________________________________
< TASK [show num_list when item > 3] >------------------------------------\ ^__^\ (oo)\_______(__)\ )\/\||----w ||| ||Saturday 07 November 2020 09:14:32 +0800 (0:00:00.159) 0:00:00.271 *****
skipping: [10.11.67.32] => (item=1)
skipping: [10.11.67.32] => (item=2)
skipping: [10.11.67.32] => (item=3)
skipping: [10.11.67.32] => (item=4)
ok: [10.11.67.32] => (item=5) => {"ansible_loop_var": "item", "item": 5
}
ok: [10.11.67.32] => (item=6) => {"ansible_loop_var": "item", "item": 6
}____________
< PLAY RECAP >------------\ ^__^\ (oo)\_______(__)\ )\/\||----w ||| ||10.11.67.32 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Saturday 07 November 2020 09:14:32 +0800 (0:00:00.168) 0:00:00.439 *****
===============================================================================
debug ------------------------------------------------------------------- 0.33s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
total ------------------------------------------------------------------- 0.33s
Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
四、Tags属性
考虑这样一个情况:
若更新了Nginx 的配置文件后,我们需要通过PlayBook将新的配置发布到生产服务器上,然后再重新加载我们的Nginx 服务。但以现在的PlayBook来说,每次更改Nginx 配置文件后虽然可以通过它发布到生产服务器上,但整个PlayBook中的每个任务都要执行一次,这样无形中扩大了变更范围和变更风险
Tags 属性就可以解决这个问题
我们可以通过Play中的tags 属性,去解决目前PlayBook变更而导致的扩大变更范围和变更风险的问题。在改进的PlayBook中,针对文件发布TASK 任务 “update nginx main config” 和 “add virtualhost config” 新增了属性 tags ,属性值为updateconfig。另外我们新增"reload nginx server" TASK任务。当配置文件更新后,去reload Nginx 服务。那重新加载需要依赖于 Nginx 服务是已经启动状态。所以,还需要进一步通过判断 Nngix 的 pid 文件存在,才证明 Nginx 服务本身是启动中,启动中才可以 reload Nginx 服务。 判断一个文件是否存在使用 stat 模块
判断一个文件是否存在使用 stat
模块
- name: check nginx runningstat: path=/var/run/nginx.pidregister: nginxrunning
观察结果,会发现 nginxrunning.stat.exists
的值是 true
就表示启动状态,是 false
就是关闭状态。
- name: tags playbook examplehosts: webserversgather_facts: novars:createuser:- tomcat- www- mysqltasks:- name: create useruser: name={{ item }} state=presentwith_items: "{{ createuser }}"- name: yum nginx webserveryum: name=nginx state=present- name: update nginx main configcopy: src=nginx.conf dest=/etc/nginx/tags: updateconfig- name: add virtualhost configcopy: src=www.qfedu.com.conf dest=/etc/nginx/conf.d/tags: updateconfig- name: check nginx syntaxshell: /usr/sbin/nginx -tregister: nginxsyntaxtags: updateconfig- name: check nginx runningstat: path=/var/run/nginx.pidregister: nginxrunningtags: updateconfig- name: print nginx syntaxdebug: var=nginxsyntax- name: print nginx syntaxdebug: var=nginxrunning- name: reload nginx serverservice: name=nginx state=reloadedwhen: nginxsyntax.rc == 0 and nginxrunning.stat.exists == truetags: updateconfig- name: start nginx serverservice: name=nginx state=startedwhen:- nginxsyntax.rc == 0- nginxrunning.stat.exists == falsetags: updateconfig
指定tags 去执行PlayBook
执行时一定要指定tags,这样再执行的过程中只会执行task 任务上打上tag 标记为 updateconfig 的任务
# ansible-playbook -i hosts site.yml -t updateconfig
结合Ansible的错误处理逻辑,上面的play漏洞百出
下面是我还改进的playbook
- name: tags playbook examplehosts: 10.11.67.32gather_facts: novars:createuser:- tomcat- www- mysqltasks:- name: create useruser: name={{ item }} state=presentwith_items: "{{ createuser }}"- name: yum nginx webserveryum: name=nginx state=present- name: update nginx main configcopy: src=nginx.conf dest=/etc/nginx/- name: add virtualhost configcopy: src=www.qfedu.com.conf dest=/etc/nginx/conf.d/- name: check nginx syntaxshell: nginx -tregister: nginxsyntaxtags: kakaops- name: check nginx runningshell: systemctl is-active nginxregister: nginxrunningtags: kakaopsignore_errors: yes- name: print nginx syntaxdebug: var=nginxsyntaxtags: kakaops- name: print nginx syntaxdebug: var=nginxrunningtags: kakaops- name: reload nginx configsystemd: name=nginx state=reloadedwhen: nginxsyntax.rc == 0tags: kakaops- name: systemctl start nginxsystemd: name=nginx state=startedwhen:- nginxsyntax.rc == 0- nginxrunning.rc != 0tags: kakaops
大体逻辑是这样的,检查配置文件的错误不能忽略,一旦配置文件出错,立即终止play,只有检查配置文件正确的,才继续往下执行,重新加载配置文件。检查nginx是否开启的错误输出可以用ignore_erroes=yes忽略,通过条件判断,如果没开启,就会开启nginx。判断nginx是否开启,我没有用stat模块,检查/var/run/nginx.pid是否存在,因为这样的检查方法存在一个bug。当nginx停止的时候,上面的play执行了一个nginx -t 的命令,产生/var/run/nginx.pid文件。这时候,nginx没有启动,但我们的启动逻辑会失效
五、Handlers属性
观察当前的 Playbook,细心的你会发现,当我的配置文件没有发生变化时,每次依然都会去触发TASK “reload nginx server”。如何能做到只有配置文件发生变化的时候才去触发TASK “reload nginx server”,这样的处理才是最完美的实现。此时可以使用 handlers 属性
handlers 英 [ˈhændləz] 美 [ˈhændlərz] n.处理程序,经办人
notify 英 [ˈnəʊtɪfaɪ] 美 [ˈnoʊtɪfaɪ] v.(正式)通报,通知
在改进的PlayBook中,针对文件发布TASK 任务 “update nginx main config” 和 “add virtualhost config” 增加了新属性 notify, 值为 “reload nginx server”。它的意思是说,针对这两个文件发布的TASK,设置一个通知机制,当Ansible 认为文件的内容发生了变化(文件MD5发生变化了),它就会发送一个通知信号,通知 handlers 中的某一个任务。具体发送到handlers中的哪个任务,由notify 的值"reload nginx server"决定。通知发出后handlers 会根据发送的通知,在handlers中相关的任务中寻找名称为"reload nginx server" 的任务。当发现存在这样名字的TASK,就会执行它。若没有找到,则什么也不做。若我们要实现这样的机制,千万要注意notify属性设置的值,一定要确保能和handlers中的TASK 名称对应上。修改任何一方的文件都会导致两端的文件不一致,都会触发任务的执行。
- name: test handlershosts: allgather_facts: notasks:- name: copy a file to remote servercopy:src: a.txtdest: /tmp/a.txtnotify:- test ping- ping a remote serverhandlers:- name: ping a remote serverping:- name: test pingping:
...
改进PlayBook
- name: handlers playbook examplehosts: webserversgather_facts: novars:createuser:- tomcat- www- mysqltasks:- name: create useruser: name={{ item }} state=presentwith_items: "{{ createuser }}"- name: yum nginx webserveryum: name=nginx state=present- name: update nginx main configcopy: src=nginx.conf dest=/etc/nginx/tags: updateconfignotify: reload nginx server- name: add virtualhost configcopy: src=www.qfedu.com.conf dest=/etc/nginx/conf.d/tags: updateconfignotify: reload nginx server- name: check nginx syntaxshell: /usr/sbin/nginx -tregister: nginxsyntaxtags: updateconfig- name: check nginx runningstat: path=/var/run/nginx.pidregister: nginxrunningtags: updateconfig- name: start nginx serverservice: name=nginx state=startedwhen:- nginxsyntax.rc == 0- nginxrunning.stat.exists == falsehandlers:- name: reload nginx serverservice: name=nginx state=reloadedwhen:- nginxsyntax.rc == 0- nginxrunning.stat.exists == true
执行**
首次执行,若配置文件没有发生变化,可以发现根本就没有触发handlers 中TASK任务
# ansible-playbook -i hosts site.yml -t updateconfig
人为对Nginx 配置文件稍作修改,只要MD5校验值发生变化即可。此时再执行,发现触发了handlers 中的TASK任务
# ansible-playbook -i hosts site.yml -t updateconfig
六、Ansible中处理失败的任务
1、Ansible管理play中的任务错误的正常逻辑
Ansible评估任务的返回代码,从而确定任务是成功还是失败
通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务,但有些时候,可能希望即使在任务失败时也继续执行play
如果判断任务因为判断失败,被Ansible终止后续play的话,那么判断任务还有什么意义?
2、忽略任务失败 ignore_errors: yes
默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的
tasks:
- name: install httpd
yum:
name: packages //没有这个包
state: present
ignore_errors: yes //可选{yes、no}
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allgather_facts: notasks:- name: install httpdyum:name: packages //没有这个包state: presentignore_errors: yes //可选{yes、no}- name: shoe some massagedebug:msg: "hello word"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [install httpd] ******************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "failures": ["No package packages available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring //已经忽略这个任务出错TASK [shoe some massage] **************************************************************************************************************************************************
ok: [client.example.com] => {"msg": "hello word"
}PLAY RECAP ****************************************************************************************************************************************************************
3、任务失败也强制执行处理程序(handlers)
在play中设置force_handlers: yes关键字,则即使play因为后续任务失败而中止也会调用被通知的处理程序(force:促使,推动)
//查看playbook
[root@localhost project]# cat playbook.yaml
hosts: all
force_handlers: yes //可选{yes、no}
tasks:name: install httpd
shell: ls //这条命令一定会执行成功,从而保证handlers处理程序一定会被触发
notify:- massage
name: install httpd
yum:
name: packages //没有这个包,肯定会出错
state: present
handlers:
- name: massage
debug:
msg: “hello word”
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allforce_handlers: yes //可选{yes、no}tasks:- name: install httpdshell: ls //这条命令一定会执行成功,从而保证handlers处理程序一定会被触发notify:- massage- name: install httpdyum:name: packages //没有这个包,肯定会出错state: presenthandlers:- name: massagedebug:msg: "hello word"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [install httpd] ******************************************************************************************************************************************************
changed: [client.example.com]TASK [install httpd] *****************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"changed": false, "failures": ["No package packages available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}RUNNING HANDLER [massage] *************************************************************************************************************************************************
ok: [client.example.com] => {"msg": "hello word"
}PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
处理程序会在任务报告changed结果时获得通知,而在任务报告ok或failed结果时不会获得通知
4、指定任务失败的条件
在任务中使用failed_when关键字来指定表示任务已失败的条件;通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败
演示实例一:使用failed_when关键字
在playbook中执行脚本会以最后一个命令作为错误判断标准,中间错误命令不会影响整体的出错,同样也不会因为中间出错而报错
//查看使用的脚本
[root@localhost project]# cat files/test.sh
#!/bin/bash
cat /root //这句肯定会出错
echo "hello word"//注意:在playbook中执行脚本会以最后一个命令作为错误判断标准,中间错误命令不会影响整体的出错,同样也不会因为中间出错而报错//查看playbook,执行一次看是否成功
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testscript:files/test.sh
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
changed: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //这样无法判断是否都执行成功//添加任务失败判断语句
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testscript:files/test.shregister: resultfailed_when: "'Is a directory' in result['stdout']"
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to client.example.com closed.\r\n", "stderr_lines": ["Shared connection to client.example.com closed."], "stdout": "cat: /root: Is a directory\r\nhello word\r\n", "stdout_lines": ["cat: /root: Is a directory", "hello word"]}PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
:fail模块也可用于强制任务失败(主要是将杂乱的提示信息通过自己设置提示方式,达到简单、明了的目的)
演示实例二
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testscript:files/test.shregister: result- fail:msg: "There have a failed"when: "'Is a directory' in result['stdout']"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
changed: [client.example.com]TASK [fail] ***************************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"changed": false, "msg": "There have a failed"}PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
5、制定何时任务报告"changed"结果
当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序;如果任务不需要进行更改,则会报告ok并且不通知处理程序
使用changed_when关键字可用于控制任务在何时报告它已进行了更改
演示实例一
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testshell: echo "hello word"//执行后发现,每次都是changed
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
changed: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //添加changed_when关键字,以便报告OK
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testshell: echo "hello word"changed_when: false //可选{true、false}
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
ok: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
根据通过已注册变量收集的模块的输出来报告changed
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: alltasks:- name: testcommand: echo "hello word"register: resultchanged_when: "'hello word' in result['stdout']"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]TASK [test] ***************************************************************************************************************************************************************
changed: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //因为在result['stdout']中有hello word ,所以被认定为是true,所以就显示changed
6、Ansible块和错误处理
1️⃣:在playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式
2️⃣:通过块,也可结合rescue和always语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复
3️⃣:在block子句中的任务以及rescue子句中的任务(如果出现故障)运行之后,always子句中的任务运行
4️⃣:总结:
block:定义要运行的主要任务
rescue:定义要在block子句中定义的任务失败时运行的任务
always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败
5️⃣:演示:
演示实例一:当只有block和rescue,且block语句执行成功时,只执行block语句而不执行rescue语句(rescue:营救、救援)
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allgather_facts: notasks:- name: testblock:- name: blockshell: echo "hello word"rescue:- name: rescueshell: ls /root//执行play
[root@localhost project]# ansible-playbook --syntax-check playbook.yamlplaybook: playbook.yaml
[root@localhost project]# an
anacron ansible-config ansible-console ansible-galaxy ansible-playbook ansible-test
ansible ansible-connection ansible-doc ansible-inventory ansible-pull ansible-vault
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [block] **************************************************************************************************************************************************************
changed: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //可以发现,只执行了block语句,并没有执行rescue语句
演示实例二:当只有block和rescue,且block语句执行失败时,不执行block语句而执行rescue语句
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allgather_facts: notasks:- name: testblock:- name: blockcommand: cat / //这句肯定会失败rescue:- name: rescueshell: ls /root//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [block] **************************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": ["cat", "/"], "delta": "0:00:00.005350", "end": "2020-09-08 10:59:18.381699", "msg": "non-zero return code", "rc": 1, "start": "2020-09-08 10:59:18.376349", "stderr": "cat: /: Is a directory", "stderr_lines": ["cat: /: Is a directory"], "stdout": "", "stdout_lines": []}TASK [rescue] *************************************************************************************************************************************************************
changed: [client.example.com]PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
演示实例三:当block语句、rescue语句和always语句都有时,无论block语句是否失败,always语句总是执行
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allgather_facts: notasks:- name: testblock:- name: blockcommand: cat /rescue:- name: rescueshell: ls /rootalways:- name: alwaysdebug:msg: "This is my test"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [block] **************************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": ["cat", "/"], "delta": "0:00:00.008993", "end": "2020-09-08 11:05:47.816489", "msg": "non-zero return code", "rc": 1, "start": "2020-09-08 11:05:47.807496", "stderr": "cat: /: Is a directory", "stderr_lines": ["cat: /: Is a directory"], "stdout": "", "stdout_lines": []}TASK [rescue] *************************************************************************************************************************************************************
changed: [client.example.com]TASK [always] *************************************************************************************************************************************************************
ok: [client.example.com] => {"msg": "This is my test"
}PLAY RECAP ****************************************************************************************************************************************************************
client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
6️⃣:block中的when条件也会应用到其rescue和always子句(若存在)
演示实例一:
//查看playbook
[root@localhost project]# cat playbook.yaml
---
- hosts: allgather_facts: notasks:- name: testblock:- name: blockcommand: echo "hello word" //该语句没有错误when: ansible_facts['distribution'] == "CentOS" //条件判断出错会导致block语句不会执行rescue:- name: rescueshell: ls /rootalways:- name: alwaysdebug:msg: "This is my test"//执行play
[root@localhost project]# ansible-playbook playbook.yamlPLAY [all] ****************************************************************************************************************************************************************TASK [block] **************************************************************************************************************************************************************
fatal: [client.example.com]: FAILED! => {"msg": "The conditional check 'ansible_facts['distribution'] == \"CentOS\"' failed. The error was: error while evaluating conditional (ansible_facts['distribution'] == \"CentOS\"): 'dict object' has no attribute 'distribution'\n\nThe error appears to be in '/root/project/playbook.yaml': line 7, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: block\n ^ here\n"}TASK [rescue] *************************************************************************************************************************************************************
changed: [client.example.com]TASK [always] *************************************************************************************************************************************************************
ok: [client.example.com] => {"msg": "This is my test"
}PLAY RECAP ****************************************************************************************************************************************************************
Absible#Ansible-Playbook的任务控制相关推荐
- Python+Django+Ansible Playbook自动化运维项目实战(二)
Python+Django+Ansible Playbook自动化运维项目实战 一.资产管理,自动化发现.扫描 1.服务端资产探测.扫描发现 1)资产管理的资产: 2)抽象与约定: 2.探测协议和模块 ...
- Python+Django+Ansible Playbook自动化运维项目实战:资产管理
Python+Django+Ansible Playbook自动化运维项目实战 一.资产管理,自动化发现.扫描 1.服务端资产探测.扫描发现 1)资产管理的资产: 2)抽象与约定: 2.探测协议和模块 ...
- Ansible playbook
1.什么是playbook playbook :定义一个文本文件,以yml为后缀结尾,那playbook组成如下. play:定义的是主机的角色 task: 定义的是具体执行的任务 总结:playbo ...
- ansible playbook详细教程(笔记)
ctrl F 执行playbook命令 ansible playbook -i "inventory文件名" playbook.yml f 10 (并行级别10) 加参 ...
- ansible playbook play常用参数配置
我们知道ansible playbook可由多个play组成,而每个play又可以由多个task组成,如果不熟悉playbook play概念的可参考ansible playbook基本概念 下面是一 ...
- 37: sudo提权 、 Ansible配置 、 Ansible Playbook 、 Ansible进阶 、 总结和答疑
Top NSD AUTOMATION DAY02 案例1:配置sudo权限 案例2:修改Ansible配置 案例3:Playbook应用案例 案例4:Playbook应用案例 1 案例1:配置sudo ...
- CHAPTER 5 Ansible playbook(二)
ansible-playbook 5.1 任务控制 5.1.1 Ansible任务控制基本介绍 5.1.2 条件判断(when) 5.1.3 循环控制(with_items) 5.1.3.1 标准lo ...
- ansible的任务执行控制(循环、条件判定、触发器、处理失败任务)
ansible的任务执行控制 一.循环 1.简单循环 2.循环散列或字典列表 二.条件判定 1.when条件语句 2.条件判断 三.触发器 四. 处理失败任务 1.ignore_errors 2.fo ...
- ansible playbook的使用
一.playbook的使用 1.ansible的playbook与临时命令 临时命令可以对一组目标主机进行一项简单的任务.要发挥ansible的真正力量,还需要了解如何使用playbook轻松的对 ...
- ansible笔记(11):初识ansible playbook(二)
ansible笔记(11):初识ansible playbook(二)有前文作为基础,如下示例是非常容易理解的:--- - hosts: test211remote_user: roottasks:- ...
最新文章
- 查找Linux中内存和CPU使用率最高的进程
- SECRET SHARING STEP BY STEP
- GDCM:gdcm::DataSet的测试程序
- Nginx的反向代理 和 负载均衡
- J2EE第五课Servlet随课笔记
- 欢乐纪中某A and B组赛【2019.1.23】
- Jedis使用java连接Redis
- html5学习笔记---03. Canvas简介,Canvas的使用方法
- c语言如何找一个数的ac码,详细解析C语言中的开方实现
- SpringBoot作mongodb批量更新
- python tkmessagebox_在python中关闭tkmessagebox一段时间后
- STM32开发环境搭建
- python写小说阅读器_用python实现自己的小说阅读器
- ffmpeg h264 h265 视频格式操作
- 20个优秀的 HTML5 网站设计案例欣赏
- java单例模式实例_java 单例模式的实例详解
- LaTeX下载安装及Markdown转PDF方法
- 安装nodejs遇到的坑
- foobar2000使用cue文件播放时出现Unable to open item for playback (Object not found):的问题解决
- 【2018黑龙江省赛】UPC-7222 Overflow(模拟物理水体积)