Background: in Puppet it is possible to execute a command unless it has already been executed:
exec { '/bin/echo root >> /usr/lib/cron/cron.allow': path => '/usr/bin:/usr/sbin:/bin', unless => 'grep root /usr/lib/cron/cron.allow 2>/dev/null', }
Aim: to execute a command unless it has already been run in Ansible
Methods
tasks/main.yml
- name: add vhost sensu
command: rabbitmqctl add_vhost /sensu
Results
TASK [ansible-rabbitmq : add vhost sensu] **************************************
fatal: [111.222.333.444]: FAILED! => {"changed": true, "cmd": ["rabbitmqctl",
"add_vhost", "/sensu"], "delta": "0:00:00.210140", "end":
"2016-07-29 12:55:19.384455", "failed": true, "rc": 2, "start":
"2016-07-29 12:55:19.174315", "stderr": "Error: vhost_already_exists: /sensu",
"stdout": "Creating vhost \"/sensu\" ...", "stdout_lines":
["Creating vhost \"/sensu\" ..."], "warnings": []}
Discussion
Googling unless ansible
showed this document about when
. Based on that documentation, a when
statement was added:
- name: add vhost sensu
command: rabbitmqctl add_vhost /sensu
when: rabbitmqctl list_vhosts | grep sensu
running the code resulted in:
fatal: [192.168.0.9]: FAILED! => {"failed": true, "msg": "The conditional
check 'rabbitmqctl list_vhosts | grep sensu' failed. The error was: template
error while templating string: expected token 'end of statement block', got
'list_vhosts'. String: {% if rabbitmqctl list_vhosts | grep sensu %} True {%
else %} False {% endif %}\n\nThe error appears to have been in '/etc/ansible
/roles/ansible-rabbitmq/tasks/main.yml': line 10, column 3, but may\nbe
elsewhere in the file depending on the exact syntax problem.\n\nThe
offending line appears to be:\n\n\n- name: add vhost sensu\n ^ here\n"}
- First of all, imagine that
when
was successful then the command will not run and then it looks more likeonlyif
in Puppet. - Secondly, if the when would be successful should an escalation mark be used in order to simulate an unless?
- Use of
register
. What if that file is lost or the vhost has been removed by for example a human? Puppet'sunless
always executes the commands so that it is clear whether the command needs to be executed.
I think what you're looking do is this:
Re: #3
register
does not create a file. If you're capturing the output ofrabbitmqctl list_vhosts
viaregister
, the contents will be as valid as the system's current state.The problem is the line
when: rabbitmqctl list_vhosts | grep sensu
. It is not possible to use bash here.You need to put the
rabbitmqctl list_vhosts | grep sensu
in a separate task and register the result to use it in the when clause. You can usenot
filter to getunless
like behavior.Something like this should work:
The
Get rabbitmq vhosts.
in this example will always be executed. Theadd vhost sensu
only if the string sensu is not in the registeredrabbitmq_vhosts
.Consult the documentation on conditionals and jinja filters for more information.
The
when
option is the only thing Ansible has regarding conditions. But you can not directly define a command there.when
expects a Jinja expression and furthermore is evaluated on the Ansible control host. So you first need to run a task to fetch the result and register it.stdout_lines
is an array of all lines the shell task returned. So you can count the number of entries and only run your task when 0 items have been returned