If you’re using the shell module with Ansible and piping the output to another command, it might be a good idea to set pipefail. This way, if the first command fails, the whole task will fail.
For example, let’s say we’re running this silly task to look for /tmp directory and then trim the string “tmp” from the result.
ansible all -i "localhost," -m shell -a \ 'ls -ld /tmp | tr -d tmp'
This will return something like this, with a successful return code.
localhost | CHANGED | rc=0 >>
drwxrwxrw. 26 roo roo 640 Se 28 19:08 /
But, let’s say the directory doesn’t exist, what would the result be?
ansible all -i "localhost," -m shell -a \ 'ls -ld /tmpnothere | tr -d tmp'
Still success because of the pipe to trim was successful, even though we can see the ls command failed.
localhost | CHANGED | rc=0 >>
ls: cannot access ‘/tmpnothere’: No such file or directory
This time, let’s set pipefail first.
ansible all -i "localhost," -m shell -a \ 'set -o pipefail && ls -ld /tmpnothere | tr -d tmp'
This time it fails, as expected.
localhost | FAILED | rc=2 >>
ls: cannot access ‘/tmpnothere’: No such file or directorynon-zero return code
If /bin/sh on the remote node does not point to bash then you’ll need to pass in an argument specifying bash as the executable to use for the shell task.
- name: Silly task shell: set -o pipefail && ls -ld /tmp | tr -d tmp args: executable: /usr/bin/bash
Ansible lint will pick these things up for you, so why not run it across your code 😉