ansibleansible-template

Execute regular expression within Ansible playbook


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!


Solution

  • 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'']'