实施任务控制

实施任务控制

编写循环和条件任务

利用循环迭代任务

通过利用循环,我们无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。

Ansible支持使用loop关键字对一组项目迭代任务。可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。

简单循环

简单循环对一组项目迭代任务。loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。

创建用户不用循环
[root@control book]# cat   debug/loop.yml---
- name: look
  hosts: server1
  tasks:
    - name: cat  loop
      user: 
        name: tom
        uid: 1201
        state: present 

[root@server1 ~]# id  tom
uid=1201(tom) gid=1201(tom) groups=1201(tom)

用循环创建用户
[root@control book]# cat   debug/loop.yml 
---
- name: look
  hosts: server1
  tasks:
    - name: cat  loop
      user: 
        name: '{{ item  }}'
        state: present 

      loop:
        - time1
        - time2
        - time3

[root@control book]# ansible-playbook debug/loop.yml   

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  loop] ***************************************************************
changed: [192.168.56.130] => (item=time1)
changed: [192.168.56.130] => (item=time2)
changed: [192.168.56.130] => (item=time3)

PLAY RECAP *********************************************************************
192.168.56.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

//查看结果

[root@server1 ~]# id  time1
uid=1202(time1) gid=1202(time1) groups=1202(time1)
[root@server1 ~]# id  time2
uid=1203(time2) gid=1203(time2) groups=1203(time2)
[root@server1 ~]# id  time3
uid=1204(time3) gid=1204(time3) groups=1204(time3)
在循环里使用变量
---
- name: look
  hosts: server1
  vars_files:         //局外变量模块
    - /opt/book/debug/users.yml   //变量文件地址
  tasks:
    - name: cat  loop
      user:                   //创建用户模块
        name: '{{ item  }}'    //loop循环关键字
        state: present
      loop: "{{ users  }}"     //引用变量


//创建变量文件
[root@control book]# cat   debug/users.yml 
users: 
 - time1
 - time2
 - time3
 - time4

//运行
[root@control book]# ansible-playbook debug/loop.yml 

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  loop] ***************************************************************
changed: [192.168.56.130] => (item=time1)
changed: [192.168.56.130] => (item=time2)
changed: [192.168.56.130] => (item=time3)
changed: [192.168.56.130] => (item=time4)

PLAY RECAP *********************************************************************
192.168.56.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


//查看结果
[root@server1 ~]# id  time1
uid=1001(time1) gid=1001(time1) groups=1001(time1)
[root@server1 ~]# id  time2
uid=1002(time2) gid=1002(time2) groups=1002(time2)
[root@server1 ~]# id  time3
uid=1003(time3) gid=1003(time3) groups=1003(time3)
[root@server1 ~]# id  time4
uid=1004(time4) gid=1004(time4) groups=1004(time4)
循环散列或字典表

loop列表不需要是简单值列表。在以下示例中,列表中的每个项实际上是散列或字典。示例中的每个散列或字典具有两个键,即namegroups,当前item循环变量中每个键的值可以分别通过item.nameitem.groups变量来检索。

//编写变量文件
[root@control book]# cat debug/users.yml 
users: 
 - name: time1
   uid: 2000
 - name: time2
   uid: 2001
 - name: time3
   uid: 2002


[root@control book]# cat debug/loop.yml 
---
- name: look
  hosts: server1
  vars_files:
    - /opt/book/debug/users.yml
  tasks:
    - name: cat  loop
      user: 
        name: "{{ item.name  }}"
        uid: "{{ item.uid  }}"
        state: present 
      loop: "{{ users  }}"

//执行
[root@control book]# ansible-playbook debug/loop.yml 

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  loop] ***************************************************************
changed: [192.168.56.130] => (item={'name': 'time1', 'uid': 2000})
changed: [192.168.56.130] => (item={'name': 'time2', 'uid': 2001})
changed: [192.168.56.130] => (item={'name': 'time3', 'uid': 2002})

PLAY RECAP *********************************************************************
192.168.56.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


