ansible笔记():handlers的用法

这篇文章会介绍playbook中handlers的用法。

在开始介绍之前,我们先来描述一个工作场景:

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

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

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

---
- hosts: test211
remote_user: root
tasks:
- name: modify the configuration
lineinfile:
path=/etc/nginx/conf.d/www.chinasoft.com.conf
regexp="listen(.*) 80 (.*)"
line="listen\1 8088 \2"
backrefs=yes
backup=yes
- name: restart nginx
service:
name=nginx
state=restarted # 配置文件
[root@web01:/etc/nginx/conf.d]# cat /etc/nginx/conf.d/www.chinasoft.com.conf
server {
listen default_server;
server_name localhost www.chinasoft.com;
root /usr/share/nginx/html; # Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf; location / {
} error_page 404 /404.html;
location = /40x.html {
} error_page 500 502 503 504 /50x.html;
location = /50x.html {
} } 上述play表示修改test211主机的/etc/nginx/conf.d/www.chinasoft.com.conf配置文件,将监听端口80改为监听端口8088,端口修改完成后,重启服务。
那么现在我们来执行一下上述playbook,看一下执行效果 执行后可以看到,play中的两个任务都被正常执行了,如下图所示 [root@node1 data]# ansible-playbook test_handle01.yml PLAY [test211] ************************************************************** TASK [Gathering Facts] ******************************************************
ok: [test211] TASK [modify the configuration] *********************************************
changed: [test211] TASK [restart nginx] ********************************************************
changed: [test211] PLAY RECAP ******************************************************************
test211 : ok=3 changed=2 unreachable=0 failed=0 此时再次查看test70主机的端口号,已经从80改为8088,如下图所示 [root@web01:/etc/nginx/conf.d]# ss -tnlp|grep 8088
LISTEN 0 511 *:8088 *:* users:(("nginx",42135,8),("nginx",42136,8),("nginx",42137,8),("nginx",42139,8),("nginx",42140,8)) 这样没有任何问题,与我们预期的一样,端口号从80修改为8088,重启了服务 那么,我们再来重复执行一遍上述playbook试试,看看会出现什么情况,重复执行效果如下 [root@node1 data]# ansible-playbook test_handle01.yml PLAY [test211] *************************************************************** TASK [Gathering Facts] *******************************************************
ok: [test211] TASK [modify the configuration] **********************************************
ok: [test211] TASK [restart nginx] *********************************************************
changed: [test211] PLAY RECAP *******************************************************************
test211 : ok=3 changed=1 unreachable=0 failed=0 如上所示,当我们再次执行同样的playbook时,由于配置文件中的端口号已经是8088,所以,任务"Modify the configuration"的状态为OK(换句话说,这个任务并没有在远程主机进行任何实际操作),这是由于ansible的幂等性造成的(前文已经对幂等性做出了解释,此处不再赘述),因为目标状态与我们预期的状态一致,所以ansible并没有做任何改动,这是完全正常的,从上可以看出,任务"restart nginx"也正常的执行了,而且是"真正的"执行了,换句话说就是它的确重启了对应的nginx服务,对远程主机进行了实际的操作。 第二次运行剧本的过程似乎没有什么问题,但是仔细想想,又有些不妥,因为我们重启服务的目的是为了在修改配置文件以后使新的配置生效,而第二次运行剧本的这种情况下,我们并没有真正修改服务器配置,因为服务器配置本来 就与我们预期的一致,但是,在没有修改配置的情况下,仍然重启了服务,这种重启是不需要的,我们想要达到的效果是,如果配置文件发生了改变,则重启服务,如果配置文件并没有被真正的修改,则不对服务进行任何操作,这种情况下,我们该怎们办呢? handlers就是来解决这种问题的,此处我们先大概的描述一下handlers的概念,后面会给出示例,你可以把handlers理解成另一种tasks,handlers是另一种'任务列表',handlers中的任务会被tasks中的任务进行"调用",但是,被"调用"并不意味着一定会执行,只有当tasks中的任务"真正执行"以后(真正的进行实际操作,造成了实际的改变),handlers中被调用的任务才会执行,如果tasks中的任务并没有做出任何实际的操作,那么handlers中的任务即使被'调用',也并不会执行。这样说似乎不容易被理解,我们来写一个小示例,示例如下。 ---
- hosts: test211
remote_user: root
tasks:
- name: modify the configuration
lineinfile:
path=/etc/nginx/conf.d/www.chinasoft.com.conf
regexp="listen(.*) 80 (.*)"
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 nginx"被"Modify the configuration"调用了,没错,如你所见,我们使用notify关键字'调用'handlers中的任务,或者说,通过notify关键字'通知'handlers中的任务,所以,综上所述,上例中的play表示,如果"Modify the configuration"真正的修改了配置文件(实际的操作),那么则执行"restart nginx"任务,如果"Modify the configuration"并没有进行任何实际的改动,则不执行"restart nginx" ,这就是handlers的作用,聪明如你肯定已经明白了,动手执行一下上述playbook试试吧。 handlers是另一种任务列表,所以handlers中可以有多个任务,被tasks中不同的任务notify,示例如下 ---
- hosts: test211
remote_user: root
tasks:
- name: make testfile211a
file: path=/data/testfile211a
state=directory
notify: ht2
- name: make testfile211b
file: path=/data/testfile211b
state=directory
notify: ht1 handlers:
- name: ht1
file: path=/data/ht1
state=touch
- name: ht2
file: path=/data/ht2
state=touch 如上例所示,tasks与handlers都是任务列表,只是handlers中的任务被tasks中的任务notify罢了,那么我们来执行一下上述playbook,如下所示 [root@node1 data]# ansible-playbook test_handle03.yml PLAY [test211] ************************************************************* TASK [Gathering Facts] *****************************************************
ok: [test211] TASK [make testfile211a] ***************************************************
changed: [test211] TASK [make testfile211b] ***************************************************
changed: [test211] RUNNING HANDLER [ht1] ******************************************************
changed: [test211] RUNNING HANDLER [ht2] ******************************************************
changed: [test211] PLAY RECAP *****************************************************************
test211 : ok=5 changed=4 unreachable=0 failed=0 从上图可以看出,handler执行的顺序与handler在playbook中定义的顺序是相同的,与"handler被notify"的顺序无关。 如上图所示,默认情况下,所有task执行完毕后,才会执行各个handler,并不是执行完某个task后,立即执行对应的handler,如果你想要在执行完某些task以后立即执行对应的handler,则需要使用meta模块,示例如下 ---
- hosts: test211
remote_user: root
tasks:
- name: task1
file: path=/data/testfile01
state=touch
notify: handler1
- name: task2
file: path=/data/testfile02
state=touch
notify: handler2 - meta: flush_handlers - name: task3
file: path=/data/testfile03
state=touch
notify: handler3 handlers:
- name: handler1
file: path=/data/ht1
state=touch
- name: handler2
file: path=/data/ht2
state=touch
- name: handler3
file: path=/data/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,那么我们来实际运行一下上述剧本,运行结果如下 [root@node1:/data]# ansible-playbook test-handle04.yml PLAY [test211] ****************************************************************** TASK [Gathering Facts] **********************************************************
ok: [test211] TASK [task1] ********************************************************************
changed: [test211] TASK [task2] ********************************************************************
changed: [test211] RUNNING HANDLER [handler1] ******************************************************
changed: [test211] RUNNING HANDLER [handler2] ******************************************************
changed: [test211] TASK [task3] ********************************************************************
changed: [test211] RUNNING HANDLER [handler3] ******************************************************
changed: [test211] PLAY RECAP **********************************************************************
test211 : ok=7 changed=6 unreachable=0 failed=0 正如上图所示,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: test211
remote_user: root
tasks:
- name: task1
file: path=/data/testfile1
state=touch
notify: handler group1 handlers:
- name: handler1
listen: handler group1
file: path=/data/ht1
state=touch
- name: handler2
listen: handler group1
file: path=/data/ht2
state=touch [root@node1:/data]# ansible-playbook test_handler05.yml PLAY [test211] ************************************************************* TASK [Gathering Facts] *****************************************************
ok: [test211] TASK [task1] ***************************************************************
changed: [test211] RUNNING HANDLER [handler1] *************************************************
changed: [test211] RUNNING HANDLER [handler2] *************************************************
changed: [test211] PLAY RECAP *****************************************************************
test211 : ok=4 changed=3 unreachable=0 failed=0 如上例所示,handler1与handler2的listen的值都是handler group1,当task1中notify的值为handler group1时,handler1与handler2都会被notify,还是很方便的。

