marcb4
marcb4

Reputation: 57

Create new list from two lists and create "helper" key to match 2 keys

Weird title, but the question is pretty complex. (Please don't hesitate to change the title if you know a better one)

I need to create a fresh new list with altered keys from other list, substrings from keys to check key name of other list and match these key substrings with another key from list.

I hope it gets clear when I try to clarify what I need.

First list named ansible_facts["ansible_net_virtual-systems"][0].vsys_zonelist outputs this:

{
    "ansible_facts": {
        "ansible_net_virtual-systems": [
            {
                "vsys_zonelist": [
                    "L3_v0123_Zone1",
                    "L3_v0124_Zone2",
                    "L3_v0125_Zone3",
                    "L3_Trans_v0020_Zone4"  
                ]
            }
        ]
    }
}

Second list ansible_facts.ansible_net_routing_table:

{
    "ansible_facts": {
        "ansible_net_routing_table": [
            {
                "virtual_router": "Internal",
                "destination": "10.12.123.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.123",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.124.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.124",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.125.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.125",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.20.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.20",
                "route_table": "unicast"
            }
        ]
    }
}

Now I have the substring v0123 from first list and interface: ae1.123 from second list. That means that they belong together. I now need the destination from the second list for each matching lists and also alter the name I get from ansible_facts["ansible_net_virtual-systems"][0].vsys_zonelist.

What I need: Create a list that should look like this:

("interface": "ae1.123" is not needed anymore. Just a helper to match everything)

{
    "result_list": [
        {
            "name": "n-x-123-Zone1",
            "destination": "10.12.123.0/24"
        },
        {
            "name": "n-x-124-Zone2",
            "destination": "10.12.124.0/24"
        },
        {
            "name": "n-x-125-Zone3",
            "destination": "10.12.125.0/24"
        },
        {
            "name": "n-x-20-Zone4",
            "destination": "10.12.20.0/24"
        }
    ]
}

I tried many different ways but somehow I cant manage to get it to work as everything I've done, doesn't help me to create my needed list.

Some input for what I've already tried:

- name: DEBUG list with split and loop
  ansible.builtin.debug:
    # creates
    # n-x-01-Name
    # but no list(!), just messages, but could be useful to create a loop
    msg: "n-x-{% if item.split('_')[1].startswith('Client') %}{{ item[3:100] }}{% else %}{{ item.split('_')[1] | regex_replace('v','') }}-{% endif %}{% if item.split('_')[2] is defined and item.split('_')[2].startswith('Trans') %}{{ item[3:50] }}{% elif item.split('_')[1].startswith('Clients')%}{% else %}{{ item[9:100] | default('') }}{% endif %}"
  loop: '{{ ansible_facts["ansible_net_virtual-systems"][0].vsys_zonelist }}'
  delegate_to: 127.0.0.1

- name: create extract_interface
  ansible.builtin.set_fact:
    # creates (also see next task) 
    # {
    #   {
    #     "interface": "ae1.123"
    #   },
    #   {
    #     "interface": "ae1.124"
    #   }
    # }
    extract_interface: "{{ ansible_facts.ansible_net_routing_table | map(attribute='interface') | map('community.general.dict_kv', 'interface') | list }}"
  delegate_to: 127.0.0.1

- name: create map_destination_to_interface
  ansible.builtin.set_fact:
    # {
    #   "ae1.123": "10.12.123.0/24",
    #   "ae1.124": "10.12.124.0/24"
    # }
    map_destination_to_interface: "{{ ansible_facts.ansible_net_routing_table | zip(extract_interface) | map('combine') | items2dict(key_name='interface', value_name='destination') }}"
  delegate_to: 127.0.0.1

Maybe someone can understand what's needed. Thanks to everyone in advance!

Upvotes: 0

Views: 68

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68034

Declare the variables. Zip the lists and create the structure

lists: "{{ ansible_facts.ansible_net_routing_table|
           zip(ansible_facts['ansible_net_virtual-systems'][0].vsys_zonelist) }}"
result_list_str: |
  {% for i in lists %}
  {% set arr=i.1|split('_') %}
  - destination: {{ i.0.destination }}
    name: n-x-{{ arr[-2][1:]|int }}-{{ arr[-1] }}
  {% endfor %}
result_list: "{{ result_list_str|from_yaml }}"

gives

