Improve Ansible tasks by debugging them
Say you’re working on the below task.
- name: Check if webroot exists
stat:
path: /var/www/public_html
When running your playbook, the task will return ‘ok’ whether the directory exists or not.
TASK [Check if webroot exists] *********************************
ok: [203.0.113.2]
That’s not exactly what we want. How can we do something about it and make our task more accurate? Enter the debug module.
First, you need to register an arbitrary variable to identify your task.
- name: Check if webroot exists
stat:
path: /var/www/public_html
register: webroot
Now, we can add the below code under the task:
- debug: msg=
This will invoke the debug
module and will return the result of the task for you to better understand what’s going on.
TASK [debug] *****************************************************
ok: [203.0.113.2] => {
"msg": {
"changed": false,
"stat": {
"exists": false
}
}
}
Above, we can see it returned false
, which means our directory doesn’t exist. Good. Now, let’s improve our task to reflect that.
We essentially have three options. Either we want the playbook to continue, either we want it to fail…but continue, or we want it to fail immediately. It’s up to you to decide what should happen now. Is the task required for you to proceed in the playbook? Then make it fail (Or fix it on the fly. More below). Is it not critical to the execution of the playbook? Then let it run. Ansible offers the changed_when
or failed_when
parameters to achieve just that. It also offers a few more fine-grained options (e.g. max_fail_percentage
, any_errors_fatal
) for advanced usage. Please refer to Ansible’s error handling for all details.
Below, we’ll be forcing the task to fail immediately if the directory doesn’t exist.
- name: Check if webroot exists
stat:
path: /var/www/public_html
register: webroot
failed_when: webroot.stat.exists == false
Note the failed_when
construct: we’re drilling down through the previous debug
output to narrow-down our check to the true/false boolean only.
If we run the playbook again, it’ll stop immediately upon failure.
TASK [Check if webroot exists] *************************************************
fatal: [203.0.113.2]: FAILED! => {"changed": false, "failed": true, "failed_when_result": true, "stat": {"exists": false}}
The playbook recap will also show a failure.
PLAY RECAP *******************************************************
203.0.113.2 : ok=76 changed=3 unreachable=0 failed=1
Alternatively, we can make it fail but continue with the remaining tasks. This needs us to add a new ignore_errors
parameter.
- name: Check if webroot exists
stat:
path: /var/www/public_html
register: webroot
failed_when: webroot.stat.exists == false
ignore_errors: true
We have a failure but the playbook continues to run.
TASK [Check if webroot exists] *************************************************
fatal: [203.0.113.2]: FAILED! => {"changed": false, "failed": true, "failed_when_result": true, "stat": {"exists": false}}
...ignoring
Sure it’ll show a big red line to indicate failure, but if you have tens of tasks, you might not see it. The playbook recap will also not outline a failure, which is why I wouldn’t necessarily recommend this option.
What about fixing the issue on the fly instead? Because after all that’s what we want, and nothing else.
- name: Check if webroot exists
stat:
path: /var/www/public_html
register: webroot
- name: Create webroot directory
file:
path: /var/www/public_html
state: directory
mode: 0755
when: webroot.stat.exists == false
What we’re doing here is we’re first checking if the directory exists and we’re not making any assumption about it. The task will return ‘ok’ because it has performed its check successfully no matter the result. What’s more interesting is we’re then creating the missing directory if and only if it doesn’t already exist. And to do that we’re relying on the output the debug
module gave us previously. Nifty.
Here’s what your playbook output will now look like on the first run:
TASK [Check if webroot exists] *************************************************
ok: [203.0.113.2]
TASK [Create webroot directory] *********************************
changed: [203.0.113.2]
And on subsequent runs:
TASK [Check if webroot exists] *************************************************
ok: [203.0.113.2]
TASK [Create webroot directory] ************************************************
skipping: [203.0.113.2]
Any task for which the condition will not be met will be automatically skipped. This considerably speeds up playbook runs.
Improving your tasks to make them more relevant and reliable starts with understanding the underlying debug code generated by your Ansible modules. Use it!