//结果
[root@server1 ~]# id  time1
uid=2000(time1) gid=2000(time1) groups=2000(time1)
[root@server1 ~]# id  time2
uid=2001(time2) gid=2001(time2) groups=2001(time2)
[root@server1 ~]# id  time3
uid=2002(time3) gid=2002(time3) groups=2002(time3)
将Register变量与Loop一起使用

register关键字也可以捕获循环任务的输出。以下代码片段显示了循环任务中register变量的结构:

[root@control book]# cat   debug/loop.yml ---
- name: look
  hosts: server1
  tasks:
    - name: cat  loop
      command: "echo hello {{ item  }} ,your  name?"  
      loop:         //循环
        - lisi
        - wangwu
        - xiaohong
      register: result       //注册变量

    - debug:           //收集事实模块        
        var: result     //输出指定事实

//在debug   var中不用加 "{{}}"  /大括号

[root@control book]# ansible-playbook debug/loop.yml 

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  loop] ***************************************************************
changed: [192.168.56.130] => (item=lisi)
changed: [192.168.56.130] => (item=wangwu)
changed: [192.168.56.130] => (item=xiaohong)

TASK [debug] *******************************************************************
ok: [192.168.56.130] => {
    "result": {
        "changed": true,
        "msg": "All items completed",
        "results": [
            {
                "ansible_loop_var": "item",
                "changed": true,
                "cmd": [
                    "echo",
                    "hello",
                    "lisi",
                    ",your",
                    "name?"
                ],
                "delta": "0:00:00.002498",
                "end": "2021-07-25 12:47:50.353290",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo hello lisi ,your  name?",
                        "_uses_shell": false,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "stdin_add_newline": true,
                        "strip_empty_ends": true,
                        "warn": true
                    }
                },
                "item": "lisi",
                "rc": 0,
                "start": "2021-07-25 12:47:50.350792",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "hello lisi ,your name?",
                "stdout_lines": [
                    "hello lisi ,your name?"
                ]
            },
            {
                "ansible_loop_var": "item",
                "changed": true,
                "cmd": [
                    "echo",
                    "hello",
                    "wangwu",
                    ",your",
                    "name?"
                ],
                "delta": "0:00:00.001697",
                "end": "2021-07-25 12:47:50.551735",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo hello wangwu ,your  name?",
                        "_uses_shell": false,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "stdin_add_newline": true,
                        "strip_empty_ends": true,
                        "warn": true
                    }
                },
                "item": "wangwu",
                "rc": 0,
                "start": "2021-07-25 12:47:50.550038",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "hello wangwu ,your name?",
                "stdout_lines": [
                    "hello wangwu ,your name?"
                ]
            },
            {
                "ansible_loop_var": "item",
                "changed": true,
                "cmd": [
                    "echo",
                    "hello",
                    "xiaohong",
                    ",your",
                    "name?"
                ],
                "delta": "0:00:00.001758",
                "end": "2021-07-25 12:47:50.751189",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo hello xiaohong ,your  name?",
                        "_uses_shell": false,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "stdin_add_newline": true,
                        "strip_empty_ends": true,
                        "warn": true
                    }
                },
                "item": "xiaohong",
                "rc": 0,
                "start": "2021-07-25 12:47:50.749431",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "hello xiaohong ,your name?",
                "stdout_lines": [
                    "hello xiaohong ,your name?"
                ]
            }
        ]
    }
}


有条件地运行任务

Ansible可使用conditionals在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。

我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。

以下场景说明了在Ansible中使用条件的情况:

  • 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
  • Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
  • 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
  • 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
  • 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
条件语法

when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。

可以测试的一个最简单条件是某一布尔变量是True还是False。以下示例中的when语句导致任务仅在run_my_taskTrue时运行:

[root@control book]# cat  debug/us.yml 
---
- name: look
  hosts: server1
  vars_files:
    - /opt/book/debug/users.yml
  vars:
    power: False        //布尔值 否
  tasks:
    - name: cat  where
      user:
        name: "{{ item.name  }}"
        uid: "{{ item.uid  }}"
        state: present 
      loop: "{{ users  }}"
      when: power


