I'm trying to build security groups rule and routes from a list of CIDRs, and can't quite get the mapping syntax right.
I have an list of cidrs:
cidrs:
  - 10.12.0.0/16
  - 10.99.0.0/16
  - 192.168.128.0/24
And I'd like to transform it into a list of rules for a security group, such as:
rules:
  - proto: all
    cidr_ip: 10.12.0.0/16
  - proto: all
    cidr_ip: 10.99.0.0/16
  - proto: all
    cidr_ip: 192.168.128.0/24
What's the syntax for performing this sort of transformation using Jinja2/Ansible filters?
1. Filter combine in loop
For example, the playbook
shell> cat playbook.yml
- hosts: localhost
  vars:
    cidrs:
      - 10.12.0.0/16
      - 10.99.0.0/16
      - 192.168.128.0/24
    protos:
      proto: all
  tasks:
    - set_fact:
        rules: "{{ rules|default([]) +
                   [{'cidr_ip': item}|combine(protos)] }}"
      loop: "{{ cidrs }}"
    - debug:
        var: rules
gives (abridged)
shell> ansible-playbook playbook.yml
  rules:
  - cidr_ip: 10.12.0.0/16
    proto: all
  - cidr_ip: 10.99.0.0/16
    proto: all
  - cidr_ip: 192.168.128.0/24
    proto: all
2. Modified list and filter combine in map
If the input is a list of dictionaries, aka hashes, then simple map would do the job. For example, the playbook below gives the same result
shell> cat playbook.yml
- hosts: localhost
  gather_facts: false
  vars:
    cidrs:
      - cidr_ip: 10.12.0.0/16
      - cidr_ip: 10.99.0.0/16
      - cidr_ip: 192.168.128.0/24
    protos:
      proto: all
  tasks:
    - set_fact:
        rules: "{{ cidrs|map('combine', protos)|list }}"
    - debug:
        var: rules
3. Custom plugin and filter combine in map
The filter product seems a good candidate to start with the transformation of a simple list into a list of hashes. But, there is no filter in Ansible to transform a list of two items into a dictionary, AFAIK. Let's write such a filter. For example
shell> cat filter_plugins/dict.py
def item2dict(t):
    h = {t[0]:t[1]}
    return h
class FilterModule(object):
    ''' Ansible dict filters '''
    def filters(self):
        return {
            'item2dict': item2dict
        }
Then the playbook below gives the same result
shell> cat playbook.yml
- hosts: localhost
  vars:
    cidrs:
      - 10.12.0.0/16
      - 10.99.0.0/16
      - 192.168.128.0/24
    protos:
      proto: all
  tasks:
    - set_fact:
        rules: "{{ ['cidr_ip']|product(cidrs)|map('item2dict')|
                   map('combine', protos)|list }}"
    - debug:
        var: rules
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With