Search code examples
ansiblejinja2jmespathjson-query

Filtering addresses matching condition


I want to provide list of allowed VLAN's as a variable to my server.

Ansible playbook should be able to filter server's IP addreses based on this VLAN's.

  • I have a list of all IP addresses available on server (ansible_all_ipv4_addresses from ansible facts)

  • I have a global variable my_subnets:

    my_subnets:
      - vlan: 2
        subnet: "192.168.2.0/24"
        gateway: "192.168.2.10"
      - vlan: 3
        subnet: "192.168.3.0/24"
        dns: "192.168.3.12"
      - vlan: 4
        subnet: "192.168.4.0/24"
      - vlan: 5
        subnet: "192.168.5.0/24"
    
  • And I have per-service variable allowed_vlans:

    allowed_vlans:
      - 2
      - 5
    

I am looking for a way how to template out just "192.168.2.0/24" and "192.168.5.0/24"


I was thinking about:

1. Jinja way

Something like extract from my_subnets items matching allowed_vlans and map them with ansible_all_ipv4_addresses through ipaddr() filter.

2. JSON query way

I've tried:

{{ my_subnets | json_query('[?vlan in allowed_vlans].subnet') }}

but it seems the json_query is not using python syntax for evaluating if something is in array.


Solution

  • The contains() function is how JMESPath checks for membership, but as best I can tell it has no ability to refer upward in the object tree, nor assign expressions to internal variables as does the jq language. But, one can cheat and serialize the expression to JSON and then use JMESPath's literal expression syntax:

    tasks:
    - debug:
        verbosity: 0
        msg: |
          {{ my_subnets | json_query(jq) }}
      vars:
        # this "vars" trick was recommended by the json_query docs, but isn't required
        jq: |
          [? contains(`{{ allowed_subnets | to_json }}`, vlan) ].subnet