Ansible playbooks are a mighty tool for automation and scaling of your server infrastructure. Playbooks are executed using ansible-playbook
. Often the execution lines become complex and not easily rememberable by themselves. By adding ansible-playbook
to the shebang (#!
) of the playbook file, you can make them effectively standalone executables with complex program arguments.
Wait … What?!? Let me show you how this works in practice:
#!/usr/bin/env -S ansible-playbook -K
# NOTE: Don't provide the playbook filename in the shebang. It is added automatically.
---
- name: Phoenixify mjoelnir
hosts: mjoelnir.home
user: phoenix
become: yes
become_user: root
roles:
- role: phoenixify
bash_configure: true
gui_config: true
# even more stuff ....
Those are the contents of my mjoelnir.yml
file. Making this file an executable (chmod +x mjoelnir.yml
) allows me now to execute this file, which will just run it as an ansible playbook.
./mjoelnir.yml # more conventient than `ansible-playbook -K mjoelnir.yml`
Important note: In teh shebang the filename is added automatically at the end. So don’t provide the playbook yaml filename there otherwise the playbook will be executed twice.
I find this awesome!
A more complex example
In the above example it was a convenience feature, but for some complex real-world scenarios this is a real life-improvement.
Let’s assume a complex line like the following for an imaginary rauchkofel
server:
ansible-playbook -i inventory --ask-vault-pass -e @vault.yml rauchkofel.yml
This is something that you encounter often on real-world production systems. Indeed, this can become much more complex! You keep some of the server variables in an encrypted vault file and this makes already the line to type in non-trivial.
There is however no need to create a separate bash script or to email each other the commands that needs to be run or remember each time what you have to type, because we can just add this to our shebang:
#!/usr/bin/env -S ansible-playbook -i inventory --ask-vault-pass -e @vault.yml
---
- name: Setting up rauchkofel
hosts: rauchkofel
user: root
roles:
- role: skeleton
- role: grafana
- role: nginx
# ....
Now all what we need to do is make the file executable and then run it.
chmod +x rauchkofel.yml
./rauchkofel.yml
This is awesome!! 🚀
Adding more program parameters
If you need to add more custom program parameters, that also works. e.g.
./rauchkofel.yml --tags=nginx
Will do exactly what you expect, it will result in a run of
ansible-playbook -i inventory --ask-vault-pass -e @vault.yml rauchkofel.yml --tags=nginx
Common pitfalls
“Unrecognized arguments: XYZ.yaml”
The playbook terminates with
usage: ansible-playbook [-h] [--version] [-v] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
[--flush-cache] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-t TAGS]
[--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
[-i INVENTORY] [--list-hosts] [-l SUBSET]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--list-tasks]
[--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]```
ansible-playbook: error: unrecognized arguments: ./mjoelnir.yml
Solution: The playbook filename needs to be the last argument.
WRONG: #!/usr/bin/env -S ansible-playbook mjoelnir.yml -K
RIGHT: #!/usr/bin/env -S ansible-playbook -K mjoelnir.yml
Also: Check if you really need the playbook filename because it’s added automatically (See the next topic).
The playbook is executed twice
Probably you have provided the playbook filename in the shebang. Don’t do that, it is added automatically.
So, e.g. assuming you have the playbook rauchkofel.yml
.
WRONG:
#!/usr/bin/env -S ansible-playbook rauchkofel.yml
---
...
RIGHT:
#!/usr/bin/env -S ansible-playbook
---
...
The reason is that the filename is added automatically, so if you provide it manually, it will be executed twice.