Ansible Playbook 根据任务状态执行特定任务
使用 handlers
先举个例子,用 Ansible 去修改 ssh 服务的配置文件并重启服务,下边这个 Playbook 可以实现这个功能:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
在这个 Playbook 中,每次执行都会重启 ssh 服务,虽然能够实现结果,但是不满足 Ansible 的幂等性规则。
为了解决这个问题,Ansible 可以做到在某些任务处于 changed 状态时执行特定任务,Ansible 通过一下三个字段实现这个功能:
notify:设置哪些任务处于changed时触发特定任务handlers:设置可由notify触发的任务listen:用于监听notify
下边是一个优化后的 Playbook:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
notify: restart sshd
handlers:
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
listen: restart sshd
这里可以看到:
- 设置 ssh 配置文件的 Play 有一个
notify内容为restart sshd,表示有一个restart sshd的通知 handlers下有一个重启 sshd 服务的 Play- 有一个
listen内容为restart sshd,这个和前边notify对应
这三个字段实现的功能就是当发生 ssh 配置文件修改时,重启 sshd 服务,如果没有发生配置文件修改,则重启 sshd 服务的 Play 不会执行。
[root@study ansible]# ansible-playbook /tmp/test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
ok: [servera]
TASK [restart ssh] ************************************************************************************************************************************************
changed: [servera]
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@study ansible]# ansible-playbook test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
ok: [servera]
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果
notify要触发的 Play 只有一个,那么listen可以省略,只需要notify的内容和handlers的 Play 的name对应上。如果
notify和loop结合使用,发生changed时,会将所有可触发的handlersPlay 执行一遍。https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#notifying-and-loops
多个任务触发同一个
handlersPlay 时,Play 只会执行一次。
handlers中含有静态导入或动态导入时,静态导入支持单独通知被导入的 Play,动态导入被通知时导入的任务会被全部执行。
设置 handlers 任务触发时间
默认情况下,handlers 的 Play 会在所有 tasks 都执行完后才去执行,通过 meta: flush_handlers 可以让 handlers 的 Play 提前执行:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
notify: restart sshd
- name: Flush handlers
meta: flush_handlers
- name: debug
ansible.builtin.debug:
msg: "Hello World!"
handlers:
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
listen: restart sshd
在这个 Playbook 中,重启服务的 Play 会在 debug 任务之前执行。
[root@study ansible]# ansible-playbook test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
changed: [servera]
TASK [Flush handlers] *********************************************************************************************************************************************
RUNNING HANDLER [restart ssh] *************************************************************************************************************************************
changed: [servera]
TASK [debug] ******************************************************************************************************************************************************
ok: [servera] => {
"msg": "Hello World!"
}
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0