[root@control book]# ansible-playbook debug/us.yml 

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  where] **************************************************************
skipping: [192.168.56.130] => (item={'name': 'time1', 'uid': 2000}) 
skipping: [192.168.56.130] => (item={'name': 'time2', 'uid': 2001}) 
skipping: [192.168.56.130] => (item={'name': 'time3', 'uid': 2002}) 
//略过
PLAY RECAP *********************************************************************
192.168.56.130             : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

[root@control debug]# cat users.yml 
users: 
 - name: time1
   uid: 2000
 - name: time2
   uid: 2001
 - name: time3
   uid: 2002


[root@control book]# cat  debug/us.yml 
---
- name: look
  hosts: server1
  vars_files:
    - /opt/book/debug/users.yml
  tasks:
    - name: cat  where
      user:
        name: "{{ item.name  }}"
        uid: "{{ item.uid  }}"
        state: present 
      loop: "{{ users  }}"
      when: '"{{ item.name }}"  ==  "time1"' //只允许time1执行

//运行结果
[root@control book]# ansible-playbook debug/us.yml 

PLAY [look] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.130]

TASK [cat  where] **************************************************************
[WARNING]: conditional statements should not include jinja2 templating
delimiters such as {{ }} or {% %}. Found: "{{ item.name }}"  ==  "time1"
changed: [192.168.56.130] => (item={'name': 'time1', 'uid': 2000})   //通过
skipping: [192.168.56.130] => (item={'name': 'time2', 'uid': 2001}) 
skipping: [192.168.56.130] => (item={'name': 'time3', 'uid': 2002}) 

PLAY RECAP *********************************************************************
192.168.56.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


[root@server1 ~]# id  time1
uid=2000(time1) gid=2000(time1) groups=2000(time1)

以下示例测试my_service变量是否具有值。若有值,则将my_service的值用作要安装的软件包的名称。如果未定义my_service变量,则跳过任务且不显示错误。

[root@control book]# cat  debug/us.yml 
---
- name: look
  hosts: server1
  vars_files:
    - /opt/book/debug/users.yml
  tasks:
    - name: cat  where
      user:
        name: "{{ users.name }}"
        state: present 
      when: user is  defined  //只执行变量存在的值

下表显示了在处理条件时可使用的一些运算:

示例条件

操作示例
等于(值为字符串)ansible_machine == “x86_64”
等于(值为数字)max_memory == 512
小于min_memory < 128
大于min_memory > 256
小于等于min_memory <= 256
大于等于min_memory >= 512
不等于min_memory != 512
变量存在min_memory is defined
变量不存在min_memory is not defined
布尔变量是True。1、True或yes的求值为Truememory_available
布尔变量是False。0、False或no的求值为Falsenot memory_available
第一个变量的值存在,作为第二个变量的列表中的值ansible_distribution in supported_distros

上表中的最后一个条目初看起来有些令人困惑。下例演示了它的工作原理。

在示例中,ansible_distribution变量是在Gathering Facts任务期间确定的事实,用于标识托管主机的操作系统分支。变量supported_distrosplaybook创建,包含该playbook支持的操作系统分发列表。如果ansible_distribution的值在supported_distros列表中,则条件通过且任务运行。

---
- name:
  hosts: server2
  vars:
    platform:         //定义变量
      - redhat
      - CentOS
  tasks:
    - name: test
      yum:
        name: vsftpd
        state: present
      when: ansible_facts['distribution'] in platform
//when  里面不用加大括号

注意when语句的缩进。由于when语句不是模块变量,它必须通过缩进到任务的最高级别,放置在模块的外面。

任务是YAML散列/字典,when语句只是任务中的又一个键,就如任务的名称以及它所使用的模块一样。通常的惯例是将可能存在的任何when关键字放在任务名称和模块(及模块参数)的后面。

测试多个条件

