如何控制 Ansible Playbook任务的执行

举报
山河已无恙 发表于 2022/08/25 00:34:27 2022/08/25
【摘要】 写在前面今天和小伙伴们分享一些 Ansible 中如何控制剧本任务执行的笔记博文内容分为两部分,控制任务执行,和控制主机执行顺序,涉及内容:剧本默认执行顺序分析Demo,先角色后任务import 或 include 导入角色的demo在剧本执行前后的钩子处理不同情况下的 handler 执行情况,批量执行 handler(推拉两种方式)如何控制执行主机的顺序食用方式了解 Ansible 基础...

写在前面


  • 今天和小伙伴们分享一些 Ansible 中如何控制剧本任务执行的笔记
  • 博文内容分为两部分,控制任务执行,和控制主机执行顺序,涉及内容:
    • 剧本默认执行顺序分析Demo,先角色后任务
    • import 或 include 导入角色的demo
    • 在剧本执行前后的钩子处理
    • 不同情况下的 handler 执行情况,批量执行 handler(推拉两种方式)
    • 如何控制执行主机的顺序
  • 食用方式
    • 了解 Ansible 基础知识
    • 可以编写 Ansible 剧本、角色
  • 理解不足小伙伴帮忙指正

“别把我跟你混为一谈,我努力过,所以我不后悔。”


使用的 ansibler 版本

$ ansible --version
ansible 2.8.0rc1
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/student/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.8 (default, Apr  3 2019, 17:26:03) [GCC 8.2.1 20180905 (Red Hat 8.2.1-3)]
$

控制任务执行

角色最先执行

在 Play 中,Ansible 始终先执行角色中的任务,然后执行在tasks部分下定义的任务,来看一个Demo

$ cat deploy_apache_demo.yml
---
- name: Ensure Apache is deployed
  hosts: all
  gather_facts: no

  tasks:
    - name: Open the firewall
      firewalld:
        service: http
        permanent: yes
        state: enabled
  roles:
    - role: apache

上面的执行,我们可以看到执行数据顺序为,先执行firewall角色,然后执行apache角色,最后执行的是 Open the firewall,

PLAY [Ensure Apache is deployed] *********************************************************************
.....
TASK [firewall : Ensure Firewall Sources Configuration] **********************************************
.....
TASK [apache : Ensure httpd packages are installed] **************************************************
.....
TASK [apache : Ensure SELinux allows httpd connections to a remote database] *************************
.....
TASK [apache : Ensure httpd service is started and enabled] ******************************************
.....
TASK [Open the firewall] *****************************************************************************
.....
PLAY RECAP *******************************************************************************************

剧本里没有定义firewall,为什么会执行,是因为apache角色依赖了他,我们可以在apache角色的meta目录的maia.ymal 文件下面看到,它依赖了firewall角色

$ cat roles/apache/meta/main.yml  | grep -C 2 firewall
dependencies:
  - name: firewall
  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
  # if you add dependencies to this list.
$

所以不管剧本编写顺序如何,同一剧本中执行顺序为,依赖角色要在当前角色之前执行,当前角色role要在调用剧本任务task之前执行。

为了剧本的可读性,一般情况下,剧本任务是写在角色后面的,整个书写顺序也就是执行顺序。

那么,如果我们希望在角色执行前执行任务,应该如何处理,有两种方法,其一是使用task钩子,类似生命周期中的回调函数一样,另一钟方法,即下面提到的,使用import或者include,关于这两个动作,小伙伴们一定不陌生,前端常见的模板引擎一般都会涉及到。不同的动作,实现相对的功能,但是原理是不同的

import 或 include 作为任务的角色

Ansible的最新版本允许将角色作为任务来包含或导入,而不是使用play中的角色部分。通过这样的方式,可以使剧本按照编写的顺序执行,而不是先执行角色的方式

  • 优点是可以按照编写顺序运行一组任务、导入或包含一个角色,然后运行更多的任务。
  • 缺点是,在没有仔细检查的情况下,可能不太清楚您的剧本使用的是哪些角色,因为角色切入了任务内部

import和include 有些许区别

  • 使用include_role模块可以动态包含角色,
  • 使用import_role模块则可静态导入角色。

