From a43c0fc1faa0b11713d2eb7cd62fde4dc2f4a0e9 Mon Sep 17 00:00:00 2001 From: Jason King Date: Fri, 29 Sep 2023 10:58:59 -0700 Subject: [PATCH] feat: Limit VLANs when targeting CML (required for cat9kv) (#32) * Added vscode dir to gitignore * Improved "make test" * Updated galaxy version to 1.2.9 * Added feature to limit VLANs when targeting CML (required for cat9kv) --- .gitignore | 3 +- Makefile | 2 +- galaxy.yml | 2 +- playbooks/nso_update_data.yml | 4 +- playbooks/show.yml | 4 +- plugins/filter/intf.py | 86 ++++++++++++++++++++++++++++++++++- 6 files changed, 93 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 124a1a4..898bc78 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ ansible_collections/ .cache/ collections/ envvars -*.gz \ No newline at end of file +*.gz +.vscode/ \ No newline at end of file diff --git a/Makefile b/Makefile index 6352afb..ad426fd 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ publish: $(TARBALL_NAME) ## Publish Collection (set env:GALAXY_TOKEN) format: ## Format Python code yapf --style=yapf.ini -i -r *.py $(PYDIRS) -test: $(VENV) $(TARBALL_NAME) ## Run Sanity Tests +test: clean build $(VENV) $(TARBALL_NAME) ## Run Sanity Tests $(RM) -r ./ansible_collections ansible-galaxy collection install --force $(TARBALL_NAME) -p ./ansible_collections cd ./ansible_collections/ciscops/mdd && git init . diff --git a/galaxy.yml b/galaxy.yml index d79abe0..8b4e175 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -8,7 +8,7 @@ namespace: ciscops name: mdd # The version of the collection. Must be compatible with semantic versioning -version: 1.2.8 +version: 1.2.9 # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: README.md diff --git a/playbooks/nso_update_data.yml b/playbooks/nso_update_data.yml index c4011e3..9910515 100644 --- a/playbooks/nso_update_data.yml +++ b/playbooks/nso_update_data.yml @@ -19,8 +19,8 @@ block: - name: Translate/truncate interface names and truncate config set_fact: - mdd_data: "{{ mdd_data | ciscops.mdd.config_xform(cml_intf_xlate | default(None), cml_truncate_list | default(None)) }}" - when: (cml_intf_xlate is defined and cml_intf_xlate) or (cml_truncate_list is defined and cml_truncate_list) + mdd_data: "{{ mdd_data | ciscops.mdd.config_xform(cml_intf_xlate | default(None), cml_truncate_list | default(None), cml_vlan_list | default(None)) }}" + when: (cml_intf_xlate is defined and cml_intf_xlate) or (cml_truncate_list is defined and cml_truncate_list) or (cml_vlan_list is defined and cml_vlan_list) - name: Update MDD Data ansible.builtin.include_role: diff --git a/playbooks/show.yml b/playbooks/show.yml index a65e7dd..6066ea8 100644 --- a/playbooks/show.yml +++ b/playbooks/show.yml @@ -6,8 +6,8 @@ tasks: - name: Translate/truncate interface names and truncate config set_fact: - mdd_data: "{{ mdd_data | ciscops.mdd.config_xform(cml_intf_xlate | default(None), cml_truncate_list | default(None)) }}" - when: (cml_intf_xlate is defined and cml_intf_xlate) or (cml_truncate_list is defined and cml_truncate_list) + mdd_data: "{{ mdd_data | ciscops.mdd.config_xform(cml_intf_xlate | default(None), cml_truncate_list | default(None), cml_vlan_list | default(None)) }}" + when: (cml_intf_xlate is defined and cml_intf_xlate) or (cml_truncate_list is defined and cml_truncate_list) or (cml_vlan_list is defined and cml_vlan_list) - debug: var: mdd_data \ No newline at end of file diff --git a/plugins/filter/intf.py b/plugins/filter/intf.py index 4808287..71dfbfb 100644 --- a/plugins/filter/intf.py +++ b/plugins/filter/intf.py @@ -164,6 +164,89 @@ def intf_truncate(data, intf_dict=None): return data_out +def vlan_truncate(data, vlan_list=None): + if not data: + return {} + + if vlan_list is None: + return data + + data_out = data.copy() + + if "mdd:openconfig" in data: + oc_data = data["mdd:openconfig"] + + # Truncate VLANs from network instances + try: + instances = oc_data["openconfig-network-instance:network-instances"]["openconfig-network-instance:network-instance"] + for (instance_index, instance) in enumerate(instances): + temp_vlan_list = [] + try: + vlans = instance["openconfig-network-instance:vlans"]["openconfig-network-instance:vlan"] + for vlan in vlans: + if vlan["openconfig-network-instance:vlan-id"] in vlan_list: + temp_vlan_list.append(vlan) + (data_out["mdd:openconfig"]["openconfig-network-instance:network-instances"]["openconfig-network-instance:network-instance"] + [instance_index]["openconfig-network-instance:vlans"]["openconfig-network-instance:vlan"]) = temp_vlan_list + except KeyError: + pass + except KeyError: + pass + + # Truncate VLANs from STP + try: + rapid_pvst = oc_data["openconfig-spanning-tree:stp"]["openconfig-spanning-tree:rapid-pvst"] + try: + temp_stp_vlan_list = [] + vlans = rapid_pvst["openconfig-spanning-tree:vlan"] + for vlan in vlans: + if vlan["openconfig-spanning-tree:vlan-id"] in vlan_list: + temp_stp_vlan_list.append(vlan) + (data_out["mdd:openconfig"]["openconfig-spanning-tree:stp"]["openconfig-spanning-tree:rapid-pvst"] + ["openconfig-spanning-tree:vlan"]) = temp_stp_vlan_list + except KeyError: + pass + except KeyError: + pass + + # Truncate VLANs from trunk interfaces + try: + interfaces = oc_data["openconfig-interfaces:interfaces"]["openconfig-interfaces:interface"] + for interface_index, interface in enumerate(interfaces): + # Check port-channel interfaces + try: + temp_allowed_vlan_list = [] + allowed_vlans = (interface["openconfig-if-aggregate:aggregation"]["openconfig-vlan:switched-vlan"] + ["openconfig-vlan:config"]["openconfig-vlan:trunk-vlans"]) + for vlan in allowed_vlans: + if vlan in vlan_list: + temp_allowed_vlan_list.append(vlan) + (data_out["mdd:openconfig"]["openconfig-interfaces:interfaces"]["openconfig-interfaces:interface"][interface_index] + ["openconfig-if-aggregate:aggregation"]["openconfig-vlan:switched-vlan"]["openconfig-vlan:config"] + ["openconfig-vlan:trunk-vlans"]) = temp_allowed_vlan_list + except KeyError: + pass + + # Check physical interfaces + try: + temp_allowed_vlan_list = [] + allowed_vlans = (interface["openconfig-if-ethernet:ethernet"]["openconfig-vlan:switched-vlan"] + ["openconfig-vlan:config"]["openconfig-vlan:trunk-vlans"]) + for vlan in allowed_vlans: + if vlan in vlan_list: + temp_allowed_vlan_list.append(vlan) + (data_out["mdd:openconfig"]["openconfig-interfaces:interfaces"]["openconfig-interfaces:interface"][interface_index] + ["openconfig-if-ethernet:ethernet"]["openconfig-vlan:switched-vlan"]["openconfig-vlan:config"] + ["openconfig-vlan:trunk-vlans"]) = temp_allowed_vlan_list + except KeyError: + pass + + except KeyError: + pass + + return data_out + + def delete_key(data, key_list): if isinstance(data, dict): if key_list[0] in list(data): @@ -190,10 +273,11 @@ def config_truncate(data, truncate_list=None): return data_out -def config_xform(data, intf_dict=None, truncate_list=None): +def config_xform(data, intf_dict=None, truncate_list=None, vlan_list=None): data = intf_truncate(data, intf_dict) data = intf_xlate(data, intf_dict) data = config_truncate(data, truncate_list) + data = vlan_truncate(data, vlan_list) return data