• Ansible Playbook handlers的用法


    在开始介绍handlers的用法之前,先来描述一个工作场景。

    当我们修改了某些程序的配置文件以后,有可能需要重启应用程序,以便能够使新的配置生效,那么,如果使用playbook来实现这个简单的功能,该怎样编写playbook呢?

    我们来试试,此处我们使用nginx作为示例,虽然nginx可以使用nginx -s reload命令重载配置,但是此处的示例中并不会使用这个命令,而是用nginx类比那些需要重启生效的应用。

    假设我们想要将nginx中的某个server的端口从8080改成8088,并且在修改配置以后重启nginx,那么我们可以编写如下剧本。

    ---
    - hosts: test181
      remote_user: root
      tasks:
      - name: Modify the configuration
        lineinfile:
          path=/etc/nginx/conf.d/test.lvzhenjiang.net.conf
          regexp="listen 8080;"
          line="listen 8088;"
          backrefs=yes
          backup=yes
      - name: restart nginx
        service:
          name=nginx
          state=restarted
    

    上述play表示修改test181主机的/etc/nginx/conf.d/test.lvzhenjiang.net.conf配置文件,将监听端口8080改为监听端口8088,端口修改完成后,重启服务。

    image

    可以看到test181主机上的8080正常被监听,那么现在我们来执行一下上述playbook,看一下执行效果!

    执行后可以看到,play中的两个任务都被正常执行了,如下图所示:

    image

    此时再次查看test70主机的端口号,已经从8080改为8088,如下图所示:

    image

    这样没有任何问题,与我们预期的一样,端口号从8080修改为8088,重启了服务!

    那么,我们再来重复执行一遍上述playbook试试,看看会出现什么情况,重复执行效果如下:

    image

    如上图所示,当我们再次执行同样的playbook时,由于配置文件中的端口号已经是8088,所以,任务Modify the configuration的状态为OK(换句话说,这个任务并没有在远程主机进行任何实际操作),这是由于ansible的幂等性造成的(前文已经对幂等性做出了解释,此处不再赘述),因为目标状态与我们预期的状态一致,所以ansible并没有做任何改动,这是完全正常的,从上图可以看出,任务restart nginx也正常的执行了,而且是真正的执行了,换句话说就是它的确重启了对应的nginx服务,对远程主机进行了实际的操作。

    第二次运行剧本的过程似乎没有什么问题,但是仔细想想,又有些不妥,因为我们重启服务的目的是为了在修改配置文件以后使新的配置生效,而第二次运行剧本的这种情况下,我们并没有真正修改服务器配置,因为服务器配置本来 就与我们预期的一致,但是,在没有修改配置的情况下,仍然重启了服务,这种重启是不需要的,我们想要达到的效果是,如果配置文件发生了改变,则重启服务,如果配置文件并没有被真正的修改,则不对服务进行任何操作,这种情况下,我们该怎们办呢?

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

    ---
    - hosts: test181
      remote_user: root
      tasks:
      - name: Modify the configuration
        lineinfile:
          path=/etc/nginx/conf.d/test.lvzhenjiang.net.conf
          regexp="listen 8080;"
          line="listen 8088;"
          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状态,此处不再赘述),所以,任务执行后的状态为changed则会执行对应的handlers,这就是handlers的作用,聪明如你肯定已经明白了,动手执行一下上述playbook试试吧!

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

    ---
    - hosts: test181
      remote_user: root
      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,如下图所示:

    image

    从上图可以看出,handler执行的顺序与handler在playbook中定义的顺序是相同的,handlernotify的顺序无关

    如上图所示,默认情况下,所有task执行完毕后,才会执行各个handler,并不是执行完某个task后,立即执行对应的handler,如果你想要在执行完某些task以后立即执行对应的handler,则需要使用meta模块,示例如下:

    ---
    - hosts: test181
      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_handlers,meta: flush_handlers表示立即执行之前的task所对应handler,什么意思呢?意思就是,在当前meta任务之前,一共有两个任务,task1与task2,它们都有对应的handler,当执行完task1与task2以后,立即执行对应的handler,而不是像默认情况那样在所有任务都执行完毕以后才能执行各个handler,那么我们来实际运行一下上述剧本,运行结果如下:

    image

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

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

    我们还可以在一个task中一次性notify多个handler,怎样才能一次性notify多个handler呢?你可能会尝试将多个handler使用相同的name,但是这样并不可行,因为当多个handler的name相同时,只有一个handler会被执行,所以,我们并不能通过这种方式notify多个handler,如果想要一次notify多个handler,则需要借助另一个关键字,它就是listen,你可以把listen理解成组名,我们可以把多个handler分成组,当我们需要一次性notify多个handler时,只要将多个handler分为一组,使用相同的组名即可,当notify对应的值为组名时,组内的所有handler都会被notify,这样说可能还是不容易理解,我们来看个小示例,示例如下:

    ---
    - hosts: test181
      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
    

    如上例所示,handler1与handler2的listen的值都是handler group1,当task1中notify的值为handler group1时,handler1与handler2都会被notify,还是很方便的。

  • 相关阅读:
    struts2基础
    javaEE环境搭建-eclipse
    geth
    redis常用命令
    angular-ui-select 下拉框支持过滤单选多选解决方案(系列一)
    angularjs中向html页面添加内容节点元素代码段的两种方法
    modal
    弹性布局
    自定义鼠标样式
    angularjs指令弹框点击空白处隐藏及常规方法
  • 原文地址:https://www.cnblogs.com/lvzhenjiang/p/16097704.html
Copyright © 2020-2023  润新知