特定のtaskに変更があったときだけ連動して動く処理を定義できるhandlerですが、処理の実行順序で思い違いしがちなところがあったので確認してみました。
(handlerを使ったroleがあるのを忘れて無邪気に次に処理されるroleを書き足したら期待しない実行順序になって処理がコケたというヤラカシがあったのでまとめ)
notify/handlerそのものについてはこちら参照。
- handlerを実装したrole
- post_tasks
- pre_tasks
- post_tasks/pre_tasksでhandler使用
- post_tasks/pre_tasksのnotify先が同じtaskの場合
- (参考) tasksとrolesの併用
- (参考) tasks/roles/pre_tasks/post_tasksの併用
- 処理順について書かれたドキュメント
- 処理順まとめ
- 確認環境
handlerを実装したrole
. ├── playbook.yml └── roles ├── sample1 │ ├── handlers │ │ └── main.yml │ └── tasks │ └── main.yml └── sample2 └── tasks └── main.yml
roleは以下の通り。
- sample1:
tasks
とhandlers
を実装(taskの結果によってhandlerの中身が起動する) - sample2:
tasks
のみ
playbookは以下の通りで、sample1 -> sample2 の順に実行。
--- - hosts: localhost gather_facts: false roles: - sample1 - sample2
ディレクトリ構造のイメージから、
- sample1のtask
- sample1のhandler
- sample2
の順序で実行されそう(roles/sample1
で定義された全処理が終わったらroles/sample2
)だけど、実際は、
- sample1のtask
- sample2のtask
- sample1のhandler
となり、「全roles
のtaskが処理されてからhandler」の順序で処理されます。
post_tasks
じゃあ「とあるrole/taskでhandlerを使いつつ、その処理後に通常のtask処理を行いたい」場合にどうすればよいかというと、post_tasks
を使います。
post_tasks: - name: this is post_tasks debug: msg: gochisousama desita. roles: - sample1 - sample2
post_tasks
に記述したtaskは、playbook内の記述順に関係なく、roles
の後に処理されます。
- roles/sample1のtask
- roles/sample2のtask
- roles/sample1のhandler
- post_tasksのtask
※ ↑のplaybookは処理順が決まってることを確認するためにpost_tasks
を最初に書いているけど、実際は最後に書いた方が直観的に処理順序が分かりやすい。
pre_tasks
postがあるならpreもある。
post_tasks: - name: this is post_tasks debug: msg: gochisousama desita. roles: - sample1 - sample2 pre_tasks: - name: this is pre_tasks debug: msg: itadakimasu
post_tasks
と同じように、playbook内の記述順に関係なく、rolesの前に処理されます。
- pre_tasksのtask
- roles/sample1のtask
- roles/sample2のtask
- roles/sample1のhandler
- post_tasksのtask
※ ↑のplaybookは処理順が決まってることを確認するためにpost_tasks
の例同様pre_tasks
を最後に書いているけど(ry
post_tasks/pre_tasksでhandler使用
post_tasks: - name: this is post_tasks debug: msg: gochisousama desita. - name: exec at post_task command: ls notify: post_notify roles: - sample1 - sample2 handlers: - name: pre_notify debug: msg: handler at pre_notify listen: pre_notify - name: post_notify debug: msg: handler at post_notify listen: post_notify post_tasks: - name: this is post_tasks debug: msg: gochisousama desita. - name: exec at pre_task command: ls notify: pre_notify
これはrolesのディレクトリ構造の勘違いと違って、
- pre_tasksのtask
- pre_tasksのhandler (ここで
pre_tasks
の全処理が完了) - rolesのsample1, sample2, rolesのhandler (ここで
roles
の全処理が完了) - post_tasksのtask
- post_tasksのhandler
「一連のtaskの中で複数回notifyされてもhandlerのtaskが処理されるのは1回」が基本動作だけど、post_tasks
とpre_tasks
のhandlerはそれぞれpost_tasks
のhandler、pre_tasks
のhandlerとして独立して1回ずつ処理されます。
post_tasks/pre_tasksのnotify先が同じtaskの場合
これは、handlerでnotifyで通知されたtaskはpost_tasks
/pre_tasks
それぞれで処理されます。
tasks
を追加しても同様に個別に処理されます。
「post_tasks
内で複数回notifyされても処理は1回」だけど「post_tasks
,pre_tasks
それぞれでnotifyされた場合は、それぞれで処理される」(テキストだと説明難しいな。。)
post_tasks: - name: exec at post_task command: ls notify: post_notify pre_tasks: - name: exec at pre_task command: ls notify: pre_notify tasks: - name: exec at task command: ls notify: task_notify handlers: - name: handler_at_task debug: msg: handler at task listen: task_notify - name: pre_notify debug: msg: handler at pre_notify listen: pre_notify - name: post_notify debug: msg: handler at post_notify listen: post_notify - name: all notify task debug: msg: curry! listen: - task_notify - pre_notify - post_notify
handlers
セクションがちょっとゴチャゴチャしてるけど、この場合の処理順序は以下の通り。
- pre_tasksのtask
- pre_tasksのhandlerでpre_notify
- pre_tasksのhandlerでall notify task
- tasks
- tasksのhandlerでhandler_at_task
- tasksのhandlerでall notify task
- post_tasksのtask
- post_tasksのhandlerでpre_notify
- post_tasksのhandlerでall notify task
(参考) tasksとrolesの併用
例題でよく出てくると思うけど、playの中でtasks
とroles
を両方定義した場合の処理順序。
tasks: - name: this task by "tasks" in playbook debug: msg: hello - name: exec at task command: ls notify: task_notify roles: - sample1 - sample2 handlers: - name: handler_at_task debug: msg: handler at task listen: task_notify
この場合は、記述順に関係なく、
- rolesの全てのtasks
- playの全てのtasks
- handlers
- rolesのhandlers
- playのhandlers
の順序。
(参考) tasks/roles/pre_tasks/post_tasksの併用
roles
+tasks
にさらにpre_tasks
/post_tasks
を組み込むとroles
/tasks
の前後に処理されます。
- pre_tasksの全処理
- rolesの全tasks
- tasksの全tasks
- roles/tasksのhandlers
- post_tasksの全処理
処理順について書かれたドキュメント
- Any
pre_tasks
defined in the play.- Any handlers triggered by pre_tasks.
- Each role listed in
roles:
, in the order listed. Any role dependencies defined in the role’smeta/main.yml
run first, subject to tag filtering and conditionals. See Using role dependencies for more details.- Any
tasks
defined in the play.- Any handlers triggered by the roles or tasks.
- Any
post_tasks
defined in the play.- Any handlers triggered by post_tasks.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
- handlers notified within
pre_tasks
,tasks
, andpost_tasks
sections are automatically flushed at the end of section where they were notified.- handlers notified within
roles
section are automatically flushed at the end oftasks
section, but before anytasks
handlers.- handlers are play scoped and as such can be used outside of the role they are defined in.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html
2.9だとこの記述は以下のURL。
pre_tasks(task -> handler) -> roles -> tasks -> handler(roles & tasks) -> post_tasks(task -> handler) の順序は明記されてるけど、rolesのhandlerとtasksのhandlerは特に明記されてない気がする。
(実際に動かしてみると、rolesのhandler -> tasksのhandlerの順になった)
処理順まとめ
- pre_tasksのtask
- pre_tasksによるhandler
- 全rolesのtask
- 全tasks
- rolesによる全handler
- tasksによる全handler
- post_tasksのtask
- post_tasksによるhandler
確認環境
(a2.10) [zaki@cloud-dev pre_post_tasks (master)]$ ansible-playbook --version ansible-playbook 2.10.2 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/src/ansible-sample/venv/a2.10/lib64/python3.6/site-packages/ansible executable location = /home/zaki/src/ansible-sample/venv/a2.10/bin/ansible-playbook python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
微妙に古いね…