handlers

接上一篇文章 Ansible Playbooks 介绍 和 使用 一 继续说明

用于当关注的资源发生变化时采取一定的操作。

notify这个 action可用于在每个play的最后被处罚,这样可以避免多次有改变时每次都执行指定的操作,取而代之,尽在所有的变化发生完成后一次性执行指定的操作。在notify中列出的操作成为handler。

例如:

- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache

handler是task列表,这些task与前述task并没有本质上的不同。

handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=httpd state=restarted

playbook 案例 2 handlers

应用场景

在webservs组安装httpd服务,默认启动httpd监听的是80端口

步骤

  1. 创建一个配置安装httpd服务的playbook,并配置开机器启动等相关操作
  2. 执行httpd.yml
  3. 修改配置文件httpd.conf中的端口为8080
  4. 再次执行httpd的playbook文件

首先创建httpd.yml文件

[root@node01 ansible]# pwd
/etc/ansible
[root@node01 ansible]# cat httpd.yml
- hosts: webservs
remote_user: root
tasks:
- name: install httpd packge
yum: name=httpd state=present
- name: configuration file for httpd
copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: start httpd service
service: name=httpd enabled=true state=started

创建配置文件目录,并拷贝httpd.conf

[root@node01 ansible]# pwd
/etc/ansible
[root@node01 ansible]# mkdir conf
[root@node01 ansible]# cp /etc/httpd/conf/httpd.conf conf/
[root@node01 ansible]# vim conf/httpd.conf

执行httpd.yuml的playbook

[root@node01 ansible]# ansible-playbook httpd.yml 

PLAY [webservs] ***********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65] TASK [install httpd packge] ***********************************************************************************************
changed: [10.0.0.65] TASK [configuration file for httpd] ***************************************************************************************
ok: [10.0.0.65] TASK [start httpd service] ************************************************************************************************
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=4 changed=2 unreachable=0 failed=0

验证:

