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
时,会将所有可触发的handlers
Play 执行一遍。https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#notifying-and-loops
多个任务触发同一个
handlers
Play 时,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