一个when语句可用于评估多个条件。使用andor关键字组合条件,并使用括号分组条件。

如果任意一条为真实满足条件时,应当使用or

如果任何条件都要满足时用 ,应当用and

when:   x=True    or   y=False
when:   x=True    and   y=True

when使用and运算符用列表表示

when:
  - x=True
  - y=True

这种格式提高了可读性,而可读性是良好编写Ansible Playbook的关键目标。

通过使用括号分组条件,可以表达更复杂的条件语句

when: >
  ( x=True )
  or
  ( y=False )

实施处理程序

ansible处理程序

处理程序是响应是由其他任务出发的任务通知。仅当任务在受管主机上更改了某些内容时,任务才通知其处理程序。每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。因为处理程序就是任务,所以可以在处理程序中使用他们将用于任何其他任务的模块。通常而言,处理程序被用于重新引导主机和重启服务。

处理程序可视为非活动任务,只有在使用notify语句显式调用时才会被触发。在下列代码片段中,只有配置文件更新并且通知了该任务,restart apache处理程序才会重启Apache服务器:

---
- hosts: server4
  tasks:
    - name: install  apache
      yum:
        name: httpd
        state: present
        
    - name: config httpd
      copy:
        src: /opt/book/notify/httpd-vhosts.conf 
        dest: /etc/httpd/conf.d/vhosts.conf
      notify:            //notify语句指出该任务需要触发一个处理程序
        - restart httpd   //要运行的处理程序的名称

    - name: service for httpd
      service:
        name: httpd
        state: restarted
        enabled: yes

  handlers:       //handlers关键字表示处理程序任务列表的开头
    - name: restart httpd    # 被任务调用的处理程序的名称
      service:         # 用于该处理程序的模块
        name: httpd
        state: restarted
使用处理程序的好处

使用处理程序时需要牢记几个重要事项:

  • 处理程序始终按照playhandlers部分指定的顺序运行。它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行。
  • 处理程序通常在相关play中的所有其他任务完成后运行。playbooktasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行。
  • 处理程序名称存在于各play命名空间中。如果两个处理程序被错误地给予相同的名称,则仅会运行一个。
  • 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。
  • 如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知。处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序。

处理程序用于在任务对受管主机进行更改时执行额外操作。它们不应用作正常任务的替代。

处理任务失败

管理play中的任务错误

Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务。

但有些时候,可能希望即使在任务失败时也继续执行play。例如,或许预期待定任务有可能会失败,并且希望通过有条件地运行某项其他任务来修复。

Ansible有多种功能可用于管理任务错误。

忽略任务失败

默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。

下列代码片段演示了如何在任务中使用ignore_errors,以便在任务失败时也继续在主机上执行playbook。例如,如果notapkg软件包不存在,则yum模块将失败,但若将ignore_errors设为yes,则执行将继续。

[root@control book]# cat  notify/notify.yml 
---
- hosts: server4
  gather_facts: no
  tasks:
    - name: install  apache
      yum:
        name: httpd2       //错误安装服务
        state: present
      ignore_errors: yes     //如果任务执行失败忽略此任务

    - name: config httpd
      copy:
        src: /opt/book/notify/httpd-vhosts.conf 
        dest: /etc/httpd/conf.d/vhosts.conf
      notify:
        - restart httpd

    - name: service for httpd
      service:
        name: httpd
        state: restarted
        enabled: yes

  handlers:
    - name: restart httpd
      service: 
        name: httpd
        state: restarted

//执行结果
[root@control book]# ansible-playbook notify/notify.yml 

PLAY [server4] *****************************************************************