创建一个角色,执行的任务为打印当前的主机名

$ ansible-galaxy init role_tasks_demo
$ echo "- shell: hostname" > roles/role_tasks_demo/tasks/main.yml 

编写剧本,两种不同的方式引入角色

---
- name: Executing a role as a task
  hosts: a_web_servers
  tasks:
     - name: A normal task
       debug:
         msg: 'first task'
     - name: A task to import_role role_tasks_demo   here
       import_role:
         name: role_tasks_demo
     - name: A task to include role_tasks_demo   here
       include_role:
         name: role_tasks_demo
     - name: Another normal task
       debug:
         msg: 'second task'


执行剧本

$ ansible-playbook  role_tasks.yaml
PLAY [Executing a role as a task] ********************************************************************
TASK [Gathering Facts] *******************************************************************************
ok: [serverb.lab.example.com]

TASK [A normal task] *********************************************************************************
ok: [serverb.lab.example.com] => {
    "msg": "first task"
}
TASK [role_tasks_demo : shell] ***********************************************************************
changed: [serverb.lab.example.com]
TASK [A task to include role_tasks_demo   here] ******************************************************
TASK [role_tasks_demo : shell] ***********************************************************************
changed: [serverb.lab.example.com]
TASK [Another normal task] ***************************************************************************
ok: [serverb.lab.example.com] => {
    "msg": "second task"
}
PLAY RECAP *******************************************************************************************
serverb.lab.example.com    : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

我们可以看到,按照任务编写的顺序执行,角色执行了两次,这里需要注意一点,通过 import_role 方式导入的角色并会作为当前剧本的一部分,而通过 include 的方式会作为一个单独的任务模块来执行,我么通过执行的输出也可以看到,具体的原因:

  • 使用import_role时,ansible-playbook 命令首先解析角色并插入到play中,然后开始执行。Ansible 会立即检测和报告语法错误,不会开始执行playbook。

  • 使用 include_role 时,Ansible 会在 play 执行期间到达 include_role 任务时解析角色并插⼊到 play 中。如果Ansible 检测到角色中存在语法错误,则中止执行 playbook 。

对于 when 指令的行为有所不同。使用include_role任务时,如果when指令中的条件为 false,则 Ansible不解析角色。看一个Demno

$ cat role_tasks.yaml
---
- name: Executing a role as a task
  hosts: servera
  tasks:
     - name: A normal task
       debug:
         msg: 'first task'

     - name: import_role role
       import_role:
         name: role_tasks_demo
       when: false

     - name: include_role role
       include_role:
         name: role_tasks_demo

     - name: Another normal task
       debug:
         msg: 'second task'

执行我么可以看到。import_role被直接跳过了,因为when的原因,并没有执行

$ ansible-playbook  role_tasks.yaml
PLAY [Executing a role as a task] *********************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [servera]
TASK [A normal task] **********************************************************************************
ok: [servera] => {
    "msg": "first task"
}
TASK [role_tasks_demo : shell] ************************************************************************
skipping: [servera]
TASK [include_role role] ******************************************************************************
TASK [role_tasks_demo : shell] ************************************************************************
changed: [servera]
TASK [Another normal task] ****************************************************************************
ok: [servera] => {
    "msg": "second task"
}
PLAY RECAP ********************************************************************************************
servera                    : ok=4    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

角色执行前&&任务执行后的钩子

有时候我们希望⼀个剧本 在角色之前运行某些任务,以及它们所通知的处理程序。也可能希望在普通任务tasks处理程序handler运行后运行 play 中的任务

可以使用两个指令(而非 tasks)来实现这一目标:

  • pre_tasks 是在 roles 部分前运行的 tasks 部分
  • post_tasks 是在 tasks 部分以及 tasks 所通知的任何处理程序后运行的 tasks 部分

我们通过Demo来看下,创建一个测试角色,同样打印主机名

$ ansible-galaxy  init tasks_hook_demo
$ echo "- shell: hostname" > roles/tasks_hook_demo/tasks/main.yml

编写剧本,使用 pro_takspost_task来执行剧本之前前后的钩子任务

