Reputation: 2071
I'm currently writing an Ansible play that follows this general format and is run via a cron job:
pre_tasks:
-Configuration / package installation
tasks:
-Work with installed packages
post_tasks:
-Cleanup / uninstall packages
The problem with the above is that sometimes a command in the tasks
section fails, and when it does the post_tasks
section doesn't run, leaving the system in a messy state. Is it possible to force the commands in post_tasks
to run even if a failure or fatal error occurs?
My current approach is to apply ignore_errors: yes
to everything under the tasks
section, and then apply a when:
conditional to each task to individually check if the prior command succeeded.
This solution seems like a hack, but it gets worse because even with ignore_errors: yes
set, if a Fatal error is encountered for a task the entire play will still immediately fail, so I have to also run a cron'd bash script to manually check on things after reach play execution.
All I want is a guarantee that even if tasks
fails, post_tasks
will still run. I'm sure there is a way to do this without resorting to bash script wrappers.
Upvotes: 35
Views: 33790
Reputation: 4074
@MarkTamsky is right, but here's also a quick explanation.
You can group multiple tasks into block
s and then task directives will be one level deeper (like the code in a "try" block in most OO languages), and at the higher level, you can control what happens if one or more of these block tasks fail(s) with rescue
(like "catch"es after "try" blocks).
Also if you need some tasks to run at the end of the execution of the block tasks (i.e., no matter whether those block tasks fail or not) you can use always
(like Python's "finally").
Example(directly copied from the documentation):
- name: Attempt and graceful roll back demo
block: # <--- a block of tasks
- name: Print a message
ansible.builtin.debug:
msg: 'I execute normally'
- name: Force a failure
ansible.builtin.command: /bin/false
- name: Never print this
ansible.builtin.debug:
msg: 'I never execute, due to the above task failing, :-('
rescue: # <--- a rescue
- name: Print when errors
ansible.builtin.debug:
msg: 'I caught an error'
- name: Force a failure in middle of recovery! >:-)
ansible.builtin.command: /bin/false
- name: Never print this
ansible.builtin.debug:
msg: 'I also never execute :-('
always: # <--- an always
- name: Always do this
ansible.builtin.debug:
msg: "This always executes"
NOTICE 1: Each block must be in a "tasks", i.e.:
tasks:
- name: some name
block:
- name: some name
<module>
NOTICE 2: Every directive (e.g. when
, become
, etc.) at the block level will be applied to "each of the tasks in the block one by one" and not to the block itself.
Upvotes: 4
Reputation: 854
This feature became available in Ansible 2.0:
This is the documentation for the new stanza markers block
, rescue
, and always
.
Upvotes: 63
Reputation: 71
You should use handlers (http://docs.ansible.com/ansible/playbooks_intro.html) and set:
force_handlers: true
Please give a look to KubeNow's integration test (https://github.com/kubenow/KubeNow/blob/master/test/integration-test.yml).
Upvotes: 3
Reputation: 9346
Don't use post_tasks
block but rather have your cleanup process as part of regular tasks
.
Upvotes: -15