TASK [install  apache]           *********************************************************
fatal: [192.168.56.133]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "failures": ["No package httpd2 available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring
                              //任务失败忽略了安装任务
TASK [config httpd] ************************************************************
ok: [192.168.56.133]

TASK [service for httpd] *******************************************************
changed: [192.168.56.133]

PLAY RECAP *********************************************************************
192.168.56.133             : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   

任务失败后强制执行处理程序

通常而言,如果任务失败并且play在该主机上中止,则收到play中早前任务通知的处理程序将不会运行。如果在play中设置force_handlers: yes关键字,则即使play因为后续任务失败而中止也会调用被通知的处理程序。

下列代码片段演示了如何在play中使用force_handlers关键字,以便在任务失败时也强制执行相应的处理程序:

[root@control book]# cat   notify/notify.yml 
---
- hosts: server4
  gather_facts: no
  force_handlers: yes    //如果任务失败强制执行处理程序handlers
  tasks:
    - name: install  apache
      yum:
        name: httpd2   //错误安装服务
        state: present

    - name: config httpd
      copy:
        src: /opt/book/notify/httpd-vhosts.conf 
        dest: /etc/httpd/conf.d/vhosts.conf
      notify:
        - restart httpd

    - name: service for httpd
      service:
        name: httpd
        state: restarted
        enabled: yes

  handlers:
    - name: restart httpd
      service: 
        name: httpd
        state: restarted

//处理结果
[root@control book]# ansible-playbook notify/notify.yml 

PLAY [server4] *****************************************************************

TASK [install  apache] *********************************************************
fatal: [192.168.56.133]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "failures": ["No package httpd2 available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}

PLAY RECAP *********************************************************************
192.168.56.133             : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   


请记住,处理程序会在任务报告changed结果时获得通知,而在任务报告okfailed结果时不会获得通知。

指定任务失败条件

可以在任务中使用failed_when关键字来指定表示任务已失败的条件。这通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败。

例如,可以运行输出错误消息的脚本,并使用该消息定义任务的失败状态。下列代码片段演示了如何在任务中使用failed_when关键字

//在受控主机上写一个脚本
[root@server4 ~]# cat  ti.sh 
#!/bin/bash

useradd tom
echo  "123" | passwd --stdin  tom



//在控制主机上写playbook
[root@control book]# cat  debug/when.yml 
---
- hosts: server4
  tasks:
    - name: debug   when
      command: /root/ti.sh
      register: result  //自定注册变量   把结果赋值给注册变量
    - debug:
      var: result    //输出注册变量
//执行结构
[root@control book]# ansible-playbook debug/when.yml 

PLAY [server4] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.133]

TASK [debug   when] ************************************************************
changed: [192.168.56.133]

TASK [debug] *******************************************************************
ok: [192.168.56.133] => {
    "result": {
        "changed": true,
        "cmd": [
            "/root/ti.sh"
        ],
        "delta": "0:00:00.074483",
        "end": "2021-07-27 11:34:51.553113",
        "failed": false,
        "rc": 0,
        "start": "2021-07-27 11:34:51.478630",
        "stderr": "useradd: user 'tom' already exists",
        "stderr_lines": [
            "useradd: user 'tom' already exists"
        ],
        "stdout": "Changing password for user tom.\npasswd: all authentication tokens updated successfully.",
        "stdout_lines": [
            "Changing password for user tom.",
            "passwd: all authentication tokens updated successfully."
        ]
    }
}

PLAY RECAP *********************************************************************
192.168.56.133             : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


//修改文件
[root@control book]# cat  debug/when.yml 
---
- hosts: server4
  tasks:
    - name: debug   when
      command: /root/ti.sh
      register: result       //把输出的结果注册变量result
      failed_when: "'already' in result.stderr"
//在变量result.stderr中查找是否有'already' 如果有则任务失败

//执行结果
[root@control book]# ansible-playbook debug/when.yml 

PLAY [server2] *****************************************************************

TASK [Gathering Facts] *********************************************************
fatal: [192.168.56.131]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.56.131 port 22: No route to host", "unreachable": true}
                   //执行失败
PLAY RECAP *********************************************************************
192.168.56.131             : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   


fail模块也可用于强制任务失败。上面的场景也可以编写为两个任务:

[root@control book]# cat   debug/when.yml 
---
- hosts: server4
  tasks:
    - name: debug   when
      command: /root/ti.sh
      register: result
      ignore_errors: yes  //如果任务执行失败忽略此任务

    - name: look
      fail:                    //强制任务失败
        msg: "用户已经创建"       //输出
      when: "'already' in result.stderr"  条件
 
//执行结果
[root@control book]# ansible-playbook debug/when.yml 

PLAY [server4] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.56.133]