---
- name: task task exec order
  hosts: a_web_servers
  pre_tasks:
     - name: pre_tasks in task
       shell: echo 'pre_tasks'
  post_tasks:
     - name: post_tasks in taks
       shell: echo 'post_tasks'
  tasks:
     - name: task
       shell: echo 'tasks'
  roles:
    - tasks_hook_demo

可以看到编写顺序并不会影响到执行顺序

$ ansible-playbook  tasks_hook.yaml
PLAY [task task exec order] **************************************************************************
TASK [Gathering Facts] *******************************************************************************
ok: [serverb.lab.example.com]
TASK [pre_tasks in task] *****************************************************************************
changed: [serverb.lab.example.com]
TASK [tasks_hook_demo : shell] ***********************************************************************
changed: [serverb.lab.example.com]
TASK [task] ******************************************************************************************
changed: [serverb.lab.example.com]
TASK [post_tasks in taks] ****************************************************************************
changed: [serverb.lab.example.com]
PLAY RECAP *******************************************************************************************
serverb.lab.example.com    : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

上面的执行顺序为 pre_tasks > roles > tasks > post_tasks,不管语句顺序如何变化,都不会改变执行顺序

这里,有小伙伴会想到,如果任务中有handlers应该如何处理?

handlers的执行顺序

Ansible 按照以下顺序运行 Play 的不同部分:

  • pre_tasks
  • pre_tasks 部分中通知的处理程序 handlers
  • roles
  • tasks
  • roles 和 tasks 部分中通知的处理程序 handlers
  • post_tasks
  • post_tasks 部分中通知的处理程序 handlers

这些部分在 Play 中的顺序不会修改以上列出的执行顺序。来看一个demo

这里我们先创建一个角色,使用shell 模块打印一句话

$ ansible-galaxy  init task_liruilong_exec_order --init-path=roles
- task_liruilong_exec_order was created successfully
$ ansible-galaxy  list | grep liruilo
- task_liruilong_exec_order, (unknown version)
$ tee  roles/task_liruilong_exec_order/tasks/main.yml <<- EOF
> ---
> - name: role: task_liruilong_exec_order
>   shell: echo "roles  liruilong"
> EOF
---
- name: role task_liruilong_exec_order
  shell: echo "roles  liruilong"

然后我在角色中添加一个通知,在角色的handlers文件夹中定义执行的事件,在taks发生chagent的时候会触发通知,执行通知的handler

$ vim roles/task_liruilong_exec_order/tasks/main.yml
$ cat roles/task_liruilong_exec_order/tasks/main.yml
---
- name: role  task_liruilong_exec_order
  shell: echo "roles  liruilong"
  notify:
    - role_handler
$ vim roles/task_liruilong_exec_order/handlers/main.yml
$ cat roles/task_liruilong_exec_order/handlers/main.yml
---
# handlers file for task_liruilong_exec_order
- name: role_handler
  shell: echo 'role in role_handler'
$ vim task_order.yaml

来看下我们的剧本,在pre_tasks和post_tasks,tasks中,都有剧本中handler的notify。

$ cat task_order.yaml
---
- name: tesk task exec order
  hosts: servera
  pre_tasks:
     - name: task in pre_taks
       shell: echo 'task in pre_tasks'
       notify:
         - ploybook_in_handler
  roles:
     - role: task_liruilong_exec_order

  tasks:
     - name: task in tasks
       shell: echo 'task in tasks'
       notify:
         - ploybook_in_handler

  post_tasks:
     - name: taks in post_tasks
       shell: echo 'task in post_tasks'
       notify:
         - ploybook_in_handler

  handlers:
     - name: ploybook_in_handler
       shell: echo ' ploybook in handle'

执行剧本,可以看到剧本你的执行顺序为:pre_taks > pre_taks handler > role > tasks > role handler > tasks handler > post_tasks > post_tasks handler

