当前位置: 首页 > article >正文

Ansible的handler

环境

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

handler

当任务结果产生变化时,通过 notify 通知handler做相应处理。

一个简单例子

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify:
        - handler1

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

注意:只有task产生变化时,才会触发notify。由于debug语句不产生变化,所以指定 changed_when: true ,强制task1产生变化。

一个复杂例子

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify:
        - handler2
        - handler1

    - name: task3
      debug:
        msg: "I am task3"

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"
    
    - name: handler2
      debug:
        msg: "I am handler2"

运行结果如下:

TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am task3"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

RUNNING HANDLER [handler2] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler2"
}

可见:

  1. 一个task可以nofiy多个handler
  2. 多个handler的运行顺序和notify时的顺序无关,只和handler本身的顺序有关(本例中,notify的顺序是handler2在handler1之前,但运行时是按handler本身的顺序,handler1在handler2之前)
  3. handler在所有task运行结束之后才运行(本例中,task2 notify了handler,但handler是在task3之后才运行的)
---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify:
        - handler1

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify:
        - handler1

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

可见,若多个task notify同一个handler,该handler只会运行一次。

通过 listen 匹配topic

前面的例子,在notify时,是通过handler的 name 来匹配topic的。也可以通过handler的 listen 来匹配:

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify:
        - task1 changed

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify:
        - task2 changed

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"
      listen:
        - "task2 changed"
        - "task1 changed"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

可见,通过 listen ,一个handler可以监听多个nofiy的topic。

考一考

下面的play,运行结果是什么?

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify:
        - task1 changed

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify:
        - task2 changed

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"
      listen: "task2 changed"

    - name: handler2
      debug:
        msg: "I am handler2"
      listen:
        - "task2 changed"
        - "task1 changed"

    - name: handler3
      debug:
        msg: "I am handler3"
      listen: "task1 changed"

答:运行结果为:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

RUNNING HANDLER [handler2] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler2"
}

RUNNING HANDLER [handler3] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler3"
}

立即运行handler

前面提到,handler是在所有task运行结束后才运行的。如果想要立即运行handler,可用 meta: flush_handlers

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify: handler2

    - name: flush
      meta: flush_handlers

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify: handler1

    - name: task3
      debug:
        msg: "I am task3"

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"

    - name: handler2
      debug:
        msg: "I am handler2"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [flush] ***************************************************************************************

RUNNING HANDLER [handler2] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler2"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am task3"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

可见,flush之后,handler2立即运行了,而handler1则是在所有task都运行结束之后才运行的。

注意:flush触发运行的handler,如果随后又被notify,还会再次运行:

---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify: handler1

    - name: flush
      meta: flush_handlers

    - name: task2
      debug:
        msg: "I am task2"
      changed_when: true
      notify: handler1

  handlers:
    - name: handler1
      debug:
        msg: "I am handler1"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

TASK [flush] ***************************************************************************************

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

TASK [task2] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task2"
}

RUNNING HANDLER [handler1] *************************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

可见,handler1运行了两次。

handler的命名最好不要包含变量

---
- hosts: all
  vars:
    var1: "aaa"
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify: handler {{ var1 }}

  handlers:
    - name: handler {{ var1 }}
      debug:
        msg: "I am handler1"

运行结果如下:

TASK [task1] ***************************************************************************************
changed: [192.168.1.55] => {
    "msg": "I am task1"
}

RUNNING HANDLER [handler aaa] **********************************************************************
ok: [192.168.1.55] => {
    "msg": "I am handler1"
}

没有问题。但是,这里有个潜在的问题:

---
- hosts: all
  #vars:
  #  var1: "aaa"
  tasks:
    - name: task0
      set_fact:
        var1: "aa"

    - name: task1
      debug:
        msg: "I am task1"
      changed_when: true
      notify: handler {{ var1 }} # 可以识别

  handlers:
    - name: handler {{ var1 }} # 无法识别
      debug:
        msg: "I am handler1"

运行结果如下:

TASK [task0] ***************************************************************************************
ok: [192.168.1.55]

TASK [task1] ***************************************************************************************
[WARNING]: Handler 'handler {{ var1 }}' is unusable because it has no listen topics and the name
could not be templated (host-specific variables are not supported in handler names). The error:
'var1' is undefined. 'var1' is undefined
ERROR! The requested handler 'handler aa' was not found in either the main handlers list nor in the listening handlers list

可见,对于动态定义的变量,notify可以识别,而handler命名处无法识别(未定义)。

类似的,如果已定义的变量,如果动态改变其值,notify可以识别,而handler命名处仍然是原值。

所以,最好不要在handler命名处使用变量。

参考

  • https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html

http://www.kler.cn/a/144514.html

相关文章:

  • 编译 CUDA加速的 OpenCV-4.8.0 版本
  • Linux中tar命令的几个高级用法
  • 每日一题:LeetCode-589.N叉树的前序遍历序列构造二叉树
  • JAVA毕业设计111—基于Java+Springboot+Vue的养老院管理系统(源码+数据库+12000字论文)
  • postman和Jmeter做接口测试的区别(经验之谈)
  • ​Spring Boot 分片上传文件
  • Blender中的集合(collection)概念
  • 【Python】【Torch】神经网络中各层输出的特征图可视化详解和示例
  • springsecurity5.7.x和springsecurity6.x配置文件对比
  • 8.AUTOSAR 诊断栈分析(一)
  • 55.跳跃游戏
  • 医保线上购药系统:代码驱动的医疗创新
  • C语言结构、联合和枚举
  • Vue组件基础
  • Springboot websocket前端无法访问到,Websocket因AOP代理 前端无法请求到
  • Leetcode—45.跳跃游戏II【中等】
  • Oracle数据库语句大全
  • Lua实现面向对象三大特性
  • python通过继承、组合、委托组织类
  • 【数据结构】用C语言实现顺序栈(附完整运行代码)