TASK [debug   when] ************************************************************
changed: [192.168.56.133]

TASK [look] ********************************************************************
fatal: [192.168.56.133]: FAILED! => {"changed": false, "msg": "用户已经创建"}

PLAY RECAP *********************************************************************
192.168.56.133             : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   


指定何时任务报告 “Changed” 结果

当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。

changed_when关键字可用于控制任务在何时报告它已进行了更改。例如,下一示例中的shell模块将用于获取供后续任务使用的Kerberos凭据。它通常会在运行时始终报告changed。为抵制这种更改,应设置changed_when: false,以便它仅报告okfailed

[root@control book]# cat  debug/en.yml 
---
- hosts: server4
  gather_facts: no
  tasks:
    - name:   when
      shell: echo "redaht" | passwd --stdin tom
      register: result    //定义注册变量
      notify:        
        - print info
  handlers:
    - name: print info
      debug:
        msg: "密码设置成功"

[root@control book]# ansible-playbook debug/en.yml 

PLAY [server4] *****************************************************************

TASK [when] ********************************************************************
changed: [192.168.56.133]

RUNNING HANDLER [print info] ***************************************************
ok: [192.168.56.133] => {
    "msg": "密码设置成功"
}

PLAY RECAP *********************************************************************
192.168.56.133             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


以下示例使用shell模块,根据通过已注册变量收集的模块的输出来报告changed

- hosts: server4
  gather_facts: no
  tasks:
    - name:   when
      shell: echo "redaht" | passwd --stdin tom
      register: result   //注册变量
      changed_when: "'successfully' not in result.stdout"
      notify:     //notify语句指出该任务需要触发一个处理程序
        - print info     要运行的处理程序的名称
  handlers:          //执行触发程序
    - name: print info
      debug:
        msg: "密码设置成功"


[root@control book]# ansible-playbook debug/when.yml 

PLAY [server4] *****************************************************************

TASK [when] ********************************************************************
ok: [192.168.56.133]

PLAY RECAP *********************************************************************
192.168.56.133             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


Ansible块和错误处理

playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式。任务块可以含有when关键字,以将某一条件应用到多个任务。

- name: block 
  hosts: server4
  tasks:
    - name: install
      block:
      - name: package needed by yum
        yum:
          name: yum-plugin-versionlock
          state: present
      - name: lock version of tadata
        lineinfile:
          dest: /etc/yum/pluginconf.d/versionlock.list
          line: tzdata-2020j-1
          state: present
      when: ansible_distribution == "Redhat"

通过块,也可结合rescuealways语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障)运行之后,always子句中的任务运行。总结:

  • block:定义要运行的主要任务
  • rescue:定义要在block子句中定义的任务失败时运行的任务
  • always:定义始终都独立运行的任务,不论blockrescue子句中定义的任务是成功还是失败
[root@control book]# cat  block/block.yml ---
- hosts: server4
  tasks:
    - name: useradd 
      block:
        - name: useradd  time1        
          user:
            name: time1
            state: present
      rescue:
         - name: useradd time2
           user:
             name: time2
             state: present

      always:
        - name: useradd time3
          user:
            name: time3
            state: present


//执行结果
[root@server4 ~]# id  time1
uid=1002(time1) gid=1002(time1) groups=1002(time1)
[root@server4 ~]# id  time2
id: 'time2': no such user
[root@server4 ~]# id  time3
uid=1003(time3) gid=1003(time3) groups=1003(time3)

在ansible块中如果block执行成功则rescue不会执行,反之block执行失败则rescue会执行,always必定执行

block中的when条件也会应用到其rescue和always子句(若存在)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值