[root@node01 ansible]# ansible webservs -a 'rpm -qa httpd'
10.0.0.65 | CHANGED | rc=0 >>
httpd-2.4.6-80.el7.centos.1.x86_64 [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep 80'
10.0.0.65 | CHANGED | rc=0 >>
tcp6 0 0 :::80 :::* LISTEN 31354/httpd

修改ansible服务端下httpd.conf配置文件中的端口为8080,然后重新执行

[root@node01 ansible]# egrep '^Listen' conf/httpd.conf
Listen 8080
[root@node01 ansible]# ansible-playbook httpd.yml PLAY [webservs] *********************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65] TASK [install httpd packge] ***********************************************************************************************
ok: [10.0.0.65] TASK [configuration file for httpd] ***************************************************************************************
changed: [10.0.0.65] TASK [start httpd service] ************************************************************************************************
ok: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=4 changed=1 unreachable=0 failed=0 [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep httpd'
10.0.0.65 | CHANGED | rc=0 >>
tcp6 0 0 :::80 :::* LISTEN 31354/httpd [root@node01 ansible]# ansible webservs -m shell -a 'egrep "^Listen" /etc/httpd/conf/httpd.conf'
10.0.0.65 | CHANGED | rc=0 >>
Listen 8080

最后可以看到,虽然远程主机的配置文件中的端口修改了,但实际监听的端口没有变,说明httpd没有重启

此时就需要用handlers,来监听当有类似于这样的配置文件操作变更的时候,就需要重启这样的操作,

下面修改httpd.yml中的内容

[root@node01 ansible]# cat httpd.yml
- hosts: webservs
remote_user: root
tasks:
- name: install httpd packge
yum: name=httpd state=present
- name: configuration file for httpd
copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: name=httpd enabled=true state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted

再次把httpd.conf中的端口改成808,然后再次执行

[root@node01 ansible]# egrep '^Listen' conf/httpd.conf
Listen 808
[root@node01 ansible]# ansible-playbook httpd.yml PLAY [webservs] *********************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65] TASK [install httpd packge] ***********************************************************************************************
ok: [10.0.0.65] TASK [configuration file for httpd] ***************************************************************************************
changed: [10.0.0.65] TASK [start httpd service] ************************************************************************************************
ok: [10.0.0.65] RUNNING HANDLER [restart httpd] *******************************************************************************************
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=5 changed=2 unreachable=0 failed=0 [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep httpd'
10.0.0.65 | CHANGED | rc=0 >>
tcp6 0 0 :::808 :::* LISTEN 32212/httpd

最后可以看到,远程主机的httpd服务监听的端口已经变成了808。

vars 变量

在playbook中使用变量,可以直接在playbook中直接定义变量,也可以在其他模板中定义变量,在playbook文件中饮用

下面以httpd.yml为例,在文件中增加vars变量

[root@node01 ansible]# cat httpd.yml
- hosts: webservs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=present
- name: configuration file for httpd
copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: name={{ service }} enabled=true state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted

从上面的定义可以看出,变量的引用是通过{{ }} 两个大括号来的

下面看下重新执行一下,看下效果

[root@node01 ansible]# ansible-playbook httpd.yml 

PLAY [webservs] ***********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65] TASK [install httpd package] **********************************************************************************************
ok: [10.0.0.65] TASK [configuration file for httpd] ***************************************************************************************
ok: [10.0.0.65] TASK [start httpd service] ************************************************************************************************
ok: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=4 changed=0 unreachable=0 failed=0

可以看到都是OK,说明变量引用成功了

setup facts 变量使用

playbook也可以直接引用facts中获取的远程主机信息的变量来使用

案例

首先来查看

[root@node01 ansible]# ansible webservs -m setup | head
10.0.0.65 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.0.0.65"
],
"ansible_all_ipv6_addresses": [
"fe80::20c:29ff:fe07:47f6"
],
"ansible_apparmor": {
"status": "disabled"

这里就使用变量:ansible_all_ipv4_addresses 来调用使用

[root@node01 ansible]# cat test.yml
- hosts: webservs
remote_user: root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans
[root@node01 ansible]# ansible-playbook test.yml PLAY [webservs] *********************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65] TASK [copy file] **********************************************************************************************************
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=2 changed=1 unreachable=0 failed=0 [root@node01 ansible]# ansible webservs -a 'cat /tmp/vars.ans'
10.0.0.65 | CHANGED | rc=0 >>
["10.0.0.65"]

从上面最后输出的结果来看,变量的调用成功。

inventory 中定义变量

同样也可以在inventory中定义变量,然后在playbook中引用

案例

修改inventory文件hosts

[root@node01 ansible]# cat hosts
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups [webservs]
10.0.0.65 testvars="10.0.0.65" [dbservs]
10.0.0.66 testvars="10.0.0.66"

上面给个主机定义了 testvars变量

下面来引用,修改playbook文件

[root@node01 ansible]# cat test.yml
- hosts: webservs, dbservs
remote_user: root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_addresses }}\n{{ testvars }}" dest=/tmp/vars.ans
[root@node01 ansible]# ansible-playbook test.yml PLAY [webservs, dbservs] ************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65]
ok: [10.0.0.66] TASK [copy file] **********************************************************************************************************
changed: [10.0.0.66]
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=2 changed=1 unreachable=0 failed=0
10.0.0.66 : ok=2 changed=1 unreachable=0 failed=0 [root@node01 ansible]# ansible all -a 'cat /tmp/vars.ans'
10.0.0.66 | CHANGED | rc=0 >>
[u'10.0.0.66']
10.0.0.66 10.0.0.65 | CHANGED | rc=0 >>
[u'10.0.0.65']
10.0.0.65

从上面最后的输出结果可以看出,引用成功。

条件测试

如果需要根据变量、facts或此前任务的执行结果来为某task执行与否的前提时要用到条件测试。

when 语句

在task后面添加when子句即可使用条件测试;when语句支持jinja2表达式语法,例如:

tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"

when 语句中还可以使用jinja2的太多filter,例如要忽略此前某语句的错误并基于其结果(failed或者sucess)运行后面指定的语句,可使用类似如下的形式:

tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result | failed
- command: /bin/something_else
when: result | success
- command: /bin/still/something_else
when: result | skipped

此外 when语句中还可以使用facts或playbook中定义的变量。

案例

判断当主机名为node02的时候,添加一个node02的新用户,否则其他机器不添加

首先使用ansible查看所有主机的主机名:

[root@node01 ansible]# ansible all -m setup | grep ansible_fqdn
"ansible_fqdn": "node02",
"ansible_fqdn": "node03",

定义和执行playbook文件

[root@node01 ansible]# cat cond.yml
- hosts: all
remote_user: root
vars:
- username: node02
tasks:
- name: create {{ username }} user
user: name={{ username }}
when: ansible_fqdn == "node02"
[root@node01 ansible]# ansible-playbook cond.yml PLAY [all] **************************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.65]
ok: [10.0.0.66] TASK [create node02 user] *************************************************************************************************
skipping: [10.0.0.66]
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=2 changed=1 unreachable=0 failed=0
10.0.0.66 : ok=1 changed=0 unreachable=0 failed=0 [root@node01 ansible]# ansible all -a 'grep node02 /etc/passwd'
10.0.0.66 | FAILED | rc=1 >>
non-zero return code 10.0.0.65 | CHANGED | rc=0 >>
node02:x:1002:1002::/home/node02:/bin/bash