ansible笔记(12):handlers的用法的更多相关文章

  1. Ext.Net学习笔记12:Ext.Net GridPanel Filter用法

    Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...

  2. python笔记之常用模块用法分析

    python笔记之常用模块用法分析 内置模块(不用import就可以直接使用) 常用内置函数 help(obj) 在线帮助, obj可是任何类型 callable(obj) 查看一个obj是不是可以像 ...

  3. ansible笔记(8):常用模块之系统类模块(二)

    ansible笔记():常用模块之系统类模块(二) user模块 user模块可以帮助我们管理远程主机上的用户,比如创建用户.修改用户.删除用户.为用户创建密钥对等操作. 此处我们介绍一些user模块 ...

  4. ansible笔记(3):ansible模块的基本使用

    ansible笔记():ansible模块的基本使用 在前文的基础上,我们已经知道,当我们使用ansible完成实际任务时,需要依靠ansible的各个模块,比如,我们想要去ping某主机,则需要使用 ...

  5. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  6. 机器学习实战 - 读书笔记(12) - 使用FP-growth算法来高效发现频繁项集

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第12章 - 使用FP-growth算法来高效发现频繁项集. 基本概念 FP-growt ...

  7. SQL反模式学习笔记12 存储图片或其他多媒体大文件

    目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点:     1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...

  8. ansible笔记(11):初识ansible playbook(二)

    ansible笔记():初识ansible playbook(二) 有前文作为基础,如下示例是非常容易理解的: --- - hosts: test211 remote_user: root tasks ...

  9. ansible笔记(10):初识ansible playbook

    ansible笔记():初识ansible playbook 假设,我们想要在test70主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令 ansible test70 -m ...

