I am writing an Ansible play that iterates over a list of dictionaries to ensure that all files extensions are of either .txt
or .csv
format.
My current taks is:
- name: validate file extension
assert:
that:
- item | regex_search('.*(csv|txt)$') is match
fail_msg: "file with invalid extension in my_dicts"
loop: "{{ my_dicts | map(attribute='file_name') | flatten }}"
loop_control:
label: "{{ item }}"
A sample input that would be valid and pass is:
my_dicts:
- file_name:
- foo.txt
- bar.csv
- file_name:
- test.txt
- helloWorld.csv
My issue is that other file extensions are also passing my regex when I need it to throw an error.
An example would be the following:
my_dicts:
- file_name:
- foo.bat
- bar.exe
Which returns:
{
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": "foo.bat",
"msg": "All assertions passed."
},
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": "bar.exe",
"msg": "All assertions passed."
}
]
}
Any insight as to why my regex isn't failing would be greatly appreciated!
You are mixing a test and a filter, the two accepting a regular expression, indeed.
So, since you are using the assert
module, what you want is indeed a test, match
and you will need to pass you regular expression to the test itself:
- name: validate file extension
assert:
that:
- item is match('.*(csv|txt)$')
fail_msg: "file with invalid extension in my_dicts"
loop: "{{ my_dicts | map(attribute='file_name') | flatten }}"
loop_control:
label: "{{ item }}"
This said, you could also do the same without the annoying verbosity of the loop, thanks to the reject
filter that can apply a test to all the elements of a list:
- name: validate file extension
assert:
that:
- _erroneous | length == 0
fail_msg: "Some items are erroneous: {{ _erroneous }}"
vars:
_erroneous: >-
{{
my_dicts
| map(attribute='file_name')
| flatten
| reject('match', '.*(csv|txt)$')
}}
Which would give an error like:
fatal: [localhost]: FAILED! => changed=false
assertion: _erroneous | length == 0
evaluated_to: false
msg: 'Some items are erroneous: [''foo.exe'', ''bar.bat'']'
So, given:
- name: validate file extension
assert:
that: item is match('.*(csv|txt)$')
fail_msg: "file with invalid extension in my_dicts"
loop: "{{ my_dicts | map(attribute='file_name') | flatten }}"
loop_control:
label: "{{ item }}"
vars:
my_dicts:
- file_name:
- foo.csv
- bar.txt
- baz.exe
This yields:
ok: [localhost] => (item=foo.csv) => changed=false
ansible_loop_var: item
item: foo.csv
msg: All assertions passed
ok: [localhost] => (item=bar.txt) => changed=false
ansible_loop_var: item
item: bar.txt
msg: All assertions passed
failed: [localhost] (item=baz.exe) => changed=false
ansible_loop_var: item
assertion: item is match('.*(csv|txt)$')
evaluated_to: false
item: baz.exe
msg: Assertion failed
And with:
- name: validate file extension
assert:
that:
- _erroneous | length == 0
fail_msg: "Some items are erroneous: {{ _erroneous }}"
vars:
_erroneous: >-
{{
my_dicts
| map(attribute='file_name')
| flatten
| reject('match', '.*(csv|txt)$')
}}
my_dicts:
- file_name:
- foo.csv
- bar.txt
- file_name:
- baz.exe
- qux.bat
It would yield:
fatal: [localhost]: FAILED! => changed=false
assertion: _erroneous | length == 0
evaluated_to: false
msg: 'Some items are erroneous: [''baz.exe'', ''qux.bat'']'