Using the Ansible Stat Module on a Loop
Table of Contents
Using the Ansible stat module on a loop
Hi again, it’s been a while since I wrote something on this blog. This time I was working on a Ansible playbook and I get this:
Problem
I want to verify if a file exists. Depending on the registered output I want to perform some other actions.
On my specific use case, I want to use in in conjunct with the file
module to define the state on my next task.
Solution
Here is the solution that worked for me, using loops
, loop_control
,and jinja2
filters.
- name: Stat over the files
stat:
path: "{{ my_loop }}"
loop:
- /etc/cron.allow
- /etc/at.allow
loop_control:
loop_var: my_loop
register: my_stat_var
- name: Create a file if not exists
file:
path: "{{ item.my_loop }}"
owner: root
group: root
mode: og-rwx
state: "{{ 'file' if item.stat.exists else 'touch' }}"
loop: "{{ my_stat_var.results }}"
Basically, I’m using the new loop
syntax to iterate over all the files that I want to check.
In order to avoid some warnings about the loop using item
I implement the loop_control
and loop_var
syntax to control the loop behavior and on this specific case,
instead of using the word item
I will substitute it with the one that I define as my loop_var
in this case is called my_loop
(Remember this, I will use it on the next task).
I’m registering the result of the stat task on a variable, for this case is my_stat_var
Here is an example of the output, when the 2 files do not exists:
ok: [instance-amazon2] => {
"my_loop": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "my_loop",
"at_cron_restricted_touch": "/etc/cron.allow",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": false,
"get_mime": true,
"path": "/etc/cron.allow"
}
},
"stat": {
"exists": false
}
},
{
"ansible_loop_var": "my_loop",
"at_cron_restricted_touch": "/etc/at.allow",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": false,
"get_mime": true,
"path": "/etc/at.allow"
}
},
"stat": {
"exists": false
}
}
]
}
}
On the next task I access the results of the registered variable my_stat_var
using, according to the previous output,
I need to use the results
variable to access it and gives me 2 arrays (each one for each file)
Also, I extract the path
from the same variable my_stat_var.results
but as it is part of a loop,
I will access it using item.my_loop
as on the the second task loop I’m not using a loop_control
,
also I can access it using item.item
but I prefer the first syntax.
In case you implement a loop_control
on you can access it as my_second_loop.my_loop
Also, I extract if the file exists with the variable item.stat.exists
but I’m putting that on a jinja2
filter, that way it will evaluate and set the correct option on the state
# When the file exists
state: file
# When the file does not exists
state: touch
This behavior also brings idempotency to your task, because:
- If the files does not exists on the first iteration it will be created and,
- The next time you run the tasks as the files already exists it will works as a
stat
and will return the current state ofpath
.
That is all for now. See you soon!