Search code examples
ansiblejinja2

ansible match list element


---
- name: main
  hosts: localhost
  become: true
  vars:
    allowed_options: [AllowAgent,RSAAuthentication,RSATokeN]
    match_config:
          test:
            matchkey: 'User'
            matchvalue: 'user1'
            allowagent: 'domaintoken'
            rsatoken: 'XXXXXZZZ0000000'
          test2:
            matchkey: 'Address'
            matchvalue: '162.243.72.0/24,192.43.120.0/23'
            rsaauthentication: 'enabled'
            invalidkey: invalidvalue
  tasks:
   - name: deploy
     template:
        src: xa.j2
        dest: /tmp/xa.txt

template file

{% if (allowed_options is defined) and allowed_options %}
{% for k,v in match_config.items() %}
Match {{ v.matchkey }} {{ v.matchvalue }}
{% for optname, optval in v.items() if optname not in ['matchkey', 'matchvalue'] %}
{% if optname in allowed_options|lower %}
  {{ optname }} {{ optval }}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}

I get the right output:

Match User user1
  allowagent domaintoken
  rsatoken XXXXXZZZ0000000
Match Address 162.243.72.0/24,192.43.120.0/23
  rsaauthentication enabled

But, I would prefer

Match User user1
  AllowAgent domaintoken
  RSATokeN XXXXXZZZ0000000
Match Address 162.243.72.0/24,192.43.120.0/23
  RSAAuthentication enabled

I just plain and simple can't figure out...

So I just compare case insensitive in jinja2 template and if it match just to use list[element]


Solution

  • Declare the below dictionary

      allowed_dict: "{{ dict(allowed_options|map('lower')|zip(allowed_options)) }}"
    

    gives

      allowed_dict:
        allowagent: AllowAgent
        rsaauthentication: RSAAuthentication
        rsatoken: RSATokeN
    

    and use it in the template

    {% for k,v in match_config.items() %}
    Match {{ v.matchkey }} {{ v.matchvalue }}
    {% for optname, optval in v.items() %}
    {% if optname in allowed_dict %}
      {{ allowed_dict[optname] }} {{ optval }}
    {% endif %}
    {% endfor %}
    {% endfor %}
    

    gives

    Match User user1
      AllowAgent domaintoken
      RSATokeN XXXXXZZZ0000000
    Match Address 162.243.72.0/24,192.43.120.0/23
      RSAAuthentication enabled
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        allowed_options: [AllowAgent, RSAAuthentication, RSATokeN]
        allowed_dict: "{{ dict(allowed_options|map('lower')|zip(allowed_options)) }}"
        match_config:
              test:
                matchkey: 'User'
                matchvalue: 'user1'
                allowagent: 'domaintoken'
                rsatoken: 'XXXXXZZZ0000000'
              test2:
                matchkey: 'Address'
                matchvalue: '162.243.72.0/24,192.43.120.0/23'
                rsaauthentication: 'enabled'
                invalidkey: invalidvalue
    
      tasks:
    
        - debug:
            var: allowed_dict
    
        - debug:
            msg: |
              {% for k,v in match_config.items() %}
              Match {{ v.matchkey }} {{ v.matchvalue }}
              {% for optname, optval in v.items() %}
              {% if optname in allowed_dict %}
                {{ allowed_dict[optname] }} {{ optval }}
              {% endif %}
              {% endfor %}
              {% endfor %}
    

    If the variable allowed_options might be undefined set it to an empty list

      allowed_dict: "{{ dict(allowed_options|d([])|map('lower')|
                             zip(allowed_options|d([]))) }}"
    

    This would result in an empty dictionary

      allowed_dict: {}
    

    Q: Explain the construct zip(allowed_options)

    A: Take a look at the intermediate results

        - debug:
            msg: |
              allowed_options|map('lower'):
              {{ allowed_options|map('lower')|to_yaml }}
              allowed_options|map('lower')|zip(allowed_options):
              {{ allowed_options|map('lower')|zip(allowed_options)|to_yaml }}
              dict(allowed_options|map('lower')|zip(allowed_options)):
              {{ dict(allowed_options|map('lower')|zip(allowed_options))|to_nice_yaml }}
    

    gives

      msg: |-
        allowed_options|map('lower'):
        [allowagent, rsaauthentication, rsatoken]
      
        allowed_options|map('lower')|zip(allowed_options):
        - [allowagent, AllowAgent]
        - [rsaauthentication, RSAAuthentication]
        - [rsatoken, RSATokeN]
      
        dict(allowed_options|map('lower')|zip(allowed_options)):
        allowagent: AllowAgent
        rsaauthentication: RSAAuthentication
        rsatoken: RSATokeN