-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[minor_change] Addition of a filter plugin called aci_listify to the …
…collection which flattens nested dictionaries
- Loading branch information
Showing
3 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
# Copyright: (c) 2017, Ramses Smeyers <[email protected]> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "certified"} | ||
|
||
DOCUMENTATION = r""" | ||
name: aci_listify | ||
short_description: Flattens the nested dictionaries representing the ACI model data. | ||
description: | ||
- This filter flattens and transforms the input data into a list. | ||
- See the Examples section below. | ||
options: | ||
data: | ||
description: This option represents the ACI model data which is a list of dictionaries or a dictionary with any level of nesting data. | ||
type: raw | ||
required: True | ||
keys: | ||
description: Comma separated keys of type string denoting the ACI objects. | ||
required: True | ||
""" | ||
|
||
EXAMPLES = r""" | ||
- name: Set vars | ||
ansible.builtin.set_fact: | ||
data: | ||
tenant: | ||
- name: ansible_test | ||
description: Created using listify | ||
app: | ||
- name: app_test | ||
epg: | ||
- name: web | ||
bd: web_bd | ||
- name: app | ||
bd: app_bd | ||
bd: | ||
- name: bd_test | ||
subnet: | ||
- name: 10.10.10.1 | ||
mask: 24 | ||
scope: private | ||
vrf: vrf_test | ||
- name: bd_test2 | ||
subnet: | ||
- name: 20.20.20.1 | ||
mask: 24 | ||
scope: public | ||
vrf: vrf_test | ||
vrf: | ||
- name: vrf_test | ||
- name: Create tenants | ||
cisco.aci.aci_tenant: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
description: '{{ item.tenant_description }}' | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant") }}' | ||
- name: Create VRFs | ||
cisco.aci.aci_vrf: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
vrf_name: '{{ item.tenant_vrf_name }}' | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant","vrf") }}' | ||
- name: Create BDs | ||
cisco.aci.aci_bd: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
vrf: '{{ item.tenant_bd_vrf }}' | ||
bd: '{{ item.tenant_bd_name }}' | ||
enable_routing: yes | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant","bd") }}' | ||
- name: Create BD subnets | ||
cisco.aci.aci_bd_subnet: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
bd: '{{ item.tenant_bd_name }}' | ||
gateway: '{{ item.tenant_bd_subnet_name }}' | ||
mask: '{{ item.tenant_bd_subnet_mask }}' | ||
scope: '{{ item.tenant_bd_subnet_scope }}' | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant","bd","subnet") }}' | ||
- name: Create APs | ||
cisco.aci.aci_ap: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
app_profile: '{{ item.tenant_app_name }}' | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant","app") }}' | ||
- name: Create EPGs | ||
cisco.aci.aci_epg: | ||
host: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
tenant: '{{ item.tenant_name }}' | ||
app_profile: '{{ item.tenant_app_name }}' | ||
epg: '{{ item.tenant_app_epg_name }}' | ||
bd: '{{ item.tenant_app_epg_bd }}' | ||
with_items: '{{ data|cisco.aci.aci_listify("tenant","app","epg") }}' | ||
""" | ||
|
||
|
||
def listify(d, *keys): | ||
return listify_worker(d, keys, 0, [], {}, "") | ||
|
||
|
||
def listify_worker(d, keys, depth, result, cache, prefix): | ||
prefix += keys[depth] + "_" | ||
|
||
if keys[depth] in d: | ||
for item in d[keys[depth]]: | ||
cache_work = cache.copy() | ||
if isinstance(item, dict): | ||
for k, v in item.items(): | ||
if not isinstance(v, dict) and not isinstance(v, list): | ||
cache_key = prefix + k | ||
cache_value = v | ||
cache_work[cache_key] = cache_value | ||
|
||
if len(keys) - 1 == depth: | ||
result.append(cache_work) | ||
else: | ||
for k, v in item.items(): | ||
if k == keys[depth + 1]: | ||
if isinstance(v, dict) or isinstance(v, list): | ||
result = listify_worker({k: v}, keys, depth + 1, result, cache_work, prefix) | ||
return result | ||
|
||
|
||
class FilterModule(object): | ||
"""Ansible core jinja2 filters""" | ||
|
||
def filters(self): | ||
return { | ||
"aci_listify": listify, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# No ACI simulator yet, so not enabled | ||
# unsupported |
114 changes: 114 additions & 0 deletions
114
tests/integration/targets/aci_filter_listify/tasks/main.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# Test code for the ACI modules | ||
# Copyright: (c) 2023, Shreyas Srish ([email protected]) | ||
# | ||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
- name: Test that we have an ACI APIC host, ACI username and ACI password | ||
fail: | ||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' | ||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined | ||
|
||
- name: Set vars | ||
ansible.builtin.set_fact: | ||
aci_info: &aci_info | ||
host: "{{ aci_hostname }}" | ||
username: "{{ aci_username }}" | ||
password: "{{ aci_password }}" | ||
validate_certs: '{{ aci_validate_certs | default(false) }}' | ||
use_ssl: '{{ aci_use_ssl | default(true) }}' | ||
use_proxy: '{{ aci_use_proxy | default(true) }}' | ||
output_level: '{{ aci_output_level | default("info") }}' | ||
aci_model_data: | ||
tenant: | ||
- name: ansible_test | ||
description: Created using listify | ||
app: | ||
- name: app_test | ||
epg: | ||
- name: web | ||
bd: web_bd | ||
- name: app | ||
bd: app_bd | ||
bd: | ||
- name: bd_test | ||
subnet: | ||
- name: 10.10.10.1 | ||
mask: 24 | ||
scope: private | ||
vrf: vrf_test | ||
- name: bd_test2 | ||
subnet: | ||
- name: 20.20.20.1 | ||
mask: 24 | ||
scope: public | ||
vrf: vrf_test | ||
vrf: | ||
- name: vrf_test | ||
|
||
- name: Create tenants | ||
cisco.aci.aci_tenant: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
description: '{{ item.tenant_description }}' | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant") }}' | ||
register: tenant_listify | ||
|
||
- name: Create VRFs | ||
cisco.aci.aci_vrf: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
vrf_name: '{{ item.tenant_vrf_name }}' | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant","vrf") }}' | ||
register: vrf_listify | ||
|
||
- name: Create BDs | ||
cisco.aci.aci_bd: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
vrf: '{{ item.tenant_bd_vrf }}' | ||
bd: '{{ item.tenant_bd_name }}' | ||
enable_routing: yes | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant","bd") }}' | ||
register: bd_listify | ||
|
||
- name: Create BD subnets | ||
cisco.aci.aci_bd_subnet: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
bd: '{{ item.tenant_bd_name }}' | ||
gateway: '{{ item.tenant_bd_subnet_name }}' | ||
mask: '{{ item.tenant_bd_subnet_mask }}' | ||
scope: '{{ item.tenant_bd_subnet_scope }}' | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant","bd","subnet") }}' | ||
register: bd_subnets_listify | ||
|
||
- name: Create APs | ||
cisco.aci.aci_ap: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
app_profile: '{{ item.tenant_app_name }}' | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant","app") }}' | ||
register: ap_listify | ||
|
||
- name: Create EPGs | ||
cisco.aci.aci_epg: | ||
<<: *aci_info | ||
tenant: '{{ item.tenant_name }}' | ||
app_profile: '{{ item.tenant_app_name }}' | ||
epg: '{{ item.tenant_app_epg_name }}' | ||
bd: '{{ item.tenant_app_epg_bd }}' | ||
with_items: '{{ aci_model_data|cisco.aci.aci_listify("tenant","app","epg") }}' | ||
register: epg_listify | ||
|
||
- name: Validate listify | ||
assert: | ||
that: | ||
- tenant_listify.results.0.current.0.fvTenant.attributes.name == "ansible_test" | ||
- vrf_listify.results.0.current.0.fvCtx.attributes.name == "vrf_test" | ||
- bd_listify.results.0.current.0.fvBD.attributes.name == "bd_test" | ||
- bd_listify.results.1.current.0.fvBD.attributes.name == "bd_test2" | ||
- bd_subnets_listify.results.0.current.0.fvSubnet.attributes.ip == "10.10.10.1/24" | ||
- bd_subnets_listify.results.1.current.0.fvSubnet.attributes.ip == "20.20.20.1/24" | ||
- ap_listify.results.0.current.0.fvAp.attributes.name == "app_test" | ||
- epg_listify.results.0.current.0.fvAEPg.attributes.name == "web" | ||
- epg_listify.results.1.current.0.fvAEPg.attributes.name == "app" |