I want to be able to guarantee that after a long running shell command is executed successfully on a given host, it is not executed in subsequent playbook runs on that host.
I was happy to learn of the creates
option to the Ansible shell task (see http://docs.ansible.com/ansible/shell_module.html); using this I can create a file after a shell command succeeds and not have that command execute in future runs:
- name: Install Jupiter theme
shell: wp theme install ~/downloads/jupiter-theme.zip --activate
&& touch ~/ansible-flags/install-jupiter-theme
args:
creates: ~/ansible-flags/install-jupiter-theme
As you can see, I have a directory ansible-flags
for these control files in the home directory of my active user (deploy
).
However, this is quite a kludge. Is there a better way to do this?
Also, the situation gets a lot more complicated when I need to run a step as a different user; in that case, I don't have access to the deploy
home directory and its subdirectories. I could grant access, of course, but that's adding even more complexity. How would you recommend I deal with this?
The easiest way to run only one task in Ansible Playbook is using the tags statement parameter of the “ansible-playbook” command. The default behavior is to execute all the tags in your Playbook with --tags all .
Using the --limit parameter of the ansible-playbook command is the easiest option to limit the execution of the code to only one host. The advantage is that you don't need to edit the Ansible Playbook code before executing to only one host.
Your playbook should be idempotent!
So either task should be safe to be executed multiple times (e.g. echo ok
) or your should check whether you should execute it at all.
Your task may look like this:
- name: Install Jupiter theme
shell: wp theme is-installed jupiter || wp theme install ~/downloads/jupiter-theme.zip --activate
It will check if the jupiter theme is installed and will run wp theme install
only if theme is not installed.
But this will mark the result of task as changed
in any case.
To make it nice, you can do this:
- name: Install Jupiter theme
shell: wp theme is-installed jupiter && echo ThemeAlreadyInstalled || wp theme install ~/downloads/jupiter-theme.zip --activate
register: cmd_result
changed_when: cmd_result.stdout != "ThemeAlreadyInstalled"
First, it will check if the jupiter theme is already installed.
If this is the case, it will output ThemeAlreadyInstalled
and exit.
Otherwise it will call wp theme install
.
The task's result is registered into cmd_result
.
We user changed_when
parameter to state the fact that if ThemeAlreadyInstalled
ansible shouldn't consider the task as changed, so it remains green in your playbook output.
If you do some preparation tasks before wp theme install
(e.g. download theme), you may want to run the test as separate task to register the result and use when
clauses in subsequent tasks:
- name: Check Jupiter theme is installed
shell: wp theme is-installed jupiter && echo Present || echo Absent
register: wp_theme
changed_when: false
- name: Download theme
get_url: url=...
when: wp_theme.stdout == "Absent"
- name: Install Jupiter theme
shell: wp theme install ~/downloads/jupiter-theme.zip --activate
when: wp_theme.stdout == "Absent"
Ansible itself is stateless, so whatever technique you use needs to be implement by yourself. There is no easier way like telling Ansible to only ever run a task once.
I think what you have already is pretty straight forward. Maybe use another path to check. I'm pretty sure the wp theme install
will actually extract that zip to some location, which you then can use together with the creates
option.
There are alternatives but nothing that makes it easier:
Create a script in any language you like, that checks for the theme and if it is not installed, install it. Instead of the shell task then you would execute the script with the script module.
Install a local fact in /etc/ansible/facts.d
which checks if the theme in already installed. Then you could simply apply a condition based on that fact to the shell
task.
Set up fact caching, then register the result of your shell task and store it as a fact. With fact caching enabled you can access the stored result on later playbook runs.
It only gets more complicated. The creates
option is perfect for this scenario and if you use the location where the wp
command extracted the zip to, it also is pretty clean.
Of course you need to grant access to that file, if you have a need to access it from another user account. Storing stuff in a users home directory with the permissions set to only be readable by the owner indeed is no ideal solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With