ansibleansible-filter

Ansible filter for simple text transforms of lists?


I have an Ansible variable specifing a directory, and another which is a list of files. I want to derive a list of paths comprised of each file prefixed by the directory.

vars:
  dir: /tmp
  files:
  - a
  - b
  - c
  paths: .. # some transform expression

The eventual value of paths should be as though it had been explicitly defined as

  paths:
  - /tmp/a
  - /tmp/b
  - /tmp/c

I've tried a solution with regex_replace, but that's a pretty nuclear option for such a simple transform, and I ran into endless quoting issues. I've also tried various combinations with map, join, path_join, and I don't know what-all else. Some would make perfect sense, if they didn't expect their arguments to be a mix of filter input and actual parameters.

The regex_replace example I tried seem to imply that variable definitions could 'forward reference' others in the same vars structure, but a few of my attempts gave me pages of errors suggesting that's not [always?] the case.

This is a heavily over-simplified example, and I'm looking for a more general solution than once just for the data shown.


Solution

  • Q: "I'm looking for a more general solution."

    A: Given the data

      dir: /tmp
      files: [a, b, c]
    
    1. The standard option is joining the products
      paths: "{{ [dir]|product(files)|map('join', '/') }}"
    

    gives

      paths:
        - /tmp/a
        - /tmp/b
        - /tmp/c
    
    1. The cutting-edge option is the filter community.general.path_join. The below expression gives the same result
      paths: "{{ [dir]|product(files)|map('community.general.path_join') }}"
    
    1. But, you can easily create a general solution on your own. Write your own filters. For example,
    def string_prefix(s, prefix):
        return prefix + str(s)
    

    See string_filters.py. Create directory plugins/filter and get the filters

    shell> cd plugins/filter
    shell> wget https://raw.githubusercontent.com/vbotka/ansible-plugins/master/filter_plugins/string_filters/string_filters.py
    

    Configure DEFAULT_FILTER_PLUGIN_PATH

    shell> pwd
    /scratch/tmp7/test-481
    shell> ansible-config dump | grep DEFAULT_FILTER_PLUGIN_PATH
    DEFAULT_FILTER_PLUGIN_PATH(/export/scratch/tmp7/test-481/ansible.cfg) = ['/scratch/tmp7/test-481/plugins/filter']
    
    shell> tree .
    .
    ├── ansible.cfg
    ├── hosts
    ├── pb.yml
    └── plugins
        └── filter
            └── string_filters.py
    

    Then, the below expression gives the same result

      paths: "{{ files|map('string_prefix', dir ~ '/') }}"
    

    Example of a complete playbook for testing

    shell> cat pb.yml 
    - hosts: localhost
    
      vars:
    
        dir: /tmp
        files: [a, b, c]
    
        paths1: "{{ [dir]|product(files)|map('join', '/') }}"
        paths2: "{{ [dir]|product(files)|map('community.general.path_join') }}"
        paths3: "{{ files|map('string_prefix', dir ~ '/') }}"
    
      tasks:
    
        - debug:
            var: paths1
        - debug:
            var: paths2
        - debug:
            var: paths3
    

    See an example of other plugins.