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
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.
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
“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.
#!/usr/bin/env -S ansible-playbook mjoelnir.yml -K
#!/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
#!/usr/bin/env -S ansible-playbook rauchkofel.yml --- ...
#!/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.