ansible笔记(4)之handlers

ansible笔记(4)之handlers

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

本来打算自己写一波 ansible 系列的,后来发现一老哥写的太好了,「点击此处直达」,我这里也就边看边对该系列文章做下笔记,方便以后查阅,ansible 入门的话墙裂建议阅读前方链接博文~~~

介绍

此处我们先大概的描述一下 handlers 的概念,你可以把 handlers 理解成另一种 tasks,handlers 是另一种任务列表,handlers 中的任务会被 tasks 中的任务进行调用,但是,被调用并不意味着一定会执行,只有当 tasks 中的任务真正执行以后(真正的进行实际操作,造成了实际的改变),handlers 中被调用的任务才会执行,如果 tasks 中的任务并没有做出任何实际的操作,那么 handlers 中的任务即使被调用,也并不会执行。这样说似乎不容易被理解,我们来写一个小示例,示例如下。

---
- hosts: all
  tasks:
  - name: Modify the configuration
    lineinfile:
      path=/etc/nginx/conf.d/test.zze.xyz.conf
      regexp="listen(.*) 8080(.*)"
      line="listen\1 8088\2"
      backrefs=yes
      backup=yes
    notify:
      restart nginx
 
  handlers:
  - name: restart nginx
    service:
      name=nginx
      state=restarted

如上例所示,我们使用 handlers 关键字,指明哪些任务可以被调用,之前说过,handlers 是另一种任务列表,你可以把 handlers 理解成另外一种tasks,你可以理解成它们是平级的,所以,handlers 与 tasks 是对齐的(缩进相同)。

上例中的 handlers 中只有一个任务,这个任务的名称为 restart nginx,之前也说明过,handlers 中的任务需要被 tasks 中的任务调用,那么上例中,restart nginx 被哪个任务调用了呢?很明显,restart nginxModify the configuration 调用了。没错,如你所见,我们使用 notify 关键字调用 handlers 中的任务,或者说,通过 notify 关键字通知 handlers 中的任务。

所以,综上所述,上例中的 play 表示,如果 Modify the configuration 真正的修改了配置文件(实际的操作),那么则执行 restart nginx 任务,如果 Modify the configuration 并没有进行任何实际的改动,则不执行 restart nginx,通常来说,任务执行后如果做出了实际的操作,任务执行后的状态为 changed,所以,任务执行后的状态为 changed 则会执行对应的 handlers,这就是 handlers 的作用。

执行顺序

handlers 是另一种任务列表,所以 handlers 中可以有多个任务,被 tasks 中不同的任务 notify,示例如下:

---
- hosts: all
  tasks:
  - name: make testfile1
    file: path=/testdir/testfile1
          state=directory
    notify: ht2
  - name: make testfile2
    file: path=/testdir/testfile2
          state=directory
    notify: ht1
 
  handlers:
  - name: ht1
    file: path=/testdir/ht1
          state=touch
  - name: ht2
    file: path=/testdir/ht2
          state=touch

如上例所示,tasks 与 handlers 都是任务列表,只是 handlers 中的任务被 tasks 中的任务 notify 罢了,那么我们来执行一下上述 playbook,如下:

$ ansible-playbook test

PLAY [all] ****************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************
ok: [B]
ok: [C]

TASK [make testfile1] *****************************************************************************************************************************
changed: [C]
changed: [B]

TASK [make testfile2] *****************************************************************************************************************************
changed: [B]
changed: [C]

RUNNING HANDLER [ht1] *****************************************************************************************************************************
changed: [C]
changed: [B]

RUNNING HANDLER [ht2] *****************************************************************************************************************************
changed: [C]
changed: [B]

PLAY RECAP ****************************************************************************************************************************************
B                          : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
C                          : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

可以看出,handler 执行的顺序与 handler 在 playbook 中定义的顺序是相同的,与 handler 被 notify 的顺序无关。

默认情况下,所有 task 执行完毕后,才会执行各个 handler,并不是执行完某个 task 后,立即执行对应的 handler。

立即执行

如果你想要在执行完某些 task 以后立即执行对应的 handler,则需要使用 meta 模块,示例如下:

---
- hosts: all
  remote_user: root
  tasks:
  - name: task1
    file: path=/testdir/testfile
          state=touch
    notify: handler1
  - name: task2
    file: path=/testdir/testfile2
          state=touch
    notify: handler2
 
  - meta: flush_handlers
 
  - name: task3
    file: path=/testdir/testfile3
          state=touch
    notify: handler3
 
  handlers:
  - name: handler1
    file: path=/testdir/ht1
          state=touch
  - name: handler2
    file: path=/testdir/ht2
          state=touch
  - name: handler3
    file: path=/testdir/ht3
          state=touch

如上例所示,我在 task1 与 task2 之后写入了一个任务,我并没有为这个任务指定 name 属性,这个任务使用 meta 模块,meta 任务是一种特殊的任务,meta 任务可以影响 ansible 的内部运行方式。

上例中,meta 任务的参数值为 flush_handlersmeta: flush_handlers 表示立即执行之前的 task 所对应 handler,什么意思呢?意思就是,在当前 meta 任务之前,一共有两个任务,task1task2,它们都有对应的 handler,当执行完 task1 与 task2 以后,立即执行对应的 handler,而不是像默认情况那样在所有任务都执行完毕以后才能执行各个 handler,那么我们来实际运行一下上述剧本,运行结果如下:

$ ansible-playbook test

PLAY [all] ****************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************
ok: [B]
ok: [C]

TASK [task1] **************************************************************************************************************************************
changed: [C]
changed: [B]

TASK [task2] **************************************************************************************************************************************
changed: [B]
changed: [C]

RUNNING HANDLER [handler1] ************************************************************************************************************************
changed: [C]
changed: [B]

RUNNING HANDLER [handler2] ************************************************************************************************************************
changed: [C]
changed: [B]

TASK [task3] **************************************************************************************************************************************
changed: [C]
changed: [B]

RUNNING HANDLER [handler3] ************************************************************************************************************************
changed: [B]
changed: [C]

PLAY RECAP ****************************************************************************************************************************************
B                          : ok=7    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
C                          : ok=7    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

如上所示,meta 任务之前的任务 task1task2 在进行了实际操作以后,立即运行了对应的 handler1handler2,然后才运行了 task3,在所有 task 都运行完毕后,又逐个将剩余的 handler 根据情况进行调用。

聪明如你一定想到了,如果想要每个 task 在实际操作后都立马执行对应 handlers,则可以在每个任务之后都添加一个 meta 任务,并将其值设置为 flush_handlers 所以,我们可以依靠 meta 任务,让 handler 的使用变得更加灵活。

批量调用

我们还可以在一个 task 中一次性 notify 多个 handler,需要借助另一个关键字,它就是 listen,你可以把 listen 理解成组名,我们可以把多个 handler 分成组,当我们需要一次性 notify 多个 handler 时,只要将多个 handler 分为一组,使用相同的组名即可,当 notify 对应的值为组名时,组内的所有 handler 都会被 notify,这样说可能还是不容易理解,我们来看个小示例,示例如下:

---
- hosts: all
  remote_user: root
  tasks:
  - name: task1
    file: path=/testdir/testfile
          state=touch
    notify: handler group1
 
  handlers:
  - name: handler1
    listen: handler group1
    file: path=/testdir/ht1
          state=touch
  - name: handler2
    listen: handler group1
    file: path=/testdir/ht2
          state=touch

如上例所示,handler1handler2listen 的值都是 handler group1,当 task1notify 的值为handler group1 时,handler1handler2 都会被 notify,还是很方便的。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/ansible4.html

Buy me a cup of coffee ☕.