I am trying to declare a host variable in an Ansible YAML defaults file of a role, that should contain the content of multiple files as lists entries.
Consider the files dir/1.txt
with the content one
and dir/2.txt
with the content two
, so the variable should equal to [ "one", "two" ]
.
To achieve that I am trying to combine the fileglob
and file
lookups, but I can't get it working.
My first idea was to just take the output of the fileglob
lookup and take it as input for the file
lookup like this, but that throws an error:
myvar: "{{ lookup('file', lookup('fileglob', 'dir/*.txt')) }}"
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while templating '{{ lookup('file', lookup('fileglob', 'dir/*.txt')) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while running the lookup plugin 'file'. Error was a <class 'ansible.errors.AnsibleError'>, original message: could not locate file in lookup: /path/to/dir/1.txt,/path/to/dir/2.txt. could not locate file in lookup: /path/to/dir/1.txt,/path/to/dir/2.txt"}
The fileglob
lookup does not seem to return an actual list
of files, but a comma delimited string, as the output of this test playbook demonstrates:
- hosts: localhost
vars:
files: "{{ lookup('fileglob', 'dir/*.txt') }}"
tasks:
- ansible.builtin.debug:
var: files
ok: [localhost] => {
"files": "/path/to/dir/1.txt,/path/to/dir/2.txt"
}
The documentation of the file
lookup suggests that the module can take a list of files as input, but as separate terms. So if I only run the lookup on the two example files, it returns a comma delimited string of contents:
- hosts: localhost
vars:
contents: "{{ lookup('file', 'dir/1.txt', 'dir/2.txt') }}"
tasks:
- ansible.builtin.debug:
var: contents
ok: [localhost] => {
"contents": "one,two"
}
Now I don't know how to convert the output of the fileglob
lookup to multiple input terms for the file
lookup. Also I am worried what happens if a file contains a ,
since I can't simply run split(",")
on the output of the file
lookup to receive a list, then.
Is it possible to achieve what I'm trying within the variables definition or do I have to resort to ansible logic and set_facts
with_fileglob
?
What you are asking is basically the difference between lookup
and query
, as explained in the documentation:
The difference between
lookup
andquery
is largely that query will always return a list. The default behavior oflookup
is to return a string of comma separated values.lookup
can be explicitly configured to return a list usingwantlist=True
.
Source: Forcing lookups to return lists: query
and wantlist=True
So, here, you want to use a query
instead of a lookup
:
- debug:
var: query('fileglob', 'dir/*.txt')
Giving:
ok: [localhost] =>
query('fileglob', 'dir/*.txt'):
- /path/to/dir/1.txt
- /path/to/dir/2.txt
As for passing the list of files from the fileglob
lookup to the file
one, you can unpack the list returned by fileglob
with a star *
, like in Python.
So, your task ends up being
- debug:
var: "query('file', *query('fileglob', 'dir/*.txt'))"
Which would yield a list of the content of your files, as expected:
ok: [localhost] =>
query('file', *query('fileglob', 'dir/*.txt')):
- one
- two