$ ansible-playbook  task_order.yaml
PLAY [tesk task exec order] **************************************************************************
TASK [Gathering Facts] *******************************************************************************ok: [servera]
TASK [task in pre_taks] ******************************************************************************changed: [servera]
RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera]
TASK [task_liruilong_exec_order : role  task_liruilong_exec_order] ***********************************changed: [servera]
TASK [task in tasks] *********************************************************************************changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler] *******************************************changed: [servera]
RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera]
TASK [taks in post_tasks] ****************************************************************************changed: [servera]
RUNNING HANDLER [ploybook_in_handler] ****************************************************************changed: [servera]
PLAY RECAP *******************************************************************************************servera                    : ok=9    changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

这里要说明的是剧本中这些块的顺序不会改变执行顺序。一个剧本包含pre_tasks,roles,tasks,post tasks和handlers部分是不寻常的。如果在多个部分中得到通知,则处理程序handler可以在剧本执行期间的不同时间多次运行。但是不会存在 一个处理的程序连续执行多次,即同一时间段,多此次通知只执行一次。

那么这里的话,如果我希望某一任务在发生change后,同时通知多个处理程序handler,应该如何处理

任务一次性通知多个handlers任务

  • 按名称通知handlers列表。
  • 通知配置了listen来监听多个handlers

下面的剧本中,notify部分并没有发生改变,但是handlers部分我们添加一个listen属性,即由原来的通知变成了监听,这里其实有点类似观察者设计模式的两种实现方式,当观察者的数据较少的时候,采用的是推的一种方式,较多时,通过拉的方式实现。

---
- name: tesk task exec order
  hosts: servera
  pre_tasks:
     - name: task in pre_taks
       shell: echo 'task in pre_tasks'
       notify:
         - ploybook_in_handler
  roles:
     - role: task_liruilong_exec_order

  tasks:
     - name: task in tasks
       shell: echo 'task in tasks'
       notify:
         - ploybook_in_handler

  post_tasks:
     - name: taks in post_tasks
       shell: echo 'task in post_tasks'
       notify:
         - ploybook_in_handler

  handlers:
     - name: ploybook_in_handler 1
       shell: echo ' ploybook in handle 1'
       listen: ploybook_in_handler
     - name: ploybook_in_handler 2
       shell: echo ' ploybook in handle 2'
       listen: ploybook_in_handler
student@workstation task-execution]$ ansible-playbook  task_order.yaml
PLAY [tesk task exec order] ***************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [servera]
TASK [task in pre_taks] *******************************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] ***************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] ***************************************************************
changed: [servera]
TASK [task_liruilong_exec_order : role  task_liruilong_exec_order] ************************************
changed: [servera]
TASK [task in tasks] **********************************************************************************
changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler] ********************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] ***************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] ***************************************************************
changed: [servera]
TASK [taks in post_tasks] *****************************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] ***************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] ***************************************************************
changed: [servera]
PLAY RECAP ********************************************************************************************
servera                    : ok=12   changed=11   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

当然,有小伙伴说,我不嫌麻烦,我就想每次推,那么应该如何实现,可以在notafy写成一个list

$ cat  roles/task_liruilong_exec_order/tasks/main.yml
---
- name: role  task_liruilong_exec_order
  shell: echo "roles  liruilong"
  notify:
    - role_handler1
    - role_handler2

$ cat roles/task_liruilong_exec_order/handlers/main.yml
---
# handlers file for task_liruilong_exec_order
- name: role_handler1
  shell: echo 'role in role_handler 1'
- name: role_handler2
  shell: echo 'role in role_handler 2'
$

这样也是可以的

$ ansible-playbook task_order.yaml
PLAY [tesk task exec order] ***************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [servera]
.........
TASK [task_liruilong_exec_order : role  task_liruilong_exec_order] ************************************
changed: [servera]
TASK [task in tasks] **********************************************************************************
changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler1] *******************************************
changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler2] *******************************************
changed: [servera]
.....

在上面的Demo中,我们可以看到,任务处理程序 handler 总是在一个任务块处理完之后才会执行,那如果我希望在任务执行到一半,执行前面的任务处理程序,应该这么处理?

立即运行剧本中特定任务通知的任何处理程序

若要立即运行由 Play 中特定任务通知的任何处理程序,可以添加一个使用 meta 模块 flush_handlers 参数任务:

meta: flush_handlers