随机推荐

  1. Project facet Java version 1.8 not supported

    把其它的项目到自己的eclipse中后,进行运行项目之后,就会提示为“Project facet Java version 1.8 not supported”.   进行更改配置,进行右键项目就会弹 ...

  2. [leetcode-128] 最长连续序列

    给定一个未排序的整数数组,找出最长连续序列的长度. 要求算法的时间复杂度为 O(n). 示例: 输入: [100, 4, 200, 1, 3, 2] 输出: 4 解释: 最长连续序列是 [1, 2, ...

  3. python matplotlib 库学习

    基本使用 import matplotlib.pyplot as plt import numpy as np x = np.linspace(-1,1,50) y = 2*x+1 plt.figur ...

  4. Vertica系列:从一些细节看Vertica为什么是一个优秀的数据仓库平台

    ===========================================对象名称可以长到128字符===========================================1 ...

  5. jquery判断对象是否存在

    if($("#abc").length >0) { ... } if($("#abc").html() != "") { ... }

  6. C#调用C++导出类的一个实例

    一直认为带导出类dll的只有VC自己可以调用,其它编程语言无法调用,今天看到一篇文章才知道自己错了.https://blog.csdn.net/huiyouyongdeyu2011/article/d ...

  7. Spring整合redis配置文件详解

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  8. HTTP访问控制(CORS)

    当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求.   比如,站点 http://domain-a.com 的某 HTML 页面通过 <img ...

  9. PHP文件系统管理

    文件概念: 第一个是windows的文件,另一个php根据LINUX的文件,两者是有所不同的,我们说的页面基于windows的文件可以是是文件夹(也就是目录)或是文件,而php两者都必须有,它包含目录 ...

  10. 第25月第4天 Blog-API-with-Django-Rest-Framework项目记录01

    #------------------------------ 1. djangochinaorg项目 https://github.com/DjangoChinaOrg/Django-China-A ...