从上最后执行的结果来看,when的条件测试判断成功。

迭代

当有需要重复性执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为item变量,并通过with_items语句来指明迭代的元素列表即可。例如:

- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2

事实上,with_items中可以使用元素还可以为hashes,例如:

- name: add several users
user: name={{ item }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', group: 'wheel' }
- { name: 'testuser2', group: 'root' }

templates 模板

在某个服务的配置文件中,预先定义好需要变更的变量,然后在执行playbook的时候,向定义好的配置文件中传入参数,可灵活修改;

如http服务,一个http监听80端口,另一个监听8080端口,则可以使用

案例

以httpd的配置文件为例,对其进行修改

[root@node01 ansible]# pwd
/etc/ansible
[root@node01 ansible]# mkdir templates
[root@node01 ansible]# cp /etc/httpd/conf/httpd.conf templates/httpd.conf.j2
[root@node01 ansible]# egrep "^Listen|^ServerName" templates/httpd.conf.j2
Listen {{ http_port }}
ServerName {{ ansible_fqdn }}

然后修改inventory文件中增加变量

[root@node01 ansible]# cat /etc/ansible/hosts
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups [webservs]
10.0.0.65 http_port=80 [dbservs]
10.0.0.66 http_port=8080

定义playbook文件

[root@node01 ansible]# cat apache.yml
- hosts: webservs dbservs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=present
- name: configuration file for httpd
template: src=/etc/ansible/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: name={{ service}} enabled=true state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted

执行

[root@node01 ansible]# ansible-playbook apache.yml 

PLAY [webservs dbservs] ***************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.66]
ok: [10.0.0.65] TASK [install httpd package] **********************************************************************************************
ok: [10.0.0.65]
ok: [10.0.0.66] TASK [configuration file for httpd] ***************************************************************************************
changed: [10.0.0.65]
changed: [10.0.0.66] TASK [start httpd service] ************************************************************************************************
changed: [10.0.0.65]
changed: [10.0.0.66] RUNNING HANDLER [restart httpd] *******************************************************************************************
changed: [10.0.0.66]
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=5 changed=3 unreachable=0 failed=0
10.0.0.66 : ok=5 changed=3 unreachable=0 failed=0 [root@node01 ansible]# ansible all -m shell -a 'egrep "^Listen|^ServerName" /etc/httpd/conf/httpd.conf'
10.0.0.65 | CHANGED | rc=0 >>
Listen 80
ServerName node02 10.0.0.66 | CHANGED | rc=0 >>
Listen 8080
ServerName node03 [root@node01 ansible]# ansible all -m shell -a 'netstat -lntup | grep httpd'
10.0.0.65 | CHANGED | rc=0 >>
tcp6 0 0 :::80 :::* LISTEN 34619/httpd 10.0.0.66 | CHANGED | rc=0 >>
tcp6 0 0 :::8080 :::* LISTEN 29274/httpd

从上个最后的执行结果可以看出,template中定义的端口已经生效了。

tags

当一个playbook需要运行多次是,可以在playbook文件中的一个tasks中,定义一个tags,在第二次运行时,可以指定tags,只运行其中一个tasks。

案例

重新定义playbook文件

[root@node01 ansible]# cat apache.yml
- hosts: webservs dbservs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=present
- name: configuration file for httpd
template: src=/etc/ansible/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: name={{ service}} enabled=true state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted [root@node01 ansible]# cat hosts
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups [webservs]
10.0.0.65 http_port=808 [dbservs]
10.0.0.66 http_port=800

运行:

[root@node01 ansible]# ansible-playbook apache.yml --tags="conf"

PLAY [webservs dbservs] ***************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.0.0.66]
ok: [10.0.0.65] TASK [configuration file for httpd] ***************************************************************************************
changed: [10.0.0.65]
changed: [10.0.0.66] RUNNING HANDLER [restart httpd] *******************************************************************************************
changed: [10.0.0.66]
changed: [10.0.0.65] PLAY RECAP ****************************************************************************************************************
10.0.0.65 : ok=3 changed=2 unreachable=0 failed=0
10.0.0.66 : ok=3 changed=2 unreachable=0 failed=0

从上面运行的结果来看,安装和启动没有运行,只运行了配置修改和重启。