---
- name: tesk task exec order
  hosts: servera
  pre_tasks:
     - name: task in pre_taks
       shell: echo 'task in pre_tasks'
       notify:
         - ploybook_in_handler
  roles:
     - role: task_liruilong_exec_order

  tasks:
     - name: task in tasks 1
       shell: echo 'task in tasks 1'
       notify:
         - ploybook_in_handler

     - meta: flush_handlers

     - name: task in tasks 2
       shell: echo 'task in tasks 2'
       notify:
         - ploybook_in_handler

  post_tasks:
     - name: taks in post_tasks
       shell: echo 'task in post_tasks'
       notify:
         - ploybook_in_handler

  handlers:
     - name: ploybook_in_handler 1
       shell: echo ' ploybook in handle 1'
       listen: ploybook_in_handler
     - name: ploybook_in_handler 2
       shell: echo ' ploybook in handle 2'
       listen: ploybook_in_handler

$ ansible-playbook  task_order.yaml
PLAY [tesk task exec order] **************************************************************************
TASK [Gathering Facts] *******************************************************************************
ok: [servera]
TASK [task in pre_taks] ******************************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] **************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] **************************************************************
changed: [servera]
TASK [task_liruilong_exec_order : role  task_liruilong_exec_order] ***********************************
changed: [servera]
TASK [task in tasks 1] *******************************************************************************
changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler1] ******************************************
changed: [servera]
RUNNING HANDLER [task_liruilong_exec_order : role_handler2] ******************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] **************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] **************************************************************
changed: [servera]
TASK [task in tasks 2] *******************************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] **************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] **************************************************************
changed: [servera]
TASK [taks in post_tasks] ****************************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 1] **************************************************************
changed: [servera]
RUNNING HANDLER [ploybook_in_handler 2] **************************************************************
changed: [servera]
PLAY RECAP *******************************************************************************************
servera                    : ok=16   changed=15   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
$

控制主机执行顺序

Ansible根据剧本hosts指令确定要管理的主机。默认情况下,Ansible2.4和更高版本根据清单中主机列出的顺序运行剧本。您可以使用order指令更改该顺序。

order指令接受以下值:

  • inventory 清单顺序。这是默认值。
  • reverse_inventory 清单相反顺序。
  • sorted 主机按字母顺序排列。数字在字母前排序。
  • reverse_sorted 主机以相反的字母顺序排列。
  • shuffle 每次您执行剧本时,随机排序。

由于Ansible通常在多个主机上并行运行每个任务,因此 ansible-playbook 命令的输出可能无法反映预期的顺序:输出显示的是任务完成顺序,而不是执行顺序。

来看一个Demo,下面的配置中,我们定义了order: sorted的顺序执行主机

$ cat  host-all.yaml
---
- name: Executing a role as a task
  hosts: all
  order: sorted
  tasks:
     - name: A normal task
       debug:
         msg: 'first task'

可以看到执行顺序即为字母顺序

$ ansible-playbook  host-all.yaml -f 1
PLAY [Executing a role as a task] *********************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [servera]
ok: [serverb]
ok: [serverc]
ok: [serverd]
ok: [servere]
ok: [serverf]
TASK [A normal task] **********************************************************************************
ok: [servera] => {
    "msg": "first task"
}
ok: [serverb] => {
    "msg": "first task"
}
ok: [serverc] => {
    "msg": "first task"
}
ok: [serverd] => {
    "msg": "first task"
}
ok: [servere] => {
    "msg": "first task"
}
ok: [serverf] => {
    "msg": "first task"
}
PLAY RECAP ********************************************************************************************
servera                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverd                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
servere                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverf                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

主机执行顺序为随机执行

$ cat host-all.yaml
---
- name: Executing a role as a task
  hosts: all
  order: shuffle
  tasks:
     - name: A normal task
       debug:
         msg: 'first task'

$ ansible-playbook  host-all.yaml -f 1

PLAY [Executing a role as a task] *********************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [serverb]
ok: [serverc]
ok: [servere]
ok: [serverf]
ok: [serverd]
ok: [servera]

