• Ansible playbook的block


    环境

    • 控制节点:Ubuntu 22.04
    • Ansible 2.10.8
    • 管理节点:CentOS 8

    block

    顾名思义,通过block可以把task按逻辑划分到不同的“块”里面,实现“块操作”。此外,block还提供了错误处理功能。

    task分组

    下面的例子,把3个task放到一个block里面。

    创建文件 testBlock1.yml 如下:

    ---
    - name: testBlock1
      hosts: all
      tasks:
      - name: My task 1
        block:
        - name: Part1
          debug:
            msg: "Hello Zhang San"
    
        - name: Part2
          debug:
            msg: "Hello Li Si"
    
        - name: Part3
          debug:
            msg: "Hello Wang Wu"
        when: 2 > 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行结果如下:

    ➜  temp ansible-playbook testBlock1.yml
    
    PLAY [testBlock1] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Zhang San"
    }
    
    TASK [Part2] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Li Si"
    }
    
    TASK [Part3] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Wang Wu"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    如果把block的判断条件 when: 2 > 1 改为 when: 2 == 1 ,则运行结果如下:

    ➜  temp ansible-playbook testBlock1.yml
    
    PLAY [testBlock1] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [Part2] ***************************************************************************************
    skipping: [192.168.1.55]
    
    TASK [Part3] ***************************************************************************************
    skipping: [192.168.1.55]
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=1    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可见,由于条件不满足,block里的3个task都没有执行。

    错误处理

    如果block里的某个task出错了,则后面的task不再运行。

    创建文件 testBlock2.yml 如下:

    ---
    - name: testBlock2
      hosts: all
      tasks:
      - name: My task 1
        block:
        - name: Part1
          debug:
            msg: "Hello Zhang San"
    
        - name: Part2
          command: /bin/false # will trigger an error
    
        - name: Part3
          debug:
            msg: "Hello Li Si"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行结果如下:

    ➜  temp ansible-playbook testBlock2.yml
    
    PLAY [testBlock2] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Zhang San"
    }
    
    TASK [Part2] ***************************************************************************************
    fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001904", "end": "2023-10-26 08:50:36.850526", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 08:50:36.848622", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可见,由于Part2出错,Part3并没有运行。

    Ansible的错误处理有两个关键字:

    • rescue :类似于 catch
    • always :类似于 finally

    先加上 always 看看效果:

    ---
    - name: testBlock2
      hosts: all
      tasks:
      - name: My task 1
        block:
        - name: Part1
          debug:
            msg: "Hello Zhang San"
    
        - name: Part2
          command: /bin/false # will trigger an error
    
        - name: Part3
          debug:
            msg: "Hello Li Si"
        always:
        - name: Always do this
          debug:
            msg: "End End End"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    ➜  temp ansible-playbook testBlock2.yml
    
    PLAY [testBlock2] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Zhang San"
    }
    
    TASK [Part2] ***************************************************************************************
    fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.002734", "end": "2023-10-26 08:52:19.329781", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 08:52:19.327047", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
    
    TASK [Always do this] ******************************************************************************
    ok: [192.168.1.55] => {
        "msg": "End End End"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=3    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    可见,Part2出错, always 也会运行(当然,Part3不会运行)。

    注意:加上 always ,failed仍然是1。

    现在来试一下 rescue

    ---
    - name: testBlock2
      hosts: all
      tasks:
      - name: My task 1
        block:
        - name: Part1
          debug:
            msg: "Hello Zhang San"
    
        - name: Part2
          command: /bin/false # will trigger an error
    
        - name: Part3
          debug:
            msg: "Hello Li Si"
        always:
        - name: Always do this
          debug:
            msg: "End End End"
        rescue:
        - name: Rescue tasks
          debug:
            msg: "Something is wrong!"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行结果如下:

    ➜  temp ansible-playbook testBlock2.yml
    
    PLAY [testBlock2] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Hello Zhang San"
    }
    
    TASK [Part2] ***************************************************************************************
    fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001726", "end": "2023-10-26 09:00:01.785445", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 09:00:01.783719", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
    
    TASK [Rescue tasks] ********************************************************************************
    ok: [192.168.1.55] => {
        "msg": "Something is wrong!"
    }
    
    TASK [Always do this] ******************************************************************************
    ok: [192.168.1.55] => {
        "msg": "End End End"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注意,always是在rescue之后运行的(Part3仍然不会运行)。

    注:如果task没有出错, rescue 不会被触发。

    rescue与handler

    我们知道,当task运行成功,状态改变时,可以用 notify 来触发handler。但如果后续的task出错了,则当前task的handler并不会触发。如果有 rescue ,则handler仍然会被触发(在 always 之后)。在 rescue 中可以通过 meta: flush_handlers 来立即触发handler(在 always 之前)。

    ---
    - name: testBlock2
      hosts: all
      tasks:
      - name: My task 1
        block:
        - name: Part1
          debug:
            msg: "Hello Zhang San"
          changed_when: true
          notify: Run me even after an error
    
        - name: Part2
          command: /bin/false # will trigger an error
    
        - name: Part3
          debug:
            msg: "Hello Li Si"
        always:
        - name: Always do this
          debug:
            msg: "End End End"
        rescue:
        - name: Rescue tasks
          #debug:
          #  msg: "Something is wrong!"
          meta: flush_handlers
      handlers:
      - name: Run me even after an error
        debug:
          msg: 'This handler runs even on error'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行结果如下:

    ➜  temp ansible-playbook testBlock2.yml
    
    PLAY [testBlock2] **********************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [Part1] ***************************************************************************************
    changed: [192.168.1.55] => {
        "msg": "Hello Zhang San"
    }
    
    TASK [Part2] ***************************************************************************************
    fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.002172", "end": "2023-10-26 09:11:26.530609", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 09:11:26.528437", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
    
    RUNNING HANDLER [Run me even after an error] *******************************************************
    ok: [192.168.1.55] => {
        "msg": "This handler runs even on error"
    }
    
    TASK [Always do this] ******************************************************************************
    ok: [192.168.1.55] => {
        "msg": "End End End"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    本例中,Part1运行成功,且改变了状态,所以触发了handler Run me even after an error 。但由于Part2出错,如果没有 rescue ,则Part1的handler不会触发。加上 rescue 之后,就会触发Part1的handler。本例中加上了 meta: flush_handlers ,所以会立即触发handler。

    参考

    • https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html
  • 相关阅读:
    基于JAVA+SpringMVC+Mybatis+MYSQL的家庭理财管理系统
    verilog中$monitor 的用法
    Flutter实战-请求封装(一)
    创新案例分享 | 建设交通运输管理信息系统,全面提升执法能力
    测试员:“我有五年测试经验”HR: “不,你只是把一年的工作经验用了五年”
    GitHub和Gitee的区别以及具体使用
    【python经验总结】我与bug的那些日子
    QGIS提取两条线元素的交点
    纯c#运行开源本地大模型Mixtral-8x7B
    C语言深度解析:函数的形参和实参与传值和传址(多角度分析,让你有一种相见恨晚的感觉!!!!)
  • 原文地址:https://blog.csdn.net/duke_ding2/article/details/134047516