result_list:
  - destination: 10.12.123.0/24
    name: n-x-123-Zone1
  - destination: 10.12.124.0/24
    name: n-x-124-Zone2
  - destination: 10.12.125.0/24
    name: n-x-125-Zone3
  - destination: 10.12.20.0/24
    name: n-x-20-Zone4

Example of a complete playbook for testing

- hosts: localhost

  vars:

    ansible_facts:
      ansible_net_routing_table:
      - age: '3924798'
        destination: 10.12.123.0/24
        flags: '  Oi  '
        interface: ae1.123
        metric: '10'
        nexthop: 0.0.0.0
        route_table: unicast
        virtual_router: Internal
      - age: '3924798'
        destination: 10.12.124.0/24
        flags: '  Oi  '
        interface: ae1.124
        metric: '10'
        nexthop: 0.0.0.0
        route_table: unicast
        virtual_router: Internal
      - age: '3924798'
        destination: 10.12.125.0/24
        flags: '  Oi  '
        interface: ae1.125
        metric: '10'
        nexthop: 0.0.0.0
        route_table: unicast
        virtual_router: Internal
      - age: '3924798'
        destination: 10.12.20.0/24
        flags: '  Oi  '
        interface: ae1.20
        metric: '10'
        nexthop: 0.0.0.0
        route_table: unicast
        virtual_router: Internal
      ansible_net_virtual-systems:
      - vsys_zonelist:
        - L3_v0123_Zone1
        - L3_v0124_Zone2
        - L3_v0125_Zone3
        - L3_Trans_v0020_Zone4

    lists: "{{ ansible_facts.ansible_net_routing_table|
               zip(ansible_facts['ansible_net_virtual-systems'][0].vsys_zonelist) }}"
    result_list_str: |
      {% for i in lists %}
      {% set arr=i.1|split('_') %}
      - destination: {{ i.0.destination }}
        name: n-x-{{ arr[-2][1:]|int }}-{{ arr[-1] }}
      {% endfor %}
    result_list: "{{ result_list_str|from_yaml }}"

  tasks:

    - debug:
        var: result_list

Upvotes: 1

Edo Akse
Edo Akse

Reputation: 4391

You've tagged this question with python, so I'm going to answer in python.

Some string manipulation and a couple of loops can extract what you need.

# not needed, but nice for printing out the result
import json


ansible_facts = {
    "ansible_facts": {
        "ansible_net_virtual-systems": [
            {
                "vsys_zonelist": [
                    "L3_v0123_Zone1",
                    "L3_v0124_Zone2",
                    "L3_v0125_Zone3",
                    "L3_Trans_v0020_Zone4",
                ]
            }
        ],
        "ansible_net_routing_table": [
            {
                "virtual_router": "Internal",
                "destination": "10.12.123.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.123",
                "route_table": "unicast",
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.124.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.124",
                "route_table": "unicast",
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.125.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.125",
                "route_table": "unicast",
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.20.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.20",
                "route_table": "unicast",
            },
        ],
    }
}

result = {"result_list": []}
for vs in ansible_facts["ansible_facts"]["ansible_net_virtual-systems"][0]["vsys_zonelist"]:
    # work from the last element as that's the consistent part
    # turn to int to remove leading zeros
    vs_vers = int(vs.split("_")[-2].replace("v", ""))
    for nrt in ansible_facts["ansible_facts"]["ansible_net_routing_table"]:
        nrt_vers = int(nrt["interface"].split(".")[-1])
        # note that the 3rd octet of the destination IP address also seems to be the version
        # you can use that to compare as well, as such:
        # nrt_vers = int(nrt["destination"].split(".")[2])
        if nrt_vers == vs_vers:
            # work from the last element as that's the consistent part
            vs_zone = vs.split("_")[-1]
            # f-strings to turn it into the correct name
            vs_name = f"n-x-{vs_vers}-{vs_zone}"
            nrt_destination = nrt["destination"]
            result["result_list"].append({"name": vs_name, "destination": nrt_destination})
            # break to stop needless iteration
            break 


print(json.dumps(result, indent=4))

output

{
    "result_list": [
        {
            "name": "n-x-123-Zone1",
            "destination": "10.12.123.0/24"
        },
        {
            "name": "n-x-124-Zone2",
            "destination": "10.12.124.0/24"
        },
        {
            "name": "n-x-125-Zone3",
            "destination": "10.12.125.0/24"
        },
        {
            "name": "n-x-20-Zone4",
            "destination": "10.12.20.0/24"
        }
    ]
}

Upvotes: 1

Related Questions