TASK [A normal task] **********************************************************************************
ok: [serverf] => {
    "msg": "first task"
}
ok: [servera] => {
    "msg": "first task"
}
ok: [servere] => {
    "msg": "first task"
}
ok: [serverd] => {
    "msg": "first task"
}
ok: [serverb] => {
    "msg": "first task"
}
ok: [serverc] => {
    "msg": "first task"
}

PLAY RECAP ********************************************************************************************
servera                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverd                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
servere                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverf                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

我们来看一个具体的实际应用。

实战

$ cat deploy_haproxy.yml
- name: Ensure HAProxy is deployed
  hosts: lb_servers
  force_handlers: True

  pre_tasks:
    - name: Setting the maintenance message
      copy:
        dest: /etc/motd.d/maintenance
        content: "Maintenance in progress\n"

  roles:
    # The "haproxy" role has a dependency on the "firewall" role.
    # The "firewall" role requires a "firewall_rules" variable be defined.
    - role: haproxy

  post_tasks:
    - name: Removing the maintenance message
      file:
        path: /etc/motd.d/maintenance
        state: absent

  handlers:
    - name: Sending an email to student
      mail:
        subject: "HAProxy reloaded on {{ inventory_hostname }}"
        to: student@workstation.lab.example.com
      delegate_to: localhost
      become: false
      listen: reload haproxy

    - name: Logging a message to syslog
      syslogger:
        msg: "HAProxy reloaded on {{ inventory_hostname }}"
      delegate_to: localhost
      become: false
      listen: reload haproxy

上面的剧本在执行haproxy这个角色的时候,通过pro_taks添加登录时的欢迎信息,提示系统正在维护,维护信息写到 /etc/motd.d/maintenance,同时在角色执行完后,在post_tasks中删除欢迎信息。

同时监听角色中的haproxy services文件重新加载的事件,当服务配置文件重新load的时候,发送邮件,并且写入系统日志

$ cat roles/haproxy/handlers/main.yml
---
# handlers file for haproxy


- name: restart haproxy
  service:
    name: haproxy
    state: restarted

- name: reload haproxy
  service:
    name: haproxy
    state: reloaded

$

执行剧本

$ ansible-playbook  deploy_haproxy.yml
PLAY [Ensure HAProxy is deployed] *********************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [servera.lab.example.com]
TASK [Setting the maintenance message] ****************************************************************
changed: [servera.lab.example.com]
TASK [firewall : Ensure Firewall Sources Configuration] ***********************************************
ok: [servera.lab.example.com] => (item={'port': '80/tcp'})
TASK [haproxy : Ensure haproxy packages are present] **************************************************
changed: [servera.lab.example.com]
TASK [haproxy : Ensure haproxy is started and enabled] ************************************************
changed: [servera.lab.example.com]
TASK [haproxy : Ensure haproxy configuration is set] **************************************************
changed: [servera.lab.example.com]
RUNNING HANDLER [haproxy : reload haproxy] ************************************************************
changed: [servera.lab.example.com]
RUNNING HANDLER [Sending an email to student] *********************************************************
ok: [servera.lab.example.com]
RUNNING HANDLER [Logging a message to syslog] *********************************************************
changed: [servera.lab.example.com]
TASK [Removing the maintenance message] ***************************************************************
changed: [servera.lab.example.com]
PLAY RECAP ********************************************************************************************
servera.lab.example.com    : ok=10   changed=7    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
You have new mail in /var/spool/mail/student

登录机器可以发现系统维护的信息,等角色执行完。维护信息消失

$ ssh servera
Activate the web console with: systemctl enable --now cockpit.socket

Maintenance in progress
[student@servera ~]$ exit
logout
Connection to servera closed.
You have mail in /var/spool/mail/student
$ ssh servera
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Sat Aug 13 01:15:44 2022 from 172.25.250.9
[student@servera ~]$

可以看到邮件信息

$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/student": 1 message 1 new
>N  1 root@workstation.lab  Sat Aug 13 01:10  27/1102  "HAProxy reloaded on servera.lab.example.com"
& q
Held 1 message in /var/spool/mail/student

博文参考


《Red Hat Ansible Engine 2.8 DO447》


关于Ansible最佳实践之Playbook控制任务的执行就和小伙伴们分享到这里, 生活加油哦 ^_^

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。