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的任务控制相关推荐

  1. Python+Django+Ansible Playbook自动化运维项目实战(二)

    Python+Django+Ansible Playbook自动化运维项目实战 一.资产管理,自动化发现.扫描 1.服务端资产探测.扫描发现 1)资产管理的资产: 2)抽象与约定: 2.探测协议和模块 ...

  2. Python+Django+Ansible Playbook自动化运维项目实战:资产管理

    Python+Django+Ansible Playbook自动化运维项目实战 一.资产管理,自动化发现.扫描 1.服务端资产探测.扫描发现 1)资产管理的资产: 2)抽象与约定: 2.探测协议和模块 ...

  3. Ansible playbook

    1.什么是playbook playbook :定义一个文本文件,以yml为后缀结尾,那playbook组成如下. play:定义的是主机的角色 task: 定义的是具体执行的任务 总结:playbo ...

  4. ansible playbook详细教程(笔记)

    ctrl F  执行playbook命令   ansible ­playbook -­i "inventory文件名" playbook.yml ­f 10 (并行级别10) 加参 ...

  5. ansible playbook play常用参数配置

    我们知道ansible playbook可由多个play组成,而每个play又可以由多个task组成,如果不熟悉playbook play概念的可参考ansible playbook基本概念 下面是一 ...

  6. 37: sudo提权 、 Ansible配置 、 Ansible Playbook 、 Ansible进阶 、 总结和答疑

    Top NSD AUTOMATION DAY02 案例1:配置sudo权限 案例2:修改Ansible配置 案例3:Playbook应用案例 案例4:Playbook应用案例 1 案例1:配置sudo ...

  7. 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 ...

  8. ansible的任务执行控制(循环、条件判定、触发器、处理失败任务)

    ansible的任务执行控制 一.循环 1.简单循环 2.循环散列或字典列表 二.条件判定 1.when条件语句 2.条件判断 三.触发器 四. 处理失败任务 1.ignore_errors 2.fo ...

  9. ansible playbook的使用

    一.playbook的使用 1.ansible的playbook与临时命令 ​ 临时命令可以对一组目标主机进行一项简单的任务.要发挥ansible的真正力量,还需要了解如何使用playbook轻松的对 ...

  10. ansible笔记(11):初识ansible playbook(二)

    ansible笔记(11):初识ansible playbook(二)有前文作为基础,如下示例是非常容易理解的:--- - hosts: test211remote_user: roottasks:- ...

最新文章

  1. 查找Linux中内存和CPU使用率最高的进程
  2. SECRET SHARING STEP BY STEP
  3. GDCM:gdcm::DataSet的测试程序
  4. Nginx的反向代理 和 负载均衡
  5. J2EE第五课Servlet随课笔记
  6. 欢乐纪中某A and B组赛【2019.1.23】
  7. Jedis使用java连接Redis
  8. html5学习笔记---03. Canvas简介,Canvas的使用方法
  9. c语言如何找一个数的ac码,详细解析C语言中的开方实现
  10. SpringBoot作mongodb批量更新
  11. python tkmessagebox_在python中关闭tkmessagebox一段时间后
  12. STM32开发环境搭建
  13. python写小说阅读器_用python实现自己的小说阅读器
  14. ffmpeg h264 h265 视频格式操作
  15. 20个优秀的 HTML5 网站设计案例欣赏
  16. java单例模式实例_java 单例模式的实例详解
  17. LaTeX下载安装及Markdown转PDF方法
  18. 安装nodejs遇到的坑
  19. foobar2000使用cue文件播放时出现Unable to open item for playback (Object not found):的问题解决
  20. 【2018黑龙江省赛】UPC-7222 Overflow(模拟物理水体积)

热门文章

  1. RDD优化--RDD共享变量(广播变量与累加器)
  2. 「学IT一定要看」一些学习的建议
  3. 恺撒密码的python实现介绍
  4. 6.1 CUDA: pinned memory固定存储
  5. docer启动一个容器时的过程
  6. 怎么设置企业邮箱服务器端口,腾讯企业邮箱服务器配置及端口号设置
  7. AARRR模型是什么?
  8. 3d建模软件安装教程,游戏建模必备软件推荐(收藏)
  9. matlab 非线性方程组 最小值,如何在matlab中求解非线性方程组的参数值
  10. 什么是机器人,机器人的发展主要经历哪几个历史阶段?