说明

特殊的 tags: always 表示无论指定或者不指定,都会运行对应的tasks

Ansible Playbooks 介绍 和 使用 二的更多相关文章

  1. Ansible Playbooks 介绍 和 使用 一

    目录 Ansible Playbooks Playbooks 组成部分: YAML 介绍 YAML 语法 Ansible 基础元素 变量 facts registre 通过命令传递变量 通过roles ...

  2. ansible运维工具(二)

    ansible playbook(二) 运行palybook时 要使用ansible-playbook命令 palybook执行任务的顺序是,在第一个主机上完成第一个任务,然后在第二个主机上完成第一个 ...

  3. Ansible简单介绍(一)

    一 :ansible简单介绍 此名取自 Ansible 作者最喜爱的<安德的游戏> 小说,而这部小说更被后人改编成电影 -<战争游戏>. 官网地址:https://www.an ...

  4. 第二十七章 ansible变量介绍

    一.ansible变量介绍 1.概念 变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其它地方或许会反复使用,那么如果讲 ...

  5. 3、Ansible playbooks(Hosts、Users、tasks、handlers、变量、条件测试(when、迭代)、templates)

    Ansible playbooks playbook是由一个或多个“play”组成的列表.play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色.从根本上来讲 ...

  6. 从Client应用场景介绍IdentityServer4(二)

    原文:从Client应用场景介绍IdentityServer4(二) 本节介绍Client的ClientCredentials客户端模式,先看下画的草图: 一.在Server上添加动态新增Client ...

  7. Ansible Playbooks入门介绍

    1.目录结构 2.详细目录 3.主任务文件main.yaml 主任务文件main.yaml - name: print server name and user to remote testbox # ...

  8. ansible的介绍和一些基本模块介绍

    必须保证ansible工作站与各个node实现无密码ssh登入 ①:192.168.1.100 - 在你本地的工作站或服务器上安装 Ansible.   ②:文件服务器1到代理服务器3 - 使用 19 ...

  9. ansible模块介绍之ios_command

    一.模块简介 ios_command此模块将任意命令发送到ios节点并返回设备读取的结果 此模块不支持在配置模式下使用,即只支持在用户模式>和特权模式#下使用 官方文档地址:https://do ...

随机推荐

  1. ElasticSearch 中文分词插件ik 的使用

    下载 IK 的版本要与 Elasticsearch 的版本一致,因此下载 7.1.0 版本. 安装 1.中文分词插件下载地址:https://github.com/medcl/elasticsearc ...

  2. 你遇到了吗?Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.fs.FileAlreadyExistsException)

    我在使用 Structured Streaming 的 ForeachWriter,写 HDFS 文件时,出现了这个异常 这个异常出现的原因是HDFS作为一个分布式文件系统,支持多线程读,但是不支持多 ...

  3. 深究1.8版本HashMap源码

    put方法 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } 在putVal方法之 ...

  4. Angular 项目中如何使用 ECharts

    在有些使用 ECharts 库的 Angular 项目中,通常除了安装 npm 包之外,还会在 angular.json 中配置 “build.options.scripts”,将 “node_mod ...

  5. Lost My Music:倍增实现可持久化单调栈维护凸包

    题目就是求树上每个节点的所有祖先中(ci-cj)/(dj-di)的最小值. 那么就是(ci-cj)/(di-dj)的最大值了. 对于每一个点,它的(ci,di)都是二维坐标系里的一个点 要求的就是祖先 ...

  6. CSPS模拟 42

    T3数位$dp$还没改完啊 哭了 T1 对$DAG$里所有点求他能到达的点的数量 考试时算了$bitset$内存扛不住,yy了个线段树合并上去 没有A不是因为被卡了,而是数组又开小了.. 我以为不能卡 ...

  7. Python调用函数加括号和不加括号的区别

    Python调用函数加括号和不加括号的区别 # -*- coding: utf-8 -*- #!/usr/bin/env python # @Time : 2018/7/3 10:03 # @Desc ...

  8. 02-model设计

    一.项目依赖包安装 1.安装Django(2.2.7) pip3 install django 2.安装DjangoRestFramework 因为DjangoRestFramework是基于Djan ...

  9. python内置模块collections介绍

    目录 python内置模块collections介绍 1.namedtuple 2.deque 3.defaultdict 4.OrderedDict 5.ChainMap 6.Counter 7.小 ...

  10. Havok Physics 2012(2)

    目录 Havok Physics 2012 Chapter 2. Creating a Simulation 创建一个模拟世界 1. Creating Physics 2012 Objects Hav ...