Ansible: Why you should use the assert module instead of failed_when
Monday, October 24 2022 · Lesezeit: 3 Minuten · 547 Wörter · Tags: ansibleAs an ansible user you may be familiar with the failed_when
clause of a task. Its condition should resolve to a boolean value and determines if it was successful or not. In my backup playbook I’ve a task creating a tar archive by using the command module. Later on I want to check if an actual POSIX tar archive was created:
- name: Check if a real tar archive was created
command: "file /mnt/backups/mail.veloc1ty.de/{{ ansible_date_time.date }}.tar"
register: filecommandoutput
failed_when: "'POSIX tar archive' not in filecommandoutput.stdout"
This task should fail when POSIX tar archive
is not found in the file
command output. If the string is not found the task should fail and force me to investigate the problem. However this could also be done in two tasks:
- name: Check if a real tar archive was created
command: "file /mnt/backups/mail.veloc1ty.de/{{ ansible_date_time.date }}.tar"
register: filecommandoutput
- name: Assert file command output
assert:
that: "'POSIX tar archive' not in filecommandoutput.stdout"
What’s the difference? Nothing! Both tasks fail perfectly if no tar archive is detected. The real advantage comes into play when you need to chain multiple conditions together, because the assert
module will tell you which condition actually failed. This can be very helpful for you as a human debugging the playbook.
Maybe another example helps you understand the advantage: Another check I do in my backup playbook is counting the backed up mails. Here is how the tasks would look like with the failed_when
clause:
- name: Check tar archive containing actual mails
shell: "tar -tf /mnt/backups/mail.veloc1ty.de/{{ ansible_date_time.date }}.tar | grep /home/vmail/veloc1ty.de/hello/Maildir/cur/ | wc -l"
register: taroutput
failed_when: taroutput.stdout and taroutput.stdout | int and taroutput | int < 1000
The failed_when
clause checks that taroutput.stdout
- exists
- is an integer
- is greater than 1000 (“more than 1000 mails are stored in that directory”)
Here is the resulting task output:
TASK [Check tar archive containing actual mails] ************************************
fatal: [XXX.veloc1ty.de]: FAILED! => {"changed": true, "cmd": "tar -tf /mnt/backups/mail.veloc1ty.de/2022-10-24.tar | grep /home/vmail/veloc1ty.de/hello/Maildir/cur/ | wc -l", "delta": "0:00:03.628501", "end": "2022-10-24 21:42:20.539682", "failed_when_result": true, "msg": "", "rc": 0, "start": "2022-10-24 21:42:16.911181", "stderr": "", "stderr_lines": [], "stdout": "15773", "stdout_lines": ["15773"]}
All we know now is that the task failed but we have no clue why. The next step is to add a debug
tasks and manually check the condition. This can all be avoided by using the assert
module. Here is the same task refactored:
- name: Check tar archive containing actual mails
shell: "tar -tf /mnt/backups/mail.veloc1ty.de/{{ ansible_date_time.date }}.tar | grep /home/vmail/veloc1ty.de/hello/Maildir/cur/ | wc -l"
register: taroutput
- name: Assert tar archive mail content
assert:
that:
- taroutput.stdout is defined
- taroutput.stdout | int
- taroutput.stdout | int < 1000
The task output of course failed, too:
TASK [Assert tar archive mail content] ************************************
fatal: [XXX.veloc1ty.de]: FAILED! => {
"assertion": "taroutput.stdout | int < 1000",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}
The assert
module tells us exactly which assertion failed. Of course I want to check if I’ve more than 1000 mails backed up and not less than 1000. Did you spot the error in the failed_when
approach above?
Here is my rule of thumb: If you only have one condition: Use failed_when
. If you have multiple conditions include the extra assert
task and prevent your future self from adding debug
tasks!
Du hast einen Kommentar, einen Wunsch oder eine Verbesserung? Schreib mir doch eine E-Mail! Die Infos dazu stehen hier.
🖇️ = Link zu anderer Webseite
🔐 = Webseite nutzt HTTPS (verschlüsselter Transportweg) Zurück