From a86f75644d7c974057792ffc55626489545ae456 Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Mon, 25 Nov 2024 15:10:38 -0800 Subject: [PATCH 001/183] MSD sub-main changes --- roles/validate/tasks/sub_main_common.yml | 148 +++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 roles/validate/tasks/sub_main_common.yml diff --git a/roles/validate/tasks/sub_main_common.yml b/roles/validate/tasks/sub_main_common.yml new file mode 100644 index 000000000..876a3fab7 --- /dev/null +++ b/roles/validate/tasks/sub_main_common.yml @@ -0,0 +1,148 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.validate] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" + - "----------------------------------------------------------------" + +- ansible.builtin.debug: msg="Role Path - {{ role_path }}" + +- ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" + +- name: Validate NDFC Service Model Data + ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" + +- ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" + when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" + +- ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" + when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" + +- name: Check for Schema Path Being Defined + ansible.builtin.set_fact: + schema_path: '' + when: schema_path is not defined + delegate_to: localhost + +- name: Check for Enhanced Roles Path Being Defined + ansible.builtin.set_fact: + enhanced_rules_path: '' + when: enhanced_rules_path is not defined + delegate_to: localhost + +- name: Perform Required Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ rules_path }}" + register: model_data + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + rules_path: "{{ role_path }}/files/rules/required_rules/msd" + delegate_to: localhost + +- name: Perform Enhanced Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ enhanced_rules_path }}" + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + when: enhanced_rules_path is defined and enhanced_rules_path + delegate_to: localhost + +# - name: Stat Factory Defaults +# ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" +# register: factory_defaults_file +# delegate_to: localhost + +# - name: Include Factory Defaults if Available +# ansible.builtin.include_vars: +# file: "{{ role_path }}/files/defaults.yml" +# when: factory_defaults_file.stat.exists +# delegate_to: localhost + +# - name: Merge factory and custom defaults +# cisco.nac_dc_vxlan.common.merge_defaults: +# factory_defaults: "{{ factory_defaults }}" +# model_data: "{{ model_data['data'] }}" +# register: defaults +# delegate_to: localhost + +# - name: Register Variable With Only Defaults from Previous Task +# ansible.builtin.set_fact: +# defaults: "{{ defaults['defaults'] }}" +# delegate_to: localhost + +- name: Prepare Service Model + cisco.nac_dc_vxlan.common.prepare_service_model: + inventory_hostname: "{{ inventory_hostname }}" + hostvars: "{{ hostvars }}" + model_data: "{{ model_data['data'] }}" + register: smd + delegate_to: localhost + +- name: Store Golden Service Model Data + ansible.builtin.set_fact: + MD: "{{ smd['model_golden'] }}" + delegate_to: localhost + +- name: Store Extended Service Model Data + ansible.builtin.set_fact: + MD_Extended: "{{ smd['model_extended'] }}" + delegate_to: localhost + +- name: Check Roles + cisco.nac_dc_vxlan.common.check_roles: + role_list: "{{ role_names }}" + register: check_roles + delegate_to: localhost + +- name: Read Run Map From Previous Run + cisco.nac_dc_vxlan.common.read_run_map: + model_data: "{{ MD_Extended }}" + register: run_map_read_result + delegate_to: localhost + +- name: Debug Run Map Read Result + ansible.builtin.debug: + msg: "{{ run_map_read_result }}" + delegate_to: localhost + +- name: Initialize Run Map + cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" + stage: starting_execution + register: run_map + delegate_to: localhost + +- name: Manage Previous Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_previous.yml + when: check_roles['save_previous'] + +- name: Manage Current Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_current.yml + when: check_roles['save_previous'] \ No newline at end of file From 77532eec2281693bfbe123c57b9019fbb108375d Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Mon, 25 Nov 2024 15:11:05 -0800 Subject: [PATCH 002/183] MSD sub-main changes --- roles/validate/tasks/sub_main.yml | 104 +++++++++++++++--------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index d19ebe204..62191b4dd 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -21,58 +21,58 @@ --- -- name: Role Entry Point - [cisco.nac_dc_vxlan.validate] - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" - - "----------------------------------------------------------------" - -- ansible.builtin.debug: msg="Role Path - {{ role_path }}" - -- ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" - -- name: Validate NDFC Service Model Data - ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" - -- ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" - when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" - -- ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" - when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" - -- name: Check for Schema Path Being Defined - ansible.builtin.set_fact: - schema_path: '' - when: schema_path is not defined - delegate_to: localhost - -- name: Check for Enhanced Roles Path Being Defined - ansible.builtin.set_fact: - enhanced_rules_path: '' - when: enhanced_rules_path is not defined - delegate_to: localhost - -- name: Perform Required Syntax and Semantic Model Validation - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" - mdata: "{{ data_path }}" - rules: "{{ rules_path }}" - register: model_data - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/required_rules/" - delegate_to: localhost - -- name: Perform Enhanced Syntax and Semantic Model Validation - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" - mdata: "{{ data_path }}" - rules: "{{ enhanced_rules_path }}" - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - when: enhanced_rules_path is defined and enhanced_rules_path - delegate_to: localhost +# - name: Role Entry Point - [cisco.nac_dc_vxlan.validate] +# ansible.builtin.debug: +# msg: +# - "----------------------------------------------------------------" +# - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" +# - "----------------------------------------------------------------" + +# - ansible.builtin.debug: msg="Role Path - {{ role_path }}" + +# - ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" + +# - name: Validate NDFC Service Model Data +# ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" + +# - ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" +# when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" + +# - ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" +# when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" + +# - name: Check for Schema Path Being Defined +# ansible.builtin.set_fact: +# schema_path: '' +# when: schema_path is not defined +# delegate_to: localhost + +# - name: Check for Enhanced Roles Path Being Defined +# ansible.builtin.set_fact: +# enhanced_rules_path: '' +# when: enhanced_rules_path is not defined +# delegate_to: localhost + +# - name: Perform Required Syntax and Semantic Model Validation +# cisco.nac_dc_vxlan.common.nac_dc_validate: +# schema: "{{ schema_path }}" +# mdata: "{{ data_path }}" +# rules: "{{ rules_path }}" +# register: model_data +# vars: +# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" +# rules_path: "{{ role_path }}/files/rules/required_rules/" +# delegate_to: localhost + +# - name: Perform Enhanced Syntax and Semantic Model Validation +# cisco.nac_dc_vxlan.common.nac_dc_validate: +# schema: "{{ schema_path }}" +# mdata: "{{ data_path }}" +# rules: "{{ enhanced_rules_path }}" +# vars: +# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" +# when: enhanced_rules_path is defined and enhanced_rules_path +# delegate_to: localhost - name: Stat Factory Defaults ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" From d37cdc46e60052fc41671bc34a06b0f95311b6a3 Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Tue, 26 Nov 2024 15:31:30 -0800 Subject: [PATCH 003/183] Added sub-main-common and service model validation --- plugins/action/common/nac_dc_import.py | 70 +++++++++++++++ .../action/common/prepare_service_model.py | 3 + plugins/action/common/read_run_map.py | 2 +- plugins/action/common/run_map.py | 2 +- roles/validate/tasks/main.yml | 10 +++ roles/validate/tasks/sub_main.yml | 85 +++---------------- roles/validate/tasks/sub_main_common.yml | 65 +++++++------- roles/validate/tasks/sub_main_msd.yml | 85 +++++++++++++++++++ 8 files changed, 212 insertions(+), 110 deletions(-) create mode 100644 plugins/action/common/nac_dc_import.py create mode 100644 roles/validate/tasks/sub_main_msd.yml diff --git a/plugins/action/common/nac_dc_import.py b/plugins/action/common/nac_dc_import.py new file mode 100644 index 000000000..94eae990e --- /dev/null +++ b/plugins/action/common/nac_dc_import.py @@ -0,0 +1,70 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase +from ansible.errors import AnsibleError + +try: + from iac_validate.yaml import load_yaml_files + from iac_validate.cli.options import DEFAULT_SCHEMA +except ImportError as imp_exc: + IAC_VALIDATE_IMPORT_ERROR = imp_exc +else: + IAC_VALIDATE_IMPORT_ERROR = None + +import os + +display = Display() + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + results['failed'] = False + results['msg'] = None + results['data'] = {} + + if IAC_VALIDATE_IMPORT_ERROR: + raise AnsibleError('iac-validate not found and must be installed. Please pip install iac-validate.') from IAC_VALIDATE_IMPORT_ERROR + + mdata = self._task.args.get('mdata') + + # Verify That Data Sources Exists + if mdata and not os.path.exists(mdata): + results['failed'] = True + results['msg'] = "The data directory ({0}) for this fabric does not appear to exist!".format(mdata) + return results + if len(os.listdir(mdata)) == 0: + results['failed'] = True + results['msg'] = "The data directory ({0}) for this fabric is empty!".format(mdata) + return results + + # Return Schema Validated Model Data + results['data'] = load_yaml_files([mdata]) + + return results diff --git a/plugins/action/common/prepare_service_model.py b/plugins/action/common/prepare_service_model.py index 68d806fc0..d546ca5c7 100644 --- a/plugins/action/common/prepare_service_model.py +++ b/plugins/action/common/prepare_service_model.py @@ -54,9 +54,12 @@ def run(self, tmp=None, task_vars=None): sm_data = self._task.args['model_data'] # results['model_extended'] contains the data that can be extended by the plugins results['model_extended'] = copy.deepcopy(sm_data) + fabric_type = sm_data.get('vxlan').get('fabric_type', None) full_plugin_path = "ansible_collections.cisco.nac_dc_vxlan.plugins.action.common.prepare_plugins" glob_plugin_path = os.path.dirname(__file__) + "/prepare_plugins" + if fabric_type == 'MSD': + glob_plugin_path = os.path.dirname(__file__) + "/prepare_plugins/msd" plugin_prefix = "prep*.py" prepare_libs = set(x.stem for x in pathlib.Path.glob(pathlib.Path(glob_plugin_path), plugin_prefix)) diff --git a/plugins/action/common/read_run_map.py b/plugins/action/common/read_run_map.py index 9c6eac28d..b7c244483 100644 --- a/plugins/action/common/read_run_map.py +++ b/plugins/action/common/read_run_map.py @@ -40,7 +40,7 @@ def run(self, tmp=None, task_vars=None): results['diff_run'] = True model_data = task_vars['model_data']['data'] - fabric_name = model_data["vxlan"]["global"]["name"] + fabric_name = model_data["vxlan"]["name"] if 'dtc' in task_vars['role_path']: common_role_path = os.path.dirname(task_vars['role_path']) diff --git a/plugins/action/common/run_map.py b/plugins/action/common/run_map.py index 2784a0b93..0d4a7f7ee 100644 --- a/plugins/action/common/run_map.py +++ b/plugins/action/common/run_map.py @@ -43,7 +43,7 @@ def run(self, tmp=None, task_vars=None): model_data = task_vars['model_data']['data'] stage = self._task.args['stage'] - fabric_name = model_data["vxlan"]["global"]["name"] + fabric_name = model_data["vxlan"]["name"] if 'dtc' in task_vars['role_path']: common_role_path = os.path.dirname(task_vars['role_path']) diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index 9d6e722c5..bf91a43f2 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -23,8 +23,18 @@ - debug: msg="{{ nac_tags.all }}" - name: Import Role Tasks + ansible.builtin.import_tasks: sub_main_common.yml + tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml + +- name: Import Role Tasks for MSD Fabric + ansible.builtin.import_tasks: sub_main_msd.yml + tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric_type == 'MSD' + +- name: Import Role Tasks for VxLAN Fabric ansible.builtin.import_tasks: sub_main.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' # Problems with lower versions of python and ansible # Python 3.9.16 and Ansible 7.3.0 (Ansible-Core 2.14.4) # Could ignore errors and try again with tags specified as below as a work around ... diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index 62191b4dd..ade2b5587 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -21,87 +21,22 @@ --- -# - name: Role Entry Point - [cisco.nac_dc_vxlan.validate] -# ansible.builtin.debug: -# msg: -# - "----------------------------------------------------------------" -# - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" -# - "----------------------------------------------------------------" - -# - ansible.builtin.debug: msg="Role Path - {{ role_path }}" - -# - ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" - -# - name: Validate NDFC Service Model Data -# ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" - -# - ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" -# when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" - -# - ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" -# when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" - -# - name: Check for Schema Path Being Defined -# ansible.builtin.set_fact: -# schema_path: '' -# when: schema_path is not defined -# delegate_to: localhost - -# - name: Check for Enhanced Roles Path Being Defined -# ansible.builtin.set_fact: -# enhanced_rules_path: '' -# when: enhanced_rules_path is not defined -# delegate_to: localhost - -# - name: Perform Required Syntax and Semantic Model Validation -# cisco.nac_dc_vxlan.common.nac_dc_validate: -# schema: "{{ schema_path }}" -# mdata: "{{ data_path }}" -# rules: "{{ rules_path }}" -# register: model_data -# vars: -# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" -# rules_path: "{{ role_path }}/files/rules/required_rules/" -# delegate_to: localhost - -# - name: Perform Enhanced Syntax and Semantic Model Validation -# cisco.nac_dc_vxlan.common.nac_dc_validate: -# schema: "{{ schema_path }}" -# mdata: "{{ data_path }}" -# rules: "{{ enhanced_rules_path }}" -# vars: -# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" -# when: enhanced_rules_path is defined and enhanced_rules_path -# delegate_to: localhost - -- name: Stat Factory Defaults - ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" - register: factory_defaults_file - delegate_to: localhost - -- name: Include Factory Defaults if Available - ansible.builtin.include_vars: - file: "{{ role_path }}/files/defaults.yml" - when: factory_defaults_file.stat.exists - delegate_to: localhost - -- name: Merge factory and custom defaults - cisco.nac_dc_vxlan.common.merge_defaults: - factory_defaults: "{{ factory_defaults }}" - model_data: "{{ model_data['data'] }}" - register: defaults - delegate_to: localhost - -- name: Register Variable With Only Defaults from Previous Task - ansible.builtin.set_fact: - defaults: "{{ defaults['defaults'] }}" +- name: Perform Required Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ rules_path }}" + register: model_data_vxlan + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + rules_path: "{{ role_path }}/files/rules/required_rules/" delegate_to: localhost - name: Prepare Service Model cisco.nac_dc_vxlan.common.prepare_service_model: inventory_hostname: "{{ inventory_hostname }}" hostvars: "{{ hostvars }}" - model_data: "{{ model_data['data'] }}" + model_data: "{{ model_data_vxlan['data'] }}" default_values: "{{ defaults }}" templates_path: "{{ role_path }}/../dtc/common/templates/" register: smd diff --git a/roles/validate/tasks/sub_main_common.yml b/roles/validate/tasks/sub_main_common.yml index 876a3fab7..8907154f8 100644 --- a/roles/validate/tasks/sub_main_common.yml +++ b/roles/validate/tasks/sub_main_common.yml @@ -53,55 +53,54 @@ when: enhanced_rules_path is not defined delegate_to: localhost -- name: Perform Required Syntax and Semantic Model Validation - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" +- name: Import Semantic Model + cisco.nac_dc_vxlan.common.nac_dc_import: mdata: "{{ data_path }}" - rules: "{{ rules_path }}" register: model_data vars: data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/required_rules/msd" delegate_to: localhost -- name: Perform Enhanced Syntax and Semantic Model Validation - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" - mdata: "{{ data_path }}" - rules: "{{ enhanced_rules_path }}" - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - when: enhanced_rules_path is defined and enhanced_rules_path - delegate_to: localhost - -# - name: Stat Factory Defaults -# ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" -# register: factory_defaults_file +# - name: Perform Enhanced Syntax and Semantic Model Validation +# cisco.nac_dc_vxlan.common.nac_dc_validate: +# schema: "{{ schema_path }}" +# mdata: "{{ data_path }}" +# rules: "{{ enhanced_rules_path }}" +# vars: +# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" +# when: enhanced_rules_path is defined and enhanced_rules_path # delegate_to: localhost -# - name: Include Factory Defaults if Available -# ansible.builtin.include_vars: -# file: "{{ role_path }}/files/defaults.yml" -# when: factory_defaults_file.stat.exists -# delegate_to: localhost +- name: Stat Factory Defaults + ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" + register: factory_defaults_file + delegate_to: localhost -# - name: Merge factory and custom defaults -# cisco.nac_dc_vxlan.common.merge_defaults: -# factory_defaults: "{{ factory_defaults }}" -# model_data: "{{ model_data['data'] }}" -# register: defaults -# delegate_to: localhost +- name: Include Factory Defaults if Available + ansible.builtin.include_vars: + file: "{{ role_path }}/files/defaults.yml" + when: factory_defaults_file.stat.exists + delegate_to: localhost -# - name: Register Variable With Only Defaults from Previous Task -# ansible.builtin.set_fact: -# defaults: "{{ defaults['defaults'] }}" -# delegate_to: localhost +- name: Merge factory and custom defaults + cisco.nac_dc_vxlan.common.merge_defaults: + factory_defaults: "{{ factory_defaults }}" + model_data: "{{ model_data['data'] }}" + register: defaults + delegate_to: localhost + +- name: Register Variable With Only Defaults from Previous Task + ansible.builtin.set_fact: + defaults: "{{ defaults['defaults'] }}" + delegate_to: localhost - name: Prepare Service Model cisco.nac_dc_vxlan.common.prepare_service_model: inventory_hostname: "{{ inventory_hostname }}" hostvars: "{{ hostvars }}" model_data: "{{ model_data['data'] }}" + default_values: "{{ defaults }}" + templates_path: "{{ role_path }}/../dtc/common/templates/" register: smd delegate_to: localhost diff --git a/roles/validate/tasks/sub_main_msd.yml b/roles/validate/tasks/sub_main_msd.yml new file mode 100644 index 000000000..22ad6cc14 --- /dev/null +++ b/roles/validate/tasks/sub_main_msd.yml @@ -0,0 +1,85 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Perform Required Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ rules_path }}" + register: model_data_msd + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + rules_path: "{{ role_path }}/files/rules/required_rules/msd/" + delegate_to: localhost + +- name: Prepare Service Model + cisco.nac_dc_vxlan.common.prepare_service_model: + inventory_hostname: "{{ inventory_hostname }}" + hostvars: "{{ hostvars }}" + model_data: "{{ model_data_msd['data'] }}" + default_values: "{{ defaults }}" + templates_path: "{{ role_path }}/../dtc/common/templates/" + register: smd + delegate_to: localhost + +- name: Store Golden Service Model Data + ansible.builtin.set_fact: + MD: "{{ smd['model_golden'] }}" + delegate_to: localhost + +- name: Store Extended Service Model Data + ansible.builtin.set_fact: + MD_Extended: "{{ smd['model_extended'] }}" + delegate_to: localhost + +- name: Check Roles + cisco.nac_dc_vxlan.common.check_roles: + role_list: "{{ role_names }}" + register: check_roles + delegate_to: localhost + +- name: Read Run Map From Previous Run + cisco.nac_dc_vxlan.common.read_run_map: + model_data: "{{ MD_Extended }}" + register: run_map_read_result + delegate_to: localhost + +- name: Debug Run Map Read Result + ansible.builtin.debug: + msg: "{{ run_map_read_result }}" + delegate_to: localhost + +- name: Initialize Run Map + cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" + stage: starting_execution + register: run_map + delegate_to: localhost + +- name: Manage Previous Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_previous.yml + when: check_roles['save_previous'] + +- name: Manage Current Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_current.yml + when: check_roles['save_previous'] \ No newline at end of file From 49dcb6d15ae67f4136c067f25bd9b276d5d64536 Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Wed, 27 Nov 2024 10:18:59 -0800 Subject: [PATCH 004/183] Split validate and load functions --- .../action/common/{nac_dc_import.py => nac_dc_load.py} | 0 plugins/action/common/nac_dc_validate.py | 4 ---- roles/validate/tasks/sub_main.yml | 3 +-- roles/validate/tasks/sub_main_common.yml | 4 ++-- roles/validate/tasks/sub_main_msd.yml | 9 ++++++--- 5 files changed, 9 insertions(+), 11 deletions(-) rename plugins/action/common/{nac_dc_import.py => nac_dc_load.py} (100%) diff --git a/plugins/action/common/nac_dc_import.py b/plugins/action/common/nac_dc_load.py similarity index 100% rename from plugins/action/common/nac_dc_import.py rename to plugins/action/common/nac_dc_load.py diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 3af8b48d3..c7a91085b 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -48,7 +48,6 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False results['msg'] = None - results['data'] = {} if IAC_VALIDATE_IMPORT_ERROR: raise AnsibleError('iac-validate not found and must be installed. Please pip install iac-validate.') from IAC_VALIDATE_IMPORT_ERROR @@ -93,7 +92,4 @@ def run(self, tmp=None, task_vars=None): results['failed'] = True results['msg'] = msg - # Return Schema Validated Model Data - results['data'] = load_yaml_files([mdata]) - return results diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index ade2b5587..3381aa95a 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -26,7 +26,6 @@ schema: "{{ schema_path }}" mdata: "{{ data_path }}" rules: "{{ rules_path }}" - register: model_data_vxlan vars: data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" rules_path: "{{ role_path }}/files/rules/required_rules/" @@ -36,7 +35,7 @@ cisco.nac_dc_vxlan.common.prepare_service_model: inventory_hostname: "{{ inventory_hostname }}" hostvars: "{{ hostvars }}" - model_data: "{{ model_data_vxlan['data'] }}" + model_data: "{{ model_data['data'] }}" default_values: "{{ defaults }}" templates_path: "{{ role_path }}/../dtc/common/templates/" register: smd diff --git a/roles/validate/tasks/sub_main_common.yml b/roles/validate/tasks/sub_main_common.yml index 8907154f8..310a79e69 100644 --- a/roles/validate/tasks/sub_main_common.yml +++ b/roles/validate/tasks/sub_main_common.yml @@ -53,8 +53,8 @@ when: enhanced_rules_path is not defined delegate_to: localhost -- name: Import Semantic Model - cisco.nac_dc_vxlan.common.nac_dc_import: +- name: Load Data Model + cisco.nac_dc_vxlan.common.nac_dc_load: mdata: "{{ data_path }}" register: model_data vars: diff --git a/roles/validate/tasks/sub_main_msd.yml b/roles/validate/tasks/sub_main_msd.yml index 22ad6cc14..f4a566d37 100644 --- a/roles/validate/tasks/sub_main_msd.yml +++ b/roles/validate/tasks/sub_main_msd.yml @@ -26,7 +26,6 @@ schema: "{{ schema_path }}" mdata: "{{ data_path }}" rules: "{{ rules_path }}" - register: model_data_msd vars: data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" rules_path: "{{ role_path }}/files/rules/required_rules/msd/" @@ -36,7 +35,7 @@ cisco.nac_dc_vxlan.common.prepare_service_model: inventory_hostname: "{{ inventory_hostname }}" hostvars: "{{ hostvars }}" - model_data: "{{ model_data_msd['data'] }}" + model_data: "{{ model_data['data'] }}" default_values: "{{ defaults }}" templates_path: "{{ role_path }}/../dtc/common/templates/" register: smd @@ -82,4 +81,8 @@ - name: Manage Current Service Model Data Files ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] \ No newline at end of file + when: check_roles['save_previous'] + +- debug: msg="{{ MD }}" + +- debug: msg="{{ MD_Extended }}" \ No newline at end of file From 7ef9df8601d9d517c7b38f54610055d92ba2cd91 Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Wed, 27 Nov 2024 10:38:54 -0800 Subject: [PATCH 005/183] Refactoring sub main common --- roles/validate/tasks/main.yml | 6 +- roles/validate/tasks/sub_main_common.yml | 74 +++++++------------ roles/validate/tasks/sub_main_msd.yml | 40 +++++----- .../{sub_main.yml => sub_main_vxlan.yml} | 34 ++++----- 4 files changed, 66 insertions(+), 88 deletions(-) rename roles/validate/tasks/{sub_main.yml => sub_main_vxlan.yml} (78%) diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index bf91a43f2..a454e6c31 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -32,7 +32,7 @@ when: MD_Extended.vxlan.fabric_type == 'MSD' - name: Import Role Tasks for VxLAN Fabric - ansible.builtin.import_tasks: sub_main.yml + ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' # Problems with lower versions of python and ansible @@ -62,3 +62,7 @@ stage: role_validate_completed register: run_map delegate_to: localhost + +- debug: msg="{{ MD }}" + +- debug: msg="{{ MD_Extended }}" \ No newline at end of file diff --git a/roles/validate/tasks/sub_main_common.yml b/roles/validate/tasks/sub_main_common.yml index 310a79e69..fdcb36807 100644 --- a/roles/validate/tasks/sub_main_common.yml +++ b/roles/validate/tasks/sub_main_common.yml @@ -41,18 +41,6 @@ - ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" -- name: Check for Schema Path Being Defined - ansible.builtin.set_fact: - schema_path: '' - when: schema_path is not defined - delegate_to: localhost - -- name: Check for Enhanced Roles Path Being Defined - ansible.builtin.set_fact: - enhanced_rules_path: '' - when: enhanced_rules_path is not defined - delegate_to: localhost - - name: Load Data Model cisco.nac_dc_vxlan.common.nac_dc_load: mdata: "{{ data_path }}" @@ -61,16 +49,6 @@ data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" delegate_to: localhost -# - name: Perform Enhanced Syntax and Semantic Model Validation -# cisco.nac_dc_vxlan.common.nac_dc_validate: -# schema: "{{ schema_path }}" -# mdata: "{{ data_path }}" -# rules: "{{ enhanced_rules_path }}" -# vars: -# data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" -# when: enhanced_rules_path is defined and enhanced_rules_path -# delegate_to: localhost - - name: Stat Factory Defaults ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" register: factory_defaults_file @@ -114,34 +92,34 @@ MD_Extended: "{{ smd['model_extended'] }}" delegate_to: localhost -- name: Check Roles - cisco.nac_dc_vxlan.common.check_roles: - role_list: "{{ role_names }}" - register: check_roles - delegate_to: localhost +# - name: Check Roles +# cisco.nac_dc_vxlan.common.check_roles: +# role_list: "{{ role_names }}" +# register: check_roles +# delegate_to: localhost -- name: Read Run Map From Previous Run - cisco.nac_dc_vxlan.common.read_run_map: - model_data: "{{ MD_Extended }}" - register: run_map_read_result - delegate_to: localhost +# - name: Read Run Map From Previous Run +# cisco.nac_dc_vxlan.common.read_run_map: +# model_data: "{{ MD_Extended }}" +# register: run_map_read_result +# delegate_to: localhost -- name: Debug Run Map Read Result - ansible.builtin.debug: - msg: "{{ run_map_read_result }}" - delegate_to: localhost +# - name: Debug Run Map Read Result +# ansible.builtin.debug: +# msg: "{{ run_map_read_result }}" +# delegate_to: localhost -- name: Initialize Run Map - cisco.nac_dc_vxlan.common.run_map: - model_data: "{{ MD_Extended }}" - stage: starting_execution - register: run_map - delegate_to: localhost +# - name: Initialize Run Map +# cisco.nac_dc_vxlan.common.run_map: +# model_data: "{{ MD_Extended }}" +# stage: starting_execution +# register: run_map +# delegate_to: localhost -- name: Manage Previous Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_previous.yml - when: check_roles['save_previous'] +# - name: Manage Previous Service Model Data Files +# ansible.builtin.include_tasks: manage_model_files_previous.yml +# when: check_roles['save_previous'] -- name: Manage Current Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] \ No newline at end of file +# - name: Manage Current Service Model Data Files +# ansible.builtin.include_tasks: manage_model_files_current.yml +# when: check_roles['save_previous'] \ No newline at end of file diff --git a/roles/validate/tasks/sub_main_msd.yml b/roles/validate/tasks/sub_main_msd.yml index f4a566d37..0134d9f34 100644 --- a/roles/validate/tasks/sub_main_msd.yml +++ b/roles/validate/tasks/sub_main_msd.yml @@ -31,25 +31,25 @@ rules_path: "{{ role_path }}/files/rules/required_rules/msd/" delegate_to: localhost -- name: Prepare Service Model - cisco.nac_dc_vxlan.common.prepare_service_model: - inventory_hostname: "{{ inventory_hostname }}" - hostvars: "{{ hostvars }}" - model_data: "{{ model_data['data'] }}" - default_values: "{{ defaults }}" - templates_path: "{{ role_path }}/../dtc/common/templates/" - register: smd - delegate_to: localhost +# - name: Prepare Service Model +# cisco.nac_dc_vxlan.common.prepare_service_model: +# inventory_hostname: "{{ inventory_hostname }}" +# hostvars: "{{ hostvars }}" +# model_data: "{{ model_data['data'] }}" +# default_values: "{{ defaults }}" +# templates_path: "{{ role_path }}/../dtc/common/templates/" +# register: smd +# delegate_to: localhost -- name: Store Golden Service Model Data - ansible.builtin.set_fact: - MD: "{{ smd['model_golden'] }}" - delegate_to: localhost +# - name: Store Golden Service Model Data +# ansible.builtin.set_fact: +# MD: "{{ smd['model_golden'] }}" +# delegate_to: localhost -- name: Store Extended Service Model Data - ansible.builtin.set_fact: - MD_Extended: "{{ smd['model_extended'] }}" - delegate_to: localhost +# - name: Store Extended Service Model Data +# ansible.builtin.set_fact: +# MD_Extended: "{{ smd['model_extended'] }}" +# delegate_to: localhost - name: Check Roles cisco.nac_dc_vxlan.common.check_roles: @@ -81,8 +81,4 @@ - name: Manage Current Service Model Data Files ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] - -- debug: msg="{{ MD }}" - -- debug: msg="{{ MD_Extended }}" \ No newline at end of file + when: check_roles['save_previous'] \ No newline at end of file diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main_vxlan.yml similarity index 78% rename from roles/validate/tasks/sub_main.yml rename to roles/validate/tasks/sub_main_vxlan.yml index 3381aa95a..9484ae52d 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main_vxlan.yml @@ -31,25 +31,25 @@ rules_path: "{{ role_path }}/files/rules/required_rules/" delegate_to: localhost -- name: Prepare Service Model - cisco.nac_dc_vxlan.common.prepare_service_model: - inventory_hostname: "{{ inventory_hostname }}" - hostvars: "{{ hostvars }}" - model_data: "{{ model_data['data'] }}" - default_values: "{{ defaults }}" - templates_path: "{{ role_path }}/../dtc/common/templates/" - register: smd - delegate_to: localhost +# - name: Prepare Service Model +# cisco.nac_dc_vxlan.common.prepare_service_model: +# inventory_hostname: "{{ inventory_hostname }}" +# hostvars: "{{ hostvars }}" +# model_data: "{{ model_data['data'] }}" +# default_values: "{{ defaults }}" +# templates_path: "{{ role_path }}/../dtc/common/templates/" +# register: smd +# delegate_to: localhost -- name: Store Golden Service Model Data - ansible.builtin.set_fact: - MD: "{{ smd['model_golden'] }}" - delegate_to: localhost +# - name: Store Golden Service Model Data +# ansible.builtin.set_fact: +# MD: "{{ smd['model_golden'] }}" +# delegate_to: localhost -- name: Store Extended Service Model Data - ansible.builtin.set_fact: - MD_Extended: "{{ smd['model_extended'] }}" - delegate_to: localhost +# - name: Store Extended Service Model Data +# ansible.builtin.set_fact: +# MD_Extended: "{{ smd['model_extended'] }}" +# delegate_to: localhost - name: Check Roles cisco.nac_dc_vxlan.common.check_roles: From 0bd0e4f417df8cde5d12e7136e42f857c0353432 Mon Sep 17 00:00:00 2001 From: "Aneesh Ramgopal (anramgop)" Date: Wed, 27 Nov 2024 11:36:04 -0800 Subject: [PATCH 006/183] MSD create role --- roles/dtc/common/tasks/main.yml | 8 +++- roles/dtc/common/tasks/sub_main_msd.yml | 30 +++++++++++++++ .../{sub_main.yml => sub_main_vxlan.yml} | 0 roles/dtc/create/tasks/main.yml | 12 ++++-- roles/dtc/create/tasks/msd/fabric.yml | 36 ++++++++++++++++++ roles/dtc/create/tasks/sub_main_msd.yml | 37 +++++++++++++++++++ .../{sub_main.yml => sub_main_vxlan.yml} | 12 +++--- .../dtc/create/tasks/{ => vxlan}/devices.yml | 0 .../tasks/{ => vxlan}/devices_discovery.yml | 0 .../{ => vxlan}/devices_preprovision.yml | 0 roles/dtc/create/tasks/{ => vxlan}/fabric.yml | 0 .../create/tasks/{ => vxlan}/interfaces.yml | 0 .../dtc/create/tasks/{ => vxlan}/policies.yml | 0 roles/dtc/create/tasks/{ => vxlan}/reset.yml | 0 .../create/tasks/{ => vxlan}/vpc_peering.yml | 0 .../tasks/{ => vxlan}/vrfs_networks.yml | 0 .../tasks/manage_model_files_current.yml | 6 +-- .../tasks/manage_model_files_previous.yml | 10 ++--- 18 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 roles/dtc/common/tasks/sub_main_msd.yml rename roles/dtc/common/tasks/{sub_main.yml => sub_main_vxlan.yml} (100%) create mode 100644 roles/dtc/create/tasks/msd/fabric.yml create mode 100644 roles/dtc/create/tasks/sub_main_msd.yml rename roles/dtc/create/tasks/{sub_main.yml => sub_main_vxlan.yml} (90%) rename roles/dtc/create/tasks/{ => vxlan}/devices.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/devices_discovery.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/devices_preprovision.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/fabric.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/interfaces.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/policies.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/reset.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/vpc_peering.yml (100%) rename roles/dtc/create/tasks/{ => vxlan}/vrfs_networks.yml (100%) diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 7b71bf04e..62ccc6023 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -22,5 +22,11 @@ --- - name: Import Role Tasks - ansible.builtin.import_tasks: sub_main.yml + ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric_type == 'MSD' + +- name: Import Role Tasks + ansible.builtin.import_tasks: sub_main_vxlan.yml + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml new file mode 100644 index 000000000..9a0be8772 --- /dev/null +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling MSD Role - [cisco.nac_dc_vxlan.dtc.create] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml diff --git a/roles/dtc/common/tasks/sub_main.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml similarity index 100% rename from roles/dtc/common/tasks/sub_main.yml rename to roles/dtc/common/tasks/sub_main_vxlan.yml diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index f2f9ff153..f90755d47 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -21,9 +21,15 @@ --- -- name: Import Role Tasks - ansible.builtin.import_tasks: sub_main.yml - when: changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy +- name: Import VxLAN Role Tasks + ansible.builtin.import_tasks: sub_main_msd.yml + when: MD_Extended.vxlan.fabric_type == 'MSD' + +# - name: Import MSD Role Tasks +# ansible.builtin.import_tasks: sub_main_vxlan.yml +# when: +# - MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' +# - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml new file mode 100644 index 000000000..2d7677ff8 --- /dev/null +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric {{ MD.vxlan.name }}" + - "----------------------------------------------------------------" + +- name: Manage fabric {{ MD.vxlan.name }} in NDFC + cisco.dcnm.dcnm_fabric: + state: merged + config: + - FABRIC_NAME: MSD_Fabric + FABRIC_TYPE: VXLAN_EVPN_MSD diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml new file mode 100644 index 000000000..12ea1f706 --- /dev/null +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -0,0 +1,37 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling MSD Role - [cisco.nac_dc_vxlan.dtc.create] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml + +- name: Create NDFC MSD Fabric + ansible.builtin.import_tasks: msd/fabric.yml + # when: + # - MD_Extended.vxlan.global is defined + # - changes_detected_fabric + tags: "{{ nac_tags.create_fabric }}" diff --git a/roles/dtc/create/tasks/sub_main.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml similarity index 90% rename from roles/dtc/create/tasks/sub_main.yml rename to roles/dtc/create/tasks/sub_main_vxlan.yml index cb1ec174d..855af8f27 100644 --- a/roles/dtc/create/tasks/sub_main.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -33,42 +33,42 @@ tags: "{{ nac_tags.create }}" - name: Create NDFC Fabric - ansible.builtin.import_tasks: fabric.yml + ansible.builtin.import_tasks: vxlan/fabric.yml when: - MD_Extended.vxlan.global is defined - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC Fabric Switches - ansible.builtin.import_tasks: devices.yml + ansible.builtin.import_tasks: vxlan/devices.yml when: - MD_Extended.vxlan.topology.switches | length > 0 - changes_detected_inventory tags: "{{ nac_tags.create_switches }}" - name: Manage VPC Peering - ansible.builtin.import_tasks: vpc_peering.yml + ansible.builtin.import_tasks: vxlan/vpc_peering.yml when: - MD_Extended.vxlan.topology.vpc_peers | length > 0 - changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" - name: Manage NDFC Fabric Interfaces - ansible.builtin.import_tasks: interfaces.yml + ansible.builtin.import_tasks: vxlan/interfaces.yml when: - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" - name: Manage NDFC Fabric VRFs and Networks - ansible.builtin.import_tasks: vrfs_networks.yml + ansible.builtin.import_tasks: vxlan/vrfs_networks.yml when: - (MD.vxlan.overlay_services is defined) and (MD_Extended.vxlan.topology.switches | length > 0) - changes_detected_vrfs or changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Policies - ansible.builtin.import_tasks: policies.yml + ansible.builtin.import_tasks: vxlan/policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - changes_detected_policy diff --git a/roles/dtc/create/tasks/devices.yml b/roles/dtc/create/tasks/vxlan/devices.yml similarity index 100% rename from roles/dtc/create/tasks/devices.yml rename to roles/dtc/create/tasks/vxlan/devices.yml diff --git a/roles/dtc/create/tasks/devices_discovery.yml b/roles/dtc/create/tasks/vxlan/devices_discovery.yml similarity index 100% rename from roles/dtc/create/tasks/devices_discovery.yml rename to roles/dtc/create/tasks/vxlan/devices_discovery.yml diff --git a/roles/dtc/create/tasks/devices_preprovision.yml b/roles/dtc/create/tasks/vxlan/devices_preprovision.yml similarity index 100% rename from roles/dtc/create/tasks/devices_preprovision.yml rename to roles/dtc/create/tasks/vxlan/devices_preprovision.yml diff --git a/roles/dtc/create/tasks/fabric.yml b/roles/dtc/create/tasks/vxlan/fabric.yml similarity index 100% rename from roles/dtc/create/tasks/fabric.yml rename to roles/dtc/create/tasks/vxlan/fabric.yml diff --git a/roles/dtc/create/tasks/interfaces.yml b/roles/dtc/create/tasks/vxlan/interfaces.yml similarity index 100% rename from roles/dtc/create/tasks/interfaces.yml rename to roles/dtc/create/tasks/vxlan/interfaces.yml diff --git a/roles/dtc/create/tasks/policies.yml b/roles/dtc/create/tasks/vxlan/policies.yml similarity index 100% rename from roles/dtc/create/tasks/policies.yml rename to roles/dtc/create/tasks/vxlan/policies.yml diff --git a/roles/dtc/create/tasks/reset.yml b/roles/dtc/create/tasks/vxlan/reset.yml similarity index 100% rename from roles/dtc/create/tasks/reset.yml rename to roles/dtc/create/tasks/vxlan/reset.yml diff --git a/roles/dtc/create/tasks/vpc_peering.yml b/roles/dtc/create/tasks/vxlan/vpc_peering.yml similarity index 100% rename from roles/dtc/create/tasks/vpc_peering.yml rename to roles/dtc/create/tasks/vxlan/vpc_peering.yml diff --git a/roles/dtc/create/tasks/vrfs_networks.yml b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml similarity index 100% rename from roles/dtc/create/tasks/vrfs_networks.yml rename to roles/dtc/create/tasks/vxlan/vrfs_networks.yml diff --git a/roles/validate/tasks/manage_model_files_current.yml b/roles/validate/tasks/manage_model_files_current.yml index 2711fc3c0..43030ab06 100644 --- a/roles/validate/tasks/manage_model_files_current.yml +++ b/roles/validate/tasks/manage_model_files_current.yml @@ -25,7 +25,7 @@ - name: Copy Service Model Data to Host ansible.builtin.copy: content: "{{ MD | to_nice_json }}" - dest: "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden.json" + dest: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" force: yes delegate_to: localhost @@ -33,14 +33,14 @@ - name: Copy Extended Service Model Data to Host ansible.builtin.copy: content: "{{ MD_Extended | to_nice_json }}" - dest: "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_extended.json" + dest: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" force: yes delegate_to: localhost # Read current golden service model data into a variable called 'smd_golden_current' - name: Read Current Service Model Data from Host ansible.builtin.include_vars: - file: "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden.json" + file: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" register: smd_golden_current delegate_to: localhost diff --git a/roles/validate/tasks/manage_model_files_previous.yml b/roles/validate/tasks/manage_model_files_previous.yml index 25fa16daf..590502927 100644 --- a/roles/validate/tasks/manage_model_files_previous.yml +++ b/roles/validate/tasks/manage_model_files_previous.yml @@ -29,31 +29,31 @@ # Check if golden and extended service model data files exist from previous runs - name: Stat the Golden Service Model Data - ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden.json" + ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" register: golden_stat delegate_to: localhost - name: Stat the Extended Service Model Data - ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_extended.json" + ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" register: extended_stat delegate_to: localhost # Read and store previous golden service model data into a variable called 'smd_golden_previous' - name: Read Previous Golden Service Model Data from Host ansible.builtin.include_vars: - file: "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden.json" + file: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" register: smd_golden_previous when: golden_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost # Rename golden file from previous run to append '_previous' to the filename - name: Move Golden Service Model Data Previous - ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden.json" "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_golden_previous.json" + ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden_previous.json" when: golden_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost # Rename extended file from previous run to append '_previous' to the filename - name: Move Extended Service Model Data Previous - ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_extended.json" "{{ role_path }}/files/{{ MD.vxlan.global.name }}_service_model_extended_previous.json" + ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended_previous.json" when: extended_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost From 075475e13762160799a5faa35075ed3c968b69d3 Mon Sep 17 00:00:00 2001 From: mwiebe Date: Mon, 2 Dec 2024 20:11:19 -0500 Subject: [PATCH 007/183] Additional refactoring for MSD and VXLAN workflows --- plugins/action/common/nac_dc_validate.py | 1 - roles/dtc/common/tasks/main.yml | 4 +- roles/dtc/common/tasks/msd/ndfc_children.yml | 3 + roles/dtc/common/tasks/msd/ndfc_fabric.yml | 3 + roles/dtc/common/tasks/sub_main_msd.yml | 32 ++++++++--- roles/dtc/common/tasks/sub_main_vxlan.yml | 34 +++++------ .../common/tasks/{ => vxlan}/ndfc_fabric.yml | 0 .../{ => vxlan}/ndfc_interface_access.yml | 0 .../{ => vxlan}/ndfc_interface_access_po.yml | 0 .../tasks/{ => vxlan}/ndfc_interface_all.yml | 0 .../{ => vxlan}/ndfc_interface_loopback.yml | 0 .../{ => vxlan}/ndfc_interface_po_routed.yml | 0 .../{ => vxlan}/ndfc_interface_routed.yml | 0 .../{ => vxlan}/ndfc_interface_trunk.yml | 0 .../{ => vxlan}/ndfc_interface_trunk_po.yml | 0 .../tasks/{ => vxlan}/ndfc_interface_vpc.yml | 0 .../tasks/{ => vxlan}/ndfc_inventory.yml | 0 .../{ => vxlan}/ndfc_link_vpc_peering.yml | 0 .../tasks/{ => vxlan}/ndfc_networks.yml | 0 .../common/tasks/{ => vxlan}/ndfc_policy.yml | 0 .../{ => vxlan}/ndfc_sub_interface_routed.yml | 0 .../tasks/{ => vxlan}/ndfc_vpc_peering.yml | 0 .../common/tasks/{ => vxlan}/ndfc_vrfs.yml | 0 roles/dtc/create/tasks/msd/fabric.yml | 2 +- .../files/rules/required_rules/msd/.gitkeep | 0 .../files/rules/required_rules/vxlan/.gitkeep | 0 .../{ => vxlan}/201_global_spanning_tree.py | 0 .../202_global_underlay_mcast_trm.py | 0 .../{ => vxlan}/203_global_underlay_isis.py | 0 .../{ => vxlan}/301_topology_switch_serial.py | 0 .../302_topology_switch_management.py | 0 .../{ => vxlan}/303_topology_switch_role.py | 0 ...pology_switch_interfaces_members_unique.py | 0 .../305_topology_switch_interfaces_vpc.py | 0 .../401_overlay_services_cross_reference.py | 0 .../{ => vxlan}/402_overlay_services_vrfs.py | 0 .../403_overlay_services_networks.py | 0 .../{ => vxlan}/501_policy_cross_reference.py | 0 .../502_policy_vrf_lite_cross_reference.py | 0 roles/validate/tasks/main.yml | 12 ++-- roles/validate/tasks/sub_main_common_post.yml | 54 ++++++++++++++++++ ...ain_common.yml => sub_main_common_pre.yml} | 35 ------------ roles/validate/tasks/sub_main_msd.yml | 54 +----------------- roles/validate/tasks/sub_main_vxlan.yml | 56 +------------------ 44 files changed, 116 insertions(+), 174 deletions(-) create mode 100644 roles/dtc/common/tasks/msd/ndfc_children.yml create mode 100644 roles/dtc/common/tasks/msd/ndfc_fabric.yml rename roles/dtc/common/tasks/{ => vxlan}/ndfc_fabric.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_access.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_access_po.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_all.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_loopback.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_po_routed.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_routed.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_trunk.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_trunk_po.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_interface_vpc.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_inventory.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_link_vpc_peering.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_networks.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_policy.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_sub_interface_routed.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_vpc_peering.yml (100%) rename roles/dtc/common/tasks/{ => vxlan}/ndfc_vrfs.yml (100%) create mode 100644 roles/validate/files/rules/required_rules/msd/.gitkeep create mode 100644 roles/validate/files/rules/required_rules/vxlan/.gitkeep rename roles/validate/files/rules/required_rules/{ => vxlan}/201_global_spanning_tree.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/202_global_underlay_mcast_trm.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/203_global_underlay_isis.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/301_topology_switch_serial.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/302_topology_switch_management.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/303_topology_switch_role.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/304_topology_switch_interfaces_members_unique.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/305_topology_switch_interfaces_vpc.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/401_overlay_services_cross_reference.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/402_overlay_services_vrfs.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/403_overlay_services_networks.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/501_policy_cross_reference.py (100%) rename roles/validate/files/rules/required_rules/{ => vxlan}/502_policy_vrf_lite_cross_reference.py (100%) create mode 100644 roles/validate/tasks/sub_main_common_post.yml rename roles/validate/tasks/{sub_main_common.yml => sub_main_common_pre.yml} (75%) diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index c7a91085b..6e32f6106 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -30,7 +30,6 @@ try: import iac_validate.validator - from iac_validate.yaml import load_yaml_files from iac_validate.cli.options import DEFAULT_SCHEMA except ImportError as imp_exc: IAC_VALIDATE_IMPORT_ERROR = imp_exc diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 62ccc6023..d219dee4a 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -21,12 +21,12 @@ --- -- name: Import Role Tasks +- name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'MSD' -- name: Import Role Tasks +- name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' diff --git a/roles/dtc/common/tasks/msd/ndfc_children.yml b/roles/dtc/common/tasks/msd/ndfc_children.yml new file mode 100644 index 000000000..6def6b2e0 --- /dev/null +++ b/roles/dtc/common/tasks/msd/ndfc_children.yml @@ -0,0 +1,3 @@ +--- + +- debug: msg="Building NDFC MSD Child Fabric Data" \ No newline at end of file diff --git a/roles/dtc/common/tasks/msd/ndfc_fabric.yml b/roles/dtc/common/tasks/msd/ndfc_fabric.yml new file mode 100644 index 000000000..fa74285bc --- /dev/null +++ b/roles/dtc/common/tasks/msd/ndfc_fabric.yml @@ -0,0 +1,3 @@ +--- + +- debug: msg="Building NDFC MSD Fabric Data" \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 9a0be8772..12a6bd255 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -21,10 +21,28 @@ --- -- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Calling MSD Role - [cisco.nac_dc_vxlan.dtc.create] +" - - "----------------------------------------------------------------" - tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml +- ansible.builtin.fail: msg="Service Model Not Defined. Role cisco.nac_dc_vxlan.validate Must Be Called First" + when: MD is undefined + delegate_to: localhost + +# -------------------------------------------------------------------- +# Remove all files from the previous run if run_map requires it +# -------------------------------------------------------------------- +- name: Cleanup Files from Previous Run if run_map requires it + ansible.builtin.include_tasks: cleanup_files.yml + when: + - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) + +# -------------------------------------------------------------------- +# Build Create Fabric parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.include_tasks: msd/ndfc_fabric.yml + +# -------------------------------------------------------------------- +# Build NDFC Child Fabric Inventory List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Child Fabric Inventory List From Template + ansible.builtin.include_tasks: msd/ndfc_children.yml diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index 41331d3d9..9029aa98e 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -38,119 +38,119 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.include_tasks: ndfc_fabric.yml + ansible.builtin.include_tasks: vxlan/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch Inventory List From Template - ansible.builtin.include_tasks: ndfc_inventory.yml + ansible.builtin.include_tasks: vxlan/ndfc_inventory.yml # -------------------------------------------------------------------- # Build Fabric intra links for vpc peering From Template # -------------------------------------------------------------------- - name: Build Intra Fabric Links From Template - ansible.builtin.include_tasks: ndfc_link_vpc_peering.yml + ansible.builtin.include_tasks: vxlan/ndfc_link_vpc_peering.yml # -------------------------------------------------------------------- # Build vPC Peering parameter List From Template # -------------------------------------------------------------------- - name: Build vPC Peering Parameters - ansible.builtin.include_tasks: ndfc_vpc_peering.yml + ansible.builtin.include_tasks: vxlan/ndfc_vpc_peering.yml # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric VRFs Attach List From Template - ansible.builtin.include_tasks: ndfc_vrfs.yml + ansible.builtin.include_tasks: vxlan/ndfc_vrfs.yml # -------------------------------------------------------------------- # Build NDFC Fabric Networks Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Networks Attach List From Template - ansible.builtin.include_tasks: ndfc_networks.yml + ansible.builtin.include_tasks: vxlan/ndfc_networks.yml # -------------------------------------------------------------------- # Build NDFC Fabric Loopback Interfaces List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Loopback Interfaces List From Template - ansible.builtin.include_tasks: ndfc_interface_loopback.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_loopback.yml # -------------------------------------------------------------------- # Build NDFC Fabric Access Port-Channel Interfaces List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Access Port-Channel Interfaces List From Template - ansible.builtin.include_tasks: ndfc_interface_access_po.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_access_po.yml # -------------------------------------------------------------------- # Build NDFC Fabric Trunk Port-Channel Interfaces List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Trunk Port-Channel Interfaces List From Template - ansible.builtin.include_tasks: ndfc_interface_trunk_po.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_trunk_po.yml # -------------------------------------------------------------------- # Build NDFC Fabric Interface Routed List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Interface Routed List From Template - ansible.builtin.include_tasks: ndfc_interface_routed.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_routed.yml # -------------------------------------------------------------------- # Build NDFC Fabric Sub-Interface Routed List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Sub-Interface Routed List From Template - ansible.builtin.include_tasks: ndfc_sub_interface_routed.yml + ansible.builtin.include_tasks: vxlan/ndfc_sub_interface_routed.yml # -------------------------------------------------------------------- # Build NDFC Fabric Routed Port-Channel Interface List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Routed Port-Channel Interface List From Template - ansible.builtin.include_tasks: ndfc_interface_po_routed.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_po_routed.yml # -------------------------------------------------------------------- # Build Trunk Interfaces List From Template # -------------------------------------------------------------------- - name: Build Trunk Interfaces List From Template - ansible.builtin.include_tasks: ndfc_interface_trunk.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_trunk.yml # -------------------------------------------------------------------- # Build Access Interfaces List From Template # -------------------------------------------------------------------- - name: Build Access Interfaces List From Template - ansible.builtin.include_tasks: ndfc_interface_access.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_access.yml # -------------------------------------------------------------------- # Build Fabric interface VPC List From Template # -------------------------------------------------------------------- - name: Build Fabric interface VPC List From Template - ansible.builtin.include_tasks: ndfc_interface_vpc.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_vpc.yml # -------------------------------------------------------------------- # Build Fabric interface all List From Template # -------------------------------------------------------------------- - name: Build Fabric interface All List From Template - ansible.builtin.include_tasks: ndfc_interface_all.yml + ansible.builtin.include_tasks: vxlan/ndfc_interface_all.yml # -------------------------------------------------------------------- # Build Fabric Policy List From Template # -------------------------------------------------------------------- - name: Build Fabric Policy List From Template - ansible.builtin.include_tasks: ndfc_policy.yml + ansible.builtin.include_tasks: vxlan/ndfc_policy.yml - name: Run Diff Flags ansible.builtin.debug: diff --git a/roles/dtc/common/tasks/ndfc_fabric.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_fabric.yml rename to roles/dtc/common/tasks/vxlan/ndfc_fabric.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_access.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_access.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_access_po.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_all.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_all.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_loopback.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_po_routed.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_routed.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_trunk.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_trunk_po.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml diff --git a/roles/dtc/common/tasks/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_interface_vpc.yml rename to roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml diff --git a/roles/dtc/common/tasks/ndfc_inventory.yml b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_inventory.yml rename to roles/dtc/common/tasks/vxlan/ndfc_inventory.yml diff --git a/roles/dtc/common/tasks/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_link_vpc_peering.yml rename to roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml diff --git a/roles/dtc/common/tasks/ndfc_networks.yml b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_networks.yml rename to roles/dtc/common/tasks/vxlan/ndfc_networks.yml diff --git a/roles/dtc/common/tasks/ndfc_policy.yml b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_policy.yml rename to roles/dtc/common/tasks/vxlan/ndfc_policy.yml diff --git a/roles/dtc/common/tasks/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_sub_interface_routed.yml rename to roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml diff --git a/roles/dtc/common/tasks/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_vpc_peering.yml rename to roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml diff --git a/roles/dtc/common/tasks/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml similarity index 100% rename from roles/dtc/common/tasks/ndfc_vrfs.yml rename to roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml index 2d7677ff8..27797fac0 100644 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -32,5 +32,5 @@ cisco.dcnm.dcnm_fabric: state: merged config: - - FABRIC_NAME: MSD_Fabric + - FABRIC_NAME: "{{ MD.vxlan.name }}" FABRIC_TYPE: VXLAN_EVPN_MSD diff --git a/roles/validate/files/rules/required_rules/msd/.gitkeep b/roles/validate/files/rules/required_rules/msd/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/validate/files/rules/required_rules/vxlan/.gitkeep b/roles/validate/files/rules/required_rules/vxlan/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/validate/files/rules/required_rules/201_global_spanning_tree.py b/roles/validate/files/rules/required_rules/vxlan/201_global_spanning_tree.py similarity index 100% rename from roles/validate/files/rules/required_rules/201_global_spanning_tree.py rename to roles/validate/files/rules/required_rules/vxlan/201_global_spanning_tree.py diff --git a/roles/validate/files/rules/required_rules/202_global_underlay_mcast_trm.py b/roles/validate/files/rules/required_rules/vxlan/202_global_underlay_mcast_trm.py similarity index 100% rename from roles/validate/files/rules/required_rules/202_global_underlay_mcast_trm.py rename to roles/validate/files/rules/required_rules/vxlan/202_global_underlay_mcast_trm.py diff --git a/roles/validate/files/rules/required_rules/203_global_underlay_isis.py b/roles/validate/files/rules/required_rules/vxlan/203_global_underlay_isis.py similarity index 100% rename from roles/validate/files/rules/required_rules/203_global_underlay_isis.py rename to roles/validate/files/rules/required_rules/vxlan/203_global_underlay_isis.py diff --git a/roles/validate/files/rules/required_rules/301_topology_switch_serial.py b/roles/validate/files/rules/required_rules/vxlan/301_topology_switch_serial.py similarity index 100% rename from roles/validate/files/rules/required_rules/301_topology_switch_serial.py rename to roles/validate/files/rules/required_rules/vxlan/301_topology_switch_serial.py diff --git a/roles/validate/files/rules/required_rules/302_topology_switch_management.py b/roles/validate/files/rules/required_rules/vxlan/302_topology_switch_management.py similarity index 100% rename from roles/validate/files/rules/required_rules/302_topology_switch_management.py rename to roles/validate/files/rules/required_rules/vxlan/302_topology_switch_management.py diff --git a/roles/validate/files/rules/required_rules/303_topology_switch_role.py b/roles/validate/files/rules/required_rules/vxlan/303_topology_switch_role.py similarity index 100% rename from roles/validate/files/rules/required_rules/303_topology_switch_role.py rename to roles/validate/files/rules/required_rules/vxlan/303_topology_switch_role.py diff --git a/roles/validate/files/rules/required_rules/304_topology_switch_interfaces_members_unique.py b/roles/validate/files/rules/required_rules/vxlan/304_topology_switch_interfaces_members_unique.py similarity index 100% rename from roles/validate/files/rules/required_rules/304_topology_switch_interfaces_members_unique.py rename to roles/validate/files/rules/required_rules/vxlan/304_topology_switch_interfaces_members_unique.py diff --git a/roles/validate/files/rules/required_rules/305_topology_switch_interfaces_vpc.py b/roles/validate/files/rules/required_rules/vxlan/305_topology_switch_interfaces_vpc.py similarity index 100% rename from roles/validate/files/rules/required_rules/305_topology_switch_interfaces_vpc.py rename to roles/validate/files/rules/required_rules/vxlan/305_topology_switch_interfaces_vpc.py diff --git a/roles/validate/files/rules/required_rules/401_overlay_services_cross_reference.py b/roles/validate/files/rules/required_rules/vxlan/401_overlay_services_cross_reference.py similarity index 100% rename from roles/validate/files/rules/required_rules/401_overlay_services_cross_reference.py rename to roles/validate/files/rules/required_rules/vxlan/401_overlay_services_cross_reference.py diff --git a/roles/validate/files/rules/required_rules/402_overlay_services_vrfs.py b/roles/validate/files/rules/required_rules/vxlan/402_overlay_services_vrfs.py similarity index 100% rename from roles/validate/files/rules/required_rules/402_overlay_services_vrfs.py rename to roles/validate/files/rules/required_rules/vxlan/402_overlay_services_vrfs.py diff --git a/roles/validate/files/rules/required_rules/403_overlay_services_networks.py b/roles/validate/files/rules/required_rules/vxlan/403_overlay_services_networks.py similarity index 100% rename from roles/validate/files/rules/required_rules/403_overlay_services_networks.py rename to roles/validate/files/rules/required_rules/vxlan/403_overlay_services_networks.py diff --git a/roles/validate/files/rules/required_rules/501_policy_cross_reference.py b/roles/validate/files/rules/required_rules/vxlan/501_policy_cross_reference.py similarity index 100% rename from roles/validate/files/rules/required_rules/501_policy_cross_reference.py rename to roles/validate/files/rules/required_rules/vxlan/501_policy_cross_reference.py diff --git a/roles/validate/files/rules/required_rules/502_policy_vrf_lite_cross_reference.py b/roles/validate/files/rules/required_rules/vxlan/502_policy_vrf_lite_cross_reference.py similarity index 100% rename from roles/validate/files/rules/required_rules/502_policy_vrf_lite_cross_reference.py rename to roles/validate/files/rules/required_rules/vxlan/502_policy_vrf_lite_cross_reference.py diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index a454e6c31..db816574c 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -22,16 +22,16 @@ --- - debug: msg="{{ nac_tags.all }}" -- name: Import Role Tasks - ansible.builtin.import_tasks: sub_main_common.yml +- name: Import Common Pre Role Tasks + ansible.builtin.import_tasks: sub_main_common_pre.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml -- name: Import Role Tasks for MSD Fabric +- name: Import MSD Fabric Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'MSD' -- name: Import Role Tasks for VxLAN Fabric +- name: Import VxLAN Fabric Role Tasks ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' @@ -57,6 +57,10 @@ # - role_deploy # - role_remove +- name: Import Common Post Role Tasks + ansible.builtin.import_tasks: sub_main_common_post.yml + tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml + - name: Mark Stage Role Validate Completed cisco.nac_dc_vxlan.common.run_map: stage: role_validate_completed diff --git a/roles/validate/tasks/sub_main_common_post.yml b/roles/validate/tasks/sub_main_common_post.yml new file mode 100644 index 000000000..351ff9635 --- /dev/null +++ b/roles/validate/tasks/sub_main_common_post.yml @@ -0,0 +1,54 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Check Roles + cisco.nac_dc_vxlan.common.check_roles: + role_list: "{{ role_names }}" + register: check_roles + delegate_to: localhost + +- name: Read Run Map From Previous Run + cisco.nac_dc_vxlan.common.read_run_map: + model_data: "{{ MD_Extended }}" + register: run_map_read_result + delegate_to: localhost + +- name: Debug Run Map Read Result + ansible.builtin.debug: + msg: "{{ run_map_read_result }}" + delegate_to: localhost + +- name: Initialize Run Map + cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" + stage: starting_execution + register: run_map + delegate_to: localhost + +- name: Manage Previous Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_previous.yml + when: check_roles['save_previous'] + +- name: Manage Current Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_current.yml + when: check_roles['save_previous'] diff --git a/roles/validate/tasks/sub_main_common.yml b/roles/validate/tasks/sub_main_common_pre.yml similarity index 75% rename from roles/validate/tasks/sub_main_common.yml rename to roles/validate/tasks/sub_main_common_pre.yml index fdcb36807..a75c5e521 100644 --- a/roles/validate/tasks/sub_main_common.yml +++ b/roles/validate/tasks/sub_main_common_pre.yml @@ -35,9 +35,6 @@ - name: Validate NDFC Service Model Data ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" -- ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" - when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" - - ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" @@ -91,35 +88,3 @@ ansible.builtin.set_fact: MD_Extended: "{{ smd['model_extended'] }}" delegate_to: localhost - -# - name: Check Roles -# cisco.nac_dc_vxlan.common.check_roles: -# role_list: "{{ role_names }}" -# register: check_roles -# delegate_to: localhost - -# - name: Read Run Map From Previous Run -# cisco.nac_dc_vxlan.common.read_run_map: -# model_data: "{{ MD_Extended }}" -# register: run_map_read_result -# delegate_to: localhost - -# - name: Debug Run Map Read Result -# ansible.builtin.debug: -# msg: "{{ run_map_read_result }}" -# delegate_to: localhost - -# - name: Initialize Run Map -# cisco.nac_dc_vxlan.common.run_map: -# model_data: "{{ MD_Extended }}" -# stage: starting_execution -# register: run_map -# delegate_to: localhost - -# - name: Manage Previous Service Model Data Files -# ansible.builtin.include_tasks: manage_model_files_previous.yml -# when: check_roles['save_previous'] - -# - name: Manage Current Service Model Data Files -# ansible.builtin.include_tasks: manage_model_files_current.yml -# when: check_roles['save_previous'] \ No newline at end of file diff --git a/roles/validate/tasks/sub_main_msd.yml b/roles/validate/tasks/sub_main_msd.yml index 0134d9f34..400d755c6 100644 --- a/roles/validate/tasks/sub_main_msd.yml +++ b/roles/validate/tasks/sub_main_msd.yml @@ -21,7 +21,7 @@ --- -- name: Perform Required Syntax and Semantic Model Validation +- name: Perform Required Syntax and Semantic Model Validation for MSD Fabric cisco.nac_dc_vxlan.common.nac_dc_validate: schema: "{{ schema_path }}" mdata: "{{ data_path }}" @@ -30,55 +30,3 @@ data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" rules_path: "{{ role_path }}/files/rules/required_rules/msd/" delegate_to: localhost - -# - name: Prepare Service Model -# cisco.nac_dc_vxlan.common.prepare_service_model: -# inventory_hostname: "{{ inventory_hostname }}" -# hostvars: "{{ hostvars }}" -# model_data: "{{ model_data['data'] }}" -# default_values: "{{ defaults }}" -# templates_path: "{{ role_path }}/../dtc/common/templates/" -# register: smd -# delegate_to: localhost - -# - name: Store Golden Service Model Data -# ansible.builtin.set_fact: -# MD: "{{ smd['model_golden'] }}" -# delegate_to: localhost - -# - name: Store Extended Service Model Data -# ansible.builtin.set_fact: -# MD_Extended: "{{ smd['model_extended'] }}" -# delegate_to: localhost - -- name: Check Roles - cisco.nac_dc_vxlan.common.check_roles: - role_list: "{{ role_names }}" - register: check_roles - delegate_to: localhost - -- name: Read Run Map From Previous Run - cisco.nac_dc_vxlan.common.read_run_map: - model_data: "{{ MD_Extended }}" - register: run_map_read_result - delegate_to: localhost - -- name: Debug Run Map Read Result - ansible.builtin.debug: - msg: "{{ run_map_read_result }}" - delegate_to: localhost - -- name: Initialize Run Map - cisco.nac_dc_vxlan.common.run_map: - model_data: "{{ MD_Extended }}" - stage: starting_execution - register: run_map - delegate_to: localhost - -- name: Manage Previous Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_previous.yml - when: check_roles['save_previous'] - -- name: Manage Current Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] \ No newline at end of file diff --git a/roles/validate/tasks/sub_main_vxlan.yml b/roles/validate/tasks/sub_main_vxlan.yml index 9484ae52d..c14bef235 100644 --- a/roles/validate/tasks/sub_main_vxlan.yml +++ b/roles/validate/tasks/sub_main_vxlan.yml @@ -21,64 +21,12 @@ --- -- name: Perform Required Syntax and Semantic Model Validation +- name: Perform Required Syntax and Semantic Model Validation for VXLAN Fabric cisco.nac_dc_vxlan.common.nac_dc_validate: schema: "{{ schema_path }}" mdata: "{{ data_path }}" rules: "{{ rules_path }}" vars: data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/required_rules/" + rules_path: "{{ role_path }}/files/rules/required_rules/vxlan/" delegate_to: localhost - -# - name: Prepare Service Model -# cisco.nac_dc_vxlan.common.prepare_service_model: -# inventory_hostname: "{{ inventory_hostname }}" -# hostvars: "{{ hostvars }}" -# model_data: "{{ model_data['data'] }}" -# default_values: "{{ defaults }}" -# templates_path: "{{ role_path }}/../dtc/common/templates/" -# register: smd -# delegate_to: localhost - -# - name: Store Golden Service Model Data -# ansible.builtin.set_fact: -# MD: "{{ smd['model_golden'] }}" -# delegate_to: localhost - -# - name: Store Extended Service Model Data -# ansible.builtin.set_fact: -# MD_Extended: "{{ smd['model_extended'] }}" -# delegate_to: localhost - -- name: Check Roles - cisco.nac_dc_vxlan.common.check_roles: - role_list: "{{ role_names }}" - register: check_roles - delegate_to: localhost - -- name: Read Run Map From Previous Run - cisco.nac_dc_vxlan.common.read_run_map: - model_data: "{{ MD_Extended }}" - register: run_map_read_result - delegate_to: localhost - -- name: Debug Run Map Read Result - ansible.builtin.debug: - msg: "{{ run_map_read_result }}" - delegate_to: localhost - -- name: Initialize Run Map - cisco.nac_dc_vxlan.common.run_map: - model_data: "{{ MD_Extended }}" - stage: starting_execution - register: run_map - delegate_to: localhost - -- name: Manage Previous Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_previous.yml - when: check_roles['save_previous'] - -- name: Manage Current Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] \ No newline at end of file From 9a73ea9ad1ea9650b431623387c0dc2defaa861d Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 2 Dec 2024 21:35:32 -0500 Subject: [PATCH 008/183] updates for msd fabric templating --- plugins/action/common/nac_dc_load.py | 5 +++- plugins/action/common/nac_dc_validate.py | 1 - roles/dtc/common/tasks/ndfc_fabric.yml | 8 ++++-- roles/dtc/common/tasks/sub_main_msd.yml | 25 +++++++++++++------ roles/dtc/common/templates/ndfc_fabric.j2 | 9 +++++-- .../templates/ndfc_fabric/msd_fabric/.gitkeep | 0 .../ndfc_fabric/msd_fabric/dci/.gitkeep | 0 .../msd_fabric/dci/msd_fabric_dci.j2 | 12 +++++++++ .../ndfc_fabric/msd_fabric/general/.gitkeep | 0 .../msd_fabric/general/msd_fabric_general.j2 | 6 +++++ .../ndfc_fabric/msd_fabric/msd_fabric_base.j2 | 7 ++++++ .../ndfc_fabric/msd_fabric/resources/.gitkeep | 0 .../resources/msd_fabric_resources.j2 | 4 +++ .../ndfc_fabric/msd_fabric/security/.gitkeep | 0 .../security/msd_fabric_security.j2 | 2 ++ 15 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 diff --git a/plugins/action/common/nac_dc_load.py b/plugins/action/common/nac_dc_load.py index 94eae990e..2b5154bae 100644 --- a/plugins/action/common/nac_dc_load.py +++ b/plugins/action/common/nac_dc_load.py @@ -58,13 +58,16 @@ def run(self, tmp=None, task_vars=None): if mdata and not os.path.exists(mdata): results['failed'] = True results['msg'] = "The data directory ({0}) for this fabric does not appear to exist!".format(mdata) + return results + if len(os.listdir(mdata)) == 0: results['failed'] = True results['msg'] = "The data directory ({0}) for this fabric is empty!".format(mdata) + return results - # Return Schema Validated Model Data + # Return Merged Model Data results['data'] = load_yaml_files([mdata]) return results diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index c7a91085b..6e32f6106 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -30,7 +30,6 @@ try: import iac_validate.validator - from iac_validate.yaml import load_yaml_files from iac_validate.cli.options import DEFAULT_SCHEMA except ImportError as imp_exc: IAC_VALIDATE_IMPORT_ERROR = imp_exc diff --git a/roles/dtc/common/tasks/ndfc_fabric.yml b/roles/dtc/common/tasks/ndfc_fabric.yml index 26a8351a7..629a458bd 100644 --- a/roles/dtc/common/tasks/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/ndfc_fabric.yml @@ -28,7 +28,11 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_fabric.yml" + file_name: >- + {% if MD.vxlan.name is defined and MD.vxlan.name %} + {{ MD.vxlan.name }}_ndfc_fabric.yml + {% elif MD.vxlan.global.name is defined and MD.vxlan.global.name %} + {{ MD.vxlan.global.name }}_ndfc_fabric.yml delegate_to: localhost - name: Stat Previous File If It Exists @@ -59,7 +63,7 @@ - ansible.builtin.set_fact: fabric_config: "{{ lookup('file', file_name) | from_yaml }}" - when: MD.vxlan.global + when: MD.vxlan.global or MD.vxlan.multisite delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 9a0be8772..4be7dab87 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -21,10 +21,21 @@ --- -- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Calling MSD Role - [cisco.nac_dc_vxlan.dtc.create] +" - - "----------------------------------------------------------------" - tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml +- ansible.builtin.fail: msg="Service Model Not Defined. Role cisco.nac_dc_vxlan.validate Must Be Called First" + when: MD is undefined + delegate_to: localhost + +# -------------------------------------------------------------------- +# Remove all files from the previous run if run_map requires it +# -------------------------------------------------------------------- +- name: Cleanup Files from Previous Run if run_map requires it + ansible.builtin.include_tasks: cleanup_files.yml + when: + - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) + +# -------------------------------------------------------------------- +# Build Create Fabric Parameter List From Template +# -------------------------------------------------------------------- + +- name: Build MSD Fabric Create Parameters + ansible.builtin.include_tasks: ndfc_fabric.yml diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index f8aa6e2fc..51e478ed1 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -5,12 +5,17 @@ {% set vxlan = MD_Extended.vxlan %} {% set global = vxlan.global %} {% set fabric_type = vxlan.global.fabric_type | default('VXLAN_EVPN') %} -{% if fabric_type == 'VXLAN_EVPN' %} +{% if fabric_type == 'VXLAN_EVPN' or vxlan.fabric_type == 'VXLAN_EVPN' %} {# Include NDFC DC VXLAN EVPN Base Template #} {% include '/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2' %} +{% elif vxlan.fabric_type == 'MSD'%} + +{# Include NDFC MSD Base Template #} +{% include '/ndfc_fabric/msd/msd_fabric_base.j2' %} + {% else %} -{# Supported fabric types are: DC VXLAN EVPN #} +{# Supported fabric types are: DC VXLAN EVPN, MSD #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 new file mode 100644 index 000000000..a06fccaa4 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 @@ -0,0 +1,12 @@ +{# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.name }} #} + BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} + MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} + ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} + ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) }} + ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} + DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} + MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_bgp_password | default(defaults.vxlan.multisite.enable_bgp_password) }} +{% if vxlan.multisite.enable_bgp_password is defined and vxlan.multisite.enable_bgp_password %} + MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.bgp_password }} + MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.bgp_auth_key_type | default(defaults.vxlan.multisite.bgp_auth_key_type) }} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 new file mode 100644 index 000000000..1c4e92ca8 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -0,0 +1,6 @@ +{# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.name }} #} + ENABLE_PVLAN: false + ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} + MS_LOOPBACK_ID: {{ vxlan.multisite.loopback_id | default(defaults.vxlan.multisite.loopback_id) }} + BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} +{# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 new file mode 100644 index 000000000..8f4d07d09 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 @@ -0,0 +1,7 @@ +{# Auto-generated NDFC DC VXLAN EVPN Base config data structure for fabric {{ vxlan.name }} #} +- FABRIC_NAME: {{ vxlan.name }} + FABRIC_TYPE: VXLAN_EVPN_MSD + DEPLOY: True + +{# Include NDFC DC VXLAN EVPN General Template #} +{% include '/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 new file mode 100644 index 000000000..31bd7dd82 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -0,0 +1,4 @@ +{# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.name }} #} + LOOPBACK100_IP_RANGE: {{ vxlan.multisite.vtep_loopback_ip_range | default(defaults.vxlan.multisite.vtep_loopback_ip_range) }} + DCI_SUBNET_RANGE: {{ vxlan.multisite.dci_subnet_range | default(defaults.vxlan.multisite.dci_subnet_range) }} + DCI_SUBNET_MASK: {{ vxlan.multisite.dci_subnet_mask | default(defaults.vxlan.multisite.dci_subnet_mask) }} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 new file mode 100644 index 000000000..a7f56a612 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 @@ -0,0 +1,2 @@ +{# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.name }} #} + ENABLE_SGT: false \ No newline at end of file From 0a1b04264c29273d4926a25747abcd11f4e434c5 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 2 Dec 2024 21:37:59 -0500 Subject: [PATCH 009/183] remove dup file --- roles/dtc/common/tasks/msd/ndfc_fabric.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 roles/dtc/common/tasks/msd/ndfc_fabric.yml diff --git a/roles/dtc/common/tasks/msd/ndfc_fabric.yml b/roles/dtc/common/tasks/msd/ndfc_fabric.yml deleted file mode 100644 index fa74285bc..000000000 --- a/roles/dtc/common/tasks/msd/ndfc_fabric.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- - -- debug: msg="Building NDFC MSD Fabric Data" \ No newline at end of file From e413ba3471826a0c4808fa47d550410694b9ca5d Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 2 Dec 2024 21:39:52 -0500 Subject: [PATCH 010/183] update create task for msd --- roles/dtc/create/tasks/msd/fabric.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml index 27797fac0..153b16aab 100644 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -31,6 +31,4 @@ - name: Manage fabric {{ MD.vxlan.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged - config: - - FABRIC_NAME: "{{ MD.vxlan.name }}" - FABRIC_TYPE: VXLAN_EVPN_MSD + config: "{{ fabric_config }}" From a220eddfe00a3805ec35a1eb4dfb9abe8776bfde Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 2 Dec 2024 21:41:11 -0500 Subject: [PATCH 011/183] update create task for msd --- roles/dtc/create/tasks/sub_main_msd.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 12ea1f706..53bb19feb 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -31,7 +31,7 @@ - name: Create NDFC MSD Fabric ansible.builtin.import_tasks: msd/fabric.yml - # when: - # - MD_Extended.vxlan.global is defined - # - changes_detected_fabric + when: + - MD_Extended.vxlan.multisite is defined + - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" From 87c8395fcfc9c008b16dee8d61c54ce8850b9595 Mon Sep 17 00:00:00 2001 From: mwiebe Date: Mon, 2 Dec 2024 21:44:22 -0500 Subject: [PATCH 012/183] Add child fabrics logic --- plugins/action/dtc/move_child_fabrics.py | 83 ++++++++++++++++++++ roles/dtc/create/tasks/msd/child_fabrics.yml | 42 ++++++++++ roles/dtc/create/tasks/msd/fabric.yml | 2 +- roles/dtc/create/tasks/sub_main_msd.yml | 14 +++- 4 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 plugins/action/dtc/move_child_fabrics.py create mode 100644 roles/dtc/create/tasks/msd/child_fabrics.yml diff --git a/plugins/action/dtc/move_child_fabrics.py b/plugins/action/dtc/move_child_fabrics.py new file mode 100644 index 000000000..7163d0291 --- /dev/null +++ b/plugins/action/dtc/move_child_fabrics.py @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase + +display = Display() + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + results['failed'] = False + + fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') + parent_fabric_name = self._task.args['parent_fabric_name'] + child_fabrics = self._task.args['child_fabrics'] + + # Build a list of child fabrics that are associated with the parent fabric + associated_child_fabrics = [] + for fabric in fabric_associations: + if fabric.get('fabricParent') == parent_fabric_name: + associated_child_fabrics.append(fabric.get('fabricName')) + + for fabric in child_fabrics: + if fabric.get('name') not in associated_child_fabrics: + json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, fabric.get('name')) + add_fabric_result = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "POST", + "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", + "json_data": json_data + }, + task_vars=task_vars, + tmp=tmp + ) + + return results + + +# cisco.dcnm.dcnm_rest: +# method: POST +# path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd +# json_data: '{"destFabric":"nac-msd","sourceFabric":"nac-ndfc1"}' + +# https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations/ +# GET +# + +# https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd +# POST +# {"destFabric":"nac-msd","sourceFabric":"nac-ndfc1"} + +# https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit +# POST +# {"destFabric":"nac-msd","sourceFabric":"nac-ndfc1"} + + diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml new file mode 100644 index 000000000..e1514c0b0 --- /dev/null +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -0,0 +1,42 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Child Fabrics Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric {{ MD.vxlan.name }}" + - "----------------------------------------------------------------" + +- name: Get Fabric Association Data from NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations + register: fabric_associations + +- name: Move Child Fabrics To Fabric - {{ MD.vxlan.name }} + cisco.nac_dc_vxlan.dtc.move_child_fabrics: + fabric_associations: "{{ fabric_associations }}" + parent_fabric_name: "{{ MD_Extended.vxlan.name }}" + child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" + when: fabric_associations is defined diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml index 27797fac0..d0e1a04d9 100644 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -28,7 +28,7 @@ - "+ Manage Fabric {{ MD.vxlan.name }}" - "----------------------------------------------------------------" -- name: Manage fabric {{ MD.vxlan.name }} in NDFC +- name: Manage Fabric {{ MD.vxlan.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged config: diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 12ea1f706..42533fa5b 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -25,13 +25,23 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Calling MSD Role - [cisco.nac_dc_vxlan.dtc.create] +" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.create] +" - "----------------------------------------------------------------" tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.create }}" + - name: Create NDFC MSD Fabric ansible.builtin.import_tasks: msd/fabric.yml # when: # - MD_Extended.vxlan.global is defined - # - changes_detected_fabric + # - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" + +- name: Manage NDFC MSD Fabric Child Fabrics + ansible.builtin.import_tasks: msd/child_fabrics.yml + # when: + # - MD_Extended.vxlan.topology.switches | length > 0 + # - changes_detected_inventory + # tags: "{{ nac_tags.create_switches }}" From a1b5bbda65d6745465b37834c47589542918cfb4 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 3 Dec 2024 09:08:06 -0500 Subject: [PATCH 013/183] updated defaults --- roles/validate/files/defaults.yml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 2f4ffc69a..4ef1034b3 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -210,16 +210,6 @@ factory_defaults: distance: 110 bfd: enabled: false - default_information_originate: - always: false - nssa: - default_information_originate: false - no_redistribution: false - no_summary: false - translate: - always: false - supress_fa: false - never: false bgp: best_path_as_path_relax: false graceful_restart: true @@ -280,4 +270,18 @@ factory_defaults: as_override: false route_reflector_client: false default_originate: false - next_hop_self: false \ No newline at end of file + next_hop_self: false + multisite: + anycast_gateway_mac: 20:20:00:00:00:aa + vtep_loopback_id: 100 + vtep_loopback_ip_range: 10.10.0.0/24 + dci_subnet_range: 10.10.1.0/24 + dci_subnet_mask: 30 + bgw_ip_tag: 54321 + overlay_ifc: direct_to_bgws + underlay_autoconfig: false + enable_bgp_send_community: false + enable_bgp_log_neighbor_change: false + enable_bgp_bfd: false + delay_restore: 300 + enable_bgp_password: false From 9070b839b513efdc0659e13b464f667290fbc102 Mon Sep 17 00:00:00 2001 From: mwiebe Date: Tue, 3 Dec 2024 13:14:08 -0500 Subject: [PATCH 014/183] Update prepare plugins --- .../action/common/prepare_plugins/prep_001_list_defaults.py | 3 ++- plugins/action/common/prepare_service_model.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py index 515906c67..1b4828cc3 100644 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py @@ -52,7 +52,6 @@ def set_list_default(self, parent_keys, target_key): # used by other plugins without having to check if the key exists. def prepare(self): self.model_data = self.kwargs['results']['model_extended'] - # -------------------------------------------------------------------- # Fabric Global List Defaults # -------------------------------------------------------------------- @@ -74,6 +73,8 @@ def prepare(self): # Check vxlan.topology list elements parent_keys = ['vxlan', 'topology'] dm_check = data_model_key_check(self.model_data, parent_keys) + if 'topology' in dm_check['keys_not_found']: + self.model_data['vxlan']['topology'] = {} if 'topology' in dm_check['keys_no_data']: self.model_data['vxlan']['topology'] = {'edge_connections': []} self.model_data['vxlan']['topology'] = {'fabric_links': []} diff --git a/plugins/action/common/prepare_service_model.py b/plugins/action/common/prepare_service_model.py index d546ca5c7..c2bebc18d 100644 --- a/plugins/action/common/prepare_service_model.py +++ b/plugins/action/common/prepare_service_model.py @@ -58,8 +58,6 @@ def run(self, tmp=None, task_vars=None): full_plugin_path = "ansible_collections.cisco.nac_dc_vxlan.plugins.action.common.prepare_plugins" glob_plugin_path = os.path.dirname(__file__) + "/prepare_plugins" - if fabric_type == 'MSD': - glob_plugin_path = os.path.dirname(__file__) + "/prepare_plugins/msd" plugin_prefix = "prep*.py" prepare_libs = set(x.stem for x in pathlib.Path.glob(pathlib.Path(glob_plugin_path), plugin_prefix)) From e7520ec582a95f6465ed5e9316d80c3a9a349e00 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 4 Dec 2024 19:26:11 -0500 Subject: [PATCH 015/183] more work on msd & shift to overlay key from overlay_services but with backward compat. --- plugins/action/common/nac_dc_validate.py | 74 +++++++-- .../prepare_plugins/prep_001_list_defaults.py | 49 ++++++ .../common/prepare_plugins/prep_101_fabric.py | 109 +++++++++++++ .../common/prepare_plugins/prep_101_global.py | 30 ---- .../prep_104_fabric_overlay_services.py | 50 ++++++ roles/dtc/common/tasks/main.yml | 10 +- roles/dtc/common/tasks/ndfc_fabric.yml | 1 + roles/dtc/common/tasks/sub_main_vxlan.yml | 2 +- roles/dtc/common/templates/ndfc_fabric.j2 | 10 +- .../advanced/dc_vxlan_fabric_advanced.j2 | 14 +- .../dc_vxlan_fabric/dc_vxlan_fabric_base.j2 | 4 +- roles/dtc/create/tasks/main.yml | 12 +- roles/dtc/create/tasks/sub_main_msd.yml | 3 +- .../rules/{enhanced_rules => common}/.gitkeep | 0 .../{required_rules => multisite}/.gitkeep | 0 .../files/rules/required_rules/vxlan/.gitkeep | 0 .../{required_rules/msd => vxlan}/.gitkeep | 0 .../vxlan/201_global_spanning_tree.py | 0 .../vxlan/202_global_underlay_mcast_trm.py | 0 .../vxlan/203_global_underlay_isis.py | 0 .../vxlan/301_topology_switch_serial.py | 0 .../vxlan/302_topology_switch_management.py | 0 .../vxlan/303_topology_switch_role.py | 0 ...pology_switch_interfaces_members_unique.py | 0 .../305_topology_switch_interfaces_vpc.py | 0 .../401_overlay_services_cross_reference.py | 53 +++++- .../vxlan/402_overlay_services_vrfs.py | 40 ++--- .../vxlan/403_overlay_services_networks.py | 14 +- .../vxlan/501_policy_cross_reference.py | 0 .../502_policy_vrf_lite_cross_reference.py | 0 roles/validate/tasks/main.yml | 22 +-- roles/validate/tasks/sub_main.yml | 152 ++++++++++++++++++ roles/validate/tasks/sub_main_vxlan.yml | 2 +- 33 files changed, 530 insertions(+), 121 deletions(-) create mode 100644 plugins/action/common/prepare_plugins/prep_101_fabric.py delete mode 100644 plugins/action/common/prepare_plugins/prep_101_global.py rename roles/validate/files/rules/{enhanced_rules => common}/.gitkeep (100%) rename roles/validate/files/rules/{required_rules => multisite}/.gitkeep (100%) delete mode 100644 roles/validate/files/rules/required_rules/vxlan/.gitkeep rename roles/validate/files/rules/{required_rules/msd => vxlan}/.gitkeep (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/201_global_spanning_tree.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/202_global_underlay_mcast_trm.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/203_global_underlay_isis.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/301_topology_switch_serial.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/302_topology_switch_management.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/303_topology_switch_role.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/304_topology_switch_interfaces_members_unique.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/305_topology_switch_interfaces_vpc.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/401_overlay_services_cross_reference.py (65%) rename roles/validate/files/rules/{required_rules => }/vxlan/402_overlay_services_vrfs.py (66%) rename roles/validate/files/rules/{required_rules => }/vxlan/403_overlay_services_networks.py (74%) rename roles/validate/files/rules/{required_rules => }/vxlan/501_policy_cross_reference.py (100%) rename roles/validate/files/rules/{required_rules => }/vxlan/502_policy_vrf_lite_cross_reference.py (100%) create mode 100644 roles/validate/tasks/sub_main.yml diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 6e32f6106..8f45aaaf3 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -29,6 +29,7 @@ from ansible.errors import AnsibleError try: + from iac_validate.yaml import load_yaml_files import iac_validate.validator from iac_validate.cli.options import DEFAULT_SCHEMA except ImportError as imp_exc: @@ -37,6 +38,7 @@ IAC_VALIDATE_IMPORT_ERROR = None import os +from ...plugin_utils.helper_functions import data_model_key_check display = Display() @@ -77,18 +79,64 @@ def run(self, tmp=None, task_vars=None): if schema == '': schema = DEFAULT_SCHEMA - validator = iac_validate.validator.Validator(schema, rules) - if schema: - validator.validate_syntax([mdata]) - if rules: - validator.validate_semantics([mdata]) - - msg = "" - for error in validator.errors: - msg += error + "\n" - - if msg: - results['failed'] = True - results['msg'] = msg + rules_list = [] + if rules and task_vars['role_path'] in rules: + # Load in-memory data model using iac-validate + # Perform the load in this if block to avoid loading the data model multiple times when custom enhanced rules are provided + results['data'] = load_yaml_files([mdata]) + + # Introduce common directory to the rules list by default once vrf and network rules are updated + # rules_to_run.append(f'{rules}common') + parent_keys = ['vxlan', 'fabric'] + check = data_model_key_check(results['data'], parent_keys) + if 'fabric' in check['keys_found'] and 'fabric' in check['keys_data']: + if 'type' in results['data']['vxlan']['fabric']: + if results['data']['vxlan']['fabric']['type'] in ('VXLAN_EVPN'): + rules_list.append(f'{rules}vxlan/') + elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCF'): + rules_list.append(f'{rules}multisite/') + else: + results['failed'] = True + results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['fabric']['type']} is not a supported fabric type." + else: + results['failed'] = True + results['msg'] = "vxlan.fabric.type is not defined in the data model." + else: + # This else block is to be removed after the deprecation of vxlan.global.fabric_type + parent_keys = ['vxlan', 'global'] + check = data_model_key_check(results['data'], parent_keys) + if 'global' in check['keys_found'] and 'global' in check['keys_data']: + if 'fabric_type' in results['data']['vxlan']['global']: + display.deprecated("Attempting to use vxlan.global.fabric_type due to vxlan.fabric.type not being found. vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric.type.") + + if results['data']['vxlan']['global']['fabric_type'] in ('VXLAN_EVPN'): + rules_list.append(f'{rules}vxlan/') + elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCF'): + rules_list.append(f'{rules}multisite/') + else: + results['failed'] = True + results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['global']['fabric_type']} is not a supported fabric type." + else: + results['failed'] = True + results['msg'] = "vxlan.fabric.type is not defined in the data model." + else: + # Else block to pickup custom enhanced rules provided by the user + rules_list.append(f'{rules}') + + for rules_item in rules_list: + validator = iac_validate.validator.Validator(schema, rules_item) + if schema: + validator.validate_syntax([mdata]) + if rules_item: + validator.validate_semantics([mdata]) + + msg = "" + for error in validator.errors: + msg += error + "\n" + + if msg: + results['failed'] = True + results['msg'] = msg + break return results diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py index 515906c67..95872ddd5 100644 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py @@ -127,6 +127,55 @@ def prepare(self): # Fabric Overlay List Defaults # -------------------------------------------------------------------- + # Check vxlan.overlay list elements + parent_keys = ['vxlan', 'overlay'] + dm_check = data_model_key_check(self.model_data, parent_keys) + if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: + self.model_data['vxlan']['overlay'] = {'vrfs': []} + self.model_data['vxlan']['overlay'] = {'vrf_attach_groups': []} + self.model_data['vxlan']['overlay'] = {'networks': []} + self.model_data['vxlan']['overlay'] = {'network_attach_groups': []} + + # Check vxlan.overlay_services.vrfs list element + target_key = 'vrfs' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.overlay.vrf_attach_groups list element + target_key = 'vrf_attach_groups' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.overlay.vrf_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['overlay']['vrf_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # Check vxlan.overlay.networks list element + target_key = 'networks' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.overlay.network_attach_groups list element + target_key = 'network_attach_groups' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.overlay.network_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['overlay']['network_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['overlay']['network_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # -------------------------------------------------------------------- + # Fabric Overlay List Defaults - Backwards Compatibility + # -------------------------------------------------------------------- + # Check vxlan.overlay_services list elements parent_keys = ['vxlan', 'overlay_services'] dm_check = data_model_key_check(self.model_data, parent_keys) diff --git a/plugins/action/common/prepare_plugins/prep_101_fabric.py b/plugins/action/common/prepare_plugins/prep_101_fabric.py new file mode 100644 index 000000000..d87085e2c --- /dev/null +++ b/plugins/action/common/prepare_plugins/prep_101_fabric.py @@ -0,0 +1,109 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from ansible.utils.display import Display +from ....plugin_utils.helper_functions import data_model_key_check + +display = Display() + + +class PreparePlugin: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.keys = [] + + def prepare(self): + model_data = self.kwargs['results']['model_extended'] + + parent_keys = ['vxlan', 'fabric'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'fabric' in dm_check['keys_not_found'] or 'fabric' in dm_check['keys_no_data']: + display.deprecated( + "Attempting to use vxlan.global.name and vxlan.global.fabric_type due to vxlan.fabric.name and vxlan.fabric.type not being found. " + "vxlan.global.name and vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric." + ) + + # Prepare the data model to ensure vxlan.fabric.name is set + # global_data_check = False + # parent_keys = ['vxlan', 'global'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'global' in dm_check['keys_found'] and 'global' in dm_check['keys_data']: + # parent_keys = ['vxlan', 'global', 'name'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'name' in dm_check['keys_found'] and 'name' in dm_check['keys_data']: + # model_data['vxlan']['fabric']['name'] = model_data['vxlan']['global']['name'] + # else: + # global_data_check = True + + # parent_keys = ['vxlan', 'global', 'fabric_type'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'fabric_type' in dm_check['keys_found'] and 'fabric_type' in dm_check['keys_data']: + # model_data['vxlan']['fabric']['type'] = model_data['vxlan']['global']['fabric_type'] + # else: + # self.kwargs['results']['failed'] = True + # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." + # global_data_check = True + # else: + # self.kwargs['results']['failed'] = True + # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." + + # if global_data_check: + # self.kwargs['results']['failed'] = True + # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." + # else: + # parent_keys = ['vxlan', 'fabric', 'name'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'name' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: + # parent_keys = ['vxlan', 'global', 'name'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'name' in dm_check['keys_data']: + # # Insert warning about deprecation and where found + # model_data['vxlan']['fabric']['name'] = model_data['vxlan']['global']['name'] + # else: + # self.kwargs['results']['failed'] = True + # self.kwargs['results']['msg'] = "vxlan.fabric.name is not set in the model data." + + # # Prepare the data model to ensure vxlan.fabric.type is set + # parent_keys = ['vxlan', 'fabric', 'type'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'type' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: + # parent_keys = ['vxlan', 'global', 'fabric_type'] + # dm_check = data_model_key_check(model_data, parent_keys) + # if 'fabric_type' in dm_check['keys_data']: + # # Insert warning about deprecation and where found + # model_data['vxlan']['fabric']['type'] = model_data['vxlan']['global']['fabric_type'] + # else: + # self.kwargs['results']['failed'] = True + # self.kwargs['results']['msg'] = "vxlan.fabric.type is not set in the model data." + + # 1 - no fabric key data model + # 2a - fabric key data model with no data (i.e. no name or type) > semantic valdiation failure with schema + # 2b - fabric key data model with no data (i.e. name or type) > check if we have global name and global fabric_type + + + # insert comment to indicate this is a oneoff check for fabric key as this should really be done in a rule, + # but fabric name and key are foundational for the collection so we need to ensure it is set. + # this prepare plugin also helps retain backwards compatibility with the global fabric name and fabric_type keys previously used. + + # Prepare the data model to ensure vxlan.fabric.name is set + + self.kwargs['results']['model_extended'] = model_data + return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_101_global.py b/plugins/action/common/prepare_plugins/prep_101_global.py deleted file mode 100644 index 1a675eb17..000000000 --- a/plugins/action/common/prepare_plugins/prep_101_global.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - -class PreparePlugin: - def __init__(self, **kwargs): - self.kwargs = kwargs - self.keys = [] - - def prepare(self): - model_data = self.kwargs['results']['model_extended'] - self.kwargs['results']['model_extended'] = model_data - return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py index b71c952bb..e3bf2f221 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py @@ -29,6 +29,56 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] switches = model_data['vxlan']['topology']['switches'] + # Rebuild sm_data['vxlan']['overlay']['vrf_attach_groups'] into + # a structure that is easier to use. + vrf_grp_name_list = [] + model_data['vxlan']['overlay']['vrf_attach_groups_dict'] = {} + for grp in model_data['vxlan']['overlay']['vrf_attach_groups']: + model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] + vrf_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['hostname'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['hostname'] = found_switch['management']['management_ipv6_address'] + + # Remove vrf_attach_group from vrf if the group_name is not defined + for vrf in model_data['vxlan']['overlay']['vrfs']: + if 'vrf_attach_group' in vrf: + if vrf.get('vrf_attach_group') not in vrf_grp_name_list: + del vrf['vrf_attach_group'] + + # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into + # a structure that is easier to use. + net_grp_name_list = [] + model_data['vxlan']['overlay']['network_attach_groups_dict'] = {} + for grp in model_data['vxlan']['overlay']['network_attach_groups']: + model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']] = [] + net_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['hostname'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['hostname'] = found_switch['management']['management_ipv6_address'] + + # Remove network_attach_group from net if the group_name is not defined + for net in model_data['vxlan']['overlay']['networks']: + if 'network_attach_group' in net: + if net.get('network_attach_group') not in net_grp_name_list: + del net['network_attach_group'] + + # Backwards compatibility for vxlan.overlay_services + # Rebuild sm_data['vxlan']['overlay_services']['vrf_attach_groups'] into # a structure that is easier to use. vrf_grp_name_list = [] diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index d219dee4a..dda5ec0e9 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -21,12 +21,12 @@ --- -- name: Import Role Tasks for MSD Fabric - ansible.builtin.import_tasks: sub_main_msd.yml - tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric_type == 'MSD' - - name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' + +- name: Import Role Tasks for MSD Fabric + ansible.builtin.import_tasks: sub_main_msd.yml + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric_type == 'MSD' diff --git a/roles/dtc/common/tasks/ndfc_fabric.yml b/roles/dtc/common/tasks/ndfc_fabric.yml index 629a458bd..bbfdba87a 100644 --- a/roles/dtc/common/tasks/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/ndfc_fabric.yml @@ -33,6 +33,7 @@ {{ MD.vxlan.name }}_ndfc_fabric.yml {% elif MD.vxlan.global.name is defined and MD.vxlan.global.name %} {{ MD.vxlan.global.name }}_ndfc_fabric.yml + {% endif %} delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index 9029aa98e..dd01a62ab 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -38,7 +38,7 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.include_tasks: vxlan/ndfc_fabric.yml + ansible.builtin.include_tasks: ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index 51e478ed1..baf5aa264 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -3,17 +3,19 @@ {#- DO NOT EDIT MANUALLY #} {% set vxlan = MD_Extended.vxlan %} +{% if vxlan.global is defined %} {% set global = vxlan.global %} -{% set fabric_type = vxlan.global.fabric_type | default('VXLAN_EVPN') %} -{% if fabric_type == 'VXLAN_EVPN' or vxlan.fabric_type == 'VXLAN_EVPN' %} +{% endif %} +{% set fabric_type = vxlan.fabric_type | default('VXLAN_EVPN') %} +{% if fabric_type == 'VXLAN_EVPN' %} {# Include NDFC DC VXLAN EVPN Base Template #} {% include '/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2' %} -{% elif vxlan.fabric_type == 'MSD'%} +{% elif fabric_type == 'MSD'%} {# Include NDFC MSD Base Template #} -{% include '/ndfc_fabric/msd/msd_fabric_base.j2' %} +{% include '/ndfc_fabric/msd_fabric/msd_fabric_base.j2' %} {% else %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index ce09372fb..6b2c35843 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -7,13 +7,13 @@ L2_HOST_INTF_MTU: {{ vxlan.underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} {% if ndfc_version | cisco.nac_dc_vxlan.version_compare('12.2.2', '>=') %} - STP_ROOT_OPTION: {{ global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol) }} -{% if global.spanning_tree.root_bridge_protocol is defined and global.spanning_tree.root_bridge_protocol != 'unmanaged' %} -{% if (global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'rpvst+' %} - STP_VLAN_RANGE: {{ ndfc_utils.convert_ranges(global.spanning_tree.vlan_range, defaults.vxlan.global.spanning_tree.vlan_range) }} -{% elif (global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'mst' %} - MST_INSTANCE_RANGE: {{ ndfc_utils.convert_ranges(global.spanning_tree.mst_instance_range, defaults.vxlan.global.spanning_tree.mst_instance_range) }} + STP_ROOT_OPTION: {{ vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol) }} +{% if vxlan.global.spanning_tree.root_bridge_protocol is defined and global.spanning_tree.root_bridge_protocol != 'unmanaged' %} +{% if (vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'rpvst+' %} + STP_VLAN_RANGE: {{ ndfc_utils.convert_ranges(vxlan.global.spanning_tree.vlan_range, defaults.vxlan.global.spanning_tree.vlan_range) }} +{% elif (vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'mst' %} + MST_INSTANCE_RANGE: {{ ndfc_utils.convert_ranges(vxlan.global.spanning_tree.mst_instance_range, defaults.vxlan.global.spanning_tree.mst_instance_range) }} {% endif %} - STP_BRIDGE_PRIORITY: {{ global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} + STP_BRIDGE_PRIORITY: {{ vxlan.global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} {% endif %} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 index ef4f95fbd..fa2fd4e52 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 @@ -1,6 +1,6 @@ {# Auto-generated NDFC DC VXLAN EVPN Base config data structure for fabric {{ vxlan.global.name }} #} -- FABRIC_NAME: {{ global.name }} - FABRIC_TYPE: {{ fabric_type }} +- FABRIC_NAME: {{ vxlan.fabric.name }} + FABRIC_TYPE: {{ vxlan.fabric.type }} DEPLOY: True {# Include NDFC DC VXLAN EVPN General Template #} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index f90755d47..a80afd39e 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -21,16 +21,16 @@ --- +- name: Import MSD Role Tasks + ansible.builtin.import_tasks: sub_main_vxlan.yml + when: + - MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' + - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy + - name: Import VxLAN Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml when: MD_Extended.vxlan.fabric_type == 'MSD' -# - name: Import MSD Role Tasks -# ansible.builtin.import_tasks: sub_main_vxlan.yml -# when: -# - MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' -# - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy - - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: stage: role_create_completed diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index dfe2e5ad6..076326ad7 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -35,7 +35,8 @@ - name: Create NDFC MSD Fabric ansible.builtin.import_tasks: msd/fabric.yml when: - - MD_Extended.vxlan.multisite is defined + - MD_Extended.vxlan.name is defined + - MD_Extended.vxlan.fabric_type == "MSD" - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" diff --git a/roles/validate/files/rules/enhanced_rules/.gitkeep b/roles/validate/files/rules/common/.gitkeep similarity index 100% rename from roles/validate/files/rules/enhanced_rules/.gitkeep rename to roles/validate/files/rules/common/.gitkeep diff --git a/roles/validate/files/rules/required_rules/.gitkeep b/roles/validate/files/rules/multisite/.gitkeep similarity index 100% rename from roles/validate/files/rules/required_rules/.gitkeep rename to roles/validate/files/rules/multisite/.gitkeep diff --git a/roles/validate/files/rules/required_rules/vxlan/.gitkeep b/roles/validate/files/rules/required_rules/vxlan/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/roles/validate/files/rules/required_rules/msd/.gitkeep b/roles/validate/files/rules/vxlan/.gitkeep similarity index 100% rename from roles/validate/files/rules/required_rules/msd/.gitkeep rename to roles/validate/files/rules/vxlan/.gitkeep diff --git a/roles/validate/files/rules/required_rules/vxlan/201_global_spanning_tree.py b/roles/validate/files/rules/vxlan/201_global_spanning_tree.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/201_global_spanning_tree.py rename to roles/validate/files/rules/vxlan/201_global_spanning_tree.py diff --git a/roles/validate/files/rules/required_rules/vxlan/202_global_underlay_mcast_trm.py b/roles/validate/files/rules/vxlan/202_global_underlay_mcast_trm.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/202_global_underlay_mcast_trm.py rename to roles/validate/files/rules/vxlan/202_global_underlay_mcast_trm.py diff --git a/roles/validate/files/rules/required_rules/vxlan/203_global_underlay_isis.py b/roles/validate/files/rules/vxlan/203_global_underlay_isis.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/203_global_underlay_isis.py rename to roles/validate/files/rules/vxlan/203_global_underlay_isis.py diff --git a/roles/validate/files/rules/required_rules/vxlan/301_topology_switch_serial.py b/roles/validate/files/rules/vxlan/301_topology_switch_serial.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/301_topology_switch_serial.py rename to roles/validate/files/rules/vxlan/301_topology_switch_serial.py diff --git a/roles/validate/files/rules/required_rules/vxlan/302_topology_switch_management.py b/roles/validate/files/rules/vxlan/302_topology_switch_management.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/302_topology_switch_management.py rename to roles/validate/files/rules/vxlan/302_topology_switch_management.py diff --git a/roles/validate/files/rules/required_rules/vxlan/303_topology_switch_role.py b/roles/validate/files/rules/vxlan/303_topology_switch_role.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/303_topology_switch_role.py rename to roles/validate/files/rules/vxlan/303_topology_switch_role.py diff --git a/roles/validate/files/rules/required_rules/vxlan/304_topology_switch_interfaces_members_unique.py b/roles/validate/files/rules/vxlan/304_topology_switch_interfaces_members_unique.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/304_topology_switch_interfaces_members_unique.py rename to roles/validate/files/rules/vxlan/304_topology_switch_interfaces_members_unique.py diff --git a/roles/validate/files/rules/required_rules/vxlan/305_topology_switch_interfaces_vpc.py b/roles/validate/files/rules/vxlan/305_topology_switch_interfaces_vpc.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/305_topology_switch_interfaces_vpc.py rename to roles/validate/files/rules/vxlan/305_topology_switch_interfaces_vpc.py diff --git a/roles/validate/files/rules/required_rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py similarity index 65% rename from roles/validate/files/rules/required_rules/vxlan/401_overlay_services_cross_reference.py rename to roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py index a368d6ada..b4e0f9f79 100644 --- a/roles/validate/files/rules/required_rules/vxlan/401_overlay_services_cross_reference.py +++ b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py @@ -14,6 +14,12 @@ def match(cls, inventory): vrf_attach_groups = None switch_keys = ['vxlan', 'topology', 'switches'] + network_keys = ['vxlan', 'overlay', 'networks'] + vrf_keys = ['vxlan', 'overlay', 'vrfs'] + network_attach_keys = ['vxlan', 'overlay', 'network_attach_groups'] + vrf_attach_keys = ['vxlan', 'overlay', 'vrf_attach_groups'] + + # For backwards compatibility network_keys = ['vxlan', 'overlay_services', 'networks'] vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] @@ -46,6 +52,41 @@ def match(cls, inventory): # Ensure Network is not referencing a VRF that is not defined in the service model results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) + if sm_vrfs and vrf_attach_groups: + results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) + if sm_networks and network_attach_groups: + results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) + + # For backwards compatibility + sm_networks = None + sm_vrfs = None + network_attach_groups = None + vrf_attach_groups = None + + network_keys = ['vxlan', 'overlay_services', 'networks'] + vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] + network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] + vrf_attach_keys = ['vxlan', 'overlay_services', 'vrf_attach_groups'] + + check = cls.data_model_key_check(inventory, network_keys) + if 'networks' in check['keys_data']: + sm_networks = cls.safeget(inventory, network_keys) + + check = cls.data_model_key_check(inventory, vrf_keys) + if 'vrfs' in check['keys_data']: + sm_vrfs = cls.safeget(inventory, vrf_keys) + + check = cls.data_model_key_check(inventory, vrf_attach_keys) + if 'vrf_attach_groups' in check['keys_data']: + vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) + + check = cls.data_model_key_check(inventory, network_attach_keys) + if 'network_attach_groups' in check['keys_data']: + network_attach_groups = cls.safeget(inventory, network_attach_keys) + + # Ensure Network is not referencing a VRF that is not defined in the service model + results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) + if sm_vrfs and vrf_attach_groups: results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) if sm_networks and network_attach_groups: @@ -94,11 +135,11 @@ def cross_reference_vrfs_nets(cls, sm_vrfs, sm_networks, results): for net in sm_networks: if net.get("vrf_name") is not None: if net.get("vrf_name") not in vrf_names: - msg1 = "Network ({0}) is referencing VRF ({1})" - msg2 = " which is not defined in the service model. Add the VRF to the service model or remove the network from the service model" - results.append(msg1.format(net.get("name"), net.get("vrf_name"))) - results.append(msg2) - results.append(" and re-run the playbook") + results.append( + f"Network ({net.get('name')}) is referencing VRF ({net.get('vrf_name')}) " + "which is not defined in the service model. Add the VRF to the service model or remove the network from the service model " + "and re-run the playbook." + ) return results @@ -113,6 +154,6 @@ def cross_reference_switches(cls, attach_groups, switches, target, results): if not any(s.get('management').get('management_ipv6_address') == switch.get("hostname") for s in switches): ag = attach_group.get("name") hn = switch.get("hostname") - results.append("{0} attach group {1} hostname {2} does not match any switch in the topology".format(target, ag, hn)) + results.append(f"{target} attach group {ag} hostname {hn} does not match any switch in the topology.") return results diff --git a/roles/validate/files/rules/required_rules/vxlan/402_overlay_services_vrfs.py b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py similarity index 66% rename from roles/validate/files/rules/required_rules/vxlan/402_overlay_services_vrfs.py rename to roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py index 714bd98be..a64bc7bd0 100644 --- a/roles/validate/files/rules/required_rules/vxlan/402_overlay_services_vrfs.py +++ b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py @@ -19,16 +19,18 @@ def match(cls, inventory): if inventory["vxlan"].get("underlay").get("multicast", None): fabric_trm_status = inventory["vxlan"]["underlay"]["multicast"].get("trm_enable", False) - if inventory["vxlan"].get("overlay_services", None): - if inventory["vxlan"].get("overlay_services").get("vrfs", None): - vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] + if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): + if inventory["vxlan"].get("overlay").get("vrfs", None): + vrfs = inventory["vxlan"]["overlay"]["vrfs"] + elif inventory["vxlan"].get("overlay_services").get("vrfs", None): + vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] for vrf in vrfs: current_vrf_netflow_status = vrf.get("netflow_enable", None) if current_vrf_netflow_status is not None: if fabric_netflow_status is False and current_vrf_netflow_status is True: results.append( - f"For vxlan.overlay_services.vrfs.{vrf['name']}.netflow_enable to be enabled, " + f"For vxlan.overlay.vrfs.{vrf['name']}.netflow_enable to be enabled, " f"first vxlan.global.netflow.enable must be enabled (true)." ) break @@ -37,8 +39,8 @@ def match(cls, inventory): current_vrf_netflow_monitor = vrf.get("netflow_monitor", None) if current_vrf_netflow_monitor is None: results.append( - f"When vxlan.overlay_services.vrfs.{vrf['name']}.netflow_enable is enabled, " - f"then vxlan.overlay_services.vrfs.{vrf['name']}.netflow_monitor must be set " + f"When vxlan.overlay.vrfs.{vrf['name']}.netflow_enable is enabled, " + f"then vxlan.overlay.vrfs.{vrf['name']}.netflow_monitor must be set " "to a valid value from vxlan.global.netflow." ) break @@ -47,7 +49,7 @@ def match(cls, inventory): if current_vrf_trm_status is not None: if fabric_trm_status is False and current_vrf_trm_status is True: results.append( - f"For vxlan.overlay_services.vrfs.{vrf['name']}.trm_enable to be enabled, " + f"For vxlan.overlay.vrfs.{vrf['name']}.trm_enable to be enabled, " f"first vxlan.underlay.multicast.trm_enable must be enabled (true)." ) break @@ -62,8 +64,8 @@ def match(cls, inventory): if fabric_trm_status: if current_vrf_trm_no_rp and current_vrf_trm_underlay_mcast_ip is None: results.append( - f"When vxlan.overlay_services.vrfs.{vrf['name']}.no_rp is enabled (true), " - f"then vxlan.overlay_services.vrfs.{vrf['name']}.underlay_mcast_ip must be set." + f"When vxlan.overlay.vrfs.{vrf['name']}.no_rp is enabled (true), " + f"then vxlan.overlay.vrfs.{vrf['name']}.underlay_mcast_ip must be set." ) break @@ -72,27 +74,27 @@ def match(cls, inventory): current_vrf_trm_no_rp and current_vrf_trm_rp_loopback_id or current_vrf_trm_no_rp and current_vrf_trm_overlay_multicast_group): results.append( - f"When vxlan.overlay_services.vrfs.{vrf['name']}.no_rp is enabled (true), " - f"then vxlan.overlay_services.vrfs.{vrf['name']}.rp_external, " - f"vxlan.overlay_services.vrfs.{vrf['name']}.rp_address, " - f"vxlan.overlay_services.vrfs.{vrf['name']}.rp_loopback_id, " - f"vxlan.overlay_services.vrfs.{vrf['name']}.overlay_multicast_group must be disabled (false)." + f"When vxlan.overlay.vrfs.{vrf['name']}.no_rp is enabled (true), " + f"then vxlan.overlay.vrfs.{vrf['name']}.rp_external, " + f"vxlan.overlay.vrfs.{vrf['name']}.rp_address, " + f"vxlan.overlay.vrfs.{vrf['name']}.rp_loopback_id, " + f"vxlan.overlay.vrfs.{vrf['name']}.overlay_multicast_group must be disabled (false)." ) break if current_vrf_trm_rp_external and current_vrf_trm_rp_loopback_id: results.append( - f"When vxlan.overlay_services.vrfs.{vrf['name']}.rp_external is enabled (true), " - f"then vxlan.overlay_services.vrfs.{vrf['name']}.rp_loopback_id must be disabled (false)." + f"When vxlan.overlay.vrfs.{vrf['name']}.rp_external is enabled (true), " + f"then vxlan.overlay.vrfs.{vrf['name']}.rp_loopback_id must be disabled (false)." ) break if (current_vrf_trm_rp_external and current_vrf_trm_rp_address is None or current_vrf_trm_rp_external and current_vrf_trm_underlay_mcast_ip is None): results.append( - f"When vxlan.overlay_services.vrfs.{vrf['name']}.rp_external is enabled (true), " - f"then vxlan.overlay_services.vrfs.{vrf['name']}.rp_address and " - f"vxlan.overlay_services.vrfs.{vrf['name']}.underlay_mcast_ip must be set." + f"When vxlan.overlay.vrfs.{vrf['name']}.rp_external is enabled (true), " + f"then vxlan.overlay.vrfs.{vrf['name']}.rp_address and " + f"vxlan.overlay.vrfs.{vrf['name']}.underlay_mcast_ip must be set." ) break diff --git a/roles/validate/files/rules/required_rules/vxlan/403_overlay_services_networks.py b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py similarity index 74% rename from roles/validate/files/rules/required_rules/vxlan/403_overlay_services_networks.py rename to roles/validate/files/rules/vxlan/403_overlay_services_networks.py index 1c2e27b08..97348cd94 100644 --- a/roles/validate/files/rules/required_rules/vxlan/403_overlay_services_networks.py +++ b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py @@ -21,8 +21,10 @@ def match(cls, inventory): fabric_trm_status = inventory["vxlan"]["underlay"]["multicast"].get("trm_enable", False) if inventory.get("vxlan", None): - if inventory["vxlan"].get("overlay_services", None): - if inventory["vxlan"].get("overlay_services").get("networks", None): + if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): + if inventory["vxlan"].get("overlay").get("networks", None): + networks = inventory["vxlan"]["overlay"]["networks"] + elif inventory["vxlan"].get("overlay_services").get("networks", None): networks = inventory["vxlan"]["overlay_services"]["networks"] for network in networks: @@ -30,7 +32,7 @@ def match(cls, inventory): if current_network_netflow_status is not None: if fabric_netflow_status is False and current_network_netflow_status is True: results.append( - f"For vxlan.overlay_services.networks.{network['name']}.netflow_enable to be enabled, " + f"For vxlan.overlay.networks.{network['name']}.netflow_enable to be enabled, " f"first vxlan.global.netflow.enable must be enabled (true)." ) break @@ -39,8 +41,8 @@ def match(cls, inventory): current_network_netflow_monitor = network.get("vlan_netflow_monitor", None) if current_network_netflow_monitor is None: results.append( - f"When vxlan.overlay_services.networks.{network['name']}.netflow_enable is enabled, " - f"then vxlan.overlay_services.networks.{network['name']}.vlan_netflow_monitor must be set " + f"When vxlan.overlay.networks.{network['name']}.netflow_enable is enabled, " + f"then vxlan.overlay.networks.{network['name']}.vlan_netflow_monitor must be set " "to a valid value from vxlan.global.netflow." ) break @@ -49,7 +51,7 @@ def match(cls, inventory): if current_network_trm_status is not None: if fabric_trm_status is False and current_network_trm_status is True: results.append( - f"For vxlan.overlay_services.networks.{network['name']}.trm_enable to be enabled, " + f"For vxlan.overlay.networks.{network['name']}.trm_enable to be enabled, " f"first vxlan.underlay.multicast.trm_enable must be enabled (true)." ) break diff --git a/roles/validate/files/rules/required_rules/vxlan/501_policy_cross_reference.py b/roles/validate/files/rules/vxlan/501_policy_cross_reference.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/501_policy_cross_reference.py rename to roles/validate/files/rules/vxlan/501_policy_cross_reference.py diff --git a/roles/validate/files/rules/required_rules/vxlan/502_policy_vrf_lite_cross_reference.py b/roles/validate/files/rules/vxlan/502_policy_vrf_lite_cross_reference.py similarity index 100% rename from roles/validate/files/rules/required_rules/vxlan/502_policy_vrf_lite_cross_reference.py rename to roles/validate/files/rules/vxlan/502_policy_vrf_lite_cross_reference.py diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index db816574c..9d6e722c5 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -22,19 +22,9 @@ --- - debug: msg="{{ nac_tags.all }}" -- name: Import Common Pre Role Tasks - ansible.builtin.import_tasks: sub_main_common_pre.yml +- name: Import Role Tasks + ansible.builtin.import_tasks: sub_main.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml - -- name: Import MSD Fabric Role Tasks - ansible.builtin.import_tasks: sub_main_msd.yml - tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric_type == 'MSD' - -- name: Import VxLAN Fabric Role Tasks - ansible.builtin.import_tasks: sub_main_vxlan.yml - tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' # Problems with lower versions of python and ansible # Python 3.9.16 and Ansible 7.3.0 (Ansible-Core 2.14.4) # Could ignore errors and try again with tags specified as below as a work around ... @@ -57,16 +47,8 @@ # - role_deploy # - role_remove -- name: Import Common Post Role Tasks - ansible.builtin.import_tasks: sub_main_common_post.yml - tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml - - name: Mark Stage Role Validate Completed cisco.nac_dc_vxlan.common.run_map: stage: role_validate_completed register: run_map delegate_to: localhost - -- debug: msg="{{ MD }}" - -- debug: msg="{{ MD_Extended }}" \ No newline at end of file diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml new file mode 100644 index 000000000..1d251656b --- /dev/null +++ b/roles/validate/tasks/sub_main.yml @@ -0,0 +1,152 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.validate] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" + - "----------------------------------------------------------------" + +- ansible.builtin.debug: msg="Role Path - {{ role_path }}" + +- ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" + +- name: Validate NDFC Service Model Data + ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" + +- ansible.builtin.debug: msg="Workflow is Direct to Device (DTD)" + when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.nxos.nxos" + +- ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" + when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" + +- name: Check for Schema Path Being Defined + ansible.builtin.set_fact: + schema_path: '' + when: schema_path is not defined + delegate_to: localhost + +- name: Check for Enhanced Roles Path Being Defined + ansible.builtin.set_fact: + enhanced_rules_path: '' + when: enhanced_rules_path is not defined + delegate_to: localhost + +- name: Perform Required Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ rules_path }}" + register: model_data + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + rules_path: "{{ role_path }}/files/rules/" + delegate_to: localhost + +- name: Perform Custom Enhanced Syntax and Semantic Model Validation + cisco.nac_dc_vxlan.common.nac_dc_validate: + schema: "{{ schema_path }}" + mdata: "{{ data_path }}" + rules: "{{ enhanced_rules_path }}" + vars: + data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + when: enhanced_rules_path is defined and enhanced_rules_path + delegate_to: localhost + +- name: Stat Factory Defaults + ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" + register: factory_defaults_file + delegate_to: localhost + +- name: Include Factory Defaults if Available + ansible.builtin.include_vars: + file: "{{ role_path }}/files/defaults.yml" + when: factory_defaults_file.stat.exists + delegate_to: localhost + +- name: Merge factory and custom defaults + cisco.nac_dc_vxlan.common.merge_defaults: + factory_defaults: "{{ factory_defaults }}" + model_data: "{{ model_data['data'] }}" + register: defaults + delegate_to: localhost + +- name: Register Variable With Only Defaults from Previous Task + ansible.builtin.set_fact: + defaults: "{{ defaults['defaults'] }}" + delegate_to: localhost + +- name: Prepare Service Model + cisco.nac_dc_vxlan.common.prepare_service_model: + inventory_hostname: "{{ inventory_hostname }}" + hostvars: "{{ hostvars }}" + model_data: "{{ model_data['data'] }}" + default_values: "{{ defaults }}" + templates_path: "{{ role_path }}/../dtc/common/templates/" + register: smd + delegate_to: localhost + +- ansible.builtin.meta: end_play + +- name: Store Golden Service Model Data + ansible.builtin.set_fact: + MD: "{{ smd['model_golden'] }}" + delegate_to: localhost + +- name: Store Extended Service Model Data + ansible.builtin.set_fact: + MD_Extended: "{{ smd['model_extended'] }}" + delegate_to: localhost + +- name: Check Roles + cisco.nac_dc_vxlan.common.check_roles: + role_list: "{{ role_names }}" + register: check_roles + delegate_to: localhost + +- name: Read Run Map From Previous Run + cisco.nac_dc_vxlan.common.read_run_map: + model_data: "{{ MD_Extended }}" + register: run_map_read_result + delegate_to: localhost + +- name: Debug Run Map Read Result + ansible.builtin.debug: + msg: "{{ run_map_read_result }}" + delegate_to: localhost + +- name: Initialize Run Map + cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" + stage: starting_execution + register: run_map + delegate_to: localhost + +- name: Manage Previous Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_previous.yml + when: check_roles['save_previous'] + +- name: Manage Current Service Model Data Files + ansible.builtin.include_tasks: manage_model_files_current.yml + when: check_roles['save_previous'] diff --git a/roles/validate/tasks/sub_main_vxlan.yml b/roles/validate/tasks/sub_main_vxlan.yml index c14bef235..75c64515c 100644 --- a/roles/validate/tasks/sub_main_vxlan.yml +++ b/roles/validate/tasks/sub_main_vxlan.yml @@ -28,5 +28,5 @@ rules: "{{ rules_path }}" vars: data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/required_rules/vxlan/" + rules_path: "{{ role_path }}/files/rules/" delegate_to: localhost From f8217798e120adc3f36d6c465a1407dadd99877c Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 4 Dec 2024 22:19:46 -0500 Subject: [PATCH 016/183] updates for build and deployment of both single fabrics and msd fabrics --- .../common/prepare_plugins/prep_101_fabric.py | 117 +++++++++--------- .../prep_104_fabric_overlay_services.py | 12 +- plugins/action/common/read_run_map.py | 4 +- plugins/action/common/run_map.py | 5 +- roles/dtc/common/tasks/main.yml | 4 +- .../common/tasks/{ => msd}/ndfc_fabric.yml | 8 +- roles/dtc/common/tasks/sub_main_msd.yml | 2 +- roles/dtc/common/tasks/sub_main_vxlan.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_fabric.yml | 77 ++++++++++++ .../common/templates/ndfc_attach_networks.j2 | 34 +++-- .../dtc/common/templates/ndfc_attach_vrfs.j2 | 46 ++++--- roles/dtc/common/templates/ndfc_fabric.j2 | 8 +- .../advanced/dc_vxlan_fabric_advanced.j2 | 4 +- .../bootstrap/dc_vxlan_fabric_bootstrap.j2 | 26 ++-- .../dc_vxlan_fabric/dc_vxlan_fabric_base.j2 | 2 +- .../dc_vxlan_fabric_flow_monitor.j2 | 18 +-- .../general/dc_vxlan_fabric_general.j2 | 8 +- .../dc_vxlan_fabric_manageability.j2 | 14 +-- .../protocols/dc_vxlan_fabric_protocols.j2 | 2 +- .../dc_vxlan_fabric_replication.j2 | 2 +- .../resources/dc_vxlan_fabric_resources.j2 | 2 +- .../security/dc_vxlan_fabric_security.j2 | 2 +- .../vpc/dc_vxlan_fabric_vpc.j2 | 22 ++-- .../msd_fabric/dci/msd_fabric_dci.j2 | 2 +- .../msd_fabric/general/msd_fabric_general.j2 | 4 +- .../ndfc_fabric/msd_fabric/msd_fabric_base.j2 | 4 +- .../resources/msd_fabric_resources.j2 | 2 +- .../security/msd_fabric_security.j2 | 2 +- .../templates/ndfc_links_vpc_peering.j2 | 2 +- roles/dtc/create/tasks/main.yml | 9 +- roles/dtc/create/tasks/msd/child_fabrics.yml | 6 +- roles/dtc/create/tasks/msd/fabric.yml | 4 +- roles/dtc/create/tasks/sub_main_msd.yml | 4 +- roles/dtc/create/tasks/sub_main_vxlan.yml | 2 + roles/dtc/create/tasks/vxlan/devices.yml | 2 +- .../create/tasks/vxlan/devices_discovery.yml | 4 +- roles/dtc/create/tasks/vxlan/fabric.yml | 4 +- roles/dtc/create/tasks/vxlan/interfaces.yml | 20 +-- roles/dtc/create/tasks/vxlan/policies.yml | 4 +- roles/dtc/create/tasks/vxlan/vpc_peering.yml | 6 +- .../dtc/create/tasks/vxlan/vrfs_networks.yml | 6 +- roles/dtc/deploy/tasks/main.yml | 1 + roles/dtc/deploy/tasks/sub_main.yml | 8 +- roles/dtc/remove/tasks/main.yml | 14 ++- roles/dtc/remove/tasks/msd/.gitkeep | 0 .../tasks/sub_main_msd.yml} | 9 -- .../{sub_main.yml => sub_main_vxlan.yml} | 16 +-- roles/dtc/remove/tasks/vxlan/.gitkeep | 0 .../remove/tasks/{ => vxlan}/interfaces.yml | 2 +- roles/dtc/remove/tasks/{ => vxlan}/links.yml | 2 +- .../dtc/remove/tasks/{ => vxlan}/networks.yml | 2 +- roles/dtc/remove/tasks/{ => vxlan}/policy.yml | 2 +- .../dtc/remove/tasks/{ => vxlan}/switches.yml | 2 +- .../remove/tasks/{ => vxlan}/vpc_peers.yml | 2 +- roles/dtc/remove/tasks/{ => vxlan}/vrfs.yml | 2 +- roles/validate/files/defaults.yml | 2 +- roles/validate/tasks/main.yml | 1 + .../tasks/manage_model_files_current.yml | 6 +- .../tasks/manage_model_files_previous.yml | 10 +- roles/validate/tasks/sub_main.yml | 2 - roles/validate/tasks/sub_main_common_post.yml | 54 -------- roles/validate/tasks/sub_main_common_pre.yml | 90 -------------- roles/validate/tasks/sub_main_msd.yml | 32 ----- roles/validate/tasks/sub_main_vxlan.yml | 32 ----- 64 files changed, 338 insertions(+), 461 deletions(-) rename roles/dtc/common/tasks/{ => msd}/ndfc_fabric.yml (90%) create mode 100644 roles/dtc/common/tasks/vxlan/ndfc_fabric.yml create mode 100644 roles/dtc/remove/tasks/msd/.gitkeep rename roles/dtc/{create/tasks/vxlan/reset.yml => remove/tasks/sub_main_msd.yml} (79%) rename roles/dtc/remove/tasks/{sub_main.yml => sub_main_vxlan.yml} (86%) create mode 100644 roles/dtc/remove/tasks/vxlan/.gitkeep rename roles/dtc/remove/tasks/{ => vxlan}/interfaces.yml (98%) rename roles/dtc/remove/tasks/{ => vxlan}/links.yml (96%) rename roles/dtc/remove/tasks/{ => vxlan}/networks.yml (97%) rename roles/dtc/remove/tasks/{ => vxlan}/policy.yml (98%) rename roles/dtc/remove/tasks/{ => vxlan}/switches.yml (97%) rename roles/dtc/remove/tasks/{ => vxlan}/vpc_peers.yml (97%) rename roles/dtc/remove/tasks/{ => vxlan}/vrfs.yml (97%) delete mode 100644 roles/validate/tasks/sub_main_common_post.yml delete mode 100644 roles/validate/tasks/sub_main_common_pre.yml delete mode 100644 roles/validate/tasks/sub_main_msd.yml delete mode 100644 roles/validate/tasks/sub_main_vxlan.yml diff --git a/plugins/action/common/prepare_plugins/prep_101_fabric.py b/plugins/action/common/prepare_plugins/prep_101_fabric.py index d87085e2c..e1dce5c4d 100644 --- a/plugins/action/common/prepare_plugins/prep_101_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_101_fabric.py @@ -33,77 +33,72 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] + # Checking for fabric key in the data model. + # This type of check should be done in a rule, but fabric.name and fabric.type are foundational for the collection so we need to ensure it is set. + # This prepare plugin also helps retain backwards compatibility with global.name and global.fabric_type keys previously used. parent_keys = ['vxlan', 'fabric'] dm_check = data_model_key_check(model_data, parent_keys) if 'fabric' in dm_check['keys_not_found'] or 'fabric' in dm_check['keys_no_data']: display.deprecated( - "Attempting to use vxlan.global.name and vxlan.global.fabric_type due to vxlan.fabric.name and vxlan.fabric.type not being found. " + "Attempting to use vxlan.global.name and vxlan.global.fabric_type due to vxlan.fabric.name and vxlan.fabric.type not being defined. " "vxlan.global.name and vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric." ) - # Prepare the data model to ensure vxlan.fabric.name is set - # global_data_check = False - # parent_keys = ['vxlan', 'global'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'global' in dm_check['keys_found'] and 'global' in dm_check['keys_data']: - # parent_keys = ['vxlan', 'global', 'name'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'name' in dm_check['keys_found'] and 'name' in dm_check['keys_data']: - # model_data['vxlan']['fabric']['name'] = model_data['vxlan']['global']['name'] - # else: - # global_data_check = True - - # parent_keys = ['vxlan', 'global', 'fabric_type'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'fabric_type' in dm_check['keys_found'] and 'fabric_type' in dm_check['keys_data']: - # model_data['vxlan']['fabric']['type'] = model_data['vxlan']['global']['fabric_type'] - # else: - # self.kwargs['results']['failed'] = True - # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." - # global_data_check = True - # else: - # self.kwargs['results']['failed'] = True - # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." - - # if global_data_check: - # self.kwargs['results']['failed'] = True - # self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." - # else: - # parent_keys = ['vxlan', 'fabric', 'name'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'name' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: - # parent_keys = ['vxlan', 'global', 'name'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'name' in dm_check['keys_data']: - # # Insert warning about deprecation and where found - # model_data['vxlan']['fabric']['name'] = model_data['vxlan']['global']['name'] - # else: - # self.kwargs['results']['failed'] = True - # self.kwargs['results']['msg'] = "vxlan.fabric.name is not set in the model data." + parent_keys = ['vxlan', 'global'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'global' in dm_check['keys_found'] and 'global' in dm_check['keys_data']: + model_data['vxlan'].update({'fabric': {}}) + parent_keys = ['vxlan', 'global', 'name'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'name' in dm_check['keys_found'] and 'name' in dm_check['keys_data']: + model_data['vxlan']['fabric'].update({'name': model_data['vxlan']['global']['name']}) + else: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = "vxlan.global.name is not defined in the data model. Please set vxlan.fabric.name." - # # Prepare the data model to ensure vxlan.fabric.type is set - # parent_keys = ['vxlan', 'fabric', 'type'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'type' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: - # parent_keys = ['vxlan', 'global', 'fabric_type'] - # dm_check = data_model_key_check(model_data, parent_keys) - # if 'fabric_type' in dm_check['keys_data']: - # # Insert warning about deprecation and where found - # model_data['vxlan']['fabric']['type'] = model_data['vxlan']['global']['fabric_type'] - # else: - # self.kwargs['results']['failed'] = True - # self.kwargs['results']['msg'] = "vxlan.fabric.type is not set in the model data." + parent_keys = ['vxlan', 'global', 'fabric_type'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'fabric_type' in dm_check['keys_found'] and 'fabric_type' in dm_check['keys_data']: + model_data['vxlan']['fabric'].update({'type': model_data['vxlan']['global']['fabric_type']}) + else: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = "vxlan.global.fabric_type is not defined in the data model. Please set vxlan.fabric.type." + else: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = "vxlan.fabric is not set in the model data." - # 1 - no fabric key data model - # 2a - fabric key data model with no data (i.e. no name or type) > semantic valdiation failure with schema - # 2b - fabric key data model with no data (i.e. name or type) > check if we have global name and global fabric_type - - - # insert comment to indicate this is a oneoff check for fabric key as this should really be done in a rule, - # but fabric name and key are foundational for the collection so we need to ensure it is set. - # this prepare plugin also helps retain backwards compatibility with the global fabric name and fabric_type keys previously used. + else: + # Prepare the data model to ensure vxlan.fabric.name is set + parent_keys = ['vxlan', 'fabric', 'name'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'name' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: + display.deprecated( + "Attempting to use vxlan.global.name due to vxlan.fabric.name not being defined. " + "vxlan.global.name is being deprecated. Please use vxlan.fabric." + ) + parent_keys = ['vxlan', 'global', 'name'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'name' in dm_check['keys_data']: + model_data['vxlan']['fabric'].update({'name': model_data['vxlan']['global']['name']}) + else: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = "vxlan.fabric.name is not defined in the data model." - # Prepare the data model to ensure vxlan.fabric.name is set + # Prepare the data model to ensure vxlan.fabric.type is set + parent_keys = ['vxlan', 'fabric', 'type'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'type' in dm_check['keys_no_data'] or 'type' in dm_check['keys_not_found']: + display.deprecated( + "Attempting to use vxlan.global.type due to vxlan.fabric.type not being defined. " + "vxlan.global.type is being deprecated. Please use vxlan.fabric." + ) + parent_keys = ['vxlan', 'global', 'fabric_type'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'fabric_type' in dm_check['keys_data']: + model_data['vxlan']['fabric'].update({'type': model_data['vxlan']['global']['fabric_type']}) + else: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = "vxlan.fabric.type is not defined in the data model." self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py index ba0c320cf..0fad465c9 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py @@ -43,9 +43,9 @@ def prepare(self): if any(sw['name'] == switch['hostname'] for sw in switches): found_switch = next((item for item in switches if item["name"] == switch['hostname'])) if found_switch.get('management').get('management_ipv4_address'): - switch['hostname'] = found_switch['management']['management_ipv4_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] elif found_switch.get('management').get('management_ipv6_address'): - switch['hostname'] = found_switch['management']['management_ipv6_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] # Remove vrf_attach_group from vrf if the group_name is not defined for vrf in model_data['vxlan']['overlay']['vrfs']: @@ -67,9 +67,9 @@ def prepare(self): if any(sw['name'] == switch['hostname'] for sw in switches): found_switch = next((item for item in switches if item["name"] == switch['hostname'])) if found_switch.get('management').get('management_ipv4_address'): - switch['hostname'] = found_switch['management']['management_ipv4_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] elif found_switch.get('management').get('management_ipv6_address'): - switch['hostname'] = found_switch['management']['management_ipv6_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] # Remove network_attach_group from net if the group_name is not defined for net in model_data['vxlan']['overlay']['networks']: @@ -93,9 +93,9 @@ def prepare(self): if any(sw['name'] == switch['hostname'] for sw in switches): found_switch = next((item for item in switches if item["name"] == switch['hostname'])) if found_switch.get('management').get('management_ipv4_address'): - switch['hostname'] = found_switch['management']['management_ipv4_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] elif found_switch.get('management').get('management_ipv6_address'): - switch['hostname'] = found_switch['management']['management_ipv6_address'] + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] # Remove vrf_attach_group from vrf if the group_name is not defined for vrf in model_data['vxlan']['overlay_services']['vrfs']: diff --git a/plugins/action/common/read_run_map.py b/plugins/action/common/read_run_map.py index b7c244483..6f3de7b40 100644 --- a/plugins/action/common/read_run_map.py +++ b/plugins/action/common/read_run_map.py @@ -39,8 +39,8 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['diff_run'] = True - model_data = task_vars['model_data']['data'] - fabric_name = model_data["vxlan"]["name"] + model_data = self._task.args.get('model_data') + fabric_name = model_data['vxlan']['fabric']['name'] if 'dtc' in task_vars['role_path']: common_role_path = os.path.dirname(task_vars['role_path']) diff --git a/plugins/action/common/run_map.py b/plugins/action/common/run_map.py index 0d4a7f7ee..a8460f475 100644 --- a/plugins/action/common/run_map.py +++ b/plugins/action/common/run_map.py @@ -41,9 +41,10 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False - model_data = task_vars['model_data']['data'] + model_data = self._task.args.get('model_data') stage = self._task.args['stage'] - fabric_name = model_data["vxlan"]["name"] + + fabric_name = model_data['vxlan']['fabric']['name'] if 'dtc' in task_vars['role_path']: common_role_path = os.path.dirname(task_vars['role_path']) diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index dda5ec0e9..67293f417 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -24,9 +24,9 @@ - name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' + when: MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' - name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric_type == 'MSD' + when: MD_Extended.vxlan.fabric.type == 'MSD' diff --git a/roles/dtc/common/tasks/ndfc_fabric.yml b/roles/dtc/common/tasks/msd/ndfc_fabric.yml similarity index 90% rename from roles/dtc/common/tasks/ndfc_fabric.yml rename to roles/dtc/common/tasks/msd/ndfc_fabric.yml index bbfdba87a..a6ed2eeae 100644 --- a/roles/dtc/common/tasks/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/msd/ndfc_fabric.yml @@ -28,12 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: >- - {% if MD.vxlan.name is defined and MD.vxlan.name %} - {{ MD.vxlan.name }}_ndfc_fabric.yml - {% elif MD.vxlan.global.name is defined and MD.vxlan.global.name %} - {{ MD.vxlan.global.name }}_ndfc_fabric.yml - {% endif %} + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" delegate_to: localhost - name: Stat Previous File If It Exists @@ -64,7 +59,6 @@ - ansible.builtin.set_fact: fabric_config: "{{ lookup('file', file_name) | from_yaml }}" - when: MD.vxlan.global or MD.vxlan.multisite delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 74306c00f..4796d44f2 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -38,7 +38,7 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.include_tasks: ndfc_fabric.yml + ansible.builtin.include_tasks: msd/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Child Fabric Inventory List From Template diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index dd01a62ab..9029aa98e 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -38,7 +38,7 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.include_tasks: ndfc_fabric.yml + ansible.builtin.include_tasks: vxlan/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template diff --git a/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml new file mode 100644 index 000000000..a6ed2eeae --- /dev/null +++ b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml @@ -0,0 +1,77 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/templates/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_attach_networks.j2 index 4be242a0d..96742c991 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks.j2 @@ -2,12 +2,17 @@ # This NDFC networks and switch attachments config data structure is auto-generated # DO NOT EDIT MANUALLY # -{% for net in MD_Extended.vxlan.overlay_services.networks %} +{% if MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks %} +{% set networks = MD_Extended.vxlan.overlay.networks %} +{% elif MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks %} +{% set networks = MD_Extended.vxlan.overlay_services.networks %} +{% endif %} +{% for net in networks %} - net_name: {{ net['name'] }} {# ------------------------------------------------------ #} {# Properties Section #} {# ------------------------------------------------------ #} - is_l2only: {{ net['is_l2_only'] | default(defaults.vxlan.overlay_services.networks.is_l2_only) }} + is_l2only: {{ net['is_l2_only'] | default(defaults.vxlan.overlay.networks.is_l2_only) }} vrf_name: {{ net['vrf_name'] | default(omit) }} net_id: {{ net['net_id'] | default(omit) }} vlan_id: {{ net['vlan_id'] | default(omit) }} @@ -30,7 +35,7 @@ secondary_ip_gw4: {{ net['secondary_ip_addresses'][3]['ip_address'] }} {% endif %} {% endif %} - arp_suppress: {{ net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress) }} + arp_suppress: {{ net['arp_suppress'] | default(defaults.vxlan.overlay.networks.arp_supress) }} dhcp_loopback_id: {{ net['dhcp_loopback_id'] | default(omit) }} {% if net.dhcp_servers is defined %} {% if net.dhcp_servers | length == 1 %} @@ -51,25 +56,30 @@ {% endif %} {% endif %} gw_ipv6_subnet: {{ net['gw_ipv6_address'] | default(omit) }} - int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay_services.networks.net_description) }} - l3gw_on_border: {{ net['l3gw_on_border'] | default(defaults.vxlan.overlay_services.networks.l3gw_on_border) }} - mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay_services.networks.mtu_l3intf) }} + int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay.networks.net_description) }} + l3gw_on_border: {{ net['l3gw_on_border'] | default(defaults.vxlan.overlay.networks.l3gw_on_border) }} + mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay.networks.mtu_l3intf) }} {% if (MD.vxlan.underlay.general.replication_mode | lower) == 'multicast' %} - multicast_group_address: {{ net['multicast_group_address'] | default(defaults.vxlan.overlay_services.networks.multicast_group_address) }} + multicast_group_address: {{ net['multicast_group_address'] | default(defaults.vxlan.overlay.networks.multicast_group_address) }} {% endif %} - netflow_enable: {{ net['netflow_enable'] | default(defaults.vxlan.overlay_services.networks.netflow_enable) }} + netflow_enable: {{ net['netflow_enable'] | default(defaults.vxlan.overlay.networks.netflow_enable) }} {% if net['netflow_enable'] is defined and net['netflow_enable'] | bool %} vlan_nf_monitor: {{ net['vlan_netflow_monitor'] | default(omit) }} {% endif %} - route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay_services.networks.route_target_both) }} - route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay_services.networks.route_tag) }} - trm_enable: {{ net['trm_enable'] | default(defaults.vxlan.overlay_services.networks.trm_enable) }} + route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay.networks.route_target_both) }} + route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} + trm_enable: {{ net['trm_enable'] | default(defaults.vxlan.overlay.networks.trm_enable) }} {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} {% if net['network_attach_group'] is defined %} attach: -{% for attach in MD_Extended.vxlan.overlay_services.network_attach_groups_dict[net['network_attach_group']] %} +{% if MD_Extended.vxlan.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay.network_attach_groups_dict %} +{% set network_attach_groups_dict = MD_Extended.vxlan.overlay.network_attach_groups_dict %} +{% elif MD_Extended.vxlan.overlay_services.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} +{% set network_attach_groups_dict = MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} +{% endif %} +{% for attach in network_attach_groups_dict[net['network_attach_group']] %} - ip_address: {{ attach['mgmt_ip_address'] }} ports: {{ attach['ports'] }} {% endfor %} diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index c3c1dc425..d3d40fa62 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -2,7 +2,12 @@ # This NDFC VRFs and switch attachments config data structure is auto-generated # DO NOT EDIT MANUALLY # -{% for vrf in MD_Extended.vxlan.overlay_services.vrfs %} +{% if MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs %} +{% set vrfs = MD_Extended.vxlan.overlay.vrfs %} +{% elif MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs %} +{% set vrfs = MD_Extended.vxlan.overlay_services.vrfs %} +{% endif %} +{% for vrf in vrfs %} - vrf_name: {{ vrf['name'] }} {# ------------------------------------------------------ #} {# Properties Section #} @@ -10,46 +15,51 @@ vrf_id: {{ vrf['vrf_id'] | default(omit) }} vlan_id: {{ vrf['vlan_id'] | default(omit) }} vrf_vlan_name: {{ vrf['vrf_vlan_name'] | default(omit) }} - vrf_intf_desc: {{ vrf['vrf_intf_desc'] | default(defaults.vxlan.overlay_services.vrfs.vrf_intf_desc) }} - vrf_description: {{ vrf['vrf_description'] | default(defaults.vxlan.overlay_services.vrfs.vrf_description) }} - vrf_int_mtu: {{ vrf['vrf_int_mtu'] | default(defaults.vxlan.overlay_services.vrfs.vrf_int_mtu) }} - loopback_route_tag: {{ vrf['loopback_route_tag'] | default(defaults.vxlan.overlay_services.vrfs.loopback_route_tag) }} - max_bgp_paths: {{ vrf['max_bgp_paths'] | default(defaults.vxlan.overlay_services.vrfs.max_bgp_paths) }} - max_ibgp_paths: {{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay_services.vrfs.max_ibgp_paths) }} - ipv6_linklocal_enable: {{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay_services.vrfs.ipv6_linklocal_enable) }} - adv_host_routes: {{ vrf['adv_host_routes'] | default(defaults.vxlan.overlay_services.vrfs.adv_host_routes) }} - adv_default_routes: {{ vrf['adv_default_routes'] | default(defaults.vxlan.overlay_services.vrfs.adv_default_routes) }} - static_default_route: {{ vrf['static_default_route'] | default(defaults.vxlan.overlay_services.vrfs.static_default_route) }} + vrf_intf_desc: {{ vrf['vrf_intf_desc'] | default(defaults.vxlan.overlay.vrfs.vrf_intf_desc) }} + vrf_description: {{ vrf['vrf_description'] | default(defaults.vxlan.overlay.vrfs.vrf_description) }} + vrf_int_mtu: {{ vrf['vrf_int_mtu'] | default(defaults.vxlan.overlay.vrfs.vrf_int_mtu) }} + loopback_route_tag: {{ vrf['loopback_route_tag'] | default(defaults.vxlan.overlay.vrfs.loopback_route_tag) }} + max_bgp_paths: {{ vrf['max_bgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_bgp_paths) }} + max_ibgp_paths: {{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_ibgp_paths) }} + ipv6_linklocal_enable: {{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay.vrfs.ipv6_linklocal_enable) }} + adv_host_routes: {{ vrf['adv_host_routes'] | default(defaults.vxlan.overlay.vrfs.adv_host_routes) }} + adv_default_routes: {{ vrf['adv_default_routes'] | default(defaults.vxlan.overlay.vrfs.adv_default_routes) }} + static_default_route: {{ vrf['static_default_route'] | default(defaults.vxlan.overlay.vrfs.static_default_route) }} bgp_password: {{ vrf['bgp_password'] | default(omit) }} bgp_password_encryption_type: {{ vrf['bgp_password_encryption_type'] | default(omit) }} - disable_rt_auto: {{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay_services.vrfs.disable_rt_auto) }} + disable_rt_auto: {{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay.vrfs.disable_rt_auto) }} export_evpn_rt: {{ vrf['export_evpn_rt'] | default(omit) }} export_mvpn_rt: {{ vrf['export_mvpn_rt'] | default(omit) }} export_vpn_rt: {{ vrf['export_vpn_rt'] | default(omit) }} import_evpn_rt: {{ vrf['import_evpn_rt'] | default(omit) }} import_mvpn_rt: {{ vrf['import_mvpn_rt'] | default(omit) }} import_vpn_rt: {{ vrf['import_vpn_rt'] | default(omit) }} - netflow_enable: {{ vrf['netflow_enable'] | default(defaults.vxlan.overlay_services.vrfs.netflow_enable) }} + netflow_enable: {{ vrf['netflow_enable'] | default(defaults.vxlan.overlay.vrfs.netflow_enable) }} {% if vrf['netflow_enable'] is defined and vrf['netflow_enable'] | bool %} nf_monitor: {{ vrf['netflow_monitor'] }} {% endif %} - no_rp: {{ vrf['no_rp'] | default(defaults.vxlan.overlay_services.vrfs.no_rp) }} - trm_enable: {{ vrf['trm_enable'] | default(defaults.vxlan.overlay_services.vrfs.trm_enable) }} + no_rp: {{ vrf['no_rp'] | default(defaults.vxlan.overlay.vrfs.no_rp) }} + trm_enable: {{ vrf['trm_enable'] | default(defaults.vxlan.overlay.vrfs.trm_enable) }} {% if vrf['trm_enable'] is defined and vrf['trm_enable'] | bool %} overlay_mcast_group: {{ vrf['overlay_multicast_group'] | default(omit) }} rp_address: {{ vrf['rp_address'] | default(omit) }} rp_external: {{ vrf['rp_external'] | default(omit) }} rp_loopback_id: {{ vrf['rp_loopback_id'] | default(omit) }} - trm_bgw_msite: {{ vrf['trm_bgw_msite'] | default(defaults.vxlan.overlay_services.vrfs.trm_bgw_msite) }} + trm_bgw_msite: {{ vrf['trm_bgw_msite'] | default(defaults.vxlan.overlay.vrfs.trm_bgw_msite) }} underlay_mcast_ip: {{ vrf['underlay_mcast_ip'] | default(omit) }} {% endif %} - redist_direct_rmap: {{ vrf['redist_direct_routemap'] | default(defaults.vxlan.overlay_services.vrfs.redist_direct_routemap) }} + redist_direct_rmap: {{ vrf['redist_direct_routemap'] | default(defaults.vxlan.overlay.vrfs.redist_direct_routemap) }} {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} {% if vrf['vrf_attach_group'] is defined %} attach: -{% for attach in MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict[vrf['vrf_attach_group']] %} +{% if MD_Extended.vxlan.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} +{% elif MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} +{% endif %} +{% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} - ip_address: {{ attach['mgmt_ip_address'] }} {% endfor %} deploy: false diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index baf5aa264..5c1b576c0 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -3,16 +3,12 @@ {#- DO NOT EDIT MANUALLY #} {% set vxlan = MD_Extended.vxlan %} -{% if vxlan.global is defined %} -{% set global = vxlan.global %} -{% endif %} -{% set fabric_type = vxlan.fabric_type | default('VXLAN_EVPN') %} -{% if fabric_type == 'VXLAN_EVPN' %} +{% if vxlan.fabric.type == 'VXLAN_EVPN' %} {# Include NDFC DC VXLAN EVPN Base Template #} {% include '/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2' %} -{% elif fabric_type == 'MSD'%} +{% elif vxlan.fabric.type == 'MSD'%} {# Include NDFC MSD Base Template #} {% include '/ndfc_fabric/msd_fabric/msd_fabric_base.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 6b2c35843..ef484b65e 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} OVERLAY_MODE: cli GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false @@ -8,7 +8,7 @@ HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} {% if ndfc_version | cisco.nac_dc_vxlan.version_compare('12.2.2', '>=') %} STP_ROOT_OPTION: {{ vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol) }} -{% if vxlan.global.spanning_tree.root_bridge_protocol is defined and global.spanning_tree.root_bridge_protocol != 'unmanaged' %} +{% if vxlan.global.spanning_tree.root_bridge_protocol is defined and vxlan.global.spanning_tree.root_bridge_protocol != 'unmanaged' %} {% if (vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'rpvst+' %} STP_VLAN_RANGE: {{ ndfc_utils.convert_ranges(vxlan.global.spanning_tree.vlan_range, defaults.vxlan.global.spanning_tree.vlan_range) }} {% elif (vxlan.global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'mst' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 index 13c6732a7..116f4c996 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 @@ -1,16 +1,16 @@ -{# Auto-generated NDFC DC VXLAN EVPN Bootstrap config data structure for fabric {{ vxlan.global.name }} #} -{% if global.bootstrap is defined %} -{% if global.bootstrap.enable_bootstrap is defined and global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} - DHCP_ENABLE: {{ global.bootstrap.enable_local_dhcp_server }} - DHCP_IPV6_ENABLE: {{ global.bootstrap.dhcp_version }} - DHCP_START: {{ global.bootstrap.dhcp_v4.scope_start_address }} - DHCP_END: {{ global.bootstrap.dhcp_v4.scope_end_address }} - MGMT_GW: {{ global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} - MGMT_PREFIX: {{ global.bootstrap.dhcp_v4.mgmt_prefix }} - BOOTSTRAP_MULTISUBNET: "{{ global.bootstrap.dhcp_v4.multi_subnet_scope }}" +{# Auto-generated NDFC DC VXLAN EVPN Bootstrap config data structure for fabric {{ vxlan.fabric.name }} #} +{% if vxlan.global.bootstrap is defined %} +{% if vxlan.global.bootstrap.enable_bootstrap is defined and vxlan.global.bootstrap.enable_bootstrap %} + BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} + DHCP_ENABLE: {{ vxlan.global.bootstrap.enable_local_dhcp_server }} + DHCP_IPV6_ENABLE: {{ vxlan.global.bootstrap.dhcp_version }} + DHCP_START: {{ vxlan.global.bootstrap.dhcp_v4.scope_start_address }} + DHCP_END: {{ vxlan.global.bootstrap.dhcp_v4.scope_end_address }} + MGMT_GW: {{ vxlan.global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} + MGMT_PREFIX: {{ vxlan.global.bootstrap.dhcp_v4.mgmt_prefix }} + BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" {% endif %} -{% if global.bootstrap.enable_bootstrap is defined and not global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} +{% if vxlan.global.bootstrap.enable_bootstrap is defined and not vxlan.global.bootstrap.enable_bootstrap %} + BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} {% endif %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 index fa2fd4e52..a8c591272 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC DC VXLAN EVPN Base config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Base config data structure for fabric {{ vxlan.fabric.name }} #} - FABRIC_NAME: {{ vxlan.fabric.name }} FABRIC_TYPE: {{ vxlan.fabric.type }} DEPLOY: True diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/flow_monitor/dc_vxlan_fabric_flow_monitor.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/flow_monitor/dc_vxlan_fabric_flow_monitor.j2 index cc3d2da4a..765a5dc98 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/flow_monitor/dc_vxlan_fabric_flow_monitor.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/flow_monitor/dc_vxlan_fabric_flow_monitor.j2 @@ -1,26 +1,26 @@ -{# Auto-generated NDFC DC VXLAN EVPN Flow Monitor config data structure for fabric {{ vxlan.global.name }} #} - ENABLE_NETFLOW: {{ global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} -{% if global.netflow.enable is defined and global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} -{% if global.netflow.exporter is defined %} +{# Auto-generated NDFC DC VXLAN EVPN Flow Monitor config data structure for fabric {{ vxlan.fabric.name }} #} + ENABLE_NETFLOW: {{ vxlan.global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} +{% if vxlan.global.netflow.enable is defined and vxlan.global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} +{% if vxlan.global.netflow.exporter is defined %} {% set exporter_dict = dict() %} {% set _ = exporter_dict.update({ "NETFLOW_EXPORTER_LIST":[] }) %} -{% for e in global.netflow.exporter %} +{% for e in vxlan.global.netflow.exporter %} {% set _ = exporter_dict["NETFLOW_EXPORTER_LIST"].append(dict(EXPORTER_NAME=e.name,IP=e.ip_address,VRF=e.vrf | default(""), SRC_IF_NAME=e.source_interface,UDP_PORT=e.udp_port)) %} {% endfor %} NETFLOW_EXPORTER_LIST: "{{ exporter_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if global.netflow.record is defined %} +{% if vxlan.global.netflow.record is defined %} {% set record_dict = dict() %} {% set _ = record_dict.update({ "NETFLOW_RECORD_LIST":[] }) %} -{% for r in global.netflow.record %} +{% for r in vxlan.global.netflow.record %} {% set _ = record_dict["NETFLOW_RECORD_LIST"].append(dict(RECORD_NAME=r.name,RECORD_TEMPLATE =r.template,LAYER2_RECORD=r.layer2 | default(false) | string | lower)) %} {% endfor %} NETFLOW_RECORD_LIST: "{{ record_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if global.netflow.monitor is defined %} +{% if vxlan.global.netflow.monitor is defined %} {% set monitor_dict = dict() %} {% set _ = monitor_dict.update({ "NETFLOW_MONITOR_LIST":[] }) %} -{% for m in global.netflow.monitor %} +{% for m in vxlan.global.netflow.monitor %} {% set _ = monitor_dict["NETFLOW_MONITOR_LIST"].append(dict(MONITOR_NAME=m.name,RECORD_NAME=m.record,EXPORTER1=m.exporter1,EXPORTER2=m.exporter2 | default(""))) %} {% endfor %} NETFLOW_MONITOR_LIST: "{{ monitor_dict | tojson | replace('"', '\\"') }}" diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 index a11946d88..a959ef136 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 @@ -1,5 +1,5 @@ -{# Auto-generated NDFC DC VXLAN EVPN General config data structure for fabric {{ vxlan.global.name }} #} - BGP_AS: {{ global.bgp_asn }} +{# Auto-generated NDFC DC VXLAN EVPN General config data structure for fabric {{ vxlan.fabric.name }} #} + BGP_AS: {{ vxlan.global.bgp_asn }} UNDERLAY_IS_V6: {{ (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) }} {% if (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'True' %} USE_LINK_LOCAL: {{ vxlan.underlay.ipv6.enable_ipv6_link_local_address | default(defaults.vxlan.underlay.ipv6.enable_ipv6_link_local_address | title) }} @@ -12,6 +12,6 @@ SUBNET_TARGET_MASK: {{ vxlan.underlay.general.subnet_mask | default(defaults.vxlan.underlay.general.subnet_mask) }} {% endif %} LINK_STATE_ROUTING: {{ vxlan.underlay.general.routing_protocol | default(defaults.vxlan.underlay.general.routing_protocol) }} - RR_COUNT: {{ global.route_reflectors | default(defaults.vxlan.global.route_reflectors) }} - ANYCAST_GW_MAC: {{ global.anycast_gateway_mac | default(defaults.vxlan.global.anycast_gateway_mac) }} + RR_COUNT: {{ vxlan.global.route_reflectors | default(defaults.vxlan.global.route_reflectors) }} + ANYCAST_GW_MAC: {{ vxlan.global.anycast_gateway_mac | default(defaults.vxlan.global.anycast_gateway_mac) }} {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/manageability/dc_vxlan_fabric_manageability.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/manageability/dc_vxlan_fabric_manageability.j2 index bf36cf904..1e449b120 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/manageability/dc_vxlan_fabric_manageability.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/manageability/dc_vxlan_fabric_manageability.j2 @@ -1,8 +1,8 @@ -{# Auto-generated NDFC DC VXLAN EVPN Manageability config data structure for fabric {{ vxlan.global.name }} #} -{% if global.dns_servers is defined and global.dns_servers %} +{# Auto-generated NDFC DC VXLAN EVPN Manageability config data structure for fabric {{ vxlan.fabric.name }} #} +{% if vxlan.global.dns_servers is defined and vxlan.global.dns_servers %} {% set dns_server_ips = [] %} {% set dns_server_vrfs = [] %} -{% for dns in global.dns_servers %} +{% for dns in vxlan.global.dns_servers %} {% if dns.ip_address | string is defined and dns.ip_address %} {% set dns_ip = dns.ip_address | string %} {% set dns_server_ips = dns_server_ips.append(dns_ip) %} @@ -15,10 +15,10 @@ DNS_SERVER_IP_LIST: {{ dns_server_ips | join(',') | default(omit) }} DNS_SERVER_VRF: {{ dns_server_vrfs | join(',') | default(omit) }} {% endif %} -{% if global.ntp_servers is defined and global.ntp_servers %} +{% if vxlan.global.ntp_servers is defined and vxlan.global.ntp_servers %} {% set ntp_server_ips = [] %} {% set ntp_server_vrfs = [] %} -{% for ntp in global.ntp_servers %} +{% for ntp in vxlan.global.ntp_servers %} {% if ntp.ip_address is defined and ntp.ip_address %} {% set ntp_ip = ntp.ip_address | string %} {% set ntp_server_ips = ntp_server_ips.append(ntp_ip) %} @@ -31,11 +31,11 @@ NTP_SERVER_IP_LIST: {{ ntp_server_ips | join(',') | default(omit) }} NTP_SERVER_VRF: {{ ntp_server_vrfs | join(',') | default(omit) }} {% endif %} -{% if global.syslog_servers is defined and global.syslog_servers %} +{% if vxlan.global.syslog_servers is defined and vxlan.global.syslog_servers %} {% set syslog_server_ips = [] %} {% set syslog_server_vrfs = [] %} {% set syslog_server_sevs = [] %} -{% for syslog_server in global.syslog_servers %} +{% for syslog_server in vxlan.global.syslog_servers %} {% if syslog_server.ip_address is defined and syslog_server.ip_address %} {% set syslog_server_ip = syslog_server.ip_address | string %} {% set syslog_server_ips = syslog_server_ips.append(syslog_server_ip) %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 index a4f849992..87a895902 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC DC VXLAN EVPN Protocols config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Protocols config data structure for fabric {{ vxlan.fabric.name }} #} BGP_LB_ID: {{ vxlan.underlay.general.underlay_routing_loopback_id | default(defaults.vxlan.underlay.general.underlay_routing_loopback_id) }} NVE_LB_ID: {{ vxlan.underlay.general.underlay_vtep_loopback_id | default(defaults.vxlan.underlay.general.underlay_vtep_loopback_id) }} LINK_STATE_ROUTING_TAG: {{ vxlan.underlay.general.underlay_routing_protocol_tag | default(defaults.vxlan.underlay.general.underlay_routing_protocol_tag) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/replication/dc_vxlan_fabric_replication.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/replication/dc_vxlan_fabric_replication.j2 index 295a4e1ea..9d183070e 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/replication/dc_vxlan_fabric_replication.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/replication/dc_vxlan_fabric_replication.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC DC VXLAN EVPN Replication config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Replication config data structure for fabric {{ vxlan.fabric.name }} #} {% if (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} REPLICATION_MODE: {{ vxlan.underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) | title }} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 index 1aa0c0465..3075edc56 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC DC VXLAN EVPN Resources config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Resources config data structure for fabric {{ vxlan.fabric.name }} #} STATIC_UNDERLAY_IP_ALLOC: {{ (vxlan.underlay.general.manual_underlay_allocation | default(defaults.vxlan.underlay.general.manual_underlay_allocation) | title)}} {% if (vxlan.underlay.general.manual_underlay_allocation | default(defaults.vxlan.underlay.general.manual_underlay_allocation) | title) == 'False' %} {% if (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/security/dc_vxlan_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/security/dc_vxlan_fabric_security.j2 index f23297b1b..27e6be195 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/security/dc_vxlan_fabric_security.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/security/dc_vxlan_fabric_security.j2 @@ -1,2 +1,2 @@ -{# Auto-generated NDFC DC VXLAN EVPN Security config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN Security config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_SGT: false \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 49105ed70..f281c2183 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -1,13 +1,13 @@ -{# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.global.name }} #} +{# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_FABRIC_VPC_DOMAIN_ID: False - VPC_PEER_LINK_VLAN: {{ global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} - VPC_PEER_KEEP_ALIVE_OPTION: {{ global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} - VPC_AUTO_RECOVERY_TIME: {{ global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} - VPC_DELAY_RESTORE_TIME: {{ global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - VPC_PEER_LINK_PO: {{ global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_DOMAIN_ID_RANGE: {{ global.vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} - VPC_DELAY_RESTORE: {{ global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - ADVERTISE_PIP_BGP: {{ (global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} -{% if (global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} - ADVERTISE_PIP_ON_BORDER: {{ global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} + VPC_PEER_LINK_VLAN: {{ vxlan.global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} + VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} + VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} + VPC_DELAY_RESTORE_TIME: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} + VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} + VPC_DOMAIN_ID_RANGE: {{ vxlan.global.vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} + VPC_DELAY_RESTORE: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} + ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} +{% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} + ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 index a06fccaa4..e459e813b 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.name }} #} +{# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.fabric.name }} #} BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 index 1c4e92ca8..baafab7ce 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -1,6 +1,6 @@ -{# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.name }} #} +{# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_PVLAN: false ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} - MS_LOOPBACK_ID: {{ vxlan.multisite.loopback_id | default(defaults.vxlan.multisite.loopback_id) }} + MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 index 8f4d07d09..19ea1f875 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 @@ -1,5 +1,5 @@ -{# Auto-generated NDFC DC VXLAN EVPN Base config data structure for fabric {{ vxlan.name }} #} -- FABRIC_NAME: {{ vxlan.name }} +{# Auto-generated NDFC MultiSite Domain (MSD) Base config data structure for fabric {{ vxlan.fabric.name }} #} +- FABRIC_NAME: {{ vxlan.fabric.name }} FABRIC_TYPE: VXLAN_EVPN_MSD DEPLOY: True diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index 31bd7dd82..8f7fd4959 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -1,4 +1,4 @@ -{# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.name }} #} +{# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.fabric.name }} #} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.vtep_loopback_ip_range | default(defaults.vxlan.multisite.vtep_loopback_ip_range) }} DCI_SUBNET_RANGE: {{ vxlan.multisite.dci_subnet_range | default(defaults.vxlan.multisite.dci_subnet_range) }} DCI_SUBNET_MASK: {{ vxlan.multisite.dci_subnet_mask | default(defaults.vxlan.multisite.dci_subnet_mask) }} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 index a7f56a612..80d69feb6 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 @@ -1,2 +1,2 @@ -{# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.name }} #} +{# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_SGT: false \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 index bfa6a03d2..2d179f36c 100644 --- a/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 +++ b/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 @@ -8,7 +8,7 @@ {% set peer1_interface = peers['peer1_peerlink_interfaces'][interface_index] %} {% set peer2_interface = peers['peer2_peerlink_interfaces'][interface_index] %} {% if peer1_interface is defined and peer2_interface is defined %} -- dst_fabric : {{ MD_Extended.vxlan.global.name }} +- dst_fabric : {{ MD_Extended.vxlan.fabric.name }} template: int_pre_provision_intra_fabric_link src_interface: {{peer1_interface.name}} dst_interface: {{peer2_interface.name}} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index a80afd39e..be015e3b8 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -21,18 +21,19 @@ --- -- name: Import MSD Role Tasks +- name: Import VXLAN Role Tasks ansible.builtin.import_tasks: sub_main_vxlan.yml when: - - MD_Extended.vxlan.fabric_type == 'VXLAN_EVPN' + - MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy -- name: Import VxLAN Role Tasks +- name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml - when: MD_Extended.vxlan.fabric_type == 'MSD' + when: MD_Extended.vxlan.fabric.type == 'MSD' - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" stage: role_create_completed register: run_map delegate_to: localhost diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml index e1514c0b0..31677c764 100644 --- a/roles/dtc/create/tasks/msd/child_fabrics.yml +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD.vxlan.name }}" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" - name: Get Fabric Association Data from NDFC @@ -34,9 +34,9 @@ path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations register: fabric_associations -- name: Move Child Fabrics To Fabric - {{ MD.vxlan.name }} +- name: Move Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} cisco.nac_dc_vxlan.dtc.move_child_fabrics: fabric_associations: "{{ fabric_associations }}" - parent_fabric_name: "{{ MD_Extended.vxlan.name }}" + parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" when: fabric_associations is defined diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml index b157898f0..e810c30d3 100644 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -25,10 +25,10 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD.vxlan.name }}" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Manage Fabric {{ MD.vxlan.name }} in NDFC +- name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged config: "{{ fabric_config }}" diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 076326ad7..d9e6d51a0 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -35,8 +35,8 @@ - name: Create NDFC MSD Fabric ansible.builtin.import_tasks: msd/fabric.yml when: - - MD_Extended.vxlan.name is defined - - MD_Extended.vxlan.fabric_type == "MSD" + - MD_Extended.vxlan.fabric.name is defined + - MD_Extended.vxlan.fabric.type == "MSD" - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index 855af8f27..494ecc9ea 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -35,6 +35,8 @@ - name: Create NDFC Fabric ansible.builtin.import_tasks: vxlan/fabric.yml when: + - MD_Extended.vxlan.fabric.name is defined + - MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" - MD_Extended.vxlan.global is defined - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" diff --git a/roles/dtc/create/tasks/vxlan/devices.yml b/roles/dtc/create/tasks/vxlan/devices.yml index 0c6e81b14..f823a9891 100644 --- a/roles/dtc/create/tasks/vxlan/devices.yml +++ b/roles/dtc/create/tasks/vxlan/devices.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Devices Fabric {{ MD.vxlan.global.name }}" + - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" - name: Manage Devices Discovery diff --git a/roles/dtc/create/tasks/vxlan/devices_discovery.yml b/roles/dtc/create/tasks/vxlan/devices_discovery.yml index 60add0df8..1b12ac321 100644 --- a/roles/dtc/create/tasks/vxlan/devices_discovery.yml +++ b/roles/dtc/create/tasks/vxlan/devices_discovery.yml @@ -21,9 +21,9 @@ --- -- name: Add NDFC Fabric Devices {{ MD.vxlan.global.name }} +- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_inventory: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ updated_inv_config['updated_inv_list'] }}" deploy: false save: true diff --git a/roles/dtc/create/tasks/vxlan/fabric.yml b/roles/dtc/create/tasks/vxlan/fabric.yml index 2ec479a87..549e57852 100644 --- a/roles/dtc/create/tasks/vxlan/fabric.yml +++ b/roles/dtc/create/tasks/vxlan/fabric.yml @@ -25,10 +25,10 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD.vxlan.global.name }}" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Manage fabric {{ MD.vxlan.global.name }} in NDFC +- name: Manage fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged config: "{{ fabric_config }}" diff --git a/roles/dtc/create/tasks/vxlan/interfaces.yml b/roles/dtc/create/tasks/vxlan/interfaces.yml index af086ecff..45d537092 100644 --- a/roles/dtc/create/tasks/vxlan/interfaces.yml +++ b/roles/dtc/create/tasks/vxlan/interfaces.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Fabric Interfaces {{ MD.vxlan.global.name }}" + - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" # -------------------------------------------------------------------- @@ -34,7 +34,7 @@ - name: Manage Access Portchannel Interface cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_access_po }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 @@ -45,7 +45,7 @@ - name: Manage Trunk Portchannel Interface cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_trunk_po }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 @@ -56,7 +56,7 @@ - name: Manage Interface Routed cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 @@ -67,7 +67,7 @@ - name: Manage Sub-interface Routed cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ sub_interface_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 @@ -78,7 +78,7 @@ - name: Manage Interface Port-Channel Routed cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_po_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 @@ -89,7 +89,7 @@ - name: Manage NDFC Fabric Loopback cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 @@ -100,7 +100,7 @@ - name: Manage Interface Trunk cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_trunk }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 @@ -111,7 +111,7 @@ - name: Manage Interface Access cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_access }}" when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 @@ -122,7 +122,7 @@ - name: Manage NDFC Fabric vPCs cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ interface_vpc }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 diff --git a/roles/dtc/create/tasks/vxlan/policies.yml b/roles/dtc/create/tasks/vxlan/policies.yml index c052c15af..3b9d2e497 100644 --- a/roles/dtc/create/tasks/vxlan/policies.yml +++ b/roles/dtc/create/tasks/vxlan/policies.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Policies Fabric {{ MD.vxlan.global.name }}" + - "+ Manage Policies Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" # -------------------------------------------------------------------- @@ -33,7 +33,7 @@ # -------------------------------------------------------------------- - name: Manage NDFC Fabric Policies cisco.dcnm.dcnm_policy: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" use_desc_as_key: true config: "{{ policy_config }}" deploy: false diff --git a/roles/dtc/create/tasks/vxlan/vpc_peering.yml b/roles/dtc/create/tasks/vxlan/vpc_peering.yml index a5ab3a566..bb97948ba 100644 --- a/roles/dtc/create/tasks/vxlan/vpc_peering.yml +++ b/roles/dtc/create/tasks/vxlan/vpc_peering.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage Fabric vPC Peers {{ MD.vxlan.global.name }}" + - "+ Manage Fabric vPC Peers {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" # -------------------------------------------------------------------- @@ -35,7 +35,7 @@ - name: Manage Intra Fabric Links for vpc peering cisco.dcnm.dcnm_links: state: replaced - src_fabric: "{{ MD_Extended.vxlan.global.name }}" + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ link_vpc_peering }}" vars: ansible_command_timeout: 3000 @@ -47,7 +47,7 @@ - name: Manage vPC Peering cisco.dcnm.dcnm_vpc_pair: - src_fabric: "{{ MD.vxlan.global.name }}" + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" deploy: false state: replaced config: "{{ vpc_peering }}" diff --git a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml index ec1a19c8c..025c486bb 100644 --- a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml +++ b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml @@ -25,7 +25,7 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage VRFs and Networks Fabric {{ MD.vxlan.global.name }}" + - "+ Manage VRFs and Networks Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" # -------------------------------------------------------------------- @@ -33,7 +33,7 @@ # -------------------------------------------------------------------- - name: Manage NDFC Fabric VRFs cisco.dcnm.dcnm_vrf: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ vrf_config }}" register: manage_vrf_result @@ -48,7 +48,7 @@ # -------------------------------------------------------------------- - name: Manage NDFC Fabric Networks cisco.dcnm.dcnm_network: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced config: "{{ net_config }}" register: manage_network_result diff --git a/roles/dtc/deploy/tasks/main.yml b/roles/dtc/deploy/tasks/main.yml index 96c5ec4cf..1e82ec4b3 100644 --- a/roles/dtc/deploy/tasks/main.yml +++ b/roles/dtc/deploy/tasks/main.yml @@ -28,6 +28,7 @@ - name: Mark Stage Role Deploy Completed cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" stage: role_deploy_completed register: run_map delegate_to: localhost diff --git a/roles/dtc/deploy/tasks/sub_main.yml b/roles/dtc/deploy/tasks/sub_main.yml index e41999840..27464d917 100644 --- a/roles/dtc/deploy/tasks/sub_main.yml +++ b/roles/dtc/deploy/tasks/sub_main.yml @@ -30,16 +30,16 @@ - ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" -- name: Config-Save for Fabric {{ MD.vxlan.global.name }} +- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.global.name }}/config-save" + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" when: MD_Extended.vxlan.topology.switches | length > 0 # TODO: Need to add logic to only save if changes are made -- name: Deploy for Fabric {{ MD.vxlan.global.name }} +- name: Deploy for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.global.name }}/config-deploy?forceShowRun=false" + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy?forceShowRun=false" method: POST vars: ansible_command_timeout: 3000 diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index 8cb4e2a77..0a0cdcce8 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -21,12 +21,20 @@ --- -- name: Import Role Tasks - ansible.builtin.import_tasks: sub_main.yml - when: changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs or changes_detected_vpc_peering or changes_detected_link_vpc_peering or changes_detected_inventory +- name: Import VXLAN Role Tasks + ansible.builtin.import_tasks: sub_main_vxlan.yml + when: + - MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' + - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs or changes_detected_vpc_peering or changes_detected_link_vpc_peering or changes_detected_inventory + +- name: Import MSD Role Tasks + ansible.builtin.import_tasks: sub_main_msd.yml + when: + - MD_Extended.vxlan.fabric.type == 'MSD' - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" stage: role_remove_completed register: run_map delegate_to: localhost diff --git a/roles/dtc/remove/tasks/msd/.gitkeep b/roles/dtc/remove/tasks/msd/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/create/tasks/vxlan/reset.yml b/roles/dtc/remove/tasks/sub_main_msd.yml similarity index 79% rename from roles/dtc/create/tasks/vxlan/reset.yml rename to roles/dtc/remove/tasks/sub_main_msd.yml index b528fcd0f..f4d2e7e69 100644 --- a/roles/dtc/create/tasks/vxlan/reset.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -20,12 +20,3 @@ # SPDX-License-Identifier: MIT --- - -- name: Remove all devices from the NDFC fabric {{ fabric_name }} - cisco.dcnm.dcnm_inventory: - fabric: "{{ fabric_name }}" - state: deleted - config: "{{ lookup('file', 'ndfc_inventory.yml') | from_yaml }}" - vars: - ansible_command_timeout: 1000 - ansible_connect_timeout: 1000 diff --git a/roles/dtc/remove/tasks/sub_main.yml b/roles/dtc/remove/tasks/sub_main_vxlan.yml similarity index 86% rename from roles/dtc/remove/tasks/sub_main.yml rename to roles/dtc/remove/tasks/sub_main_vxlan.yml index 2e9046990..397e124c5 100644 --- a/roles/dtc/remove/tasks/sub_main.yml +++ b/roles/dtc/remove/tasks/sub_main_vxlan.yml @@ -35,48 +35,48 @@ - name: Get List of Fabric Switches from NDFC cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.global.name }}/inventory/switchesByFabric" + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" register: switch_list tags: "{{ nac_tags.remove }}" - name: Remove Fabric Policy - ansible.builtin.import_tasks: policy.yml + ansible.builtin.import_tasks: vxlan/policy.yml tags: "{{ nac_tags.remove_policy }}" when: - changes_detected_policy - name: Remove Fabric Interfaces - ansible.builtin.import_tasks: interfaces.yml + ansible.builtin.import_tasks: vxlan/interfaces.yml tags: "{{ nac_tags.remove_interfaces }}" when: - changes_detected_interfaces - name: Remove Fabric Networks - ansible.builtin.import_tasks: networks.yml + ansible.builtin.import_tasks: vxlan/networks.yml tags: "{{ nac_tags.remove_networks }}" when: - changes_detected_networks - name: Remove Fabric VRFs - ansible.builtin.import_tasks: vrfs.yml + ansible.builtin.import_tasks: vxlan/vrfs.yml tags: "{{ nac_tags.remove_vrfs }}" when: - changes_detected_vrfs - name: Remove Fabric Links - ansible.builtin.import_tasks: links.yml + ansible.builtin.import_tasks: vxlan/links.yml tags: "{{ nac_tags.remove_links }}" when: - changes_detected_link_vpc_peering - name: Remove Fabric vPC Peering - ansible.builtin.import_tasks: vpc_peers.yml + ansible.builtin.import_tasks: vxlan/vpc_peers.yml tags: "{{ nac_tags.remove_vpc_peers }}" when: - changes_detected_vpc_peering - name: Remove Fabric Switches - ansible.builtin.import_tasks: switches.yml + ansible.builtin.import_tasks: vxlan/switches.yml tags: "{{ nac_tags.remove_switches }}" when: - changes_detected_inventory diff --git a/roles/dtc/remove/tasks/vxlan/.gitkeep b/roles/dtc/remove/tasks/vxlan/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/remove/tasks/interfaces.yml b/roles/dtc/remove/tasks/vxlan/interfaces.yml similarity index 98% rename from roles/dtc/remove/tasks/interfaces.yml rename to roles/dtc/remove/tasks/vxlan/interfaces.yml index ab08d570b..19c68e9c4 100644 --- a/roles/dtc/remove/tasks/interfaces.yml +++ b/roles/dtc/remove/tasks/vxlan/interfaces.yml @@ -27,7 +27,7 @@ - name: Remove Unmanaged Fabric Interfaces cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden config: "{{ interface_all }}" # deploy: false diff --git a/roles/dtc/remove/tasks/links.yml b/roles/dtc/remove/tasks/vxlan/links.yml similarity index 96% rename from roles/dtc/remove/tasks/links.yml rename to roles/dtc/remove/tasks/vxlan/links.yml index d547771a5..7c3a35f67 100644 --- a/roles/dtc/remove/tasks/links.yml +++ b/roles/dtc/remove/tasks/vxlan/links.yml @@ -28,7 +28,7 @@ - name: Remove Intra Fabric Links for vPC Peering cisco.dcnm.dcnm_links: state: replaced - src_fabric: "{{ MD_Extended.vxlan.global.name }}" + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ link_vpc_peering }}" vars: ansible_command_timeout: 3000 diff --git a/roles/dtc/remove/tasks/networks.yml b/roles/dtc/remove/tasks/vxlan/networks.yml similarity index 97% rename from roles/dtc/remove/tasks/networks.yml rename to roles/dtc/remove/tasks/vxlan/networks.yml index 82487a744..706fa9efe 100644 --- a/roles/dtc/remove/tasks/networks.yml +++ b/roles/dtc/remove/tasks/vxlan/networks.yml @@ -27,7 +27,7 @@ - name: Remove Unmanaged Fabric Networks cisco.dcnm.dcnm_network: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden config: "{{ net_config }}" vars: diff --git a/roles/dtc/remove/tasks/policy.yml b/roles/dtc/remove/tasks/vxlan/policy.yml similarity index 98% rename from roles/dtc/remove/tasks/policy.yml rename to roles/dtc/remove/tasks/vxlan/policy.yml index d203a5ad6..26cf28f8a 100644 --- a/roles/dtc/remove/tasks/policy.yml +++ b/roles/dtc/remove/tasks/vxlan/policy.yml @@ -37,7 +37,7 @@ - name: Remove Unmanaged NDFC Fabric Policy cisco.dcnm.dcnm_policy: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" use_desc_as_key: true config: "{{ unmanaged_policy_config.unmanaged_policies }}" deploy: true diff --git a/roles/dtc/remove/tasks/switches.yml b/roles/dtc/remove/tasks/vxlan/switches.yml similarity index 97% rename from roles/dtc/remove/tasks/switches.yml rename to roles/dtc/remove/tasks/vxlan/switches.yml index a3ab2de85..1094f1997 100644 --- a/roles/dtc/remove/tasks/switches.yml +++ b/roles/dtc/remove/tasks/vxlan/switches.yml @@ -26,7 +26,7 @@ - name: Remove Unmanaged NDFC Fabric Devices cisco.dcnm.dcnm_inventory: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ updated_inv_config['updated_inv_list'] }}" deploy: true save: true diff --git a/roles/dtc/remove/tasks/vpc_peers.yml b/roles/dtc/remove/tasks/vxlan/vpc_peers.yml similarity index 97% rename from roles/dtc/remove/tasks/vpc_peers.yml rename to roles/dtc/remove/tasks/vxlan/vpc_peers.yml index 9c400a647..dc8e1dcbb 100644 --- a/roles/dtc/remove/tasks/vpc_peers.yml +++ b/roles/dtc/remove/tasks/vxlan/vpc_peers.yml @@ -27,7 +27,7 @@ - name: Remove Unmanaged vPC Peering cisco.dcnm.dcnm_vpc_pair: - src_fabric: "{{ MD.vxlan.global.name }}" + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" deploy: true state: overridden config: "{{ vpc_peering }}" diff --git a/roles/dtc/remove/tasks/vrfs.yml b/roles/dtc/remove/tasks/vxlan/vrfs.yml similarity index 97% rename from roles/dtc/remove/tasks/vrfs.yml rename to roles/dtc/remove/tasks/vxlan/vrfs.yml index 87e39d7e4..68bce074e 100644 --- a/roles/dtc/remove/tasks/vrfs.yml +++ b/roles/dtc/remove/tasks/vxlan/vrfs.yml @@ -27,7 +27,7 @@ - name: Remove Unmanaged Fabric VRFs cisco.dcnm.dcnm_vrf: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden config: "{{ vrf_config }}" vars: diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 4ef1034b3..5b81d6c60 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -164,7 +164,7 @@ factory_defaults: isis: false authentication_enable: false authentication_key_id: 100 - overlay_services: + overlay: vrfs: vrf_description: "Configured by Ansible NetAsCode" vrf_intf_desc: "Configured by Ansible NetAsCode" diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index 9d6e722c5..41525ac72 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -49,6 +49,7 @@ - name: Mark Stage Role Validate Completed cisco.nac_dc_vxlan.common.run_map: + model_data: "{{ MD_Extended }}" stage: role_validate_completed register: run_map delegate_to: localhost diff --git a/roles/validate/tasks/manage_model_files_current.yml b/roles/validate/tasks/manage_model_files_current.yml index 43030ab06..b6679e495 100644 --- a/roles/validate/tasks/manage_model_files_current.yml +++ b/roles/validate/tasks/manage_model_files_current.yml @@ -25,7 +25,7 @@ - name: Copy Service Model Data to Host ansible.builtin.copy: content: "{{ MD | to_nice_json }}" - dest: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" + dest: "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" force: yes delegate_to: localhost @@ -33,14 +33,14 @@ - name: Copy Extended Service Model Data to Host ansible.builtin.copy: content: "{{ MD_Extended | to_nice_json }}" - dest: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" + dest: "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_extended.json" force: yes delegate_to: localhost # Read current golden service model data into a variable called 'smd_golden_current' - name: Read Current Service Model Data from Host ansible.builtin.include_vars: - file: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" + file: "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" register: smd_golden_current delegate_to: localhost diff --git a/roles/validate/tasks/manage_model_files_previous.yml b/roles/validate/tasks/manage_model_files_previous.yml index 590502927..2d2b30b9c 100644 --- a/roles/validate/tasks/manage_model_files_previous.yml +++ b/roles/validate/tasks/manage_model_files_previous.yml @@ -29,31 +29,31 @@ # Check if golden and extended service model data files exist from previous runs - name: Stat the Golden Service Model Data - ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" + ansible.builtin.stat: path="{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" register: golden_stat delegate_to: localhost - name: Stat the Extended Service Model Data - ansible.builtin.stat: path="{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" + ansible.builtin.stat: path="{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_extended.json" register: extended_stat delegate_to: localhost # Read and store previous golden service model data into a variable called 'smd_golden_previous' - name: Read Previous Golden Service Model Data from Host ansible.builtin.include_vars: - file: "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" + file: "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" register: smd_golden_previous when: golden_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost # Rename golden file from previous run to append '_previous' to the filename - name: Move Golden Service Model Data Previous - ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden.json" "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_golden_previous.json" + ansible.builtin.command: mv "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden_previous.json" when: golden_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost # Rename extended file from previous run to append '_previous' to the filename - name: Move Extended Service Model Data Previous - ansible.builtin.command: mv "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended.json" "{{ role_path }}/files/{{ MD.vxlan.name }}_service_model_extended_previous.json" + ansible.builtin.command: mv "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_extended.json" "{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_extended_previous.json" when: extended_stat.stat.exists and check_roles['save_previous'] delegate_to: localhost diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index 1d251656b..64112202a 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -107,8 +107,6 @@ register: smd delegate_to: localhost -- ansible.builtin.meta: end_play - - name: Store Golden Service Model Data ansible.builtin.set_fact: MD: "{{ smd['model_golden'] }}" diff --git a/roles/validate/tasks/sub_main_common_post.yml b/roles/validate/tasks/sub_main_common_post.yml deleted file mode 100644 index 351ff9635..000000000 --- a/roles/validate/tasks/sub_main_common_post.yml +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Check Roles - cisco.nac_dc_vxlan.common.check_roles: - role_list: "{{ role_names }}" - register: check_roles - delegate_to: localhost - -- name: Read Run Map From Previous Run - cisco.nac_dc_vxlan.common.read_run_map: - model_data: "{{ MD_Extended }}" - register: run_map_read_result - delegate_to: localhost - -- name: Debug Run Map Read Result - ansible.builtin.debug: - msg: "{{ run_map_read_result }}" - delegate_to: localhost - -- name: Initialize Run Map - cisco.nac_dc_vxlan.common.run_map: - model_data: "{{ MD_Extended }}" - stage: starting_execution - register: run_map - delegate_to: localhost - -- name: Manage Previous Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_previous.yml - when: check_roles['save_previous'] - -- name: Manage Current Service Model Data Files - ansible.builtin.include_tasks: manage_model_files_current.yml - when: check_roles['save_previous'] diff --git a/roles/validate/tasks/sub_main_common_pre.yml b/roles/validate/tasks/sub_main_common_pre.yml deleted file mode 100644 index a75c5e521..000000000 --- a/roles/validate/tasks/sub_main_common_pre.yml +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Role Entry Point - [cisco.nac_dc_vxlan.validate] - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Calling Role - [cisco.nac_dc_vxlan.validate] +" - - "----------------------------------------------------------------" - -- ansible.builtin.debug: msg="Role Path - {{ role_path }}" - -- ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" - -- name: Validate NDFC Service Model Data - ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" - -- ansible.builtin.debug: msg="Workflow is Direct to Controller (DTC)" - when: hostvars[inventory_hostname]['ansible_network_os'] == "cisco.dcnm.dcnm" - -- name: Load Data Model - cisco.nac_dc_vxlan.common.nac_dc_load: - mdata: "{{ data_path }}" - register: model_data - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - delegate_to: localhost - -- name: Stat Factory Defaults - ansible.builtin.stat: path="{{ role_path }}/files/defaults.yml" - register: factory_defaults_file - delegate_to: localhost - -- name: Include Factory Defaults if Available - ansible.builtin.include_vars: - file: "{{ role_path }}/files/defaults.yml" - when: factory_defaults_file.stat.exists - delegate_to: localhost - -- name: Merge factory and custom defaults - cisco.nac_dc_vxlan.common.merge_defaults: - factory_defaults: "{{ factory_defaults }}" - model_data: "{{ model_data['data'] }}" - register: defaults - delegate_to: localhost - -- name: Register Variable With Only Defaults from Previous Task - ansible.builtin.set_fact: - defaults: "{{ defaults['defaults'] }}" - delegate_to: localhost - -- name: Prepare Service Model - cisco.nac_dc_vxlan.common.prepare_service_model: - inventory_hostname: "{{ inventory_hostname }}" - hostvars: "{{ hostvars }}" - model_data: "{{ model_data['data'] }}" - default_values: "{{ defaults }}" - templates_path: "{{ role_path }}/../dtc/common/templates/" - register: smd - delegate_to: localhost - -- name: Store Golden Service Model Data - ansible.builtin.set_fact: - MD: "{{ smd['model_golden'] }}" - delegate_to: localhost - -- name: Store Extended Service Model Data - ansible.builtin.set_fact: - MD_Extended: "{{ smd['model_extended'] }}" - delegate_to: localhost diff --git a/roles/validate/tasks/sub_main_msd.yml b/roles/validate/tasks/sub_main_msd.yml deleted file mode 100644 index 400d755c6..000000000 --- a/roles/validate/tasks/sub_main_msd.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Perform Required Syntax and Semantic Model Validation for MSD Fabric - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" - mdata: "{{ data_path }}" - rules: "{{ rules_path }}" - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/required_rules/msd/" - delegate_to: localhost diff --git a/roles/validate/tasks/sub_main_vxlan.yml b/roles/validate/tasks/sub_main_vxlan.yml deleted file mode 100644 index 75c64515c..000000000 --- a/roles/validate/tasks/sub_main_vxlan.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Perform Required Syntax and Semantic Model Validation for VXLAN Fabric - cisco.nac_dc_vxlan.common.nac_dc_validate: - schema: "{{ schema_path }}" - mdata: "{{ data_path }}" - rules: "{{ rules_path }}" - vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" - rules_path: "{{ role_path }}/files/rules/" - delegate_to: localhost From 73abf697e7af0718cfa42239dd0d290600d79d30 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 5 Dec 2024 10:57:38 -0500 Subject: [PATCH 017/183] chagnes from review with mike --- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 2 +- .../401_overlay_services_cross_reference.py | 85 ++++++++++--------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index da83cfce4..a0949307c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_attach_vrfs.yml" + file_name: "{{ MD.vxlan.global.name }}_ndfc_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py index b4e0f9f79..3a7cf6db2 100644 --- a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py +++ b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py @@ -14,16 +14,18 @@ def match(cls, inventory): vrf_attach_groups = None switch_keys = ['vxlan', 'topology', 'switches'] - network_keys = ['vxlan', 'overlay', 'networks'] - vrf_keys = ['vxlan', 'overlay', 'vrfs'] - network_attach_keys = ['vxlan', 'overlay', 'network_attach_groups'] - vrf_attach_keys = ['vxlan', 'overlay', 'vrf_attach_groups'] - # For backwards compatibility - network_keys = ['vxlan', 'overlay_services', 'networks'] - vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] - network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] - vrf_attach_keys = ['vxlan', 'overlay_services', 'vrf_attach_groups'] + # Remove the check for overlay_services after deprecation + # Remove lines 21 - 23 + overlay_key = 'overlay' + check = cls.data_model_key_check(inventory, ['vxlan']) + if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: + overlay_key = 'overlay_services' + + network_keys = ['vxlan', f'{overlay_key}', 'networks'] + vrf_keys = ['vxlan', f'{overlay_key}', 'vrfs'] + network_attach_keys = ['vxlan', f'{overlay_key}', 'network_attach_groups'] + vrf_attach_keys = ['vxlan', f'{overlay_key}', 'vrf_attach_groups'] # Check if vrfs, network and switch data is defined in the service model check = cls.data_model_key_check(inventory, switch_keys) @@ -58,39 +60,40 @@ def match(cls, inventory): results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) # For backwards compatibility - sm_networks = None - sm_vrfs = None - network_attach_groups = None - vrf_attach_groups = None + # Lines 54 - 88 will be removed after the deprecation in a future release + # sm_networks = None + # sm_vrfs = None + # network_attach_groups = None + # vrf_attach_groups = None - network_keys = ['vxlan', 'overlay_services', 'networks'] - vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] - network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] - vrf_attach_keys = ['vxlan', 'overlay_services', 'vrf_attach_groups'] - - check = cls.data_model_key_check(inventory, network_keys) - if 'networks' in check['keys_data']: - sm_networks = cls.safeget(inventory, network_keys) - - check = cls.data_model_key_check(inventory, vrf_keys) - if 'vrfs' in check['keys_data']: - sm_vrfs = cls.safeget(inventory, vrf_keys) - - check = cls.data_model_key_check(inventory, vrf_attach_keys) - if 'vrf_attach_groups' in check['keys_data']: - vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) - - check = cls.data_model_key_check(inventory, network_attach_keys) - if 'network_attach_groups' in check['keys_data']: - network_attach_groups = cls.safeget(inventory, network_attach_keys) - - # Ensure Network is not referencing a VRF that is not defined in the service model - results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) - - if sm_vrfs and vrf_attach_groups: - results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) - if sm_networks and network_attach_groups: - results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) + # network_keys = ['vxlan', 'overlay_services', 'networks'] + # vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] + # network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] + # vrf_attach_keys = ['vxlan', 'overlay_services', 'vrf_attach_groups'] + + # check = cls.data_model_key_check(inventory, network_keys) + # if 'networks' in check['keys_data']: + # sm_networks = cls.safeget(inventory, network_keys) + + # check = cls.data_model_key_check(inventory, vrf_keys) + # if 'vrfs' in check['keys_data']: + # sm_vrfs = cls.safeget(inventory, vrf_keys) + + # check = cls.data_model_key_check(inventory, vrf_attach_keys) + # if 'vrf_attach_groups' in check['keys_data']: + # vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) + + # check = cls.data_model_key_check(inventory, network_attach_keys) + # if 'network_attach_groups' in check['keys_data']: + # network_attach_groups = cls.safeget(inventory, network_attach_keys) + + # # Ensure Network is not referencing a VRF that is not defined in the service model + # results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) + + # if sm_vrfs and vrf_attach_groups: + # results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) + # if sm_networks and network_attach_groups: + # results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) return results From becfbd5cfb01cdefad7bd2ccde3610eced67976b Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 5 Dec 2024 13:19:12 -0500 Subject: [PATCH 018/183] update fabric name reference to use extended --- plugins/action/dtc/get_poap_data.py | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_inventory.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_networks.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_policy.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/plugins/action/dtc/get_poap_data.py b/plugins/action/dtc/get_poap_data.py index 31a48e878..c6ace50ad 100644 --- a/plugins/action/dtc/get_poap_data.py +++ b/plugins/action/dtc/get_poap_data.py @@ -66,7 +66,7 @@ def __init__(self, params): self.task_vars = params['task_vars'] self.tmp = params['tmp'] - self.fabric_name = self.model_data['vxlan']['global']['name'] + self.fabric_name = self.model_data['vxlan']['fabric']['name'] self.switches = self.model_data['vxlan']['topology']['switches'] self.poap_supported_switches = False self.preprovision_supported_switches = False diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml index b83285eeb..ba50dea14 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_access.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml index a03c57f89..2e5b2b6f9 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_access_po.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml index a23f05795..392934c75 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_all.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_all.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml index cb7284bd1..d720d5f68 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_loopback_interfaces.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_loopback_interfaces.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml index 24bc6373b..7fb2af335 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_po_routed.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_po_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml index 32bddef02..4c2f90680 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_routed.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml index ca1edf7d0..073f02ce2 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_trunk.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml index f3b807d9d..b97086acc 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_trunk_po.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml index efd1d385a..5554d65d4 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_interface_vpc.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_vpc.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml index df01b1605..db6667a41 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml @@ -33,7 +33,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_inventory.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml index 691e2d1fb..1102baf10 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_link_vpc_peering.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_link_vpc_peering.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml index 595cf45b9..5437b7c21 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_attach_networks.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_networks.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml index 66d011696..f8eb9712c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_policy.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_policy.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml index 3c8282146..9677853e0 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_sub_interface_routed.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_sub_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml index bd53f0ac4..261d4899c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_vpc_peering.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_vpc_peering.yml" delegate_to: localhost - name: Stat Previous File If It Exists diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index a0949307c..2ea68d179 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -28,7 +28,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_attach_vrfs.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists From b6cbb56ed556c4f8ea7c663a1e22c5261dad2d67 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 5 Dec 2024 17:15:57 -0500 Subject: [PATCH 019/183] updats to msite templates --- .../msd_fabric/dci/msd_fabric_dci.j2 | 22 ++++++++++--------- .../msd_fabric/general/msd_fabric_general.j2 | 4 ++++ .../ndfc_fabric/msd_fabric/msd_fabric_base.j2 | 9 ++++++++ .../resources/msd_fabric_resources.j2 | 12 +++++++--- .../security/msd_fabric_security.j2 | 2 +- roles/validate/files/defaults.yml | 17 +++++++++----- 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 index e459e813b..8867c1525 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 @@ -1,12 +1,14 @@ {# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.fabric.name }} #} - BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} - MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} - ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} - ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) }} - ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} - DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} - MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_bgp_password | default(defaults.vxlan.multisite.enable_bgp_password) }} -{% if vxlan.multisite.enable_bgp_password is defined and vxlan.multisite.enable_bgp_password %} - MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.bgp_password }} - MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.bgp_auth_key_type | default(defaults.vxlan.multisite.bgp_auth_key_type) }} + BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} + MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} +{% if vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) %} + ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} + ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) | lower }} + ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} +{% endif %} + DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} + MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) }} +{% if vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) %} + MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.ebgp_password }} + MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.ebgp_password_encryption_type | default(defaults.vxlan.multisite.ebgp_password_encryption_type) }} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 index baafab7ce..07b9c8717 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -1,6 +1,10 @@ {# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.fabric.name }} #} + VXLAN_UNDERLAY_IS_V6: False +{% if not vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) %} ENABLE_PVLAN: false +{% endif %} ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} + TOR_AUTO_DEPLOY: False {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 index 19ea1f875..ba997f3da 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 @@ -5,3 +5,12 @@ {# Include NDFC DC VXLAN EVPN General Template #} {% include '/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2' %} + +{# Include NDFC DC VXLAN EVPN DCI Template #} +{% include '/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2' %} + +{# Include NDFC DC VXLAN EVPN Security Template #} +{% include '/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2' %} + +{# Include NDFC DC VXLAN EVPN Resources Template #} +{% include '/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index 8f7fd4959..734960736 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -1,4 +1,10 @@ {# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.fabric.name }} #} - LOOPBACK100_IP_RANGE: {{ vxlan.multisite.vtep_loopback_ip_range | default(defaults.vxlan.multisite.vtep_loopback_ip_range) }} - DCI_SUBNET_RANGE: {{ vxlan.multisite.dci_subnet_range | default(defaults.vxlan.multisite.dci_subnet_range) }} - DCI_SUBNET_MASK: {{ vxlan.multisite.dci_subnet_mask | default(defaults.vxlan.multisite.dci_subnet_mask) }} \ No newline at end of file +{% if not defaults.vxlan.multisite.enable_ipv6_underlay %} + LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} + DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} + DCI_SUBNET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} +{% else %} + LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} + V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} + V6_DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.ipv6_dci_subnet_mask) }} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 index 80d69feb6..a38f6b565 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 @@ -1,2 +1,2 @@ {# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_SGT: false \ No newline at end of file + ENABLE_SGT: false \ No newline at end of file diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 5b81d6c60..5918c7cd8 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -272,16 +272,21 @@ factory_defaults: default_originate: false next_hop_self: false multisite: + enable_ipv6_underlay: false anycast_gateway_mac: 20:20:00:00:00:aa vtep_loopback_id: 100 - vtep_loopback_ip_range: 10.10.0.0/24 - dci_subnet_range: 10.10.1.0/24 - dci_subnet_mask: 30 + ipv4_vtep_loopback_range: 10.10.0.0/24 + ipv4_dci_subnet_range: 10.10.1.0/24 + ipv4_dci_subnet_mask: 30 + ipv6_vtep_loopback_range: fd00::a10:0/120 + ipv6_dci_subnet_range: fd00::a11:0/120 + ipv6_dci_subnet_mask: 126 bgw_ip_tag: 54321 - overlay_ifc: direct_to_bgws - underlay_autoconfig: false + overlay_ifc: Direct_To_BGWS + underlay_autoconfig: true enable_bgp_send_community: false enable_bgp_log_neighbor_change: false enable_bgp_bfd: false delay_restore: 300 - enable_bgp_password: false + enable_ebgp_password: false + enable_trm: false From 1e7af3360e6685a8ab00dedb2ccd5ac9d8ba56a8 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 5 Dec 2024 20:23:45 -0500 Subject: [PATCH 020/183] update to msd tempaltes and add conditional to only run child fabrics if defined --- plugins/filter/quote.py | 85 +++++++++++++++++++ .../msd_fabric/general/msd_fabric_general.j2 | 2 +- .../resources/msd_fabric_resources.j2 | 2 +- .../security/msd_fabric_security.j2 | 2 +- roles/dtc/create/tasks/sub_main_msd.yml | 4 +- 5 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 plugins/filter/quote.py diff --git a/plugins/filter/quote.py b/plugins/filter/quote.py new file mode 100644 index 000000000..9203ea354 --- /dev/null +++ b/plugins/filter/quote.py @@ -0,0 +1,85 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +DOCUMENTATION = r""" + name: quote + version_added: "0.4.0" + short_description: Quote + description: + - Quote a string or integer. + positional: item + options: + item: + description: Item to quote. + required: true +""" + +EXAMPLES = r""" + + quoted: "{{ var1 | cisco.nac_dc_vxlan.quote() }}" + # => True + +""" + +RETURN = r""" + _value: + description: + - A string value. + type: str +""" + +import operator +from jinja2.runtime import Undefined +from jinja2.exceptions import UndefinedError + +from packaging.version import Version + +from ansible.module_utils.six import string_types +from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError +from ansible.module_utils.common.text.converters import to_native + + +def quote(item): + # if not isinstance(version1, (string_types, Undefined)): + # raise AnsibleFilterTypeError(f"Can only check string versions, however version1 is: {type(version1)}") + + # if not isinstance(version2, (string_types, Undefined)): + # raise AnsibleFilterTypeError(f"Can only check string versions, however version2 is: {type(version2)}") + + # if not isinstance(op, (string_types, Undefined)) and op not in SUPPORTED_COMPARISON_OPERATORS: + # raise AnsibleFilterError(f"Unsupported operator {op} type. Supported operators are: {SUPPORTED_COMPARISON_OPERATORS}") + + try: + return f'"{item}"' + except UndefinedError: + raise + except Exception as e: + raise AnsibleFilterError("Unable handle version: %s" % to_native(e), orig_exc=e) + + +# ---- Ansible filters ---- +class FilterModule(object): + """ Quote filter """ + + def filters(self): + return { + "quote": quote + } diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 index 07b9c8717..362e2257f 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -6,5 +6,5 @@ ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} - TOR_AUTO_DEPLOY: False + TOR_AUTO_DEPLOY: false {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index 734960736..dc5d0db36 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -2,7 +2,7 @@ {% if not defaults.vxlan.multisite.enable_ipv6_underlay %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} - DCI_SUBNET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} + DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 index a38f6b565..715734a79 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/security/msd_fabric_security.j2 @@ -1,2 +1,2 @@ {# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_SGT: false \ No newline at end of file + ENABLE_SGT: "off" \ No newline at end of file diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index d9e6d51a0..8ee865a55 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -42,7 +42,7 @@ - name: Manage NDFC MSD Fabric Child Fabrics ansible.builtin.import_tasks: msd/child_fabrics.yml - # when: - # - MD_Extended.vxlan.topology.switches | length > 0 + when: + - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 # - changes_detected_inventory # tags: "{{ nac_tags.create_switches }}" From 48019b0c950b33952dee8ac2335b2e6b533d6c79 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Sun, 8 Dec 2024 21:40:14 -0500 Subject: [PATCH 021/183] first commit from hospital --- plugins/action/common/nac_dc_validate.py | 2 + ...ild_fabrics.py => manage_child_fabrics.py} | 1 - .../dtc/update_switch_hostname_policy.py | 8 +- roles/dtc/common/tasks/isn/ndfc_fabric.yml | 77 +++++++++++++ roles/dtc/common/tasks/isn/ndfc_inventory.yml | 105 ++++++++++++++++++ roles/dtc/common/tasks/main.yml | 5 + roles/dtc/common/tasks/msd/ndfc_networks.yml | 83 ++++++++++++++ roles/dtc/common/tasks/msd/ndfc_vrfs.yml | 83 ++++++++++++++ roles/dtc/common/tasks/sub_main_isn.yml | 48 ++++++++ .../dtc/common/tasks/vxlan/ndfc_networks.yml | 4 +- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 4 +- roles/dtc/common/templates/ndfc_fabric.j2 | 7 +- .../templates/ndfc_fabric/isn_fabric/.gitkeep | 0 .../ndfc_fabric/isn_fabric/advanced/.gitkeep | 0 .../advanced/isn_fabric_advanced.j2 | 10 ++ .../ndfc_fabric/isn_fabric/bootstrap/.gitkeep | 0 .../bootstrap/isn_fabric_bootstrap.j2 | 19 ++++ .../isn_fabric/flow_monitor/.gitkeep | 0 .../flow_monitor/isn_fabric_flow_monitor.j2 | 28 +++++ .../ndfc_fabric/isn_fabric/general/.gitkeep | 0 .../isn_fabric/general/isn_fabric_general.j2 | 4 + .../ndfc_fabric/isn_fabric/isn_fabric_base.j2 | 19 ++++ .../ndfc_fabric/isn_fabric/resources/.gitkeep | 0 .../resources/isn_fabric_resources.j2 | 2 + .../ndfc_fabric/isn_fabric/temp.json | 86 ++++++++++++++ roles/dtc/common/templates/ndfc_inventory.j2 | 50 +++------ .../common/templates/ndfc_inventory/.gitkeep | 0 .../ndfc_inventory/dc_vxlan_fabric/.gitkeep | 0 .../dc_vxlan_fabric_inventory.j2 | 32 ++++++ .../ndfc_inventory/isn_fabric/.gitkeep | 0 .../isn_fabric/isn_fabric_inventory.j2 | 33 ++++++ roles/dtc/create/tasks/isn/devices.yml | 32 ++++++ .../create/tasks/isn/devices_discovery.yml | 60 ++++++++++ roles/dtc/create/tasks/isn/fabric.yml | 34 ++++++ roles/dtc/create/tasks/main.yml | 4 + roles/dtc/create/tasks/msd/child_fabrics.yml | 9 +- roles/dtc/create/tasks/msd/vrfs_networks.yml | 58 ++++++++++ roles/dtc/create/tasks/sub_main_isn.yml | 48 ++++++++ roles/dtc/create/tasks/sub_main_msd.yml | 10 ++ roles/dtc/create/tasks/sub_main_vxlan.yml | 9 +- .../dtc/create/tasks/vxlan/vrfs_networks.yml | 17 ++- roles/dtc/deploy/tasks/sub_main.yml | 10 +- roles/dtc/remove/tasks/msd/child_fabrics.yml | 0 roles/dtc/remove/tasks/msd/networks.yml | 45 ++++++++ roles/dtc/remove/tasks/msd/vrfs.yml | 45 ++++++++ roles/dtc/remove/tasks/sub_main_msd.yml | 12 ++ roles/validate/files/defaults.yml | 10 ++ roles/validate/files/rules/isn/.gitkeep | 0 48 files changed, 1055 insertions(+), 58 deletions(-) rename plugins/action/dtc/{move_child_fabrics.py => manage_child_fabrics.py} (99%) create mode 100644 roles/dtc/common/tasks/isn/ndfc_fabric.yml create mode 100644 roles/dtc/common/tasks/isn/ndfc_inventory.yml create mode 100644 roles/dtc/common/tasks/msd/ndfc_networks.yml create mode 100644 roles/dtc/common/tasks/msd/ndfc_vrfs.yml create mode 100644 roles/dtc/common/tasks/sub_main_isn.yml create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/isn_fabric_advanced.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json create mode 100644 roles/dtc/common/templates/ndfc_inventory/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 create mode 100644 roles/dtc/common/templates/ndfc_inventory/isn_fabric/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 create mode 100644 roles/dtc/create/tasks/isn/devices.yml create mode 100644 roles/dtc/create/tasks/isn/devices_discovery.yml create mode 100644 roles/dtc/create/tasks/isn/fabric.yml create mode 100644 roles/dtc/create/tasks/msd/vrfs_networks.yml create mode 100644 roles/dtc/create/tasks/sub_main_isn.yml create mode 100644 roles/dtc/remove/tasks/msd/child_fabrics.yml create mode 100644 roles/dtc/remove/tasks/msd/networks.yml create mode 100644 roles/dtc/remove/tasks/msd/vrfs.yml create mode 100644 roles/validate/files/rules/isn/.gitkeep diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 8f45aaaf3..1a9fc3b41 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -95,6 +95,8 @@ def run(self, tmp=None, task_vars=None): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCF'): rules_list.append(f'{rules}multisite/') + elif results['data']['vxlan']['fabric']['type'] in ('ISN'): + rules_list.append(f'{rules}isn/') else: results['failed'] = True results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['fabric']['type']} is not a supported fabric type." diff --git a/plugins/action/dtc/move_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py similarity index 99% rename from plugins/action/dtc/move_child_fabrics.py rename to plugins/action/dtc/manage_child_fabrics.py index 7163d0291..1e7eb14e2 100644 --- a/plugins/action/dtc/move_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -70,7 +70,6 @@ def run(self, tmp=None, task_vars=None): # https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations/ # GET -# # https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd # POST diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index f52891b20..574dfe755 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -49,7 +49,13 @@ def run(self, tmp=None, task_vars=None): template_name=template_name ) - switch_match = next((item for item in model_data["vxlan"]["topology"]["switches"] if item["serial_number"] == switch_serial_number)) + dm_switches = [] + if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN'): + dm_switches = model_data["vxlan"]["topology"]["switches"] + elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): + dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] + + switch_match = next((item for item in dm_switches if item["serial_number"] == switch_serial_number)) if policy_match["nvPairs"]["SWITCH_NAME"] != switch_match["name"]: policy_match["nvPairs"]["SWITCH_NAME"] = switch_match["name"] diff --git a/roles/dtc/common/tasks/isn/ndfc_fabric.yml b/roles/dtc/common/tasks/isn/ndfc_fabric.yml new file mode 100644 index 000000000..a6ed2eeae --- /dev/null +++ b/roles/dtc/common/tasks/isn/ndfc_fabric.yml @@ -0,0 +1,77 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/isn/ndfc_inventory.yml b/roles/dtc/common/tasks/isn/ndfc_inventory.yml new file mode 100644 index 000000000..bcaae0608 --- /dev/null +++ b/roles/dtc/common/tasks/isn/ndfc_inventory.yml @@ -0,0 +1,105 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Get POAP Data From POAP Enabled Devices + cisco.nac_dc_vxlan.dtc.get_poap_data: + model_data: "{{ MD_Extended }}" + register: poap_data + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_inventory: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Set Path For Inventory File Lookup + ansible.builtin.set_fact: + inv_file_path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Build Fabric Switch Inventory List From Template + ansible.builtin.template: + src: ndfc_inventory.j2 + dest: "{{ inv_file_path }}" + delegate_to: localhost + +- name: Create Empty inv_config Var + ansible.builtin.set_fact: + inv_config: [] + delegate_to: localhost + +- name: Set inv_config Var + ansible.builtin.set_fact: + inv_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.isn.topology.switches | default([])) | length > 0 + delegate_to: localhost + +- name: Retrieve NDFC Device Username and Password from Group Vars and update inv_config + cisco.nac_dc_vxlan.common.get_credentials: + inv_list: "{{ inv_config }}" + register: updated_inv_config + no_log: true + +- name: Credential Retrieval Failed + ansible.builtin.fail: + msg: "{{ updated_inv_config }}" + when: updated_inv_config['retrieve_failed'] + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_inventory: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 67293f417..425e2cfd6 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -26,6 +26,11 @@ tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' +- name: Import Role Tasks for ISN Fabric + ansible.builtin.import_tasks: sub_main_isn.yml + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric.type == 'ISN' + - name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml diff --git a/roles/dtc/common/tasks/msd/ndfc_networks.yml b/roles/dtc/common/tasks/msd/ndfc_networks.yml new file mode 100644 index 000000000..0f024b8fa --- /dev/null +++ b/roles/dtc/common/tasks/msd/ndfc_networks.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_networks: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_networks.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Networks Attach List From Template + ansible.builtin.template: + src: ndfc_attach_networks.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set net_config Var + ansible.builtin.set_fact: + net_config: [] + delegate_to: localhost + +- name: Set net_config Var + ansible.builtin.set_fact: + net_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.overlay.networks | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_networks: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml new file mode 100644 index 000000000..ce693ece4 --- /dev/null +++ b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_vrfs: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_vrfs.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build VRFs Attach List From Template + ansible.builtin.template: + src: ndfc_attach_vrfs.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Create Empty vrf_config Var + ansible.builtin.set_fact: + vrf_config: [] + delegate_to: localhost + +- name: Set vrf_config Var + ansible.builtin.set_fact: + vrf_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_vrfs: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml new file mode 100644 index 000000000..c7640485f --- /dev/null +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -0,0 +1,48 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- ansible.builtin.fail: msg="Service Model Not Defined. Role cisco.nac_dc_vxlan.validate Must Be Called First" + when: MD is undefined + delegate_to: localhost + +# -------------------------------------------------------------------- +# Remove all files from the previous run if run_map requires it +# -------------------------------------------------------------------- +- name: Cleanup Files from Previous Run if run_map requires it + ansible.builtin.include_tasks: cleanup_files.yml + when: + - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) + +# -------------------------------------------------------------------- +# Build Create Fabric Parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.include_tasks: isn/ndfc_fabric.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Switch Inventory List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Switch Inventory List From Template + ansible.builtin.include_tasks: isn/ndfc_inventory.yml diff --git a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml index 5437b7c21..ef9714cfd 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml @@ -64,7 +64,9 @@ - name: Set net_config Var ansible.builtin.set_fact: net_config: "{{ lookup('file', file_name) | from_yaml }}" - when: (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + when: > + (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 or + (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index 2ea68d179..ac9a3be00 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -64,7 +64,9 @@ - name: Set vrf_config Var ansible.builtin.set_fact: vrf_config: "{{ lookup('file', file_name) | from_yaml }}" - when: (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + when: > + (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 or + (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index 5c1b576c0..2ffbcc154 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -13,7 +13,10 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_fabric/msd_fabric/msd_fabric_base.j2' %} -{% else %} +{% elif vxlan.fabric.type == 'ISN'%} -{# Supported fabric types are: DC VXLAN EVPN, MSD #} +{# Include NDFC ISN Base Template #} +{% include '/ndfc_fabric/isn_fabric/isn_fabric_base.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN, MSD, and ISN #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/isn_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/isn_fabric_advanced.j2 new file mode 100644 index 000000000..ea5a13cc5 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/advanced/isn_fabric_advanced.j2 @@ -0,0 +1,10 @@ +{# Auto-generated NDFC ISN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} + POWER_REDUNDANCY_MODE: ps-redundant +{# Not supporting these features in ISN currently #} +{# Most of these features are supported only on Cisco NX-OS switches #} +{# Some of these features are supported only on Cisco Catalyst 9000 switches #} + MPLS_HANDOFF: false + AAA_REMOTE_IP_ENABLED: false + INBAND_MGMT: false + FEATURE_PTP: false +{# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 new file mode 100644 index 000000000..73889b0b0 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 @@ -0,0 +1,19 @@ +{# Auto-generated NDFC ISN Bootstrap config data structure for fabric {{ vxlan.fabric.name }} #} +{# Most of these features are supported only on Cisco NX-OS switches #} +{# Some of these features are supported only on Cisco Catalyst 9000 switches #} +{% if vxlan.multisite.isn.bootstrap is defined %} +{% if (vxlan.multisite.isn.bootstrap.enable_bootstrap is defined and vxlan.multisite.isn.bootstrap.enable_bootstrap | bool) or defaults.vxlan.multisite.isn.bootstrap.enable_bootstrap | bool %} + BOOTSTRAP_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_bootstrap | default(defaults.vxlan.multisite.isn.bootstrap.enable_bootstrap) | bool }} + INBAND_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_inband | default(defaults.vxlan.multisite.isn.bootstrap.enable_inband) | bool }} + DHCP_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_local_dhcp_server | default(defaults.vxlan.multisite.isn.bootstrap.enable_local_dhcp_server) | bool }} + DHCP_IPV6_ENABLE: {{ vxlan.multisite.isn.bootstrap.dhcp_version | default(defaults.vxlan.multisite.isn.bootstrap.dhcp_version) }} + DHCP_START: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.scope_start_address }} + DHCP_END: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.scope_end_address }} + MGMT_GW: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.switch_mgmt_default_gw }} + MGMT_PREFIX: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.mgmt_prefix }} + BOOTSTRAP_MULTISUBNET: "{{ vxlan.multisite.isn.bootstrap.dhcp_v4.multi_subnet_scope }}" + ENABLE_AAA: {{ vxlan.multisite.isn.bootstrap.enable_aaa | default(defaults.vxlan.multisite.isn.bootstrap.enable_aaa) | bool }} +{% endif %} +{% else %} + BOOTSTRAP_ENABLE: false +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 new file mode 100644 index 000000000..75e95771a --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 @@ -0,0 +1,28 @@ +{# Auto-generated NDFC ISN Flow Monitor config data structure for fabric {{ vxlan.fabric.name }} #} + ENABLE_NETFLOW: {{ vxlan.multisite.isn.netflow.enable | default(defaults.vxlan.multisite.isn.netflow.enable) }} +{% if vxlan.multisite.isn.netflow.enable is defined and vxlan.multisite.isn.netflow.enable | bool or defaults.vxlan.multisite.isn.netflow.enable | bool %} +{% if vxlan.multisite.isn.netflow.exporter is defined %} +{% set exporter_dict = dict() %} +{% set _ = exporter_dict.update({ "NETFLOW_EXPORTER_LIST":[] }) %} +{% for e in vxlan.multisite.isn.netflow.exporter %} +{% set _ = exporter_dict["NETFLOW_EXPORTER_LIST"].append(dict(EXPORTER_NAME=e.name,IP=e.ip_address,VRF=e.vrf | default(""), SRC_IF_NAME=e.source_interface,UDP_PORT=e.udp_port)) %} +{% endfor %} + NETFLOW_EXPORTER_LIST: "{{ exporter_dict | tojson | replace('"', '\\"') }}" +{% endif %} +{% if vxlan.multisite.isn.netflow.record is defined %} +{% set record_dict = dict() %} +{% set _ = record_dict.update({ "NETFLOW_RECORD_LIST":[] }) %} +{% for r in vxlan.multisite.isn.netflow.record %} +{% set _ = record_dict["NETFLOW_RECORD_LIST"].append(dict(RECORD_NAME=r.name,RECORD_TEMPLATE =r.template,LAYER2_RECORD=r.layer2 | default(false) | string | lower)) %} +{% endfor %} + NETFLOW_RECORD_LIST: "{{ record_dict | tojson | replace('"', '\\"') }}" +{% endif %} +{% if vxlan.multisite.isn.netflow.monitor is defined %} +{% set monitor_dict = dict() %} +{% set _ = monitor_dict.update({ "NETFLOW_MONITOR_LIST":[] }) %} +{% for m in vxlan.multisite.isn.netflow.monitor %} +{% set _ = monitor_dict["NETFLOW_MONITOR_LIST"].append(dict(MONITOR_NAME=m.name,RECORD_NAME=m.record,EXPORTER1=m.exporter1,EXPORTER2=m.exporter2 | default(""))) %} +{% endfor %} + NETFLOW_MONITOR_LIST: "{{ monitor_dict | tojson | replace('"', '\\"') }}" +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2 new file mode 100644 index 000000000..b74cf2d7d --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2 @@ -0,0 +1,4 @@ +{# Auto-generated NDFC ISN General config data structure for fabric {{ vxlan.fabric.name }} #} + BGP_AS: {{ vxlan.multisite.isn.bgp_asn }} + IS_READ_ONLY: false +{# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 new file mode 100644 index 000000000..b7ad1e745 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 @@ -0,0 +1,19 @@ +{# Auto-generated NDFC ISN Base config data structure for fabric {{ vxlan.fabric.name }} #} +- FABRIC_NAME: {{ vxlan.fabric.name }} + FABRIC_TYPE: ISN + DEPLOY: True + +{# Include NDFC ISN General Template #} +{% include '/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2' %} + +{# Include NDFC ISN Advanced Template #} +{% include '/ndfc_fabric/isn_fabric/advanced/isn_fabric_advanced.j2' %} + +{# Include NDFC ISN Resources Template #} +{% include '/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2' %} + +{# Include NDFC ISN Bootstrap Template #} +{# {% include '/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2' %} #} + +{# Include NDFC ISN Flow Monitor Template #} +{% include '/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2 new file mode 100644 index 000000000..693ada97b --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2 @@ -0,0 +1,2 @@ +{# Auto-generated NDFC ISN Resources config data structure for fabric {{ vxlan.fabric.name }} #} + SUBINTERFACE_RANGE: {{ vxlan.multisite.isn.sub_int_range | default(defaults.vxlan.multisite.isn.sub_int_range) | title }} diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json new file mode 100644 index 000000000..215a2d90c --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json @@ -0,0 +1,86 @@ +{ + "fabricName": "ISN", + "templateName": "External_Fabric", + "nvPairs": { + "FABRIC_NAME": "ISN", + "BGP_AS": "65000", + "PM_ENABLE": "false", + "EXT_FABRIC_TYPE": "Multi-Site External Network", + "PM_ENABLE_PREV": "false", + "INBAND_MGMT_PREV": "false", + "FEATURE_PTP_INTERNAL": "false", + "DEPLOYMENT_FREEZE": "false", + "LOOPBACK0_IP_RANGE": "10.1.0.0/22", + "FABRIC_TYPE": "External", + "FF": "External", + "MSO_SITE_ID": "", + "MSO_CONTROLER_ID": "", + "MSO_SITE_GROUP_NAME": "", + "PREMSO_PARENT_FABRIC": "", + "MSO_CONNECTIVITY_DEPLOYED": "", + "INBAND_ENABLE_PREV": "false", + "DCI_SUBNET_RANGE": "10.10.1.0/24", + "DCI_SUBNET_TARGET_MASK": "30", + "ENABLE_NETFLOW_PREV": "", + "ALLOW_NXC": "true", + "ALLOW_NXC_PREV": "", + "OVERWRITE_GLOBAL_NXC": "false", + "NXC_DEST_VRF": "management", + "NXC_SRC_INTF": "", + "NXC_PROXY_SERVER": "", + "NXC_PROXY_PORT": "8080", + "DHCP_START_INTERNAL": "", + "DHCP_END_INTERNAL": "", + "MGMT_GW_INTERNAL": "", + "MGMT_PREFIX_INTERNAL": "", + "BOOTSTRAP_MULTISUBNET_INTERNAL": "", + "MGMT_V6PREFIX_INTERNAL": "", + "DHCP_IPV6_ENABLE_INTERNAL": "", + "DOMAIN_NAME_INTERNAL": "", + "PNP_ENABLE_INTERNAL": "", + "POWER_REDUNDANCY_MODE": "ps-redundant", + "MPLS_HANDOFF": "false", + "MPLS_LB_ID": "", + "AAA_REMOTE_IP_ENABLED": "false", + "SNMP_SERVER_HOST_TRAP": "true", + "CDP_ENABLE": "false", + "ENABLE_NXAPI": "false", + "NXAPI_HTTPS_PORT": "", + "ENABLE_NXAPI_HTTP": false, + "NXAPI_HTTP_PORT": "", + "INBAND_MGMT": "false", + "FEATURE_PTP": "false", + "PTP_LB_ID": "", + "PTP_DOMAIN_ID": "", + "ENABLE_RT_INTF_STATS": "false", + "INTF_STAT_LOAD_INTERVAL": "", + "FABRIC_FREEFORM": "", + "AAA_SERVER_CONF": "", + "SUBINTERFACE_RANGE": "2-511", + "MPLS_LOOPBACK_IP_RANGE": "", + "enableRealTimeBackup": "", + "enableScheduledBackup": "", + "scheduledTime": "", + "INBAND_ENABLE": false, + "DHCP_ENABLE": false, + "PNP_ENABLE": false, + "DHCP_IPV6_ENABLE": "", + "DOMAIN_NAME": "", + "DHCP_START": "", + "DHCP_END": "", + "MGMT_GW": "", + "MGMT_PREFIX": "", + "MGMT_V6PREFIX": "", + "ENABLE_AAA": false, + "BOOTSTRAP_CONF": "", + "BOOTSTRAP_CONF_XE": "", + "BOOTSTRAP_MULTISUBNET": "", + "ENABLE_NETFLOW": "false", + "NETFLOW_EXPORTER_LIST": "", + "NETFLOW_RECORD_LIST": "", + "NETFLOW_MONITOR_LIST": "", + "NETFLOW_SAMPLER_LIST": "", + "IS_READ_ONLY": false, + "BOOTSTRAP_ENABLE": "false" + } +} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 7d2b89bfe..895f85058 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -1,35 +1,17 @@ --- -# This NDFC switch inventory config data structure is auto-generated -# DO NOT EDIT MANUALLY -# -{% set poap_data = poap_data['poap_data'] %} -{% for switch in MD_Extended.vxlan.topology.switches %} -{% if switch.management.management_ipv4_address is defined %} -- seed_ip: {{ switch['management']['management_ipv4_address'] }} -{% elif switch.management.management_ipv6_address is defined %} -- seed_ip: {{ switch['management']['management_ipv6_address'] }} -{% endif %} - auth_proto: {{ MD['vxlan']['global']['auth_proto'] | default(defaults.vxlan.global.auth_proto) }} - user_name: PLACE_HOLDER_USERNAME - password: PLACE_HOLDER_PASSWORD - max_hops: 0 # this is the default value as it is not defined into the data model - role: {{ switch['role'] }} - preserve_config: false -{% if MD_Extended.vxlan.global.bootstrap is defined %} -{% if MD_Extended.vxlan.global.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.global.bootstrap.enable_bootstrap %} -{% if switch.poap is defined and switch.poap.bootstrap %} -{% if poap_data[switch['serial_number']] is defined %} -{% set pdata = poap_data[switch['serial_number']] %} - poap: - - serial_number: {{ switch['serial_number'] }} - hostname: {{ switch['name'] }} - model: {{ pdata['model'] }} - version: {{ pdata['version'] }} - config_data: - modulesModel: {{ pdata['modulesModel'] }} - gateway: {{ pdata['gateway'] }} -{% endif %} -{% endif %} -{% endif %} -{% endif %} -{% endfor %} \ No newline at end of file +{#- This NDFC fabric config data structure is auto-generated #} +{#- DO NOT EDIT MANUALLY #} + +{% set vxlan = MD_Extended.vxlan %} +{% if vxlan.fabric.type == 'VXLAN_EVPN' %} + +{# Include NDFC DC VXLAN EVPN Base Template #} +{% include '/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2' %} + +{% elif vxlan.fabric.type == 'ISN'%} + +{# Include NDFC ISN Base Template #} +{% include '/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN and ISN #} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory/.gitkeep b/roles/dtc/common/templates/ndfc_inventory/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 new file mode 100644 index 000000000..e2482e42f --- /dev/null +++ b/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 @@ -0,0 +1,32 @@ +{# Auto-generated NDFC DC VXLAN EVPN Inventory config data structure for fabric {{ vxlan.fabric.name }} #} +{% set poap_data = poap_data['poap_data'] %} +{% for switch in MD_Extended.vxlan.topology.switches %} +{% if switch.management.management_ipv4_address is defined %} +- seed_ip: {{ switch['management']['management_ipv4_address'] }} +{% elif switch.management.management_ipv6_address is defined %} +- seed_ip: {{ switch['management']['management_ipv6_address'] }} +{% endif %} + auth_proto: {{ MD['vxlan']['global']['auth_proto'] | default(defaults.vxlan.global.auth_proto) }} + user_name: PLACE_HOLDER_USERNAME + password: PLACE_HOLDER_PASSWORD + max_hops: 0 # this is the default value as it is not defined into the data model + role: {{ switch['role'] }} + preserve_config: false +{% if MD_Extended.vxlan.global.bootstrap is defined %} +{% if MD_Extended.vxlan.global.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.global.bootstrap.enable_bootstrap %} +{% if switch.poap is defined and switch.poap.bootstrap %} +{% if poap_data[switch['serial_number']] is defined %} +{% set pdata = poap_data[switch['serial_number']] %} + poap: + - serial_number: {{ switch['serial_number'] }} + hostname: {{ switch['name'] }} + model: {{ pdata['model'] }} + version: {{ pdata['version'] }} + config_data: + modulesModel: {{ pdata['modulesModel'] }} + gateway: {{ pdata['gateway'] }} +{% endif %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory/isn_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_inventory/isn_fabric/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 new file mode 100644 index 000000000..dbe6eb183 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 @@ -0,0 +1,33 @@ +{# Auto-generated NDFC ISN Inventory config data structure for fabric {{ vxlan.fabric.name }} #} +{% set poap_data = poap_data['poap_data'] %} +{% for switch in MD_Extended.vxlan.multisite.isn.topology.switches %} +{% if switch.management.management_ipv4_address is defined %} +- seed_ip: {{ switch['management']['management_ipv4_address'] }} +{% elif switch.management.management_ipv6_address is defined %} +- seed_ip: {{ switch['management']['management_ipv6_address'] }} +{% endif %} + deviceType: NX-OS + auth_proto: {{ MD['vxlan']['global']['auth_proto'] | default(defaults.vxlan.global.auth_proto) }} + user_name: PLACE_HOLDER_USERNAME + password: PLACE_HOLDER_PASSWORD + max_hops: 0 # this is the default value as it is not defined into the data model + role: core_router + preserve_config: true +{% if MD_Extended.vxlan.multisite.isn.bootstrap is defined %} +{% if MD_Extended.vxlan.multisite.isn.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.multisite.isn.bootstrap.enable_bootstrap %} +{% if switch.poap is defined and switch.poap.bootstrap %} +{% if poap_data[switch['serial_number']] is defined %} +{% set pdata = poap_data[switch['serial_number']] %} + poap: + - serial_number: {{ switch['serial_number'] }} + hostname: {{ switch['name'] }} + model: {{ pdata['model'] }} + version: {{ pdata['version'] }} + config_data: + modulesModel: {{ pdata['modulesModel'] }} + gateway: {{ pdata['gateway'] }} +{% endif %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/roles/dtc/create/tasks/isn/devices.yml b/roles/dtc/create/tasks/isn/devices.yml new file mode 100644 index 000000000..fc7dee548 --- /dev/null +++ b/roles/dtc/create/tasks/isn/devices.yml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Devices Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage Devices Discovery + ansible.builtin.include_tasks: devices_discovery.yml diff --git a/roles/dtc/create/tasks/isn/devices_discovery.yml b/roles/dtc/create/tasks/isn/devices_discovery.yml new file mode 100644 index 000000000..11ed62d47 --- /dev/null +++ b/roles/dtc/create/tasks/isn/devices_discovery.yml @@ -0,0 +1,60 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} + cisco.dcnm.dcnm_inventory: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ updated_inv_config['updated_inv_list'] }}" + deploy: false + save: true + state: merged + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: MD_Extended.vxlan.multisite.isn.topology.switches | length > 0 + +- name: Create List of Switch Serial Numbers from Data Model + ansible.builtin.set_fact: + md_serial_numbers: "{{ MD_Extended.vxlan.multisite.isn.topology.switches | map(attribute='serial_number') | list }}" + delegate_to: localhost + +- name: Build Switch Hostname Policy Payload from Data Model Update + cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy: + model_data: "{{ MD_Extended }}" + switch_serial_numbers: "{{ md_serial_numbers }}" + template_name: host_11_1 + register: results +# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + +- name: Join List of Switch Hostname Policy IDs from NDFC + ansible.builtin.set_fact: + policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}" + when: results.policy_update | length > 0 + delegate_to: localhost + +- name: Update Switch Hostname Policy in NDFC + cisco.dcnm.dcnm_rest: + method: PUT + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" + json_data: "{{ results.policy_update.values() | list | to_json }}" + when: results.policy_update | length > 0 diff --git a/roles/dtc/create/tasks/isn/fabric.yml b/roles/dtc/create/tasks/isn/fabric.yml new file mode 100644 index 000000000..e810c30d3 --- /dev/null +++ b/roles/dtc/create/tasks/isn/fabric.yml @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC + cisco.dcnm.dcnm_fabric: + state: merged + config: "{{ fabric_config }}" diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index be015e3b8..997264de0 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -27,6 +27,10 @@ - MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy +- name: Import ISN Role Tasks + ansible.builtin.import_tasks: sub_main_isn.yml + when: MD_Extended.vxlan.fabric.type == 'ISN' + - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml when: MD_Extended.vxlan.fabric.type == 'MSD' diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml index 31677c764..f124150b4 100644 --- a/roles/dtc/create/tasks/msd/child_fabrics.yml +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -34,9 +34,12 @@ path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations register: fabric_associations -- name: Move Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} - cisco.nac_dc_vxlan.dtc.move_child_fabrics: +- ansible.builtin.debug: + var: fabric_associations + +- name: Add Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} + cisco.nac_dc_vxlan.dtc.manage_child_fabrics: fabric_associations: "{{ fabric_associations }}" parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" - when: fabric_associations is defined + when: fabric_associations is defined and fabric_associations diff --git a/roles/dtc/create/tasks/msd/vrfs_networks.yml b/roles/dtc/create/tasks/msd/vrfs_networks.yml new file mode 100644 index 000000000..2be757e42 --- /dev/null +++ b/roles/dtc/create/tasks/msd/vrfs_networks.yml @@ -0,0 +1,58 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage VRFs and Networks Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage VRFs and Networks Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Fabric VRFs + cisco.dcnm.dcnm_vrf: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vrf_config }}" + register: manage_vrf_result + when: + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs + - changes_detected_vrfs + + +# -------------------------------------------------------------------- +# Manage Network Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Fabric Networks + cisco.dcnm.dcnm_network: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ net_config }}" + register: manage_network_result + when: + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - changes_detected_networks diff --git a/roles/dtc/create/tasks/sub_main_isn.yml b/roles/dtc/create/tasks/sub_main_isn.yml new file mode 100644 index 000000000..e7d799d28 --- /dev/null +++ b/roles/dtc/create/tasks/sub_main_isn.yml @@ -0,0 +1,48 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.create] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml + +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.create }}" + +- name: Create NDFC ISN Fabric + ansible.builtin.import_tasks: isn/fabric.yml + when: + - MD_Extended.vxlan.fabric.name is defined + - MD_Extended.vxlan.fabric.type == "ISN" + - changes_detected_fabric + tags: "{{ nac_tags.create_fabric }}" + +- name: Manage NDFC ISN Fabric Switches + ansible.builtin.import_tasks: isn/devices.yml + when: + - MD_Extended.vxlan.multisite.isn.topology.switches | length > 0 + - changes_detected_inventory + tags: "{{ nac_tags.create_switches }}" diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 8ee865a55..10af9cdb9 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -46,3 +46,13 @@ - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 # - changes_detected_inventory # tags: "{{ nac_tags.create_switches }}" + +- ansible.builtin.meta: end_play + +- name: Manage NDFC Fabric VRFs and Networks + ansible.builtin.import_tasks: msd/vrfs_networks.yml + when: > + MD_Extended.vxlan.multisite.overlay is defined and + MD_Extended.vxlan.multisite.topology.switches | length > 0 and + (changes_detected_vrfs or changes_detected_networks) + tags: "{{ nac_tags.create_vrfs_networks }}" diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index 494ecc9ea..ac7415ae1 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -64,14 +64,15 @@ - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: vxlan/vrfs_networks.yml - when: - - (MD.vxlan.overlay_services is defined) and (MD_Extended.vxlan.topology.switches | length > 0) - - changes_detected_vrfs or changes_detected_networks + when: > + (MD_Extended.vxlan.overlay_services is defined or MD_Extended.vxlan.overlay is defined) and + MD_Extended.vxlan.topology.switches | length > 0 and + (changes_detected_vrfs or changes_detected_networks) tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Policies ansible.builtin.import_tasks: vxlan/policies.yml - when: + when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - changes_detected_policy tags: "{{ nac_tags.create_policy }}" diff --git a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml index 025c486bb..9e6b27c34 100644 --- a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml +++ b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml @@ -37,11 +37,10 @@ state: replaced config: "{{ vrf_config }}" register: manage_vrf_result - when: - - MD.vxlan.overlay_services.vrfs is defined - - MD.vxlan.overlay_services.vrfs - - changes_detected_vrfs - + when: > + (MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs) or + (MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs) and + changes_detected_vrfs # -------------------------------------------------------------------- # Manage Network Configuration on NDFC @@ -52,7 +51,7 @@ state: replaced config: "{{ net_config }}" register: manage_network_result - when: - - MD.vxlan.overlay_services.networks is defined - - MD.vxlan.overlay_services.networks - - changes_detected_networks + when: > + (MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks) or + (MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks) and + changes_detected_networks diff --git a/roles/dtc/deploy/tasks/sub_main.yml b/roles/dtc/deploy/tasks/sub_main.yml index 27464d917..7c176ea84 100644 --- a/roles/dtc/deploy/tasks/sub_main.yml +++ b/roles/dtc/deploy/tasks/sub_main.yml @@ -34,7 +34,10 @@ cisco.dcnm.dcnm_rest: method: POST path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" - when: MD_Extended.vxlan.topology.switches | length > 0 + when: > + (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0) or + (MD_Extended.vxlan.multisite.isn.topology.switches is defined and MD_Extended.vxlan.multisite.isn.topology.switches | length > 0) or + MD_Extended.vxlan.fabric.type == 'MSD' # TODO: Need to add logic to only save if changes are made - name: Deploy for Fabric {{ MD_Extended.vxlan.fabric.name }} @@ -44,5 +47,8 @@ vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 - when: MD_Extended.vxlan.topology.switches | length > 0 + when: > + (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0) or + (MD_Extended.vxlan.multisite.isn.topology.switches is defined and MD_Extended.vxlan.multisite.isn.topology.switches | length > 0) or + MD_Extended.vxlan.fabric.type == 'MSD' # TODO: Need to add logic to only deploy if changes are made diff --git a/roles/dtc/remove/tasks/msd/child_fabrics.yml b/roles/dtc/remove/tasks/msd/child_fabrics.yml new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/remove/tasks/msd/networks.yml b/roles/dtc/remove/tasks/msd/networks.yml new file mode 100644 index 000000000..706fa9efe --- /dev/null +++ b/roles/dtc/remove/tasks/msd/networks.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Remove Unmanaged Fabric Networks + cisco.dcnm.dcnm_network: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: overridden + config: "{{ net_config }}" + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - switch_list.response.DATA | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "---------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" + - "---------------------------------------------------------------------------------------------------------------" + when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/msd/vrfs.yml b/roles/dtc/remove/tasks/msd/vrfs.yml new file mode 100644 index 000000000..68bce074e --- /dev/null +++ b/roles/dtc/remove/tasks/msd/vrfs.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Remove Unmanaged Fabric VRFs + cisco.dcnm.dcnm_vrf: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: overridden + config: "{{ vrf_config }}" + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - switch_list.response.DATA | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "--------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" + - "--------------------------------------------------------------------------------------------------------" + when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/sub_main_msd.yml b/roles/dtc/remove/tasks/sub_main_msd.yml index f4d2e7e69..26558c586 100644 --- a/roles/dtc/remove/tasks/sub_main_msd.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -20,3 +20,15 @@ # SPDX-License-Identifier: MIT --- + +- name: Remove Fabric Networks + ansible.builtin.import_tasks: msd/networks.yml + tags: "{{ nac_tags.remove_networks }}" + when: + - changes_detected_networks + +- name: Remove Fabric VRFs + ansible.builtin.import_tasks: msd/vrfs.yml + tags: "{{ nac_tags.remove_vrfs }}" + when: + - changes_detected_vrfs diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 5918c7cd8..452e5a8a7 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -290,3 +290,13 @@ factory_defaults: delay_restore: 300 enable_ebgp_password: false enable_trm: false + isn: + sub_int_range: 2-511 + bootstrap: + enable_bootstrap: false + enable_inband: false + enable_local_dhcp_server: false + dhcp_version: DHCPv4 + enable_aaa: false + netflow: + enable: false diff --git a/roles/validate/files/rules/isn/.gitkeep b/roles/validate/files/rules/isn/.gitkeep new file mode 100644 index 000000000..e69de29bb From 15655e75d29a736588ec0bb78ccb87bd7574a62c Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 9 Dec 2024 00:26:44 -0500 Subject: [PATCH 022/183] updates for remove child fabrics and isn --- plugins/action/dtc/manage_child_fabrics.py | 98 ++++++++++++++++--- .../dtc/update_switch_hostname_policy.py | 1 + .../ndfc_fabric/isn_fabric/temp.json | 86 ---------------- roles/dtc/create/tasks/msd/child_fabrics.yml | 1 + roles/dtc/create/tasks/sub_main_msd.yml | 4 - roles/dtc/remove/tasks/msd/child_fabrics.yml | 42 ++++++++ roles/dtc/remove/tasks/sub_main_msd.yml | 24 +++-- 7 files changed, 143 insertions(+), 113 deletions(-) delete mode 100644 roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index 1e7eb14e2..e2793bfcd 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -39,6 +39,7 @@ def run(self, tmp=None, task_vars=None): fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') parent_fabric_name = self._task.args['parent_fabric_name'] child_fabrics = self._task.args['child_fabrics'] + operation = self._task.args['operation'] # Build a list of child fabrics that are associated with the parent fabric associated_child_fabrics = [] @@ -46,19 +47,49 @@ def run(self, tmp=None, task_vars=None): if fabric.get('fabricParent') == parent_fabric_name: associated_child_fabrics.append(fabric.get('fabricName')) - for fabric in child_fabrics: - if fabric.get('name') not in associated_child_fabrics: - json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, fabric.get('name')) - add_fabric_result = self._execute_module( - module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "POST", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", - "json_data": json_data - }, - task_vars=task_vars, - tmp=tmp - ) + if operation == 'add': + for fabric in child_fabrics: + if fabric.get('name') not in associated_child_fabrics: + json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, fabric.get('name')) + add_fabric_result = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "POST", + "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", + "json_data": json_data + }, + task_vars=task_vars, + tmp=tmp + ) + + if add_fabric_result.get('failed'): + results['failed'] = True + results['msg'] = f"{add_fabric_result['msg']['MESSAGE']}: {add_fabric_result['msg']['DATA']}" + break + + results['changed'] = True + + if operation == 'remove': + for associated_child_fabric in associated_child_fabrics: + if not any(associated_child_fabric == child_fabric['name'] for child_fabric in child_fabrics): + json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, associated_child_fabric) + remove_fabric_result = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "POST", + "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit", + "json_data": json_data + }, + task_vars=task_vars, + tmp=tmp + ) + + if remove_fabric_result.get('failed'): + results['failed'] = True + results['msg'] = f"{remove_fabric_result['msg']['MESSAGE']}: {remove_fabric_result['msg']['DATA']}" + break + + results['changed'] = True return results @@ -70,6 +101,47 @@ def run(self, tmp=None, task_vars=None): # https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations/ # GET +# Response: +# "response": { +# "DATA": [ +# { +# "fabricId": 2, +# "fabricName": "nac-fabric1", +# "fabricParent": "None", +# "fabricState": "standalone", +# "fabricTechnology": "VXLANFabric", +# "fabricType": "Switch_Fabric" +# }, +# { +# "fabricId": 3, +# "fabricName": "nac-fabric2", +# "fabricParent": "nac-msd1", +# "fabricState": "member", +# "fabricTechnology": "VXLANFabric", +# "fabricType": "Switch_Fabric" +# }, +# { +# "fabricId": 4, +# "fabricName": "nac-isn1", +# "fabricParent": "None", +# "fabricState": "standalone", +# "fabricTechnology": "External", +# "fabricType": "External" +# }, +# { +# "fabricId": 5, +# "fabricName": "nac-msd1", +# "fabricParent": "None", +# "fabricState": "msd", +# "fabricTechnology": "VXLANFabric", +# "fabricType": "MSD" +# } +# ], +# "MESSAGE": "OK", +# "METHOD": "GET", +# "REQUEST_PATH": "https://10.15.0.110:443/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", +# "RETURN_CODE": 200 +# } # https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd # POST diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index 574dfe755..f660e99b0 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -58,6 +58,7 @@ def run(self, tmp=None, task_vars=None): switch_match = next((item for item in dm_switches if item["serial_number"] == switch_serial_number)) if policy_match["nvPairs"]["SWITCH_NAME"] != switch_match["name"]: + results['changed'] = True policy_match["nvPairs"]["SWITCH_NAME"] = switch_match["name"] policy_update.update({switch_serial_number: policy_match}) diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json deleted file mode 100644 index 215a2d90c..000000000 --- a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/temp.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "fabricName": "ISN", - "templateName": "External_Fabric", - "nvPairs": { - "FABRIC_NAME": "ISN", - "BGP_AS": "65000", - "PM_ENABLE": "false", - "EXT_FABRIC_TYPE": "Multi-Site External Network", - "PM_ENABLE_PREV": "false", - "INBAND_MGMT_PREV": "false", - "FEATURE_PTP_INTERNAL": "false", - "DEPLOYMENT_FREEZE": "false", - "LOOPBACK0_IP_RANGE": "10.1.0.0/22", - "FABRIC_TYPE": "External", - "FF": "External", - "MSO_SITE_ID": "", - "MSO_CONTROLER_ID": "", - "MSO_SITE_GROUP_NAME": "", - "PREMSO_PARENT_FABRIC": "", - "MSO_CONNECTIVITY_DEPLOYED": "", - "INBAND_ENABLE_PREV": "false", - "DCI_SUBNET_RANGE": "10.10.1.0/24", - "DCI_SUBNET_TARGET_MASK": "30", - "ENABLE_NETFLOW_PREV": "", - "ALLOW_NXC": "true", - "ALLOW_NXC_PREV": "", - "OVERWRITE_GLOBAL_NXC": "false", - "NXC_DEST_VRF": "management", - "NXC_SRC_INTF": "", - "NXC_PROXY_SERVER": "", - "NXC_PROXY_PORT": "8080", - "DHCP_START_INTERNAL": "", - "DHCP_END_INTERNAL": "", - "MGMT_GW_INTERNAL": "", - "MGMT_PREFIX_INTERNAL": "", - "BOOTSTRAP_MULTISUBNET_INTERNAL": "", - "MGMT_V6PREFIX_INTERNAL": "", - "DHCP_IPV6_ENABLE_INTERNAL": "", - "DOMAIN_NAME_INTERNAL": "", - "PNP_ENABLE_INTERNAL": "", - "POWER_REDUNDANCY_MODE": "ps-redundant", - "MPLS_HANDOFF": "false", - "MPLS_LB_ID": "", - "AAA_REMOTE_IP_ENABLED": "false", - "SNMP_SERVER_HOST_TRAP": "true", - "CDP_ENABLE": "false", - "ENABLE_NXAPI": "false", - "NXAPI_HTTPS_PORT": "", - "ENABLE_NXAPI_HTTP": false, - "NXAPI_HTTP_PORT": "", - "INBAND_MGMT": "false", - "FEATURE_PTP": "false", - "PTP_LB_ID": "", - "PTP_DOMAIN_ID": "", - "ENABLE_RT_INTF_STATS": "false", - "INTF_STAT_LOAD_INTERVAL": "", - "FABRIC_FREEFORM": "", - "AAA_SERVER_CONF": "", - "SUBINTERFACE_RANGE": "2-511", - "MPLS_LOOPBACK_IP_RANGE": "", - "enableRealTimeBackup": "", - "enableScheduledBackup": "", - "scheduledTime": "", - "INBAND_ENABLE": false, - "DHCP_ENABLE": false, - "PNP_ENABLE": false, - "DHCP_IPV6_ENABLE": "", - "DOMAIN_NAME": "", - "DHCP_START": "", - "DHCP_END": "", - "MGMT_GW": "", - "MGMT_PREFIX": "", - "MGMT_V6PREFIX": "", - "ENABLE_AAA": false, - "BOOTSTRAP_CONF": "", - "BOOTSTRAP_CONF_XE": "", - "BOOTSTRAP_MULTISUBNET": "", - "ENABLE_NETFLOW": "false", - "NETFLOW_EXPORTER_LIST": "", - "NETFLOW_RECORD_LIST": "", - "NETFLOW_MONITOR_LIST": "", - "NETFLOW_SAMPLER_LIST": "", - "IS_READ_ONLY": false, - "BOOTSTRAP_ENABLE": "false" - } -} \ No newline at end of file diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml index f124150b4..61afd99ae 100644 --- a/roles/dtc/create/tasks/msd/child_fabrics.yml +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -42,4 +42,5 @@ fabric_associations: "{{ fabric_associations }}" parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" + operation: add when: fabric_associations is defined and fabric_associations diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 10af9cdb9..271c09813 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -44,10 +44,6 @@ ansible.builtin.import_tasks: msd/child_fabrics.yml when: - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 - # - changes_detected_inventory - # tags: "{{ nac_tags.create_switches }}" - -- ansible.builtin.meta: end_play - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: msd/vrfs_networks.yml diff --git a/roles/dtc/remove/tasks/msd/child_fabrics.yml b/roles/dtc/remove/tasks/msd/child_fabrics.yml index e69de29bb..2dea537f9 100644 --- a/roles/dtc/remove/tasks/msd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/msd/child_fabrics.yml @@ -0,0 +1,42 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Child Fabrics. This could take several minutes..." + when: + - MD_Extended.vxlan.multisite.child_fabrics is defined + - MD_Extended.vxlan.multisite.child_fabrics | length > 0 + - (child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool) + +- name: Get Fabric Association Data from NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations + register: fabric_associations + +- name: Remove Unmanaged Child Fabrics from NDFC + cisco.nac_dc_vxlan.dtc.manage_child_fabrics: + fabric_associations: "{{ fabric_associations }}" + parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" + child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" + operation: remove + when: fabric_associations is defined and fabric_associations diff --git a/roles/dtc/remove/tasks/sub_main_msd.yml b/roles/dtc/remove/tasks/sub_main_msd.yml index 26558c586..072e61f5d 100644 --- a/roles/dtc/remove/tasks/sub_main_msd.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -21,14 +21,18 @@ --- -- name: Remove Fabric Networks - ansible.builtin.import_tasks: msd/networks.yml - tags: "{{ nac_tags.remove_networks }}" - when: - - changes_detected_networks +# - name: Remove Fabric Networks +# ansible.builtin.import_tasks: msd/networks.yml +# tags: "{{ nac_tags.remove_networks }}" +# when: +# - changes_detected_networks -- name: Remove Fabric VRFs - ansible.builtin.import_tasks: msd/vrfs.yml - tags: "{{ nac_tags.remove_vrfs }}" - when: - - changes_detected_vrfs +# - name: Remove Fabric VRFs +# ansible.builtin.import_tasks: msd/vrfs.yml +# tags: "{{ nac_tags.remove_vrfs }}" +# when: +# - changes_detected_vrfs + +- name: Remove Child Fabrics + ansible.builtin.import_tasks: msd/child_fabrics.yml + # tags: "{{ nac_tags.remove_child_fabrics }}" From 13c8ba607d25d53935018e465cdc2a7ae700d6d1 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 10 Dec 2024 20:51:14 -0500 Subject: [PATCH 023/183] updates to current msd workflow --- .../prepare_plugins/prep_001_list_defaults.py | 55 +++++++ .../prep_103_topology_switches.py | 1 + .../prep_104_fabric_overlay.py | 140 ++++++++++++++++++ .../prep_104_fabric_overlay_services.py | 131 ---------------- .../prep_106_topology_vpc_interfaces.py | 1 + plugins/action/dtc/map_msd_inventory.py | 58 ++++++++ roles/dtc/common/tasks/sub_main_msd.yml | 24 +++ .../common/templates/ndfc_attach_networks.j2 | 102 ++----------- .../dtc/common/templates/ndfc_attach_vrfs.j2 | 81 ++-------- .../msd_fabric/general/msd_fabric_general.j2 | 2 +- roles/dtc/common/templates/ndfc_inventory.j2 | 2 +- .../common/templates/ndfc_networks/.gitkeep | 0 .../dc_vxlan_fabric_networks.j2 | 86 +++++++++++ .../msd_fabric/msd_fabric_networks.j2 | 56 +++++++ roles/dtc/common/templates/ndfc_vrfs/.gitkeep | 0 .../dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 | 65 ++++++++ .../ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 | 42 ++++++ roles/dtc/create/tasks/msd/vrfs_networks.yml | 1 - roles/dtc/create/tasks/sub_main_msd.yml | 8 +- roles/dtc/remove/tasks/main.yml | 1 + roles/dtc/remove/tasks/sub_main_msd.yml | 38 +++-- .../401_overlay_services_cross_reference.py | 8 +- 22 files changed, 597 insertions(+), 305 deletions(-) create mode 100644 plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py delete mode 100644 plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py create mode 100644 plugins/action/dtc/map_msd_inventory.py create mode 100644 roles/dtc/common/templates/ndfc_networks/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 create mode 100644 roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 create mode 100644 roles/dtc/common/templates/ndfc_vrfs/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 create mode 100644 roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py index 1fd9566b7..8798874ad 100644 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py @@ -222,6 +222,61 @@ def prepare(self): list_index += 1 + # -------------------------------------------------------------------- + # Multisite Fabric Overlay List Defaults + # -------------------------------------------------------------------- + + # Check vxlan.multisite list elements + parent_keys = ['vxlan', 'multisite'] + dm_check = data_model_key_check(self.model_data, parent_keys) + if 'multisite' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: + self.model_data['vxlan'] = {'multisite': {}} + + # Check vxlan.multisite.overlay list elements + parent_keys = ['vxlan', 'multisite', 'overlay'] + dm_check = data_model_key_check(self.model_data, parent_keys) + if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: + self.model_data['vxlan']['multisite']['overlay'] = {'vrfs': []} + self.model_data['vxlan']['multisite']['overlay'] = {'vrf_attach_groups': []} + self.model_data['vxlan']['multisite']['overlay'] = {'networks': []} + self.model_data['vxlan']['multisite']['overlay'] = {'network_attach_groups': []} + + # Check vxlan.multisite.overlay_services.vrfs list element + target_key = 'vrfs' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.multisite.overlay.vrf_attach_groups list element + target_key = 'vrf_attach_groups' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.multisite.overlay.vrf_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # Check vxlan.multisite.overlay.networks list element + target_key = 'networks' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.multisite.overlay.network_attach_groups list element + target_key = 'network_attach_groups' + self.set_list_default(parent_keys, target_key) + + # Check vxlan.multisite.overlay.network_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + # -------------------------------------------------------------------- # Fabric Policy List Defaults # -------------------------------------------------------------------- diff --git a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py index bbcf5c345..7abce4c60 100644 --- a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py +++ b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py @@ -18,6 +18,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # SPDX-License-Identifier: MIT + from ....plugin_utils.helper_functions import hostname_to_ip_mapping diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py new file mode 100644 index 000000000..33a27755f --- /dev/null +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -0,0 +1,140 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from ....plugin_utils.helper_functions import data_model_key_check + + +class PreparePlugin: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.keys = [] + + def prepare(self): + model_data = self.kwargs['results']['model_extended'] + switches = model_data['vxlan']['topology']['switches'] + + # Remove the check for overlay_services after deprecation + # Remove lines 32-37 + overlay_key = 'overlay' + check = data_model_key_check(model_data, ['vxlan']) + if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: + overlay_key = 'overlay_services' + + if model_data['vxlan']['fabric']['type'] in ('VXLAN_EVPN'): + # Rebuild sm_data['vxlan'][overlay_key]['vrf_attach_groups'] into + # a structure that is easier to use. + vrf_grp_name_list = [] + model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'] = {} + for grp in model_data['vxlan'][overlay_key]['vrf_attach_groups']: + model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']] = [] + vrf_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + + # Remove vrf_attach_group from vrf if the group_name is not defined + for vrf in model_data['vxlan'][overlay_key]['vrfs']: + if 'vrf_attach_group' in vrf: + if vrf.get('vrf_attach_group') not in vrf_grp_name_list: + del vrf['vrf_attach_group'] + + # Rebuild sm_data['vxlan'][overlay_key]['network_attach_groups'] into + # a structure that is easier to use. + net_grp_name_list = [] + model_data['vxlan'][overlay_key]['network_attach_groups_dict'] = {} + for grp in model_data['vxlan'][overlay_key]['network_attach_groups']: + model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']] = [] + net_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + + # Remove network_attach_group from net if the group_name is not defined + for net in model_data['vxlan'][overlay_key]['networks']: + if 'network_attach_group' in net: + if net.get('network_attach_group') not in net_grp_name_list: + del net['network_attach_group'] + + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF'): + # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into + # a structure that is easier to use. + vrf_grp_name_list = [] + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'] = {} + for grp in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] + vrf_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + + # Remove vrf_attach_group from vrf if the group_name is not defined + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: + if 'vrf_attach_group' in vrf: + if vrf.get('vrf_attach_group') not in vrf_grp_name_list: + del vrf['vrf_attach_group'] + + # Rebuild sm_data['vxlan'][overlay_key]['network_attach_groups'] into + # a structure that is easier to use. + net_grp_name_list = [] + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'] = {} + for grp in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']] = [] + net_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']]: + if any(sw['name'] == switch['hostname'] for sw in switches): + found_switch = next((item for item in switches if item["name"] == switch['hostname'])) + if found_switch.get('management').get('management_ipv4_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + + # Remove network_attach_group from net if the group_name is not defined + for net in model_data['vxlan']['multisite']['overlay']['networks']: + if 'network_attach_group' in net: + if net.get('network_attach_group') not in net_grp_name_list: + del net['network_attach_group'] + + self.kwargs['results']['model_extended'] = model_data + return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py deleted file mode 100644 index 0fad465c9..000000000 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - - -class PreparePlugin: - def __init__(self, **kwargs): - self.kwargs = kwargs - self.keys = [] - - def prepare(self): - model_data = self.kwargs['results']['model_extended'] - switches = model_data['vxlan']['topology']['switches'] - - # Rebuild sm_data['vxlan']['overlay']['vrf_attach_groups'] into - # a structure that is easier to use. - vrf_grp_name_list = [] - model_data['vxlan']['overlay']['vrf_attach_groups_dict'] = {} - for grp in model_data['vxlan']['overlay']['vrf_attach_groups']: - model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] - vrf_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']]: - if any(sw['name'] == switch['hostname'] for sw in switches): - found_switch = next((item for item in switches if item["name"] == switch['hostname'])) - if found_switch.get('management').get('management_ipv4_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] - elif found_switch.get('management').get('management_ipv6_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] - - # Remove vrf_attach_group from vrf if the group_name is not defined - for vrf in model_data['vxlan']['overlay']['vrfs']: - if 'vrf_attach_group' in vrf: - if vrf.get('vrf_attach_group') not in vrf_grp_name_list: - del vrf['vrf_attach_group'] - - # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into - # a structure that is easier to use. - net_grp_name_list = [] - model_data['vxlan']['overlay']['network_attach_groups_dict'] = {} - for grp in model_data['vxlan']['overlay']['network_attach_groups']: - model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']] = [] - net_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']]: - if any(sw['name'] == switch['hostname'] for sw in switches): - found_switch = next((item for item in switches if item["name"] == switch['hostname'])) - if found_switch.get('management').get('management_ipv4_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] - elif found_switch.get('management').get('management_ipv6_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] - - # Remove network_attach_group from net if the group_name is not defined - for net in model_data['vxlan']['overlay']['networks']: - if 'network_attach_group' in net: - if net.get('network_attach_group') not in net_grp_name_list: - del net['network_attach_group'] - - # Backwards compatibility for vxlan.overlay_services - - # Rebuild sm_data['vxlan']['overlay_services']['vrf_attach_groups'] into - # a structure that is easier to use. - vrf_grp_name_list = [] - model_data['vxlan']['overlay_services']['vrf_attach_groups_dict'] = {} - for grp in model_data['vxlan']['overlay_services']['vrf_attach_groups']: - model_data['vxlan']['overlay_services']['vrf_attach_groups_dict'][grp['name']] = [] - vrf_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['overlay_services']['vrf_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['overlay_services']['vrf_attach_groups_dict'][grp['name']]: - if any(sw['name'] == switch['hostname'] for sw in switches): - found_switch = next((item for item in switches if item["name"] == switch['hostname'])) - if found_switch.get('management').get('management_ipv4_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] - elif found_switch.get('management').get('management_ipv6_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] - - # Remove vrf_attach_group from vrf if the group_name is not defined - for vrf in model_data['vxlan']['overlay_services']['vrfs']: - if 'vrf_attach_group' in vrf: - if vrf.get('vrf_attach_group') not in vrf_grp_name_list: - del vrf['vrf_attach_group'] - - # Rebuild sm_data['vxlan']['overlay_services']['network_attach_groups'] into - # a structure that is easier to use. - net_grp_name_list = [] - model_data['vxlan']['overlay_services']['network_attach_groups_dict'] = {} - for grp in model_data['vxlan']['overlay_services']['network_attach_groups']: - model_data['vxlan']['overlay_services']['network_attach_groups_dict'][grp['name']] = [] - net_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['overlay_services']['network_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['overlay_services']['network_attach_groups_dict'][grp['name']]: - if any(sw['name'] == switch['hostname'] for sw in switches): - found_switch = next((item for item in switches if item["name"] == switch['hostname'])) - if found_switch.get('management').get('management_ipv4_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] - elif found_switch.get('management').get('management_ipv6_address'): - switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] - - # Remove network_attach_group from net if the group_name is not defined - for net in model_data['vxlan']['overlay_services']['networks']: - if 'network_attach_group' in net: - if net.get('network_attach_group') not in net_grp_name_list: - del net['network_attach_group'] - - self.kwargs['results']['model_extended'] = model_data - return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py index 1a2cdfaf7..ecd7b3602 100644 --- a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py @@ -22,6 +22,7 @@ # Group vPC interfaces by vpc_peers, vpc_id and switch_name # This helps in identifying vPC interfaces for a given vpc_peer, vpc_id and switch_name # Reduces the need to loop through all interfaces to find vPC interfaces in Jinja2 templates + class PreparePlugin: def __init__(self, **kwargs): self.kwargs = kwargs diff --git a/plugins/action/dtc/map_msd_inventory.py b/plugins/action/dtc/map_msd_inventory.py new file mode 100644 index 000000000..0b4211947 --- /dev/null +++ b/plugins/action/dtc/map_msd_inventory.py @@ -0,0 +1,58 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase + +display = Display() + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + results['failed'] = False + + parent_fabric_name = self._task.args['parent_fabric_name'] + + msd_inventory = self._execute_module( + module_name="cisco.dcnm.dcnm_inventory", + module_args={ + "fabric": parent_fabric_name, + "state": "query" + }, + task_vars=task_vars, + tmp=tmp + ) + + msd_switches = {} + for switch in msd_inventory.get('response', []): + msd_switches.update({switch['hostName']: switch['ipAddress']}) + msd_switches.update({switch['ipAddress']: switch['ipAddress']}) + + results['msd_switches'] = msd_switches + + return results diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 4796d44f2..953af22c7 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -46,3 +46,27 @@ - name: Build NDFC Child Fabric Inventory List From Template ansible.builtin.include_tasks: msd/ndfc_children.yml + +- name: Get Switch Inventory from MSD Fabric + cisco.nac_dc_vxlan.dtc.map_msd_inventory: + parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" + register: msd_inventory + +- name: Set MSD Switches List + ansible.builtin.set_fact: + msd_switches: "{{ msd_inventory.msd_switches }}" + when: msd_inventory.msd_switches is defined + +# -------------------------------------------------------------------- +# Build NDFC Fabric VRFs Attach List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric VRFs Attach List From Template + ansible.builtin.include_tasks: msd/ndfc_vrfs.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Networks Attach List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Networks Attach List From Template + ansible.builtin.include_tasks: msd/ndfc_networks.yml diff --git a/roles/dtc/common/templates/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_attach_networks.j2 index 96742c991..03088f882 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks.j2 @@ -1,89 +1,17 @@ --- -# This NDFC networks and switch attachments config data structure is auto-generated -# DO NOT EDIT MANUALLY -# -{% if MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks %} -{% set networks = MD_Extended.vxlan.overlay.networks %} -{% elif MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks %} -{% set networks = MD_Extended.vxlan.overlay_services.networks %} -{% endif %} -{% for net in networks %} -- net_name: {{ net['name'] }} -{# ------------------------------------------------------ #} -{# Properties Section #} -{# ------------------------------------------------------ #} - is_l2only: {{ net['is_l2_only'] | default(defaults.vxlan.overlay.networks.is_l2_only) }} - vrf_name: {{ net['vrf_name'] | default(omit) }} - net_id: {{ net['net_id'] | default(omit) }} - vlan_id: {{ net['vlan_id'] | default(omit) }} - vlan_name: {{ net['vlan_name'] | default(omit) }} - gw_ip_subnet: {{ net['gw_ip_address'] | default(omit) }} -{% if net.secondary_ip_addresses is defined %} -{% if net.secondary_ip_addresses | length == 1 %} - secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} -{% elif net.secondary_ip_addresses | length == 2 %} - secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} - secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} -{% elif net.secondary_ip_addresses | length == 3 %} - secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} - secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} - secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} -{% elif net.secondary_ip_addresses | length == 4 %} - secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} - secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} - secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} - secondary_ip_gw4: {{ net['secondary_ip_addresses'][3]['ip_address'] }} -{% endif %} -{% endif %} - arp_suppress: {{ net['arp_suppress'] | default(defaults.vxlan.overlay.networks.arp_supress) }} - dhcp_loopback_id: {{ net['dhcp_loopback_id'] | default(omit) }} -{% if net.dhcp_servers is defined %} -{% if net.dhcp_servers | length == 1 %} - dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} - dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} -{% elif net.dhcp_servers | length == 2 %} - dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} - dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} - dhcp_srvr2_ip: {{ net['dhcp_servers'][1]['ip_address'] }} - dhcp_srvr2_vrf: {{ net['dhcp_servers'][1]['vrf'] }} -{% elif net.dhcp_servers | length == 3 %} - dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} - dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} - dhcp_srvr2_ip: {{ net['dhcp_servers'][1]['ip_address'] }} - dhcp_srvr2_vrf: {{ net['dhcp_servers'][1]['vrf'] }} - dhcp_srvr3_ip: {{ net['dhcp_servers'][2]['ip_address'] }} - dhcp_srvr3_vrf: {{ net['dhcp_servers'][2]['vrf'] }} -{% endif %} -{% endif %} - gw_ipv6_subnet: {{ net['gw_ipv6_address'] | default(omit) }} - int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay.networks.net_description) }} - l3gw_on_border: {{ net['l3gw_on_border'] | default(defaults.vxlan.overlay.networks.l3gw_on_border) }} - mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay.networks.mtu_l3intf) }} -{% if (MD.vxlan.underlay.general.replication_mode | lower) == 'multicast' %} - multicast_group_address: {{ net['multicast_group_address'] | default(defaults.vxlan.overlay.networks.multicast_group_address) }} -{% endif %} - netflow_enable: {{ net['netflow_enable'] | default(defaults.vxlan.overlay.networks.netflow_enable) }} -{% if net['netflow_enable'] is defined and net['netflow_enable'] | bool %} - vlan_nf_monitor: {{ net['vlan_netflow_monitor'] | default(omit) }} -{% endif %} - route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay.networks.route_target_both) }} - route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} - trm_enable: {{ net['trm_enable'] | default(defaults.vxlan.overlay.networks.trm_enable) }} -{# ------------------------------------------------------ #} -{# Attach Group Section #} -{# ------------------------------------------------------ #} -{% if net['network_attach_group'] is defined %} - attach: -{% if MD_Extended.vxlan.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay.network_attach_groups_dict %} -{% set network_attach_groups_dict = MD_Extended.vxlan.overlay.network_attach_groups_dict %} -{% elif MD_Extended.vxlan.overlay_services.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} -{% set network_attach_groups_dict = MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} -{% endif %} -{% for attach in network_attach_groups_dict[net['network_attach_group']] %} - - ip_address: {{ attach['mgmt_ip_address'] }} - ports: {{ attach['ports'] }} -{% endfor %} - deploy: false -{% endif %} +{#- This NDFC fabric networks data structure is auto-generated #} +{#- DO NOT EDIT MANUALLY #} -{% endfor %} +{% set vxlan = MD_Extended.vxlan %} +{% if vxlan.fabric.type == 'VXLAN_EVPN' %} + +{# Include NDFC DC VXLAN EVPN Base Template #} +{% include '/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2' %} + +{% elif vxlan.fabric.type == 'MSD'%} + +{# Include NDFC MSD Base Template #} +{% include '/ndfc_networks/msd_fabric/msd_fabric_networks.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN and MSDs #} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index d3d40fa62..8c227befd 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -1,68 +1,17 @@ --- -# This NDFC VRFs and switch attachments config data structure is auto-generated -# DO NOT EDIT MANUALLY -# -{% if MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs %} -{% set vrfs = MD_Extended.vxlan.overlay.vrfs %} -{% elif MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs %} -{% set vrfs = MD_Extended.vxlan.overlay_services.vrfs %} -{% endif %} -{% for vrf in vrfs %} -- vrf_name: {{ vrf['name'] }} -{# ------------------------------------------------------ #} -{# Properties Section #} -{# ------------------------------------------------------ #} - vrf_id: {{ vrf['vrf_id'] | default(omit) }} - vlan_id: {{ vrf['vlan_id'] | default(omit) }} - vrf_vlan_name: {{ vrf['vrf_vlan_name'] | default(omit) }} - vrf_intf_desc: {{ vrf['vrf_intf_desc'] | default(defaults.vxlan.overlay.vrfs.vrf_intf_desc) }} - vrf_description: {{ vrf['vrf_description'] | default(defaults.vxlan.overlay.vrfs.vrf_description) }} - vrf_int_mtu: {{ vrf['vrf_int_mtu'] | default(defaults.vxlan.overlay.vrfs.vrf_int_mtu) }} - loopback_route_tag: {{ vrf['loopback_route_tag'] | default(defaults.vxlan.overlay.vrfs.loopback_route_tag) }} - max_bgp_paths: {{ vrf['max_bgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_bgp_paths) }} - max_ibgp_paths: {{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_ibgp_paths) }} - ipv6_linklocal_enable: {{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay.vrfs.ipv6_linklocal_enable) }} - adv_host_routes: {{ vrf['adv_host_routes'] | default(defaults.vxlan.overlay.vrfs.adv_host_routes) }} - adv_default_routes: {{ vrf['adv_default_routes'] | default(defaults.vxlan.overlay.vrfs.adv_default_routes) }} - static_default_route: {{ vrf['static_default_route'] | default(defaults.vxlan.overlay.vrfs.static_default_route) }} - bgp_password: {{ vrf['bgp_password'] | default(omit) }} - bgp_password_encryption_type: {{ vrf['bgp_password_encryption_type'] | default(omit) }} - disable_rt_auto: {{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay.vrfs.disable_rt_auto) }} - export_evpn_rt: {{ vrf['export_evpn_rt'] | default(omit) }} - export_mvpn_rt: {{ vrf['export_mvpn_rt'] | default(omit) }} - export_vpn_rt: {{ vrf['export_vpn_rt'] | default(omit) }} - import_evpn_rt: {{ vrf['import_evpn_rt'] | default(omit) }} - import_mvpn_rt: {{ vrf['import_mvpn_rt'] | default(omit) }} - import_vpn_rt: {{ vrf['import_vpn_rt'] | default(omit) }} - netflow_enable: {{ vrf['netflow_enable'] | default(defaults.vxlan.overlay.vrfs.netflow_enable) }} -{% if vrf['netflow_enable'] is defined and vrf['netflow_enable'] | bool %} - nf_monitor: {{ vrf['netflow_monitor'] }} -{% endif %} - no_rp: {{ vrf['no_rp'] | default(defaults.vxlan.overlay.vrfs.no_rp) }} - trm_enable: {{ vrf['trm_enable'] | default(defaults.vxlan.overlay.vrfs.trm_enable) }} -{% if vrf['trm_enable'] is defined and vrf['trm_enable'] | bool %} - overlay_mcast_group: {{ vrf['overlay_multicast_group'] | default(omit) }} - rp_address: {{ vrf['rp_address'] | default(omit) }} - rp_external: {{ vrf['rp_external'] | default(omit) }} - rp_loopback_id: {{ vrf['rp_loopback_id'] | default(omit) }} - trm_bgw_msite: {{ vrf['trm_bgw_msite'] | default(defaults.vxlan.overlay.vrfs.trm_bgw_msite) }} - underlay_mcast_ip: {{ vrf['underlay_mcast_ip'] | default(omit) }} -{% endif %} - redist_direct_rmap: {{ vrf['redist_direct_routemap'] | default(defaults.vxlan.overlay.vrfs.redist_direct_routemap) }} -{# ------------------------------------------------------ #} -{# Attach Group Section #} -{# ------------------------------------------------------ #} -{% if vrf['vrf_attach_group'] is defined %} - attach: -{% if MD_Extended.vxlan.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} -{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} -{% elif MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} -{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} -{% endif %} -{% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} - - ip_address: {{ attach['mgmt_ip_address'] }} -{% endfor %} - deploy: false -{% endif %} +{#- This NDFC fabric vrfs config data structure is auto-generated #} +{#- DO NOT EDIT MANUALLY #} -{% endfor %} +{% set vxlan = MD_Extended.vxlan %} +{% if vxlan.fabric.type == 'VXLAN_EVPN' %} + +{# Include NDFC DC VXLAN EVPN Base Template #} +{% include '/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2' %} + +{% elif vxlan.fabric.type == 'MSD'%} + +{# Include NDFC MSD Base Template #} +{% include '/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN and ISN #} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 index 362e2257f..a593cfa1f 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -1,5 +1,5 @@ {# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.fabric.name }} #} - VXLAN_UNDERLAY_IS_V6: False + VXLAN_UNDERLAY_IS_V6: {{ vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) }} {% if not vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) %} ENABLE_PVLAN: false {% endif %} diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 895f85058..9bae159b7 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -1,5 +1,5 @@ --- -{#- This NDFC fabric config data structure is auto-generated #} +{#- This NDFC fabric inventory config data structure is auto-generated #} {#- DO NOT EDIT MANUALLY #} {% set vxlan = MD_Extended.vxlan %} diff --git a/roles/dtc/common/templates/ndfc_networks/.gitkeep b/roles/dtc/common/templates/ndfc_networks/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 new file mode 100644 index 000000000..68c5ea7b5 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 @@ -0,0 +1,86 @@ +{# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{% if MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks %} +{% set networks = MD_Extended.vxlan.overlay.networks %} +{% elif MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks %} +{% set networks = MD_Extended.vxlan.overlay_services.networks %} +{% endif %} +{% for net in networks %} +- net_name: {{ net['name'] }} +{# ------------------------------------------------------ #} +{# Properties Section #} +{# ------------------------------------------------------ #} + is_l2only: {{ net['is_l2_only'] | default(defaults.vxlan.overlay.networks.is_l2_only) }} + vrf_name: {{ net['vrf_name'] | default(omit) }} + net_id: {{ net['net_id'] | default(omit) }} + vlan_id: {{ net['vlan_id'] | default(omit) }} + vlan_name: {{ net['vlan_name'] | default(omit) }} + gw_ip_subnet: {{ net['gw_ip_address'] | default(omit) }} +{% if net.secondary_ip_addresses is defined %} +{% if net.secondary_ip_addresses | length == 1 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 2 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 3 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} + secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 4 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} + secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} + secondary_ip_gw4: {{ net['secondary_ip_addresses'][3]['ip_address'] }} +{% endif %} +{% endif %} + arp_suppress: {{ net['arp_suppress'] | default(defaults.vxlan.overlay.networks.arp_supress) }} + dhcp_loopback_id: {{ net['dhcp_loopback_id'] | default(omit) }} +{% if net.dhcp_servers is defined %} +{% if net.dhcp_servers | length == 1 %} + dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} + dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} +{% elif net.dhcp_servers | length == 2 %} + dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} + dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} + dhcp_srvr2_ip: {{ net['dhcp_servers'][1]['ip_address'] }} + dhcp_srvr2_vrf: {{ net['dhcp_servers'][1]['vrf'] }} +{% elif net.dhcp_servers | length == 3 %} + dhcp_srvr1_ip: {{ net['dhcp_servers'][0]['ip_address'] }} + dhcp_srvr1_vrf: {{ net['dhcp_servers'][0]['vrf'] }} + dhcp_srvr2_ip: {{ net['dhcp_servers'][1]['ip_address'] }} + dhcp_srvr2_vrf: {{ net['dhcp_servers'][1]['vrf'] }} + dhcp_srvr3_ip: {{ net['dhcp_servers'][2]['ip_address'] }} + dhcp_srvr3_vrf: {{ net['dhcp_servers'][2]['vrf'] }} +{% endif %} +{% endif %} + gw_ipv6_subnet: {{ net['gw_ipv6_address'] | default(omit) }} + int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay.networks.net_description) }} + l3gw_on_border: {{ net['l3gw_on_border'] | default(defaults.vxlan.overlay.networks.l3gw_on_border) }} + mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay.networks.mtu_l3intf) }} +{% if (MD.vxlan.underlay.general.replication_mode | lower) == 'multicast' %} + multicast_group_address: {{ net['multicast_group_address'] | default(defaults.vxlan.overlay.networks.multicast_group_address) }} +{% endif %} + netflow_enable: {{ net['netflow_enable'] | default(defaults.vxlan.overlay.networks.netflow_enable) }} +{% if net['netflow_enable'] is defined and net['netflow_enable'] | bool %} + vlan_nf_monitor: {{ net['vlan_netflow_monitor'] | default(omit) }} +{% endif %} + route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay.networks.route_target_both) }} + route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} + trm_enable: {{ net['trm_enable'] | default(defaults.vxlan.overlay.networks.trm_enable) }} +{# ------------------------------------------------------ #} +{# Attach Group Section #} +{# ------------------------------------------------------ #} +{% if net['network_attach_group'] is defined %} + attach: +{% if MD_Extended.vxlan.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay.network_attach_groups_dict %} +{% set network_attach_groups_dict = MD_Extended.vxlan.overlay.network_attach_groups_dict %} +{% elif MD_Extended.vxlan.overlay_services.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} +{% set network_attach_groups_dict = MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} +{% endif %} +{% for attach in network_attach_groups_dict[net['network_attach_group']] %} + - ip_address: {{ attach['mgmt_ip_address'] }} + ports: {{ attach['ports'] }} +{% endfor %} + deploy: false +{% endif %} + +{% endfor %} diff --git a/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 new file mode 100644 index 000000000..41792ede1 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 @@ -0,0 +1,56 @@ +{# Auto-generated NDFC MSD network_attach_groups_dict config data structure for fabric {{ vxlan.fabric.name }} #} +{% if MD_Extended.vxlan.multisite.overlay.networks is defined and MD_Extended.vxlan.multisite.overlay.networks %} +{% set networks = MD_Extended.vxlan.multisite.overlay.networks %} +{% else %} +{% set networks = [] %} +{% endif %} +{% for net in networks %} +- net_name: {{ net['name'] }} +{# ------------------------------------------------------ #} +{# Properties Section #} +{# ------------------------------------------------------ #} + is_l2only: {{ net['is_l2_only'] | default(defaults.vxlan.overlay.networks.is_l2_only) }} + vrf_name: {{ net['vrf_name'] | default(omit) }} + net_id: {{ net['net_id'] | default(omit) }} + vlan_id: {{ net['vlan_id'] | default(omit) }} + vlan_name: {{ net['vlan_name'] | default(omit) }} + gw_ip_subnet: {{ net['gw_ip_address'] | default(omit) }} +{% if net.secondary_ip_addresses is defined %} +{% if net.secondary_ip_addresses | length == 1 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 2 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 3 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} + secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} +{% elif net.secondary_ip_addresses | length == 4 %} + secondary_ip_gw1: {{ net['secondary_ip_addresses'][0]['ip_address'] }} + secondary_ip_gw2: {{ net['secondary_ip_addresses'][1]['ip_address'] }} + secondary_ip_gw3: {{ net['secondary_ip_addresses'][2]['ip_address'] }} + secondary_ip_gw4: {{ net['secondary_ip_addresses'][3]['ip_address'] }} +{% endif %} +{% endif %} + arp_suppress: {{ net['arp_suppress'] | default(defaults.vxlan.overlay.networks.arp_supress) }} + gw_ipv6_subnet: {{ net['gw_ipv6_address'] | default(omit) }} + int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay.networks.net_description) }} + mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay.networks.mtu_l3intf) }} + route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay.networks.route_target_both) }} + route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} +{# ------------------------------------------------------ #} +{# Attach Group Section #} +{# ------------------------------------------------------ #} +{% if net['network_attach_group'] is defined %} + attach: +{% if MD_Extended.vxlan.multisite.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.multisite.overlay.network_attach_groups_dict %} +{% set network_attach_groups_dict = MD_Extended.vxlan.multisite.overlay.network_attach_groups_dict %} +{% endif %} +{% for attach in network_attach_groups_dict[net['network_attach_group']] %} + - ip_address: {{ msd_switches[attach['hostname']] }} + ports: {{ attach['ports'] }} +{% endfor %} + deploy: false +{% endif %} + +{% endfor %} diff --git a/roles/dtc/common/templates/ndfc_vrfs/.gitkeep b/roles/dtc/common/templates/ndfc_vrfs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 new file mode 100644 index 000000000..7e24e6660 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 @@ -0,0 +1,65 @@ +{# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{% if MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs %} +{% set vrfs = MD_Extended.vxlan.overlay.vrfs %} +{% elif MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs %} +{% set vrfs = MD_Extended.vxlan.overlay_services.vrfs %} +{% endif %} +{% for vrf in vrfs %} +- vrf_name: {{ vrf['name'] }} +{# ------------------------------------------------------ #} +{# Properties Section #} +{# ------------------------------------------------------ #} + vrf_id: {{ vrf['vrf_id'] | default(omit) }} + vlan_id: {{ vrf['vlan_id'] | default(omit) }} + vrf_vlan_name: {{ vrf['vrf_vlan_name'] | default(omit) }} + vrf_intf_desc: {{ vrf['vrf_intf_desc'] | default(defaults.vxlan.overlay.vrfs.vrf_intf_desc) }} + vrf_description: {{ vrf['vrf_description'] | default(defaults.vxlan.overlay.vrfs.vrf_description) }} + vrf_int_mtu: {{ vrf['vrf_int_mtu'] | default(defaults.vxlan.overlay.vrfs.vrf_int_mtu) }} + loopback_route_tag: {{ vrf['loopback_route_tag'] | default(defaults.vxlan.overlay.vrfs.loopback_route_tag) }} + max_bgp_paths: {{ vrf['max_bgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_bgp_paths) }} + max_ibgp_paths: {{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_ibgp_paths) }} + ipv6_linklocal_enable: {{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay.vrfs.ipv6_linklocal_enable) }} + adv_host_routes: {{ vrf['adv_host_routes'] | default(defaults.vxlan.overlay.vrfs.adv_host_routes) }} + adv_default_routes: {{ vrf['adv_default_routes'] | default(defaults.vxlan.overlay.vrfs.adv_default_routes) }} + static_default_route: {{ vrf['static_default_route'] | default(defaults.vxlan.overlay.vrfs.static_default_route) }} + bgp_password: {{ vrf['bgp_password'] | default(omit) }} + bgp_password_encryption_type: {{ vrf['bgp_password_encryption_type'] | default(omit) }} + disable_rt_auto: {{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay.vrfs.disable_rt_auto) }} + export_evpn_rt: {{ vrf['export_evpn_rt'] | default(omit) }} + export_mvpn_rt: {{ vrf['export_mvpn_rt'] | default(omit) }} + export_vpn_rt: {{ vrf['export_vpn_rt'] | default(omit) }} + import_evpn_rt: {{ vrf['import_evpn_rt'] | default(omit) }} + import_mvpn_rt: {{ vrf['import_mvpn_rt'] | default(omit) }} + import_vpn_rt: {{ vrf['import_vpn_rt'] | default(omit) }} + netflow_enable: {{ vrf['netflow_enable'] | default(defaults.vxlan.overlay.vrfs.netflow_enable) }} +{% if vrf['netflow_enable'] is defined and vrf['netflow_enable'] | bool %} + nf_monitor: {{ vrf['netflow_monitor'] }} +{% endif %} + no_rp: {{ vrf['no_rp'] | default(defaults.vxlan.overlay.vrfs.no_rp) }} + trm_enable: {{ vrf['trm_enable'] | default(defaults.vxlan.overlay.vrfs.trm_enable) }} +{% if vrf['trm_enable'] is defined and vrf['trm_enable'] | bool %} + overlay_mcast_group: {{ vrf['overlay_multicast_group'] | default(omit) }} + rp_address: {{ vrf['rp_address'] | default(omit) }} + rp_external: {{ vrf['rp_external'] | default(omit) }} + rp_loopback_id: {{ vrf['rp_loopback_id'] | default(omit) }} + trm_bgw_msite: {{ vrf['trm_bgw_msite'] | default(defaults.vxlan.overlay.vrfs.trm_bgw_msite) }} + underlay_mcast_ip: {{ vrf['underlay_mcast_ip'] | default(omit) }} +{% endif %} + redist_direct_rmap: {{ vrf['redist_direct_routemap'] | default(defaults.vxlan.overlay.vrfs.redist_direct_routemap) }} +{# ------------------------------------------------------ #} +{# Attach Group Section #} +{# ------------------------------------------------------ #} +{% if vrf['vrf_attach_group'] is defined %} + attach: +{% if MD_Extended.vxlan.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} +{% elif MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} +{% endif %} +{% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} + - ip_address: {{ attach['mgmt_ip_address'] }} +{% endfor %} + deploy: false +{% endif %} + +{% endfor %} diff --git a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 new file mode 100644 index 000000000..65f245e86 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 @@ -0,0 +1,42 @@ +{# Auto-generated NDFC MSD VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{% if MD_Extended.vxlan.multisite.overlay.vrfs is defined and MD_Extended.vxlan.multisite.overlay.vrfs %} +{% set vrfs = MD_Extended.vxlan.multisite.overlay.vrfs %} +{% else %} +{% set vrfs = [] %} +{% endif %} +{% for vrf in vrfs %} +- vrf_name: {{ vrf['name'] }} +{# ------------------------------------------------------ #} +{# Properties Section #} +{# ------------------------------------------------------ #} + vrf_id: {{ vrf['vrf_id'] | default(omit) }} + vlan_id: {{ vrf['vlan_id'] | default(omit) }} + vrf_vlan_name: {{ vrf['vrf_vlan_name'] | default(omit) }} + vrf_intf_desc: {{ vrf['vrf_intf_desc'] | default(defaults.vxlan.overlay.vrfs.vrf_intf_desc) }} + vrf_description: {{ vrf['vrf_description'] | default(defaults.vxlan.overlay.vrfs.vrf_description) }} + vrf_int_mtu: {{ vrf['vrf_int_mtu'] | default(defaults.vxlan.overlay.vrfs.vrf_int_mtu) }} + loopback_route_tag: {{ vrf['loopback_route_tag'] | default(defaults.vxlan.overlay.vrfs.loopback_route_tag) }} + max_bgp_paths: {{ vrf['max_bgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_bgp_paths) }} + max_ibgp_paths: {{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay.vrfs.max_ibgp_paths) }} + ipv6_linklocal_enable: {{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay.vrfs.ipv6_linklocal_enable) }} + disable_rt_auto: {{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay.vrfs.disable_rt_auto) }} + export_evpn_rt: {{ vrf['export_evpn_rt'] | default(omit) }} + export_vpn_rt: {{ vrf['export_vpn_rt'] | default(omit) }} + import_evpn_rt: {{ vrf['import_evpn_rt'] | default(omit) }} + import_vpn_rt: {{ vrf['import_vpn_rt'] | default(omit) }} + redist_direct_rmap: {{ vrf['redist_direct_routemap'] | default(defaults.vxlan.overlay.vrfs.redist_direct_routemap) }} +{# ------------------------------------------------------ #} +{# Attach Group Section #} +{# ------------------------------------------------------ #} +{% if vrf['vrf_attach_group'] is defined %} + attach: +{% if MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict %} +{% endif %} +{% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} + - ip_address: {{ msd_switches[attach['hostname']] }} +{% endfor %} + deploy: false +{% endif %} + +{% endfor %} diff --git a/roles/dtc/create/tasks/msd/vrfs_networks.yml b/roles/dtc/create/tasks/msd/vrfs_networks.yml index 2be757e42..46ba1fee5 100644 --- a/roles/dtc/create/tasks/msd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/msd/vrfs_networks.yml @@ -42,7 +42,6 @@ - MD_Extended.vxlan.multisite.overlay.vrfs - changes_detected_vrfs - # -------------------------------------------------------------------- # Manage Network Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 271c09813..396fe5730 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -47,8 +47,8 @@ - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: msd/vrfs_networks.yml - when: > - MD_Extended.vxlan.multisite.overlay is defined and - MD_Extended.vxlan.multisite.topology.switches | length > 0 and - (changes_detected_vrfs or changes_detected_networks) + when: + - MD_Extended.vxlan.multisite.overlay is defined + - MD_Extended.vxlan.multisite.overlay + - (changes_detected_vrfs or changes_detected_networks) tags: "{{ nac_tags.create_vrfs_networks }}" diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index 0a0cdcce8..b7cd6c7fa 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -31,6 +31,7 @@ ansible.builtin.import_tasks: sub_main_msd.yml when: - MD_Extended.vxlan.fabric.type == 'MSD' + - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs or changes_detected_vpc_peering or changes_detected_link_vpc_peering or changes_detected_inventory - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/sub_main_msd.yml b/roles/dtc/remove/tasks/sub_main_msd.yml index 072e61f5d..bdec899ed 100644 --- a/roles/dtc/remove/tasks/sub_main_msd.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -21,17 +21,35 @@ --- -# - name: Remove Fabric Networks -# ansible.builtin.import_tasks: msd/networks.yml -# tags: "{{ nac_tags.remove_networks }}" -# when: -# - changes_detected_networks +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.remove] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.remove] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.remove }}" # Tags defined in roles/common_global/vars/main.yml -# - name: Remove Fabric VRFs -# ansible.builtin.import_tasks: msd/vrfs.yml -# tags: "{{ nac_tags.remove_vrfs }}" -# when: -# - changes_detected_vrfs +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.remove }}" + +- name: Get List of Fabric Switches from NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" + register: switch_list + tags: "{{ nac_tags.remove }}" + +- name: Remove Fabric Networks + ansible.builtin.import_tasks: msd/networks.yml + tags: "{{ nac_tags.remove_networks }}" + when: + - changes_detected_networks + +- name: Remove Fabric VRFs + ansible.builtin.import_tasks: msd/vrfs.yml + tags: "{{ nac_tags.remove_vrfs }}" + when: + - changes_detected_vrfs - name: Remove Child Fabrics ansible.builtin.import_tasks: msd/child_fabrics.yml diff --git a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py index 3a7cf6db2..d57354c38 100644 --- a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py +++ b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py @@ -22,10 +22,10 @@ def match(cls, inventory): if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: overlay_key = 'overlay_services' - network_keys = ['vxlan', f'{overlay_key}', 'networks'] - vrf_keys = ['vxlan', f'{overlay_key}', 'vrfs'] - network_attach_keys = ['vxlan', f'{overlay_key}', 'network_attach_groups'] - vrf_attach_keys = ['vxlan', f'{overlay_key}', 'vrf_attach_groups'] + network_keys = ['vxlan', overlay_key, 'networks'] + vrf_keys = ['vxlan', overlay_key, 'vrfs'] + network_attach_keys = ['vxlan', overlay_key, 'network_attach_groups'] + vrf_attach_keys = ['vxlan', overlay_key, 'vrf_attach_groups'] # Check if vrfs, network and switch data is defined in the service model check = cls.data_model_key_check(inventory, switch_keys) From 12196094a9c7c7842a2b6dc90d643cd5d89b9be3 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 10 Dec 2024 21:34:39 -0500 Subject: [PATCH 024/183] update github templates --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +++- .github/ISSUE_TEMPLATE/documentation_report.yml | 4 +++- .github/ISSUE_TEMPLATE/feature_request.yml | 4 +++- .github/pull_request_template.md | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9f9c517c4..8f9a48fff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -76,12 +76,14 @@ body: label: Which section of the data model is this issue related to? multiple: false options: + - vxlan.fabric - vxlan.global - vxlan.topology - vxlan.underlay - - vxlan.overlay_services + - vxlan.overlay - vxlan.overlay_extensions - vxlan.policy + - vxlan.multisite - defaults.vxlan - other validations: diff --git a/.github/ISSUE_TEMPLATE/documentation_report.yml b/.github/ISSUE_TEMPLATE/documentation_report.yml index bc22f8e69..de9f9e19c 100644 --- a/.github/ISSUE_TEMPLATE/documentation_report.yml +++ b/.github/ISSUE_TEMPLATE/documentation_report.yml @@ -41,12 +41,14 @@ body: label: Which section of the data model is the documentation update related? multiple: false options: + - vxlan.fabric - vxlan.global - vxlan.topology - vxlan.underlay - - vxlan.overlay_services + - vxlan.overlay - vxlan.overlay_extensions - vxlan.policy + - vxlan.multisite - defaults.vxlan - other validations: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index c1ff85869..ce9bdf894 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -50,12 +50,14 @@ body: label: Which section of the data model is the new feature related? multiple: false options: + - vxlan.fabric - vxlan.global - vxlan.topology - vxlan.underlay - - vxlan.overlay_services + - vxlan.overlay - vxlan.overlay_extensions - vxlan.policy + - vxlan.multisite - defaults.vxlan - other validations: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a9cbc8ffc..39e02a3f4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,12 +16,14 @@ ## Related Data Model Element +* [ ] vxlan.fabric * [ ] vxlan.global * [ ] vxlan.topology * [ ] vxlan.underlay -* [ ] vxlan.overlay_services +* [ ] vxlan.overlay * [ ] vxlan.overlay_extensions * [ ] vxlan.policy +* [ ] vxlan.multisite * [ ] defaults.vxlan * [ ] other From a33823f6fb9ebf3068f6a9d9162e01ca45f9dfea Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 10 Dec 2024 21:53:46 -0500 Subject: [PATCH 025/183] fix pipeline errors --- plugins/action/common/nac_dc_load.py | 73 ---------------- plugins/action/common/nac_dc_validate.py | 8 +- .../common/prepare_plugins/prep_101_fabric.py | 12 ++- .../prep_104_fabric_overlay.py | 4 +- plugins/action/dtc/manage_child_fabrics.py | 8 +- .../dtc/update_switch_hostname_policy.py | 2 +- plugins/filter/quote.py | 85 ------------------- .../401_overlay_services_cross_reference.py | 4 +- .../rules/vxlan/402_overlay_services_vrfs.py | 2 +- tests/sanity/ignore-2.14.txt | 6 +- tests/sanity/ignore-2.15.txt | 6 +- tests/sanity/ignore-2.16.txt | 6 +- 12 files changed, 35 insertions(+), 181 deletions(-) delete mode 100644 plugins/action/common/nac_dc_load.py delete mode 100644 plugins/filter/quote.py diff --git a/plugins/action/common/nac_dc_load.py b/plugins/action/common/nac_dc_load.py deleted file mode 100644 index 2b5154bae..000000000 --- a/plugins/action/common/nac_dc_load.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - -from __future__ import absolute_import, division, print_function - - -__metaclass__ = type - -from ansible.utils.display import Display -from ansible.plugins.action import ActionBase -from ansible.errors import AnsibleError - -try: - from iac_validate.yaml import load_yaml_files - from iac_validate.cli.options import DEFAULT_SCHEMA -except ImportError as imp_exc: - IAC_VALIDATE_IMPORT_ERROR = imp_exc -else: - IAC_VALIDATE_IMPORT_ERROR = None - -import os - -display = Display() - - -class ActionModule(ActionBase): - - def run(self, tmp=None, task_vars=None): - results = super(ActionModule, self).run(tmp, task_vars) - results['failed'] = False - results['msg'] = None - results['data'] = {} - - if IAC_VALIDATE_IMPORT_ERROR: - raise AnsibleError('iac-validate not found and must be installed. Please pip install iac-validate.') from IAC_VALIDATE_IMPORT_ERROR - - mdata = self._task.args.get('mdata') - - # Verify That Data Sources Exists - if mdata and not os.path.exists(mdata): - results['failed'] = True - results['msg'] = "The data directory ({0}) for this fabric does not appear to exist!".format(mdata) - - return results - - if len(os.listdir(mdata)) == 0: - results['failed'] = True - results['msg'] = "The data directory ({0}) for this fabric is empty!".format(mdata) - - return results - - # Return Merged Model Data - results['data'] = load_yaml_files([mdata]) - - return results diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 1a9fc3b41..5b4271a31 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -109,8 +109,12 @@ def run(self, tmp=None, task_vars=None): check = data_model_key_check(results['data'], parent_keys) if 'global' in check['keys_found'] and 'global' in check['keys_data']: if 'fabric_type' in results['data']['vxlan']['global']: - display.deprecated("Attempting to use vxlan.global.fabric_type due to vxlan.fabric.type not being found. vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric.type.") - + deprecated_msg = ( + "Attempting to use vxlan.global.fabric_type due to vxlan.fabric.type not being found. " + "vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric.type." + ) + display.deprecated(msg=deprecated_msg, version='1.0.0') + if results['data']['vxlan']['global']['fabric_type'] in ('VXLAN_EVPN'): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCF'): diff --git a/plugins/action/common/prepare_plugins/prep_101_fabric.py b/plugins/action/common/prepare_plugins/prep_101_fabric.py index e1dce5c4d..9940d471f 100644 --- a/plugins/action/common/prepare_plugins/prep_101_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_101_fabric.py @@ -39,10 +39,12 @@ def prepare(self): parent_keys = ['vxlan', 'fabric'] dm_check = data_model_key_check(model_data, parent_keys) if 'fabric' in dm_check['keys_not_found'] or 'fabric' in dm_check['keys_no_data']: - display.deprecated( - "Attempting to use vxlan.global.name and vxlan.global.fabric_type due to vxlan.fabric.name and vxlan.fabric.type not being defined. " + deprecated_msg = ( + "Attempting to use vxlan.global.name and vxlan.global.fabric_type due to " + "vxlan.fabric.name and vxlan.fabric.type not being defined. " "vxlan.global.name and vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric." ) + display.deprecated(msg=deprecated_msg, version="1.0.0") parent_keys = ['vxlan', 'global'] dm_check = data_model_key_check(model_data, parent_keys) @@ -72,10 +74,11 @@ def prepare(self): parent_keys = ['vxlan', 'fabric', 'name'] dm_check = data_model_key_check(model_data, parent_keys) if 'name' in dm_check['keys_no_data'] or 'name' in dm_check['keys_not_found']: - display.deprecated( + deprecated_msg = ( "Attempting to use vxlan.global.name due to vxlan.fabric.name not being defined. " "vxlan.global.name is being deprecated. Please use vxlan.fabric." ) + display.deprecated(msg=deprecated_msg, version="1.0.0") parent_keys = ['vxlan', 'global', 'name'] dm_check = data_model_key_check(model_data, parent_keys) if 'name' in dm_check['keys_data']: @@ -88,10 +91,11 @@ def prepare(self): parent_keys = ['vxlan', 'fabric', 'type'] dm_check = data_model_key_check(model_data, parent_keys) if 'type' in dm_check['keys_no_data'] or 'type' in dm_check['keys_not_found']: - display.deprecated( + deprecated_msg = ( "Attempting to use vxlan.global.type due to vxlan.fabric.type not being defined. " "vxlan.global.type is being deprecated. Please use vxlan.fabric." ) + display.deprecated(msg=deprecated_msg, version="1.0.0") parent_keys = ['vxlan', 'global', 'fabric_type'] dm_check = data_model_key_check(model_data, parent_keys) if 'fabric_type' in dm_check['keys_data']: diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index 33a27755f..9c1ad87fc 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -34,7 +34,7 @@ def prepare(self): # Remove the check for overlay_services after deprecation # Remove lines 32-37 overlay_key = 'overlay' - check = data_model_key_check(model_data, ['vxlan']) + check = data_model_key_check(model_data, ['vxlan']) if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: overlay_key = 'overlay_services' @@ -86,7 +86,7 @@ def prepare(self): if 'network_attach_group' in net: if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] - + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF'): # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into # a structure that is easier to use. diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index e2793bfcd..b69e4744a 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -55,7 +55,7 @@ def run(self, tmp=None, task_vars=None): module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "POST", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", "json_data": json_data }, task_vars=task_vars, @@ -68,7 +68,7 @@ def run(self, tmp=None, task_vars=None): break results['changed'] = True - + if operation == 'remove': for associated_child_fabric in associated_child_fabrics: if not any(associated_child_fabric == child_fabric['name'] for child_fabric in child_fabrics): @@ -77,7 +77,7 @@ def run(self, tmp=None, task_vars=None): module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "POST", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit", "json_data": json_data }, task_vars=task_vars, @@ -150,5 +150,3 @@ def run(self, tmp=None, task_vars=None): # https://rtp-ndfc1.cisco.com/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit # POST # {"destFabric":"nac-msd","sourceFabric":"nac-ndfc1"} - - diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index f660e99b0..2b841e3b6 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -54,7 +54,7 @@ def run(self, tmp=None, task_vars=None): dm_switches = model_data["vxlan"]["topology"]["switches"] elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] - + switch_match = next((item for item in dm_switches if item["serial_number"] == switch_serial_number)) if policy_match["nvPairs"]["SWITCH_NAME"] != switch_match["name"]: diff --git a/plugins/filter/quote.py b/plugins/filter/quote.py deleted file mode 100644 index 9203ea354..000000000 --- a/plugins/filter/quote.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - -DOCUMENTATION = r""" - name: quote - version_added: "0.4.0" - short_description: Quote - description: - - Quote a string or integer. - positional: item - options: - item: - description: Item to quote. - required: true -""" - -EXAMPLES = r""" - - quoted: "{{ var1 | cisco.nac_dc_vxlan.quote() }}" - # => True - -""" - -RETURN = r""" - _value: - description: - - A string value. - type: str -""" - -import operator -from jinja2.runtime import Undefined -from jinja2.exceptions import UndefinedError - -from packaging.version import Version - -from ansible.module_utils.six import string_types -from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError -from ansible.module_utils.common.text.converters import to_native - - -def quote(item): - # if not isinstance(version1, (string_types, Undefined)): - # raise AnsibleFilterTypeError(f"Can only check string versions, however version1 is: {type(version1)}") - - # if not isinstance(version2, (string_types, Undefined)): - # raise AnsibleFilterTypeError(f"Can only check string versions, however version2 is: {type(version2)}") - - # if not isinstance(op, (string_types, Undefined)) and op not in SUPPORTED_COMPARISON_OPERATORS: - # raise AnsibleFilterError(f"Unsupported operator {op} type. Supported operators are: {SUPPORTED_COMPARISON_OPERATORS}") - - try: - return f'"{item}"' - except UndefinedError: - raise - except Exception as e: - raise AnsibleFilterError("Unable handle version: %s" % to_native(e), orig_exc=e) - - -# ---- Ansible filters ---- -class FilterModule(object): - """ Quote filter """ - - def filters(self): - return { - "quote": quote - } diff --git a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py index d57354c38..010685900 100644 --- a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py +++ b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py @@ -18,7 +18,7 @@ def match(cls, inventory): # Remove the check for overlay_services after deprecation # Remove lines 21 - 23 overlay_key = 'overlay' - check = cls.data_model_key_check(inventory, ['vxlan']) + check = cls.data_model_key_check(inventory, ['vxlan']) if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: overlay_key = 'overlay_services' @@ -65,7 +65,7 @@ def match(cls, inventory): # sm_vrfs = None # network_attach_groups = None # vrf_attach_groups = None - + # network_keys = ['vxlan', 'overlay_services', 'networks'] # vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] # network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] diff --git a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py index a64bc7bd0..9441a018b 100644 --- a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py +++ b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py @@ -23,7 +23,7 @@ def match(cls, inventory): if inventory["vxlan"].get("overlay").get("vrfs", None): vrfs = inventory["vxlan"]["overlay"]["vrfs"] elif inventory["vxlan"].get("overlay_services").get("vrfs", None): - vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] + vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] for vrf in vrfs: current_vrf_netflow_status = vrf.get("netflow_enable", None) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index d81804d6b..9ee98627a 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_global.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -19,6 +19,8 @@ plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has plugins/action/dtc/update_switch_hostname_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtd/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/test/inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py import-3.10!skip diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index d81804d6b..9ee98627a 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_global.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -19,6 +19,8 @@ plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has plugins/action/dtc/update_switch_hostname_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtd/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/test/inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py import-3.10!skip diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index d81804d6b..9ee98627a 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_global.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_104_fabric_overlay_services.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -19,6 +19,8 @@ plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has plugins/action/dtc/update_switch_hostname_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtd/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/test/inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py import-3.10!skip From 4eb8d41b36f2aee7748260516a8115592f69e90f Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 10 Dec 2024 21:59:43 -0500 Subject: [PATCH 026/183] fix pipeline errors --- tests/sanity/ignore-2.14.txt | 2 ++ tests/sanity/ignore-2.15.txt | 2 ++ tests/sanity/ignore-2.16.txt | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 9ee98627a..b884a59c2 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,7 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 9ee98627a..b884a59c2 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,7 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 9ee98627a..b884a59c2 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,7 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation From 898fc202586106e046febee40737971db7e66169 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 11 Dec 2024 02:25:26 -0500 Subject: [PATCH 027/183] fix deprecation error in pipeline --- tests/sanity/ignore-2.14.txt | 4 ++-- tests/sanity/ignore-2.15.txt | 4 ++-- tests/sanity/ignore-2.16.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index b884a59c2..30491e760 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index b884a59c2..30491e760 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index b884a59c2..30491e760 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation From b0cb580a8df3fa3bd90f33d031d8a5fdcfd33135 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 11 Dec 2024 02:36:49 -0500 Subject: [PATCH 028/183] fix deprecation error in pipeline --- tests/sanity/ignore-2.14.txt | 4 ++-- tests/sanity/ignore-2.15.txt | 4 ++-- tests/sanity/ignore-2.16.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 30491e760..e7a8e1786 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 30491e760..e7a8e1786 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 30491e760..e7a8e1786 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate # No collection name found in call to Display.deprecated or AnsibleModule.deprecate +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation From 58bb54ab6251981d301bb81142da68428ffadbce Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 11 Dec 2024 03:03:10 -0500 Subject: [PATCH 029/183] fix deprecation error in pipeline --- tests/sanity/ignore-2.14.txt | 4 ++-- tests/sanity/ignore-2.15.txt | 4 ++-- tests/sanity/ignore-2.16.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index e7a8e1786..912544ad5 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index e7a8e1786..912544ad5 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index e7a8e1786..912544ad5 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,9 +1,9 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name!skip +plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name: No collection name found in call to Display.deprecated or AnsibleModule.deprecate!skip +plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation From 9ccf7226fa3a68d12f75baa7e843b3d5d4f011ac Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Thu, 12 Dec 2024 20:17:13 +0000 Subject: [PATCH 030/183] Fix prep_001 plugin for multisite --- .../action/common/prepare_plugins/prep_001_list_defaults.py | 3 ++- roles/validate/tasks/main.yml | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py index 8798874ad..83c34be07 100644 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py @@ -52,6 +52,7 @@ def set_list_default(self, parent_keys, target_key): # used by other plugins without having to check if the key exists. def prepare(self): self.model_data = self.kwargs['results']['model_extended'] + # -------------------------------------------------------------------- # Fabric Global List Defaults # -------------------------------------------------------------------- @@ -230,7 +231,7 @@ def prepare(self): parent_keys = ['vxlan', 'multisite'] dm_check = data_model_key_check(self.model_data, parent_keys) if 'multisite' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan'] = {'multisite': {}} + self.model_data['vxlan']['multisite'] = {} # Check vxlan.multisite.overlay list elements parent_keys = ['vxlan', 'multisite', 'overlay'] diff --git a/roles/validate/tasks/main.yml b/roles/validate/tasks/main.yml index 41525ac72..e112592e8 100644 --- a/roles/validate/tasks/main.yml +++ b/roles/validate/tasks/main.yml @@ -20,8 +20,6 @@ # SPDX-License-Identifier: MIT --- -- debug: msg="{{ nac_tags.all }}" - - name: Import Role Tasks ansible.builtin.import_tasks: sub_main.yml tags: "{{ nac_tags.validate_role }}" # Tags defined in roles/common_global/vars/main.yml From 2e64830afd0a7f6900f4eb9f712a954a658943dc Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Fri, 13 Dec 2024 03:06:41 +0000 Subject: [PATCH 031/183] Workflow fixes --- roles/dtc/common/tasks/sub_main_msd.yml | 1 - .../dc_vxlan_fabric_networks.j2 | 2 + .../msd_fabric/msd_fabric_networks.j2 | 3 + .../dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 | 2 + .../ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 | 3 + roles/dtc/remove/tasks/main.yml | 2 +- roles/dtc/remove/tasks/sub_main_msd.yml | 2 + .../rules/vxlan/402_overlay_services_vrfs.py | 47 ++++++++++++-- .../vxlan/403_overlay_services_networks.py | 63 +++++++++++++++++-- 9 files changed, 113 insertions(+), 12 deletions(-) diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 953af22c7..db88946a9 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -55,7 +55,6 @@ - name: Set MSD Switches List ansible.builtin.set_fact: msd_switches: "{{ msd_inventory.msd_switches }}" - when: msd_inventory.msd_switches is defined # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template diff --git a/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 index 68c5ea7b5..988c99b57 100644 --- a/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 +++ b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 @@ -1,4 +1,6 @@ {# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{# TODO: Remove lines 3-8. When we get here we should be normalized around overlay, not overlay_services#} +{% set networks = [] %} {% if MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks %} {% set networks = MD_Extended.vxlan.overlay.networks %} {% elif MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks %} diff --git a/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 index 41792ede1..04062bd4c 100644 --- a/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 +++ b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 @@ -41,6 +41,8 @@ {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} +{# Don't need to attach vrfs if there are no msd_switches #} +{% if msd_switches|length > 0 %} {% if net['network_attach_group'] is defined %} attach: {% if MD_Extended.vxlan.multisite.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.multisite.overlay.network_attach_groups_dict %} @@ -52,5 +54,6 @@ {% endfor %} deploy: false {% endif %} +{% endif %} {% endfor %} diff --git a/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 index 7e24e6660..ad37341b7 100644 --- a/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 @@ -1,4 +1,6 @@ {# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{# TODO: Remove lines 3-8. When we get here we should be normalized around overlay, not overlay_services#} +{% set vrfs = [] %} {% if MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs %} {% set vrfs = MD_Extended.vxlan.overlay.vrfs %} {% elif MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs %} diff --git a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 index 65f245e86..1eb61cbc9 100644 --- a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 @@ -28,6 +28,8 @@ {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} +{# Don't need to attach vrfs if there are no msd_switches #} +{% if msd_switches|length > 0 %} {% if vrf['vrf_attach_group'] is defined %} attach: {% if MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict %} @@ -38,5 +40,6 @@ {% endfor %} deploy: false {% endif %} +{% endif %} {% endfor %} diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index b7cd6c7fa..c9f755aa6 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -31,7 +31,7 @@ ansible.builtin.import_tasks: sub_main_msd.yml when: - MD_Extended.vxlan.fabric.type == 'MSD' - - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs or changes_detected_vpc_peering or changes_detected_link_vpc_peering or changes_detected_inventory + # - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/sub_main_msd.yml b/roles/dtc/remove/tasks/sub_main_msd.yml index bdec899ed..4efd92283 100644 --- a/roles/dtc/remove/tasks/sub_main_msd.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -39,12 +39,14 @@ register: switch_list tags: "{{ nac_tags.remove }}" +# These are not working right... investigate - name: Remove Fabric Networks ansible.builtin.import_tasks: msd/networks.yml tags: "{{ nac_tags.remove_networks }}" when: - changes_detected_networks +# These are not working right... investigate - name: Remove Fabric VRFs ansible.builtin.import_tasks: msd/vrfs.yml tags: "{{ nac_tags.remove_vrfs }}" diff --git a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py index 9441a018b..ec2fcf1de 100644 --- a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py +++ b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py @@ -19,12 +19,22 @@ def match(cls, inventory): if inventory["vxlan"].get("underlay").get("multicast", None): fabric_trm_status = inventory["vxlan"]["underlay"]["multicast"].get("trm_enable", False) - if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): - if inventory["vxlan"].get("overlay").get("vrfs", None): - vrfs = inventory["vxlan"]["overlay"]["vrfs"] - elif inventory["vxlan"].get("overlay_services").get("vrfs", None): + vrf_keys = ['vxlan', 'overlay', 'vrfs'] + check = cls.data_model_key_check(inventory, vrf_keys) + if 'vrfs' in check['keys_data']: + vrfs = inventory["vxlan"]["overlay"]["vrfs"] + else: + vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] + check = cls.data_model_key_check(inventory, vrf_keys) + if 'vrfs' in check['keys_data']: vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] + # if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): + # if inventory["vxlan"].get("overlay").get("vrfs", None): + # vrfs = inventory["vxlan"]["overlay"]["vrfs"] + # elif inventory["vxlan"].get("overlay_services").get("vrfs", None): + # vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] + for vrf in vrfs: current_vrf_netflow_status = vrf.get("netflow_enable", None) if current_vrf_netflow_status is not None: @@ -99,3 +109,32 @@ def match(cls, inventory): break return results + + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict diff --git a/roles/validate/files/rules/vxlan/403_overlay_services_networks.py b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py index 97348cd94..daf4c7acd 100644 --- a/roles/validate/files/rules/vxlan/403_overlay_services_networks.py +++ b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py @@ -15,17 +15,40 @@ def match(cls, inventory): if inventory["vxlan"].get("global").get("netflow", None): fabric_netflow_status = inventory["vxlan"]["global"]["netflow"].get("enable", False) + # Uncomment 19-22 when verified to work and remove line 13-16. + # netflow_keys = ['vxlan', 'global', 'netflow', 'enable'] + # check = cls.data_model_key_check(inventory, netflow_keys) + # if 'enable' in check['keys_data']: + # fabric_netflow_status = cls.safeget(inventory, netflow_keys) + + if inventory.get("vxlan", None): if inventory["vxlan"].get("underlay", None): if inventory["vxlan"].get("underlay").get("multicast", None): fabric_trm_status = inventory["vxlan"]["underlay"]["multicast"].get("trm_enable", False) - if inventory.get("vxlan", None): - if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): - if inventory["vxlan"].get("overlay").get("networks", None): - networks = inventory["vxlan"]["overlay"]["networks"] - elif inventory["vxlan"].get("overlay_services").get("networks", None): - networks = inventory["vxlan"]["overlay_services"]["networks"] + # Uncomment 31-34 when verified to work and remove line 25-28. + # trm_keys = ['vxlan', 'underlay', 'multicast', 'trm_enabled'] + # check = cls.data_model_key_check(inventory, trm_keys) + # if 'trm_enable' in check['keys_data']: + # fabric_trm_status = cls.safeget(inventory, trm_keys) + + network_keys = ['vxlan', 'overlay', 'networks'] + check = cls.data_model_key_check(inventory, network_keys) + if 'networks' in check['keys_data']: + networks = inventory["vxlan"]["overlay"]["networks"] + else: + network_keys = ['vxlan', 'overlay_services', 'networks'] + check = cls.data_model_key_check(inventory, network_keys) + if 'networks' in check['keys_data']: + networks = inventory["vxlan"]["overlay_services"]["networks"] + + # if inventory.get("vxlan", None): + # if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): + # if inventory["vxlan"].get("overlay").get("networks", None): + # networks = inventory["vxlan"]["overlay"]["networks"] + # elif inventory["vxlan"].get("overlay_services").get("networks", None): + # networks = inventory["vxlan"]["overlay_services"]["networks"] for network in networks: current_network_netflow_status = network.get("netflow_enable", None) @@ -57,3 +80,31 @@ def match(cls, inventory): break return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict From 58dd0f0e03b54d933bb859b8fab0a1619272fdaa Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Fri, 20 Dec 2024 21:27:27 +0000 Subject: [PATCH 032/183] Fix list defaults bug --- .../prepare_plugins/prep_001_list_defaults.py | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py index 83c34be07..474a12311 100644 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py @@ -74,13 +74,11 @@ def prepare(self): # Check vxlan.topology list elements parent_keys = ['vxlan', 'topology'] dm_check = data_model_key_check(self.model_data, parent_keys) - if 'topology' in dm_check['keys_not_found']: - self.model_data['vxlan']['topology'] = {} - if 'topology' in dm_check['keys_no_data']: - self.model_data['vxlan']['topology'] = {'edge_connections': []} - self.model_data['vxlan']['topology'] = {'fabric_links': []} - self.model_data['vxlan']['topology'] = {'switches': []} - self.model_data['vxlan']['topology'] = {'vpc_peers': []} + if ('topology' in dm_check['keys_no_data']) or ('topology' in dm_check['keys_not_found']): + self.model_data['vxlan']['topology']['edge_connections'] = [] + self.model_data['vxlan']['topology']['fabric_links'] = [] + self.model_data['vxlan']['topology']['switches'] = [] + self.model_data['vxlan']['topology']['vpc_peers'] = [] # Check vxlan.topology.fabric_links list element target_key = 'fabric_links' @@ -133,10 +131,10 @@ def prepare(self): parent_keys = ['vxlan', 'overlay'] dm_check = data_model_key_check(self.model_data, parent_keys) if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay'] = {'vrfs': []} - self.model_data['vxlan']['overlay'] = {'vrf_attach_groups': []} - self.model_data['vxlan']['overlay'] = {'networks': []} - self.model_data['vxlan']['overlay'] = {'network_attach_groups': []} + self.model_data['vxlan']['overlay']['vrfs'] = [] + self.model_data['vxlan']['overlay']['vrf_attach_groups'] = [] + self.model_data['vxlan']['overlay']['networks'] = [] + self.model_data['vxlan']['overlay']['network_attach_groups'] = [] # Check vxlan.overlay_services.vrfs list element target_key = 'vrfs' @@ -182,10 +180,10 @@ def prepare(self): parent_keys = ['vxlan', 'overlay_services'] dm_check = data_model_key_check(self.model_data, parent_keys) if 'overlay_services' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay_services'] = {'vrfs': []} - self.model_data['vxlan']['overlay_services'] = {'vrf_attach_groups': []} - self.model_data['vxlan']['overlay_services'] = {'networks': []} - self.model_data['vxlan']['overlay_services'] = {'network_attach_groups': []} + self.model_data['vxlan']['overlay_services']['vrfs'] = [] + self.model_data['vxlan']['overlay_services']['vrf_attach_groups'] = [] + self.model_data['vxlan']['overlay_services']['networks'] = [] + self.model_data['vxlan']['overlay_services']['network_attach_groups'] = [] # Check vxlan.overlay_services.vrfs list element target_key = 'vrfs' @@ -237,10 +235,10 @@ def prepare(self): parent_keys = ['vxlan', 'multisite', 'overlay'] dm_check = data_model_key_check(self.model_data, parent_keys) if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay'] = {'vrfs': []} - self.model_data['vxlan']['multisite']['overlay'] = {'vrf_attach_groups': []} - self.model_data['vxlan']['multisite']['overlay'] = {'networks': []} - self.model_data['vxlan']['multisite']['overlay'] = {'network_attach_groups': []} + self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] + self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] + self.model_data['vxlan']['multisite']['overlay']['networks'] = [] + self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] # Check vxlan.multisite.overlay_services.vrfs list element target_key = 'vrfs' From e7ef318ecfd9a9965abd4a5177808ecf6f49d2c9 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sat, 21 Dec 2024 05:48:24 +0000 Subject: [PATCH 033/183] Prepare plugin refactor --- ...{prep_101_fabric.py => prep_001_fabric.py} | 21 + .../prepare_plugins/prep_001_list_defaults.py | 308 -------------- .../prepare_plugins/prep_002_list_defaults.py | 395 ++++++++++++++++++ .../common/prepare_plugins/prep_999_verify.py | 65 +++ plugins/plugin_utils/data_model_keys.py | 67 +++ 5 files changed, 548 insertions(+), 308 deletions(-) rename plugins/action/common/prepare_plugins/{prep_101_fabric.py => prep_001_fabric.py} (84%) delete mode 100644 plugins/action/common/prepare_plugins/prep_001_list_defaults.py create mode 100644 plugins/action/common/prepare_plugins/prep_002_list_defaults.py create mode 100644 plugins/action/common/prepare_plugins/prep_999_verify.py create mode 100644 plugins/plugin_utils/data_model_keys.py diff --git a/plugins/action/common/prepare_plugins/prep_101_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py similarity index 84% rename from plugins/action/common/prepare_plugins/prep_101_fabric.py rename to plugins/action/common/prepare_plugins/prep_001_fabric.py index 9940d471f..497e3b7a9 100644 --- a/plugins/action/common/prepare_plugins/prep_101_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -33,6 +33,13 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] + # !!! WARNING !!! + # ------------------------------------------------------------------------------------------ + # If you are debugging problems with the data model and sections are missing make sure + # you don't have any data files with only the toplevel vxlan: key. This can cause problems + # where IaC validate removes sections of the model data, like the vxlan.underlay section + # ------------------------------------------------------------------------------------------ + # Checking for fabric key in the data model. # This type of check should be done in a rule, but fabric.name and fabric.type are foundational for the collection so we need to ensure it is set. # This prepare plugin also helps retain backwards compatibility with global.name and global.fabric_type keys previously used. @@ -104,5 +111,19 @@ def prepare(self): self.kwargs['results']['failed'] = True self.kwargs['results']['msg'] = "vxlan.fabric.type is not defined in the data model." + + # Replace 'overlay_services' key with 'overlay' + parent_keys = ['vxlan', 'overlay_services'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'overlay_services' in dm_check['keys_found']: + deprecated_msg = ( + "vxlan.overlay_services is being deprecated. " + "Please use vxlan.overlay instead" + ) + display.deprecated(msg=deprecated_msg, version="1.0.0") + model_data['vxlan']['overlay'] = model_data['vxlan']['overlay_services'] + del model_data['vxlan']['overlay_services'] + + self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py b/plugins/action/common/prepare_plugins/prep_001_list_defaults.py deleted file mode 100644 index 474a12311..000000000 --- a/plugins/action/common/prepare_plugins/prep_001_list_defaults.py +++ /dev/null @@ -1,308 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - - -from ....plugin_utils.helper_functions import data_model_key_check - - -def update_nested_dict(nested_dict, keys, new_value): - if len(keys) == 1: - nested_dict[keys[0]] = new_value - else: - key = keys[0] - if key in nested_dict: - update_nested_dict(nested_dict[key], keys[1:], new_value) - - -class PreparePlugin: - def __init__(self, **kwargs): - self.kwargs = kwargs - self.keys = [] - - def set_list_default(self, parent_keys, target_key): - keys = parent_keys + [target_key] - dm_check = data_model_key_check(self.model_data, keys) - if target_key in dm_check['keys_not_found'] or \ - target_key in dm_check['keys_no_data']: - update_nested_dict(self.model_data, keys, []) - - # The prepare method is used to default each list or nested list - # in the model data to an empty list if the key for the list does - # not exist or data under they key does not exist. - # - # This is to ensure that the model data is consistent and can be - # used by other plugins without having to check if the key exists. - def prepare(self): - self.model_data = self.kwargs['results']['model_extended'] - - # -------------------------------------------------------------------- - # Fabric Global List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.global list elements - parent_keys = ['vxlan', 'global'] - target_key = 'dns_servers' - self.set_list_default(parent_keys, target_key) - - # keys = ['vxlan', 'global', 'ntp_servers'] - parent_keys = ['vxlan', 'global'] - target_key = 'ntp_servers' - self.set_list_default(parent_keys, target_key) - - # -------------------------------------------------------------------- - # Fabric Topology List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.topology list elements - parent_keys = ['vxlan', 'topology'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if ('topology' in dm_check['keys_no_data']) or ('topology' in dm_check['keys_not_found']): - self.model_data['vxlan']['topology']['edge_connections'] = [] - self.model_data['vxlan']['topology']['fabric_links'] = [] - self.model_data['vxlan']['topology']['switches'] = [] - self.model_data['vxlan']['topology']['vpc_peers'] = [] - - # Check vxlan.topology.fabric_links list element - target_key = 'fabric_links' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.topology.edge_connections list element - target_key = 'edge_connections' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.topology.switches list element - target_key = 'switches' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.topology.vpc_peers list element - target_key = 'vpc_peers' - self.set_list_default(parent_keys, target_key) - - # -------------------------------------------------------------------- - # Fabric Topology Switches Freeforms List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.topology.switches[index].freeforms list elements - list_index = 0 - for switch in self.model_data['vxlan']['topology']['switches']: - dm_check = data_model_key_check(switch, ['freeforms']) - if 'freeforms' in dm_check['keys_not_found'] or \ - 'freeforms' in dm_check['keys_no_data']: - self.model_data['vxlan']['topology']['switches'][list_index]['freeforms'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Topology Switches Interfaces List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.topology.switches[index].interfaces list elements - list_index = 0 - for switch in self.model_data['vxlan']['topology']['switches']: - dm_check = data_model_key_check(switch, ['interfaces']) - if 'interfaces' in dm_check['keys_not_found'] or 'interfaces' in dm_check['keys_no_data']: - self.model_data['vxlan']['topology']['switches'][list_index]['interfaces'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Overlay List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.overlay list elements - parent_keys = ['vxlan', 'overlay'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay']['vrfs'] = [] - self.model_data['vxlan']['overlay']['vrf_attach_groups'] = [] - self.model_data['vxlan']['overlay']['networks'] = [] - self.model_data['vxlan']['overlay']['network_attach_groups'] = [] - - # Check vxlan.overlay_services.vrfs list element - target_key = 'vrfs' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay.vrf_attach_groups list element - target_key = 'vrf_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay.vrf_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay']['vrf_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.overlay.networks list element - target_key = 'networks' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay.network_attach_groups list element - target_key = 'network_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay.network_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay']['network_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay']['network_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Overlay List Defaults - Backwards Compatibility - # -------------------------------------------------------------------- - - # Check vxlan.overlay_services list elements - parent_keys = ['vxlan', 'overlay_services'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'overlay_services' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay_services']['vrfs'] = [] - self.model_data['vxlan']['overlay_services']['vrf_attach_groups'] = [] - self.model_data['vxlan']['overlay_services']['networks'] = [] - self.model_data['vxlan']['overlay_services']['network_attach_groups'] = [] - - # Check vxlan.overlay_services.vrfs list element - target_key = 'vrfs' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay_services.vrf_attach_groups list element - target_key = 'vrf_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay_services.vrf_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay_services']['vrf_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay_services']['vrf_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.overlay_services.networks list element - target_key = 'networks' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay_services.network_attach_groups list element - target_key = 'network_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.overlay_services.network_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay_services']['network_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay_services']['network_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Multisite Fabric Overlay List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.multisite list elements - parent_keys = ['vxlan', 'multisite'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'multisite' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite'] = {} - - # Check vxlan.multisite.overlay list elements - parent_keys = ['vxlan', 'multisite', 'overlay'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'overlay' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] - self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] - self.model_data['vxlan']['multisite']['overlay']['networks'] = [] - self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] - - # Check vxlan.multisite.overlay_services.vrfs list element - target_key = 'vrfs' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.multisite.overlay.vrf_attach_groups list element - target_key = 'vrf_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.multisite.overlay.vrf_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.multisite.overlay.networks list element - target_key = 'networks' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.multisite.overlay.network_attach_groups list element - target_key = 'network_attach_groups' - self.set_list_default(parent_keys, target_key) - - # Check vxlan.multisite.overlay.network_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['multisite']['overlay']['network_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Policy List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.policy list elements - parent_keys = ['vxlan', 'policy'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'policy' in dm_check['keys_not_found'] or 'policy' in dm_check['keys_no_data']: - self.model_data['vxlan']['policy'] = {} - self.model_data['vxlan']['policy'].update({'policies': []}) - self.model_data['vxlan']['policy'].update({'groups': []}) - self.model_data['vxlan']['policy'].update({'switches': []}) - - parent_keys = ['vxlan', 'policy', 'policies'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'policies' in dm_check['keys_not_found'] or 'policies' in dm_check['keys_no_data']: - self.model_data['vxlan']['policy']['policies'] = [] - - parent_keys = ['vxlan', 'policy', 'groups'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'groups' in dm_check['keys_not_found'] or 'groups' in dm_check['keys_no_data']: - self.model_data['vxlan']['policy']['groups'] = [] - - parent_keys = ['vxlan', 'policy', 'switches'] - dm_check = data_model_key_check(self.model_data, parent_keys) - if 'switches' in dm_check['keys_not_found'] or 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['policy']['switches'] = [] - - self.kwargs['results']['model_extended'] = self.model_data - return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py new file mode 100644 index 000000000..24e1b250b --- /dev/null +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -0,0 +1,395 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + + +from ....plugin_utils.helper_functions import data_model_key_check +from ....plugin_utils.data_model_keys import model_keys + + +def update_nested_dict(nested_dict, keys, new_value): + if len(keys) == 1: + nested_dict[keys[0]] = new_value + else: + key = keys[0] + if key in nested_dict: + update_nested_dict(nested_dict[key], keys[1:], new_value) + + +class PreparePlugin: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.keys = [] + + def set_list_default(self, parent_keys, target_key): + keys = parent_keys + [target_key] + dm_check = data_model_key_check(self.model_data, keys) + if target_key in dm_check['keys_not_found'] or \ + target_key in dm_check['keys_no_data']: + update_nested_dict(self.model_data, keys, []) + + # The prepare method is used to default each list or nested list + # in the model data to an empty list if the key for the list does + # not exist or data under they key does not exist. + # + # This is to ensure that the model data is consistent and can be + # used by other plugins without having to check if the key exists. + def prepare(self): + self.model_data = self.kwargs['results']['model_extended'] + + # -------------------------------------------------------------------- + # Fabric Global List Defaults + # -------------------------------------------------------------------- + from pprint import pprint + + paths = [ + 'global.dns_servers', + 'global.ntp_servers', + 'global.syslog_servers', + 'global.netflow', + 'global.netflow.exporter', + 'global.netflow.record', + 'global.netflow.monitor', + 'topology', + 'topology.edge_connections', + 'topology.fabric_links', + 'topology.switches', + 'topology.vpc_peers', + 'overlay', + 'overlay.vrfs', + 'overlay.vrf_attach_groups', + 'overlay.networks', + 'overlay.network_attach_groups', + 'multisite', + 'multisite.overlay', + 'multisite.overlay.vrfs', + 'multisite.overlay.vrf_attach_groups', + 'multisite.overlay.networks', + 'multisite.overlay.network_attach_groups', + 'policy', + 'policy.policies', + 'policy.groups', + 'policy.switches' + ] + for path in paths: + # Get all but the last 2 elements of model_keys[path] + path_type = model_keys[path][-1] + parent_keys = model_keys[path][:-2] + target_key = model_keys[path][-2] + if path_type == 'KEY': + dm_check = data_model_key_check(self.model_data, parent_keys + [target_key]) + if target_key in dm_check['keys_not_found'] or target_key in dm_check['keys_no_data']: + update_nested_dict(self.model_data, parent_keys + [target_key], {}) + if path_type == 'LIST': + self.set_list_default(parent_keys, target_key) + + # -------------------------------------------------------------------- + # Fabric Topology Switches Freeforms List Defaults + # -------------------------------------------------------------------- + + # Check vxlan.topology.switches[index].freeforms list elements + list_index = 0 + for switch in self.model_data['vxlan']['topology']['switches']: + dm_check = data_model_key_check(switch, ['freeforms']) + if 'freeforms' in dm_check['keys_not_found'] or \ + 'freeforms' in dm_check['keys_no_data']: + self.model_data['vxlan']['topology']['switches'][list_index]['freeforms'] = [] + + list_index += 1 + + # -------------------------------------------------------------------- + # Fabric Topology Switches Interfaces List Defaults + # -------------------------------------------------------------------- + + # Check vxlan.topology.switches[index].interfaces list elements + list_index = 0 + for switch in self.model_data['vxlan']['topology']['switches']: + dm_check = data_model_key_check(switch, ['interfaces']) + if 'interfaces' in dm_check['keys_not_found'] or 'interfaces' in dm_check['keys_no_data']: + self.model_data['vxlan']['topology']['switches'][list_index]['interfaces'] = [] + + list_index += 1 + + # Check vxlan.overlay.vrf_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['overlay']['vrf_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # Check vxlan.overlay.network_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['overlay']['network_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['overlay']['network_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # Check vxlan.multisite.overlay.vrf_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # Check vxlan.multisite.overlay.network_attach_groups[index].switches list elements + list_index = 0 + for group in self.model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + dm_check = data_model_key_check(group, ['switches']) + if 'switches' in dm_check['keys_not_found'] or \ + 'switches' in dm_check['keys_no_data']: + self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'][list_index]['switches'] = [] + + list_index += 1 + + # # Check vxlan.global list elements + # parent_keys = ['vxlan', 'global'] + # target_key = 'dns_servers' + # self.set_list_default(parent_keys, target_key) + + # # keys = ['vxlan', 'global', 'ntp_servers'] + # parent_keys = ['vxlan', 'global'] + # target_key = 'ntp_servers' + # self.set_list_default(parent_keys, target_key) + + # # keys = ['vxlan', 'global', 'syslog_servers'] + # parent_keys = ['vxlan', 'global'] + # target_key = 'syslog_servers' + # self.set_list_default(parent_keys, target_key) + + # -------------------------------------------------------------------- + # Fabric Topology List Defaults + # -------------------------------------------------------------------- + + # # Check vxlan.topology list elements + # parent_keys = ['vxlan', 'topology'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'topology' in dm_check['keys_not_found'] or 'topology' in dm_check['keys_no_data']: + # self.model_data['vxlan']['topology'] = {} + # self.model_data['vxlan']['topology']['edge_connections'] = [] + # self.model_data['vxlan']['topology']['fabric_links'] = [] + # self.model_data['vxlan']['topology']['switches'] = [] + # self.model_data['vxlan']['topology']['vpc_peers'] = [] + + + # # Check vxlan.topology.fabric_links list element + # target_key = 'fabric_links' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.topology.edge_connections list element + # target_key = 'edge_connections' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.topology.switches list element + # target_key = 'switches' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.topology.vpc_peers list element + # target_key = 'vpc_peers' + # self.set_list_default(parent_keys, target_key) + + + # -------------------------------------------------------------------- + # Fabric Overlay List Defaults + # -------------------------------------------------------------------- + + # # Check vxlan.overlay list elements + # parent_keys = ['vxlan', 'overlay'] + + # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay'] = {} + + # check_keys = parent_keys + ['vrfs'] + # dm_check = data_model_key_check(self.model_data, check_keys) + # if 'vrfs' in dm_check['keys_not_found'] or 'vrfs' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay']['vrfs'] = [] + # self.model_data['vxlan']['overlay']['vrf_attach_groups'] = [] + + # check_keys = parent_keys + ['networks'] + # dm_check = data_model_key_check(self.model_data, check_keys) + # if 'networks' in dm_check['keys_not_found'] or 'networks' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay']['networks'] = [] + # self.model_data['vxlan']['overlay']['network_attach_groups'] = [] + + # # Check vxlan.overlay.vrfs list element + # target_key = 'vrfs' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay.vrf_attach_groups list element + # target_key = 'vrf_attach_groups' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay.networks list element + # target_key = 'networks' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay.network_attach_groups list element + # target_key = 'network_attach_groups' + # self.set_list_default(parent_keys, target_key) + + + # # MWIEBE: SHOULD NOT NEED THIS ANYMORE + # # -------------------------------------------------------------------- + # # Fabric Overlay List Defaults - Backwards Compatibility + # # -------------------------------------------------------------------- + + # # Check vxlan.overlay_services list elements + # parent_keys = ['vxlan', 'overlay_services'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'overlay_services' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay_services']['vrfs'] = [] + # self.model_data['vxlan']['overlay_services']['vrf_attach_groups'] = [] + # self.model_data['vxlan']['overlay_services']['networks'] = [] + # self.model_data['vxlan']['overlay_services']['network_attach_groups'] = [] + + # # Check vxlan.overlay_services.vrfs list element + # target_key = 'vrfs' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay_services.vrf_attach_groups list element + # target_key = 'vrf_attach_groups' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay_services.vrf_attach_groups[index].switches list elements + # list_index = 0 + # for group in self.model_data['vxlan']['overlay_services']['vrf_attach_groups']: + # dm_check = data_model_key_check(group, ['switches']) + # if 'switches' in dm_check['keys_not_found'] or \ + # 'switches' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay_services']['vrf_attach_groups'][list_index]['switches'] = [] + + # list_index += 1 + + # # Check vxlan.overlay_services.networks list element + # target_key = 'networks' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay_services.network_attach_groups list element + # target_key = 'network_attach_groups' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.overlay_services.network_attach_groups[index].switches list elements + # list_index = 0 + # for group in self.model_data['vxlan']['overlay_services']['network_attach_groups']: + # dm_check = data_model_key_check(group, ['switches']) + # if 'switches' in dm_check['keys_not_found'] or \ + # 'switches' in dm_check['keys_no_data']: + # self.model_data['vxlan']['overlay_services']['network_attach_groups'][list_index]['switches'] = [] + + # list_index += 1 + + # -------------------------------------------------------------------- + # Multisite Fabric Overlay List Defaults + # -------------------------------------------------------------------- + + # # Check vxlan.overlay list elements + # parent_keys = ['vxlan', 'multisite', 'overlay'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + + # if 'multisite' in dm_check['keys_not_found'] or 'multisite' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite'] = {} + # self.model_data['vxlan']['multisite']['overlay'] = {} + + # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite']['overlay'] = {} + + # check_keys = parent_keys + ['vrfs'] + # dm_check = data_model_key_check(self.model_data, check_keys) + # if 'vrfs' in dm_check['keys_not_found'] or 'vrfs' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] + # self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] + + # check_keys = parent_keys + ['networks'] + # dm_check = data_model_key_check(self.model_data, check_keys) + # if 'networks' in dm_check['keys_not_found'] or 'networks' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite']['overlay']['networks'] = [] + # self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] + + # # Check vxlan.multisite list elements + # parent_keys = ['vxlan', 'multisite'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'multisite' in dm_check['keys_not_found'] or 'multisite' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite'] = {} + + # # Check vxlan.multisite.overlay list elements + # parent_keys = ['vxlan', 'multisite', 'overlay'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: + # self.model_data['vxlan']['multisite']['overlay'] = {} + # self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] + # self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] + # self.model_data['vxlan']['multisite']['overlay']['networks'] = [] + # self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] + + # # Check vxlan.multisite.overlay.vrfs list element + # target_key = 'vrfs' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.multisite.overlay.vrf_attach_groups list element + # target_key = 'vrf_attach_groups' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.multisite.overlay.networks list element + # target_key = 'networks' + # self.set_list_default(parent_keys, target_key) + + # # Check vxlan.multisite.overlay.network_attach_groups list element + # target_key = 'network_attach_groups' + # self.set_list_default(parent_keys, target_key) + + + # -------------------------------------------------------------------- + # Fabric Policy List Defaults + # -------------------------------------------------------------------- + + # # Check vxlan.policy list elements + # parent_keys = ['vxlan', 'policy'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'policy' in dm_check['keys_not_found'] or 'policy' in dm_check['keys_no_data']: + # self.model_data['vxlan']['policy'] = {} + # self.model_data['vxlan']['policy'].update({'policies': []}) + # self.model_data['vxlan']['policy'].update({'groups': []}) + # self.model_data['vxlan']['policy'].update({'switches': []}) + + # parent_keys = ['vxlan', 'policy', 'policies'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'policies' in dm_check['keys_not_found'] or 'policies' in dm_check['keys_no_data']: + # self.model_data['vxlan']['policy']['policies'] = [] + + # parent_keys = ['vxlan', 'policy', 'groups'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'groups' in dm_check['keys_not_found'] or 'groups' in dm_check['keys_no_data']: + # self.model_data['vxlan']['policy']['groups'] = [] + + # parent_keys = ['vxlan', 'policy', 'switches'] + # dm_check = data_model_key_check(self.model_data, parent_keys) + # if 'switches' in dm_check['keys_not_found'] or 'switches' in dm_check['keys_no_data']: + # self.model_data['vxlan']['policy']['switches'] = [] + + self.kwargs['results']['model_extended'] = self.model_data + return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_999_verify.py b/plugins/action/common/prepare_plugins/prep_999_verify.py new file mode 100644 index 000000000..206100e47 --- /dev/null +++ b/plugins/action/common/prepare_plugins/prep_999_verify.py @@ -0,0 +1,65 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from ansible.utils.display import Display +from ....plugin_utils.helper_functions import data_model_key_check +from ....plugin_utils.data_model_keys import model_keys + +display = Display() + + +class PreparePlugin: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.keys = [] + + + def prepare(self): + model_data = self.kwargs['results']['model_extended'] + self.kwargs['results']['failed'] = False + self.kwargs['results']['msg'] = None + fail_msg = "Mandatory key ({}) not found in prepared data model!" + fail_msg += " There is either a bug in one of the prepare plugins or" + fail_msg += " the data was not included in the data model." + fail_msg += " Data Model Section: ({})" + + + # This prepare plugin serves as a final sanity check after all of the + # previous prepare plugins have been called to transform the model data. + # + # This plugin ensures the following: + # * All keys required for this collection to function are present (not accidentally overwritten) + # * List items that were present before the prepare plugins ran are still present + for key in model_keys.keys(): + dm_check = data_model_key_check(model_data, model_keys[key]) + # model_keys['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] + # Get 2nd to last item from the python list above + # model_keys[key][-2] - Gets 'policies' + if model_keys[key][-2] in dm_check['keys_not_found']: + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = fail_msg.format(key, model_keys[key]) + return self.kwargs['results'] + + + import epdb ; epdb.set_trace() + + # We don't need to pass any data back in this plugin because we don't modify any data. + return self.kwargs['results'] diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py new file mode 100644 index 000000000..e91ddd4a5 --- /dev/null +++ b/plugins/plugin_utils/data_model_keys.py @@ -0,0 +1,67 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +# This is an example file for help functions that can be called by +# our various action plugins for common routines. +# +# For example in prepare_serice_model.py we can do the following: +# from ..helper_functions import do_something + +root_key = 'vxlan' + +model_keys = {} +model_keys['fabric.name'] = [root_key, 'fabric', 'name', 'KEY'] +model_keys['fabric.type'] = [root_key, 'fabric', 'type', 'KEY'] + +model_keys['global'] = [root_key, 'global', 'KEY'] +model_keys['global.dns_servers'] = [root_key, 'global', 'dns_servers', 'LIST'] +model_keys['global.ntp_servers'] = [root_key, 'global', 'ntp_servers', 'LIST'] +model_keys['global.syslog_servers'] = [root_key, 'global', 'syslog_servers', 'LIST'] +model_keys['global.netflow'] = [root_key, 'global', 'netflow', 'KEY'] +model_keys['global.netflow.exporter'] = [root_key, 'global', 'netflow', 'exporter', 'LIST'] +model_keys['global.netflow.record'] = [root_key, 'global', 'netflow', 'record', 'LIST'] +model_keys['global.netflow.monitor'] = [root_key, 'global', 'netflow', 'monitor', 'LIST'] +# --- +model_keys['underlay'] = [root_key, 'underlay', 'KEY'] +# --- +model_keys['topology'] = [root_key, 'topology', 'KEY'] +model_keys['topology.edge_connections'] = [root_key, 'topology', 'edge_connections', 'LIST'] +model_keys['topology.fabric_links'] = [root_key, 'topology', 'fabric_links', 'LIST'] +model_keys['topology.switches'] = [root_key, 'topology', 'switches', 'LIST'] +model_keys['topology.vpc_peers'] = [root_key, 'topology', 'vpc_peers', 'LIST'] +# --- +model_keys['overlay'] = [root_key, 'overlay', 'KEY'] +model_keys['overlay.vrfs'] = [root_key, 'overlay', 'vrfs', 'LIST'] +model_keys['overlay.vrf_attach_groups'] = [root_key, 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['overlay.networks'] = [root_key, 'overlay', 'networks', 'LIST'] +model_keys['overlay.network_attach_groups'] = [root_key, 'overlay', 'network_attach_groups', 'LIST'] +# --- +model_keys['multisite'] = [root_key, 'multisite', 'KEY'] +model_keys['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] +model_keys['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] +model_keys['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] +model_keys['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] +# --- +model_keys['policy'] = [root_key, 'policy', 'KEY'] +model_keys['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] +model_keys['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] +model_keys['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] From e7ee3ff04a127ee44a79a1de991a219899d3ee33 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sun, 22 Dec 2024 17:55:50 +0000 Subject: [PATCH 034/183] More refactoring --- .../common/prepare_plugins/prep_001_fabric.py | 12 +- .../prepare_plugins/prep_002_list_defaults.py | 252 ++---------------- .../prep_104_fabric_overlay.py | 37 ++- .../common/prepare_plugins/prep_999_verify.py | 5 +- .../action/common/prepare_service_model.py | 6 +- plugins/plugin_utils/data_model_keys.py | 3 + roles/dtc/common/tasks/main.yml | 2 +- roles/dtc/common/tasks/msd/ndfc_vrfs.yml | 3 +- roles/dtc/common/tasks/sub_main_isn.yml | 24 ++ roles/dtc/common/tasks/sub_main_msd.yml | 26 ++ roles/dtc/common/tasks/sub_main_vxlan.yml | 82 ++++-- .../common/tasks/vxlan/ndfc_interface_all.yml | 2 - .../dtc/common/tasks/vxlan/ndfc_networks.yml | 3 +- roles/dtc/common/tasks/vxlan/ndfc_policy.yml | 2 +- .../common/tasks/vxlan/ndfc_vpc_peering.yml | 2 +- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 6 +- .../templates/ndfc_attach_vrfs_loopbacks.j2 | 4 +- .../dc_vxlan_fabric_networks.j2 | 5 - .../dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 | 5 - .../create/tasks/isn/devices_discovery.yml | 2 +- roles/dtc/create/tasks/isn/fabric.yml | 2 +- roles/dtc/create/tasks/main.yml | 33 ++- roles/dtc/create/tasks/msd/fabric.yml | 2 +- roles/dtc/create/tasks/msd/vrfs_networks.yml | 16 +- roles/dtc/create/tasks/sub_main_isn.yml | 4 +- roles/dtc/create/tasks/sub_main_msd.yml | 4 +- roles/dtc/create/tasks/sub_main_vxlan.yml | 20 +- .../create/tasks/vxlan/devices_discovery.yml | 4 +- roles/dtc/create/tasks/vxlan/fabric.yml | 2 +- roles/dtc/create/tasks/vxlan/interfaces.yml | 20 +- roles/dtc/create/tasks/vxlan/links.yml | 4 +- roles/dtc/create/tasks/vxlan/policies.yml | 2 +- roles/dtc/create/tasks/vxlan/vpc_peering.yml | 4 +- .../dtc/create/tasks/vxlan/vrfs_networks.yml | 33 ++- roles/dtc/deploy/tasks/main.yml | 16 +- roles/dtc/remove/tasks/main.yml | 17 +- roles/dtc/remove/tasks/msd/networks.yml | 2 +- roles/dtc/remove/tasks/msd/vrfs.yml | 2 +- roles/dtc/remove/tasks/sub_main_msd.yml | 4 +- roles/dtc/remove/tasks/sub_main_vxlan.yml | 14 +- roles/dtc/remove/tasks/vxlan/interfaces.yml | 2 +- roles/dtc/remove/tasks/vxlan/links.yml | 4 +- roles/dtc/remove/tasks/vxlan/networks.yml | 2 +- roles/dtc/remove/tasks/vxlan/switches.yml | 2 +- roles/dtc/remove/tasks/vxlan/vpc_peers.yml | 2 +- roles/dtc/remove/tasks/vxlan/vrfs.yml | 2 +- .../fabric_empty_example/networks.yaml | 2 +- .../examples/fabric_empty_example/vrfs.yaml | 2 +- .../fabric_full_large_example/networks.yaml | 2 +- .../fabric_full_large_example/vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../vrfs.yaml | 2 +- .../networks.yaml | 2 +- .../fabric_full_small_sha_example/vrfs.yaml | 2 +- 64 files changed, 344 insertions(+), 394 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 497e3b7a9..2e9742c15 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -40,6 +40,14 @@ def prepare(self): # where IaC validate removes sections of the model data, like the vxlan.underlay section # ------------------------------------------------------------------------------------------ + if not bool(model_data): + msg = 'Model data is empty! It is possible there is no data in host_vars or there' + msg += ' might be a bug in the model data. Please check host_vars for this fabric.' + msg += ' Possible reasons: duplicate keys, unsupported keys, invalid yaml etc...' + self.kwargs['results']['failed'] = True + self.kwargs['results']['msg'] = msg + return self.kwargs['results'] + # Checking for fabric key in the data model. # This type of check should be done in a rule, but fabric.name and fabric.type are foundational for the collection so we need to ensure it is set. # This prepare plugin also helps retain backwards compatibility with global.name and global.fabric_type keys previously used. @@ -112,7 +120,9 @@ def prepare(self): self.kwargs['results']['msg'] = "vxlan.fabric.type is not defined in the data model." - # Replace 'overlay_services' key with 'overlay' + # For backwards compatibility, replace 'overlay_services' key with 'overlay' + # NOTE: No prepare plugin, jinja2 template or ansible task should reference 'overlay_services' after this replacement. + # NOTE: Rules are different since rules run BEFORE prepare plugins parent_keys = ['vxlan', 'overlay_services'] dm_check = data_model_key_check(model_data, parent_keys) if 'overlay_services' in dm_check['keys_found']: diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py index 24e1b250b..6d8280ad4 100644 --- a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -19,10 +19,12 @@ # # SPDX-License-Identifier: MIT - +from ansible.utils.display import Display from ....plugin_utils.helper_functions import data_model_key_check from ....plugin_utils.data_model_keys import model_keys +display = Display() + def update_nested_dict(nested_dict, keys, new_value): if len(keys) == 1: @@ -63,10 +65,14 @@ def prepare(self): 'global.dns_servers', 'global.ntp_servers', 'global.syslog_servers', + 'global.spanning_tree', + 'global.spanning_tree.vlan_range', + 'global.spanning_tree.mst_instance_range', 'global.netflow', 'global.netflow.exporter', 'global.netflow.record', 'global.netflow.monitor', + 'underlay', 'topology', 'topology.edge_connections', 'topology.fabric_links', @@ -100,6 +106,13 @@ def prepare(self): if path_type == 'LIST': self.set_list_default(parent_keys, target_key) + # -------------------------------------------------------------------- + # The following sections deal with more difficult nexted list + # structures where there is a list_index in the middle of the dict. + # There may be a way to reduce the amount of code but for now leaving + # it as is. + # -------------------------------------------------------------------- + # -------------------------------------------------------------------- # Fabric Topology Switches Freeforms List Defaults # -------------------------------------------------------------------- @@ -127,6 +140,10 @@ def prepare(self): list_index += 1 + # -------------------------------------------------------------------- + # Fabric Overlay vrf and network attach group List Defaults + # -------------------------------------------------------------------- + # Check vxlan.overlay.vrf_attach_groups[index].switches list elements list_index = 0 for group in self.model_data['vxlan']['overlay']['vrf_attach_groups']: @@ -167,229 +184,16 @@ def prepare(self): list_index += 1 - # # Check vxlan.global list elements - # parent_keys = ['vxlan', 'global'] - # target_key = 'dns_servers' - # self.set_list_default(parent_keys, target_key) - - # # keys = ['vxlan', 'global', 'ntp_servers'] - # parent_keys = ['vxlan', 'global'] - # target_key = 'ntp_servers' - # self.set_list_default(parent_keys, target_key) - - # # keys = ['vxlan', 'global', 'syslog_servers'] - # parent_keys = ['vxlan', 'global'] - # target_key = 'syslog_servers' - # self.set_list_default(parent_keys, target_key) - - # -------------------------------------------------------------------- - # Fabric Topology List Defaults - # -------------------------------------------------------------------- - - # # Check vxlan.topology list elements - # parent_keys = ['vxlan', 'topology'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'topology' in dm_check['keys_not_found'] or 'topology' in dm_check['keys_no_data']: - # self.model_data['vxlan']['topology'] = {} - # self.model_data['vxlan']['topology']['edge_connections'] = [] - # self.model_data['vxlan']['topology']['fabric_links'] = [] - # self.model_data['vxlan']['topology']['switches'] = [] - # self.model_data['vxlan']['topology']['vpc_peers'] = [] - - - # # Check vxlan.topology.fabric_links list element - # target_key = 'fabric_links' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.topology.edge_connections list element - # target_key = 'edge_connections' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.topology.switches list element - # target_key = 'switches' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.topology.vpc_peers list element - # target_key = 'vpc_peers' - # self.set_list_default(parent_keys, target_key) - - - # -------------------------------------------------------------------- - # Fabric Overlay List Defaults - # -------------------------------------------------------------------- - - # # Check vxlan.overlay list elements - # parent_keys = ['vxlan', 'overlay'] - - # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay'] = {} - - # check_keys = parent_keys + ['vrfs'] - # dm_check = data_model_key_check(self.model_data, check_keys) - # if 'vrfs' in dm_check['keys_not_found'] or 'vrfs' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay']['vrfs'] = [] - # self.model_data['vxlan']['overlay']['vrf_attach_groups'] = [] - - # check_keys = parent_keys + ['networks'] - # dm_check = data_model_key_check(self.model_data, check_keys) - # if 'networks' in dm_check['keys_not_found'] or 'networks' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay']['networks'] = [] - # self.model_data['vxlan']['overlay']['network_attach_groups'] = [] - - # # Check vxlan.overlay.vrfs list element - # target_key = 'vrfs' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay.vrf_attach_groups list element - # target_key = 'vrf_attach_groups' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay.networks list element - # target_key = 'networks' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay.network_attach_groups list element - # target_key = 'network_attach_groups' - # self.set_list_default(parent_keys, target_key) - - - # # MWIEBE: SHOULD NOT NEED THIS ANYMORE - # # -------------------------------------------------------------------- - # # Fabric Overlay List Defaults - Backwards Compatibility - # # -------------------------------------------------------------------- - - # # Check vxlan.overlay_services list elements - # parent_keys = ['vxlan', 'overlay_services'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'overlay_services' in dm_check['keys_not_found'] or 'overlay_services' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay_services']['vrfs'] = [] - # self.model_data['vxlan']['overlay_services']['vrf_attach_groups'] = [] - # self.model_data['vxlan']['overlay_services']['networks'] = [] - # self.model_data['vxlan']['overlay_services']['network_attach_groups'] = [] - - # # Check vxlan.overlay_services.vrfs list element - # target_key = 'vrfs' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay_services.vrf_attach_groups list element - # target_key = 'vrf_attach_groups' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay_services.vrf_attach_groups[index].switches list elements - # list_index = 0 - # for group in self.model_data['vxlan']['overlay_services']['vrf_attach_groups']: - # dm_check = data_model_key_check(group, ['switches']) - # if 'switches' in dm_check['keys_not_found'] or \ - # 'switches' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay_services']['vrf_attach_groups'][list_index]['switches'] = [] - - # list_index += 1 - - # # Check vxlan.overlay_services.networks list element - # target_key = 'networks' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay_services.network_attach_groups list element - # target_key = 'network_attach_groups' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.overlay_services.network_attach_groups[index].switches list elements - # list_index = 0 - # for group in self.model_data['vxlan']['overlay_services']['network_attach_groups']: - # dm_check = data_model_key_check(group, ['switches']) - # if 'switches' in dm_check['keys_not_found'] or \ - # 'switches' in dm_check['keys_no_data']: - # self.model_data['vxlan']['overlay_services']['network_attach_groups'][list_index]['switches'] = [] - - # list_index += 1 - - # -------------------------------------------------------------------- - # Multisite Fabric Overlay List Defaults - # -------------------------------------------------------------------- - - # # Check vxlan.overlay list elements - # parent_keys = ['vxlan', 'multisite', 'overlay'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - - # if 'multisite' in dm_check['keys_not_found'] or 'multisite' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite'] = {} - # self.model_data['vxlan']['multisite']['overlay'] = {} - - # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite']['overlay'] = {} - - # check_keys = parent_keys + ['vrfs'] - # dm_check = data_model_key_check(self.model_data, check_keys) - # if 'vrfs' in dm_check['keys_not_found'] or 'vrfs' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] - # self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] - - # check_keys = parent_keys + ['networks'] - # dm_check = data_model_key_check(self.model_data, check_keys) - # if 'networks' in dm_check['keys_not_found'] or 'networks' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite']['overlay']['networks'] = [] - # self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] - - # # Check vxlan.multisite list elements - # parent_keys = ['vxlan', 'multisite'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'multisite' in dm_check['keys_not_found'] or 'multisite' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite'] = {} - - # # Check vxlan.multisite.overlay list elements - # parent_keys = ['vxlan', 'multisite', 'overlay'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'overlay' in dm_check['keys_not_found'] or 'overlay' in dm_check['keys_no_data']: - # self.model_data['vxlan']['multisite']['overlay'] = {} - # self.model_data['vxlan']['multisite']['overlay']['vrfs'] = [] - # self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] = [] - # self.model_data['vxlan']['multisite']['overlay']['networks'] = [] - # self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'] = [] - - # # Check vxlan.multisite.overlay.vrfs list element - # target_key = 'vrfs' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.multisite.overlay.vrf_attach_groups list element - # target_key = 'vrf_attach_groups' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.multisite.overlay.networks list element - # target_key = 'networks' - # self.set_list_default(parent_keys, target_key) - - # # Check vxlan.multisite.overlay.network_attach_groups list element - # target_key = 'network_attach_groups' - # self.set_list_default(parent_keys, target_key) - - - # -------------------------------------------------------------------- - # Fabric Policy List Defaults - # -------------------------------------------------------------------- - - # # Check vxlan.policy list elements - # parent_keys = ['vxlan', 'policy'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'policy' in dm_check['keys_not_found'] or 'policy' in dm_check['keys_no_data']: - # self.model_data['vxlan']['policy'] = {} - # self.model_data['vxlan']['policy'].update({'policies': []}) - # self.model_data['vxlan']['policy'].update({'groups': []}) - # self.model_data['vxlan']['policy'].update({'switches': []}) - - # parent_keys = ['vxlan', 'policy', 'policies'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'policies' in dm_check['keys_not_found'] or 'policies' in dm_check['keys_no_data']: - # self.model_data['vxlan']['policy']['policies'] = [] - - # parent_keys = ['vxlan', 'policy', 'groups'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'groups' in dm_check['keys_not_found'] or 'groups' in dm_check['keys_no_data']: - # self.model_data['vxlan']['policy']['groups'] = [] - - # parent_keys = ['vxlan', 'policy', 'switches'] - # dm_check = data_model_key_check(self.model_data, parent_keys) - # if 'switches' in dm_check['keys_not_found'] or 'switches' in dm_check['keys_no_data']: - # self.model_data['vxlan']['policy']['switches'] = [] + # Before returning check to see if global or underlay data is present and + # generate a warning if they are empty. There might actualy be data but + # one of the other model files might have a bug or everything except the + # top level vxlan key is commented out. + if not bool(self.model_data['vxlan']['underlay']): + msg = '((vxlan.underlay)) data is empty! Check your host_vars model data.' + display.warning(msg=msg, formatted=True) + if not bool(self.model_data['vxlan']['global']): + msg = '((vxlan.global)) data is empty! Check your host_vars model data.' + display.warning(msg=msg, formatted=True) self.kwargs['results']['model_extended'] = self.model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index 9c1ad87fc..4e9f26970 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -31,25 +31,18 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] switches = model_data['vxlan']['topology']['switches'] - # Remove the check for overlay_services after deprecation - # Remove lines 32-37 - overlay_key = 'overlay' - check = data_model_key_check(model_data, ['vxlan']) - if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: - overlay_key = 'overlay_services' - if model_data['vxlan']['fabric']['type'] in ('VXLAN_EVPN'): - # Rebuild sm_data['vxlan'][overlay_key]['vrf_attach_groups'] into + # Rebuild sm_data['vxlan']['overlay']['vrf_attach_groups'] into # a structure that is easier to use. vrf_grp_name_list = [] - model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'] = {} - for grp in model_data['vxlan'][overlay_key]['vrf_attach_groups']: - model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']] = [] + model_data['vxlan']['overlay']['vrf_attach_groups_dict'] = {} + for grp in model_data['vxlan']['overlay']['vrf_attach_groups']: + model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] vrf_grp_name_list.append(grp['name']) for switch in grp['switches']: - model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']].append(switch) + model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan'][overlay_key]['vrf_attach_groups_dict'][grp['name']]: + for switch in model_data['vxlan']['overlay']['vrf_attach_groups_dict'][grp['name']]: if any(sw['name'] == switch['hostname'] for sw in switches): found_switch = next((item for item in switches if item["name"] == switch['hostname'])) if found_switch.get('management').get('management_ipv4_address'): @@ -58,22 +51,22 @@ def prepare(self): switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] # Remove vrf_attach_group from vrf if the group_name is not defined - for vrf in model_data['vxlan'][overlay_key]['vrfs']: + for vrf in model_data['vxlan']['overlay']['vrfs']: if 'vrf_attach_group' in vrf: if vrf.get('vrf_attach_group') not in vrf_grp_name_list: del vrf['vrf_attach_group'] - # Rebuild sm_data['vxlan'][overlay_key]['network_attach_groups'] into + # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into # a structure that is easier to use. net_grp_name_list = [] - model_data['vxlan'][overlay_key]['network_attach_groups_dict'] = {} - for grp in model_data['vxlan'][overlay_key]['network_attach_groups']: - model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']] = [] + model_data['vxlan']['overlay']['network_attach_groups_dict'] = {} + for grp in model_data['vxlan']['overlay']['network_attach_groups']: + model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']] = [] net_grp_name_list.append(grp['name']) for switch in grp['switches']: - model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']].append(switch) + model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan'][overlay_key]['network_attach_groups_dict'][grp['name']]: + for switch in model_data['vxlan']['overlay']['network_attach_groups_dict'][grp['name']]: if any(sw['name'] == switch['hostname'] for sw in switches): found_switch = next((item for item in switches if item["name"] == switch['hostname'])) if found_switch.get('management').get('management_ipv4_address'): @@ -82,7 +75,7 @@ def prepare(self): switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] # Remove network_attach_group from net if the group_name is not defined - for net in model_data['vxlan'][overlay_key]['networks']: + for net in model_data['vxlan']['overlay']['networks']: if 'network_attach_group' in net: if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] @@ -112,7 +105,7 @@ def prepare(self): if vrf.get('vrf_attach_group') not in vrf_grp_name_list: del vrf['vrf_attach_group'] - # Rebuild sm_data['vxlan'][overlay_key]['network_attach_groups'] into + # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into # a structure that is easier to use. net_grp_name_list = [] model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_999_verify.py b/plugins/action/common/prepare_plugins/prep_999_verify.py index 206100e47..97e62a33a 100644 --- a/plugins/action/common/prepare_plugins/prep_999_verify.py +++ b/plugins/action/common/prepare_plugins/prep_999_verify.py @@ -59,7 +59,10 @@ def prepare(self): return self.kwargs['results'] - import epdb ; epdb.set_trace() + # from pprint import pprint + # md = model_data + # import epdb ; epdb.set_trace() + # pprint(md) # We don't need to pass any data back in this plugin because we don't modify any data. return self.kwargs['results'] diff --git a/plugins/action/common/prepare_service_model.py b/plugins/action/common/prepare_service_model.py index c2bebc18d..c61764d31 100644 --- a/plugins/action/common/prepare_service_model.py +++ b/plugins/action/common/prepare_service_model.py @@ -54,7 +54,6 @@ def run(self, tmp=None, task_vars=None): sm_data = self._task.args['model_data'] # results['model_extended'] contains the data that can be extended by the plugins results['model_extended'] = copy.deepcopy(sm_data) - fabric_type = sm_data.get('vxlan').get('fabric_type', None) full_plugin_path = "ansible_collections.cisco.nac_dc_vxlan.plugins.action.common.prepare_plugins" glob_plugin_path = os.path.dirname(__file__) + "/prepare_plugins" @@ -86,6 +85,11 @@ def run(self, tmp=None, task_vars=None): templates_path=tp, results=results).prepare() + if results.get('failed'): + # Check each plugin for failureds and break out of the loop early + # if a failure is encounterd. + break + if results['failed']: # If there is a failure, remove the model data to make the failure message more readable results_copy = results.copy() diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index e91ddd4a5..d10b6a41e 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -39,6 +39,9 @@ model_keys['global.netflow.exporter'] = [root_key, 'global', 'netflow', 'exporter', 'LIST'] model_keys['global.netflow.record'] = [root_key, 'global', 'netflow', 'record', 'LIST'] model_keys['global.netflow.monitor'] = [root_key, 'global', 'netflow', 'monitor', 'LIST'] +model_keys['global.spanning_tree'] = [root_key, 'global', 'spanning_tree', 'KEY'] +model_keys['global.spanning_tree.vlan_range'] = [root_key, 'global', 'spanning_tree', 'vlan_range', 'LIST'] +model_keys['global.spanning_tree.mst_instance_range'] = [root_key, 'global', 'spanning_tree', 'mst_instance_range', 'LIST'] # --- model_keys['underlay'] = [root_key, 'underlay', 'KEY'] # --- diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 425e2cfd6..bbb3cdff1 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -34,4 +34,4 @@ - name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric.type == 'MSD' + when: MD_Extended.vxlan.fabric.type == 'MSD' \ No newline at end of file diff --git a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml index f414ee031..9923d716e 100644 --- a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml @@ -102,6 +102,5 @@ ansible.builtin.set_fact: vrf_attach_config: "{{ lookup('file', file_name) | from_yaml }}" when: > - (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 or - (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 delegate_to: localhost \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml index 7ef97fb1c..b9b474864 100644 --- a/roles/dtc/common/tasks/sub_main_isn.yml +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -46,3 +46,27 @@ - name: Build NDFC Fabric Switch Inventory List From Template ansible.builtin.import_tasks: isn/ndfc_inventory.yml + +# -------------------------------------------------------------------- +# Save Local Variables To NameSpace Dict For Use Elsewhere +# -------------------------------------------------------------------- +- name: Save Local Variables With Namespace Context + ansible.builtin.set_fact: + vars_common_isn: + changes_detected_fabric: "{{ changes_detected_fabric }}" + changes_detected_inventory: "{{ changes_detected_inventory }}" + fabric_config: "{{ fabric_config }}" + inv_config: "{{ inv_config }}" + poap_data: "{{ poap_data }}" + updated_inv_config: "{{ updated_inv_config }}" + +- name: Run Diff Flags + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Fabric Changes Detected - [ {{ vars_common_isn.changes_detected_fabric }} ]" + - "+ Inventory Changes Detected - [ {{ vars_common_isn.changes_detected_inventory }} ]" + - "+ ----- Run Map -----" + - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" + - "+ Force Run Flag - [ {{ force_run_all }} ]" + - "----------------------------------------------------------------" diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 34d30888c..3507c8b38 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -69,3 +69,29 @@ - name: Build NDFC Fabric Networks Attach List From Template ansible.builtin.import_tasks: msd/ndfc_networks.yml + +# -------------------------------------------------------------------- +# Save Local Variables To NameSpace Dict For Use Elsewhere +# -------------------------------------------------------------------- +- name: Save Local Variables With Namespace Context + ansible.builtin.set_fact: + vars_common_msd: + changes_detected_fabric: "{{ changes_detected_fabric }}" + changes_detected_vrfs: "{{ changes_detected_vrfs }}" + changes_detected_networks: "{{ changes_detected_networks }}" + fabric_config: "{{ fabric_config }}" + net_config: "{{ net_config }}" + vrf_config: "{{ vrf_config }}" + vrf_attach_config: "{{ vrf_attach_config }}" + +- name: Run Diff Flags + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Fabric Changes Detected - [ {{ vars_common_msd.changes_detected_fabric }} ]" + - "+ VRFs Changes Detected - [ {{ vars_common_msd.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_msd.changes_detected_networks }} ]" + - "+ ----- Run Map -----" + - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" + - "+ Force Run Flag - [ {{ force_run_all }} ]" + - "----------------------------------------------------------------" diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index e4e9234ff..b82b56214 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -159,31 +159,77 @@ - name: Build Fabric Links List From Template ansible.builtin.import_tasks: vxlan/ndfc_fabric_links.yml +# -------------------------------------------------------------------- +# Save Local Variables To NameSpace Dict For Use Elsewhere +# -------------------------------------------------------------------- +- name: Save Local Variables With Namespace Context + ansible.builtin.set_fact: + vars_common_vxlan: + changes_detected_fabric: "{{ changes_detected_fabric }}" + changes_detected_fabric_links: "{{ changes_detected_fabric_links }}" + changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" + changes_detected_interface_access: "{{ changes_detected_interface_access }}" + changes_detected_interfaces: "{{ changes_detected_interfaces }}" + changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" + changes_detected_interface_po_routed: "{{ changes_detected_interface_po_routed }}" + changes_detected_interface_routed: "{{ changes_detected_interface_routed }}" + changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" + changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" + changes_detected_interface_vpc: "{{ changes_detected_interface_vpc }}" + changes_detected_link_vpc_peering: "{{ changes_detected_link_vpc_peering }}" + changes_detected_networks: "{{ changes_detected_networks }}" + changes_detected_policy: "{{ changes_detected_policy }}" + changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" + changes_detected_vpc_peering: "{{ changes_detected_vpc_peering }}" + changes_detected_vrfs: "{{ changes_detected_vrfs }}" + fabric_config: "{{ fabric_config }}" + fabric_links: "{{ fabric_links }}" + interface_access_po: "{{ interface_access_po }}" + interface_access: "{{ interface_access }}" + interface_all: "{{ interface_all }}" + int_loopback_config: "{{ int_loopback_config }}" + interface_po_routed: "{{ interface_po_routed }}" + interface_routed: "{{ interface_routed }}" + interface_trunk_po: "{{ interface_trunk_po }}" + interface_trunk: "{{ interface_trunk }}" + interface_vpc: "{{ interface_vpc }}" + inv_config: "{{ inv_config }}" + link_vpc_peering: "{{ link_vpc_peering }}" + net_config: "{{ net_config }}" + poap_data: "{{ poap_data }}" + policy_config: "{{ policy_config }}" + sub_interface_routed: "{{ sub_interface_routed }}" + updated_inv_config: "{{ updated_inv_config }}" + vpc_peering: "{{ vpc_peering }}" + vrf_config: "{{ vrf_config }}" + vrf_attach_config: "{{ vrf_attach_config }}" + + - name: Run Diff Flags ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Fabric Changes Detected - [ {{ changes_detected_fabric }} ]" - - "+ Inventory Changes Detected - [ {{ changes_detected_inventory }} ]" - - "+ vPC Link Peer Changes Detected - [ {{ changes_detected_link_vpc_peering }} ]" - - "+ vPC Peer Changes Detected - [ {{ changes_detected_vpc_peering }} ]" + - "+ Fabric Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric }} ]" + - "+ Inventory Changes Detected - [ {{ vars_common_vxlan.changes_detected_inventory }} ]" + - "+ vPC Link Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_link_vpc_peering }} ]" + - "+ vPC Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_vpc_peering }} ]" - "+ ----- Interfaces -----" - - "+ Interface vPC Changes Detected - [ {{ changes_detected_interface_vpc }} ]" - - "+ Interface Access Changes Detected - [ {{ changes_detected_interface_access }} ]" - - "+ Interface Access PO Changes Detected - [ {{ changes_detected_interface_access_po }} ]" - - "+ Interface Loopback Changes Detected - [ {{ changes_detected_interface_loopback }} ]" - - "+ Interface PO Routed Changes Detected - [ {{ changes_detected_interface_po_routed }} ]" - - "+ Interface Routed Changes Detected - [ {{ changes_detected_interface_routed }} ]" - - "+ Interface Trunk Changes Detected - [ {{ changes_detected_interface_trunk }} ]" - - "+ Interface Trunk PO Changes Detected - [ {{ changes_detected_interface_trunk_po }} ]" - - "+ Sub Interface Routed Changes Detected - [ {{ changes_detected_sub_interface_routed }} ]" + - "+ Interface vPC Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_vpc }} ]" + - "+ Interface Access Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access }} ]" + - "+ Interface Access PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access_po }} ]" + - "+ Interface Loopback Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_loopback }} ]" + - "+ Interface PO Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_po_routed }} ]" + - "+ Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_routed }} ]" + - "+ Interface Trunk Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_trunk }} ]" + - "+ Interface Trunk PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_trunk_po }} ]" + - "+ Sub Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_sub_interface_routed }} ]" - "+ ----- All Interfaces -----" - - "+ All Interfaces Changes Detected - [ {{ changes_detected_interfaces }} ]" + - "+ All Interfaces Changes Detected - [ {{ vars_common_vxlan.changes_detected_interfaces }} ]" - "+ ----- All Interfaces -----" - - "+ VRFs Changes Detected - [ {{ changes_detected_vrfs }} ]" - - "+ Networks Changes Detected - [ {{ changes_detected_networks }} ]" - - "+ Policy Changes Detected - [ {{ changes_detected_policy }} ]" - - "+ Fabric Links Changes Detected - [ {{ changes_detected_fabric_links }} ]" + - "+ VRFs Changes Detected - [ {{ vars_common_vxlan.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_vxlan.changes_detected_networks }} ]" + - "+ Policy Changes Detected - [ {{ vars_common_vxlan.changes_detected_policy }} ]" + - "+ Fabric Links Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric_links }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml index 392934c75..ff9047757 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml @@ -81,5 +81,3 @@ when: - file_diff_result.file_data_changed - check_roles['save_previous'] - -# ansible_run_tags \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml index ef9714cfd..797d1149c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml @@ -65,8 +65,7 @@ ansible.builtin.set_fact: net_config: "{{ lookup('file', file_name) | from_yaml }}" when: > - (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 or - (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml index f8eb9712c..1203bb7b9 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml @@ -75,4 +75,4 @@ delegate_to: localhost when: - file_diff_result.file_data_changed - - check_roles['save_previous'] + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml index 354c33d73..261d4899c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml @@ -80,4 +80,4 @@ delegate_to: localhost when: - file_diff_result.file_data_changed - - check_roles['save_previous'] + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index 3468e5b59..30c72ff51 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -65,8 +65,7 @@ ansible.builtin.set_fact: vrf_config: "{{ lookup('file', file_name) | from_yaml }}" when: > - (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 or - (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files @@ -104,6 +103,5 @@ ansible.builtin.set_fact: vrf_attach_config: "{{ lookup('file', file_name) | from_yaml }}" when: > - (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 or - (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 delegate_to: localhost \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 index 97f9e21d5..7b64ca088 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 @@ -1,11 +1,11 @@ [ - {% for vrf in MD_Extended.vxlan.overlay_services.vrfs %} + {% for vrf in MD_Extended.vxlan.overlay.vrfs %} {% if vrf['vrf_attach_group'] is defined %} { "vrfName": "{{ vrf["name"] }}", "lanAttachList": [ - {% for attach in MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict[vrf["vrf_attach_group"]] %} + {% for attach in MD_Extended.vxlan.overlay.vrf_attach_groups_dict[vrf["vrf_attach_group"]] %} { "fabric": "{{ MD_Extended.vxlan.fabric.name }}", "vrfName": "{{ vrf["name"] }}", diff --git a/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 index 29db305be..d00ad13b8 100644 --- a/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 +++ b/roles/dtc/common/templates/ndfc_networks/dc_vxlan_fabric/dc_vxlan_fabric_networks.j2 @@ -1,10 +1,7 @@ {# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} -{# TODO: Remove lines 3-8. When we get here we should be normalized around overlay, not overlay_services#} {% set networks = [] %} {% if MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks %} {% set networks = MD_Extended.vxlan.overlay.networks %} -{% elif MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks %} -{% set networks = MD_Extended.vxlan.overlay_services.networks %} {% endif %} {% for net in networks %} - net_name: {{ net['name'] }} @@ -75,8 +72,6 @@ attach: {% if MD_Extended.vxlan.overlay.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay.network_attach_groups_dict %} {% set network_attach_groups_dict = MD_Extended.vxlan.overlay.network_attach_groups_dict %} -{% elif MD_Extended.vxlan.overlay_services.network_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} -{% set network_attach_groups_dict = MD_Extended.vxlan.overlay_services.network_attach_groups_dict %} {% endif %} {% for attach in network_attach_groups_dict[net['network_attach_group']] %} - ip_address: {{ attach['mgmt_ip_address'] }} diff --git a/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 index b8bd09af9..b27f9b8b8 100644 --- a/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/dc_vxlan_fabric/dc_vxlan_fabric_vrfs.j2 @@ -1,10 +1,7 @@ {# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} -{# TODO: Remove lines 3-8. When we get here we should be normalized around overlay, not overlay_services#} {% set vrfs = [] %} {% if MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs %} {% set vrfs = MD_Extended.vxlan.overlay.vrfs %} -{% elif MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs %} -{% set vrfs = MD_Extended.vxlan.overlay_services.vrfs %} {% endif %} {% for vrf in vrfs %} - vrf_name: {{ vrf['name'] }} @@ -55,8 +52,6 @@ attach: {% if MD_Extended.vxlan.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} {% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay.vrf_attach_groups_dict %} -{% elif MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict is defined and MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} -{% set vrf_attach_groups_dict = MD_Extended.vxlan.overlay_services.vrf_attach_groups_dict %} {% endif %} {% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} - ip_address: {{ attach['mgmt_ip_address'] }} diff --git a/roles/dtc/create/tasks/isn/devices_discovery.yml b/roles/dtc/create/tasks/isn/devices_discovery.yml index 11ed62d47..7374085b0 100644 --- a/roles/dtc/create/tasks/isn/devices_discovery.yml +++ b/roles/dtc/create/tasks/isn/devices_discovery.yml @@ -24,7 +24,7 @@ - name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_inventory: fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ updated_inv_config['updated_inv_list'] }}" + config: "{{ vars_common_isn.updated_inv_config['updated_inv_list'] }}" deploy: false save: true state: merged diff --git a/roles/dtc/create/tasks/isn/fabric.yml b/roles/dtc/create/tasks/isn/fabric.yml index e810c30d3..0b17956e5 100644 --- a/roles/dtc/create/tasks/isn/fabric.yml +++ b/roles/dtc/create/tasks/isn/fabric.yml @@ -31,4 +31,4 @@ - name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged - config: "{{ fabric_config }}" + config: "{{ vars_common_isn.fabric_config }}" diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index ccf1471ce..05f98ba12 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -23,23 +23,40 @@ - name: Import VXLAN Role Tasks ansible.builtin.import_tasks: sub_main_vxlan.yml - when: - - MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' - - changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy + when: > + (MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN') and + (vars_common_vxlan.changes_detected_fabric) or + (vars_common_vxlan.changes_detected_inventory) or + (vars_common_vxlan.changes_detected_vpc_peering) or + (vars_common_vxlan.changes_detected_interfaces) or + (vars_common_vxlan.changes_detected_link_vpc_peering) or + (vars_common_vxlan.changes_detected_vrfs) or + (vars_common_vxlan.changes_detected_networks) or + (vars_common_vxlan.changes_detected_policy) - name: Import ISN Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml - when: MD_Extended.vxlan.fabric.type == 'ISN' + when: > + (MD_Extended.vxlan.fabric.type == 'ISN') and + (vars_common_isn.changes_detected_fabric) or + (vars_common_isn.changes_detected_inventory) - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml - when: MD_Extended.vxlan.fabric.type == 'MSD' + when: > + (MD_Extended.vxlan.fabric.type == 'MSD') and + (vars_common_msd.changes_detected_fabric) or + (vars_common_msd.changes_detected_vrfs) or + (vars_common_msd.changes_detected_networks) +# Check with Matt and Pete on External Fabrics - name: Import Role Tasks External Fabric ansible.builtin.import_tasks: sub_main_external.yml - when: - - changes_detected_inventory or changes_detected_interfaces or changes_detected_policy - - MD_Extended.vxlan.global.fabric_type == 'External' + when: > + (MD_Extended.vxlan.global.fabric_type == 'External') and + (changes_detected_inventory) or + (changes_detected_interfaces) or + (changes_detected_policy) - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml index e810c30d3..7141b3791 100644 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ b/roles/dtc/create/tasks/msd/fabric.yml @@ -31,4 +31,4 @@ - name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged - config: "{{ fabric_config }}" + config: "{{ vars_common_msd.fabric_config }}" diff --git a/roles/dtc/create/tasks/msd/vrfs_networks.yml b/roles/dtc/create/tasks/msd/vrfs_networks.yml index f2cb35d68..f67605efc 100644 --- a/roles/dtc/create/tasks/msd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/msd/vrfs_networks.yml @@ -35,12 +35,12 @@ cisco.dcnm.dcnm_vrf: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ vrf_config }}" + config: "{{ vars_common_msd.vrf_config }}" register: manage_vrf_result when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - changes_detected_vrfs + - vars_common_msd.changes_detected_vrfs # -------------------------------------------------------------------- # Manage Loopback VRF attachments on NDFC @@ -49,11 +49,11 @@ cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments" method: "POST" - json_data: "{{ vrf_attach_config | to_json}}" + json_data: "{{ vars_common_msd.vrf_attach_config | to_json}}" when: - - MD_Extended.vxlan.overlay_services.vrfs is defined - - MD_Extended.vxlan.overlay_services.vrfs - - changes_detected_vrfs + - MD_Extended.vxlan.overlay.vrfs is defined + - MD_Extended.vxlan.overlay.vrfs + - vars_common_msd.changes_detected_vrfs # -------------------------------------------------------------------- # Manage Network Configuration on NDFC @@ -62,9 +62,9 @@ cisco.dcnm.dcnm_network: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ net_config }}" + config: "{{ vars_common_msd.net_config }}" register: manage_network_result when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - changes_detected_networks + - vars_common_msd.changes_detected_networks diff --git a/roles/dtc/create/tasks/sub_main_isn.yml b/roles/dtc/create/tasks/sub_main_isn.yml index e7d799d28..b67d04de7 100644 --- a/roles/dtc/create/tasks/sub_main_isn.yml +++ b/roles/dtc/create/tasks/sub_main_isn.yml @@ -37,12 +37,12 @@ when: - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "ISN" - - changes_detected_fabric + - vars_common_isn.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC ISN Fabric Switches ansible.builtin.import_tasks: isn/devices.yml when: - MD_Extended.vxlan.multisite.isn.topology.switches | length > 0 - - changes_detected_inventory + - vars_common_isn.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 396fe5730..4111180dd 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -37,7 +37,7 @@ when: - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "MSD" - - changes_detected_fabric + - vars_common_msd.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC MSD Fabric Child Fabrics @@ -50,5 +50,5 @@ when: - MD_Extended.vxlan.multisite.overlay is defined - MD_Extended.vxlan.multisite.overlay - - (changes_detected_vrfs or changes_detected_networks) + - (vars_common_msd.changes_detected_vrfs or vars_common_msd.changes_detected_networks) tags: "{{ nac_tags.create_vrfs_networks }}" diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index 379a49fd4..aa4bc319f 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -38,48 +38,48 @@ - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" - MD_Extended.vxlan.global is defined - - changes_detected_fabric + - vars_common_vxlan.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC Fabric Switches ansible.builtin.import_tasks: vxlan/devices.yml when: - MD_Extended.vxlan.topology.switches | length > 0 - - changes_detected_inventory + - vars_common_vxlan.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" - name: Manage VPC Peering ansible.builtin.import_tasks: vxlan/vpc_peering.yml when: - MD_Extended.vxlan.topology.vpc_peers | length > 0 - - changes_detected_vpc_peering + - vars_common_vxlan.changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" - name: Manage NDFC Fabric Interfaces ansible.builtin.import_tasks: vxlan/interfaces.yml when: - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - - changes_detected_interfaces + - vars_common_vxlan.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: vxlan/vrfs_networks.yml - when: > - (MD_Extended.vxlan.overlay_services is defined or MD_Extended.vxlan.overlay is defined) and - MD_Extended.vxlan.topology.switches | length > 0 and - (changes_detected_vrfs or changes_detected_networks) + when: + - MD_Extended.vxlan.overlay is defined + - MD_Extended.vxlan.topology.switches | length > 0 + - vars_common_vxlan.changes_detected_vrfs or vars_common_vxlan.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Intra Links ansible.builtin.import_tasks: vxlan/links.yml when: - MD_Extended.vxlan.topology.fabric_links | length > 0 - - changes_detected_fabric_links + - vars_common_vxlan.changes_detected_fabric_links tags: "{{ nac_tags.create_links }}" - name: Manage NDFC Fabric Policies ansible.builtin.import_tasks: vxlan/policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - - changes_detected_policy + - vars_common_vxlan.changes_detected_policy tags: "{{ nac_tags.create_policy }}" diff --git a/roles/dtc/create/tasks/vxlan/devices_discovery.yml b/roles/dtc/create/tasks/vxlan/devices_discovery.yml index 1b12ac321..dde9eaffb 100644 --- a/roles/dtc/create/tasks/vxlan/devices_discovery.yml +++ b/roles/dtc/create/tasks/vxlan/devices_discovery.yml @@ -24,7 +24,7 @@ - name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_inventory: fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ updated_inv_config['updated_inv_list'] }}" + config: "{{ vars_common_vxlan.updated_inv_config['updated_inv_list'] }}" deploy: false save: true state: merged @@ -57,4 +57,4 @@ method: PUT path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" json_data: "{{ results.policy_update.values() | list | to_json }}" - when: results.policy_update | length > 0 + when: results.policy_update | length > 0 \ No newline at end of file diff --git a/roles/dtc/create/tasks/vxlan/fabric.yml b/roles/dtc/create/tasks/vxlan/fabric.yml index 549e57852..dfb042c99 100644 --- a/roles/dtc/create/tasks/vxlan/fabric.yml +++ b/roles/dtc/create/tasks/vxlan/fabric.yml @@ -31,4 +31,4 @@ - name: Manage fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC cisco.dcnm.dcnm_fabric: state: merged - config: "{{ fabric_config }}" + config: "{{ vars_common_vxlan.fabric_config }}" diff --git a/roles/dtc/create/tasks/vxlan/interfaces.yml b/roles/dtc/create/tasks/vxlan/interfaces.yml index 49c00566e..8b2a7c21d 100644 --- a/roles/dtc/create/tasks/vxlan/interfaces.yml +++ b/roles/dtc/create/tasks/vxlan/interfaces.yml @@ -36,7 +36,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_access_po }}" + config: "{{ vars_common_vxlan.interface_access_po }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 # -------------------------------------------------------------------- @@ -47,7 +47,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_trunk_po }}" + config: "{{ vars_common_vxlan.interface_trunk_po }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 # -------------------------------------------------------------------- @@ -58,7 +58,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_routed }}" + config: "{{ vars_common_vxlan.interface_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 # -------------------------------------------------------------------- @@ -69,7 +69,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ sub_interface_routed }}" + config: "{{ vars_common_vxlan.sub_interface_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 # -------------------------------------------------------------------- @@ -80,7 +80,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_po_routed }}" + config: "{{ vars_common_vxlan.interface_po_routed }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 # -------------------------------------------------------------------- @@ -91,7 +91,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ int_loopback_config }}" + config: "{{ vars_common_vxlan.int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 # -------------------------------------------------------------------- @@ -102,7 +102,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_trunk }}" + config: "{{ vars_common_vxlan.interface_trunk }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 # -------------------------------------------------------------------- @@ -113,7 +113,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_access }}" + config: "{{ vars_common_vxlan.interface_access }}" when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 # -------------------------------------------------------------------- @@ -124,7 +124,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_vpc }}" + config: "{{ vars_common_vxlan.interface_vpc }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 ## Will discuss with team and switchover to the below code and remove the above code @@ -136,7 +136,7 @@ # cisco.dcnm.dcnm_interface: # fabric: "{{ MD_Extended.vxlan.fabric.name }}" # state: replaced -# config: "{{ interface_all }}" +# config: "{{ vars_common_vxlan.interface_all }}" # vars: # ansible_command_timeout: 3000 # ansible_connect_timeout: 3000 diff --git a/roles/dtc/create/tasks/vxlan/links.yml b/roles/dtc/create/tasks/vxlan/links.yml index 807db6378..e292c721a 100644 --- a/roles/dtc/create/tasks/vxlan/links.yml +++ b/roles/dtc/create/tasks/vxlan/links.yml @@ -43,7 +43,7 @@ - name: Create a list of links that already exist cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" - fabric_links: "{{ fabric_links }}" + fabric_links: "{{ vars_common_vxlan.fabric_links }}" register: not_required_links when: result_links.response is defined @@ -55,7 +55,7 @@ - name: remove unwanted links from required links input ansible.builtin.set_fact: - required_links: "{{ fabric_links | difference(not_required_links['not_required_links']) }}" + required_links: "{{ vars_common_vxlan.fabric_links | difference(not_required_links['not_required_links']) }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/vxlan/policies.yml b/roles/dtc/create/tasks/vxlan/policies.yml index 3b9d2e497..d0e660c6e 100644 --- a/roles/dtc/create/tasks/vxlan/policies.yml +++ b/roles/dtc/create/tasks/vxlan/policies.yml @@ -35,7 +35,7 @@ cisco.dcnm.dcnm_policy: fabric: "{{ MD_Extended.vxlan.fabric.name }}" use_desc_as_key: true - config: "{{ policy_config }}" + config: "{{ vars_common_vxlan.policy_config }}" deploy: false state: merged register: manage_policies_result diff --git a/roles/dtc/create/tasks/vxlan/vpc_peering.yml b/roles/dtc/create/tasks/vxlan/vpc_peering.yml index 725db0296..024483324 100644 --- a/roles/dtc/create/tasks/vxlan/vpc_peering.yml +++ b/roles/dtc/create/tasks/vxlan/vpc_peering.yml @@ -36,7 +36,7 @@ cisco.dcnm.dcnm_links: state: replaced src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ link_vpc_peering }}" + config: "{{ vars_common_vxlan.link_vpc_peering }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 @@ -51,4 +51,4 @@ src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" deploy: false state: replaced - config: "{{ vpc_peering }}" + config: "{{ vars_common_vxlan.vpc_peering }}" diff --git a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml index 9e6b27c34..9170c0fe9 100644 --- a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml +++ b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml @@ -35,12 +35,25 @@ cisco.dcnm.dcnm_vrf: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ vrf_config }}" + config: "{{ vars_common_vxlan.vrf_config }}" register: manage_vrf_result - when: > - (MD_Extended.vxlan.overlay.vrfs is defined and MD_Extended.vxlan.overlay.vrfs) or - (MD_Extended.vxlan.overlay_services.vrfs is defined and MD_Extended.vxlan.overlay_services.vrfs) and - changes_detected_vrfs + when: + - MD_Extended.vxlan.overlay.vrfs is defined + - MD_Extended.vxlan.overlay.vrfs + - vars_common_vxlan.changes_detected_vrfs + +# -------------------------------------------------------------------- +# Manage Loopback VRF attachments on NDFC +# -------------------------------------------------------------------- +- name: Attach VRF Loopbacks per VRF + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments" + method: "POST" + json_data: "{{ vars_common_vxlan.vrf_attach_config | to_json}}" + when: + - MD_Extended.vxlan.overlay.vrfs is defined + - MD_Extended.vxlan.overlay.vrfs + - vars_common_vxlan.changes_detected_vrfs # -------------------------------------------------------------------- # Manage Network Configuration on NDFC @@ -49,9 +62,9 @@ cisco.dcnm.dcnm_network: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ net_config }}" + config: "{{ vars_common_vxlan.net_config }}" register: manage_network_result - when: > - (MD_Extended.vxlan.overlay.networks is defined and MD_Extended.vxlan.overlay.networks) or - (MD_Extended.vxlan.overlay_services.networks is defined and MD_Extended.vxlan.overlay_services.networks) and - changes_detected_networks + when: + - MD_Extended.vxlan.overlay.networks is defined + - MD_Extended.vxlan.overlay.networks + - vars_common_vxlan.changes_detected_networks diff --git a/roles/dtc/deploy/tasks/main.yml b/roles/dtc/deploy/tasks/main.yml index 76f46304b..811d76d76 100644 --- a/roles/dtc/deploy/tasks/main.yml +++ b/roles/dtc/deploy/tasks/main.yml @@ -24,7 +24,21 @@ - name: Import Role Tasks ansible.builtin.import_tasks: sub_main.yml tags: "{{ nac_tags.deploy }}" # Tags defined in roles/common_global/vars/main.yml - when: changes_detected_fabric or changes_detected_inventory or changes_detected_vpc_peering or changes_detected_interfaces or changes_detected_link_vpc_peering or changes_detected_vrfs or changes_detected_networks or changes_detected_policy or changes_detected_fabric_links + when: > + (vars_common_vxlan.changes_detected_fabric) or + (vars_common_vxlan.changes_detected_inventory) or + (vars_common_vxlan.changes_detected_vpc_peering) or + (vars_common_vxlan.changes_detected_interfaces) or + (vars_common_vxlan.changes_detected_link_vpc_peering) or + (vars_common_vxlan.changes_detected_vrfs) or + (vars_common_vxlan.changes_detected_networks) or + (vars_common_vxlan.changes_detected_policy) or + (vars_common_vxlan.changes_detected_fabric_links) or + (vars_common_isn.changes_detected_fabric) or + (vars_common_isn.changes_detected_inventory) or + (vars_common_msd.changes_detected_fabric) or + (vars_common_msd.changes_detected_vrfs) or + (vars_common_msd.changes_detected_networks) - name: Mark Stage Role Deploy Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index c9f755aa6..8764d30ef 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -23,15 +23,24 @@ - name: Import VXLAN Role Tasks ansible.builtin.import_tasks: sub_main_vxlan.yml - when: - - MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN' - - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs or changes_detected_vpc_peering or changes_detected_link_vpc_peering or changes_detected_inventory + # Check with Matt on changes_detected_policy here + # Was not there previously + when: > + (MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN') and + (vars_common_vxlan.changes_detected_inventory) or + (vars_common_vxlan.changes_detected_vpc_peering) or + (vars_common_vxlan.changes_detected_interfaces) or + (vars_common_vxlan.changes_detected_link_vpc_peering) or + (vars_common_vxlan.changes_detected_vrfs) or + (vars_common_vxlan.changes_detected_networks) + + # (vars_common_vxlan.changes_detected_policy) - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml when: - MD_Extended.vxlan.fabric.type == 'MSD' - # - changes_detected_interfaces or changes_detected_networks or changes_detected_vrfs + # - vars_common_msd.changes_detected_interfaces or vars_common_msd.changes_detected_networks or vars_common_msd.changes_detected_vrfs - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/msd/networks.yml b/roles/dtc/remove/tasks/msd/networks.yml index 706fa9efe..98f57ae7c 100644 --- a/roles/dtc/remove/tasks/msd/networks.yml +++ b/roles/dtc/remove/tasks/msd/networks.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_network: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ net_config }}" + config: "{{ vars_common_msd.net_config }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 diff --git a/roles/dtc/remove/tasks/msd/vrfs.yml b/roles/dtc/remove/tasks/msd/vrfs.yml index 68bce074e..1de111afe 100644 --- a/roles/dtc/remove/tasks/msd/vrfs.yml +++ b/roles/dtc/remove/tasks/msd/vrfs.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_vrf: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ vrf_config }}" + config: "{{ vars_common_msd.vrf_config }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 diff --git a/roles/dtc/remove/tasks/sub_main_msd.yml b/roles/dtc/remove/tasks/sub_main_msd.yml index 4efd92283..92f2cdfda 100644 --- a/roles/dtc/remove/tasks/sub_main_msd.yml +++ b/roles/dtc/remove/tasks/sub_main_msd.yml @@ -44,14 +44,14 @@ ansible.builtin.import_tasks: msd/networks.yml tags: "{{ nac_tags.remove_networks }}" when: - - changes_detected_networks + - vars_common_msd.changes_detected_networks # These are not working right... investigate - name: Remove Fabric VRFs ansible.builtin.import_tasks: msd/vrfs.yml tags: "{{ nac_tags.remove_vrfs }}" when: - - changes_detected_vrfs + - vars_common_msd.changes_detected_vrfs - name: Remove Child Fabrics ansible.builtin.import_tasks: msd/child_fabrics.yml diff --git a/roles/dtc/remove/tasks/sub_main_vxlan.yml b/roles/dtc/remove/tasks/sub_main_vxlan.yml index 397e124c5..0842dce8c 100644 --- a/roles/dtc/remove/tasks/sub_main_vxlan.yml +++ b/roles/dtc/remove/tasks/sub_main_vxlan.yml @@ -43,40 +43,40 @@ ansible.builtin.import_tasks: vxlan/policy.yml tags: "{{ nac_tags.remove_policy }}" when: - - changes_detected_policy + - vars_common_vxlan.changes_detected_policy - name: Remove Fabric Interfaces ansible.builtin.import_tasks: vxlan/interfaces.yml tags: "{{ nac_tags.remove_interfaces }}" when: - - changes_detected_interfaces + - vars_common_vxlan.changes_detected_interfaces - name: Remove Fabric Networks ansible.builtin.import_tasks: vxlan/networks.yml tags: "{{ nac_tags.remove_networks }}" when: - - changes_detected_networks + - vars_common_vxlan.changes_detected_networks - name: Remove Fabric VRFs ansible.builtin.import_tasks: vxlan/vrfs.yml tags: "{{ nac_tags.remove_vrfs }}" when: - - changes_detected_vrfs + - vars_common_vxlan.changes_detected_vrfs - name: Remove Fabric Links ansible.builtin.import_tasks: vxlan/links.yml tags: "{{ nac_tags.remove_links }}" when: - - changes_detected_link_vpc_peering + - vars_common_vxlan.changes_detected_link_vpc_peering - name: Remove Fabric vPC Peering ansible.builtin.import_tasks: vxlan/vpc_peers.yml tags: "{{ nac_tags.remove_vpc_peers }}" when: - - changes_detected_vpc_peering + - vars_common_vxlan.changes_detected_vpc_peering - name: Remove Fabric Switches ansible.builtin.import_tasks: vxlan/switches.yml tags: "{{ nac_tags.remove_switches }}" when: - - changes_detected_inventory + - vars_common_vxlan.changes_detected_inventory diff --git a/roles/dtc/remove/tasks/vxlan/interfaces.yml b/roles/dtc/remove/tasks/vxlan/interfaces.yml index 22039b2f8..cf3611e78 100644 --- a/roles/dtc/remove/tasks/vxlan/interfaces.yml +++ b/roles/dtc/remove/tasks/vxlan/interfaces.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ interface_all }}" + config: "{{ vars_common_vxlan.interface_all }}" # deploy: false vars: ansible_command_timeout: 3000 diff --git a/roles/dtc/remove/tasks/vxlan/links.yml b/roles/dtc/remove/tasks/vxlan/links.yml index 16dee9d66..a9667d854 100644 --- a/roles/dtc/remove/tasks/vxlan/links.yml +++ b/roles/dtc/remove/tasks/vxlan/links.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_links: state: replaced src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ link_vpc_peering }}" + config: "{{ vars_common_vxlan.link_vpc_peering }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 @@ -54,7 +54,7 @@ - name: Create a list of links that already exist cisco.nac_dc_vxlan.dtc.links_filter_and_remove: existing_links: "{{ result_links.response }}" - fabric_links: "{{ fabric_links }}" + fabric_links: "{{ vars_common_vxlan.fabric_links }}" register: links_to_be_removed when: result_links.response is defined diff --git a/roles/dtc/remove/tasks/vxlan/networks.yml b/roles/dtc/remove/tasks/vxlan/networks.yml index 706fa9efe..6709f07fd 100644 --- a/roles/dtc/remove/tasks/vxlan/networks.yml +++ b/roles/dtc/remove/tasks/vxlan/networks.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_network: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ net_config }}" + config: "{{ vars_common_vxlan.net_config }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 diff --git a/roles/dtc/remove/tasks/vxlan/switches.yml b/roles/dtc/remove/tasks/vxlan/switches.yml index 1094f1997..d1105d1c5 100644 --- a/roles/dtc/remove/tasks/vxlan/switches.yml +++ b/roles/dtc/remove/tasks/vxlan/switches.yml @@ -27,7 +27,7 @@ - name: Remove Unmanaged NDFC Fabric Devices cisco.dcnm.dcnm_inventory: fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ updated_inv_config['updated_inv_list'] }}" + config: "{{ vars_common_vxlan.updated_inv_config['updated_inv_list'] }}" deploy: true save: true state: overridden diff --git a/roles/dtc/remove/tasks/vxlan/vpc_peers.yml b/roles/dtc/remove/tasks/vxlan/vpc_peers.yml index dc8e1dcbb..298ac9e23 100644 --- a/roles/dtc/remove/tasks/vxlan/vpc_peers.yml +++ b/roles/dtc/remove/tasks/vxlan/vpc_peers.yml @@ -30,7 +30,7 @@ src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" deploy: true state: overridden - config: "{{ vpc_peering }}" + config: "{{ vars_common_vxlan.vpc_peering }}" vars: ansible_command_timeout: 1000 ansible_connect_timeout: 1000 diff --git a/roles/dtc/remove/tasks/vxlan/vrfs.yml b/roles/dtc/remove/tasks/vxlan/vrfs.yml index 68bce074e..be99d449d 100644 --- a/roles/dtc/remove/tasks/vxlan/vrfs.yml +++ b/roles/dtc/remove/tasks/vxlan/vrfs.yml @@ -29,7 +29,7 @@ cisco.dcnm.dcnm_vrf: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ vrf_config }}" + config: "{{ vars_common_vxlan.vrf_config }}" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 diff --git a/tests/integration/host_vars/examples/fabric_empty_example/networks.yaml b/tests/integration/host_vars/examples/fabric_empty_example/networks.yaml index 8b8384c61..f74926a73 100644 --- a/tests/integration/host_vars/examples/fabric_empty_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_empty_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: [] diff --git a/tests/integration/host_vars/examples/fabric_empty_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_empty_example/vrfs.yaml index 0025ac5b1..d035334b5 100644 --- a/tests/integration/host_vars/examples/fabric_empty_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_empty_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: [] vrf_attach_groups: [] \ No newline at end of file diff --git a/tests/integration/host_vars/examples/fabric_full_large_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_large_example/networks.yaml index 93139f70d..f40e2f869 100644 --- a/tests/integration/host_vars/examples/fabric_full_large_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_large_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_large_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_large_example/vrfs.yaml index 76b91f901..deaa5fab4 100644 --- a/tests/integration/host_vars/examples/fabric_full_large_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_large_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/networks.yaml index c95a81b7e..4da2cb1f6 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/vrfs.yaml index 0afbcc7d3..beb689964 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_ingress_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/networks.yaml index 8cf44458e..05dd9c3f4 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/vrfs.yaml index 907cd6991..b27908164 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_asm_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/networks.yaml index c95a81b7e..4da2cb1f6 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/vrfs.yaml index b04540abe..efe02fcee 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_isis_multicast_bidir_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/networks.yaml index c95a81b7e..4da2cb1f6 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/vrfs.yaml index b04540abe..efe02fcee 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_ingress_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/networks.yaml index 8cf44458e..05dd9c3f4 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/vrfs.yaml index 1b50bb6e4..10c471af0 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_asm_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/networks.yaml index c95a81b7e..4da2cb1f6 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/vrfs.yaml index b04540abe..efe02fcee 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_ospf_multicast_bidir_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 diff --git a/tests/integration/host_vars/examples/fabric_full_small_sha_example/networks.yaml b/tests/integration/host_vars/examples/fabric_full_small_sha_example/networks.yaml index 8cf44458e..05dd9c3f4 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_sha_example/networks.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_sha_example/networks.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: networks: - name: NetAsCodeNet1 vrf_name: NetAsCodeVrf1 diff --git a/tests/integration/host_vars/examples/fabric_full_small_sha_example/vrfs.yaml b/tests/integration/host_vars/examples/fabric_full_small_sha_example/vrfs.yaml index 1b50bb6e4..10c471af0 100644 --- a/tests/integration/host_vars/examples/fabric_full_small_sha_example/vrfs.yaml +++ b/tests/integration/host_vars/examples/fabric_full_small_sha_example/vrfs.yaml @@ -21,7 +21,7 @@ --- vxlan: - overlay_services: + overlay: vrfs: - name: NetAsCodeVrf1 vrf_id: 150001 From 7c314917d2d9d30cb213fdea2eb41dc733a40d46 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sun, 22 Dec 2024 19:23:33 +0000 Subject: [PATCH 035/183] Initialize shared dict vars --- roles/dtc/common/tasks/main.yml | 32 +++++++++++++++++++++++ roles/dtc/common/tasks/sub_main_vxlan.yml | 1 + roles/dtc/create/tasks/main.yml | 14 +++++----- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index bbb3cdff1..c837b2ffc 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -21,6 +21,38 @@ --- +# -------------------------------------------------------------------- +# Initialize NameSpace Dicts For Variable Sharing +# -------------------------------------------------------------------- +- name: Initialize NameSpace Dict For Sharing Variables + ansible.builtin.set_fact: + vars_common_vxlan: + changes_detected_fabric: false + changes_detected_fabric_links: false + changes_detected_interface_access_po: false + changes_detected_interface_access: false + changes_detected_interfaces: false + changes_detected_interface_loopback: false + changes_detected_interface_po_routed: false + changes_detected_interface_routed: false + changes_detected_interface_trunk_po: false + changes_detected_interface_trunk: false + changes_detected_interface_vpc: false + changes_detected_inventory: false + changes_detected_link_vpc_peering: false + changes_detected_networks: false + changes_detected_policy: false + changes_detected_sub_interface_routed: false + changes_detected_vpc_peering: false + changes_detected_vrfs: false + vars_common_isn: + changes_detected_fabric: false + changes_detected_inventory: false + vars_common_msd: + changes_detected_fabric: false + changes_detected_vrfs: false + changes_detected_networks: false + - name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index b82b56214..5f2921ae8 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -176,6 +176,7 @@ changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" changes_detected_interface_vpc: "{{ changes_detected_interface_vpc }}" + changes_detected_inventory: "{{ changes_detected_inventory }}" changes_detected_link_vpc_peering: "{{ changes_detected_link_vpc_peering }}" changes_detected_networks: "{{ changes_detected_networks }}" changes_detected_policy: "{{ changes_detected_policy }}" diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index 05f98ba12..c12191dbc 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -50,13 +50,13 @@ (vars_common_msd.changes_detected_networks) # Check with Matt and Pete on External Fabrics -- name: Import Role Tasks External Fabric - ansible.builtin.import_tasks: sub_main_external.yml - when: > - (MD_Extended.vxlan.global.fabric_type == 'External') and - (changes_detected_inventory) or - (changes_detected_interfaces) or - (changes_detected_policy) +# - name: Import Role Tasks External Fabric +# ansible.builtin.import_tasks: sub_main_external.yml +# when: > +# (MD_Extended.vxlan.global.fabric_type == 'External') and +# (changes_detected_inventory) or +# (changes_detected_interfaces) or +# (changes_detected_policy) - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: From 6293b98a6746a96dcfd441568b2e9a8dbd940d6f Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 8 Jan 2025 17:05:19 +0000 Subject: [PATCH 036/183] refactored external network into new format --- plugins/action/common/nac_dc_validate.py | 4 ++- .../dtc/update_switch_hostname_policy.py | 2 +- roles/dtc/common/tasks/main.yml | 22 ++++++++++++++-- roles/dtc/common/tasks/sub_main_vxlan.yml | 5 ---- roles/dtc/common/templates/ndfc_fabric.j2 | 2 +- .../advanced/dc_external_fabric_advanced.j2 | 10 +++---- .../bootstrap/dc_external_fabric_bootstrap.j2 | 26 +++++++++---------- .../dc_external_fabric_flow_monitor.j2 | 16 ++++++------ .../general/dc_external_fabric_general.j2 | 2 +- roles/dtc/common/templates/ndfc_inventory.j2 | 5 ++++ roles/dtc/create/tasks/main.yml | 23 +++++++++++----- roles/dtc/create/tasks/sub_main_external.yml | 14 +++++----- 12 files changed, 80 insertions(+), 51 deletions(-) diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 5b4271a31..712aff519 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -95,7 +95,7 @@ def run(self, tmp=None, task_vars=None): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCF'): rules_list.append(f'{rules}multisite/') - elif results['data']['vxlan']['fabric']['type'] in ('ISN'): + elif results['data']['vxlan']['fabric']['type'] in ('ISN', 'External'): rules_list.append(f'{rules}isn/') else: results['failed'] = True @@ -119,6 +119,8 @@ def run(self, tmp=None, task_vars=None): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCF'): rules_list.append(f'{rules}multisite/') + elif results['data']['vxlan']['global']['fabric_type'] in ('ISN', 'External'): + rules_list.append(f'{rules}isn/') else: results['failed'] = True results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['global']['fabric_type']} is not a supported fabric type." diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index 2b841e3b6..ec8f2d4b4 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -50,7 +50,7 @@ def run(self, tmp=None, task_vars=None): ) dm_switches = [] - if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN'): + if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN','External'): dm_switches = model_data["vxlan"]["topology"]["switches"] elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index c837b2ffc..0a21bd04f 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -37,7 +37,6 @@ changes_detected_interface_routed: false changes_detected_interface_trunk_po: false changes_detected_interface_trunk: false - changes_detected_interface_vpc: false changes_detected_inventory: false changes_detected_link_vpc_peering: false changes_detected_networks: false @@ -52,6 +51,20 @@ changes_detected_fabric: false changes_detected_vrfs: false changes_detected_networks: false + vars_common_external: + changes_detected_inventory: false + changes_detected_fabric: false + changes_detected_interface_access_po: false + changes_detected_interface_access: false + changes_detected_interfaces: false + changes_detected_interface_loopback: false + changes_detected_interface_po_routed: false + changes_detected_interface_routed: false + changes_detected_interface_trunk_po: false + changes_detected_interface_trunk: false + changes_detected_interface_vpc: false + changes_detected_sub_interface_routed: false + changes_detected_policy: false - name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml @@ -66,4 +79,9 @@ - name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_msd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric.type == 'MSD' \ No newline at end of file + when: MD_Extended.vxlan.fabric.type == 'MSD' + +- name: Import Role Tasks for MSD Fabric + ansible.builtin.import_tasks: sub_main_external.yml + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric.type == 'External' \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index 5f2921ae8..d636ad9b3 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -215,7 +215,6 @@ - "+ vPC Link Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_link_vpc_peering }} ]" - "+ vPC Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_vpc_peering }} ]" - "+ ----- Interfaces -----" - - "+ Interface vPC Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_vpc }} ]" - "+ Interface Access Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access_po }} ]" - "+ Interface Loopback Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_loopback }} ]" @@ -226,11 +225,7 @@ - "+ Sub Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_sub_interface_routed }} ]" - "+ ----- All Interfaces -----" - "+ All Interfaces Changes Detected - [ {{ vars_common_vxlan.changes_detected_interfaces }} ]" - - "+ ----- All Interfaces -----" - - "+ VRFs Changes Detected - [ {{ vars_common_vxlan.changes_detected_vrfs }} ]" - - "+ Networks Changes Detected - [ {{ vars_common_vxlan.changes_detected_networks }} ]" - "+ Policy Changes Detected - [ {{ vars_common_vxlan.changes_detected_policy }} ]" - - "+ Fabric Links Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric_links }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index 9dafcbf27..ff5476780 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -19,7 +19,7 @@ {# Include NDFC ISN Base Template #} {% include '/ndfc_fabric/isn_fabric/isn_fabric_base.j2' %} -{% elif vxlan.fabric_type == 'External' %} +{% elif vxlan.fabric.type == 'External' %} {# Include NDFC External Fabric Base Template #} {% include '/ndfc_fabric/dc_external_fabric/dc_external_fabric_base.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index c565b063f..ea85c02df 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -1,7 +1,7 @@ {# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} POWER_REDUNDANCY_MODE: ps-redundant - FEATURE_PTP: {{ global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} - PTP_DOMAIN_ID: {{ global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} - PTP_LB_ID: {{ global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} - ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} - ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} \ No newline at end of file + FEATURE_PTP: {{ vxlan.global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} + PTP_DOMAIN_ID: {{ vxlan.global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} + PTP_LB_ID: {{ vxlan.global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} + ENABLE_NXAPI: {{ vxlan.global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} + ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 index 8ff02c278..cde315389 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 @@ -1,17 +1,17 @@ {# Auto-generated NDFC DC VXLAN EVPN Bootstrap config data structure for fabric {{ vxlan.fabric.name }} #} -{% if global.bootstrap is defined %} -{% if global.bootstrap.enable_bootstrap is defined and global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} - DHCP_ENABLE: {{ global.bootstrap.enable_local_dhcp_server }} - DHCP_IPV6_ENABLE: {{ global.bootstrap.dhcp_version }} - DHCP_START: {{ global.bootstrap.dhcp_v4.scope_start_address }} - DHCP_END: {{ global.bootstrap.dhcp_v4.scope_end_address }} - MGMT_GW: {{ global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} - MGMT_PREFIX: {{ global.bootstrap.dhcp_v4.mgmt_prefix }} - BOOTSTRAP_MULTISUBNET: "{{ global.bootstrap.dhcp_v4.multi_subnet_scope }}" - DOMAIN_NAME: "{{ global.bootstrap.dhcp_v4.domain_name }}" +{% if vxlan.global.bootstrap is defined %} +{% if vxlan.global.bootstrap.enable_bootstrap is defined and vxlan.global.bootstrap.enable_bootstrap %} + BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} + DHCP_ENABLE: {{ vxlan.global.bootstrap.enable_local_dhcp_server }} + DHCP_IPV6_ENABLE: {{ vxlan.global.bootstrap.dhcp_version }} + DHCP_START: {{ vxlan.global.bootstrap.dhcp_v4.scope_start_address }} + DHCP_END: {{ vxlan.global.bootstrap.dhcp_v4.scope_end_address }} + MGMT_GW: {{ vxlan.global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} + MGMT_PREFIX: {{ vxlan.global.bootstrap.dhcp_v4.mgmt_prefix }} + BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" + DOMAIN_NAME: "{{ vxlan.global.bootstrap.dhcp_v4.domain_name }}" {% endif %} -{% if global.bootstrap.enable_bootstrap is defined and not global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} +{% if vxlan.global.bootstrap.enable_bootstrap is defined and not vxlan.global.bootstrap.enable_bootstrap %} + BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} {% endif %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/flow_monitor/dc_external_fabric_flow_monitor.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/flow_monitor/dc_external_fabric_flow_monitor.j2 index 29bac8dd6..765a5dc98 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/flow_monitor/dc_external_fabric_flow_monitor.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/flow_monitor/dc_external_fabric_flow_monitor.j2 @@ -1,26 +1,26 @@ {# Auto-generated NDFC DC VXLAN EVPN Flow Monitor config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_NETFLOW: {{ global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} -{% if global.netflow.enable is defined and global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} -{% if global.netflow.exporter is defined %} + ENABLE_NETFLOW: {{ vxlan.global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} +{% if vxlan.global.netflow.enable is defined and vxlan.global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} +{% if vxlan.global.netflow.exporter is defined %} {% set exporter_dict = dict() %} {% set _ = exporter_dict.update({ "NETFLOW_EXPORTER_LIST":[] }) %} -{% for e in global.netflow.exporter %} +{% for e in vxlan.global.netflow.exporter %} {% set _ = exporter_dict["NETFLOW_EXPORTER_LIST"].append(dict(EXPORTER_NAME=e.name,IP=e.ip_address,VRF=e.vrf | default(""), SRC_IF_NAME=e.source_interface,UDP_PORT=e.udp_port)) %} {% endfor %} NETFLOW_EXPORTER_LIST: "{{ exporter_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if global.netflow.record is defined %} +{% if vxlan.global.netflow.record is defined %} {% set record_dict = dict() %} {% set _ = record_dict.update({ "NETFLOW_RECORD_LIST":[] }) %} -{% for r in global.netflow.record %} +{% for r in vxlan.global.netflow.record %} {% set _ = record_dict["NETFLOW_RECORD_LIST"].append(dict(RECORD_NAME=r.name,RECORD_TEMPLATE =r.template,LAYER2_RECORD=r.layer2 | default(false) | string | lower)) %} {% endfor %} NETFLOW_RECORD_LIST: "{{ record_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if global.netflow.monitor is defined %} +{% if vxlan.global.netflow.monitor is defined %} {% set monitor_dict = dict() %} {% set _ = monitor_dict.update({ "NETFLOW_MONITOR_LIST":[] }) %} -{% for m in global.netflow.monitor %} +{% for m in vxlan.global.netflow.monitor %} {% set _ = monitor_dict["NETFLOW_MONITOR_LIST"].append(dict(MONITOR_NAME=m.name,RECORD_NAME=m.record,EXPORTER1=m.exporter1,EXPORTER2=m.exporter2 | default(""))) %} {% endfor %} NETFLOW_MONITOR_LIST: "{{ monitor_dict | tojson | replace('"', '\\"') }}" diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 index 8838f10c7..80017a6dd 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 @@ -1,4 +1,4 @@ {# Auto-generated NDFC DC VXLAN EVPN General config data structure for fabric {{ vxlan.fabric.name }} #} - BGP_AS: {{ global.bgp_asn }} + BGP_AS: {{ vxlan.global.bgp_asn }} {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 9bae159b7..209148aea 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -13,5 +13,10 @@ {# Include NDFC ISN Base Template #} {% include '/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2' %} +{% elif vxlan.fabric.type == 'External' %} + +{# Include NDFC DC External Template #} +{% include '/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2' %} + {# Supported fabric types are: DC VXLAN EVPN and ISN #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index c12191dbc..c3eb2feb5 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -50,13 +50,22 @@ (vars_common_msd.changes_detected_networks) # Check with Matt and Pete on External Fabrics -# - name: Import Role Tasks External Fabric -# ansible.builtin.import_tasks: sub_main_external.yml -# when: > -# (MD_Extended.vxlan.global.fabric_type == 'External') and -# (changes_detected_inventory) or -# (changes_detected_interfaces) or -# (changes_detected_policy) +- name: Import Role Tasks External Fabric + ansible.builtin.import_tasks: sub_main_external.yml + when: > + (MD_Extended.vxlan.global.fabric_type == 'External') and + (vars_common_external.changes_detected_inventory) or + (vars_common_external.changes_detected_interfaces) or + (vars_common_external.changes_detected_fabric) or + (vars_common_external.changes_detected_interface_access_po) or + (vars_common_external.changes_detected_interface_access) or + (vars_common_external.changes_detected_interface_loopback) or + (vars_common_external.changes_detected_interface_po_routed) or + (vars_common_external.changes_detected_interface_routed) or + (vars_common_external.changes_detected_interface_trunk_po) or + (vars_common_external.changes_detected_interface_trunk) or + (vars_common_external.changes_detected_sub_interface_routed) or + (vars_common_external.changes_detected_policy) - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 2b9a771bf..9257eeac0 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -36,26 +36,26 @@ ansible.builtin.import_tasks: external/fabric.yml when: - MD_Extended.vxlan.global is defined - - changes_detected_fabric + - vars_common_external.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC Fabric Switches - ansible.builtin.import_tasks: vxlan/devices.yml + ansible.builtin.import_tasks: external/devices.yml when: - MD_Extended.vxlan.topology.switches | length > 0 - - changes_detected_inventory + - vars_common_external.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" - name: Manage NDFC Fabric Interfaces - ansible.builtin.import_tasks: vxlan/interfaces.yml + ansible.builtin.import_tasks: external/interfaces.yml when: - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - - changes_detected_interfaces + - vars_common_external.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" - name: Manage NDFC Fabric Policies - ansible.builtin.import_tasks: vxlan/policies.yml + ansible.builtin.import_tasks: external/policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - - changes_detected_policy + - vars_common_external.changes_detected_policy tags: "{{ nac_tags.create_policy }}" From cffab6611cfa7dff287bfbd4b69909b305830f8b Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 9 Jan 2025 08:31:49 +0000 Subject: [PATCH 037/183] more refactoring for external fabrics --- .../dtc/common/tasks/external/ndfc_fabric.yml | 77 ++++++++++ .../tasks/external/ndfc_interface_access.yml | 83 ++++++++++ .../external/ndfc_interface_access_po.yml | 83 ++++++++++ .../tasks/external/ndfc_interface_all.yml | 83 ++++++++++ .../external/ndfc_interface_loopback.yml | 83 ++++++++++ .../external/ndfc_interface_po_routed.yml | 83 ++++++++++ .../tasks/external/ndfc_interface_routed.yml | 83 ++++++++++ .../tasks/external/ndfc_interface_trunk.yml | 83 ++++++++++ .../external/ndfc_interface_trunk_po.yml | 83 ++++++++++ .../tasks/external/ndfc_interface_vpc.yml | 83 ++++++++++ .../common/tasks/external/ndfc_inventory.yml | 105 +++++++++++++ .../dtc/common/tasks/external/ndfc_policy.yml | 78 ++++++++++ .../external/ndfc_sub_interface_routed.yml | 83 ++++++++++ roles/dtc/common/tasks/sub_main_external.yml | 142 ++++++++++++++++++ roles/dtc/common/tasks/sub_main_vxlan.yml | 5 + .../dc_external_fabric_inventory.j2 | 40 +++++ roles/dtc/create/tasks/external/devices.yml | 36 +++++ .../tasks/external/devices_discovery.yml | 60 ++++++++ .../dtc/create/tasks/external/interfaces.yml | 133 ++++++++++++++++ roles/dtc/create/tasks/external/policies.yml | 41 +++++ 20 files changed, 1547 insertions(+) create mode 100644 roles/dtc/common/tasks/external/ndfc_fabric.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_access.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_access_po.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_all.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_loopback.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_routed.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_trunk.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_interface_vpc.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_inventory.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_policy.yml create mode 100644 roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml create mode 100644 roles/dtc/common/tasks/sub_main_external.yml create mode 100644 roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 create mode 100644 roles/dtc/create/tasks/external/devices.yml create mode 100644 roles/dtc/create/tasks/external/devices_discovery.yml create mode 100644 roles/dtc/create/tasks/external/interfaces.yml create mode 100644 roles/dtc/create/tasks/external/policies.yml diff --git a/roles/dtc/common/tasks/external/ndfc_fabric.yml b/roles/dtc/common/tasks/external/ndfc_fabric.yml new file mode 100644 index 000000000..a6ed2eeae --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_fabric.yml @@ -0,0 +1,77 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/external/ndfc_interface_access.yml b/roles/dtc/common/tasks/external/ndfc_interface_access.yml new file mode 100644 index 000000000..ba50dea14 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_access.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_access: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interface_access.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_access Var + ansible.builtin.set_fact: + interface_access: [] + delegate_to: localhost + +- name: Set interface_access Var + ansible.builtin.set_fact: + interface_access: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_access: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml new file mode 100644 index 000000000..2e5b2b6f9 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_access_po: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access_po.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interface_access_po.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_access_po Var + ansible.builtin.set_fact: + interface_access_po: [] + delegate_to: localhost + +- name: Set interface_access_po Var + ansible.builtin.set_fact: + interface_access_po: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_access_po: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_all.yml b/roles/dtc/common/tasks/external/ndfc_interface_all.yml new file mode 100644 index 000000000..ff9047757 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_all.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interfaces: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_all.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Set interface_all Var + ansible.builtin.set_fact: + interface_all: [] + delegate_to: localhost + +- name: Set interface_all Var + ansible.builtin.set_fact: + interface_all: "{{ interface_access + interface_access_po + interface_trunk + interface_trunk_po + interface_routed + interface_po_routed + sub_interface_routed + interface_vpc + int_loopback_config }}" + when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 + delegate_to: localhost + +- name: Save interface_all + ansible.builtin.copy: + content: "{{ interface_all | to_nice_yaml }}" + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interfaces: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml new file mode 100644 index 000000000..d720d5f68 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_loopback: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_loopback_interfaces.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Loopback Interfaces List From Template + ansible.builtin.template: + src: ndfc_loopback_interfaces.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set int_loopback_config Var + ansible.builtin.set_fact: + int_loopback_config: [] + delegate_to: localhost + +- name: Set int_loopback_config Var + ansible.builtin.set_fact: + int_loopback_config: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_loopback: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml new file mode 100644 index 000000000..7fb2af335 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_po_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_po_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface Po + ansible.builtin.template: + src: ndfc_interface_po_routed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_po_routed Var default + ansible.builtin.set_fact: + interface_po_routed: [] + delegate_to: localhost + +- name: Set interface_po_routed Var + ansible.builtin.set_fact: + interface_po_routed: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_po_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_routed.yml b/roles/dtc/common/tasks/external/ndfc_interface_routed.yml new file mode 100644 index 000000000..4c2f90680 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interface_routed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_routed Var default + ansible.builtin.set_fact: + interface_routed: [] + delegate_to: localhost + +- name: Set interface_routed Var + ansible.builtin.set_fact: + interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml new file mode 100644 index 000000000..073f02ce2 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_trunk: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interface_trunk.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_trunk Var + ansible.builtin.set_fact: + interface_trunk: [] + delegate_to: localhost + +- name: Set interface_trunk Var + ansible.builtin.set_fact: + interface_trunk: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_trunk: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml new file mode 100644 index 000000000..b97086acc --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_trunk_po: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk_po.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interface_trunk_po.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_trunk_po Var + ansible.builtin.set_fact: + interface_trunk_po: [] + delegate_to: localhost + +- name: Set interface_trunk_po Var + ansible.builtin.set_fact: + interface_trunk_po: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_trunk_po: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml new file mode 100644 index 000000000..5554d65d4 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_vpc: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_vpc.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build VPC interface + ansible.builtin.template: + src: ndfc_interface_vpc.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set interface_vpc Var default + ansible.builtin.set_fact: + interface_vpc: [] + delegate_to: localhost + +- name: Set interface_vpc Var + ansible.builtin.set_fact: + interface_vpc: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_vpc: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_inventory.yml b/roles/dtc/common/tasks/external/ndfc_inventory.yml new file mode 100644 index 000000000..db6667a41 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_inventory.yml @@ -0,0 +1,105 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Get POAP Data From POAP Enabled Devices + cisco.nac_dc_vxlan.dtc.get_poap_data: + model_data: "{{ MD_Extended }}" + register: poap_data + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_inventory: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Set Path For Inventory File Lookup + ansible.builtin.set_fact: + inv_file_path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Build Fabric Switch Inventory List From Template + ansible.builtin.template: + src: ndfc_inventory.j2 + dest: "{{ inv_file_path }}" + delegate_to: localhost + +- name: Create Empty inv_config Var + ansible.builtin.set_fact: + inv_config: [] + delegate_to: localhost + +- name: Set inv_config Var + ansible.builtin.set_fact: + inv_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.topology.switches | default([])) | length > 0 + delegate_to: localhost + +- name: Retrieve NDFC Device Username and Password from Group Vars and update inv_config + cisco.nac_dc_vxlan.common.get_credentials: + inv_list: "{{ inv_config }}" + register: updated_inv_config + no_log: true + +- name: Credential Retrieval Failed + ansible.builtin.fail: + msg: "{{ updated_inv_config }}" + when: updated_inv_config['retrieve_failed'] + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_inventory: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_policy.yml b/roles/dtc/common/tasks/external/ndfc_policy.yml new file mode 100644 index 000000000..1203bb7b9 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_policy.yml @@ -0,0 +1,78 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_policy: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_policy.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Policy List From Template + ansible.builtin.template: + src: ndfc_policy.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + policy_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.policy.policies | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_policy: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml new file mode 100644 index 000000000..9677853e0 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_sub_interface_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_sub_interface_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build sub_interface + ansible.builtin.template: + src: ndfc_sub_interface_routed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set sub_interface_routed Var default + ansible.builtin.set_fact: + sub_interface_routed: [] + delegate_to: localhost + +- name: Set sub_interface_routed Var + ansible.builtin.set_fact: + sub_interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_sub_interface_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml new file mode 100644 index 000000000..fa81ecc1f --- /dev/null +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -0,0 +1,142 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- ansible.builtin.fail: msg="Service Model Not Defined. Role cisco.nac_dc_vxlan.validate Must Be Called First" + when: MD is undefined + delegate_to: localhost + +# -------------------------------------------------------------------- +# Remove all files from the previous run if run_map requires it +# -------------------------------------------------------------------- +- name: Cleanup Files from Previous Run if run_map requires it + ansible.builtin.import_tasks: cleanup_files.yml + when: + - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) + +# -------------------------------------------------------------------- +# Build Create Fabric Parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.import_tasks: external/ndfc_fabric.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Switch Inventory List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Switch Inventory List From Template + ansible.builtin.import_tasks: external/ndfc_inventory.yml + +- name: Build NDFC Interface Access Po List From Template + ansible.builtin.import_tasks: external/ndfc_interface_access_po.yml + +- name: Build NDFC Interface Access List From Template + ansible.builtin.import_tasks: external/ndfc_interface_access.yml + +- name: Build NDFC Interface Loopback List From Template + ansible.builtin.import_tasks: external/ndfc_interface_loopback.yml + +- name: Build NDFC Interface Po Routed List From Template + ansible.builtin.import_tasks: external/ndfc_interface_po_routed.yml + +- name: Build NDFC Interface Routed List From Template + ansible.builtin.import_tasks: external/ndfc_interface_routed.yml + +- name: Build NDFC Interface Trunk Po List From Template + ansible.builtin.import_tasks: external/ndfc_interface_trunk_po.yml + +- name: Build NDFC Interface Trunk List From Template + ansible.builtin.import_tasks: external/ndfc_interface_trunk.yml + +- name: Build NDFC Interface VPC List From Template + ansible.builtin.import_tasks: external/ndfc_interface_vpc.yml + +- name: Build NDFC Sub Interface Routed List From Template + ansible.builtin.import_tasks: external/ndfc_sub_interface_routed.yml + +- name: Build NDFC Interface all List From Template + ansible.builtin.import_tasks: external/ndfc_interface_all.yml + +- name: Build NDFC Policy List From Template + ansible.builtin.import_tasks: external/ndfc_policy.yml + + +# -------------------------------------------------------------------- +# Save Local Variables To NameSpace Dict For Use Elsewhere +# -------------------------------------------------------------------- +- name: Save Local Variables With Namespace Context + ansible.builtin.set_fact: + vars_common_external: + changes_detected_fabric: "{{ changes_detected_fabric }}" + changes_detected_inventory: "{{ changes_detected_inventory }}" + changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" + changes_detected_interface_access: "{{ changes_detected_interface_access }}" + changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" + changes_detected_interface_po_routed: "{{ changes_detected_interface_po_routed }}" + changes_detected_interface_routed: "{{ changes_detected_interface_routed }}" + changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" + changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" + changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" + changes_detected_interfaces: "{{ changes_detected_interfaces }}" + changes_detected_policy: "{{ changes_detected_policy }}" + fabric_config: "{{ fabric_config }}" + interface_access_po: "{{ interface_access_po }}" + interface_access: "{{ interface_access }}" + interface_all: "{{ interface_all }}" + int_loopback_config: "{{ int_loopback_config }}" + interface_po_routed: "{{ interface_po_routed }}" + interface_routed: "{{ interface_routed }}" + interface_trunk_po: "{{ interface_trunk_po }}" + interface_trunk: "{{ interface_trunk }}" + inv_config: "{{ inv_config }}" + poap_data: "{{ poap_data }}" + policy_config: "{{ policy_config }}" + sub_interface_routed: "{{ sub_interface_routed }}" + updated_inv_config: "{{ updated_inv_config }}" + +- name: Run Diff Flags + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Fabric Changes Detected - [ {{ vars_common_external.changes_detected_fabric }} ]" + - "+ Inventory Changes Detected - [ {{ vars_common_external.changes_detected_inventory }} ]" + - "+ ----- Interfaces -----" + - "+ Interface Access Changes Detected - [ {{ vars_common_external.changes_detected_interface_access }} ]" + - "+ Interface Access PO Changes Detected - [ {{ vars_common_external.changes_detected_interface_access_po }} ]" + - "+ Interface Loopback Changes Detected - [ {{ vars_common_external.changes_detected_interface_loopback }} ]" + - "+ Interface PO Routed Changes Detected - [ {{ vars_common_external.changes_detected_interface_po_routed }} ]" + - "+ Interface Routed Changes Detected - [ {{ vars_common_external.changes_detected_interface_routed }} ]" + - "+ Interface Trunk Changes Detected - [ {{ vars_common_external.changes_detected_interface_trunk }} ]" + - "+ Interface Trunk PO Changes Detected - [ {{ vars_common_external.changes_detected_interface_trunk_po }} ]" + - "+ Sub Interface Routed Changes Detected - [ {{ vars_common_external.changes_detected_sub_interface_routed }} ]" + - "+ ----- All Interfaces -----" + - "+ All Interfaces Changes Detected - [ {{ vars_common_external.changes_detected_interfaces }} ]" + - "+ ----- All Interfaces -----" + - "+ VRFs Changes Detected - [ {{ vars_common_external.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_external.changes_detected_networks }} ]" + - "+ Policy Changes Detected - [ {{ vars_common_external.changes_detected_policy }} ]" + - "+ Fabric Links Changes Detected - [ {{ vars_common_external.changes_detected_fabric_links }} ]" + - "+ ----- Run Map -----" + - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" + - "+ Force Run Flag - [ {{ force_run_all }} ]" + - "----------------------------------------------------------------" diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index d636ad9b3..5f2921ae8 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -215,6 +215,7 @@ - "+ vPC Link Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_link_vpc_peering }} ]" - "+ vPC Peer Changes Detected - [ {{ vars_common_vxlan.changes_detected_vpc_peering }} ]" - "+ ----- Interfaces -----" + - "+ Interface vPC Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_vpc }} ]" - "+ Interface Access Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access_po }} ]" - "+ Interface Loopback Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_loopback }} ]" @@ -225,7 +226,11 @@ - "+ Sub Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_sub_interface_routed }} ]" - "+ ----- All Interfaces -----" - "+ All Interfaces Changes Detected - [ {{ vars_common_vxlan.changes_detected_interfaces }} ]" + - "+ ----- All Interfaces -----" + - "+ VRFs Changes Detected - [ {{ vars_common_vxlan.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_vxlan.changes_detected_networks }} ]" - "+ Policy Changes Detected - [ {{ vars_common_vxlan.changes_detected_policy }} ]" + - "+ Fabric Links Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric_links }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 new file mode 100644 index 000000000..636e4534b --- /dev/null +++ b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 @@ -0,0 +1,40 @@ +{% set poap_data = poap_data['poap_data'] %} +{% for switch in MD_Extended.vxlan.topology.switches %} +{% if switch.management.management_ipv4_address is defined %} +- seed_ip: {{ switch['management']['management_ipv4_address'] }} +{% elif switch.management.management_ipv6_address is defined %} +- seed_ip: {{ switch['management']['management_ipv6_address'] }} +{% endif %} + auth_proto: {{ MD['vxlan']['global']['auth_proto'] | default(defaults.vxlan.global.auth_proto) }} + user_name: PLACE_HOLDER_USERNAME + password: PLACE_HOLDER_PASSWORD + max_hops: 0 # this is the default value as it is not defined into the data model + role: {{ switch['role'] }} + preserve_config: false +{% if MD_Extended.vxlan.global.bootstrap is defined %} +{% if MD_Extended.vxlan.global.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.global.bootstrap.enable_bootstrap %} +{% if switch.poap is defined and switch.poap.bootstrap %} +{% if poap_data[switch['serial_number']] is defined %} +{% set pdata = poap_data[switch['serial_number']] %} + poap: + - serial_number: {{ switch['serial_number'] }} + hostname: {{ switch['name'] }} + model: {{ pdata['model'] }} + version: {{ pdata['version'] }} + config_data: + modulesModel: {{ pdata['modulesModel'] }} + gateway: {{ pdata['gateway'] }} +{% elif switch['poap']['preprovision'] is defined %} + poap: + - preprovision_serial: {{ switch['poap']['preprovision']['serial_number'] }} + model: {{ switch['poap']['preprovision']['model'] }} + version: {{ switch['poap']['preprovision']['version'] }} + config_data: + modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} + gateway: {{ switch['management']['default_gateway_v4'] }} + hostname: {{ switch['name'] }} +{% endif %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} diff --git a/roles/dtc/create/tasks/external/devices.yml b/roles/dtc/create/tasks/external/devices.yml new file mode 100644 index 000000000..352b2a88a --- /dev/null +++ b/roles/dtc/create/tasks/external/devices.yml @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Devices Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage Devices Discovery + ansible.builtin.import_tasks: devices_discovery.yml + +# TODO: Enable This Capability +# - name: Add Devices POAP +# ansible.builtin.import_tasks: devices_poap.yml diff --git a/roles/dtc/create/tasks/external/devices_discovery.yml b/roles/dtc/create/tasks/external/devices_discovery.yml new file mode 100644 index 000000000..e606c63f4 --- /dev/null +++ b/roles/dtc/create/tasks/external/devices_discovery.yml @@ -0,0 +1,60 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} + cisco.dcnm.dcnm_inventory: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ vars_common_external.updated_inv_config['updated_inv_list'] }}" + deploy: false + save: true + state: merged + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: MD_Extended.vxlan.topology.switches | length > 0 + +- name: Create List of Switch Serial Numbers from Data Model + ansible.builtin.set_fact: + md_serial_numbers: "{{ MD_Extended.vxlan.topology.switches | map(attribute='serial_number') | list }}" + delegate_to: localhost + +- name: Build Switch Hostname Policy Payload from Data Model Update + cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy: + model_data: "{{ MD_Extended }}" + switch_serial_numbers: "{{ md_serial_numbers }}" + template_name: host_11_1 + register: results +# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + +- name: Join List of Switch Hostname Policy IDs from NDFC + ansible.builtin.set_fact: + policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}" + when: results.policy_update | length > 0 + delegate_to: localhost + +- name: Update Switch Hostname Policy in NDFC + cisco.dcnm.dcnm_rest: + method: PUT + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" + json_data: "{{ results.policy_update.values() | list | to_json }}" + when: results.policy_update | length > 0 \ No newline at end of file diff --git a/roles/dtc/create/tasks/external/interfaces.yml b/roles/dtc/create/tasks/external/interfaces.yml new file mode 100644 index 000000000..9867e283b --- /dev/null +++ b/roles/dtc/create/tasks/external/interfaces.yml @@ -0,0 +1,133 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Interfaces Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage Interface Access Portchannel Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Access Portchannel Interface + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_access_po }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Trunk Portchannel Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Trunk Portchannel Interface + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_trunk_po }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 + +# -------------------------------------------------------------------- +# Manage Sub-interface Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Sub-interface Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.sub_interface_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 + +# -------------------------------------------------------------------- +# Manage interface Port-Channel Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Port-Channel Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_po_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 + +# -------------------------------------------------------------------- +# Manage interface Loopback Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage NDFC Fabric Loopback + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.int_loopback_config }}" + when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 + + # -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + +## Will discuss with team and switchover to the below code and remove the above code +# # -------------------------------------------------------------------- +# # Manage Interface All Configuration on NDFC +# # -------------------------------------------------------------------- + +# - name: Manage Interface All +# cisco.dcnm.dcnm_interface: +# fabric: "{{ MD_Extended.vxlan.fabric.name }}" +# state: replaced +# config: "{{ vars_common_vxlan.interface_all }}" +# vars: +# ansible_command_timeout: 3000 +# ansible_connect_timeout: 3000 +# when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 +# delegate_to: localhost diff --git a/roles/dtc/create/tasks/external/policies.yml b/roles/dtc/create/tasks/external/policies.yml new file mode 100644 index 000000000..a2214d834 --- /dev/null +++ b/roles/dtc/create/tasks/external/policies.yml @@ -0,0 +1,41 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Policies Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Policies Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Fabric Policies + cisco.dcnm.dcnm_policy: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + use_desc_as_key: true + config: "{{ vars_common_external.policy_config }}" + deploy: false + state: merged + register: manage_policies_result From e019b7490b3ce1b3c36bb63271dd0aa36fdc61f1 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 9 Jan 2025 08:42:34 +0000 Subject: [PATCH 038/183] bug fix in sub_main_external in common --- roles/dtc/common/tasks/sub_main_external.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index fa81ecc1f..0e00ca537 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -132,10 +132,7 @@ - "+ ----- All Interfaces -----" - "+ All Interfaces Changes Detected - [ {{ vars_common_external.changes_detected_interfaces }} ]" - "+ ----- All Interfaces -----" - - "+ VRFs Changes Detected - [ {{ vars_common_external.changes_detected_vrfs }} ]" - - "+ Networks Changes Detected - [ {{ vars_common_external.changes_detected_networks }} ]" - "+ Policy Changes Detected - [ {{ vars_common_external.changes_detected_policy }} ]" - - "+ Fabric Links Changes Detected - [ {{ vars_common_external.changes_detected_fabric_links }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" From c2a0c482656a846009fe7af44d780fa8f7e5f48d Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Fri, 10 Jan 2025 20:49:16 +0000 Subject: [PATCH 039/183] External plus refactoring --- .../common/prepare_plugins/prep_001_fabric.py | 6 + .../prepare_plugins/prep_002_list_defaults.py | 273 ++++++++++-------- .../prep_103_topology_switches.py | 5 + .../prep_104_fabric_overlay.py | 18 +- .../prep_105_topology_interfaces.py | 5 + .../prep_106_topology_vpc_interfaces.py | 4 + .../prepare_plugins/prep_107_vrf_lites.py | 6 +- .../common/prepare_plugins/prep_999_verify.py | 28 +- plugins/action/dtc/get_poap_data.py | 4 + plugins/action/dtc/map_msd_inventory.py | 32 +- plugins/plugin_utils/data_model_keys.py | 80 ++--- roles/dtc/common/tasks/cleanup_files.yml | 12 +- .../dtc/common/tasks/external/ndfc_fabric.yml | 18 +- .../tasks/external/ndfc_interface_access.yml | 18 +- .../external/ndfc_interface_access_po.yml | 18 +- .../tasks/external/ndfc_interface_all.yml | 16 +- .../external/ndfc_interface_loopback.yml | 18 +- .../external/ndfc_interface_po_routed.yml | 18 +- .../tasks/external/ndfc_interface_routed.yml | 18 +- .../tasks/external/ndfc_interface_trunk.yml | 18 +- .../external/ndfc_interface_trunk_po.yml | 18 +- .../tasks/external/ndfc_interface_vpc.yml | 18 +- .../common/tasks/external/ndfc_inventory.yml | 18 +- .../dtc/common/tasks/external/ndfc_policy.yml | 18 +- .../external/ndfc_sub_interface_routed.yml | 18 +- roles/dtc/common/tasks/isn/ndfc_fabric.yml | 18 +- roles/dtc/common/tasks/isn/ndfc_inventory.yml | 18 +- roles/dtc/common/tasks/main.yml | 2 + roles/dtc/common/tasks/msd/ndfc_fabric.yml | 18 +- roles/dtc/common/tasks/msd/ndfc_networks.yml | 18 +- roles/dtc/common/tasks/msd/ndfc_vrfs.yml | 49 ++-- roles/dtc/common/tasks/sub_main_external.yml | 5 + roles/dtc/common/tasks/sub_main_isn.yml | 5 + roles/dtc/common/tasks/sub_main_msd.yml | 11 +- roles/dtc/common/tasks/sub_main_vxlan.yml | 5 + roles/dtc/common/tasks/vxlan/ndfc_fabric.yml | 18 +- .../common/tasks/vxlan/ndfc_fabric_links.yml | 18 +- .../tasks/vxlan/ndfc_interface_access.yml | 18 +- .../tasks/vxlan/ndfc_interface_access_po.yml | 18 +- .../common/tasks/vxlan/ndfc_interface_all.yml | 16 +- .../tasks/vxlan/ndfc_interface_loopback.yml | 18 +- .../tasks/vxlan/ndfc_interface_po_routed.yml | 18 +- .../tasks/vxlan/ndfc_interface_routed.yml | 18 +- .../tasks/vxlan/ndfc_interface_trunk.yml | 18 +- .../tasks/vxlan/ndfc_interface_trunk_po.yml | 18 +- .../common/tasks/vxlan/ndfc_interface_vpc.yml | 18 +- .../dtc/common/tasks/vxlan/ndfc_inventory.yml | 18 +- .../tasks/vxlan/ndfc_link_vpc_peering.yml | 18 +- .../dtc/common/tasks/vxlan/ndfc_networks.yml | 18 +- roles/dtc/common/tasks/vxlan/ndfc_policy.yml | 23 +- .../tasks/vxlan/ndfc_sub_interface_routed.yml | 18 +- .../common/tasks/vxlan/ndfc_vpc_peering.yml | 18 +- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 24 +- roles/dtc/create/tasks/msd/vrfs_networks.yml | 20 +- 54 files changed, 669 insertions(+), 538 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 2e9742c15..847706fd1 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -123,6 +123,7 @@ def prepare(self): # For backwards compatibility, replace 'overlay_services' key with 'overlay' # NOTE: No prepare plugin, jinja2 template or ansible task should reference 'overlay_services' after this replacement. # NOTE: Rules are different since rules run BEFORE prepare plugins + # import epdb ; epdb.set_trace() parent_keys = ['vxlan', 'overlay_services'] dm_check = data_model_key_check(model_data, parent_keys) if 'overlay_services' in dm_check['keys_found']: @@ -134,6 +135,11 @@ def prepare(self): model_data['vxlan']['overlay'] = model_data['vxlan']['overlay_services'] del model_data['vxlan']['overlay_services'] + parent_keys = ['vxlan', 'multisite', 'overlay'] + dm_check = data_model_key_check(model_data, parent_keys) + if 'multisite' in dm_check['keys_found'] and 'overlay' in dm_check['keys_found']: + model_data['vxlan']['overlay'] = model_data['vxlan']['multisite']['overlay'] + self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py index 6d8280ad4..6a2d2d387 100644 --- a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -22,11 +22,48 @@ from ansible.utils.display import Display from ....plugin_utils.helper_functions import data_model_key_check from ....plugin_utils.data_model_keys import model_keys +from functools import reduce +import operator display = Display() +def getFromDict(dataDict, mapList): + """ + # Summary + + Get subset of a nested Dict from a list of keys + + """ + return reduce(operator.getitem, mapList, dataDict) def update_nested_dict(nested_dict, keys, new_value): + """ + # Summary + + Update nested dictionary element value + + ## Raises + + None + + ## Parameters + + - nested_dict: Dictionary to be updated + - keys: A list of keys to access the value + - value: Update the key with this value + + ## Updates + + Updates nested_dict + + ## Usage + + ```python + + update_nested_dict(self.model_data, keys, []) + + ``` + """ if len(keys) == 1: nested_dict[keys[0]] = new_value else: @@ -41,12 +78,92 @@ def __init__(self, **kwargs): self.keys = [] def set_list_default(self, parent_keys, target_key): + """ + # Summary + + Defaults a target_key to be an empty list [] if the + target_key does not exist or does exist but there is no + data associated with the target_key. + + ## Raises + + None + + ## Parameters + + - parent_keys: A list of parent keys + - target_key: The key under the parent keys to access the list + + ## Updates + + Updates self.model_data + + ## Usage + + ```python + parent_keys = ['vxlan', 'global', 'dns_servers'] + target_key = 'dns_servers' + + self.set_list_default(parent_keys, target_key) + + ``` + """ keys = parent_keys + [target_key] dm_check = data_model_key_check(self.model_data, keys) if target_key in dm_check['keys_not_found'] or \ target_key in dm_check['keys_no_data']: update_nested_dict(self.model_data, keys, []) + def set_nested_list_default(self, model_data_subset, target_key): + """ + # Summary + + Update part of a model_data dictionary that has an arbitrary + list of items that needs to be set to empty list [] + + ## Raises + + None + + ## Parameters + + - model_data_subset: Model data subset entry point + - target_key: The target key for each list item under the entry point + + ## Updates + + Updates self.model_data + + ## Usage + + ```python + + model_data_subset = self.model_data['vxlan']['topology']['switches'] + target_key = 'freeforms' + + self.set_nested_list_default(model_data_subset, target_key) + + ``` + """ + list_index = 0 + for item in model_data_subset: + dm_check = data_model_key_check(item, [target_key]) + if target_key in dm_check['keys_not_found'] or \ + target_key in dm_check['keys_no_data']: + model_data_subset[list_index][target_key] = [] + + list_index += 1 + + # The code in this set_nested_list_default function effectively replaces this pattern: + # + # for switch in self.model_data['vxlan']['topology']['switches']: + # dm_check = data_model_key_check(switch, ['freeforms']) + # if 'freeforms' in dm_check['keys_not_found'] or \ + # 'freeforms' in dm_check['keys_no_data']: + # self.model_data['vxlan']['topology']['switches'][list_index]['freeforms'] = [] + + # list_index += 1 + # The prepare method is used to default each list or nested list # in the model data to an empty list if the key for the list does # not exist or data under they key does not exist. @@ -61,139 +178,43 @@ def prepare(self): # -------------------------------------------------------------------- from pprint import pprint - paths = [ - 'global.dns_servers', - 'global.ntp_servers', - 'global.syslog_servers', - 'global.spanning_tree', - 'global.spanning_tree.vlan_range', - 'global.spanning_tree.mst_instance_range', - 'global.netflow', - 'global.netflow.exporter', - 'global.netflow.record', - 'global.netflow.monitor', - 'underlay', - 'topology', - 'topology.edge_connections', - 'topology.fabric_links', - 'topology.switches', - 'topology.vpc_peers', - 'overlay', - 'overlay.vrfs', - 'overlay.vrf_attach_groups', - 'overlay.networks', - 'overlay.network_attach_groups', - 'multisite', - 'multisite.overlay', - 'multisite.overlay.vrfs', - 'multisite.overlay.vrf_attach_groups', - 'multisite.overlay.networks', - 'multisite.overlay.network_attach_groups', - 'policy', - 'policy.policies', - 'policy.groups', - 'policy.switches' - ] - for path in paths: + # type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') + fabric_type = self.model_data['vxlan']['fabric']['type'] + + # for path in paths: + for path in model_keys[fabric_type]: # Get all but the last 2 elements of model_keys[path] - path_type = model_keys[path][-1] - parent_keys = model_keys[path][:-2] - target_key = model_keys[path][-2] + path_type = model_keys[fabric_type][path][-1] + parent_keys = model_keys[fabric_type][path][:-2] + target_key = model_keys[fabric_type][path][-2] if path_type == 'KEY': dm_check = data_model_key_check(self.model_data, parent_keys + [target_key]) if target_key in dm_check['keys_not_found'] or target_key in dm_check['keys_no_data']: update_nested_dict(self.model_data, parent_keys + [target_key], {}) if path_type == 'LIST': self.set_list_default(parent_keys, target_key) - - # -------------------------------------------------------------------- - # The following sections deal with more difficult nexted list - # structures where there is a list_index in the middle of the dict. - # There may be a way to reduce the amount of code but for now leaving - # it as is. - # -------------------------------------------------------------------- - - # -------------------------------------------------------------------- - # Fabric Topology Switches Freeforms List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.topology.switches[index].freeforms list elements - list_index = 0 - for switch in self.model_data['vxlan']['topology']['switches']: - dm_check = data_model_key_check(switch, ['freeforms']) - if 'freeforms' in dm_check['keys_not_found'] or \ - 'freeforms' in dm_check['keys_no_data']: - self.model_data['vxlan']['topology']['switches'][list_index]['freeforms'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Topology Switches Interfaces List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.topology.switches[index].interfaces list elements - list_index = 0 - for switch in self.model_data['vxlan']['topology']['switches']: - dm_check = data_model_key_check(switch, ['interfaces']) - if 'interfaces' in dm_check['keys_not_found'] or 'interfaces' in dm_check['keys_no_data']: - self.model_data['vxlan']['topology']['switches'][list_index]['interfaces'] = [] - - list_index += 1 - - # -------------------------------------------------------------------- - # Fabric Overlay vrf and network attach group List Defaults - # -------------------------------------------------------------------- - - # Check vxlan.overlay.vrf_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay']['vrf_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.overlay.network_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['overlay']['network_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['overlay']['network_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.multisite.overlay.vrf_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay']['vrf_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Check vxlan.multisite.overlay.network_attach_groups[index].switches list elements - list_index = 0 - for group in self.model_data['vxlan']['multisite']['overlay']['network_attach_groups']: - dm_check = data_model_key_check(group, ['switches']) - if 'switches' in dm_check['keys_not_found'] or \ - 'switches' in dm_check['keys_no_data']: - self.model_data['vxlan']['multisite']['overlay']['network_attach_groups'][list_index]['switches'] = [] - - list_index += 1 - - # Before returning check to see if global or underlay data is present and - # generate a warning if they are empty. There might actualy be data but - # one of the other model files might have a bug or everything except the - # top level vxlan key is commented out. - if not bool(self.model_data['vxlan']['underlay']): - msg = '((vxlan.underlay)) data is empty! Check your host_vars model data.' - display.warning(msg=msg, formatted=True) - if not bool(self.model_data['vxlan']['global']): - msg = '((vxlan.global)) data is empty! Check your host_vars model data.' - display.warning(msg=msg, formatted=True) + if path_type == 'LIST_INDEX': + # model_keys['VXLAN_EVPN']['topology.switches.freeform'] = [root_key, 'topology', 'switches', 'freeform', 'LIST_INDEX'] + model_data_subset = getFromDict(self.model_data, parent_keys) + target_key = target_key + self.set_nested_list_default(model_data_subset, target_key) + + + # Quick Sanity Check: + # + # For Fabric Type: VXLAN_EVPN or External + # * Check for existence of global or underlay data + # + # There might actualy be data but one of the other model files might + # have a bug or everything except the top level vxlan key is commented out. + if fabric_type in ['VXLAN_EVPN', 'External']: + fn = self.model_data['vxlan']['fabric']['name'] + if not bool(self.model_data['vxlan'].get('underlay')): + msg = "((vxlan.underlay)) data is empty! Check your host_vars model data for fabric {fn}." + display.warning(msg=msg, formatted=True) + if not bool(self.model_data['vxlan'].get('global')): + msg = "((vxlan.global)) data is empty! Check your host_vars model data for fabric {fn}." + display.warning(msg=msg, formatted=True) self.kwargs['results']['model_extended'] = self.model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py index 7f89b6705..7b9cb1760 100644 --- a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py +++ b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py @@ -29,6 +29,11 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] + + # This plugin does not apply to the follwing fabric types + if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + return self.kwargs['results'] + # Loop over all the roles in vxlan.topology.switches.role model_data['vxlan']['topology']['spine'] = {} model_data['vxlan']['topology']['leaf'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index 4e9f26970..412a8611b 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -29,7 +29,12 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] - switches = model_data['vxlan']['topology']['switches'] + + # We don't have switches for Multisite fabrics so need special handling + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF', 'ISN'): + switches = [] + else: + switches = model_data['vxlan']['topology']['switches'] if model_data['vxlan']['fabric']['type'] in ('VXLAN_EVPN'): # Rebuild sm_data['vxlan']['overlay']['vrf_attach_groups'] into @@ -85,6 +90,7 @@ def prepare(self): # a structure that is easier to use. vrf_grp_name_list = [] model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'] = {} + model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'] = [] for grp in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] vrf_grp_name_list.append(grp['name']) @@ -99,6 +105,11 @@ def prepare(self): elif found_switch.get('management').get('management_ipv6_address'): switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + # Append switch to a flat list of switches for cross comparison later when we query the + # MSD fabric information. We need to stop execution if the list returned by the MSD query + # does not include one of these switches. + model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'].append(switch['hostname']) + # Remove vrf_attach_group from vrf if the group_name is not defined for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: if 'vrf_attach_group' in vrf: @@ -109,6 +120,7 @@ def prepare(self): # a structure that is easier to use. net_grp_name_list = [] model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'] = {} + model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'] = [] for grp in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']] = [] net_grp_name_list.append(grp['name']) @@ -122,6 +134,10 @@ def prepare(self): switch['mgmt_ip_address'] = found_switch['management']['management_ipv4_address'] elif found_switch.get('management').get('management_ipv6_address'): switch['mgmt_ip_address'] = found_switch['management']['management_ipv6_address'] + # Append switch to a flat list of switches for cross comparison later when we query the + # MSD fabric information. We need to stop execution if the list returned by the MSD query + # does not include one of these switches. + model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'].append(switch['hostname']) # Remove network_attach_group from net if the group_name is not defined for net in model_data['vxlan']['multisite']['overlay']['networks']: diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index d4cffc4a9..e391161c1 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -34,6 +34,11 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] + # This plugin does not apply to the follwing fabric types + if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + return self.kwargs['results'] + + model_data['vxlan']['topology']['interfaces'] = {} model_data['vxlan']['topology']['interfaces']['modes'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py index ecd7b3602..531bdf98b 100644 --- a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py @@ -30,6 +30,10 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] + + if model_data['vxlan']['fabric']['type'] == 'ISN': + return self.kwargs['results'] + # Check if vxlan.topology is defined if model_data.get('vxlan').get('topology') is not None: model_data['vxlan']['topology'] = model_data.get('vxlan').get('topology', {}) diff --git a/plugins/action/common/prepare_plugins/prep_107_vrf_lites.py b/plugins/action/common/prepare_plugins/prep_107_vrf_lites.py index bafb2ac98..5bd4e492a 100644 --- a/plugins/action/common/prepare_plugins/prep_107_vrf_lites.py +++ b/plugins/action/common/prepare_plugins/prep_107_vrf_lites.py @@ -33,8 +33,12 @@ def __init__(self, **kwargs): self.keys = [] def prepare(self): - templates_path = self.kwargs['templates_path'] model_data = self.kwargs['results']['model_extended'] + + if model_data['vxlan']['fabric']['type'] == 'ISN': + return self.kwargs['results'] + + templates_path = self.kwargs['templates_path'] default_values = self.kwargs['default_values'] # Remove lines 41-43 after route control that includes route-maps, prefix-lists, etc is merged diff --git a/plugins/action/common/prepare_plugins/prep_999_verify.py b/plugins/action/common/prepare_plugins/prep_999_verify.py index 97e62a33a..037243198 100644 --- a/plugins/action/common/prepare_plugins/prep_999_verify.py +++ b/plugins/action/common/prepare_plugins/prep_999_verify.py @@ -41,6 +41,10 @@ def prepare(self): fail_msg += " the data was not included in the data model." fail_msg += " Data Model Section: ({})" + # from pprint import pprint + # md = model_data + # pprint(md) + # This prepare plugin serves as a final sanity check after all of the # previous prepare plugins have been called to transform the model data. @@ -48,21 +52,19 @@ def prepare(self): # This plugin ensures the following: # * All keys required for this collection to function are present (not accidentally overwritten) # * List items that were present before the prepare plugins ran are still present - for key in model_keys.keys(): - dm_check = data_model_key_check(model_data, model_keys[key]) - # model_keys['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] - # Get 2nd to last item from the python list above - # model_keys[key][-2] - Gets 'policies' - if model_keys[key][-2] in dm_check['keys_not_found']: + fabric_type = model_data['vxlan']['fabric']['type'] + for key in model_keys[fabric_type].keys(): + # Remove the meta_data item from model_keys entry (KEY, LIST, LIST_INDEX) + model_keys[fabric_type][key].pop() + dm_check = data_model_key_check(model_data, model_keys[fabric_type][key]) + # Example: + # model_keys['VXLAN_EVPN']['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] + # * Get 2nd to last item from the python list above + # * model_keys[key][-2] - Gets 'policies' + if model_keys[fabric_type][key][-2] in dm_check['keys_not_found']: self.kwargs['results']['failed'] = True - self.kwargs['results']['msg'] = fail_msg.format(key, model_keys[key]) + self.kwargs['results']['msg'] = fail_msg.format(key, model_keys[fabric_type][key]) return self.kwargs['results'] - - - # from pprint import pprint - # md = model_data - # import epdb ; epdb.set_trace() - # pprint(md) # We don't need to pass any data back in this plugin because we don't modify any data. return self.kwargs['results'] diff --git a/plugins/action/dtc/get_poap_data.py b/plugins/action/dtc/get_poap_data.py index 4600b8717..9042247de 100644 --- a/plugins/action/dtc/get_poap_data.py +++ b/plugins/action/dtc/get_poap_data.py @@ -173,6 +173,10 @@ def run(self, tmp=None, task_vars=None): # Get data from Ansible task parameters params = {} params['model_data'] = self._task.args["model_data"] + + if params['model_data']['vxlan']['fabric']['type'] == 'ISN': + return results + params['action_plugin'] = self._execute_module params['task_vars'] = task_vars params['tmp'] = tmp diff --git a/plugins/action/dtc/map_msd_inventory.py b/plugins/action/dtc/map_msd_inventory.py index 0b4211947..fa6da96e4 100644 --- a/plugins/action/dtc/map_msd_inventory.py +++ b/plugins/action/dtc/map_msd_inventory.py @@ -37,6 +37,7 @@ def run(self, tmp=None, task_vars=None): results['failed'] = False parent_fabric_name = self._task.args['parent_fabric_name'] + model_data_overlay = self._task.args['model_data_overlay'] msd_inventory = self._execute_module( module_name="cisco.dcnm.dcnm_inventory", @@ -48,11 +49,36 @@ def run(self, tmp=None, task_vars=None): tmp=tmp ) + response = msd_inventory.get('response', []) msd_switches = {} - for switch in msd_inventory.get('response', []): + + if isinstance(response, str): + if response == 'The queried switch is not part of the fabric configured': + results['msd_switches'] = msd_switches + return results + + for switch in response: msd_switches.update({switch['hostName']: switch['ipAddress']}) msd_switches.update({switch['ipAddress']: switch['ipAddress']}) - results['msd_switches'] = msd_switches + # Cross reference msd_switches with the switches defined in + # VRF and Network attach list. + # + # Only makes sense to check this if msd_switches actually has switches. + if bool(msd_switches): + results['msg'] = [] + for switch in model_data_overlay['vrf_attach_switches_list']: + if switch not in msd_switches.keys(): + results['failed'] = True + msg = f"Switch ({switch}) defined under vxlan.multisite.overlay.vrf_attach_groups" + msg += f" does not exist under this MSD fabric ({parent_fabric_name})" + results['msg'].append(msg) + for switch in model_data_overlay['network_attach_switches_list']: + if switch not in msd_switches.keys(): + results['failed'] = True + msg = f"Switch ({switch}) defined under vxlan.multisite.overlay.network_attach_groups" + msg += f" does not exist under this MSD fabric ({parent_fabric_name})" + results['msg'].append(msg) - return results + results['msd_switches'] = msd_switches + return results \ No newline at end of file diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index d10b6a41e..04b539451 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -26,45 +26,55 @@ # from ..helper_functions import do_something root_key = 'vxlan' +# Keys here match data model schema +# type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') +model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MCF': {}, 'ISN': {}} -model_keys = {} -model_keys['fabric.name'] = [root_key, 'fabric', 'name', 'KEY'] -model_keys['fabric.type'] = [root_key, 'fabric', 'type', 'KEY'] +# VXLAN_EVPN KEYS -model_keys['global'] = [root_key, 'global', 'KEY'] -model_keys['global.dns_servers'] = [root_key, 'global', 'dns_servers', 'LIST'] -model_keys['global.ntp_servers'] = [root_key, 'global', 'ntp_servers', 'LIST'] -model_keys['global.syslog_servers'] = [root_key, 'global', 'syslog_servers', 'LIST'] -model_keys['global.netflow'] = [root_key, 'global', 'netflow', 'KEY'] -model_keys['global.netflow.exporter'] = [root_key, 'global', 'netflow', 'exporter', 'LIST'] -model_keys['global.netflow.record'] = [root_key, 'global', 'netflow', 'record', 'LIST'] -model_keys['global.netflow.monitor'] = [root_key, 'global', 'netflow', 'monitor', 'LIST'] -model_keys['global.spanning_tree'] = [root_key, 'global', 'spanning_tree', 'KEY'] -model_keys['global.spanning_tree.vlan_range'] = [root_key, 'global', 'spanning_tree', 'vlan_range', 'LIST'] -model_keys['global.spanning_tree.mst_instance_range'] = [root_key, 'global', 'spanning_tree', 'mst_instance_range', 'LIST'] +model_keys['VXLAN_EVPN']['global'] = [root_key, 'global', 'KEY'] +model_keys['VXLAN_EVPN']['global.dns_servers'] = [root_key, 'global', 'dns_servers', 'LIST'] +model_keys['VXLAN_EVPN']['global.ntp_servers'] = [root_key, 'global', 'ntp_servers', 'LIST'] +model_keys['VXLAN_EVPN']['global.syslog_servers'] = [root_key, 'global', 'syslog_servers', 'LIST'] +model_keys['VXLAN_EVPN']['global.netflow'] = [root_key, 'global', 'netflow', 'KEY'] +model_keys['VXLAN_EVPN']['global.netflow.exporter'] = [root_key, 'global', 'netflow', 'exporter', 'LIST'] +model_keys['VXLAN_EVPN']['global.netflow.record'] = [root_key, 'global', 'netflow', 'record', 'LIST'] +model_keys['VXLAN_EVPN']['global.netflow.monitor'] = [root_key, 'global', 'netflow', 'monitor', 'LIST'] +model_keys['VXLAN_EVPN']['global.spanning_tree'] = [root_key, 'global', 'spanning_tree', 'KEY'] +model_keys['VXLAN_EVPN']['global.spanning_tree.vlan_range'] = [root_key, 'global', 'spanning_tree', 'vlan_range', 'LIST'] +model_keys['VXLAN_EVPN']['global.spanning_tree.mst_instance_range'] = [root_key, 'global', 'spanning_tree', 'mst_instance_range', 'LIST'] # --- -model_keys['underlay'] = [root_key, 'underlay', 'KEY'] +model_keys['VXLAN_EVPN']['underlay'] = [root_key, 'underlay', 'KEY'] # --- -model_keys['topology'] = [root_key, 'topology', 'KEY'] -model_keys['topology.edge_connections'] = [root_key, 'topology', 'edge_connections', 'LIST'] -model_keys['topology.fabric_links'] = [root_key, 'topology', 'fabric_links', 'LIST'] -model_keys['topology.switches'] = [root_key, 'topology', 'switches', 'LIST'] -model_keys['topology.vpc_peers'] = [root_key, 'topology', 'vpc_peers', 'LIST'] +model_keys['VXLAN_EVPN']['topology'] = [root_key, 'topology', 'KEY'] +model_keys['VXLAN_EVPN']['topology.edge_connections'] = [root_key, 'topology', 'edge_connections', 'LIST'] +model_keys['VXLAN_EVPN']['topology.fabric_links'] = [root_key, 'topology', 'fabric_links', 'LIST'] +model_keys['VXLAN_EVPN']['topology.switches'] = [root_key, 'topology', 'switches', 'LIST'] +model_keys['VXLAN_EVPN']['topology.switches.freeform'] = [root_key, 'topology', 'switches', 'freeform', 'LIST_INDEX'] +model_keys['VXLAN_EVPN']['topology.switches.interfaces'] = [root_key, 'topology', 'switches', 'interfaces', 'LIST_INDEX'] +model_keys['VXLAN_EVPN']['topology.vpc_peers'] = [root_key, 'topology', 'vpc_peers', 'LIST'] # --- -model_keys['overlay'] = [root_key, 'overlay', 'KEY'] -model_keys['overlay.vrfs'] = [root_key, 'overlay', 'vrfs', 'LIST'] -model_keys['overlay.vrf_attach_groups'] = [root_key, 'overlay', 'vrf_attach_groups', 'LIST'] -model_keys['overlay.networks'] = [root_key, 'overlay', 'networks', 'LIST'] -model_keys['overlay.network_attach_groups'] = [root_key, 'overlay', 'network_attach_groups', 'LIST'] +model_keys['VXLAN_EVPN']['overlay'] = [root_key, 'overlay', 'KEY'] +model_keys['VXLAN_EVPN']['overlay.vrfs'] = [root_key, 'overlay', 'vrfs', 'LIST'] +model_keys['VXLAN_EVPN']['overlay.vrf_attach_groups'] = [root_key, 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['VXLAN_EVPN']['overlay.vrf_attach_groups.switches'] = [root_key, 'overlay', 'vrf_attach_groups', 'switches', 'LIST_INDEX'] +model_keys['VXLAN_EVPN']['overlay.networks'] = [root_key, 'overlay', 'networks', 'LIST'] +model_keys['VXLAN_EVPN']['overlay.network_attach_groups'] = [root_key, 'overlay', 'network_attach_groups', 'LIST'] +model_keys['VXLAN_EVPN']['overlay.network_attach_groups.switches'] = [root_key, 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] # --- -model_keys['multisite'] = [root_key, 'multisite', 'KEY'] -model_keys['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] -model_keys['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] -model_keys['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] -model_keys['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] -model_keys['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] +model_keys['VXLAN_EVPN']['policy'] = [root_key, 'policy', 'KEY'] +model_keys['VXLAN_EVPN']['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] +model_keys['VXLAN_EVPN']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] +model_keys['VXLAN_EVPN']['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] + +# MSD KEYS + # --- -model_keys['policy'] = [root_key, 'policy', 'KEY'] -model_keys['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] -model_keys['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] -model_keys['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] +model_keys['MSD']['multisite'] = [root_key, 'multisite', 'KEY'] +model_keys['MSD']['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] +model_keys['MSD']['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] +model_keys['MSD']['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['MSD']['multisite.overlay.vrf_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'switches', 'LIST_INDEX'] +model_keys['MSD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] +model_keys['MSD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] +model_keys['MSD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] diff --git a/roles/dtc/common/tasks/cleanup_files.yml b/roles/dtc/common/tasks/cleanup_files.yml index 61356931f..7c20ba893 100644 --- a/roles/dtc/common/tasks/cleanup_files.yml +++ b/roles/dtc/common/tasks/cleanup_files.yml @@ -3,18 +3,12 @@ - name: Delete content & directory ansible.builtin.file: state: absent - path: "{{ role_path }}/files/" + path: "{{ path_name }}" delegate_to: localhost - name: Recreate the directory ansible.builtin.file: - path: "{{ role_path }}/files/" + path: "{{ path_name }}" state: directory mode: '0755' - delegate_to: localhost - -- name: Add gitkeep file back to the directory - ansible.builtin.file: - path: "{{ role_path }}/files/.gitkeep" - state: touch - delegate_to: localhost + delegate_to: localhost \ No newline at end of file diff --git a/roles/dtc/common/tasks/external/ndfc_fabric.yml b/roles/dtc/common/tasks/external/ndfc_fabric.yml index a6ed2eeae..02d383b84 100644 --- a/roles/dtc/common/tasks/external/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/external/ndfc_fabric.yml @@ -28,43 +28,43 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + file_name: "ndfc_fabric.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Fabric Creation Parameters From Template ansible.builtin.template: src: ndfc_fabric.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_access.yml b/roles/dtc/common/tasks/external/ndfc_interface_access.yml index ba50dea14..8b146321b 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_access.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_access.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access.yml" + file_name: "ndfc_interface_access.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_access.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_access Var @@ -63,14 +63,14 @@ - name: Set interface_access Var ansible.builtin.set_fact: - interface_access: "{{ lookup('file', file_name) | from_yaml }}" + interface_access: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml index 2e5b2b6f9..702e4b444 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_access_po.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access_po.yml" + file_name: "ndfc_interface_access_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_access_po.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_access_po Var @@ -63,14 +63,14 @@ - name: Set interface_access_po Var ansible.builtin.set_fact: - interface_access_po: "{{ lookup('file', file_name) | from_yaml }}" + interface_access_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_all.yml b/roles/dtc/common/tasks/external/ndfc_interface_all.yml index ff9047757..b4850efb5 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_all.yml @@ -28,25 +28,25 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_all.yml" + file_name: "ndfc_interface_all.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists @@ -64,13 +64,13 @@ - name: Save interface_all ansible.builtin.copy: content: "{{ interface_all | to_nice_yaml }}" - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml index d720d5f68..0de48d66a 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_loopback.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_loopback_interfaces.yml" + file_name: "ndfc_loopback_interfaces.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Loopback Interfaces List From Template ansible.builtin.template: src: ndfc_loopback_interfaces.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set int_loopback_config Var @@ -63,14 +63,14 @@ - name: Set int_loopback_config Var ansible.builtin.set_fact: - int_loopback_config: "{{ lookup('file', file_name) | from_yaml }}" + int_loopback_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml index 7fb2af335..5573b8c02 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_po_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_po_routed.yml" + file_name: "ndfc_interface_po_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface Po ansible.builtin.template: src: ndfc_interface_po_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_po_routed Var default @@ -63,14 +63,14 @@ - name: Set interface_po_routed Var ansible.builtin.set_fact: - interface_po_routed: "{{ lookup('file', file_name) | from_yaml }}" + interface_po_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_routed.yml b/roles/dtc/common/tasks/external/ndfc_interface_routed.yml index 4c2f90680..14a6a9922 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_routed.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_routed.yml" + file_name: "ndfc_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_routed Var default @@ -63,14 +63,14 @@ - name: Set interface_routed Var ansible.builtin.set_fact: - interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml index 073f02ce2..5cb9a4084 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_trunk.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk.yml" + file_name: "ndfc_interface_trunk.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_trunk.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_trunk Var @@ -63,14 +63,14 @@ - name: Set interface_trunk Var ansible.builtin.set_fact: - interface_trunk: "{{ lookup('file', file_name) | from_yaml }}" + interface_trunk: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml index b97086acc..2e155dc7c 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_trunk_po.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk_po.yml" + file_name: "ndfc_interface_trunk_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_trunk_po.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_trunk_po Var @@ -63,14 +63,14 @@ - name: Set interface_trunk_po Var ansible.builtin.set_fact: - interface_trunk_po: "{{ lookup('file', file_name) | from_yaml }}" + interface_trunk_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml index 5554d65d4..d8c264f15 100644 --- a/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml +++ b/roles/dtc/common/tasks/external/ndfc_interface_vpc.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_vpc.yml" + file_name: "ndfc_interface_vpc.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build VPC interface ansible.builtin.template: src: ndfc_interface_vpc.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_vpc Var default @@ -63,14 +63,14 @@ - name: Set interface_vpc Var ansible.builtin.set_fact: - interface_vpc: "{{ lookup('file', file_name) | from_yaml }}" + interface_vpc: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_inventory.yml b/roles/dtc/common/tasks/external/ndfc_inventory.yml index db6667a41..c530ce8bf 100644 --- a/roles/dtc/common/tasks/external/ndfc_inventory.yml +++ b/roles/dtc/common/tasks/external/ndfc_inventory.yml @@ -33,31 +33,31 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" + file_name: "ndfc_inventory.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Set Path For Inventory File Lookup ansible.builtin.set_fact: - inv_file_path: "{{ role_path }}/files/{{ file_name }}" + inv_file_path: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Build Fabric Switch Inventory List From Template @@ -73,7 +73,7 @@ - name: Set inv_config Var ansible.builtin.set_fact: - inv_config: "{{ lookup('file', file_name) | from_yaml }}" + inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.topology.switches | default([])) | length > 0 delegate_to: localhost @@ -91,8 +91,8 @@ - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_policy.yml b/roles/dtc/common/tasks/external/ndfc_policy.yml index 1203bb7b9..54fb0d5cf 100644 --- a/roles/dtc/common/tasks/external/ndfc_policy.yml +++ b/roles/dtc/common/tasks/external/ndfc_policy.yml @@ -28,44 +28,44 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_policy.yml" + file_name: "ndfc_policy.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Policy List From Template ansible.builtin.template: src: ndfc_policy.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - ansible.builtin.set_fact: - policy_config: "{{ lookup('file', file_name) | from_yaml }}" + policy_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.policy.policies | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml index 9677853e0..5446268d7 100644 --- a/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml +++ b/roles/dtc/common/tasks/external/ndfc_sub_interface_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_sub_interface_routed.yml" + file_name: "ndfc_sub_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build sub_interface ansible.builtin.template: src: ndfc_sub_interface_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set sub_interface_routed Var default @@ -63,14 +63,14 @@ - name: Set sub_interface_routed Var ansible.builtin.set_fact: - sub_interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + sub_interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/isn/ndfc_fabric.yml b/roles/dtc/common/tasks/isn/ndfc_fabric.yml index a6ed2eeae..02d383b84 100644 --- a/roles/dtc/common/tasks/isn/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/isn/ndfc_fabric.yml @@ -28,43 +28,43 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + file_name: "ndfc_fabric.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Fabric Creation Parameters From Template ansible.builtin.template: src: ndfc_fabric.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/isn/ndfc_inventory.yml b/roles/dtc/common/tasks/isn/ndfc_inventory.yml index bcaae0608..c4d37aa69 100644 --- a/roles/dtc/common/tasks/isn/ndfc_inventory.yml +++ b/roles/dtc/common/tasks/isn/ndfc_inventory.yml @@ -33,31 +33,31 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" + file_name: "ndfc_inventory.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Set Path For Inventory File Lookup ansible.builtin.set_fact: - inv_file_path: "{{ role_path }}/files/{{ file_name }}" + inv_file_path: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Build Fabric Switch Inventory List From Template @@ -73,7 +73,7 @@ - name: Set inv_config Var ansible.builtin.set_fact: - inv_config: "{{ lookup('file', file_name) | from_yaml }}" + inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.multisite.isn.topology.switches | default([])) | length > 0 delegate_to: localhost @@ -91,8 +91,8 @@ - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 0a21bd04f..185c9eb3e 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -65,6 +65,8 @@ changes_detected_interface_vpc: false changes_detected_sub_interface_routed: false changes_detected_policy: false + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + - name: Import Role Tasks for VXLAN Fabric ansible.builtin.import_tasks: sub_main_vxlan.yml diff --git a/roles/dtc/common/tasks/msd/ndfc_fabric.yml b/roles/dtc/common/tasks/msd/ndfc_fabric.yml index a6ed2eeae..02d383b84 100644 --- a/roles/dtc/common/tasks/msd/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/msd/ndfc_fabric.yml @@ -28,43 +28,43 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + file_name: "ndfc_fabric.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Fabric Creation Parameters From Template ansible.builtin.template: src: ndfc_fabric.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/msd/ndfc_networks.yml b/roles/dtc/common/tasks/msd/ndfc_networks.yml index 0f024b8fa..905c88a26 100644 --- a/roles/dtc/common/tasks/msd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/msd/ndfc_networks.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_networks.yml" + file_name: "ndfc_attach_networks.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Networks Attach List From Template ansible.builtin.template: src: ndfc_attach_networks.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set net_config Var @@ -63,14 +63,14 @@ - name: Set net_config Var ansible.builtin.set_fact: - net_config: "{{ lookup('file', file_name) | from_yaml }}" + net_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.multisite.overlay.networks | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml index 9923d716e..b8b489d9d 100644 --- a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_vrfs.yml" + file_name: "ndfc_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build VRFs Attach List From Template ansible.builtin.template: src: ndfc_attach_vrfs.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Create Empty vrf_config Var @@ -63,14 +63,14 @@ - name: Set vrf_config Var ansible.builtin.set_fact: - vrf_config: "{{ lookup('file', file_name) | from_yaml }}" + vrf_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost @@ -87,20 +87,21 @@ file_name: "{{ MD_Extended.vxlan.fabric.name }}_attach_vrfs_loopbacks.yml" delegate_to: localhost -- name: Build VRFs Attach List From Template for loopback - ansible.builtin.template: - src: ndfc_attach_vrfs_loopbacks.j2 - dest: "{{ role_path }}/files/{{ file_name }}" - delegate_to: localhost +# Check with Matt and Pete on how we want to handle VRF loopbacks for MSD +# - name: Build VRFs Attach List From Template for loopback +# ansible.builtin.template: +# src: ndfc_attach_vrfs_loopbacks.j2 +# dest: "{{ path_name }}{{ file_name }}" +# delegate_to: localhost -- name: Create Empty vrf_config Var - ansible.builtin.set_fact: - vrf_attach_config: [] - delegate_to: localhost +# - name: Create Empty vrf_config Var +# ansible.builtin.set_fact: +# vrf_attach_config: [] +# delegate_to: localhost -- name: Set vrf_config Var - ansible.builtin.set_fact: - vrf_attach_config: "{{ lookup('file', file_name) | from_yaml }}" - when: > - (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 - delegate_to: localhost \ No newline at end of file +# - name: Set vrf_config Var +# ansible.builtin.set_fact: +# vrf_attach_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" +# when: > +# (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 +# delegate_to: localhost \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index 0e00ca537..1be6a5e68 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -28,6 +28,11 @@ # -------------------------------------------------------------------- # Remove all files from the previous run if run_map requires it # -------------------------------------------------------------------- +- name: Set path_name Var + ansible.builtin.set_fact: + path_name: "{{ role_path }}/files/external/{{ MD_Extended.vxlan.fabric.name }}/" + delegate_to: localhost + - name: Cleanup Files from Previous Run if run_map requires it ansible.builtin.import_tasks: cleanup_files.yml when: diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml index b9b474864..f7e2c8201 100644 --- a/roles/dtc/common/tasks/sub_main_isn.yml +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -28,6 +28,11 @@ # -------------------------------------------------------------------- # Remove all files from the previous run if run_map requires it # -------------------------------------------------------------------- +- name: Set path_name Var + ansible.builtin.set_fact: + path_name: "{{ role_path }}/files/isn/{{ MD_Extended.vxlan.fabric.name }}/" + delegate_to: localhost + - name: Cleanup Files from Previous Run if run_map requires it ansible.builtin.import_tasks: cleanup_files.yml when: diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 3507c8b38..1499db169 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -28,6 +28,11 @@ # -------------------------------------------------------------------- # Remove all files from the previous run if run_map requires it # -------------------------------------------------------------------- +- name: Set path_name Var + ansible.builtin.set_fact: + path_name: "{{ role_path }}/files/msd/{{ MD_Extended.vxlan.fabric.name }}/" + delegate_to: localhost + - name: Cleanup Files from Previous Run if run_map requires it ansible.builtin.import_tasks: cleanup_files.yml when: @@ -50,12 +55,15 @@ - name: Get Switch Inventory from MSD Fabric cisco.nac_dc_vxlan.dtc.map_msd_inventory: parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" + model_data_overlay: "{{ MD_Extended.vxlan.multisite.overlay }}" register: msd_inventory - name: Set MSD Switches List ansible.builtin.set_fact: msd_switches: "{{ msd_inventory.msd_switches }}" +- debug: msg="{{ msd_switches }}" + # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template # -------------------------------------------------------------------- @@ -82,7 +90,8 @@ fabric_config: "{{ fabric_config }}" net_config: "{{ net_config }}" vrf_config: "{{ vrf_config }}" - vrf_attach_config: "{{ vrf_attach_config }}" + # Check with Matt and Pete on how to handle this for MSD + # vrf_attach_config: "{{ vrf_attach_config }}" - name: Run Diff Flags ansible.builtin.debug: diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index 5f2921ae8..1bc3e4bab 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -28,6 +28,11 @@ # -------------------------------------------------------------------- # Remove all files from the previous run if run_map requires it # -------------------------------------------------------------------- +- name: Set path_name Var + ansible.builtin.set_fact: + path_name: "{{ role_path }}/files/vxlan/{{ MD_Extended.vxlan.fabric.name }}/" + delegate_to: localhost + - name: Cleanup Files from Previous Run if run_map requires it ansible.builtin.import_tasks: cleanup_files.yml when: diff --git a/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml index a6ed2eeae..02d383b84 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml @@ -28,43 +28,43 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric.yml" + file_name: "ndfc_fabric.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Fabric Creation Parameters From Template ansible.builtin.template: src: ndfc_fabric.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', file_name) | from_yaml }}" + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml index dcfabf800..6f7a762f9 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_fabric_links.yml" + file_name: "ndfc_fabric_links.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Fabric Links ansible.builtin.template: src: ndfc_fabric_links.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set fabric_links Var default @@ -63,14 +63,14 @@ - name: Set fabric_links Var ansible.builtin.set_fact: - fabric_links: "{{ lookup('file', file_name) | from_yaml }}" + fabric_links: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.fabric_links | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml index ba50dea14..8b146321b 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access.yml" + file_name: "ndfc_interface_access.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_access.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_access Var @@ -63,14 +63,14 @@ - name: Set interface_access Var ansible.builtin.set_fact: - interface_access: "{{ lookup('file', file_name) | from_yaml }}" + interface_access: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml index 2e5b2b6f9..702e4b444 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_access_po.yml" + file_name: "ndfc_interface_access_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_access_po.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_access_po Var @@ -63,14 +63,14 @@ - name: Set interface_access_po Var ansible.builtin.set_fact: - interface_access_po: "{{ lookup('file', file_name) | from_yaml }}" + interface_access_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml index ff9047757..b4850efb5 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml @@ -28,25 +28,25 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_all.yml" + file_name: "ndfc_interface_all.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists @@ -64,13 +64,13 @@ - name: Save interface_all ansible.builtin.copy: content: "{{ interface_all | to_nice_yaml }}" - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml index d720d5f68..0de48d66a 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_loopback_interfaces.yml" + file_name: "ndfc_loopback_interfaces.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Loopback Interfaces List From Template ansible.builtin.template: src: ndfc_loopback_interfaces.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set int_loopback_config Var @@ -63,14 +63,14 @@ - name: Set int_loopback_config Var ansible.builtin.set_fact: - int_loopback_config: "{{ lookup('file', file_name) | from_yaml }}" + int_loopback_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml index 7fb2af335..5573b8c02 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_po_routed.yml" + file_name: "ndfc_interface_po_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface Po ansible.builtin.template: src: ndfc_interface_po_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_po_routed Var default @@ -63,14 +63,14 @@ - name: Set interface_po_routed Var ansible.builtin.set_fact: - interface_po_routed: "{{ lookup('file', file_name) | from_yaml }}" + interface_po_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml index 4c2f90680..14a6a9922 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_routed.yml" + file_name: "ndfc_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_routed Var default @@ -63,14 +63,14 @@ - name: Set interface_routed Var ansible.builtin.set_fact: - interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml index 073f02ce2..5cb9a4084 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk.yml" + file_name: "ndfc_interface_trunk.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_trunk.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_trunk Var @@ -63,14 +63,14 @@ - name: Set interface_trunk Var ansible.builtin.set_fact: - interface_trunk: "{{ lookup('file', file_name) | from_yaml }}" + interface_trunk: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml index b97086acc..2e155dc7c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_trunk_po.yml" + file_name: "ndfc_interface_trunk_po.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Interface ansible.builtin.template: src: ndfc_interface_trunk_po.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_trunk_po Var @@ -63,14 +63,14 @@ - name: Set interface_trunk_po Var ansible.builtin.set_fact: - interface_trunk_po: "{{ lookup('file', file_name) | from_yaml }}" + interface_trunk_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml index 5554d65d4..d8c264f15 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_interface_vpc.yml" + file_name: "ndfc_interface_vpc.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build VPC interface ansible.builtin.template: src: ndfc_interface_vpc.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set interface_vpc Var default @@ -63,14 +63,14 @@ - name: Set interface_vpc Var ansible.builtin.set_fact: - interface_vpc: "{{ lookup('file', file_name) | from_yaml }}" + interface_vpc: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml index db6667a41..c530ce8bf 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml @@ -33,31 +33,31 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_inventory.yml" + file_name: "ndfc_inventory.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Set Path For Inventory File Lookup ansible.builtin.set_fact: - inv_file_path: "{{ role_path }}/files/{{ file_name }}" + inv_file_path: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Build Fabric Switch Inventory List From Template @@ -73,7 +73,7 @@ - name: Set inv_config Var ansible.builtin.set_fact: - inv_config: "{{ lookup('file', file_name) | from_yaml }}" + inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.topology.switches | default([])) | length > 0 delegate_to: localhost @@ -91,8 +91,8 @@ - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml index 1102baf10..7a70e9825 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_link_vpc_peering.yml" + file_name: "ndfc_link_vpc_peering.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Links for VPC Peering ansible.builtin.template: src: ndfc_links_vpc_peering.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set link_vpc_peering Var default @@ -63,14 +63,14 @@ - name: Set link_vpc_peering Var ansible.builtin.set_fact: - link_vpc_peering: "{{ lookup('file', file_name) | from_yaml }}" + link_vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.vpc_peers | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml index 797d1149c..cec0f7807 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_networks.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_networks.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_networks.yml" + file_name: "ndfc_attach_networks.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Networks Attach List From Template ansible.builtin.template: src: ndfc_attach_networks.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set net_config Var @@ -63,15 +63,15 @@ - name: Set net_config Var ansible.builtin.set_fact: - net_config: "{{ lookup('file', file_name) | from_yaml }}" + net_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: > (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml index 1203bb7b9..9f965bbe3 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml @@ -28,44 +28,49 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_policy.yml" + file_name: "ndfc_policy.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost # TODO: Add capability to overridde path variable above for CI/CD pipeline - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Policy List From Template ansible.builtin.template: src: ndfc_policy.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set policy_config Var + ansible.builtin.set_fact: + policy_config: [] delegate_to: localhost - ansible.builtin.set_fact: - policy_config: "{{ lookup('file', file_name) | from_yaml }}" + policy_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.policy.policies | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml index 9677853e0..5446268d7 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_sub_interface_routed.yml" + file_name: "ndfc_sub_interface_routed.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build sub_interface ansible.builtin.template: src: ndfc_sub_interface_routed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set sub_interface_routed Var default @@ -63,14 +63,14 @@ - name: Set sub_interface_routed Var ansible.builtin.set_fact: - sub_interface_routed: "{{ lookup('file', file_name) | from_yaml }}" + sub_interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml index 261d4899c..08fa07fc3 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_vpc_peering.yml" + file_name: "ndfc_vpc_peering.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build vPC Peering ansible.builtin.template: src: ndfc_vpc_peering.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set vpc_peering Var default @@ -63,14 +63,14 @@ - name: Set vpc_peering Var ansible.builtin.set_fact: - vpc_peering: "{{ lookup('file', file_name) | from_yaml }}" + vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: MD_Extended.vxlan.topology.vpc_peers | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index 30c72ff51..a7e492c95 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -28,32 +28,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_attach_vrfs.yml" + file_name: "ndfc_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build VRFs Attach List From Template ansible.builtin.template: src: ndfc_attach_vrfs.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Create Empty vrf_config Var @@ -63,15 +63,15 @@ - name: Set vrf_config Var ansible.builtin.set_fact: - vrf_config: "{{ lookup('file', file_name) | from_yaml }}" + vrf_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: > (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost @@ -85,13 +85,13 @@ - name: Set file_name Var for loopback attachments ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_attach_vrfs_loopbacks.yml" + file_name: "attach_vrfs_loopbacks.yml" delegate_to: localhost - name: Build VRFs Attach List From Template for loopback ansible.builtin.template: src: ndfc_attach_vrfs_loopbacks.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Create Empty vrf_config Var @@ -101,7 +101,7 @@ - name: Set vrf_config Var ansible.builtin.set_fact: - vrf_attach_config: "{{ lookup('file', file_name) | from_yaml }}" + vrf_attach_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: > (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 delegate_to: localhost \ No newline at end of file diff --git a/roles/dtc/create/tasks/msd/vrfs_networks.yml b/roles/dtc/create/tasks/msd/vrfs_networks.yml index f67605efc..114c7c6cc 100644 --- a/roles/dtc/create/tasks/msd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/msd/vrfs_networks.yml @@ -45,15 +45,17 @@ # -------------------------------------------------------------------- # Manage Loopback VRF attachments on NDFC # -------------------------------------------------------------------- -- name: Attach VRF Loopbacks per VRF - cisco.dcnm.dcnm_rest: - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments" - method: "POST" - json_data: "{{ vars_common_msd.vrf_attach_config | to_json}}" - when: - - MD_Extended.vxlan.overlay.vrfs is defined - - MD_Extended.vxlan.overlay.vrfs - - vars_common_msd.changes_detected_vrfs + +# Check with Matt and Pete on how we want to handle this for MSD +# - name: Attach VRF Loopbacks per VRF +# cisco.dcnm.dcnm_rest: +# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments" +# method: "POST" +# json_data: "{{ vars_common_msd.vrf_attach_config | to_json}}" +# when: +# - MD_Extended.vxlan.overlay.vrfs is defined +# - MD_Extended.vxlan.overlay.vrfs +# - vars_common_msd.changes_detected_vrfs # -------------------------------------------------------------------- # Manage Network Configuration on NDFC From 4ab1f1648cf9c0b929a13cc0ccaba59cbcec1e63 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Mon, 13 Jan 2025 18:11:27 +0000 Subject: [PATCH 040/183] ISN remove devices and bug fixes --- plugins/plugin_utils/data_model_keys.py | 8 +++ roles/dtc/create/tasks/main.yml | 2 +- roles/dtc/create/tasks/sub_main_external.yml | 2 + roles/dtc/remove/tasks/isn/switches.yml | 45 ++++++++++++++++ roles/dtc/remove/tasks/main.yml | 13 +++-- roles/dtc/remove/tasks/msd/child_fabrics.yml | 1 - roles/dtc/remove/tasks/sub_main_isn.yml | 54 ++++++++++++++++++++ 7 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 roles/dtc/remove/tasks/isn/switches.yml create mode 100644 roles/dtc/remove/tasks/sub_main_isn.yml diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 04b539451..b5a5711f7 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -71,6 +71,7 @@ # --- model_keys['MSD']['multisite'] = [root_key, 'multisite', 'KEY'] +model_keys['MSD']['multisite.child_fabrics'] = [root_key, 'multisite', 'child_fabrics', 'KEY'] model_keys['MSD']['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] model_keys['MSD']['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] model_keys['MSD']['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] @@ -78,3 +79,10 @@ model_keys['MSD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] + +# ISN KEYS + +# --- +model_keys['ISN']['multisite.isn'] = [root_key, 'multisite', 'isn', 'KEY'] +model_keys['ISN']['multisite.isn.topology'] = [root_key, 'multisite', 'isn', 'topology', 'KEY'] +model_keys['ISN']['multisite.isn.topology.switches'] = [root_key, 'multisite', 'isn', 'topology', 'switches', 'LIST'] \ No newline at end of file diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index c3eb2feb5..20b72ddce 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -53,7 +53,7 @@ - name: Import Role Tasks External Fabric ansible.builtin.import_tasks: sub_main_external.yml when: > - (MD_Extended.vxlan.global.fabric_type == 'External') and + (MD_Extended.vxlan.fabric.type == 'External') and (vars_common_external.changes_detected_inventory) or (vars_common_external.changes_detected_interfaces) or (vars_common_external.changes_detected_fabric) or diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 9257eeac0..78ba9baa9 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -35,6 +35,8 @@ - name: Create NDFC External Fabric ansible.builtin.import_tasks: external/fabric.yml when: + - MD_Extended.vxlan.fabric.name is defined + - MD_Extended.vxlan.fabric.type == "External" - MD_Extended.vxlan.global is defined - vars_common_external.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" diff --git a/roles/dtc/remove/tasks/isn/switches.yml b/roles/dtc/remove/tasks/isn/switches.yml new file mode 100644 index 000000000..8d147f652 --- /dev/null +++ b/roles/dtc/remove/tasks/isn/switches.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Switches. This could take several minutes..." + when: + - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) + +- name: Remove Unmanaged NDFC Fabric Devices + cisco.dcnm.dcnm_inventory: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ vars_common_isn.updated_inv_config['updated_inv_list'] }}" + deploy: true + save: true + state: overridden + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "----------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove NDFC Fabric Devices task because inventory_delete_mode flag is set to False +" + - "----------------------------------------------------------------------------------------------------------" + when: not ((inventory_delete_mode is defined) and (inventory_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index 8764d30ef..3c17da865 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -38,9 +38,16 @@ - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml - when: - - MD_Extended.vxlan.fabric.type == 'MSD' - # - vars_common_msd.changes_detected_interfaces or vars_common_msd.changes_detected_networks or vars_common_msd.changes_detected_vrfs + when: > + (MD_Extended.vxlan.fabric.type == 'MSD') and + (vars_common_msd.changes_detected_vrfs) or + (vars_common_msd.changes_detected_networks) + +- name: Import ISN Role Tasks + ansible.builtin.import_tasks: sub_main_isn.yml + when: > + (MD_Extended.vxlan.fabric.type == 'ISN') and + (vars_common_isn.changes_detected_inventory) - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/msd/child_fabrics.yml b/roles/dtc/remove/tasks/msd/child_fabrics.yml index 2dea537f9..6383c438f 100644 --- a/roles/dtc/remove/tasks/msd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/msd/child_fabrics.yml @@ -24,7 +24,6 @@ - ansible.builtin.debug: msg="Removing Unmanaged Child Fabrics. This could take several minutes..." when: - MD_Extended.vxlan.multisite.child_fabrics is defined - - MD_Extended.vxlan.multisite.child_fabrics | length > 0 - (child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool) - name: Get Fabric Association Data from NDFC diff --git a/roles/dtc/remove/tasks/sub_main_isn.yml b/roles/dtc/remove/tasks/sub_main_isn.yml new file mode 100644 index 000000000..960c13512 --- /dev/null +++ b/roles/dtc/remove/tasks/sub_main_isn.yml @@ -0,0 +1,54 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.remove] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.remove] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.remove }}" # Tags defined in roles/common_global/vars/main.yml + +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.remove }}" + +# TODO: May need this to remove Policy in the future for ISN +# lines 36 - 48 +# - name: Get List of Fabric Switches from NDFC +# cisco.dcnm.dcnm_rest: +# method: GET +# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" +# register: switch_list +# tags: "{{ nac_tags.remove }}" + +# - name: Remove Fabric Policy +# ansible.builtin.import_tasks: vxlan/policy.yml +# tags: "{{ nac_tags.remove_policy }}" +# when: +# - vars_common_vxlan.changes_detected_policy + +- name: Remove Fabric Switches + ansible.builtin.import_tasks: isn/switches.yml + tags: "{{ nac_tags.remove_switches }}" + when: + - vars_common_isn.changes_detected_inventory From 03942742fe00dfb1564b2ff688476880884b40ac Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 14 Jan 2025 15:11:43 +0000 Subject: [PATCH 041/183] Added support for MFD --- roles/dtc/common/tasks/mfd/ndfc_children.yml | 3 + roles/dtc/common/tasks/mfd/ndfc_fabric.yml | 77 +++++++++++++ .../common/tasks/mfd/ndfc_get_inventory.yml | 34 ++++++ roles/dtc/common/tasks/mfd/ndfc_networks.yml | 109 ++++++++++++++++++ roles/dtc/common/tasks/mfd/ndfc_vrfs.yml | 96 +++++++++++++++ roles/dtc/common/tasks/sub_main_mfd.yml | 79 +++++++++++++ roles/dtc/common/templates/ndfc_fabric.j2 | 2 +- .../ndfc_fabric/mfd_fabric/dci/.gitkeep | 0 .../ndfc_fabric/mfd_fabric/general/.gitkeep | 0 .../ndfc_fabric/mfd_fabric/resources/.gitkeep | 0 .../ndfc_fabric/mfd_fabric/security/.gitkeep | 0 11 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 roles/dtc/common/tasks/mfd/ndfc_children.yml create mode 100644 roles/dtc/common/tasks/mfd/ndfc_fabric.yml create mode 100644 roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml create mode 100644 roles/dtc/common/tasks/mfd/ndfc_networks.yml create mode 100644 roles/dtc/common/tasks/mfd/ndfc_vrfs.yml create mode 100644 roles/dtc/common/tasks/sub_main_mfd.yml create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/.gitkeep diff --git a/roles/dtc/common/tasks/mfd/ndfc_children.yml b/roles/dtc/common/tasks/mfd/ndfc_children.yml new file mode 100644 index 000000000..6def6b2e0 --- /dev/null +++ b/roles/dtc/common/tasks/mfd/ndfc_children.yml @@ -0,0 +1,3 @@ +--- + +- debug: msg="Building NDFC MSD Child Fabric Data" \ No newline at end of file diff --git a/roles/dtc/common/tasks/mfd/ndfc_fabric.yml b/roles/dtc/common/tasks/mfd/ndfc_fabric.yml new file mode 100644 index 000000000..02d383b84 --- /dev/null +++ b/roles/dtc/common/tasks/mfd/ndfc_fabric.yml @@ -0,0 +1,77 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_fabric.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml b/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml new file mode 100644 index 000000000..5e6c563b7 --- /dev/null +++ b/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Get all the switches in the Federated Fabric + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/inventory/switchesByFabric" + register: switch_results + delegate_to: "{{ inventory_hostname }}" + + +- name: Store switches in the fabric for Federated Fabric + ansible.builtin.set_fact: + switches_in_fabric: "{{ switch_results.response.DATA }}" \ No newline at end of file diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml new file mode 100644 index 000000000..ebffc49cb --- /dev/null +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -0,0 +1,109 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_networks: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD.vxlan.global.name }}_ndfc_fed_attach_networks.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Networks Attach List From Template + ansible.builtin.template: + src: ndfc_attach_networks_fed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set net_config Var + ansible.builtin.set_fact: + net_config: [] + delegate_to: localhost + +- name: Set net_config Var + ansible.builtin.set_fact: + net_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_networks: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] + +- name: Set file_name Var for switches and port attachments + ansible.builtin.set_fact: + file_name: "{{ MD.vxlan.global.name }}_attach_network_switches_ports.yml" + file_name2: "{{ MD.vxlan.global.name }}_attach_network_switches.yml" + switches: [] + networks: [] + delegate_to: localhost + +- name: Build Network attach list for switches on Federated + ansible.builtin.template: + src: ndfc_attach_networks_switches_fed.j2 + dest: "{{ role_path }}/files/{{ file_name2 }}" + delegate_to: localhost + +- name: Build Network attach list for switches and ports on Federated + ansible.builtin.template: + src: ndfc_attach_networks_switches_ports_fed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Set network_switches Var + ansible.builtin.set_fact: + network_switches: "{{ lookup('file', file_name2) | from_yaml }}" + network_switches_ports: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + delegate_to: localhost diff --git a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml new file mode 100644 index 000000000..0951fa444 --- /dev/null +++ b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml @@ -0,0 +1,96 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_vrfs: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD.vxlan.global.name }}_fed_attach_vrfs.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/files/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ role_path }}/files/{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous File If It Exists + ansible.builtin.file: + state: absent + path: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build VRFs Attach List From Template + ansible.builtin.template: + src: ndfc_attach_vrfs_fed.j2 + dest: "{{ role_path }}/files/{{ file_name }}" + delegate_to: localhost + +- name: Create Empty vrf_config Var + ansible.builtin.set_fact: + vrf_config: [] + delegate_to: localhost + +- name: Set vrf_config Var + ansible.builtin.set_fact: + vrf_config: "{{ lookup('file', file_name) | from_yaml }}" + when: (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" + file_name_current: "{{ role_path }}/files/{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_vrfs: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] + +- name: Set file_name Var for loopback attachments + ansible.builtin.set_fact: + file_name: "{{ MD.vxlan.global.name }}_attach_vrfs_loopbacks.yml" + delegate_to: localhost + +- name: Build VRFs Attach List From Template for loopback on Federated + ansible.builtin.template: + src: ndfc_attach_vrfs_loopbacks_fed.j2 + dest: "{{ role_path }}/files/{{ vrf.name }}_{{ file_name }}" + delegate_to: localhost + loop: "{{ MD_Extended.vxlan.overlay_services.vrfs }}" + loop_control: + loop_var: vrf diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml new file mode 100644 index 000000000..d3980f976 --- /dev/null +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -0,0 +1,79 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- ansible.builtin.fail: msg="Service Model Not Defined. Role cisco.nac_dc_vxlan.validate Must Be Called First" + when: MD is undefined + delegate_to: localhost + +# -------------------------------------------------------------------- +# Remove all files from the previous run if run_map requires it +# -------------------------------------------------------------------- +- name: Cleanup Files from Previous Run if run_map requires it + ansible.builtin.include_tasks: cleanup_files.yml + when: + - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) + +# -------------------------------------------------------------------- +# Build Create Fabric Parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.import_tasks: mfd/ndfc_fabric.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Get Switch Inventory when Federated Fabric +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Switch inventory + ansible.builtin.include_tasks: mfd/ndfc_get_inventory.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric VRFs Attach List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric VRFs Attach List From Template + ansible.builtin.include_tasks: mfd/ndfc_vrfs.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Networks Attach List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Networks Attach List From Template + ansible.builtin.include_tasks: mfd/ndfc_networks.yml + +- name: Set facts for missed changes_detected flags for Federated Fabric + ansible.builtin.set_fact: + vars_common_msd: + changes_detected_fabric: "{{ changes_detected_fabric | default(false) }}" + changes_detected_vrfs: "{{ changes_detected_vrfs }}" + changes_detected_networks: "{{ changes_detected_networks }}" +- name: Run Diff Flags + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Fabric Changes Detected - [ {{ vars_common_msd.changes_detected_fabric }} ]" + - "+ VRFs Changes Detected - [ {{ vars_common_msd.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_msd.changes_detected_networks }} ]" + - "+ ----- Run Map -----" + - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" + - "+ Force Run Flag - [ {{ force_run_all }} ]" + - "----------------------------------------------------------------" diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index ff5476780..02c404972 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -24,5 +24,5 @@ {# Include NDFC External Fabric Base Template #} {% include '/ndfc_fabric/dc_external_fabric/dc_external_fabric_base.j2' %} -{# Supported fabric types are: DC VXLAN EVPN, MSD, ISN, External #} +{# Supported fabric types are: DC VXLAN EVPN, MSD, MFD, ISN, External #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/.gitkeep new file mode 100644 index 000000000..e69de29bb From 15416b891a5035afcbf57ff2981ca138eff2c418 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 14 Jan 2025 17:02:30 +0000 Subject: [PATCH 042/183] Added Fed files --- .../templates/ndfc_fabric/mfd_fabric/.gitkeep | 0 .../ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 | 14 ++++++++++++++ .../mfd_fabric/general/mfd_fabric_general.j2 | 10 ++++++++++ .../ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 | 13 +++++++++++++ .../mfd_fabric/resources/mfd_fabric_resources.j2 | 10 ++++++++++ .../mfd_fabric/security/mfd_fabric_security.j2 | 2 ++ 6 files changed, 49 insertions(+) create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/.gitkeep create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 create mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 new file mode 100644 index 000000000..8867c1525 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 @@ -0,0 +1,14 @@ +{# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.fabric.name }} #} + BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} + MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} +{% if vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) %} + ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} + ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) | lower }} + ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} +{% endif %} + DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} + MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) }} +{% if vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) %} + MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.ebgp_password }} + MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.ebgp_password_encryption_type | default(defaults.vxlan.multisite.ebgp_password_encryption_type) }} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 new file mode 100644 index 000000000..a593cfa1f --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 @@ -0,0 +1,10 @@ +{# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.fabric.name }} #} + VXLAN_UNDERLAY_IS_V6: {{ vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) }} +{% if not vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) %} + ENABLE_PVLAN: false +{% endif %} + ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} + MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} + BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} + TOR_AUTO_DEPLOY: false +{# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 new file mode 100644 index 000000000..cdaa4075c --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 @@ -0,0 +1,13 @@ +{# Auto-generated NDFC MultiSite Federated Domain (MFD) Base config data structure for fabric {{ vxlan.fabric.name }} #} + +{# Include NDFC DC VXLAN EVPN General Template #} +{% include '/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2' %} + +{# Include NDFC DC VXLAN EVPN DCI Template #} +{% include '/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2' %} + +{# Include NDFC DC VXLAN EVPN Security Template #} +{% include '/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2' %} + +{# Include NDFC DC VXLAN EVPN Resources Template #} +{% include '/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 new file mode 100644 index 000000000..dc5d0db36 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 @@ -0,0 +1,10 @@ +{# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.fabric.name }} #} +{% if not defaults.vxlan.multisite.enable_ipv6_underlay %} + LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} + DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} + DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} +{% else %} + LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} + V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} + V6_DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.ipv6_dci_subnet_mask) }} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 new file mode 100644 index 000000000..715734a79 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 @@ -0,0 +1,2 @@ +{# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.fabric.name }} #} + ENABLE_SGT: "off" \ No newline at end of file From fdaa9d05decb22d7b07e51a9161832fcdfcfe447 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Tue, 14 Jan 2025 18:37:35 +0000 Subject: [PATCH 043/183] Enable child fabric delete mode flag --- README.md | 2 ++ plugins/action/dtc/manage_child_fabrics.py | 9 +++++++++ roles/common_global/defaults/main.yml | 1 + roles/dtc/common/tasks/msd/ndfc_children.yml | 20 +++++++++++++++++++- roles/dtc/create/tasks/msd/child_fabrics.yml | 1 + roles/dtc/remove/tasks/msd/child_fabrics.yml | 15 ++++++++++++++- 6 files changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9a74e1a8e..0ebfd59e1 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Inside the [example repository](https://github.com/netascode/ansible-dc-vxlan-ex ```yaml # Control Parameters for 'Remove' role tasks +child_fabric_delete_mode: false interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false @@ -85,6 +86,7 @@ The following control variables are available in this collection. | `link_vpc_delete_mode` | Remove vpc link state as part of the remove role | `false` | | `vpc_delete_mode` | Remove vpc pair state as part of the remove role | `false` | | `policy_delete_mode` | Remove policy state as part of the remove role | `false` | +| `child_fabric_delete_mode` | Remove child fabric from MSD|MCF fabric as part of the remove role | `false` | These variables are described in more detail in different sections of this document. diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index b69e4744a..11f59bde0 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -35,6 +35,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False + results['child_fabrics_moved'] = False fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') parent_fabric_name = self._task.args['parent_fabric_name'] @@ -67,6 +68,14 @@ def run(self, tmp=None, task_vars=None): results['msg'] = f"{add_fabric_result['msg']['MESSAGE']}: {add_fabric_result['msg']['DATA']}" break + # If a child fabric is successfully added under an MSD fabric set a flag + # indicating this so that it can be used later to prevent managing VRFs + # and Networks. If we dont prevent this then the VRFs and Networks could + # be removed as part of moving the child fabric. + # + # TBD: This flag is not actually being used currently. Discuss with team. + results['child_fabrics_moved'] = True + results['changed'] = True if operation == 'remove': diff --git a/roles/common_global/defaults/main.yml b/roles/common_global/defaults/main.yml index d6b5a954a..d4bcfe4ef 100644 --- a/roles/common_global/defaults/main.yml +++ b/roles/common_global/defaults/main.yml @@ -33,6 +33,7 @@ force_run_all: false # Parameters to enable/disable remove role tasks +child_fabric_delete_mode: false interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false diff --git a/roles/dtc/common/tasks/msd/ndfc_children.yml b/roles/dtc/common/tasks/msd/ndfc_children.yml index 6def6b2e0..5ffba9e37 100644 --- a/roles/dtc/common/tasks/msd/ndfc_children.yml +++ b/roles/dtc/common/tasks/msd/ndfc_children.yml @@ -1,3 +1,21 @@ --- -- debug: msg="Building NDFC MSD Child Fabric Data" \ No newline at end of file +- debug: msg="Building NDFC MSD Child Fabric Data" + +# Notes on items that still need support for MSD +# +# - Fabric Settings for MSD (Need Customer Requirements Here) +# - Fabric Settings for ISN (Need Customer Requirements Here) +# - Enable Interface Management under ISN workflow +# - Enable Policy Management under ISN/MSD worflows +# - Verify addition of multiple ISN Fabrics/Devies +# (Test Two ISN Fabrics with two ISN devices - Full Mesh) +# (Configure interfaces between the ISN devices) +# (What policy should be applied between the ISN devices) +# - Verify support of VRF / Network properties at MSD level +# - Enable support of VRF / Netowrk properties at Child level under MSD fabric +# - Verify Order of Operations +# - Create VXLAN / ISN Fabrics then MSD Fabric + Association +# - Create MSD Fabric then VXLAN / ISN Fabrics + Association +# - VRF / Network problem when child fabrics moved under MSD but MSD level VRF/Net model data is empty +# (Result is all VRF/Networks are removed after they get moved under MSD - can be controlled with flag) \ No newline at end of file diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml index 61afd99ae..a3129cf57 100644 --- a/roles/dtc/create/tasks/msd/child_fabrics.yml +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -44,3 +44,4 @@ child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" operation: add when: fabric_associations is defined and fabric_associations + register: fabric_move_result diff --git a/roles/dtc/remove/tasks/msd/child_fabrics.yml b/roles/dtc/remove/tasks/msd/child_fabrics.yml index 6383c438f..0a14762a2 100644 --- a/roles/dtc/remove/tasks/msd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/msd/child_fabrics.yml @@ -31,6 +31,9 @@ method: GET path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations register: fabric_associations + when: + - MD_Extended.vxlan.multisite.child_fabrics is defined + - (child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool) - name: Remove Unmanaged Child Fabrics from NDFC cisco.nac_dc_vxlan.dtc.manage_child_fabrics: @@ -38,4 +41,14 @@ parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" operation: remove - when: fabric_associations is defined and fabric_associations + when: + - fabric_associations is defined and fabric_associations + - (child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool) + + +- ansible.builtin.debug: + msg: + - "---------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Child Fabrics task because child_fabric_delete_mode flag is set to False +" + - "---------------------------------------------------------------------------------------------------------------" + when: not ((child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool)) From e765809ec88ff2d901379f9517bf0e00524aa496 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Tue, 14 Jan 2025 18:55:06 +0000 Subject: [PATCH 044/183] Github actions fixes --- plugins/action/common/nac_dc_validate.py | 4 ++-- .../action/common/prepare_plugins/prep_001_fabric.py | 10 ++++------ .../common/prepare_plugins/prep_002_list_defaults.py | 1 - plugins/action/dtc/map_msd_inventory.py | 2 +- plugins/plugin_utils/data_model_keys.py | 2 -- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 712aff519..bea761d92 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -113,14 +113,14 @@ def run(self, tmp=None, task_vars=None): "Attempting to use vxlan.global.fabric_type due to vxlan.fabric.type not being found. " "vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric.type." ) - display.deprecated(msg=deprecated_msg, version='1.0.0') + display.deprecated(msg=deprecated_msg, version='1.0.0', collection_name='cisco.nac_dc_vxlan') if results['data']['vxlan']['global']['fabric_type'] in ('VXLAN_EVPN'): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCF'): rules_list.append(f'{rules}multisite/') elif results['data']['vxlan']['global']['fabric_type'] in ('ISN', 'External'): - rules_list.append(f'{rules}isn/') + rules_list.append(f'{rules}isn/') else: results['failed'] = True results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['global']['fabric_type']} is not a supported fabric type." diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 847706fd1..8dfd709b7 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -59,7 +59,7 @@ def prepare(self): "vxlan.fabric.name and vxlan.fabric.type not being defined. " "vxlan.global.name and vxlan.global.fabric_type is being deprecated. Please use vxlan.fabric." ) - display.deprecated(msg=deprecated_msg, version="1.0.0") + display.deprecated(msg=deprecated_msg, version="1.0.0", collection_name='cisco.nac_dc_vxlan') parent_keys = ['vxlan', 'global'] dm_check = data_model_key_check(model_data, parent_keys) @@ -93,7 +93,7 @@ def prepare(self): "Attempting to use vxlan.global.name due to vxlan.fabric.name not being defined. " "vxlan.global.name is being deprecated. Please use vxlan.fabric." ) - display.deprecated(msg=deprecated_msg, version="1.0.0") + display.deprecated(msg=deprecated_msg, version="1.0.0", collection_name='cisco.nac_dc_vxlan') parent_keys = ['vxlan', 'global', 'name'] dm_check = data_model_key_check(model_data, parent_keys) if 'name' in dm_check['keys_data']: @@ -110,7 +110,7 @@ def prepare(self): "Attempting to use vxlan.global.type due to vxlan.fabric.type not being defined. " "vxlan.global.type is being deprecated. Please use vxlan.fabric." ) - display.deprecated(msg=deprecated_msg, version="1.0.0") + display.deprecated(msg=deprecated_msg, version="1.0.0", collection_name='cisco.nac_dc_vxlan') parent_keys = ['vxlan', 'global', 'fabric_type'] dm_check = data_model_key_check(model_data, parent_keys) if 'fabric_type' in dm_check['keys_data']: @@ -119,7 +119,6 @@ def prepare(self): self.kwargs['results']['failed'] = True self.kwargs['results']['msg'] = "vxlan.fabric.type is not defined in the data model." - # For backwards compatibility, replace 'overlay_services' key with 'overlay' # NOTE: No prepare plugin, jinja2 template or ansible task should reference 'overlay_services' after this replacement. # NOTE: Rules are different since rules run BEFORE prepare plugins @@ -131,7 +130,7 @@ def prepare(self): "vxlan.overlay_services is being deprecated. " "Please use vxlan.overlay instead" ) - display.deprecated(msg=deprecated_msg, version="1.0.0") + display.deprecated(msg=deprecated_msg, version="1.0.0", collection_name='cisco.nac_dc_vxlan') model_data['vxlan']['overlay'] = model_data['vxlan']['overlay_services'] del model_data['vxlan']['overlay_services'] @@ -140,6 +139,5 @@ def prepare(self): if 'multisite' in dm_check['keys_found'] and 'overlay' in dm_check['keys_found']: model_data['vxlan']['overlay'] = model_data['vxlan']['multisite']['overlay'] - self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py index 6a2d2d387..0cb7fc232 100644 --- a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -178,7 +178,6 @@ def prepare(self): # -------------------------------------------------------------------- from pprint import pprint - # type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') fabric_type = self.model_data['vxlan']['fabric']['type'] # for path in paths: diff --git a/plugins/action/dtc/map_msd_inventory.py b/plugins/action/dtc/map_msd_inventory.py index fa6da96e4..e317ad246 100644 --- a/plugins/action/dtc/map_msd_inventory.py +++ b/plugins/action/dtc/map_msd_inventory.py @@ -81,4 +81,4 @@ def run(self, tmp=None, task_vars=None): results['msg'].append(msg) results['msd_switches'] = msd_switches - return results \ No newline at end of file + return results diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index b5a5711f7..69f9a972c 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -26,8 +26,6 @@ # from ..helper_functions import do_something root_key = 'vxlan' -# Keys here match data model schema -# type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MCF': {}, 'ISN': {}} # VXLAN_EVPN KEYS From cde1ce4b520d70a03598bebe4b60998b99693175 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Tue, 14 Jan 2025 19:04:21 +0000 Subject: [PATCH 045/183] GitHub Actions Issues --- tests/sanity/ignore-2.14.txt | 7 +++---- tests/sanity/ignore-2.15.txt | 7 +++---- tests/sanity/ignore-2.16.txt | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 811563c57..5be6c9c9d 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,14 +1,13 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name -plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name +plugins/action/common/prepare_plugins/prep_001_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_002_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 811563c57..5be6c9c9d 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -1,14 +1,13 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name -plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name +plugins/action/common/prepare_plugins/prep_001_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_002_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 811563c57..5be6c9c9d 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,14 +1,13 @@ plugins/action/common/check_roles.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/nac_dc_validate.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/nac_dc_validate.py ansible-deprecated-no-collection-name -plugins/action/common/prepare_plugins/prep_001_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/common/prepare_plugins/prep_101_fabric.py ansible-deprecated-no-collection-name +plugins/action/common/prepare_plugins/prep_001_fabric.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_002_list_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_103_topology_switches.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation From c6e6d3ba4125309e42c53037966ff0b4a094f29b Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Tue, 14 Jan 2025 21:08:44 +0000 Subject: [PATCH 046/183] More GitHub Actions Fixes --- .../common/prepare_plugins/prep_002_list_defaults.py | 7 +++---- .../common/prepare_plugins/prep_104_fabric_overlay.py | 2 +- .../common/prepare_plugins/prep_105_topology_interfaces.py | 1 - plugins/action/common/prepare_plugins/prep_999_verify.py | 6 ------ plugins/action/dtc/update_switch_hostname_policy.py | 2 +- plugins/plugin_utils/data_model_keys.py | 2 +- .../files/rules/vxlan/402_overlay_services_vrfs.py | 1 - .../files/rules/vxlan/403_overlay_services_networks.py | 1 - 8 files changed, 6 insertions(+), 16 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py index 0cb7fc232..60a2ca5da 100644 --- a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -27,6 +27,7 @@ display = Display() + def getFromDict(dataDict, mapList): """ # Summary @@ -36,6 +37,7 @@ def getFromDict(dataDict, mapList): """ return reduce(operator.getitem, mapList, dataDict) + def update_nested_dict(nested_dict, keys, new_value): """ # Summary @@ -148,8 +150,7 @@ def set_nested_list_default(self, model_data_subset, target_key): list_index = 0 for item in model_data_subset: dm_check = data_model_key_check(item, [target_key]) - if target_key in dm_check['keys_not_found'] or \ - target_key in dm_check['keys_no_data']: + if target_key in dm_check['keys_not_found'] or target_key in dm_check['keys_no_data']: model_data_subset[list_index][target_key] = [] list_index += 1 @@ -195,10 +196,8 @@ def prepare(self): if path_type == 'LIST_INDEX': # model_keys['VXLAN_EVPN']['topology.switches.freeform'] = [root_key, 'topology', 'switches', 'freeform', 'LIST_INDEX'] model_data_subset = getFromDict(self.model_data, parent_keys) - target_key = target_key self.set_nested_list_default(model_data_subset, target_key) - # Quick Sanity Check: # # For Fabric Type: VXLAN_EVPN or External diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index 412a8611b..b7080ecdb 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -19,7 +19,7 @@ # # SPDX-License-Identifier: MIT -from ....plugin_utils.helper_functions import data_model_key_check +# from ....plugin_utils.helper_functions import data_model_key_check class PreparePlugin: diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index e391161c1..eb6779161 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -38,7 +38,6 @@ def prepare(self): if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: return self.kwargs['results'] - model_data['vxlan']['topology']['interfaces'] = {} model_data['vxlan']['topology']['interfaces']['modes'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_999_verify.py b/plugins/action/common/prepare_plugins/prep_999_verify.py index 037243198..ce6b7894f 100644 --- a/plugins/action/common/prepare_plugins/prep_999_verify.py +++ b/plugins/action/common/prepare_plugins/prep_999_verify.py @@ -31,7 +31,6 @@ def __init__(self, **kwargs): self.kwargs = kwargs self.keys = [] - def prepare(self): model_data = self.kwargs['results']['model_extended'] self.kwargs['results']['failed'] = False @@ -41,11 +40,6 @@ def prepare(self): fail_msg += " the data was not included in the data model." fail_msg += " Data Model Section: ({})" - # from pprint import pprint - # md = model_data - # pprint(md) - - # This prepare plugin serves as a final sanity check after all of the # previous prepare plugins have been called to transform the model data. # diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index ec8f2d4b4..6b96bec09 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -50,7 +50,7 @@ def run(self, tmp=None, task_vars=None): ) dm_switches = [] - if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN','External'): + if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN', 'External'): dm_switches = model_data["vxlan"]["topology"]["switches"] elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 69f9a972c..83dfc79fb 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -83,4 +83,4 @@ # --- model_keys['ISN']['multisite.isn'] = [root_key, 'multisite', 'isn', 'KEY'] model_keys['ISN']['multisite.isn.topology'] = [root_key, 'multisite', 'isn', 'topology', 'KEY'] -model_keys['ISN']['multisite.isn.topology.switches'] = [root_key, 'multisite', 'isn', 'topology', 'switches', 'LIST'] \ No newline at end of file +model_keys['ISN']['multisite.isn.topology.switches'] = [root_key, 'multisite', 'isn', 'topology', 'switches', 'LIST'] diff --git a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py index ec2fcf1de..8a28aadc6 100644 --- a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py +++ b/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py @@ -110,7 +110,6 @@ def match(cls, inventory): return results - @classmethod def data_model_key_check(cls, tested_object, keys): dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} diff --git a/roles/validate/files/rules/vxlan/403_overlay_services_networks.py b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py index daf4c7acd..f164b7718 100644 --- a/roles/validate/files/rules/vxlan/403_overlay_services_networks.py +++ b/roles/validate/files/rules/vxlan/403_overlay_services_networks.py @@ -21,7 +21,6 @@ def match(cls, inventory): # if 'enable' in check['keys_data']: # fabric_netflow_status = cls.safeget(inventory, netflow_keys) - if inventory.get("vxlan", None): if inventory["vxlan"].get("underlay", None): if inventory["vxlan"].get("underlay").get("multicast", None): From 5382ce2c52624427d3d4ef170cbbcf75ce4321a4 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Wed, 15 Jan 2025 00:14:44 +0000 Subject: [PATCH 047/183] Deploy False for Fabrics --- .../ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 | 2 +- .../common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 | 2 +- .../common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 index 145e840c7..af39712de 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 @@ -2,7 +2,7 @@ {% import 'ndfc_utils.j2' as ndfc_utils with context %} - FABRIC_NAME: {{ vxlan.fabric.name }} FABRIC_TYPE: {{ vxlan.fabric.type }} - DEPLOY: True + DEPLOY: False {# Include NDFC DC VXLAN EVPN General Template #} {% include '/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 index b7ad1e745..c3d190aa3 100644 --- a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 @@ -1,7 +1,7 @@ {# Auto-generated NDFC ISN Base config data structure for fabric {{ vxlan.fabric.name }} #} - FABRIC_NAME: {{ vxlan.fabric.name }} FABRIC_TYPE: ISN - DEPLOY: True + DEPLOY: False {# Include NDFC ISN General Template #} {% include '/ndfc_fabric/isn_fabric/general/isn_fabric_general.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 index ba997f3da..7d4af48ea 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/msd_fabric_base.j2 @@ -1,7 +1,7 @@ {# Auto-generated NDFC MultiSite Domain (MSD) Base config data structure for fabric {{ vxlan.fabric.name }} #} - FABRIC_NAME: {{ vxlan.fabric.name }} FABRIC_TYPE: VXLAN_EVPN_MSD - DEPLOY: True + DEPLOY: False {# Include NDFC DC VXLAN EVPN General Template #} {% include '/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2' %} From 57b7636b01352a8d0eaf67ed5ae91fab758ced09 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Thu, 16 Jan 2025 03:42:41 +0000 Subject: [PATCH 048/183] Refactor for sharing code and simplification --- .../prep_103_topology_switches.py | 2 +- .../prep_104_fabric_overlay.py | 2 +- .../prep_105_topology_interfaces.py | 2 +- .../prep_106_topology_vpc_interfaces.py | 4 +- plugins/action/dtc/get_poap_data.py | 4 +- .../dtc/update_switch_hostname_policy.py | 6 +- plugins/plugin_utils/data_model_keys.py | 22 ++- roles/dtc/common/tasks/common/ndfc_fabric.yml | 77 +++++++++ .../common/tasks/common/ndfc_fabric_links.yml | 83 +++++++++ .../tasks/common/ndfc_interface_access.yml | 83 +++++++++ .../tasks/common/ndfc_interface_access_po.yml | 83 +++++++++ .../tasks/common/ndfc_interface_all.yml | 83 +++++++++ .../tasks/common/ndfc_interface_loopback.yml | 83 +++++++++ .../tasks/common/ndfc_interface_po_routed.yml | 83 +++++++++ .../tasks/common/ndfc_interface_routed.yml | 83 +++++++++ .../tasks/common/ndfc_interface_trunk.yml | 83 +++++++++ .../tasks/common/ndfc_interface_trunk_po.yml | 83 +++++++++ .../tasks/common/ndfc_interface_vpc.yml | 83 +++++++++ .../common/tasks/common/ndfc_inventory.yml | 105 ++++++++++++ .../tasks/common/ndfc_link_vpc_peering.yml | 83 +++++++++ roles/dtc/common/tasks/common/ndfc_policy.yml | 83 +++++++++ .../common/ndfc_sub_interface_routed.yml | 83 +++++++++ .../common/tasks/common/ndfc_vpc_peering.yml | 83 +++++++++ roles/dtc/common/tasks/main.yml | 15 ++ roles/dtc/common/tasks/sub_main_external.yml | 26 +-- roles/dtc/common/tasks/sub_main_isn.yml | 131 ++++++++++++++- roles/dtc/common/tasks/sub_main_msd.yml | 2 +- roles/dtc/common/tasks/sub_main_vxlan.yml | 32 ++-- .../ndfc_interface_access.j2 | 0 .../ndfc_interface_access_po.j2 | 0 .../ndfc_interface_po_routed.j2 | 0 .../ndfc_interface_routed.j2 | 0 .../ndfc_interface_trunk.j2 | 0 .../ndfc_interface_trunk_po.j2 | 0 .../ndfc_interface_vpc.j2 | 0 .../ndfc_loopback_interfaces.j2 | 0 .../ndfc_sub_interface_routed.j2 | 0 roles/dtc/common/templates/ndfc_inventory.j2 | 4 +- .../ndfc_inventory/common/fabric_inventory.j2 | 41 +++++ .../isn_fabric/isn_fabric_inventory.j2 | 6 +- roles/dtc/create/tasks/common/devices.yml | 32 ++++ .../create/tasks/common/devices_discovery.yml | 74 ++++++++ .../tasks/common/devices_preprovision.yml | 79 +++++++++ roles/dtc/create/tasks/common/fabric.yml | 48 ++++++ roles/dtc/create/tasks/common/interfaces.yml | 158 ++++++++++++++++++ roles/dtc/create/tasks/common/links.yml | 82 +++++++++ roles/dtc/create/tasks/common/policies.yml | 55 ++++++ roles/dtc/create/tasks/common/vpc_peering.yml | 68 ++++++++ roles/dtc/create/tasks/external/devices.yml | 4 - roles/dtc/create/tasks/main.yml | 4 +- roles/dtc/create/tasks/sub_main_external.yml | 12 +- roles/dtc/create/tasks/sub_main_isn.yml | 27 ++- roles/dtc/create/tasks/sub_main_msd.yml | 4 +- roles/dtc/create/tasks/sub_main_vxlan.yml | 26 +-- roles/dtc/remove/tasks/common/interfaces.yml | 82 +++++++++ roles/dtc/remove/tasks/common/policy.yml | 72 ++++++++ roles/dtc/remove/tasks/common/switches.yml | 59 +++++++ roles/dtc/remove/tasks/isn/links.yml | 83 +++++++++ roles/dtc/remove/tasks/sub_main_isn.yml | 42 +++-- roles/dtc/remove/tasks/sub_main_vxlan.yml | 8 +- 60 files changed, 2557 insertions(+), 105 deletions(-) create mode 100644 roles/dtc/common/tasks/common/ndfc_fabric.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_fabric_links.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_access.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_access_po.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_all.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_loopback.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_po_routed.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_routed.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_trunk.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_trunk_po.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_interface_vpc.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_inventory.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_policy.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_sub_interface_routed.yml create mode 100644 roles/dtc/common/tasks/common/ndfc_vpc_peering.yml rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_access.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_access_po.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_po_routed.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_routed.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_trunk.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_trunk_po.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_interface_vpc.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_loopback_interfaces.j2 (100%) rename roles/dtc/common/templates/{ => ndfc_interfaces}/ndfc_sub_interface_routed.j2 (100%) create mode 100644 roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 create mode 100644 roles/dtc/create/tasks/common/devices.yml create mode 100644 roles/dtc/create/tasks/common/devices_discovery.yml create mode 100644 roles/dtc/create/tasks/common/devices_preprovision.yml create mode 100644 roles/dtc/create/tasks/common/fabric.yml create mode 100644 roles/dtc/create/tasks/common/interfaces.yml create mode 100644 roles/dtc/create/tasks/common/links.yml create mode 100644 roles/dtc/create/tasks/common/policies.yml create mode 100644 roles/dtc/create/tasks/common/vpc_peering.yml create mode 100644 roles/dtc/remove/tasks/common/interfaces.yml create mode 100644 roles/dtc/remove/tasks/common/policy.yml create mode 100644 roles/dtc/remove/tasks/common/switches.yml create mode 100644 roles/dtc/remove/tasks/isn/links.yml diff --git a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py index 7b9cb1760..5945b6f19 100644 --- a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py +++ b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py @@ -31,7 +31,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MCF']: return self.kwargs['results'] # Loop over all the roles in vxlan.topology.switches.role diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index b7080ecdb..409749c51 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -31,7 +31,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # We don't have switches for Multisite fabrics so need special handling - if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF', 'ISN'): + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF'): switches = [] else: switches = model_data['vxlan']['topology']['switches'] diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index eb6779161..e5aab0735 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -35,7 +35,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MCF']: return self.kwargs['results'] model_data['vxlan']['topology']['interfaces'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py index 531bdf98b..a8c3c0436 100644 --- a/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py @@ -31,8 +31,8 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] - if model_data['vxlan']['fabric']['type'] == 'ISN': - return self.kwargs['results'] + # if model_data['vxlan']['fabric']['type'] == 'ISN': + # return self.kwargs['results'] # Check if vxlan.topology is defined if model_data.get('vxlan').get('topology') is not None: diff --git a/plugins/action/dtc/get_poap_data.py b/plugins/action/dtc/get_poap_data.py index 9042247de..b771cfb2b 100644 --- a/plugins/action/dtc/get_poap_data.py +++ b/plugins/action/dtc/get_poap_data.py @@ -174,8 +174,8 @@ def run(self, tmp=None, task_vars=None): params = {} params['model_data'] = self._task.args["model_data"] - if params['model_data']['vxlan']['fabric']['type'] == 'ISN': - return results + # if params['model_data']['vxlan']['fabric']['type'] == 'ISN': + # return results params['action_plugin'] = self._execute_module params['task_vars'] = task_vars diff --git a/plugins/action/dtc/update_switch_hostname_policy.py b/plugins/action/dtc/update_switch_hostname_policy.py index 6b96bec09..e85c88cd2 100644 --- a/plugins/action/dtc/update_switch_hostname_policy.py +++ b/plugins/action/dtc/update_switch_hostname_policy.py @@ -50,10 +50,10 @@ def run(self, tmp=None, task_vars=None): ) dm_switches = [] - if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN', 'External'): + if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN', 'ISN', 'External'): dm_switches = model_data["vxlan"]["topology"]["switches"] - elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): - dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] + # elif model_data["vxlan"]["fabric"]["type"] in ('ISN'): + # dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"] switch_match = next((item for item in dm_switches if item["serial_number"] == switch_serial_number)) diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 83dfc79fb..161beaf58 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -65,6 +65,21 @@ model_keys['VXLAN_EVPN']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] model_keys['VXLAN_EVPN']['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] +# ISN KEYS + +model_keys['ISN']['topology'] = [root_key, 'topology', 'KEY'] +model_keys['ISN']['topology.edge_connections'] = [root_key, 'topology', 'edge_connections', 'LIST'] +model_keys['ISN']['topology.fabric_links'] = [root_key, 'topology', 'fabric_links', 'LIST'] +model_keys['ISN']['topology.switches'] = [root_key, 'topology', 'switches', 'LIST'] +model_keys['ISN']['topology.switches.freeform'] = [root_key, 'topology', 'switches', 'freeform', 'LIST_INDEX'] +model_keys['ISN']['topology.switches.interfaces'] = [root_key, 'topology', 'switches', 'interfaces', 'LIST_INDEX'] +model_keys['ISN']['topology.vpc_peers'] = [root_key, 'topology', 'vpc_peers', 'LIST'] +# --- +model_keys['ISN']['policy'] = [root_key, 'policy', 'KEY'] +model_keys['ISN']['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] +model_keys['ISN']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] +model_keys['ISN']['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] + # MSD KEYS # --- @@ -77,10 +92,3 @@ model_keys['MSD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] - -# ISN KEYS - -# --- -model_keys['ISN']['multisite.isn'] = [root_key, 'multisite', 'isn', 'KEY'] -model_keys['ISN']['multisite.isn.topology'] = [root_key, 'multisite', 'isn', 'topology', 'KEY'] -model_keys['ISN']['multisite.isn.topology.switches'] = [root_key, 'multisite', 'isn', 'topology', 'switches', 'LIST'] diff --git a/roles/dtc/common/tasks/common/ndfc_fabric.yml b/roles/dtc/common/tasks/common/ndfc_fabric.yml new file mode 100644 index 000000000..02d383b84 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_fabric.yml @@ -0,0 +1,77 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_fabric.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- ansible.builtin.set_fact: + fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/common/ndfc_fabric_links.yml b/roles/dtc/common/tasks/common/ndfc_fabric_links.yml new file mode 100644 index 000000000..6f7a762f9 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_fabric_links.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric_links: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_fabric_links.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Links + ansible.builtin.template: + src: ndfc_fabric_links.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set fabric_links Var default + ansible.builtin.set_fact: + fabric_links: [] + delegate_to: localhost + +- name: Set fabric_links Var + ansible.builtin.set_fact: + fabric_links: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.fabric_links | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric_links: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/common/ndfc_interface_access.yml b/roles/dtc/common/tasks/common/ndfc_interface_access.yml new file mode 100644 index 000000000..8e92dfa74 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_access.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_access: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_access.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_access.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_access Var + ansible.builtin.set_fact: + interface_access: [] + delegate_to: localhost + +- name: Set interface_access Var + ansible.builtin.set_fact: + interface_access: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_access: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/common/ndfc_interface_access_po.yml new file mode 100644 index 000000000..c0283359d --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_access_po.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_access_po: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_access_po.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_access_po.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_access_po Var + ansible.builtin.set_fact: + interface_access_po: [] + delegate_to: localhost + +- name: Set interface_access_po Var + ansible.builtin.set_fact: + interface_access_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_access_po: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_all.yml b/roles/dtc/common/tasks/common/ndfc_interface_all.yml new file mode 100644 index 000000000..b4850efb5 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_all.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interfaces: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_all.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Set interface_all Var + ansible.builtin.set_fact: + interface_all: [] + delegate_to: localhost + +- name: Set interface_all Var + ansible.builtin.set_fact: + interface_all: "{{ interface_access + interface_access_po + interface_trunk + interface_trunk_po + interface_routed + interface_po_routed + sub_interface_routed + interface_vpc + int_loopback_config }}" + when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 + delegate_to: localhost + +- name: Save interface_all + ansible.builtin.copy: + content: "{{ interface_all | to_nice_yaml }}" + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interfaces: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/common/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/common/ndfc_interface_loopback.yml new file mode 100644 index 000000000..205aea48f --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_loopback.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_loopback: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_loopback_interfaces.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Loopback Interfaces List From Template + ansible.builtin.template: + src: ndfc_interfaces/ndfc_loopback_interfaces.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set int_loopback_config Var + ansible.builtin.set_fact: + int_loopback_config: [] + delegate_to: localhost + +- name: Set int_loopback_config Var + ansible.builtin.set_fact: + int_loopback_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_loopback: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/common/ndfc_interface_po_routed.yml new file mode 100644 index 000000000..65cdc6d38 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_po_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_po_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_po_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface Po + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_po_routed.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_po_routed Var default + ansible.builtin.set_fact: + interface_po_routed: [] + delegate_to: localhost + +- name: Set interface_po_routed Var + ansible.builtin.set_fact: + interface_po_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_po_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_routed.yml b/roles/dtc/common/tasks/common/ndfc_interface_routed.yml new file mode 100644 index 000000000..3b0a6c484 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_routed.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_routed Var default + ansible.builtin.set_fact: + interface_routed: [] + delegate_to: localhost + +- name: Set interface_routed Var + ansible.builtin.set_fact: + interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/common/ndfc_interface_trunk.yml new file mode 100644 index 000000000..d174d1aac --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_trunk.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_trunk: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_trunk.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_trunk.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_trunk Var + ansible.builtin.set_fact: + interface_trunk: [] + delegate_to: localhost + +- name: Set interface_trunk Var + ansible.builtin.set_fact: + interface_trunk: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_trunk: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/common/ndfc_interface_trunk_po.yml new file mode 100644 index 000000000..c5c86764b --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_trunk_po.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_trunk_po: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_trunk_po.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_trunk_po.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_trunk_po Var + ansible.builtin.set_fact: + interface_trunk_po: [] + delegate_to: localhost + +- name: Set interface_trunk_po Var + ansible.builtin.set_fact: + interface_trunk_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_trunk_po: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/common/ndfc_interface_vpc.yml new file mode 100644 index 000000000..3249fdc3e --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_interface_vpc.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_interface_vpc: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_interface_vpc.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build VPC interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_vpc.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set interface_vpc Var default + ansible.builtin.set_fact: + interface_vpc: [] + delegate_to: localhost + +- name: Set interface_vpc Var + ansible.builtin.set_fact: + interface_vpc: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_interface_vpc: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_inventory.yml b/roles/dtc/common/tasks/common/ndfc_inventory.yml new file mode 100644 index 000000000..c530ce8bf --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_inventory.yml @@ -0,0 +1,105 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Get POAP Data From POAP Enabled Devices + cisco.nac_dc_vxlan.dtc.get_poap_data: + model_data: "{{ MD_Extended }}" + register: poap_data + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_inventory: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_inventory.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Set Path For Inventory File Lookup + ansible.builtin.set_fact: + inv_file_path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Build Fabric Switch Inventory List From Template + ansible.builtin.template: + src: ndfc_inventory.j2 + dest: "{{ inv_file_path }}" + delegate_to: localhost + +- name: Create Empty inv_config Var + ansible.builtin.set_fact: + inv_config: [] + delegate_to: localhost + +- name: Set inv_config Var + ansible.builtin.set_fact: + inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: (MD_Extended.vxlan.topology.switches | default([])) | length > 0 + delegate_to: localhost + +- name: Retrieve NDFC Device Username and Password from Group Vars and update inv_config + cisco.nac_dc_vxlan.common.get_credentials: + inv_list: "{{ inv_config }}" + register: updated_inv_config + no_log: true + +- name: Credential Retrieval Failed + ansible.builtin.fail: + msg: "{{ updated_inv_config }}" + when: updated_inv_config['retrieve_failed'] + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_inventory: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml new file mode 100644 index 000000000..7a70e9825 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_link_vpc_peering: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_link_vpc_peering.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Links for VPC Peering + ansible.builtin.template: + src: ndfc_links_vpc_peering.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set link_vpc_peering Var default + ansible.builtin.set_fact: + link_vpc_peering: [] + delegate_to: localhost + +- name: Set link_vpc_peering Var + ansible.builtin.set_fact: + link_vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.vpc_peers | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_link_vpc_peering: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_policy.yml b/roles/dtc/common/tasks/common/ndfc_policy.yml new file mode 100644 index 000000000..9f965bbe3 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_policy.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_policy: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_policy.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + # TODO: Add capability to overridde path variable above for CI/CD pipeline + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Policy List From Template + ansible.builtin.template: + src: ndfc_policy.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set policy_config Var + ansible.builtin.set_fact: + policy_config: [] + delegate_to: localhost + +- ansible.builtin.set_fact: + policy_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: (MD_Extended.vxlan.policy.policies | default([])) | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_policy: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/common/ndfc_sub_interface_routed.yml new file mode 100644 index 000000000..6f0fd1c6c --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_sub_interface_routed.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_sub_interface_routed: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_sub_interface_routed.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build sub_interface + ansible.builtin.template: + src: ndfc_interfaces/ndfc_sub_interface_routed.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set sub_interface_routed Var default + ansible.builtin.set_fact: + sub_interface_routed: [] + delegate_to: localhost + +- name: Set sub_interface_routed Var + ansible.builtin.set_fact: + sub_interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_sub_interface_routed: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/common/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/common/ndfc_vpc_peering.yml new file mode 100644 index 000000000..08fa07fc3 --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_vpc_peering.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_vpc_peering: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_vpc_peering.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build vPC Peering + ansible.builtin.template: + src: ndfc_vpc_peering.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set vpc_peering Var default + ansible.builtin.set_fact: + vpc_peering: [] + delegate_to: localhost + +- name: Set vpc_peering Var + ansible.builtin.set_fact: + vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.vpc_peers | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_vpc_peering: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 185c9eb3e..d91eefba0 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -37,6 +37,7 @@ changes_detected_interface_routed: false changes_detected_interface_trunk_po: false changes_detected_interface_trunk: false + changes_detected_interface_vpc: false changes_detected_inventory: false changes_detected_link_vpc_peering: false changes_detected_networks: false @@ -46,7 +47,21 @@ changes_detected_vrfs: false vars_common_isn: changes_detected_fabric: false + changes_detected_fabric_links: false + changes_detected_interface_access_po: false + changes_detected_interface_access: false + changes_detected_interfaces: false + changes_detected_interface_loopback: false + changes_detected_interface_po_routed: false + changes_detected_interface_routed: false + changes_detected_interface_trunk_po: false + changes_detected_interface_trunk: false + changes_detected_interface_vpc: false changes_detected_inventory: false + changes_detected_networks: false + changes_detected_policy: false + changes_detected_sub_interface_routed: false + changes_detected_vrfs: false vars_common_msd: changes_detected_fabric: false changes_detected_vrfs: false diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index 1be6a5e68..4790a2e6a 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -43,47 +43,47 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: external/ndfc_fabric.yml + ansible.builtin.import_tasks: common/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch Inventory List From Template - ansible.builtin.import_tasks: external/ndfc_inventory.yml + ansible.builtin.import_tasks: common/ndfc_inventory.yml - name: Build NDFC Interface Access Po List From Template - ansible.builtin.import_tasks: external/ndfc_interface_access_po.yml + ansible.builtin.import_tasks: common/ndfc_interface_access_po.yml - name: Build NDFC Interface Access List From Template - ansible.builtin.import_tasks: external/ndfc_interface_access.yml + ansible.builtin.import_tasks: common/ndfc_interface_access.yml - name: Build NDFC Interface Loopback List From Template - ansible.builtin.import_tasks: external/ndfc_interface_loopback.yml + ansible.builtin.import_tasks: common/ndfc_interface_loopback.yml - name: Build NDFC Interface Po Routed List From Template - ansible.builtin.import_tasks: external/ndfc_interface_po_routed.yml + ansible.builtin.import_tasks: common/ndfc_interface_po_routed.yml - name: Build NDFC Interface Routed List From Template - ansible.builtin.import_tasks: external/ndfc_interface_routed.yml + ansible.builtin.import_tasks: common/ndfc_interface_routed.yml - name: Build NDFC Interface Trunk Po List From Template - ansible.builtin.import_tasks: external/ndfc_interface_trunk_po.yml + ansible.builtin.import_tasks: common/ndfc_interface_trunk_po.yml - name: Build NDFC Interface Trunk List From Template - ansible.builtin.import_tasks: external/ndfc_interface_trunk.yml + ansible.builtin.import_tasks: common/ndfc_interface_trunk.yml - name: Build NDFC Interface VPC List From Template - ansible.builtin.import_tasks: external/ndfc_interface_vpc.yml + ansible.builtin.import_tasks: common/ndfc_interface_vpc.yml - name: Build NDFC Sub Interface Routed List From Template - ansible.builtin.import_tasks: external/ndfc_sub_interface_routed.yml + ansible.builtin.import_tasks: common/ndfc_sub_interface_routed.yml - name: Build NDFC Interface all List From Template - ansible.builtin.import_tasks: external/ndfc_interface_all.yml + ansible.builtin.import_tasks: common/ndfc_interface_all.yml - name: Build NDFC Policy List From Template - ansible.builtin.import_tasks: external/ndfc_policy.yml + ansible.builtin.import_tasks: common/ndfc_policy.yml # -------------------------------------------------------------------- diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml index f7e2c8201..70ae5a7d8 100644 --- a/roles/dtc/common/tasks/sub_main_isn.yml +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -43,14 +43,98 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: isn/ndfc_fabric.yml + ansible.builtin.import_tasks: common/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch Inventory List From Template - ansible.builtin.import_tasks: isn/ndfc_inventory.yml + ansible.builtin.import_tasks: common/ndfc_inventory.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Loopback Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Loopback Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_loopback.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Access Port-Channel Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Access Port-Channel Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_access_po.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Trunk Port-Channel Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Trunk Port-Channel Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_trunk_po.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Interface Routed List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Interface Routed List From Template + ansible.builtin.import_tasks: common/ndfc_interface_routed.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Sub-Interface Routed List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Sub-Interface Routed List From Template + ansible.builtin.import_tasks: common/ndfc_sub_interface_routed.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Routed Port-Channel Interface List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Routed Port-Channel Interface List From Template + ansible.builtin.import_tasks: common/ndfc_interface_po_routed.yml + +# -------------------------------------------------------------------- +# Build Trunk Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build Trunk Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_trunk.yml + +# -------------------------------------------------------------------- +# Build Access Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build Access Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_access.yml + +# -------------------------------------------------------------------- +# Build Fabric interface VPC List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric interface VPC List From Template + ansible.builtin.import_tasks: common/ndfc_interface_vpc.yml + +# -------------------------------------------------------------------- +# Build Fabric interface all List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric interface All List From Template + ansible.builtin.import_tasks: common/ndfc_interface_all.yml + +# -------------------------------------------------------------------- +# Build Fabric Policy List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Policy List From Template + ansible.builtin.import_tasks: common/ndfc_policy.yml + +# -------------------------------------------------------------------- +# Build Fabric Links List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Links List From Template + ansible.builtin.import_tasks: common/ndfc_fabric_links.yml # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere @@ -59,18 +143,57 @@ ansible.builtin.set_fact: vars_common_isn: changes_detected_fabric: "{{ changes_detected_fabric }}" + changes_detected_fabric_links: "{{ changes_detected_fabric_links }}" + changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" + changes_detected_interface_access: "{{ changes_detected_interface_access }}" + changes_detected_interfaces: "{{ changes_detected_interfaces }}" + changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" + changes_detected_interface_po_routed: "{{ changes_detected_interface_po_routed }}" + changes_detected_interface_routed: "{{ changes_detected_interface_routed }}" + changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" + changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" + changes_detected_interface_vpc: "{{ changes_detected_interface_vpc }}" changes_detected_inventory: "{{ changes_detected_inventory }}" + changes_detected_policy: "{{ changes_detected_policy }}" + changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" fabric_config: "{{ fabric_config }}" + fabric_links: "{{ fabric_links }}" + interface_access_po: "{{ interface_access_po }}" + interface_access: "{{ interface_access }}" + interface_all: "{{ interface_all }}" + int_loopback_config: "{{ int_loopback_config }}" + interface_po_routed: "{{ interface_po_routed }}" + interface_routed: "{{ interface_routed }}" + interface_trunk_po: "{{ interface_trunk_po }}" + interface_trunk: "{{ interface_trunk }}" + interface_vpc: "{{ interface_vpc }}" inv_config: "{{ inv_config }}" poap_data: "{{ poap_data }}" + policy_config: "{{ policy_config }}" + sub_interface_routed: "{{ sub_interface_routed }}" updated_inv_config: "{{ updated_inv_config }}" - name: Run Diff Flags ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Fabric Changes Detected - [ {{ vars_common_isn.changes_detected_fabric }} ]" - - "+ Inventory Changes Detected - [ {{ vars_common_isn.changes_detected_inventory }} ]" + - "+ Fabric Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric }} ]" + - "+ Inventory Changes Detected - [ {{ vars_common_vxlan.changes_detected_inventory }} ]" + - "+ ----- Interfaces -----" + - "+ Interface vPC Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_vpc }} ]" + - "+ Interface Access Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access }} ]" + - "+ Interface Access PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_access_po }} ]" + - "+ Interface Loopback Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_loopback }} ]" + - "+ Interface PO Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_po_routed }} ]" + - "+ Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_routed }} ]" + - "+ Interface Trunk Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_trunk }} ]" + - "+ Interface Trunk PO Changes Detected - [ {{ vars_common_vxlan.changes_detected_interface_trunk_po }} ]" + - "+ Sub Interface Routed Changes Detected - [ {{ vars_common_vxlan.changes_detected_sub_interface_routed }} ]" + - "+ ----- All Interfaces -----" + - "+ All Interfaces Changes Detected - [ {{ vars_common_vxlan.changes_detected_interfaces }} ]" + - "+ ----- All Interfaces -----" + - "+ Policy Changes Detected - [ {{ vars_common_vxlan.changes_detected_policy }} ]" + - "+ Fabric Links Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric_links }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 1499db169..5ea45ee70 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -43,7 +43,7 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: msd/ndfc_fabric.yml + ansible.builtin.import_tasks: common/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Child Fabric Inventory List From Template diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index 1bc3e4bab..c12a059ce 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -43,28 +43,28 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: vxlan/ndfc_fabric.yml + ansible.builtin.import_tasks: common/ndfc_fabric.yml # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch Inventory List From Template - ansible.builtin.import_tasks: vxlan/ndfc_inventory.yml + ansible.builtin.import_tasks: common/ndfc_inventory.yml # -------------------------------------------------------------------- # Build Fabric intra links for vpc peering From Template # -------------------------------------------------------------------- - name: Build Intra Fabric Links From Template - ansible.builtin.import_tasks: vxlan/ndfc_link_vpc_peering.yml + ansible.builtin.import_tasks: common/ndfc_link_vpc_peering.yml # -------------------------------------------------------------------- # Build vPC Peering parameter List From Template # -------------------------------------------------------------------- - name: Build vPC Peering Parameters - ansible.builtin.import_tasks: vxlan/ndfc_vpc_peering.yml + ansible.builtin.import_tasks: common/ndfc_vpc_peering.yml # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template @@ -85,84 +85,84 @@ # -------------------------------------------------------------------- - name: Build NDFC Fabric Loopback Interfaces List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_loopback.yml + ansible.builtin.import_tasks: common/ndfc_interface_loopback.yml # -------------------------------------------------------------------- # Build NDFC Fabric Access Port-Channel Interfaces List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Access Port-Channel Interfaces List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_access_po.yml + ansible.builtin.import_tasks: common/ndfc_interface_access_po.yml # -------------------------------------------------------------------- # Build NDFC Fabric Trunk Port-Channel Interfaces List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Trunk Port-Channel Interfaces List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_trunk_po.yml + ansible.builtin.import_tasks: common/ndfc_interface_trunk_po.yml # -------------------------------------------------------------------- # Build NDFC Fabric Interface Routed List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Interface Routed List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_routed.yml + ansible.builtin.import_tasks: common/ndfc_interface_routed.yml # -------------------------------------------------------------------- # Build NDFC Fabric Sub-Interface Routed List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Sub-Interface Routed List From Template - ansible.builtin.import_tasks: vxlan/ndfc_sub_interface_routed.yml + ansible.builtin.import_tasks: common/ndfc_sub_interface_routed.yml # -------------------------------------------------------------------- # Build NDFC Fabric Routed Port-Channel Interface List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Routed Port-Channel Interface List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_po_routed.yml + ansible.builtin.import_tasks: common/ndfc_interface_po_routed.yml # -------------------------------------------------------------------- # Build Trunk Interfaces List From Template # -------------------------------------------------------------------- - name: Build Trunk Interfaces List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_trunk.yml + ansible.builtin.import_tasks: common/ndfc_interface_trunk.yml # -------------------------------------------------------------------- # Build Access Interfaces List From Template # -------------------------------------------------------------------- - name: Build Access Interfaces List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_access.yml + ansible.builtin.import_tasks: common/ndfc_interface_access.yml # -------------------------------------------------------------------- # Build Fabric interface VPC List From Template # -------------------------------------------------------------------- - name: Build Fabric interface VPC List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_vpc.yml + ansible.builtin.import_tasks: common/ndfc_interface_vpc.yml # -------------------------------------------------------------------- # Build Fabric interface all List From Template # -------------------------------------------------------------------- - name: Build Fabric interface All List From Template - ansible.builtin.import_tasks: vxlan/ndfc_interface_all.yml + ansible.builtin.import_tasks: common/ndfc_interface_all.yml # -------------------------------------------------------------------- # Build Fabric Policy List From Template # -------------------------------------------------------------------- - name: Build Fabric Policy List From Template - ansible.builtin.import_tasks: vxlan/ndfc_policy.yml + ansible.builtin.import_tasks: common/ndfc_policy.yml # -------------------------------------------------------------------- # Build Fabric Links List From Template # -------------------------------------------------------------------- - name: Build Fabric Links List From Template - ansible.builtin.import_tasks: vxlan/ndfc_fabric_links.yml + ansible.builtin.import_tasks: common/ndfc_fabric_links.yml # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere diff --git a/roles/dtc/common/templates/ndfc_interface_access.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_access.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_access_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_access_po.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_po_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_po_routed.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_routed.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_trunk.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_trunk.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_trunk_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_trunk_po.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 diff --git a/roles/dtc/common/templates/ndfc_interface_vpc.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_interface_vpc.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 diff --git a/roles/dtc/common/templates/ndfc_loopback_interfaces.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_loopback_interfaces.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 diff --git a/roles/dtc/common/templates/ndfc_sub_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_sub_interface_routed.j2 rename to roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 209148aea..1c11ea394 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -6,7 +6,7 @@ {% if vxlan.fabric.type == 'VXLAN_EVPN' %} {# Include NDFC DC VXLAN EVPN Base Template #} -{% include '/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2' %} +{% include '/ndfc_inventory/common/fabric_inventory.j2' %} {% elif vxlan.fabric.type == 'ISN'%} @@ -16,7 +16,7 @@ {% elif vxlan.fabric.type == 'External' %} {# Include NDFC DC External Template #} -{% include '/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2' %} +{% include '/ndfc_inventory/common/fabric_inventory.j2' %} {# Supported fabric types are: DC VXLAN EVPN and ISN #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 new file mode 100644 index 000000000..6e300cc7a --- /dev/null +++ b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 @@ -0,0 +1,41 @@ +{# Auto-generated NDFC DC VXLAN EVPN Inventory config data structure for fabric {{ vxlan.fabric.name }} #} +{% set poap_data = poap_data['poap_data'] %} +{% for switch in MD_Extended.vxlan.topology.switches %} +{% if switch.management.management_ipv4_address is defined %} +- seed_ip: {{ switch['management']['management_ipv4_address'] }} +{% elif switch.management.management_ipv6_address is defined %} +- seed_ip: {{ switch['management']['management_ipv6_address'] }} +{% endif %} + auth_proto: {{ MD['vxlan']['global']['auth_proto'] | default(defaults.vxlan.global.auth_proto) }} + user_name: PLACE_HOLDER_USERNAME + password: PLACE_HOLDER_PASSWORD + max_hops: 0 # this is the default value as it is not defined into the data model + role: {{ switch['role'] }} + preserve_config: false +{% if MD_Extended.vxlan.global.bootstrap is defined %} +{% if MD_Extended.vxlan.global.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.global.bootstrap.enable_bootstrap %} +{% if switch.poap is defined and switch.poap.bootstrap %} +{% if poap_data[switch['serial_number']] is defined %} +{% set pdata = poap_data[switch['serial_number']] %} + poap: + - serial_number: {{ switch['serial_number'] }} + hostname: {{ switch['name'] }} + model: {{ pdata['model'] }} + version: {{ pdata['version'] }} + config_data: + modulesModel: {{ pdata['modulesModel'] }} + gateway: {{ pdata['gateway'] }} +{% elif switch['poap']['preprovision'] is defined %} + poap: + - preprovision_serial: {{ switch['poap']['preprovision']['serial_number'] }} + model: {{ switch['poap']['preprovision']['model'] }} + version: {{ switch['poap']['preprovision']['version'] }} + config_data: + modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} + gateway: {{ switch['management']['default_gateway_v4'] }} + hostname: {{ switch['name'] }} +{% endif %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 index dbe6eb183..6f3c0c183 100644 --- a/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/isn_fabric/isn_fabric_inventory.j2 @@ -1,6 +1,6 @@ {# Auto-generated NDFC ISN Inventory config data structure for fabric {{ vxlan.fabric.name }} #} {% set poap_data = poap_data['poap_data'] %} -{% for switch in MD_Extended.vxlan.multisite.isn.topology.switches %} +{% for switch in MD_Extended.vxlan.topology.switches %} {% if switch.management.management_ipv4_address is defined %} - seed_ip: {{ switch['management']['management_ipv4_address'] }} {% elif switch.management.management_ipv6_address is defined %} @@ -13,8 +13,8 @@ max_hops: 0 # this is the default value as it is not defined into the data model role: core_router preserve_config: true -{% if MD_Extended.vxlan.multisite.isn.bootstrap is defined %} -{% if MD_Extended.vxlan.multisite.isn.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.multisite.isn.bootstrap.enable_bootstrap %} +{% if MD_Extended.vxlan.topology.bootstrap is defined %} +{% if MD_Extended.vxlan.topology.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.topology.bootstrap.enable_bootstrap %} {% if switch.poap is defined and switch.poap.bootstrap %} {% if poap_data[switch['serial_number']] is defined %} {% set pdata = poap_data[switch['serial_number']] %} diff --git a/roles/dtc/create/tasks/common/devices.yml b/roles/dtc/create/tasks/common/devices.yml new file mode 100644 index 000000000..4700c8631 --- /dev/null +++ b/roles/dtc/create/tasks/common/devices.yml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Devices Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage Devices Discovery + ansible.builtin.import_tasks: devices_discovery.yml diff --git a/roles/dtc/create/tasks/common/devices_discovery.yml b/roles/dtc/create/tasks/common/devices_discovery.yml new file mode 100644 index 000000000..a745277e7 --- /dev/null +++ b/roles/dtc/create/tasks/common/devices_discovery.yml @@ -0,0 +1,74 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} + cisco.dcnm.dcnm_inventory: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ vars_common_local.updated_inv_config['updated_inv_list'] }}" + deploy: false + save: true + state: merged + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: MD_Extended.vxlan.topology.switches | length > 0 + +- name: Create List of Switch Serial Numbers from Data Model + ansible.builtin.set_fact: + md_serial_numbers: "{{ MD_Extended.vxlan.topology.switches | map(attribute='serial_number') | list }}" + delegate_to: localhost + +- name: Build Switch Hostname Policy Payload from Data Model Update + cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy: + model_data: "{{ MD_Extended }}" + switch_serial_numbers: "{{ md_serial_numbers }}" + template_name: host_11_1 + register: results +# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + +- name: Join List of Switch Hostname Policy IDs from NDFC + ansible.builtin.set_fact: + policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}" + when: results.policy_update | length > 0 + delegate_to: localhost + +- name: Update Switch Hostname Policy in NDFC + cisco.dcnm.dcnm_rest: + method: PUT + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" + json_data: "{{ results.policy_update.values() | list | to_json }}" + when: results.policy_update | length > 0 \ No newline at end of file diff --git a/roles/dtc/create/tasks/common/devices_preprovision.yml b/roles/dtc/create/tasks/common/devices_preprovision.yml new file mode 100644 index 000000000..add6d8a86 --- /dev/null +++ b/roles/dtc/create/tasks/common/devices_preprovision.yml @@ -0,0 +1,79 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +# This is just a placeholder example and is not currently enabled as part of +# the solution workflow. The module calls below represent a pre-provision +# workflow and how the dcnm_inventory module can be used to pre-provision +# a switch. + + tasks: + - name: Pre-provision switch Configuration + cisco.dcnm.dcnm_inventory: + fabric: nac-ndfc1 + state: merged # Only 2 options supported merged/query for poap config + config: + # All the values below are mandatory if poap configuration is being done - state is merged + - seed_ip: 192.168.9.14 + user_name: admin + password: cisco.123 + role: border + poap: + - preprovision_serial: 9Y0K4YPFFFF + model: N9K-C9300v + version: 9.3(7) + hostname: netascode-leaf3 + # image_policy: "prepro_image_policy" + config_data: + modulesModel: [N9K-X9364v, N9K-vSUP] + gateway: 192.168.9.1/24 + vars: + ansible_command_timeout: 1000 + ansible_connect_timeout: 1000 + + # Note: Calling the module in this way will switch out the fake + # serial number with the actual switch serial number and also + # poap the switch if it's in poap mode and appears in the NDFC + # poap list. + - name: Pre-provision switch Configuration + cisco.dcnm.dcnm_inventory: + fabric: nac-ndfc1 + state: merged # Only 2 options supported merged/query for poap config + config: + # All the values below are mandatory if poap configuration is being done - state is merged + - seed_ip: 192.168.9.14 + user_name: admin + password: cisco.123 + role: border + poap: + - preprovision_serial: 9Y0K4YPFFFF + serial_number: 9Y0K4YPFV64 + vars: + ansible_command_timeout: 1000 + ansible_connect_timeout: 1000 + + # preprovision: + # serial: 9Y0K4YPFFFF + # model: N9K-C9300v + # version: 9.4(8) + # modulesModel: [N9K-X9364v, N9K-vSUP] + # gateway: 10.15.9.1/24 # Add netmask to management key diff --git a/roles/dtc/create/tasks/common/fabric.yml b/roles/dtc/create/tasks/common/fabric.yml new file mode 100644 index 000000000..384c22e1f --- /dev/null +++ b/roles/dtc/create/tasks/common/fabric.yml @@ -0,0 +1,48 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Manage Fabric Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC + cisco.dcnm.dcnm_fabric: + state: merged + config: "{{ vars_common_local.fabric_config }}" diff --git a/roles/dtc/create/tasks/common/interfaces.yml b/roles/dtc/create/tasks/common/interfaces.yml new file mode 100644 index 000000000..1d378d151 --- /dev/null +++ b/roles/dtc/create/tasks/common/interfaces.yml @@ -0,0 +1,158 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Manage Fabric Interfaces Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage Interface Access Portchannel Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Access Portchannel Interface + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_access_po }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Trunk Portchannel Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Trunk Portchannel Interface + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_trunk_po }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 + +# -------------------------------------------------------------------- +# Manage Sub-interface Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Sub-interface Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.sub_interface_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 + +# -------------------------------------------------------------------- +# Manage interface Port-Channel Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Port-Channel Routed + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_po_routed }}" + when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 + +# -------------------------------------------------------------------- +# Manage interface Loopback Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage NDFC Fabric Loopback + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.int_loopback_config }}" + when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 + + # -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + +# -------------------------------------------------------------------- +# Manage interface vPC Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage NDFC Fabric vPCs + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_vpc }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 + +## Will discuss with team and switchover to the below code and remove the above code +# # -------------------------------------------------------------------- +# # Manage Interface All Configuration on NDFC +# # -------------------------------------------------------------------- + +# - name: Manage Interface All +# cisco.dcnm.dcnm_interface: +# fabric: "{{ MD_Extended.vxlan.fabric.name }}" +# state: replaced +# config: "{{ vars_common_local.interface_all }}" +# vars: +# ansible_command_timeout: 3000 +# ansible_connect_timeout: 3000 +# when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 +# delegate_to: localhost diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml new file mode 100644 index 000000000..e50000144 --- /dev/null +++ b/roles/dtc/create/tasks/common/links.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Manage Fabric Intra Fabric Links Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric Links {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Query Links - with Src & Dst Fabric + cisco.dcnm.dcnm_links: + state: query # choose from [merged, replaced, deleted, query] + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: + - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric + register: result_links + +- name: Create empty result List + ansible.builtin.set_fact: + required_links: [] + +- name: Create a list of links that already exist + cisco.nac_dc_vxlan.dtc.existing_links_check: + existing_links: "{{ result_links.response }}" + fabric_links: "{{ vars_common_local.fabric_links }}" + register: not_required_links + when: result_links.response is defined + +# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest +- name: Set not_required_links if result_links.response is not defined + ansible.builtin.set_fact: + not_required_links: [] + when: result_links.response is not defined + +- name: remove unwanted links from required links input + ansible.builtin.set_fact: + required_links: "{{ vars_common_local.fabric_links | difference(not_required_links['not_required_links']) }}" +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Fabric Links + cisco.dcnm.dcnm_links: + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ required_links }}" + deploy: false + state: merged + register: manage_fabric_links_result diff --git a/roles/dtc/create/tasks/common/policies.yml b/roles/dtc/create/tasks/common/policies.yml new file mode 100644 index 000000000..d41f057ce --- /dev/null +++ b/roles/dtc/create/tasks/common/policies.yml @@ -0,0 +1,55 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Manage Policies Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Policies Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Fabric Policies + cisco.dcnm.dcnm_policy: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + use_desc_as_key: true + config: "{{ vars_common_local.policy_config }}" + deploy: false + state: merged + register: manage_policies_result diff --git a/roles/dtc/create/tasks/common/vpc_peering.yml b/roles/dtc/create/tasks/common/vpc_peering.yml new file mode 100644 index 000000000..93c80bbab --- /dev/null +++ b/roles/dtc/create/tasks/common/vpc_peering.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- name: Manage Fabric vPC Peers Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric vPC Peers {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage Intra Fabric Links Configuration on NDFC (prepare links for vpc peering) +# -------------------------------------------------------------------- + +- name: Manage Intra Fabric Links for vpc peering + cisco.dcnm.dcnm_links: + state: replaced + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ vars_common_local.link_vpc_peering }}" + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: link_vpc_peering|length != 0 + +# -------------------------------------------------------------------- +# Manage vPC Peering +# -------------------------------------------------------------------- + +- name: Manage vPC Peering + cisco.dcnm.dcnm_vpc_pair: + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + deploy: false + state: replaced + config: "{{ vars_common_local.vpc_peering }}" diff --git a/roles/dtc/create/tasks/external/devices.yml b/roles/dtc/create/tasks/external/devices.yml index 352b2a88a..4700c8631 100644 --- a/roles/dtc/create/tasks/external/devices.yml +++ b/roles/dtc/create/tasks/external/devices.yml @@ -30,7 +30,3 @@ - name: Manage Devices Discovery ansible.builtin.import_tasks: devices_discovery.yml - -# TODO: Enable This Capability -# - name: Add Devices POAP -# ansible.builtin.import_tasks: devices_poap.yml diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index 20b72ddce..b75ad0da3 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -39,7 +39,9 @@ when: > (MD_Extended.vxlan.fabric.type == 'ISN') and (vars_common_isn.changes_detected_fabric) or - (vars_common_isn.changes_detected_inventory) + (vars_common_isn.changes_detected_inventory) or + (vars_common_isn.changes_detected_interfaces) or + (vars_common_isn.changes_detected_policy) - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 78ba9baa9..f4f499f60 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -41,22 +41,22 @@ - vars_common_external.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" -- name: Manage NDFC Fabric Switches - ansible.builtin.import_tasks: external/devices.yml +- name: Manage NDFC External Fabric Switches + ansible.builtin.import_tasks: common/devices.yml when: - MD_Extended.vxlan.topology.switches | length > 0 - vars_common_external.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" -- name: Manage NDFC Fabric Interfaces - ansible.builtin.import_tasks: external/interfaces.yml +- name: Manage NDFC External Fabric Interfaces + ansible.builtin.import_tasks: common/interfaces.yml when: - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - vars_common_external.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" -- name: Manage NDFC Fabric Policies - ansible.builtin.import_tasks: external/policies.yml +- name: Manage NDFC External Fabric Policies + ansible.builtin.import_tasks: common/policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - vars_common_external.changes_detected_policy diff --git a/roles/dtc/create/tasks/sub_main_isn.yml b/roles/dtc/create/tasks/sub_main_isn.yml index b67d04de7..8b55e6716 100644 --- a/roles/dtc/create/tasks/sub_main_isn.yml +++ b/roles/dtc/create/tasks/sub_main_isn.yml @@ -33,7 +33,7 @@ tags: "{{ nac_tags.create }}" - name: Create NDFC ISN Fabric - ansible.builtin.import_tasks: isn/fabric.yml + ansible.builtin.import_tasks: common/fabric.yml when: - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "ISN" @@ -41,8 +41,29 @@ tags: "{{ nac_tags.create_fabric }}" - name: Manage NDFC ISN Fabric Switches - ansible.builtin.import_tasks: isn/devices.yml + ansible.builtin.import_tasks: common/devices.yml when: - - MD_Extended.vxlan.multisite.isn.topology.switches | length > 0 + - MD_Extended.vxlan.topology.switches | length > 0 - vars_common_isn.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" + +- name: Manage NDFC ISN Fabric Interfaces + ansible.builtin.import_tasks: common/interfaces.yml + when: + - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) + - vars_common_isn.changes_detected_interfaces + tags: "{{ nac_tags.create_interfaces }}" + +- name: Manage NDFC ISN Fabric Intra Links + ansible.builtin.import_tasks: common/links.yml + when: + - MD_Extended.vxlan.topology.fabric_links | length > 0 + - vars_common_isn.changes_detected_fabric_links + tags: "{{ nac_tags.create_links }}" + +- name: Manage NDFC ISN Fabric Policies + ansible.builtin.import_tasks: common/policies.yml + when: + - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) + - vars_common_isn.changes_detected_policy + tags: "{{ nac_tags.create_policy }}" diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 4111180dd..6f7f29573 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -33,7 +33,7 @@ tags: "{{ nac_tags.create }}" - name: Create NDFC MSD Fabric - ansible.builtin.import_tasks: msd/fabric.yml + ansible.builtin.import_tasks: common/fabric.yml when: - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "MSD" @@ -45,7 +45,7 @@ when: - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 -- name: Manage NDFC Fabric VRFs and Networks +- name: Manage NDFC MSD Fabric VRFs and Networks ansible.builtin.import_tasks: msd/vrfs_networks.yml when: - MD_Extended.vxlan.multisite.overlay is defined diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index aa4bc319f..35f4992b5 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -32,8 +32,8 @@ - ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" tags: "{{ nac_tags.create }}" -- name: Create NDFC Fabric - ansible.builtin.import_tasks: vxlan/fabric.yml +- name: Create NDFC VXLAN Fabric + ansible.builtin.import_tasks: common/fabric.yml when: - MD_Extended.vxlan.fabric.name is defined - MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" @@ -41,28 +41,28 @@ - vars_common_vxlan.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" -- name: Manage NDFC Fabric Switches - ansible.builtin.import_tasks: vxlan/devices.yml +- name: Manage NDFC VXLAN Fabric Switches + ansible.builtin.import_tasks: common/devices.yml when: - MD_Extended.vxlan.topology.switches | length > 0 - vars_common_vxlan.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" -- name: Manage VPC Peering - ansible.builtin.import_tasks: vxlan/vpc_peering.yml +- name: Manage NDFC VXLAN VPC Peering + ansible.builtin.import_tasks: common/vpc_peering.yml when: - MD_Extended.vxlan.topology.vpc_peers | length > 0 - vars_common_vxlan.changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" -- name: Manage NDFC Fabric Interfaces - ansible.builtin.import_tasks: vxlan/interfaces.yml +- name: Manage NDFC VXLAN Fabric Interfaces + ansible.builtin.import_tasks: common/interfaces.yml when: - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - vars_common_vxlan.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" -- name: Manage NDFC Fabric VRFs and Networks +- name: Manage NDFC VXLAN Fabric VRFs and Networks ansible.builtin.import_tasks: vxlan/vrfs_networks.yml when: - MD_Extended.vxlan.overlay is defined @@ -70,15 +70,15 @@ - vars_common_vxlan.changes_detected_vrfs or vars_common_vxlan.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" -- name: Manage NDFC Fabric Intra Links - ansible.builtin.import_tasks: vxlan/links.yml +- name: Manage NDFC VXLAN Fabric Intra Links + ansible.builtin.import_tasks: common/links.yml when: - MD_Extended.vxlan.topology.fabric_links | length > 0 - vars_common_vxlan.changes_detected_fabric_links tags: "{{ nac_tags.create_links }}" -- name: Manage NDFC Fabric Policies - ansible.builtin.import_tasks: vxlan/policies.yml +- name: Manage NDFC VXLAN Fabric Policies + ansible.builtin.import_tasks: common/policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - vars_common_vxlan.changes_detected_policy diff --git a/roles/dtc/remove/tasks/common/interfaces.yml b/roles/dtc/remove/tasks/common/interfaces.yml new file mode 100644 index 000000000..3f375ce6a --- /dev/null +++ b/roles/dtc/remove/tasks/common/interfaces.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Interfaces. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) + +- name: Remove Unmanaged Fabric Interfaces + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: overridden + config: "{{ vars_common_local.interface_all }}" + # deploy: false + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + register: int_data + when: + - switch_list.response.DATA | length > 0 + - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) + +# - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} after removing or defaulting interfaces +# cisco.dcnm.dcnm_rest: +# method: POST +# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" +# when: +# - int_data.changed is true +# - switch_list.response.DATA | length > 0 +# - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) + +# - name: Deploy for Fabric {{ MD_Extended.vxlan.fabric.name }} after removing or defaulting interfaces +# cisco.dcnm.dcnm_rest: +# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy?forceShowRun=false" +# method: POST +# vars: +# ansible_command_timeout: 3000 +# ansible_connect_timeout: 3000 +# when: +# - int_data.changed is true +# - switch_list.response.DATA | length > 0 +# - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "-------------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric Interfaces task because interface_delete_mode flag is set to False +" + - "-------------------------------------------------------------------------------------------------------------------" + when: not ((interface_delete_mode is defined) and (interface_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/common/policy.yml b/roles/dtc/remove/tasks/common/policy.yml new file mode 100644 index 000000000..09dbc73bd --- /dev/null +++ b/roles/dtc/remove/tasks/common/policy.yml @@ -0,0 +1,72 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- block: + - ansible.builtin.debug: msg="Removing Unmanaged Fabric Policy From Switches. This could take several minutes..." + + - name: Create List of Switch Serial Numbers from NDFC Switch List + ansible.builtin.set_fact: + switch_serial_numbers: "{{ switch_list.response.DATA | map(attribute='serialNumber') | list }}" + delegate_to: localhost + + - name: Build Unmanaged Fabric Policy Payload + cisco.nac_dc_vxlan.dtc.unmanaged_policy: + switch_serial_numbers: "{{ switch_serial_numbers }}" + model_data: "{{ MD_Extended }}" + register: unmanaged_policy_config + # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + + - name: Remove Unmanaged NDFC Fabric Policy + cisco.dcnm.dcnm_policy: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + use_desc_as_key: true + config: "{{ unmanaged_policy_config.unmanaged_policies }}" + deploy: true + state: deleted + when: unmanaged_policy_config.unmanaged_policies | length > 0 + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - switch_list.response.DATA | length > 0 + - (policy_delete_mode is defined) and (policy_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "--------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Policy from Switches task because policy_delete_mode flag is set to False +" + - "--------------------------------------------------------------------------------------------------------" + when: not ((policy_delete_mode is defined) and (policy_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/common/switches.yml b/roles/dtc/remove/tasks/common/switches.yml new file mode 100644 index 000000000..1ed8f50a5 --- /dev/null +++ b/roles/dtc/remove/tasks/common/switches.yml @@ -0,0 +1,59 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Switches. This could take several minutes..." + when: + - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) + +- name: Remove Unmanaged NDFC Fabric Devices + cisco.dcnm.dcnm_inventory: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ vars_common_local.updated_inv_config['updated_inv_list'] }}" + deploy: true + save: true + state: overridden + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "----------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove NDFC Fabric Devices task because inventory_delete_mode flag is set to False +" + - "----------------------------------------------------------------------------------------------------------" + when: not ((inventory_delete_mode is defined) and (inventory_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/isn/links.yml b/roles/dtc/remove/tasks/isn/links.yml new file mode 100644 index 000000000..9a396cc64 --- /dev/null +++ b/roles/dtc/remove/tasks/isn/links.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged vpc peer Links. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (link_vpc_delete_mode is defined) and (link_vpc_delete_mode is true|bool) + +# TBD: Determine if this is needed for ISN +# +# - name: Remove Intra Fabric Links for vPC Peering +# cisco.dcnm.dcnm_links: +# state: replaced +# src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" +# config: "{{ vars_common_vxlan.link_vpc_peering }}" +# vars: +# ansible_command_timeout: 3000 +# ansible_connect_timeout: 3000 +# when: +# - switch_list.response.DATA | length > 0 +# - (link_vpc_delete_mode is defined) and (link_vpc_delete_mode is true|bool) + + +- block: + - ansible.builtin.debug: msg="Removing Unmanaged Fabric Links. This could take several minutes..." + + - name: Query Links - with Src & Dst Fabric + cisco.dcnm.dcnm_links: + state: query # choose from [merged, replaced, deleted, query] + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: + - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric + register: result_links + + - name: Create empty result List + ansible.builtin.set_fact: + required_links: [] + + - name: Create a list of links that already exist + cisco.nac_dc_vxlan.dtc.links_filter_and_remove: + existing_links: "{{ result_links.response }}" + fabric_links: "{{ vars_common_vxlan.fabric_links }}" + register: links_to_be_removed + when: result_links.response is defined + + # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + - name: Set not_required_links if result_links.response is not defined + ansible.builtin.set_fact: + links_to_be_removed: [] + when: result_links.response is not defined + # -------------------------------------------------------------------- + # Manage VRF Configuration on NDFC + # -------------------------------------------------------------------- + - name: Manage NDFC Fabric Links + cisco.dcnm.dcnm_links: + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ links_to_be_removed['links_to_be_removed'] }}" + deploy: false + state: deleted + register: delete_fabric_links_result + + when: + - switch_list.response.DATA | length > 0 + - (link_fabric_delete_mode is defined) and (link_fabric_delete_mode is true|bool) diff --git a/roles/dtc/remove/tasks/sub_main_isn.yml b/roles/dtc/remove/tasks/sub_main_isn.yml index 960c13512..90e71ea6d 100644 --- a/roles/dtc/remove/tasks/sub_main_isn.yml +++ b/roles/dtc/remove/tasks/sub_main_isn.yml @@ -32,23 +32,33 @@ - ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" tags: "{{ nac_tags.remove }}" -# TODO: May need this to remove Policy in the future for ISN -# lines 36 - 48 -# - name: Get List of Fabric Switches from NDFC -# cisco.dcnm.dcnm_rest: -# method: GET -# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" -# register: switch_list -# tags: "{{ nac_tags.remove }}" - -# - name: Remove Fabric Policy -# ansible.builtin.import_tasks: vxlan/policy.yml -# tags: "{{ nac_tags.remove_policy }}" -# when: -# - vars_common_vxlan.changes_detected_policy +- name: Get List of Fabric Switches from NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" + register: switch_list + tags: "{{ nac_tags.remove }}" + +- name: Remove Fabric Policy + ansible.builtin.import_tasks: common/policy.yml + tags: "{{ nac_tags.remove_policy }}" + when: + - vars_common_isn.changes_detected_policy + +- name: Remove Fabric Interfaces + ansible.builtin.import_tasks: common/interfaces.yml + tags: "{{ nac_tags.remove_interfaces }}" + when: + - vars_common_isn.changes_detected_interfaces + +- name: Remove Fabric Links + ansible.builtin.import_tasks: isn/links.yml + tags: "{{ nac_tags.remove_links }}" + when: + - vars_common_isn.changes_detected_fabric_links - name: Remove Fabric Switches - ansible.builtin.import_tasks: isn/switches.yml + ansible.builtin.import_tasks: common/switches.yml tags: "{{ nac_tags.remove_switches }}" when: - - vars_common_isn.changes_detected_inventory + - vars_common_isn.changes_detected_inventory \ No newline at end of file diff --git a/roles/dtc/remove/tasks/sub_main_vxlan.yml b/roles/dtc/remove/tasks/sub_main_vxlan.yml index 0842dce8c..cee3be034 100644 --- a/roles/dtc/remove/tasks/sub_main_vxlan.yml +++ b/roles/dtc/remove/tasks/sub_main_vxlan.yml @@ -40,13 +40,13 @@ tags: "{{ nac_tags.remove }}" - name: Remove Fabric Policy - ansible.builtin.import_tasks: vxlan/policy.yml + ansible.builtin.import_tasks: common/policy.yml tags: "{{ nac_tags.remove_policy }}" when: - vars_common_vxlan.changes_detected_policy - name: Remove Fabric Interfaces - ansible.builtin.import_tasks: vxlan/interfaces.yml + ansible.builtin.import_tasks: common/interfaces.yml tags: "{{ nac_tags.remove_interfaces }}" when: - vars_common_vxlan.changes_detected_interfaces @@ -67,7 +67,7 @@ ansible.builtin.import_tasks: vxlan/links.yml tags: "{{ nac_tags.remove_links }}" when: - - vars_common_vxlan.changes_detected_link_vpc_peering + - vars_common_vxlan.changes_detected_fabric_links - name: Remove Fabric vPC Peering ansible.builtin.import_tasks: vxlan/vpc_peers.yml @@ -76,7 +76,7 @@ - vars_common_vxlan.changes_detected_vpc_peering - name: Remove Fabric Switches - ansible.builtin.import_tasks: vxlan/switches.yml + ansible.builtin.import_tasks: common/switches.yml tags: "{{ nac_tags.remove_switches }}" when: - vars_common_vxlan.changes_detected_inventory From 7d7a39fb8a51fcd0c2f8a3ebaa7a1e88dc268664 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Thu, 16 Jan 2025 16:41:16 +0000 Subject: [PATCH 049/183] Refactoring and Multisite VRF and Network Removal Flag --- README.md | 12 +- roles/common_global/defaults/main.yml | 2 + roles/dtc/common/tasks/isn/ndfc_fabric.yml | 77 ---------- roles/dtc/common/tasks/isn/ndfc_inventory.yml | 105 ------------- .../tasks/isn/task_file_placeholder.yaml} | 15 +- roles/dtc/common/tasks/vxlan/ndfc_fabric.yml | 77 ---------- .../common/tasks/vxlan/ndfc_fabric_links.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_access.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_access_po.yml | 83 ---------- .../common/tasks/vxlan/ndfc_interface_all.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_loopback.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_po_routed.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_routed.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_trunk.yml | 83 ---------- .../tasks/vxlan/ndfc_interface_trunk_po.yml | 83 ---------- .../common/tasks/vxlan/ndfc_interface_vpc.yml | 83 ---------- .../dtc/common/tasks/vxlan/ndfc_inventory.yml | 105 ------------- .../tasks/vxlan/ndfc_link_vpc_peering.yml | 83 ---------- roles/dtc/common/tasks/vxlan/ndfc_policy.yml | 83 ---------- .../tasks/vxlan/ndfc_sub_interface_routed.yml | 83 ---------- .../common/tasks/vxlan/ndfc_vpc_peering.yml | 83 ---------- .../create/tasks/isn/devices_discovery.yml | 60 -------- ...{fabric.yml => task_file_placeholder.yaml} | 17 +-- roles/dtc/create/tasks/msd/fabric.yml | 34 ----- roles/dtc/create/tasks/vxlan/devices.yml | 36 ----- .../create/tasks/vxlan/devices_discovery.yml | 60 -------- .../tasks/vxlan/devices_preprovision.yml | 79 ---------- roles/dtc/create/tasks/vxlan/fabric.yml | 34 ----- roles/dtc/create/tasks/vxlan/interfaces.yml | 144 ------------------ roles/dtc/create/tasks/vxlan/links.yml | 68 --------- roles/dtc/create/tasks/vxlan/policies.yml | 41 ----- roles/dtc/create/tasks/vxlan/vpc_peering.yml | 54 ------- roles/dtc/remove/tasks/isn/switches.yml | 45 ------ roles/dtc/remove/tasks/msd/networks.yml | 8 +- roles/dtc/remove/tasks/msd/vrfs.yml | 12 +- roles/dtc/remove/tasks/vxlan/interfaces.yml | 68 --------- roles/dtc/remove/tasks/vxlan/policy.yml | 58 ------- roles/dtc/remove/tasks/vxlan/switches.yml | 45 ------ 38 files changed, 28 insertions(+), 2390 deletions(-) delete mode 100644 roles/dtc/common/tasks/isn/ndfc_fabric.yml delete mode 100644 roles/dtc/common/tasks/isn/ndfc_inventory.yml rename roles/dtc/{create/tasks/isn/devices.yml => common/tasks/isn/task_file_placeholder.yaml} (74%) delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_fabric.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_inventory.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_policy.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml delete mode 100644 roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml delete mode 100644 roles/dtc/create/tasks/isn/devices_discovery.yml rename roles/dtc/create/tasks/isn/{fabric.yml => task_file_placeholder.yaml} (71%) delete mode 100644 roles/dtc/create/tasks/msd/fabric.yml delete mode 100644 roles/dtc/create/tasks/vxlan/devices.yml delete mode 100644 roles/dtc/create/tasks/vxlan/devices_discovery.yml delete mode 100644 roles/dtc/create/tasks/vxlan/devices_preprovision.yml delete mode 100644 roles/dtc/create/tasks/vxlan/fabric.yml delete mode 100644 roles/dtc/create/tasks/vxlan/interfaces.yml delete mode 100644 roles/dtc/create/tasks/vxlan/links.yml delete mode 100644 roles/dtc/create/tasks/vxlan/policies.yml delete mode 100644 roles/dtc/create/tasks/vxlan/vpc_peering.yml delete mode 100644 roles/dtc/remove/tasks/isn/switches.yml delete mode 100644 roles/dtc/remove/tasks/vxlan/interfaces.yml delete mode 100644 roles/dtc/remove/tasks/vxlan/policy.yml delete mode 100644 roles/dtc/remove/tasks/vxlan/switches.yml diff --git a/README.md b/README.md index 0ebfd59e1..7a64c63c1 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false link_vpc_delete_mode: false +multisite_network_delete_mode: false +multisite_vrf_delete_mode: false network_delete_mode: false policy_delete_mode: false vpc_delete_mode: false @@ -78,15 +80,17 @@ The following control variables are available in this collection. | Variable | Description | Default Value | | -------- | ------- | ------- | +| `child_fabric_delete_mode` | Remove child fabric from MSD|MCF fabric as part of the remove role | `false` | | `force_run_all` | Force all roles in the collection to run | `false` | | `interface_delete_mode` | Remove interface state as part of the remove role | `false` | -| `network_delete_mode` | Remove network state as part of the remove role | `false` | -| `vrf_delete_mode` | Remove vrf state as part of the remove role | `false` | | `inventory_delete_mode` | Remove inventory state as part of the remove role | `false` | | `link_vpc_delete_mode` | Remove vpc link state as part of the remove role | `false` | -| `vpc_delete_mode` | Remove vpc pair state as part of the remove role | `false` | +| `multisite_network_delete_mode` | Remove network state as part of the remove role for multisite (MSD and MCF) fabrics | `false` | +| `multisite_vrf_delete_mode` | Remove vrf state as part of the remove role for multisite (MSD and MCF) fabrics | `false` | +| `network_delete_mode` | Remove network state as part of the remove role | `false` | | `policy_delete_mode` | Remove policy state as part of the remove role | `false` | -| `child_fabric_delete_mode` | Remove child fabric from MSD|MCF fabric as part of the remove role | `false` | +| `vrf_delete_mode` | Remove vrf state as part of the remove role | `false` | +| `vpc_delete_mode` | Remove vpc pair state as part of the remove role | `false` | These variables are described in more detail in different sections of this document. diff --git a/roles/common_global/defaults/main.yml b/roles/common_global/defaults/main.yml index d4bcfe4ef..9a3e4ebc7 100644 --- a/roles/common_global/defaults/main.yml +++ b/roles/common_global/defaults/main.yml @@ -38,6 +38,8 @@ interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false link_vpc_delete_mode: false +multisite_network_delete_mode: false +multisite_vrf_delete_mode: false network_delete_mode: false policy_delete_mode: false vpc_delete_mode: false diff --git a/roles/dtc/common/tasks/isn/ndfc_fabric.yml b/roles/dtc/common/tasks/isn/ndfc_fabric.yml deleted file mode 100644 index 02d383b84..000000000 --- a/roles/dtc/common/tasks/isn/ndfc_fabric.yml +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_fabric: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_fabric.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - # TODO: Add capability to overridde path variable above for CI/CD pipeline - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Fabric Creation Parameters From Template - ansible.builtin.template: - src: ndfc_fabric.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_fabric: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/isn/ndfc_inventory.yml b/roles/dtc/common/tasks/isn/ndfc_inventory.yml deleted file mode 100644 index c4d37aa69..000000000 --- a/roles/dtc/common/tasks/isn/ndfc_inventory.yml +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Get POAP Data From POAP Enabled Devices - cisco.nac_dc_vxlan.dtc.get_poap_data: - model_data: "{{ MD_Extended }}" - register: poap_data - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_inventory: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_inventory.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Set Path For Inventory File Lookup - ansible.builtin.set_fact: - inv_file_path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Build Fabric Switch Inventory List From Template - ansible.builtin.template: - src: ndfc_inventory.j2 - dest: "{{ inv_file_path }}" - delegate_to: localhost - -- name: Create Empty inv_config Var - ansible.builtin.set_fact: - inv_config: [] - delegate_to: localhost - -- name: Set inv_config Var - ansible.builtin.set_fact: - inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: (MD_Extended.vxlan.multisite.isn.topology.switches | default([])) | length > 0 - delegate_to: localhost - -- name: Retrieve NDFC Device Username and Password from Group Vars and update inv_config - cisco.nac_dc_vxlan.common.get_credentials: - inv_list: "{{ inv_config }}" - register: updated_inv_config - no_log: true - -- name: Credential Retrieval Failed - ansible.builtin.fail: - msg: "{{ updated_inv_config }}" - when: updated_inv_config['retrieve_failed'] - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_inventory: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/create/tasks/isn/devices.yml b/roles/dtc/common/tasks/isn/task_file_placeholder.yaml similarity index 74% rename from roles/dtc/create/tasks/isn/devices.yml rename to roles/dtc/common/tasks/isn/task_file_placeholder.yaml index 4700c8631..2d2c07a71 100644 --- a/roles/dtc/create/tasks/isn/devices.yml +++ b/roles/dtc/common/tasks/isn/task_file_placeholder.yaml @@ -19,14 +19,7 @@ # # SPDX-License-Identifier: MIT ---- - -- name: Manage Devices Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Manage Devices Discovery - ansible.builtin.import_tasks: devices_discovery.yml +# This is a placeholder file for future expansion of ISN fabric type +# capabilities if needed. +# +# Tasks in this file are intended to override tasks under common \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml deleted file mode 100644 index 02d383b84..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_fabric.yml +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_fabric: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_fabric.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - # TODO: Add capability to overridde path variable above for CI/CD pipeline - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Fabric Creation Parameters From Template - ansible.builtin.template: - src: ndfc_fabric.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- ansible.builtin.set_fact: - fabric_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_fabric: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml b/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml deleted file mode 100644 index 6f7a762f9..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_fabric_links.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_fabric_links: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_fabric_links.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Fabric Links - ansible.builtin.template: - src: ndfc_fabric_links.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set fabric_links Var default - ansible.builtin.set_fact: - fabric_links: [] - delegate_to: localhost - -- name: Set fabric_links Var - ansible.builtin.set_fact: - fabric_links: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.fabric_links | length > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_fabric_links: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml deleted file mode 100644 index 8b146321b..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_access: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_access.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface - ansible.builtin.template: - src: ndfc_interface_access.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_access Var - ansible.builtin.set_fact: - interface_access: [] - delegate_to: localhost - -- name: Set interface_access Var - ansible.builtin.set_fact: - interface_access: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_access: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml deleted file mode 100644 index 702e4b444..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_access_po.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_access_po: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_access_po.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface - ansible.builtin.template: - src: ndfc_interface_access_po.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_access_po Var - ansible.builtin.set_fact: - interface_access_po: [] - delegate_to: localhost - -- name: Set interface_access_po Var - ansible.builtin.set_fact: - interface_access_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_access_po: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml deleted file mode 100644 index b4850efb5..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_all.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interfaces: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_all.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Set interface_all Var - ansible.builtin.set_fact: - interface_all: [] - delegate_to: localhost - -- name: Set interface_all Var - ansible.builtin.set_fact: - interface_all: "{{ interface_access + interface_access_po + interface_trunk + interface_trunk_po + interface_routed + interface_po_routed + sub_interface_routed + interface_vpc + int_loopback_config }}" - when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 - delegate_to: localhost - -- name: Save interface_all - ansible.builtin.copy: - content: "{{ interface_all | to_nice_yaml }}" - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interfaces: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml deleted file mode 100644 index 0de48d66a..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_loopback.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_loopback: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_loopback_interfaces.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Loopback Interfaces List From Template - ansible.builtin.template: - src: ndfc_loopback_interfaces.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set int_loopback_config Var - ansible.builtin.set_fact: - int_loopback_config: [] - delegate_to: localhost - -- name: Set int_loopback_config Var - ansible.builtin.set_fact: - int_loopback_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_loopback: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml deleted file mode 100644 index 5573b8c02..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_po_routed.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_po_routed: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_po_routed.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface Po - ansible.builtin.template: - src: ndfc_interface_po_routed.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_po_routed Var default - ansible.builtin.set_fact: - interface_po_routed: [] - delegate_to: localhost - -- name: Set interface_po_routed Var - ansible.builtin.set_fact: - interface_po_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_po_routed: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml deleted file mode 100644 index 14a6a9922..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_routed.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_routed: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_routed.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface - ansible.builtin.template: - src: ndfc_interface_routed.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_routed Var default - ansible.builtin.set_fact: - interface_routed: [] - delegate_to: localhost - -- name: Set interface_routed Var - ansible.builtin.set_fact: - interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_routed: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml deleted file mode 100644 index 5cb9a4084..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_trunk: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_trunk.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface - ansible.builtin.template: - src: ndfc_interface_trunk.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_trunk Var - ansible.builtin.set_fact: - interface_trunk: [] - delegate_to: localhost - -- name: Set interface_trunk Var - ansible.builtin.set_fact: - interface_trunk: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_trunk: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml deleted file mode 100644 index 2e155dc7c..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_trunk_po.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_trunk_po: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_trunk_po.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Interface - ansible.builtin.template: - src: ndfc_interface_trunk_po.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_trunk_po Var - ansible.builtin.set_fact: - interface_trunk_po: [] - delegate_to: localhost - -- name: Set interface_trunk_po Var - ansible.builtin.set_fact: - interface_trunk_po: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_trunk_po: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml b/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml deleted file mode 100644 index d8c264f15..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_interface_vpc.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_interface_vpc: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_interface_vpc.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build VPC interface - ansible.builtin.template: - src: ndfc_interface_vpc.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set interface_vpc Var default - ansible.builtin.set_fact: - interface_vpc: [] - delegate_to: localhost - -- name: Set interface_vpc Var - ansible.builtin.set_fact: - interface_vpc: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_interface_vpc: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml b/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml deleted file mode 100644 index c530ce8bf..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_inventory.yml +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Get POAP Data From POAP Enabled Devices - cisco.nac_dc_vxlan.dtc.get_poap_data: - model_data: "{{ MD_Extended }}" - register: poap_data - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_inventory: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_inventory.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Set Path For Inventory File Lookup - ansible.builtin.set_fact: - inv_file_path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Build Fabric Switch Inventory List From Template - ansible.builtin.template: - src: ndfc_inventory.j2 - dest: "{{ inv_file_path }}" - delegate_to: localhost - -- name: Create Empty inv_config Var - ansible.builtin.set_fact: - inv_config: [] - delegate_to: localhost - -- name: Set inv_config Var - ansible.builtin.set_fact: - inv_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: (MD_Extended.vxlan.topology.switches | default([])) | length > 0 - delegate_to: localhost - -- name: Retrieve NDFC Device Username and Password from Group Vars and update inv_config - cisco.nac_dc_vxlan.common.get_credentials: - inv_list: "{{ inv_config }}" - register: updated_inv_config - no_log: true - -- name: Credential Retrieval Failed - ansible.builtin.fail: - msg: "{{ updated_inv_config }}" - when: updated_inv_config['retrieve_failed'] - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_inventory: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml deleted file mode 100644 index 7a70e9825..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_link_vpc_peering.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_link_vpc_peering: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_link_vpc_peering.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Links for VPC Peering - ansible.builtin.template: - src: ndfc_links_vpc_peering.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set link_vpc_peering Var default - ansible.builtin.set_fact: - link_vpc_peering: [] - delegate_to: localhost - -- name: Set link_vpc_peering Var - ansible.builtin.set_fact: - link_vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.vpc_peers | length > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_link_vpc_peering: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml b/roles/dtc/common/tasks/vxlan/ndfc_policy.yml deleted file mode 100644 index 9f965bbe3..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_policy.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_policy: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_policy.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - # TODO: Add capability to overridde path variable above for CI/CD pipeline - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build Policy List From Template - ansible.builtin.template: - src: ndfc_policy.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set policy_config Var - ansible.builtin.set_fact: - policy_config: [] - delegate_to: localhost - -- ansible.builtin.set_fact: - policy_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: (MD_Extended.vxlan.policy.policies | default([])) | length > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_policy: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml b/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml deleted file mode 100644 index 5446268d7..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_sub_interface_routed.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_sub_interface_routed: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_sub_interface_routed.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build sub_interface - ansible.builtin.template: - src: ndfc_sub_interface_routed.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set sub_interface_routed Var default - ansible.builtin.set_fact: - sub_interface_routed: [] - delegate_to: localhost - -- name: Set sub_interface_routed Var - ansible.builtin.set_fact: - sub_interface_routed: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_sub_interface_routed: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml deleted file mode 100644 index 08fa07fc3..000000000 --- a/roles/dtc/common/tasks/vxlan/ndfc_vpc_peering.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Initialize changes_detected Var - ansible.builtin.set_fact: - changes_detected_vpc_peering: false - delegate_to: localhost - -- name: Set file_name Var - ansible.builtin.set_fact: - file_name: "ndfc_vpc_peering.yml" - delegate_to: localhost - -- name: Stat Previous File If It Exists - ansible.builtin.stat: - path: "{{ path_name }}{{ file_name }}" - register: data_file_previous - delegate_to: localhost - -- name: Backup Previous Data File If It Exists - ansible.builtin.copy: - src: "{{ path_name }}{{ file_name }}" - dest: "{{ path_name }}{{ file_name }}.old" - when: data_file_previous.stat.exists - -- name: Delete Previous Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - when: data_file_previous.stat.exists - -- name: Build vPC Peering - ansible.builtin.template: - src: ndfc_vpc_peering.j2 - dest: "{{ path_name }}{{ file_name }}" - delegate_to: localhost - -- name: Set vpc_peering Var default - ansible.builtin.set_fact: - vpc_peering: [] - delegate_to: localhost - -- name: Set vpc_peering Var - ansible.builtin.set_fact: - vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" - when: MD_Extended.vxlan.topology.vpc_peers | length > 0 - delegate_to: localhost - -- name: Diff Previous and Current Data Files - cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ path_name }}{{ file_name }}.old" - file_name_current: "{{ path_name }}{{ file_name }}" - register: file_diff_result - delegate_to: localhost - -- name: Set File Change Flag Based on File Diff Result - ansible.builtin.set_fact: - changes_detected_vpc_peering: true - delegate_to: localhost - when: - - file_diff_result.file_data_changed - - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/create/tasks/isn/devices_discovery.yml b/roles/dtc/create/tasks/isn/devices_discovery.yml deleted file mode 100644 index 7374085b0..000000000 --- a/roles/dtc/create/tasks/isn/devices_discovery.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ vars_common_isn.updated_inv_config['updated_inv_list'] }}" - deploy: false - save: true - state: merged - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: MD_Extended.vxlan.multisite.isn.topology.switches | length > 0 - -- name: Create List of Switch Serial Numbers from Data Model - ansible.builtin.set_fact: - md_serial_numbers: "{{ MD_Extended.vxlan.multisite.isn.topology.switches | map(attribute='serial_number') | list }}" - delegate_to: localhost - -- name: Build Switch Hostname Policy Payload from Data Model Update - cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy: - model_data: "{{ MD_Extended }}" - switch_serial_numbers: "{{ md_serial_numbers }}" - template_name: host_11_1 - register: results -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest - -- name: Join List of Switch Hostname Policy IDs from NDFC - ansible.builtin.set_fact: - policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}" - when: results.policy_update | length > 0 - delegate_to: localhost - -- name: Update Switch Hostname Policy in NDFC - cisco.dcnm.dcnm_rest: - method: PUT - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" - json_data: "{{ results.policy_update.values() | list | to_json }}" - when: results.policy_update | length > 0 diff --git a/roles/dtc/create/tasks/isn/fabric.yml b/roles/dtc/create/tasks/isn/task_file_placeholder.yaml similarity index 71% rename from roles/dtc/create/tasks/isn/fabric.yml rename to roles/dtc/create/tasks/isn/task_file_placeholder.yaml index 0b17956e5..2d2c07a71 100644 --- a/roles/dtc/create/tasks/isn/fabric.yml +++ b/roles/dtc/create/tasks/isn/task_file_placeholder.yaml @@ -19,16 +19,7 @@ # # SPDX-License-Identifier: MIT ---- - -- name: Manage Fabric Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC - cisco.dcnm.dcnm_fabric: - state: merged - config: "{{ vars_common_isn.fabric_config }}" +# This is a placeholder file for future expansion of ISN fabric type +# capabilities if needed. +# +# Tasks in this file are intended to override tasks under common \ No newline at end of file diff --git a/roles/dtc/create/tasks/msd/fabric.yml b/roles/dtc/create/tasks/msd/fabric.yml deleted file mode 100644 index 7141b3791..000000000 --- a/roles/dtc/create/tasks/msd/fabric.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Fabric Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC - cisco.dcnm.dcnm_fabric: - state: merged - config: "{{ vars_common_msd.fabric_config }}" diff --git a/roles/dtc/create/tasks/vxlan/devices.yml b/roles/dtc/create/tasks/vxlan/devices.yml deleted file mode 100644 index 352b2a88a..000000000 --- a/roles/dtc/create/tasks/vxlan/devices.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Devices Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Devices Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Manage Devices Discovery - ansible.builtin.import_tasks: devices_discovery.yml - -# TODO: Enable This Capability -# - name: Add Devices POAP -# ansible.builtin.import_tasks: devices_poap.yml diff --git a/roles/dtc/create/tasks/vxlan/devices_discovery.yml b/roles/dtc/create/tasks/vxlan/devices_discovery.yml deleted file mode 100644 index dde9eaffb..000000000 --- a/roles/dtc/create/tasks/vxlan/devices_discovery.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Add NDFC Fabric Devices {{ MD_Extended.vxlan.fabric.name }} - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ vars_common_vxlan.updated_inv_config['updated_inv_list'] }}" - deploy: false - save: true - state: merged - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: MD_Extended.vxlan.topology.switches | length > 0 - -- name: Create List of Switch Serial Numbers from Data Model - ansible.builtin.set_fact: - md_serial_numbers: "{{ MD_Extended.vxlan.topology.switches | map(attribute='serial_number') | list }}" - delegate_to: localhost - -- name: Build Switch Hostname Policy Payload from Data Model Update - cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy: - model_data: "{{ MD_Extended }}" - switch_serial_numbers: "{{ md_serial_numbers }}" - template_name: host_11_1 - register: results -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest - -- name: Join List of Switch Hostname Policy IDs from NDFC - ansible.builtin.set_fact: - policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}" - when: results.policy_update | length > 0 - delegate_to: localhost - -- name: Update Switch Hostname Policy in NDFC - cisco.dcnm.dcnm_rest: - method: PUT - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk" - json_data: "{{ results.policy_update.values() | list | to_json }}" - when: results.policy_update | length > 0 \ No newline at end of file diff --git a/roles/dtc/create/tasks/vxlan/devices_preprovision.yml b/roles/dtc/create/tasks/vxlan/devices_preprovision.yml deleted file mode 100644 index add6d8a86..000000000 --- a/roles/dtc/create/tasks/vxlan/devices_preprovision.yml +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -# This is just a placeholder example and is not currently enabled as part of -# the solution workflow. The module calls below represent a pre-provision -# workflow and how the dcnm_inventory module can be used to pre-provision -# a switch. - - tasks: - - name: Pre-provision switch Configuration - cisco.dcnm.dcnm_inventory: - fabric: nac-ndfc1 - state: merged # Only 2 options supported merged/query for poap config - config: - # All the values below are mandatory if poap configuration is being done - state is merged - - seed_ip: 192.168.9.14 - user_name: admin - password: cisco.123 - role: border - poap: - - preprovision_serial: 9Y0K4YPFFFF - model: N9K-C9300v - version: 9.3(7) - hostname: netascode-leaf3 - # image_policy: "prepro_image_policy" - config_data: - modulesModel: [N9K-X9364v, N9K-vSUP] - gateway: 192.168.9.1/24 - vars: - ansible_command_timeout: 1000 - ansible_connect_timeout: 1000 - - # Note: Calling the module in this way will switch out the fake - # serial number with the actual switch serial number and also - # poap the switch if it's in poap mode and appears in the NDFC - # poap list. - - name: Pre-provision switch Configuration - cisco.dcnm.dcnm_inventory: - fabric: nac-ndfc1 - state: merged # Only 2 options supported merged/query for poap config - config: - # All the values below are mandatory if poap configuration is being done - state is merged - - seed_ip: 192.168.9.14 - user_name: admin - password: cisco.123 - role: border - poap: - - preprovision_serial: 9Y0K4YPFFFF - serial_number: 9Y0K4YPFV64 - vars: - ansible_command_timeout: 1000 - ansible_connect_timeout: 1000 - - # preprovision: - # serial: 9Y0K4YPFFFF - # model: N9K-C9300v - # version: 9.4(8) - # modulesModel: [N9K-X9364v, N9K-vSUP] - # gateway: 10.15.9.1/24 # Add netmask to management key diff --git a/roles/dtc/create/tasks/vxlan/fabric.yml b/roles/dtc/create/tasks/vxlan/fabric.yml deleted file mode 100644 index dfb042c99..000000000 --- a/roles/dtc/create/tasks/vxlan/fabric.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Fabric Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Manage fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC - cisco.dcnm.dcnm_fabric: - state: merged - config: "{{ vars_common_vxlan.fabric_config }}" diff --git a/roles/dtc/create/tasks/vxlan/interfaces.yml b/roles/dtc/create/tasks/vxlan/interfaces.yml deleted file mode 100644 index 8b2a7c21d..000000000 --- a/roles/dtc/create/tasks/vxlan/interfaces.yml +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Fabric Interfaces Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -# -------------------------------------------------------------------- -# Manage Interface Access Portchannel Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Access Portchannel Interface - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_access_po }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access_po.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Trunk Portchannel Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Trunk Portchannel Interface - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_trunk_po }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk_po.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Routed - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_routed }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed.count > 0 - -# -------------------------------------------------------------------- -# Manage Sub-interface Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Sub-interface Routed - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.sub_interface_routed }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed_sub.count > 0 - -# -------------------------------------------------------------------- -# Manage interface Port-Channel Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Port-Channel Routed - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_po_routed }}" - when: MD_Extended.vxlan.topology.interfaces.modes.routed_po.count > 0 - -# -------------------------------------------------------------------- -# Manage interface Loopback Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage NDFC Fabric Loopback - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.int_loopback_config }}" - when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - - # -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Access - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - -# -------------------------------------------------------------------- -# Manage interface vPC Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage NDFC Fabric vPCs - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_vxlan.interface_vpc }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 - -## Will discuss with team and switchover to the below code and remove the above code -# # -------------------------------------------------------------------- -# # Manage Interface All Configuration on NDFC -# # -------------------------------------------------------------------- - -# - name: Manage Interface All -# cisco.dcnm.dcnm_interface: -# fabric: "{{ MD_Extended.vxlan.fabric.name }}" -# state: replaced -# config: "{{ vars_common_vxlan.interface_all }}" -# vars: -# ansible_command_timeout: 3000 -# ansible_connect_timeout: 3000 -# when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 -# delegate_to: localhost diff --git a/roles/dtc/create/tasks/vxlan/links.yml b/roles/dtc/create/tasks/vxlan/links.yml deleted file mode 100644 index e292c721a..000000000 --- a/roles/dtc/create/tasks/vxlan/links.yml +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Fabric Intra Fabric Links Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric Links {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -- name: Query Links - with Src & Dst Fabric - cisco.dcnm.dcnm_links: - state: query # choose from [merged, replaced, deleted, query] - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: - - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric - register: result_links - -- name: Create empty result List - ansible.builtin.set_fact: - required_links: [] - -- name: Create a list of links that already exist - cisco.nac_dc_vxlan.dtc.existing_links_check: - existing_links: "{{ result_links.response }}" - fabric_links: "{{ vars_common_vxlan.fabric_links }}" - register: not_required_links - when: result_links.response is defined - -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest -- name: Set not_required_links if result_links.response is not defined - ansible.builtin.set_fact: - not_required_links: [] - when: result_links.response is not defined - -- name: remove unwanted links from required links input - ansible.builtin.set_fact: - required_links: "{{ vars_common_vxlan.fabric_links | difference(not_required_links['not_required_links']) }}" -# -------------------------------------------------------------------- -# Manage VRF Configuration on NDFC -# -------------------------------------------------------------------- -- name: Manage NDFC Fabric Links - cisco.dcnm.dcnm_links: - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ required_links }}" - deploy: false - state: merged - register: manage_fabric_links_result diff --git a/roles/dtc/create/tasks/vxlan/policies.yml b/roles/dtc/create/tasks/vxlan/policies.yml deleted file mode 100644 index d0e660c6e..000000000 --- a/roles/dtc/create/tasks/vxlan/policies.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Policies Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Policies Fabric {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -# -------------------------------------------------------------------- -# Manage VRF Configuration on NDFC -# -------------------------------------------------------------------- -- name: Manage NDFC Fabric Policies - cisco.dcnm.dcnm_policy: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - use_desc_as_key: true - config: "{{ vars_common_vxlan.policy_config }}" - deploy: false - state: merged - register: manage_policies_result diff --git a/roles/dtc/create/tasks/vxlan/vpc_peering.yml b/roles/dtc/create/tasks/vxlan/vpc_peering.yml deleted file mode 100644 index 024483324..000000000 --- a/roles/dtc/create/tasks/vxlan/vpc_peering.yml +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - ---- - -- name: Manage Fabric vPC Peers Entry Point - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage Fabric vPC Peers {{ MD_Extended.vxlan.fabric.name }}" - - "----------------------------------------------------------------" - -# -------------------------------------------------------------------- -# Manage Intra Fabric Links Configuration on NDFC (prepare links for vpc peering) -# -------------------------------------------------------------------- - -- name: Manage Intra Fabric Links for vpc peering - cisco.dcnm.dcnm_links: - state: replaced - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ vars_common_vxlan.link_vpc_peering }}" - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: link_vpc_peering|length != 0 - -# -------------------------------------------------------------------- -# Manage vPC Peering -# -------------------------------------------------------------------- - -- name: Manage vPC Peering - cisco.dcnm.dcnm_vpc_pair: - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - deploy: false - state: replaced - config: "{{ vars_common_vxlan.vpc_peering }}" diff --git a/roles/dtc/remove/tasks/isn/switches.yml b/roles/dtc/remove/tasks/isn/switches.yml deleted file mode 100644 index 8d147f652..000000000 --- a/roles/dtc/remove/tasks/isn/switches.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- ansible.builtin.debug: msg="Removing Unmanaged Fabric Switches. This could take several minutes..." - when: - - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) - -- name: Remove Unmanaged NDFC Fabric Devices - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ vars_common_isn.updated_inv_config['updated_inv_list'] }}" - deploy: true - save: true - state: overridden - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: - - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "----------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove NDFC Fabric Devices task because inventory_delete_mode flag is set to False +" - - "----------------------------------------------------------------------------------------------------------" - when: not ((inventory_delete_mode is defined) and (inventory_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/msd/networks.yml b/roles/dtc/remove/tasks/msd/networks.yml index 98f57ae7c..aba6f8532 100644 --- a/roles/dtc/remove/tasks/msd/networks.yml +++ b/roles/dtc/remove/tasks/msd/networks.yml @@ -23,7 +23,7 @@ - ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." when: - switch_list.response.DATA | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) + - (multisite_network_delete_mode is defined) and (multisite_network_delete_mode is true|bool) - name: Remove Unmanaged Fabric Networks cisco.dcnm.dcnm_network: @@ -35,11 +35,11 @@ ansible_connect_timeout: 3000 when: - switch_list.response.DATA | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) + - (multisite_network_delete_mode is defined) and (multisite_network_delete_mode is true|bool) - ansible.builtin.debug: msg: - "---------------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" + - "+ SKIPPING Remove Unmanaged Fabric Networks task because multisite_network_delete_mode flag is set to False +" - "---------------------------------------------------------------------------------------------------------------" - when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) + when: not ((multisite_network_delete_mode is defined) and (multisite_network_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/msd/vrfs.yml b/roles/dtc/remove/tasks/msd/vrfs.yml index 1de111afe..678303f06 100644 --- a/roles/dtc/remove/tasks/msd/vrfs.yml +++ b/roles/dtc/remove/tasks/msd/vrfs.yml @@ -23,7 +23,7 @@ - ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." when: - switch_list.response.DATA | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + - (multisite_vrf_delete_mode is defined) and (multisite_vrf_delete_mode is true|bool) - name: Remove Unmanaged Fabric VRFs cisco.dcnm.dcnm_vrf: @@ -35,11 +35,11 @@ ansible_connect_timeout: 3000 when: - switch_list.response.DATA | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + - (multisite_vrf_delete_mode is defined) and (multisite_vrf_delete_mode is true|bool) - ansible.builtin.debug: msg: - - "--------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" - - "--------------------------------------------------------------------------------------------------------" - when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) + - "------------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged MultiSite Fabric VRFs task because multisite_vrf_delete_mode flag is set to False +" + - "------------------------------------------------------------------------------------------------------------------" + when: not ((multisite_vrf_delete_mode is defined) and (multisite_vrf_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/vxlan/interfaces.yml b/roles/dtc/remove/tasks/vxlan/interfaces.yml deleted file mode 100644 index cf3611e78..000000000 --- a/roles/dtc/remove/tasks/vxlan/interfaces.yml +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- ansible.builtin.debug: msg="Removing Unmanaged Fabric Interfaces. This could take several minutes..." - when: - - switch_list.response.DATA | length > 0 - - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) - -- name: Remove Unmanaged Fabric Interfaces - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: overridden - config: "{{ vars_common_vxlan.interface_all }}" - # deploy: false - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - register: int_data - when: - - switch_list.response.DATA | length > 0 - - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) - -# - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} after removing or defaulting interfaces -# cisco.dcnm.dcnm_rest: -# method: POST -# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" -# when: -# - int_data.changed is true -# - switch_list.response.DATA | length > 0 -# - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) - -# - name: Deploy for Fabric {{ MD_Extended.vxlan.fabric.name }} after removing or defaulting interfaces -# cisco.dcnm.dcnm_rest: -# path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy?forceShowRun=false" -# method: POST -# vars: -# ansible_command_timeout: 3000 -# ansible_connect_timeout: 3000 -# when: -# - int_data.changed is true -# - switch_list.response.DATA | length > 0 -# - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "-------------------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Fabric Interfaces task because interface_delete_mode flag is set to False +" - - "-------------------------------------------------------------------------------------------------------------------" - when: not ((interface_delete_mode is defined) and (interface_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/vxlan/policy.yml b/roles/dtc/remove/tasks/vxlan/policy.yml deleted file mode 100644 index 26cf28f8a..000000000 --- a/roles/dtc/remove/tasks/vxlan/policy.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- block: - - ansible.builtin.debug: msg="Removing Unmanaged Fabric Policy From Switches. This could take several minutes..." - - - name: Create List of Switch Serial Numbers from NDFC Switch List - ansible.builtin.set_fact: - switch_serial_numbers: "{{ switch_list.response.DATA | map(attribute='serialNumber') | list }}" - delegate_to: localhost - - - name: Build Unmanaged Fabric Policy Payload - cisco.nac_dc_vxlan.dtc.unmanaged_policy: - switch_serial_numbers: "{{ switch_serial_numbers }}" - model_data: "{{ MD_Extended }}" - register: unmanaged_policy_config - # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest - - - name: Remove Unmanaged NDFC Fabric Policy - cisco.dcnm.dcnm_policy: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - use_desc_as_key: true - config: "{{ unmanaged_policy_config.unmanaged_policies }}" - deploy: true - state: deleted - when: unmanaged_policy_config.unmanaged_policies | length > 0 - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: - - switch_list.response.DATA | length > 0 - - (policy_delete_mode is defined) and (policy_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "--------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Policy from Switches task because policy_delete_mode flag is set to False +" - - "--------------------------------------------------------------------------------------------------------" - when: not ((policy_delete_mode is defined) and (policy_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/vxlan/switches.yml b/roles/dtc/remove/tasks/vxlan/switches.yml deleted file mode 100644 index d1105d1c5..000000000 --- a/roles/dtc/remove/tasks/vxlan/switches.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- ansible.builtin.debug: msg="Removing Unmanaged Fabric Switches. This could take several minutes..." - when: - - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) - -- name: Remove Unmanaged NDFC Fabric Devices - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ vars_common_vxlan.updated_inv_config['updated_inv_list'] }}" - deploy: true - save: true - state: overridden - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: - - (inventory_delete_mode is defined) and (inventory_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "----------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove NDFC Fabric Devices task because inventory_delete_mode flag is set to False +" - - "----------------------------------------------------------------------------------------------------------" - when: not ((inventory_delete_mode is defined) and (inventory_delete_mode is true|bool)) From 7193551db171168e17d726d4a66d4a5c2a386d64 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 22 Jan 2025 12:08:39 +0000 Subject: [PATCH 050/183] New changes to support fed fabrics and their creation --- plugins/action/common/nac_dc_validate.py | 6 +- .../common/prepare_plugins/prep_001_fabric.py | 1 + .../prep_103_topology_switches.py | 2 +- .../prep_104_fabric_overlay.py | 4 +- .../prep_105_topology_interfaces.py | 2 +- plugins/plugin_utils/data_model_keys.py | 15 ++- plugins/plugin_utils/helper_functions.py | 8 +- roles/dtc/common/tasks/main.yml | 9 ++ .../common/tasks/mfd/ndfc_get_inventory.yml | 12 +- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 30 ++--- roles/dtc/common/tasks/mfd/ndfc_vrfs.yml | 26 ++-- roles/dtc/common/tasks/sub_main_mfd.yml | 9 +- .../templates/ndfc_attach_networks_fed.j2 | 17 +++ .../ndfc_attach_networks_switches_fed.j2 | 16 +++ ...ndfc_attach_networks_switches_ports_fed.j2 | 50 +++++++ .../common/templates/ndfc_attach_vrfs_fed.j2 | 16 +++ .../ndfc_attach_vrfs_loopbacks_fed.j2 | 20 +++ roles/dtc/common/templates/ndfc_fabric.j2 | 5 + .../mfd_fabric/dci/mfd_fabric_dci.j2 | 6 + .../mfd_fabric/general/mfd_fabric_general.j2 | 11 ++ .../resources/mfd_fabric_resources.j2 | 5 +- .../security/mfd_fabric_security.j2 | 7 +- .../resources/msd_fabric_resources.j2 | 2 +- roles/dtc/create/tasks/main.yml | 26 ++-- roles/dtc/create/tasks/mfd/fabric.yml | 63 +++++++++ roles/dtc/create/tasks/mfd/vrfs_networks.yml | 123 ++++++++++++++++++ roles/dtc/create/tasks/sub_main_mfd.yml | 51 ++++++++ roles/validate/files/defaults.yml | 4 +- 28 files changed, 491 insertions(+), 55 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_attach_networks_fed.j2 create mode 100644 roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 create mode 100644 roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 create mode 100644 roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 create mode 100644 roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 create mode 100644 roles/dtc/create/tasks/mfd/fabric.yml create mode 100644 roles/dtc/create/tasks/mfd/vrfs_networks.yml create mode 100644 roles/dtc/create/tasks/sub_main_mfd.yml diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 712aff519..f606f305e 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -93,7 +93,7 @@ def run(self, tmp=None, task_vars=None): if 'type' in results['data']['vxlan']['fabric']: if results['data']['vxlan']['fabric']['type'] in ('VXLAN_EVPN'): rules_list.append(f'{rules}vxlan/') - elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCF'): + elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MFD'): rules_list.append(f'{rules}multisite/') elif results['data']['vxlan']['fabric']['type'] in ('ISN', 'External'): rules_list.append(f'{rules}isn/') @@ -117,10 +117,10 @@ def run(self, tmp=None, task_vars=None): if results['data']['vxlan']['global']['fabric_type'] in ('VXLAN_EVPN'): rules_list.append(f'{rules}vxlan/') - elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCF'): + elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MFD'): rules_list.append(f'{rules}multisite/') elif results['data']['vxlan']['global']['fabric_type'] in ('ISN', 'External'): - rules_list.append(f'{rules}isn/') + rules_list.append(f'{rules}isn/') else: results['failed'] = True results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['global']['fabric_type']} is not a supported fabric type." diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 847706fd1..22a85b3dc 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -133,6 +133,7 @@ def prepare(self): ) display.deprecated(msg=deprecated_msg, version="1.0.0") model_data['vxlan']['overlay'] = model_data['vxlan']['overlay_services'] + model_data['vxlan']['multisite']['overlay'] = model_data['vxlan']['overlay_services'] del model_data['vxlan']['overlay_services'] parent_keys = ['vxlan', 'multisite', 'overlay'] diff --git a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py index 7b9cb1760..290948b0d 100644 --- a/plugins/action/common/prepare_plugins/prep_103_topology_switches.py +++ b/plugins/action/common/prepare_plugins/prep_103_topology_switches.py @@ -31,7 +31,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MFD']: return self.kwargs['results'] # Loop over all the roles in vxlan.topology.switches.role diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index 412a8611b..3e34cbb8b 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -31,7 +31,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # We don't have switches for Multisite fabrics so need special handling - if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF', 'ISN'): + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MFD', 'ISN'): switches = [] else: switches = model_data['vxlan']['topology']['switches'] @@ -85,7 +85,7 @@ def prepare(self): if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] - if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCF'): + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MFD'): # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into # a structure that is easier to use. vrf_grp_name_list = [] diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index e391161c1..779d97d20 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -35,7 +35,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MCF']: + if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MFD']: return self.kwargs['results'] diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index b5a5711f7..4081401e6 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -28,7 +28,7 @@ root_key = 'vxlan' # Keys here match data model schema # type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') -model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MCF': {}, 'ISN': {}} +model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MFD': {}, 'ISN': {}} # VXLAN_EVPN KEYS @@ -80,6 +80,19 @@ model_keys['MSD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] +# MFD KEYS + +# --- +model_keys['MFD']['multisite'] = [root_key, 'multisite', 'KEY'] +model_keys['MFD']['multisite.child_fabrics'] = [root_key, 'multisite', 'child_fabrics', 'KEY'] +model_keys['MFD']['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] +model_keys['MFD']['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] +model_keys['MFD']['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['MFD']['multisite.overlay.vrf_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'switches', 'LIST_INDEX'] +model_keys['MFD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] +model_keys['MFD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] +model_keys['MFD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] + # ISN KEYS # --- diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index bc632aae7..357af0047 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -24,7 +24,7 @@ # # For example in prepare_serice_model.py we can do the following: # from ..helper_functions import do_something - +import re def data_model_key_check(tested_object, keys): """ @@ -164,3 +164,9 @@ def ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, switch_serial_nu ] return policy_match + +def normalise_int_lists(data): + for interface in data: + if interface.startswith('Ethernet','ethernet','Eth','eth','E','e'): + interface = "Ethernet" + re.split(r'(?=\d)', interface, 1)[1] + return data \ No newline at end of file diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 185c9eb3e..05517933a 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -51,6 +51,10 @@ changes_detected_fabric: false changes_detected_vrfs: false changes_detected_networks: false + vars_common_mfd: + changes_detected_fabric: false + changes_detected_vrfs: false + changes_detected_networks: false vars_common_external: changes_detected_inventory: false changes_detected_fabric: false @@ -83,6 +87,11 @@ tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric.type == 'MSD' +- name: Import Role Tasks for MSD Fabric + ansible.builtin.import_tasks: sub_main_mfd.yml + tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml + when: MD_Extended.vxlan.fabric.type == 'MFD' + - name: Import Role Tasks for MSD Fabric ansible.builtin.import_tasks: sub_main_external.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml diff --git a/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml b/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml index 5e6c563b7..4921d3f1c 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml @@ -24,11 +24,17 @@ - name: Get all the switches in the Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/inventory/switchesByFabric" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.fabric.name }}/inventory/switchesByFabric" register: switch_results delegate_to: "{{ inventory_hostname }}" - + failed_when: false - name: Store switches in the fabric for Federated Fabric ansible.builtin.set_fact: - switches_in_fabric: "{{ switch_results.response.DATA }}" \ No newline at end of file + switches_in_fabric: "{{ switch_results.response.DATA }}" + when: switch_results is defined and switch_results.response.DATA is defined + +- name: Set switches_in_fabric to empty list if no switches are found + ansible.builtin.set_fact: + switches_in_fabric: [] + when: switch_results is not defined or switch_results.response.DATA is not defined \ No newline at end of file diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index ebffc49cb..73562c63e 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -27,32 +27,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_ndfc_fed_attach_networks.yml" + file_name: "ndfc_fed_attach_networks.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous Data File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build Networks Attach List From Template ansible.builtin.template: src: ndfc_attach_networks_fed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Set net_config Var @@ -62,14 +62,14 @@ - name: Set net_config Var ansible.builtin.set_fact: - net_config: "{{ lookup('file', file_name) | from_yaml }}" - when: (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + net_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.overlay.networks | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost @@ -83,8 +83,8 @@ - name: Set file_name Var for switches and port attachments ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_attach_network_switches_ports.yml" - file_name2: "{{ MD.vxlan.global.name }}_attach_network_switches.yml" + file_name: "attach_network_switches_ports.yml" + file_name2: "attach_network_switches.yml" switches: [] networks: [] delegate_to: localhost @@ -92,18 +92,18 @@ - name: Build Network attach list for switches on Federated ansible.builtin.template: src: ndfc_attach_networks_switches_fed.j2 - dest: "{{ role_path }}/files/{{ file_name2 }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Build Network attach list for switches and ports on Federated ansible.builtin.template: src: ndfc_attach_networks_switches_ports_fed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name2 }}" delegate_to: localhost - name: Set network_switches Var ansible.builtin.set_fact: network_switches: "{{ lookup('file', file_name2) | from_yaml }}" network_switches_ports: "{{ lookup('file', file_name) | from_yaml }}" - when: (MD_Extended.vxlan.overlay_services.networks | default([])) | length > 0 + when: (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 delegate_to: localhost diff --git a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml index 0951fa444..aa500ada1 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml @@ -27,32 +27,32 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_fed_attach_vrfs.yml" + file_name: "ndfc_fed_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Backup Previous Data File If It Exists ansible.builtin.copy: - src: "{{ role_path }}/files/{{ file_name }}" - dest: "{{ role_path }}/files/{{ file_name }}.old" + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" when: data_file_previous.stat.exists - name: Delete Previous File If It Exists ansible.builtin.file: state: absent - path: "{{ role_path }}/files/{{ file_name }}" + path: "{{ path_name }}{{ file_name }}" delegate_to: localhost when: data_file_previous.stat.exists - name: Build VRFs Attach List From Template ansible.builtin.template: src: ndfc_attach_vrfs_fed.j2 - dest: "{{ role_path }}/files/{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost - name: Create Empty vrf_config Var @@ -62,14 +62,14 @@ - name: Set vrf_config Var ansible.builtin.set_fact: - vrf_config: "{{ lookup('file', file_name) | from_yaml }}" - when: (MD_Extended.vxlan.overlay_services.vrfs | default([])) | length > 0 + vrf_config: "{{ lookup('file', path_name + file_nam) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 delegate_to: localhost - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: - file_name_previous: "{{ role_path }}/files/{{ file_name }}.old" - file_name_current: "{{ role_path }}/files/{{ file_name }}" + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" register: file_diff_result delegate_to: localhost @@ -83,14 +83,14 @@ - name: Set file_name Var for loopback attachments ansible.builtin.set_fact: - file_name: "{{ MD.vxlan.global.name }}_attach_vrfs_loopbacks.yml" + file_name: "attach_vrfs_loopbacks.yml" delegate_to: localhost - name: Build VRFs Attach List From Template for loopback on Federated ansible.builtin.template: src: ndfc_attach_vrfs_loopbacks_fed.j2 - dest: "{{ role_path }}/files/{{ vrf.name }}_{{ file_name }}" + dest: "{{ path_name }}{{ vrf.name }}_{{ file_name }}" delegate_to: localhost - loop: "{{ MD_Extended.vxlan.overlay_services.vrfs }}" + loop: "{{ MD_Extended.vxlan.multisite.overlay.vrfs }}" loop_control: loop_var: vrf diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml index d3980f976..97b835961 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -27,8 +27,13 @@ # -------------------------------------------------------------------- # Remove all files from the previous run if run_map requires it # -------------------------------------------------------------------- +- name: Set path_name Var + ansible.builtin.set_fact: + path_name: "{{ role_path }}/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/" + delegate_to: localhost + - name: Cleanup Files from Previous Run if run_map requires it - ansible.builtin.include_tasks: cleanup_files.yml + ansible.builtin.import_tasks: cleanup_files.yml when: - not run_map_read_result.diff_run or ((force_run_all is defined) and (force_run_all is true|bool)) @@ -62,7 +67,7 @@ - name: Set facts for missed changes_detected flags for Federated Fabric ansible.builtin.set_fact: - vars_common_msd: + vars_common_mfd: changes_detected_fabric: "{{ changes_detected_fabric | default(false) }}" changes_detected_vrfs: "{{ changes_detected_vrfs }}" changes_detected_networks: "{{ changes_detected_networks }}" diff --git a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 new file mode 100644 index 000000000..bc95a6c60 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 @@ -0,0 +1,17 @@ + +[{% for net in MD_Extended.vxlan.multisite.overlay.networks %} +{ + "networkName": "{{ net['name'] }}", + "networkId":"{{ net['net_id'] }}", + "vrf":"{{ net['vrf_name'] }}", + "networkTemplate":"Default_Network_Universal", + "networkExtensionTemplate":"Default_Network_Extension_Universal", + "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address']}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.overlay_services.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.overlay_services.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.overlay_services.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name']}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", + "fabric":"{{ MD.vxlan.fabric.name }}", + "type":null, + "source":null, + "serviceNetworkTemplate":null, + "displayName":"{{ net['name'] }}" +}{% if not loop.last %},{% endif %} +{% endfor %} +] \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 new file mode 100644 index 000000000..f09fe6277 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 @@ -0,0 +1,16 @@ +{ + {% for attach_group in MD_Extended.vxlan.multisite.overlay.network_attach_groups %} + {% for switch in attach_group['switches']%} + {% for switch_inv in switches_in_fabric%} + {% if switch_inv.logicalName == switch['hostname']%} + {{switches.append(switch_inv.serialNumber)}} + {% endif%} + {% endfor%} + {% endfor%} + {% endfor%} + {% for network in MD_Extended.vxlan.multisite.overlay.networks %} + {{ networks.append(network.name )}} + {% endfor %} + 'networks':'{{ networks | join(",")}}', + 'switches':'{{switches |unique|list | join(",")}}' +} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 new file mode 100644 index 000000000..1d8e11d79 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 @@ -0,0 +1,50 @@ +[ +{% for network in MD_Extended.vxlan.multisite.overlay.networks %} + {% for attach_group in MD_Extended.vxlan.multisite.overlay.network_attach_groups %} + {% if network.network_attach_group == attach_group.name %} + {% for switch in attach_group['switches'] %} + { + 'networkName':'{{ network['name'] }}', + 'switchName': '{{ switch['hostname'] }}', + {% for switch_inv in switches_in_fabric %} + {% if switch_inv.logicalName == switch['hostname'] %} + 'switchIP':'{{ switch_inv.ipAddress }}', + 'switchSN':'{{ switch_inv.serialNumber }}', + 'peerSwitchName':'{{ switch_inv.intentedpeerName }}', + 'fabricName':'{{ switch_inv.fabricName }}', + 'clusterName':'{{ switch_inv.clusterName }}', + 'ndfcIpAddress':'{{ switch_inv.clusterIp }}', + {% if switch.tors is defined %} + {% set torString = '' %} + {% set torPortString = '' %} + {% for tor in switch.tors %} + {% if loop.last %} + {% set torString = torString ~ tor.hostname %} + {% set torPortString = torPortString ~ ' ' ~ tor.hostname ~ '(' ~ tor.ports | join(",") ~ ')' %} + 'allSwitches':'["{{ switch['hostname'] }}","{{ switch_inv.intentedpeerName }}","{{ torString }}"]', + 'ports':'{{ switch.hostname }}({{ switch.ports | join(",") }}){{ torPortString }}', + 'torSwitches':'{{ torString }}' + {% else %} + {% set torPortString = torPortString ~ ' ' ~ tor.hostname ~ '(' ~ tor.ports | join(",") ~ '),' %} + {% set torString = torString ~ tor.hostname ~ '",' %} + {% endif %} + {% endfor %} + {% else %} + 'ports':'{{ switch.hostname }}({{ switch.ports | join(",") }})', + 'torSwitches': null, + 'allSwitches':["{{ switch['hostname'] }}","{{ switch_inv.intentedpeerName }}"] + {% endif %} + {% endif %} + {% endfor %} + + + + + } + {% if not loop.last %},{% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% if not loop.last %},{% endif %} +{% endfor %} +] \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 new file mode 100644 index 000000000..db9ad67ae --- /dev/null +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 @@ -0,0 +1,16 @@ +[ + {% for vrf in MD_Extended.vxlan.multisite.overlay.vrfs %} + { + "fabric":"{{ MD.vxlan.fabric.name }}", + "vrfName":"{{ vrf.name}}", + "vrfId":"{{ vrf.vrf_id }}", + "vrfTemplate":"Default_VRF_Universal", + "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vlan_id }}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.overlay_services.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.overlay_services.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.overlay_services.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.overlay_services.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.overlay_services.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.overlay_services.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.overlay_services.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay_services.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay_services.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay_services.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vlan_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", + "serviceVrfTemplate": null, + "serviceVrfTemplate": null, + "displayName": "{{ vrf.name}}", + "vrfExtensionTemplate":"Default_VRF_Extension_Universal" + }{% if not loop.last %},{% endif %} + {% endfor %} +] + diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 new file mode 100644 index 000000000..ae9ce69e4 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 @@ -0,0 +1,20 @@ +[ + {% for attach in MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict[vrf["vrf_attach_group"]] %} + { + + "vrfName": "{{ vrf["name"] }}", + {% for switch in switches_in_fabric %} + {% if switch.logicalName == attach["hostname"] %} + "fabric": "{{ switch.fabricName }}", + "serialNumber": "{{ switch.serialNumber }}", + {% endif %} + {% endfor %} + "freeformConfig": "", + "extensionValues": "", + "vlan": {{ vrf["vlan_id"] }}, + "deployment": true, + "instanceValues": "{\"loopbackId\": \"{{ attach['loopback_id'] }}\", \"loopbackIpAddress\": \"{{ attach['loopback_ipv4'] | default('') }}\", \"loopbackIpV6Address\":\"{{ attach['loopback_ipv6'] | default('') }}\"}" + }{% if not loop.last %},{% endif %} + {% endfor %} +] + diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index 02c404972..31ce743ee 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -14,6 +14,11 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_fabric/msd_fabric/msd_fabric_base.j2' %} +{% elif vxlan.fabric.type == 'MFD'%} + +{# Include NDFC MFD Base Template #} +{% include '/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2' %} + {% elif vxlan.fabric.type == 'ISN'%} {# Include NDFC ISN Base Template #} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 index 8867c1525..51272f948 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 @@ -11,4 +11,10 @@ {% if vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) %} MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.ebgp_password }} MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.ebgp_password_encryption_type | default(defaults.vxlan.multisite.ebgp_password_encryption_type) }} +{% else %} + MS_IFC_BGP_PASSWORD: "" + MS_IFC_BGP_AUTH_KEY_TYPE: "" + MS_IFC_BGP_PASSWORD_ENABLE_PREV: "" + MS_IFC_BGP_AUTH_KEY_TYPE_PREV: "" + MS_IFC_BGP_PASSWORD_PREV: "" {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 index a593cfa1f..3757362d1 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 @@ -7,4 +7,15 @@ MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} TOR_AUTO_DEPLOY: false + FF: "MSD" + FABRIC_TYPE: "MFD" + FABRIC_NAME: "{{ vxlan.fabric.name }}" + L2_SEGMENT_ID_RANGE: {{ vxlan.multisite.layer2_vni_range | default(defaults.vxlan.multisite.layer2_vni_range) }} + L3_PARTITION_ID_RANGE: {{ vxlan.multisite.layer3_vni_range | default(defaults.vxlan.multisite.layer3_vni_range) }} + default_vrf: "Default_VRF_Universal" + default_network: "Default_Network_Universal" + vrf_extension_template: "Default_VRF_Extension_Universal" + network_extension_template: "Default_Network_Extension_Universal" + enableScheduledBackup: "" + scheduledTime: "" {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 index dc5d0db36..c423b71bc 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 @@ -2,7 +2,10 @@ {% if not defaults.vxlan.multisite.enable_ipv6_underlay %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} - DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} + DCI_SUBNET_TARGET_MASK: "{{ vxlan.multisite.ipv4_dci_subnet_mask | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }}" + LOOPBACK100_IPV6_RANGE: "" + V6_DCI_SUBNET_RANGE: "" + V6_DCI_SUBNET_TARGET_MASK: "" {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 index 715734a79..e7cb3ec27 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 @@ -1,2 +1,7 @@ {# Auto-generated NDFC MSD Security config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_SGT: "off" \ No newline at end of file + ENABLE_SGT: "off" + CLOUDSEC_KEY_STRING: "" + CLOUDSEC_ALGORITHM: "" + CLOUDSEC_ENFORCEMENT: "" + CLOUDSEC_REPORT_TIMER: "" + CLOUDSEC_AUTOCONFIG: "false" diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index dc5d0db36..e1da81c41 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -2,7 +2,7 @@ {% if not defaults.vxlan.multisite.enable_ipv6_underlay %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} - DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} + DCI_SUBNET_TARGET_MASK: "{{ vxlan.multisite.ipv4_dci_subnet_mask | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }}" {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index 20b72ddce..715c44972 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -25,39 +25,47 @@ ansible.builtin.import_tasks: sub_main_vxlan.yml when: > (MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN') and - (vars_common_vxlan.changes_detected_fabric) or + ((vars_common_vxlan.changes_detected_fabric) or (vars_common_vxlan.changes_detected_inventory) or (vars_common_vxlan.changes_detected_vpc_peering) or (vars_common_vxlan.changes_detected_interfaces) or (vars_common_vxlan.changes_detected_link_vpc_peering) or (vars_common_vxlan.changes_detected_vrfs) or (vars_common_vxlan.changes_detected_networks) or - (vars_common_vxlan.changes_detected_policy) + (vars_common_vxlan.changes_detected_policy)) - name: Import ISN Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml when: > (MD_Extended.vxlan.fabric.type == 'ISN') and - (vars_common_isn.changes_detected_fabric) or - (vars_common_isn.changes_detected_inventory) + ((vars_common_isn.changes_detected_fabric) or + (vars_common_isn.changes_detected_inventory)) - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml when: > (MD_Extended.vxlan.fabric.type == 'MSD') and - (vars_common_msd.changes_detected_fabric) or + ((vars_common_msd.changes_detected_fabric) or (vars_common_msd.changes_detected_vrfs) or - (vars_common_msd.changes_detected_networks) + (vars_common_msd.changes_detected_networks)) + +- name: Import MFD Role Tasks + ansible.builtin.import_tasks: sub_main_mfd.yml + when: > + (MD_Extended.vxlan.fabric.type == 'MFD') and + ((vars_common_mfd.changes_detected_fabric) or + (vars_common_mfd.changes_detected_vrfs) or + (vars_common_mfd.changes_detected_networks)) # Check with Matt and Pete on External Fabrics - name: Import Role Tasks External Fabric ansible.builtin.import_tasks: sub_main_external.yml when: > (MD_Extended.vxlan.fabric.type == 'External') and - (vars_common_external.changes_detected_inventory) or + ((vars_common_external.changes_detected_inventory) or (vars_common_external.changes_detected_interfaces) or (vars_common_external.changes_detected_fabric) or - (vars_common_external.changes_detected_interface_access_po) or + (vars_common_external.changes_detected_interface_access_po) or (vars_common_external.changes_detected_interface_access) or (vars_common_external.changes_detected_interface_loopback) or (vars_common_external.changes_detected_interface_po_routed) or @@ -65,7 +73,7 @@ (vars_common_external.changes_detected_interface_trunk_po) or (vars_common_external.changes_detected_interface_trunk) or (vars_common_external.changes_detected_sub_interface_routed) or - (vars_common_external.changes_detected_policy) + (vars_common_external.changes_detected_policy)) - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/create/tasks/mfd/fabric.yml b/roles/dtc/create/tasks/mfd/fabric.yml new file mode 100644 index 000000000..9d53f1100 --- /dev/null +++ b/roles/dtc/create/tasks/mfd/fabric.yml @@ -0,0 +1,63 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Check if fabric MFD {{ MD_Extended.vxlan.fabric.name }} exists in NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}" + register: get_result + failed_when: false + +- name: Set payload + set_fact: + payload: + templateName: "MSD_Fabric" + fabricName: "{{ MD_Extended.vxlan.fabric.name }}" + fabricType: "MFD" + fabricTechnology: "VXLANFabric" + nvPairs: "{{ fabric_config }}" + +- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (PUT) + cisco.dcnm.dcnm_rest: + method: PUT + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}' + json_data: '{{ payload | to_json }}' + when: + - get_result.response is defined + - get_result.response.RETURN_CODE == 200 + register: put_result + +- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (POST) + cisco.dcnm.dcnm_rest: + method: POST + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics' + json_data: '{{ payload | to_json }}' + when: get_result.response is not defined + register: post_result diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml new file mode 100644 index 000000000..f8ad573e7 --- /dev/null +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -0,0 +1,123 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Manage VRFs and Networks for MFD Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage VRFs and Networks MFD Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration for Federated NDFCs +# -------------------------------------------------------------------- + +- name: set filename for federated + set_fact: + file_name: "{{ MD.vxlan.global.name }}_fed_attach_vrfs.yml" + when: + - MD.vxlan.overlay_services.vrfs is defined + - changes_detected_vrfs + - MD.vxlan.global.fabric_type == 'MFD' + +- name: load VRF federated details from file + ansible.builtin.set_fact: + fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/' + file_name) | from_json }}" + when: + - MD.vxlan.overlay_services.vrfs is defined + - changes_detected_vrfs + - MD.vxlan.global.fabric_type == 'MFD' + +- name: Get existing VRFs in Federated Fabric + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.global.name }}/vrfs" + register: dcnm_vrf_existing + when: + - MD.vxlan.overlay_services.vrfs is defined + - changes_detected_vrfs + - MD.vxlan.global.fabric_type == 'MFD' + +- name: Manage NDFC Fabric VRFs for Federated + include_tasks: vrf_fed_config.yml + loop: "{{ fed_vrf_config }}" + loop_control: + loop_var: vrf + when: + - MD.vxlan.overlay_services.vrfs is defined + - changes_detected_vrfs + - MD.vxlan.global.fabric_type == 'MFD' + +# -------------------------------------------------------------------- +# Manage Loopback VRF attachments on NDFC (MFD) +# -------------------------------------------------------------------- +- name: Attach VRF Loopbacks per VRF + include_tasks: vrf_loopbacks.yml + loop_control: + loop_var: vrf + loop: "{{ MD.vxlan.overlay_services.vrfs }}" + when: + - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.global.fabric_type == 'MFD' + +# -------------------------------------------------------------------- +# Manage Network Configuration for Federated NDFCs +# -------------------------------------------------------------------- +- name: Query existing network.switches_to_attach.split in Federated Fabric + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{MD.vxlan.global.name}}/networks" + register: fed_networks_existing + when: + - MD.vxlan.overlay_services.networks is defined + - changes_detected_networks + - MD.vxlan.global.fabric_type == 'MFD' + +- name: Manage NDFC Fabric Networks for Federated + include_tasks: network_fed_config.yml + loop: "{{ net_config }}" + loop_control: + loop_var: network + when: + - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.overlay_services.networks is defined + - changes_detected_networks + +- name: Attach switches for all networks + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/attachments" + method: "POST" + json_data: "{{ network_switches | to_json}}" + when: + - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.overlay_services.networks is defined + - changes_detected_networks + +- name: Attach network to switches and ports for all networks + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/multiattach" + method: "POST" + json_data: "{{ network_switches_ports | to_json}}" + when: + - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.overlay_services.networks is defined + - changes_detected_networks \ No newline at end of file diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mfd.yml new file mode 100644 index 000000000..92d9a8a83 --- /dev/null +++ b/roles/dtc/create/tasks/sub_main_mfd.yml @@ -0,0 +1,51 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.create] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.create] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml + +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.create }}" + +- name: Create NDFC Fabric + ansible.builtin.import_tasks: mfd/fabric.yml + when: + - MD_Extended.vxlan.fabric.name is defined + - changes_detected_fabric + tags: "{{ nac_tags.create_fabric }}" + +# - name: Manage NDFC MFD Fabric Child Fabrics +# ansible.builtin.import_tasks: mfd/child_fabrics.yml +# when: +# - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 + +- name: Manage NDFC Fabric VRFs and Networks + ansible.builtin.import_tasks: mfd/vrfs_networks.yml + when: + - MD.vxlan.multisite.overlay is defined + - changes_detected_vrfs or changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 452e5a8a7..52885d11e 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -37,7 +37,7 @@ factory_defaults: domain_id_range: 1-1000 spanning_tree: root_bridge_protocol: unmanaged - vlan_range: + vlan_range: - from: 1 to: 3967 mst_instance_range: @@ -281,6 +281,8 @@ factory_defaults: ipv6_vtep_loopback_range: fd00::a10:0/120 ipv6_dci_subnet_range: fd00::a11:0/120 ipv6_dci_subnet_mask: 126 + layer2_vni_range: 30000-49000 + layer3_vni_range: 50000-59000 bgw_ip_tag: 54321 overlay_ifc: Direct_To_BGWS underlay_autoconfig: true From a15383b00a4098565191836787fd39e73a34503d Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 23 Jan 2025 13:28:01 +0000 Subject: [PATCH 051/183] Updates to fed --- roles/dtc/common/tasks/main.yml | 2 +- roles/dtc/common/tasks/mfd/ndfc_children.yml | 65 ++++++++++++++++++- roles/dtc/common/tasks/sub_main_mfd.yml | 12 ++-- .../common/templates/ndfc_fabric_children.j2 | 0 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_fabric_children.j2 diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 05517933a..ea7ade9fb 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -87,7 +87,7 @@ tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric.type == 'MSD' -- name: Import Role Tasks for MSD Fabric +- name: Import Role Tasks for MFD Fabric ansible.builtin.import_tasks: sub_main_mfd.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric.type == 'MFD' diff --git a/roles/dtc/common/tasks/mfd/ndfc_children.yml b/roles/dtc/common/tasks/mfd/ndfc_children.yml index 6def6b2e0..b900c3f7b 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_children.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_children.yml @@ -1,3 +1,66 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT --- -- debug: msg="Building NDFC MSD Child Fabric Data" \ No newline at end of file +- debug: msg="Building NDFC MSD Child Fabric Data" + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_fabric: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_fabric_children.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Fabric Creation Parameters From Template + ansible.builtin.template: + src: ndfc_fabric_children.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +https://10.2.0.70/onemanage/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/fed_svs_vxlan2/member + +{ + "operation": "add", + "clusterName": "ND-Cluster1", + "fabricName": "test2" +} \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml index 97b835961..cca0f8cdd 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -49,21 +49,21 @@ # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch inventory - ansible.builtin.include_tasks: mfd/ndfc_get_inventory.yml + ansible.builtin.import_tasks: mfd/ndfc_get_inventory.yml # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric VRFs Attach List From Template - ansible.builtin.include_tasks: mfd/ndfc_vrfs.yml + ansible.builtin.import_tasks: mfd/ndfc_vrfs.yml # -------------------------------------------------------------------- # Build NDFC Fabric Networks Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Networks Attach List From Template - ansible.builtin.include_tasks: mfd/ndfc_networks.yml + ansible.builtin.import_tasks: mfd/ndfc_networks.yml - name: Set facts for missed changes_detected flags for Federated Fabric ansible.builtin.set_fact: @@ -75,9 +75,9 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Fabric Changes Detected - [ {{ vars_common_msd.changes_detected_fabric }} ]" - - "+ VRFs Changes Detected - [ {{ vars_common_msd.changes_detected_vrfs }} ]" - - "+ Networks Changes Detected - [ {{ vars_common_msd.changes_detected_networks }} ]" + - "+ Fabric Changes Detected - [ {{ vars_common_mfd.changes_detected_fabric }} ]" + - "+ VRFs Changes Detected - [ {{ vars_common_mfd.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_mfd.changes_detected_networks }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/templates/ndfc_fabric_children.j2 b/roles/dtc/common/templates/ndfc_fabric_children.j2 new file mode 100644 index 000000000..e69de29bb From 630168d23a3fcc6c99265c9397e8e33cadbfac37 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 24 Jan 2025 08:49:44 +0000 Subject: [PATCH 052/183] Support for federated child fabric addition --- roles/dtc/common/tasks/mfd/ndfc_children.yml | 23 ++++++++---- roles/dtc/common/tasks/sub_main_mfd.yml | 7 ++++ .../common/templates/ndfc_fabric_children.j2 | 9 +++++ roles/dtc/create/tasks/mfd/child_fabrics.yml | 36 +++++++++++++++++++ roles/dtc/create/tasks/mfd/fabric.yml | 9 +++++ 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 roles/dtc/create/tasks/mfd/child_fabrics.yml diff --git a/roles/dtc/common/tasks/mfd/ndfc_children.yml b/roles/dtc/common/tasks/mfd/ndfc_children.yml index b900c3f7b..546ff5806 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_children.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_children.yml @@ -57,10 +57,21 @@ dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost -https://10.2.0.70/onemanage/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/fed_svs_vxlan2/member +- ansible.builtin.set_fact: + fabric_children: "{{ lookup('file', path_name + file_name) | from_yaml }}" + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost -{ - "operation": "add", - "clusterName": "ND-Cluster1", - "fabricName": "test2" -} \ No newline at end of file +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_fabric: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml index cca0f8cdd..cc4f0e420 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -44,6 +44,13 @@ - name: Build Fabric Create Parameters ansible.builtin.import_tasks: mfd/ndfc_fabric.yml +# -------------------------------------------------------------------- +# Build Create Fabric Children Parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.import_tasks: mfd/ndfc_children.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Get Switch Inventory when Federated Fabric # -------------------------------------------------------------------- diff --git a/roles/dtc/common/templates/ndfc_fabric_children.j2 b/roles/dtc/common/templates/ndfc_fabric_children.j2 index e69de29bb..f5c698fb0 100644 --- a/roles/dtc/common/templates/ndfc_fabric_children.j2 +++ b/roles/dtc/common/templates/ndfc_fabric_children.j2 @@ -0,0 +1,9 @@ +[ +{% for child in MD_Extended.vxlan.multisite.child_fabrics %} +{ + 'operation': "add", + 'clusterName': "{{ child.cluster }}", + 'fabricName': "{{ child.name }}" +}{% if not loop.last %},{% endif %} +{% endfor %} +] \ No newline at end of file diff --git a/roles/dtc/create/tasks/mfd/child_fabrics.yml b/roles/dtc/create/tasks/mfd/child_fabrics.yml new file mode 100644 index 000000000..cbc5e0095 --- /dev/null +++ b/roles/dtc/create/tasks/mfd/child_fabrics.yml @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Children Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric Children {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (POST) + cisco.dcnm.dcnm_rest: + method: PUT + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' + json_data: '{{ child | to_json }}' + register: post_result \ No newline at end of file diff --git a/roles/dtc/create/tasks/mfd/fabric.yml b/roles/dtc/create/tasks/mfd/fabric.yml index 9d53f1100..33aefe5a4 100644 --- a/roles/dtc/create/tasks/mfd/fabric.yml +++ b/roles/dtc/create/tasks/mfd/fabric.yml @@ -61,3 +61,12 @@ json_data: '{{ payload | to_json }}' when: get_result.response is not defined register: post_result + +- ansible.builtin.debug: + var: fabric_children + +- name: Add Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} + include_tasks: child_fabrics.yml + loop: "{{ fabric_children }}" + loop_control: + loop_var: child From 472f1ddd9239893ed4e3edd7dfa50119864ce1fe Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 24 Jan 2025 15:01:40 +0000 Subject: [PATCH 053/183] Added new updates to support federated overlay --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 4 +-- roles/dtc/common/tasks/mfd/ndfc_vrfs.yml | 2 +- .../common/templates/ndfc_attach_vrfs_fed.j2 | 2 +- roles/dtc/create/tasks/mfd/child_fabrics.yml | 3 +- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 18 +++++----- roles/validate/files/defaults.yml | 34 +++++++++++++++++++ 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index 73562c63e..a638e3599 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -103,7 +103,7 @@ - name: Set network_switches Var ansible.builtin.set_fact: - network_switches: "{{ lookup('file', file_name2) | from_yaml }}" - network_switches_ports: "{{ lookup('file', file_name) | from_yaml }}" + network_switches: "{{ lookup('file', path_name + file_name2) | from_yaml }}" + network_switches_ports: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 delegate_to: localhost diff --git a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml index aa500ada1..abd6aa695 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml @@ -62,7 +62,7 @@ - name: Set vrf_config Var ansible.builtin.set_fact: - vrf_config: "{{ lookup('file', path_name + file_nam) | from_yaml }}" + vrf_config: "{{ lookup('file', path_name + file_name ) | from_yaml }}" when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 delegate_to: localhost diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 index db9ad67ae..00b49787f 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 @@ -5,7 +5,7 @@ "vrfName":"{{ vrf.name}}", "vrfId":"{{ vrf.vrf_id }}", "vrfTemplate":"Default_VRF_Universal", - "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vlan_id }}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.overlay_services.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.overlay_services.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.overlay_services.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.overlay_services.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.overlay_services.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.overlay_services.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.overlay_services.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.overlay_services.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.overlay_services.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.overlay_services.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vlan_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", + "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vlan_id }}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vlan_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", "serviceVrfTemplate": null, "serviceVrfTemplate": null, "displayName": "{{ vrf.name}}", diff --git a/roles/dtc/create/tasks/mfd/child_fabrics.yml b/roles/dtc/create/tasks/mfd/child_fabrics.yml index cbc5e0095..eb2ec5995 100644 --- a/roles/dtc/create/tasks/mfd/child_fabrics.yml +++ b/roles/dtc/create/tasks/mfd/child_fabrics.yml @@ -33,4 +33,5 @@ method: PUT path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' json_data: '{{ child | to_json }}' - register: post_result \ No newline at end of file + register: post_result + failed_when: false \ No newline at end of file diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index f8ad573e7..e55d40191 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -37,7 +37,7 @@ when: - MD.vxlan.overlay_services.vrfs is defined - changes_detected_vrfs - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - name: load VRF federated details from file ansible.builtin.set_fact: @@ -45,7 +45,7 @@ when: - MD.vxlan.overlay_services.vrfs is defined - changes_detected_vrfs - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - name: Get existing VRFs in Federated Fabric cisco.dcnm.dcnm_rest: @@ -55,7 +55,7 @@ when: - MD.vxlan.overlay_services.vrfs is defined - changes_detected_vrfs - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - name: Manage NDFC Fabric VRFs for Federated include_tasks: vrf_fed_config.yml @@ -65,7 +65,7 @@ when: - MD.vxlan.overlay_services.vrfs is defined - changes_detected_vrfs - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.global.fabric.type == 'MFD' # -------------------------------------------------------------------- # Manage Loopback VRF attachments on NDFC (MFD) @@ -77,7 +77,7 @@ loop: "{{ MD.vxlan.overlay_services.vrfs }}" when: - MD.vxlan.overlay_services.vrfs is defined - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' # -------------------------------------------------------------------- # Manage Network Configuration for Federated NDFCs @@ -90,7 +90,7 @@ when: - MD.vxlan.overlay_services.networks is defined - changes_detected_networks - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - name: Manage NDFC Fabric Networks for Federated include_tasks: network_fed_config.yml @@ -98,7 +98,7 @@ loop_control: loop_var: network when: - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.overlay_services.networks is defined - changes_detected_networks @@ -108,7 +108,7 @@ method: "POST" json_data: "{{ network_switches | to_json}}" when: - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.overlay_services.networks is defined - changes_detected_networks @@ -118,6 +118,6 @@ method: "POST" json_data: "{{ network_switches_ports | to_json}}" when: - - MD.vxlan.global.fabric_type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.overlay_services.networks is defined - changes_detected_networks \ No newline at end of file diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 52885d11e..89f0cbf51 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -292,6 +292,40 @@ factory_defaults: delay_restore: 300 enable_ebgp_password: false enable_trm: false + overlay: + vrfs: + vrf_description: "Configured by Ansible NetAsCode" + vrf_intf_desc: "Configured by Ansible NetAsCode" + vrf_int_mtu: 9216 + loopback_route_tag: 12345 + max_bgp_paths: 1 + max_ibgp_paths: 2 + ipv6_linklocal_enable: true + adv_host_routes: false + adv_default_routes: true + static_default_route: true + disable_rt_auto: false + netflow_enable: false + no_rp: false + rp_external: false + redist_direct_routemap: FABRIC-RMAP-REDIST-SUBNET + trm_enable: false + trm_bgw_msite: false + networks: + net_description: "Configured by Ansible NetAsCode" + is_l2_only: false + arp_supress: false + l3gw_on_border: false + mtu_l3intf: 9216 + multicast_group_address: 239.1.1.1 + netflow_enable: false + route_target_both: false + route_tag: 12345 + trm_enable: false + vrf_attach_groups: + switches: [] + network_attach_groups: + switches: [] isn: sub_int_range: 2-511 bootstrap: From 459d30553b2d922f3676dd0ec2e5f5601bf8cb60 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sat, 25 Jan 2025 02:57:24 +0000 Subject: [PATCH 054/183] Fix route control no data --- plugins/plugin_utils/data_model_keys.py | 4 +++ .../505_policy_route_control_route_map.py | 35 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 161beaf58..0c3eeb85c 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -60,6 +60,10 @@ model_keys['VXLAN_EVPN']['overlay.network_attach_groups'] = [root_key, 'overlay', 'network_attach_groups', 'LIST'] model_keys['VXLAN_EVPN']['overlay.network_attach_groups.switches'] = [root_key, 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] # --- +model_keys['VXLAN_EVPN']['overlay_extensions'] = [root_key, 'overlay_extensions', 'KEY'] +model_keys['VXLAN_EVPN']['overlay_extensions.route_control'] = [root_key, 'overlay_extensions', 'route_control', 'KEY'] +model_keys['VXLAN_EVPN']['overlay_extensions.route_control.route_maps'] = [root_key, 'overlay_extensions', 'route_control', 'route_maps', 'LIST'] +# --- model_keys['VXLAN_EVPN']['policy'] = [root_key, 'policy', 'KEY'] model_keys['VXLAN_EVPN']['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] model_keys['VXLAN_EVPN']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] diff --git a/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py b/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py index 937aee032..2ce7e6da9 100644 --- a/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py +++ b/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py @@ -49,7 +49,7 @@ def match(cls, data): """ function used by iac-validate """ - route_control = [] + route_control = {} topology_switches = [] switch_policy = [] route_maps = [] @@ -94,7 +94,9 @@ def match(cls, data): ) # Check route maps integrity - if data["vxlan"].get("overlay_extensions").get("route_control").get("route_maps", None): + rm_keys = ['overlay_extensions', 'route_control', 'route_maps'] + check = cls.data_model_key_check(data["vxlan"], rm_keys) + if 'route_maps' in check['keys_data']: route_maps = data["vxlan"]["overlay_extensions"]["route_control"]["route_maps"] cls.check_route_maps( route_maps @@ -321,3 +323,32 @@ def check_set_metric_integrity( cls.results.append( "For vxlan.overlay_extensions.route_control.route_maps.entries.set.metric to be enabled, " + metric + " should be set in the metric.") + + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict From 553df9e1ddde91aa29d9e7aa8265c15e0de81f81 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sat, 25 Jan 2025 03:25:10 +0000 Subject: [PATCH 055/183] Fix github actions issue --- .../files/rules/vxlan/505_policy_route_control_route_map.py | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py b/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py index 2ce7e6da9..00894585c 100644 --- a/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py +++ b/roles/validate/files/rules/vxlan/505_policy_route_control_route_map.py @@ -324,7 +324,6 @@ def check_set_metric_integrity( "For vxlan.overlay_extensions.route_control.route_maps.entries.set.metric to be enabled, " + metric + " should be set in the metric.") - @classmethod def data_model_key_check(cls, tested_object, keys): dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} From d948485ab8a998d44a79fbf43865ba4751429e29 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Sat, 25 Jan 2025 19:26:03 +0000 Subject: [PATCH 056/183] Fix rule 401 --- .../rules/vxlan/401_overlay_services_cross_reference.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py index 010685900..d651e2243 100644 --- a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py +++ b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py @@ -18,9 +18,13 @@ def match(cls, inventory): # Remove the check for overlay_services after deprecation # Remove lines 21 - 23 overlay_key = 'overlay' - check = cls.data_model_key_check(inventory, ['vxlan']) - if 'overlay_services' in check['keys_found'] and 'overlay_services' in check['keys_data']: + check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) + if overlay_key in check['keys_not_found'] or overlay_key in check['keys_no_data']: overlay_key = 'overlay_services' + check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) + if overlay_key in check['keys_not_found'] or overlay_key in check['keys_no_data']: + results.append('Overlay data not found!') + return results network_keys = ['vxlan', overlay_key, 'networks'] vrf_keys = ['vxlan', overlay_key, 'vrfs'] From 242dff1d19e1c527eaddea18ea94e8878ab66f96 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 27 Jan 2025 09:36:11 +0000 Subject: [PATCH 057/183] Added support for VRFs --- .../create/tasks/mfd/network_fed_config.yml | 52 +++++++++++++ roles/dtc/create/tasks/mfd/vrf_fed_config.yml | 59 +++++++++++++++ roles/dtc/create/tasks/mfd/vrf_loopbacks.yml | 75 +++++++++++++++++++ roles/dtc/create/tasks/mfd/vrfs_networks.yml | 30 ++++---- 4 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 roles/dtc/create/tasks/mfd/network_fed_config.yml create mode 100644 roles/dtc/create/tasks/mfd/vrf_fed_config.yml create mode 100644 roles/dtc/create/tasks/mfd/vrf_loopbacks.yml diff --git a/roles/dtc/create/tasks/mfd/network_fed_config.yml b/roles/dtc/create/tasks/mfd/network_fed_config.yml new file mode 100644 index 000000000..4729c784c --- /dev/null +++ b/roles/dtc/create/tasks/mfd/network_fed_config.yml @@ -0,0 +1,52 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Manage Networks for Federated NDFC + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Networks for Federated Fabrics {{ MD.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage Network Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Get Existing Network ID for Federated Fabric + set_fact: + network_id_list: "{{ fed_networks_existing | json_query(network_query) }}" + vars: + network_query: "response.DATA[?displayName=='{{network.displayName}}'].networkId" + +- name: Update Network for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/networks/{{ network.displayName }}" + method: "PUT" + json_data: "{{ network | to_json}}" + when: network_id_list|default(None)|length != 0 + +- name: Configure Network for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/networks" + method: "POST" + json_data: "{{ network | to_json}}" + when: network_id_list|default(None)|length == 0 diff --git a/roles/dtc/create/tasks/mfd/vrf_fed_config.yml b/roles/dtc/create/tasks/mfd/vrf_fed_config.yml new file mode 100644 index 000000000..8cfd07db6 --- /dev/null +++ b/roles/dtc/create/tasks/mfd/vrf_fed_config.yml @@ -0,0 +1,59 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage VRFs for Federated NDFC + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage VRFs for Federated Fabrics {{ MD.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Get existing VRFs in Federated Fabric + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" + register: dcnm_vrf_existing + +- name: Check if VRF Exists + set_fact: + vrf_exist_result: "{{ dcnm_vrf_existing | json_query(vrf_query) }}" + vars: + vrf_query: "response.DATA[?vrfName=='{{vrf.displayName}}'].vrfName" + +- name: Update VRF for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/{{ vrf.displayName }}" + method: "PUT" + json_data: "{{ vrf | to_json}}" + when: vrf_exist_result|default(None)|length != 0 + +- name: Configure VRF for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" + method: "POST" + json_data: "{{ vrf | to_json}}" + when: vrf_exist_result|default(None)|length == 0 diff --git a/roles/dtc/create/tasks/mfd/vrf_loopbacks.yml b/roles/dtc/create/tasks/mfd/vrf_loopbacks.yml new file mode 100644 index 000000000..4235c2f44 --- /dev/null +++ b/roles/dtc/create/tasks/mfd/vrf_loopbacks.yml @@ -0,0 +1,75 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- +- name: Manage VRFs and Networks Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage VRFs and Networks Fabric {{ MD.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +# -------------------------------------------------------------------- +# Manage VRF Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{vrf.name}}_attach_vrfs_loopbacks.yml" + fabric_name: "{{ MD.vxlan.fabric.name }}" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ role_path }}/../common/files/mfd/{{ MD.vxlan.fabric.name}}/{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Set vrf_loopback_config Var + ansible.builtin.set_fact: + vrf_loopback_config: "{{ lookup('file', role_path + '/../common/files/mfd/'+ fabric_name +'/' + file_name) | from_json }}" + when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 and data_file_previous.stat.exists + delegate_to: localhost + +- name: Create complete payload for attaching VRF to Switches. + set_fact: + attach_payload: "{{ attach_payload | default([]) + [{'vrfName':vrf.name, 'lanAttachList':vrf_loopback_config}]}}" + +- name: Call API to attach VRF to Leaf Switches + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/attachments" + method: "POST" + json_data: "{{ attach_payload | to_json}}" + when: MD.vxlan.fabric.type != 'MFD' + +- name: Call API to attach VRF to Leaf Switches for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/attachments" + method: "POST" + json_data: "{{ attach_payload | to_json}}" + when: MD.vxlan.fabric.type == 'MFD' + +- name: Clear payload + set_fact: + vrf_loopback_config: [] + attach_payload: [] + switches: [] + attach_list: [] diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index e55d40191..a8d194f50 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -33,27 +33,27 @@ - name: set filename for federated set_fact: - file_name: "{{ MD.vxlan.global.name }}_fed_attach_vrfs.yml" + file_name: "ndfc_fed_attach_vrfs.yml" when: - - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.multisite.overlay.vrfs is defined - changes_detected_vrfs - MD.vxlan.fabric.type == 'MFD' - name: load VRF federated details from file ansible.builtin.set_fact: - fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/' + file_name) | from_json }}" + fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" when: - - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.multisite.overlay.vrfs is defined - changes_detected_vrfs - MD.vxlan.fabric.type == 'MFD' - name: Get existing VRFs in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.global.name }}/vrfs" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" register: dcnm_vrf_existing when: - - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.multisite.overlay.vrfs is defined - changes_detected_vrfs - MD.vxlan.fabric.type == 'MFD' @@ -63,9 +63,9 @@ loop_control: loop_var: vrf when: - - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.multisite.overlay.vrfs is defined - changes_detected_vrfs - - MD.vxlan.global.fabric.type == 'MFD' + - MD.vxlan.fabric.type == 'MFD' # -------------------------------------------------------------------- # Manage Loopback VRF attachments on NDFC (MFD) @@ -74,9 +74,9 @@ include_tasks: vrf_loopbacks.yml loop_control: loop_var: vrf - loop: "{{ MD.vxlan.overlay_services.vrfs }}" + loop: "{{ MD.vxlan.multisite.overlay.vrfs }}" when: - - MD.vxlan.overlay_services.vrfs is defined + - MD.vxlan.multisite.overlay.vrfs is defined - MD.vxlan.fabric.type == 'MFD' # -------------------------------------------------------------------- @@ -85,10 +85,10 @@ - name: Query existing network.switches_to_attach.split in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{MD.vxlan.global.name}}/networks" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{MD.vxlan.fabric.name}}/networks" register: fed_networks_existing when: - - MD.vxlan.overlay_services.networks is defined + - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks - MD.vxlan.fabric.type == 'MFD' @@ -99,7 +99,7 @@ loop_var: network when: - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.overlay_services.networks is defined + - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks - name: Attach switches for all networks @@ -109,7 +109,7 @@ json_data: "{{ network_switches | to_json}}" when: - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.overlay_services.networks is defined + - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks - name: Attach network to switches and ports for all networks @@ -119,5 +119,5 @@ json_data: "{{ network_switches_ports | to_json}}" when: - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.overlay_services.networks is defined + - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks \ No newline at end of file From 003f33454583783b92edb5eb913222220ad1dd50 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 27 Jan 2025 09:54:07 +0000 Subject: [PATCH 058/183] Corrected small error in filenameing --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index a638e3599..7ec852a1e 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -103,7 +103,7 @@ - name: Set network_switches Var ansible.builtin.set_fact: - network_switches: "{{ lookup('file', path_name + file_name2) | from_yaml }}" - network_switches_ports: "{{ lookup('file', path_name + file_name) | from_yaml }}" + network_switches: "{{ lookup('file', path_name + file_name) | from_yaml }}" + network_switches_ports: "{{ lookup('file', path_name + file_name2) | from_yaml }}" when: (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 delegate_to: localhost From a5300823842fdd4122a370b03ea4e628764ef7bb Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 27 Jan 2025 11:16:08 +0000 Subject: [PATCH 059/183] Added support for updating members --- roles/dtc/create/tasks/mfd/child_fabrics.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/roles/dtc/create/tasks/mfd/child_fabrics.yml b/roles/dtc/create/tasks/mfd/child_fabrics.yml index eb2ec5995..e05fb32de 100644 --- a/roles/dtc/create/tasks/mfd/child_fabrics.yml +++ b/roles/dtc/create/tasks/mfd/child_fabrics.yml @@ -28,10 +28,23 @@ - "+ Manage Fabric Children {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (POST) +- name: Check if fabric already a member of NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' + register: member_result + +- name: Set fact for existing fabric names + set_fact: + existing_fabric_names: >- + {{ + member_result.response.DATA | map(attribute='fabrics') | map('dict2items') | flatten | map(attribute='key') | list + }} + +- name: Manage fabric Federated {{ MD_Extended.vxlan.fabric.name }} in NDFC (PUT) cisco.dcnm.dcnm_rest: method: PUT path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' json_data: '{{ child | to_json }}' register: post_result - failed_when: false \ No newline at end of file + when: child.fabricName not in existing_fabric_names \ No newline at end of file From 573184e72a5667523373eb6aea596e8e5e506482 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 27 Jan 2025 21:34:40 -0500 Subject: [PATCH 060/183] update defaults for msite --- roles/validate/files/defaults.yml | 544 +++++++++++++++--------------- 1 file changed, 274 insertions(+), 270 deletions(-) diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 452e5a8a7..fe8128033 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -21,282 +21,286 @@ --- factory_defaults: - vxlan: - global: - route_reflectors: 2 - anycast_gateway_mac: 20:20:00:00:00:aa - auth_proto: MD5 - vpc: - peer_link_vlan: 3600 - peer_keep_alive: management - auto_recovery_time: 360 - delay_restore_time: 150 - peer_link_port_channel_id: 500 - advertise_pip: false - advertise_pip_border_only: true - domain_id_range: 1-1000 - spanning_tree: - root_bridge_protocol: unmanaged - vlan_range: - - from: 1 - to: 3967 - mst_instance_range: - - from: 0 - to: 0 - bridge_priority: 0 - netflow: - enable: false - topology: - switches: - routing_loopback_id: 0 - vtep_loopback_id: 1 - interfaces: - topology_switch_access_interface: - description: "NetAsCode Access Interface" - mtu: jumbo - speed: auto - enabled: true - access_vlan: 1 - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_trunk_interface: - description: "NetAsCode Trunk Interface" - mtu: jumbo - speed: auto - enabled: true - trunk_allowed_vlans: none - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_access_po_interface: - description: "NetAsCode Access PO Interface" - mtu: jumbo - speed: auto - enabled: true - access_vlan: 1 - pc_mode: active - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_trunk_po_interface: - description: "NetAsCode Trunk PO Interface" - mtu: jumbo - speed: auto - enabled: true - trunk_allowed_vlans: none - pc_mode: active - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_routed_interface: - description: "NetAsCode Routed Interface" - mtu: 9216 - speed: auto - enabled: true - topology_switch_routed_sub_interface: - description: "NetAsCode Routed Sub Interface" - mtu: 9216 - speed: auto - enabled: true - topology_switch_routed_po_interface: - description: "NetAsCode Routed PO Interface" - mtu: 9216 - speed: auto - enabled: true - pc_mode: active - topology_switch_loopback_interface: - description: "NetAsCode Loopback Interface" - enabled: true - vpc_peers: - domain_id: 1 - fabric_links: - edge_connections: - underlay: - general: - routing_protocol: ospf - enable_ipv6_underlay: false - replication_mode: multicast - fabric_interface_numbering: p2p - subnet_mask: 30 - manual_underlay_allocation: false - underlay_routing_loopback_id: 0 - underlay_vtep_loopback_id: 1 - underlay_routing_protocol_tag: UNDERLAY - underlay_rp_loopback_id: 254 - intra_fabric_interface_mtu: 9216 - layer2_host_interfacde_mtu: 9216 - unshut_host_interfaces: true - ipv4: - underlay_routing_loopback_ip_range: 10.2.0.0/22 - underlay_vtep_loopback_ip_range: 10.3.0.0/22 - underlay_rp_loopback_ip_range: 10.254.254.0/24 - underlay_subnet_ip_range: 10.4.0.0/16 - ipv6: - enable_ipv6_link_local_address: true - underlay_subnet_mask: 126 - ospf: - area_id: 0.0.0.0 - authentication_enable: false - authentication_key_id: 127 - isis: - level: level-2 - network_point_to_point: true - authentication_enable: false - authentication_key_id: 127 - overload_bit: true - overload_bit_elapsed_time: 60 - bgp: - authentication_enable: false - authentication_key_type: 3 - multicast: - group_subnet: 239.1.1.0/25 - rendezvous_points: 2 - rp_mode: asm - underlay_rp_loopback_id: 254 - trm_enable: false - trm_default_group: 239.1.1.0 - underlay_primary_rp_loopback_id: 2 - underlay_backup_rp_loopback_id: 3 - underlay_second_backup_rp_loopback_id: 4 - underlay_third_backup_rp_loopback_id: 5 - bfd: - enable: false - ibgp: false - ospf: false - pim: false - isis: false - authentication_enable: false - authentication_key_id: 100 - overlay: - vrfs: - vrf_description: "Configured by Ansible NetAsCode" - vrf_intf_desc: "Configured by Ansible NetAsCode" - vrf_int_mtu: 9216 - loopback_route_tag: 12345 - max_bgp_paths: 1 - max_ibgp_paths: 2 - ipv6_linklocal_enable: true - adv_host_routes: false - adv_default_routes: true - static_default_route: true - disable_rt_auto: false - netflow_enable: false - no_rp: false - rp_external: false - redist_direct_routemap: FABRIC-RMAP-REDIST-SUBNET - trm_enable: false - trm_bgw_msite: false - networks: - net_description: "Configured by Ansible NetAsCode" - is_l2_only: false - arp_supress: false - l3gw_on_border: false - mtu_l3intf: 9216 - multicast_group_address: 239.1.1.1 - netflow_enable: false - route_target_both: false - route_tag: 12345 - trm_enable: false - vrf_attach_groups: - switches: [] - network_attach_groups: - switches: [] - policy: - template_name: switch_freeform - priority: 500 - overlay_extensions: - vrf_lites: - ospf: - areas: - area_type: standard - default_area: 0 - distance: 110 - bfd: - enabled: false - bgp: - best_path_as_path_relax: false - graceful_restart: true - graceful_restart_helper: false - address_family_ipv4_unicast: - additional_paths_receive: false - additional_paths_send: false - default_originate: false - ebgp_distance: 20 - ibgp_distance: 200 - local_distance: 220 - address_family_ipv6_unicast: - additional_paths_receive: false - additional_paths_send: false - default_originate: false - ebgp_distance: 20 - ibgp_distance: 200 - local_distance: 220 + defaults: + vxlan: + global: + route_reflectors: 2 + anycast_gateway_mac: 20:20:00:00:00:aa + auth_proto: MD5 + vpc: + peer_link_vlan: 3600 + peer_keep_alive: management + auto_recovery_time: 360 + delay_restore_time: 150 + peer_link_port_channel_id: 500 + advertise_pip: false + advertise_pip_border_only: true + domain_id_range: 1-1000 + spanning_tree: + root_bridge_protocol: unmanaged + vlan_range: + - from: 1 + to: 3967 + mst_instance_range: + - from: 0 + to: 0 + bridge_priority: 0 + netflow: + enable: false + topology: switches: + routing_loopback_id: 0 + vtep_loopback_id: 1 interfaces: - ospf: - auth_type: none - auth_key_id: 0 - cost: 1 - passive_interface: false - mtu_ignore: false - advertise_subnet: false - bfd: - enabled: false - hello_interval: 10 - dead_interval: 40 - network_type: broadcast - priority: 1 - lsa_retransmit_interval: 5 - lsa_transmit_delay: 1 - bgp_peers: - next_hop_self: false + topology_switch_access_interface: + description: "NetAsCode Access Interface" + mtu: jumbo + speed: auto + enabled: true + access_vlan: 1 + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_trunk_interface: + description: "NetAsCode Trunk Interface" + mtu: jumbo + speed: auto + enabled: true + trunk_allowed_vlans: none + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_access_po_interface: + description: "NetAsCode Access PO Interface" + mtu: jumbo + speed: auto + enabled: true + access_vlan: 1 + pc_mode: active + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_trunk_po_interface: + description: "NetAsCode Trunk PO Interface" + mtu: jumbo + speed: auto + enabled: true + trunk_allowed_vlans: none + pc_mode: active + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_routed_interface: + description: "NetAsCode Routed Interface" + mtu: 9216 + speed: auto + enabled: true + topology_switch_routed_sub_interface: + description: "NetAsCode Routed Sub Interface" + mtu: 9216 + speed: auto + enabled: true + topology_switch_routed_po_interface: + description: "NetAsCode Routed PO Interface" + mtu: 9216 + speed: auto + enabled: true + pc_mode: active + topology_switch_loopback_interface: + description: "NetAsCode Loopback Interface" + enabled: true + vpc_peers: + domain_id: 1 + fabric_links: + edge_connections: + underlay: + general: + routing_protocol: ospf + enable_ipv6_underlay: false + replication_mode: multicast + fabric_interface_numbering: p2p + subnet_mask: 30 + manual_underlay_allocation: false + underlay_routing_loopback_id: 0 + underlay_vtep_loopback_id: 1 + underlay_routing_protocol_tag: UNDERLAY + underlay_rp_loopback_id: 254 + intra_fabric_interface_mtu: 9216 + layer2_host_interfacde_mtu: 9216 + unshut_host_interfaces: true + ipv4: + underlay_routing_loopback_ip_range: 10.2.0.0/22 + underlay_vtep_loopback_ip_range: 10.3.0.0/22 + underlay_rp_loopback_ip_range: 10.254.254.0/24 + underlay_subnet_ip_range: 10.4.0.0/16 + ipv6: + enable_ipv6_link_local_address: true + underlay_subnet_mask: 126 + ospf: + area_id: 0.0.0.0 + authentication_enable: false + authentication_key_id: 127 + isis: + level: level-2 + network_point_to_point: true + authentication_enable: false + authentication_key_id: 127 + overload_bit: true + overload_bit_elapsed_time: 60 + bgp: + authentication_enable: false + authentication_key_type: 3 + multicast: + group_subnet: 239.1.1.0/25 + rendezvous_points: 2 + rp_mode: asm + underlay_rp_loopback_id: 254 + trm_enable: false + trm_default_group: 239.1.1.0 + underlay_primary_rp_loopback_id: 2 + underlay_backup_rp_loopback_id: 3 + underlay_second_backup_rp_loopback_id: 4 + underlay_third_backup_rp_loopback_id: 5 + bfd: + enable: false + ibgp: false + ospf: false + pim: false + isis: false + authentication_enable: false + authentication_key_id: 100 + overlay: + vrfs: + vrf_description: "Configured by Ansible NetAsCode" + vrf_intf_desc: "Configured by Ansible NetAsCode" + vrf_int_mtu: 9216 + loopback_route_tag: 12345 + max_bgp_paths: 1 + max_ibgp_paths: 2 + ipv6_linklocal_enable: true + adv_host_routes: false + adv_default_routes: true + static_default_route: true + disable_rt_auto: false + netflow_enable: false + no_rp: false + rp_external: false + redist_direct_routemap: FABRIC-RMAP-REDIST-SUBNET + trm_enable: false + trm_bgw_msite: false + networks: + net_description: "Configured by Ansible NetAsCode" + is_l2_only: false + arp_supress: false + l3gw_on_border: false + mtu_l3intf: 9216 + multicast_group_address: 239.1.1.1 + netflow_enable: false + route_target_both: false + route_tag: 12345 + trm_enable: false + vrf_attach_groups: + switches: [] + network_attach_groups: + switches: [] + policy: + template_name: switch_freeform + priority: 500 + overlay_extensions: + vrf_lites: + ospf: + areas: + area_type: standard + default_area: 0 + distance: 110 bfd: enabled: false - disable_connected_check: false - remove_private_as: false - remove_private_as_all: false - ebgp_multihop: 2 + default_information_originate: + always: false + nssa: + default_information_originate: false + no_redistribution: false + no_summary: false + translate: + always: false + supress_fa: false + never: false + bgp: + best_path_as_path_relax: false + graceful_restart: true + graceful_restart_helper: false address_family_ipv4_unicast: - send_community: false - send_ext_community: false - allow_as_in: false - allow_as_in_number: 3 - as_override: false - route_reflector_client: false + additional_paths_receive: false + additional_paths_send: false default_originate: false - next_hop_self: false + ebgp_distance: 20 + ibgp_distance: 200 + local_distance: 220 address_family_ipv6_unicast: - send_community: false - send_ext_community: false - allow_as_in: false - allow_as_in_number: 3 - as_override: false - route_reflector_client: false + additional_paths_receive: false + additional_paths_send: false default_originate: false + ebgp_distance: 20 + ibgp_distance: 200 + local_distance: 220 + switches: + interfaces: + ospf: + auth_type: none + auth_key_id: 0 + cost: 1 + passive_interface: false + mtu_ignore: false + advertise_subnet: false + bfd: + enabled: false + hello_interval: 10 + dead_interval: 40 + network_type: broadcast + priority: 1 + lsa_retransmit_interval: 5 + lsa_transmit_delay: 1 + bgp_peers: next_hop_self: false - multisite: - enable_ipv6_underlay: false - anycast_gateway_mac: 20:20:00:00:00:aa - vtep_loopback_id: 100 - ipv4_vtep_loopback_range: 10.10.0.0/24 - ipv4_dci_subnet_range: 10.10.1.0/24 - ipv4_dci_subnet_mask: 30 - ipv6_vtep_loopback_range: fd00::a10:0/120 - ipv6_dci_subnet_range: fd00::a11:0/120 - ipv6_dci_subnet_mask: 126 - bgw_ip_tag: 54321 - overlay_ifc: Direct_To_BGWS - underlay_autoconfig: true - enable_bgp_send_community: false - enable_bgp_log_neighbor_change: false - enable_bgp_bfd: false - delay_restore: 300 - enable_ebgp_password: false - enable_trm: false - isn: - sub_int_range: 2-511 - bootstrap: - enable_bootstrap: false - enable_inband: false - enable_local_dhcp_server: false - dhcp_version: DHCPv4 - enable_aaa: false - netflow: - enable: false + bfd: + enabled: false + disable_connected_check: false + remove_private_as: false + remove_private_as_all: false + ebgp_multihop: 2 + address_family_ipv4_unicast: + send_community: false + send_ext_community: false + allow_as_in: false + allow_as_in_number: 3 + as_override: false + route_reflector_client: false + default_originate: false + next_hop_self: false + address_family_ipv6_unicast: + send_community: false + send_ext_community: false + allow_as_in: false + allow_as_in_number: 3 + as_override: false + route_reflector_client: false + default_originate: false + next_hop_self: false + multisite: + enable_ipv6_underlay: false + anycast_gateway_mac: 20:20:00:00:00:aa + vtep_loopback_id: 100 + bgw_ip_tag: 54321 + ipv4_vtep_loopback_range: 10.10.0.0/24 + ipv6_vtep_loopback_range: fd00::a10:0/120 + overlay_dci: + deployment_method: Direct_To_BGWS + ipv4_dci_subnet_range: 10.10.1.0/24 + ipv4_dci_subnet_mask: 30 + ipv6_dci_subnet_range: fd00::a11:0/120 + ipv6_dci_subnet_mask: 126 + underlay_autoconfig: true + enable_bgp_send_community: false + enable_bgp_log_neighbor_change: false + enable_bgp_bfd: false + delay_restore: 300 + enable_ebgp_password: false + enable_trm: false + isn: + sub_int_range: 2-511 From 722be093cc477c918850179aba9c4ac61c023eac Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 28 Jan 2025 11:38:36 +0000 Subject: [PATCH 061/183] Corrected comment --- roles/dtc/create/tasks/mfd/fabric.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/create/tasks/mfd/fabric.yml b/roles/dtc/create/tasks/mfd/fabric.yml index 33aefe5a4..4f79802e6 100644 --- a/roles/dtc/create/tasks/mfd/fabric.yml +++ b/roles/dtc/create/tasks/mfd/fabric.yml @@ -44,7 +44,7 @@ fabricTechnology: "VXLANFabric" nvPairs: "{{ fabric_config }}" -- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (PUT) +- name: Manage fabric federated {{ MD_Extended.vxlan.fabric.name }} in NDFC (PUT) cisco.dcnm.dcnm_rest: method: PUT path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}' @@ -54,7 +54,7 @@ - get_result.response.RETURN_CODE == 200 register: put_result -- name: Manage fabric External {{ MD_Extended.vxlan.fabric.name }} in NDFC (POST) +- name: Manage fabric federated {{ MD_Extended.vxlan.fabric.name }} in NDFC (POST) cisco.dcnm.dcnm_rest: method: POST path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics' From b7c3f2881e8c21320f6626f30d24e542136f0518 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 28 Jan 2025 07:09:22 -0500 Subject: [PATCH 062/183] fix typo --- plugins/action/common/prepare_service_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/action/common/prepare_service_model.py b/plugins/action/common/prepare_service_model.py index c61764d31..2211b207e 100644 --- a/plugins/action/common/prepare_service_model.py +++ b/plugins/action/common/prepare_service_model.py @@ -86,7 +86,7 @@ def run(self, tmp=None, task_vars=None): results=results).prepare() if results.get('failed'): - # Check each plugin for failureds and break out of the loop early + # Check each plugin for failures and break out of the loop early # if a failure is encounterd. break From 3b0a95826abd40b3da417d1120153a1573baf535 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 28 Jan 2025 07:33:40 -0500 Subject: [PATCH 063/183] fix defaults --- roles/validate/files/defaults.yml | 547 +++++++++++++++--------------- 1 file changed, 273 insertions(+), 274 deletions(-) diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index fe8128033..41e02f66f 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -21,286 +21,285 @@ --- factory_defaults: - defaults: - vxlan: - global: - route_reflectors: 2 - anycast_gateway_mac: 20:20:00:00:00:aa - auth_proto: MD5 - vpc: - peer_link_vlan: 3600 - peer_keep_alive: management - auto_recovery_time: 360 - delay_restore_time: 150 - peer_link_port_channel_id: 500 - advertise_pip: false - advertise_pip_border_only: true - domain_id_range: 1-1000 - spanning_tree: - root_bridge_protocol: unmanaged - vlan_range: - - from: 1 - to: 3967 - mst_instance_range: - - from: 0 - to: 0 - bridge_priority: 0 - netflow: - enable: false - topology: - switches: - routing_loopback_id: 0 - vtep_loopback_id: 1 - interfaces: - topology_switch_access_interface: - description: "NetAsCode Access Interface" - mtu: jumbo - speed: auto - enabled: true - access_vlan: 1 - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_trunk_interface: - description: "NetAsCode Trunk Interface" - mtu: jumbo - speed: auto - enabled: true - trunk_allowed_vlans: none - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_access_po_interface: - description: "NetAsCode Access PO Interface" - mtu: jumbo - speed: auto - enabled: true - access_vlan: 1 - pc_mode: active - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_trunk_po_interface: - description: "NetAsCode Trunk PO Interface" - mtu: jumbo - speed: auto - enabled: true - trunk_allowed_vlans: none - pc_mode: active - spanning_tree_portfast: true - enable_bpdu_guard: true - topology_switch_routed_interface: - description: "NetAsCode Routed Interface" - mtu: 9216 - speed: auto - enabled: true - topology_switch_routed_sub_interface: - description: "NetAsCode Routed Sub Interface" - mtu: 9216 - speed: auto - enabled: true - topology_switch_routed_po_interface: - description: "NetAsCode Routed PO Interface" - mtu: 9216 - speed: auto - enabled: true - pc_mode: active - topology_switch_loopback_interface: - description: "NetAsCode Loopback Interface" - enabled: true - vpc_peers: - domain_id: 1 - fabric_links: - edge_connections: - underlay: - general: - routing_protocol: ospf - enable_ipv6_underlay: false - replication_mode: multicast - fabric_interface_numbering: p2p - subnet_mask: 30 - manual_underlay_allocation: false - underlay_routing_loopback_id: 0 - underlay_vtep_loopback_id: 1 - underlay_routing_protocol_tag: UNDERLAY - underlay_rp_loopback_id: 254 - intra_fabric_interface_mtu: 9216 - layer2_host_interfacde_mtu: 9216 - unshut_host_interfaces: true - ipv4: - underlay_routing_loopback_ip_range: 10.2.0.0/22 - underlay_vtep_loopback_ip_range: 10.3.0.0/22 - underlay_rp_loopback_ip_range: 10.254.254.0/24 - underlay_subnet_ip_range: 10.4.0.0/16 - ipv6: - enable_ipv6_link_local_address: true - underlay_subnet_mask: 126 + vxlan: + global: + route_reflectors: 2 + anycast_gateway_mac: 20:20:00:00:00:aa + auth_proto: MD5 + vpc: + peer_link_vlan: 3600 + peer_keep_alive: management + auto_recovery_time: 360 + delay_restore_time: 150 + peer_link_port_channel_id: 500 + advertise_pip: false + advertise_pip_border_only: true + domain_id_range: 1-1000 + spanning_tree: + root_bridge_protocol: unmanaged + vlan_range: + - from: 1 + to: 3967 + mst_instance_range: + - from: 0 + to: 0 + bridge_priority: 0 + netflow: + enable: false + topology: + switches: + routing_loopback_id: 0 + vtep_loopback_id: 1 + interfaces: + topology_switch_access_interface: + description: "NetAsCode Access Interface" + mtu: jumbo + speed: auto + enabled: true + access_vlan: 1 + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_trunk_interface: + description: "NetAsCode Trunk Interface" + mtu: jumbo + speed: auto + enabled: true + trunk_allowed_vlans: none + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_access_po_interface: + description: "NetAsCode Access PO Interface" + mtu: jumbo + speed: auto + enabled: true + access_vlan: 1 + pc_mode: active + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_trunk_po_interface: + description: "NetAsCode Trunk PO Interface" + mtu: jumbo + speed: auto + enabled: true + trunk_allowed_vlans: none + pc_mode: active + spanning_tree_portfast: true + enable_bpdu_guard: true + topology_switch_routed_interface: + description: "NetAsCode Routed Interface" + mtu: 9216 + speed: auto + enabled: true + topology_switch_routed_sub_interface: + description: "NetAsCode Routed Sub Interface" + mtu: 9216 + speed: auto + enabled: true + topology_switch_routed_po_interface: + description: "NetAsCode Routed PO Interface" + mtu: 9216 + speed: auto + enabled: true + pc_mode: active + topology_switch_loopback_interface: + description: "NetAsCode Loopback Interface" + enabled: true + vpc_peers: + domain_id: 1 + fabric_links: + edge_connections: + underlay: + general: + routing_protocol: ospf + enable_ipv6_underlay: false + replication_mode: multicast + fabric_interface_numbering: p2p + subnet_mask: 30 + manual_underlay_allocation: false + underlay_routing_loopback_id: 0 + underlay_vtep_loopback_id: 1 + underlay_routing_protocol_tag: UNDERLAY + underlay_rp_loopback_id: 254 + intra_fabric_interface_mtu: 9216 + layer2_host_interfacde_mtu: 9216 + unshut_host_interfaces: true + ipv4: + underlay_routing_loopback_ip_range: 10.2.0.0/22 + underlay_vtep_loopback_ip_range: 10.3.0.0/22 + underlay_rp_loopback_ip_range: 10.254.254.0/24 + underlay_subnet_ip_range: 10.4.0.0/16 + ipv6: + enable_ipv6_link_local_address: true + underlay_subnet_mask: 126 + ospf: + area_id: 0.0.0.0 + authentication_enable: false + authentication_key_id: 127 + isis: + level: level-2 + network_point_to_point: true + authentication_enable: false + authentication_key_id: 127 + overload_bit: true + overload_bit_elapsed_time: 60 + bgp: + authentication_enable: false + authentication_key_type: 3 + multicast: + group_subnet: 239.1.1.0/25 + rendezvous_points: 2 + rp_mode: asm + underlay_rp_loopback_id: 254 + trm_enable: false + trm_default_group: 239.1.1.0 + underlay_primary_rp_loopback_id: 2 + underlay_backup_rp_loopback_id: 3 + underlay_second_backup_rp_loopback_id: 4 + underlay_third_backup_rp_loopback_id: 5 + bfd: + enable: false + ibgp: false + ospf: false + pim: false + isis: false + authentication_enable: false + authentication_key_id: 100 + overlay: + vrfs: + vrf_description: "Configured by Ansible NetAsCode" + vrf_intf_desc: "Configured by Ansible NetAsCode" + vrf_int_mtu: 9216 + loopback_route_tag: 12345 + max_bgp_paths: 1 + max_ibgp_paths: 2 + ipv6_linklocal_enable: true + adv_host_routes: false + adv_default_routes: true + static_default_route: true + disable_rt_auto: false + netflow_enable: false + no_rp: false + rp_external: false + redist_direct_routemap: FABRIC-RMAP-REDIST-SUBNET + trm_enable: false + trm_bgw_msite: false + networks: + net_description: "Configured by Ansible NetAsCode" + is_l2_only: false + arp_supress: false + l3gw_on_border: false + mtu_l3intf: 9216 + multicast_group_address: 239.1.1.1 + netflow_enable: false + route_target_both: false + route_tag: 12345 + trm_enable: false + vrf_attach_groups: + switches: [] + network_attach_groups: + switches: [] + policy: + template_name: switch_freeform + priority: 500 + overlay_extensions: + vrf_lites: ospf: - area_id: 0.0.0.0 - authentication_enable: false - authentication_key_id: 127 - isis: - level: level-2 - network_point_to_point: true - authentication_enable: false - authentication_key_id: 127 - overload_bit: true - overload_bit_elapsed_time: 60 + areas: + area_type: standard + default_area: 0 + distance: 110 + bfd: + enabled: false + default_information_originate: + always: false + nssa: + default_information_originate: false + no_redistribution: false + no_summary: false + translate: + always: false + supress_fa: false + never: false bgp: - authentication_enable: false - authentication_key_type: 3 - multicast: - group_subnet: 239.1.1.0/25 - rendezvous_points: 2 - rp_mode: asm - underlay_rp_loopback_id: 254 - trm_enable: false - trm_default_group: 239.1.1.0 - underlay_primary_rp_loopback_id: 2 - underlay_backup_rp_loopback_id: 3 - underlay_second_backup_rp_loopback_id: 4 - underlay_third_backup_rp_loopback_id: 5 - bfd: - enable: false - ibgp: false - ospf: false - pim: false - isis: false - authentication_enable: false - authentication_key_id: 100 - overlay: - vrfs: - vrf_description: "Configured by Ansible NetAsCode" - vrf_intf_desc: "Configured by Ansible NetAsCode" - vrf_int_mtu: 9216 - loopback_route_tag: 12345 - max_bgp_paths: 1 - max_ibgp_paths: 2 - ipv6_linklocal_enable: true - adv_host_routes: false - adv_default_routes: true - static_default_route: true - disable_rt_auto: false - netflow_enable: false - no_rp: false - rp_external: false - redist_direct_routemap: FABRIC-RMAP-REDIST-SUBNET - trm_enable: false - trm_bgw_msite: false - networks: - net_description: "Configured by Ansible NetAsCode" - is_l2_only: false - arp_supress: false - l3gw_on_border: false - mtu_l3intf: 9216 - multicast_group_address: 239.1.1.1 - netflow_enable: false - route_target_both: false - route_tag: 12345 - trm_enable: false - vrf_attach_groups: - switches: [] - network_attach_groups: - switches: [] - policy: - template_name: switch_freeform - priority: 500 - overlay_extensions: - vrf_lites: - ospf: - areas: - area_type: standard - default_area: 0 - distance: 110 + best_path_as_path_relax: false + graceful_restart: true + graceful_restart_helper: false + address_family_ipv4_unicast: + additional_paths_receive: false + additional_paths_send: false + default_originate: false + ebgp_distance: 20 + ibgp_distance: 200 + local_distance: 220 + address_family_ipv6_unicast: + additional_paths_receive: false + additional_paths_send: false + default_originate: false + ebgp_distance: 20 + ibgp_distance: 200 + local_distance: 220 + switches: + interfaces: + ospf: + auth_type: none + auth_key_id: 0 + cost: 1 + passive_interface: false + mtu_ignore: false + advertise_subnet: false + bfd: + enabled: false + hello_interval: 10 + dead_interval: 40 + network_type: broadcast + priority: 1 + lsa_retransmit_interval: 5 + lsa_transmit_delay: 1 + bgp_peers: + next_hop_self: false bfd: enabled: false - default_information_originate: - always: false - nssa: - default_information_originate: false - no_redistribution: false - no_summary: false - translate: - always: false - supress_fa: false - never: false - bgp: - best_path_as_path_relax: false - graceful_restart: true - graceful_restart_helper: false + disable_connected_check: false + remove_private_as: false + remove_private_as_all: false + ebgp_multihop: 2 address_family_ipv4_unicast: - additional_paths_receive: false - additional_paths_send: false + send_community: false + send_ext_community: false + allow_as_in: false + allow_as_in_number: 3 + as_override: false + route_reflector_client: false default_originate: false - ebgp_distance: 20 - ibgp_distance: 200 - local_distance: 220 + next_hop_self: false address_family_ipv6_unicast: - additional_paths_receive: false - additional_paths_send: false + send_community: false + send_ext_community: false + allow_as_in: false + allow_as_in_number: 3 + as_override: false + route_reflector_client: false default_originate: false - ebgp_distance: 20 - ibgp_distance: 200 - local_distance: 220 - switches: - interfaces: - ospf: - auth_type: none - auth_key_id: 0 - cost: 1 - passive_interface: false - mtu_ignore: false - advertise_subnet: false - bfd: - enabled: false - hello_interval: 10 - dead_interval: 40 - network_type: broadcast - priority: 1 - lsa_retransmit_interval: 5 - lsa_transmit_delay: 1 - bgp_peers: next_hop_self: false - bfd: - enabled: false - disable_connected_check: false - remove_private_as: false - remove_private_as_all: false - ebgp_multihop: 2 - address_family_ipv4_unicast: - send_community: false - send_ext_community: false - allow_as_in: false - allow_as_in_number: 3 - as_override: false - route_reflector_client: false - default_originate: false - next_hop_self: false - address_family_ipv6_unicast: - send_community: false - send_ext_community: false - allow_as_in: false - allow_as_in_number: 3 - as_override: false - route_reflector_client: false - default_originate: false - next_hop_self: false - multisite: - enable_ipv6_underlay: false - anycast_gateway_mac: 20:20:00:00:00:aa - vtep_loopback_id: 100 - bgw_ip_tag: 54321 - ipv4_vtep_loopback_range: 10.10.0.0/24 - ipv6_vtep_loopback_range: fd00::a10:0/120 - overlay_dci: - deployment_method: Direct_To_BGWS - ipv4_dci_subnet_range: 10.10.1.0/24 - ipv4_dci_subnet_mask: 30 - ipv6_dci_subnet_range: fd00::a11:0/120 - ipv6_dci_subnet_mask: 126 - underlay_autoconfig: true - enable_bgp_send_community: false - enable_bgp_log_neighbor_change: false - enable_bgp_bfd: false - delay_restore: 300 - enable_ebgp_password: false - enable_trm: false - isn: - sub_int_range: 2-511 + multisite: + enable_ipv6_underlay: false + anycast_gateway_mac: 20:20:00:00:00:aa + vtep_loopback_id: 100 + bgw_ip_tag: 54321 + ipv4_vtep_loopback_range: 10.10.0.0/24 + ipv6_vtep_loopback_range: fd00::a10:0/120 + overlay_dci: + deployment_method: Direct_To_BGWS + ipv4_dci_subnet_range: 10.10.1.0/24 + ipv4_dci_subnet_mask: 30 + ipv6_dci_subnet_range: fd00::a11:0/120 + ipv6_dci_subnet_mask: 126 + underlay_autoconfig: true + enable_bgp_send_community: false + enable_bgp_log_neighbor_change: false + enable_bgp_bfd: false + delay_restore: 300 + enable_ebgp_password: false + enable_trm: false + isn: + sub_int_range: 2-511 From a0d2a08cf0e0810a4408ec5970a60ffa0b3b7ede Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 28 Jan 2025 08:28:14 -0500 Subject: [PATCH 064/183] refactor template groupings for vpc and vrf loopback --- ....yml => ndfc_vpc_fabric_peering_links.yml} | 2 +- ...peering.yml => ndfc_vpc_peering_pairs.yml} | 2 +- roles/dtc/common/tasks/sub_main_vxlan.yml | 4 +- roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml | 2 +- .../common/templates/ndfc_attach_networks.j2 | 6 +- .../dtc/common/templates/ndfc_attach_vrfs.j2 | 6 +- .../common/templates/ndfc_create_fabric.j2 | 347 ------------------ roles/dtc/common/templates/ndfc_fabric.j2 | 6 +- .../dtc/common/templates/ndfc_fabric_links.j2 | 3 +- roles/dtc/common/templates/ndfc_inventory.j2 | 6 +- .../ndfc_vpc_fabric_peering_links.j2} | 3 +- .../ndfc_vpc_peering_pairs.j2} | 3 +- .../ndfc_attach_vrfs_loopbacks.j2 | 3 + 13 files changed, 23 insertions(+), 370 deletions(-) rename roles/dtc/common/tasks/common/{ndfc_link_vpc_peering.yml => ndfc_vpc_fabric_peering_links.yml} (98%) rename roles/dtc/common/tasks/common/{ndfc_vpc_peering.yml => ndfc_vpc_peering_pairs.yml} (98%) delete mode 100644 roles/dtc/common/templates/ndfc_create_fabric.j2 rename roles/dtc/common/templates/{ndfc_links_vpc_peering.j2 => ndfc_vpc/ndfc_vpc_fabric_peering_links.j2} (92%) rename roles/dtc/common/templates/{ndfc_vpc_peering.j2 => ndfc_vpc/ndfc_vpc_peering_pairs.j2} (93%) rename roles/dtc/common/templates/{ => ndfc_vrfs}/ndfc_attach_vrfs_loopbacks.j2 (92%) diff --git a/roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml b/roles/dtc/common/tasks/common/ndfc_vpc_fabric_peering_links.yml similarity index 98% rename from roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml rename to roles/dtc/common/tasks/common/ndfc_vpc_fabric_peering_links.yml index 7a70e9825..30ea4ef8a 100644 --- a/roles/dtc/common/tasks/common/ndfc_link_vpc_peering.yml +++ b/roles/dtc/common/tasks/common/ndfc_vpc_fabric_peering_links.yml @@ -52,7 +52,7 @@ - name: Build Links for VPC Peering ansible.builtin.template: - src: ndfc_links_vpc_peering.j2 + src: ndfc_vpc/ndfc_vpc_fabric_peering_links.j2 dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost diff --git a/roles/dtc/common/tasks/common/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/common/ndfc_vpc_peering_pairs.yml similarity index 98% rename from roles/dtc/common/tasks/common/ndfc_vpc_peering.yml rename to roles/dtc/common/tasks/common/ndfc_vpc_peering_pairs.yml index 08fa07fc3..82b2fba90 100644 --- a/roles/dtc/common/tasks/common/ndfc_vpc_peering.yml +++ b/roles/dtc/common/tasks/common/ndfc_vpc_peering_pairs.yml @@ -52,7 +52,7 @@ - name: Build vPC Peering ansible.builtin.template: - src: ndfc_vpc_peering.j2 + src: ndfc_vpc/ndfc_vpc_peering_pairs.j2 dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index c12a059ce..b2e5b806b 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -57,14 +57,14 @@ # -------------------------------------------------------------------- - name: Build Intra Fabric Links From Template - ansible.builtin.import_tasks: common/ndfc_link_vpc_peering.yml + ansible.builtin.import_tasks: common/ndfc_vpc_fabric_peering_links.yml # -------------------------------------------------------------------- # Build vPC Peering parameter List From Template # -------------------------------------------------------------------- - name: Build vPC Peering Parameters - ansible.builtin.import_tasks: common/ndfc_vpc_peering.yml + ansible.builtin.import_tasks: common/ndfc_vpc_peering_pairs.yml # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template diff --git a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml index a7e492c95..b4ac10d1c 100644 --- a/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/vxlan/ndfc_vrfs.yml @@ -90,7 +90,7 @@ - name: Build VRFs Attach List From Template for loopback ansible.builtin.template: - src: ndfc_attach_vrfs_loopbacks.j2 + src: ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost diff --git a/roles/dtc/common/templates/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_attach_networks.j2 index 03088f882..3d0570203 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks.j2 @@ -1,7 +1,7 @@ --- -{#- This NDFC fabric networks data structure is auto-generated #} -{#- DO NOT EDIT MANUALLY #} - +# This NDFC fabric networks config data structure is auto-generated +# DO NOT EDIT MANUALLY +# {% set vxlan = MD_Extended.vxlan %} {% if vxlan.fabric.type == 'VXLAN_EVPN' %} diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index d7edcaf8f..3c4d3367a 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -1,7 +1,7 @@ --- -{#- This NDFC fabric vrfs config data structure is auto-generated #} -{#- DO NOT EDIT MANUALLY #} - +# This NDFC fabric VRFs config data structure is auto-generated +# DO NOT EDIT MANUALLY +# {% set vxlan = MD_Extended.vxlan %} {% if vxlan.fabric.type == 'VXLAN_EVPN' %} diff --git a/roles/dtc/common/templates/ndfc_create_fabric.j2 b/roles/dtc/common/templates/ndfc_create_fabric.j2 deleted file mode 100644 index 86daf61af..000000000 --- a/roles/dtc/common/templates/ndfc_create_fabric.j2 +++ /dev/null @@ -1,347 +0,0 @@ -{% import 'ndfc_utils.j2' as ndfc_utils with context %} ---- -# This NDFC fabric config data structure is auto-generated -# DO NOT EDIT MANUALLY -# -{% set vxlan = MD_Extended.vxlan %} -{% set global = vxlan.global %} -{% set underlay = vxlan.underlay | default({}) %} -{# ------------------------------------------------------ #} -{# Global Parameters #} -{# ------------------------------------------------------ #} -- FABRIC_NAME: {{ global.name }} - BGP_AS: {{ global.bgp_asn }} - FABRIC_TYPE: VXLAN_EVPN - OVERLAY_MODE: cli - DEPLOY: True - GRFIELD_DEBUG_FLAG: Enable - AAA_REMOTE_IP_ENABLED: False - ENABLE_FABRIC_VPC_DOMAIN_ID: False - RR_COUNT: {{ global.route_reflectors | default(defaults.vxlan.global.route_reflectors) }} - ANYCAST_GW_MAC: {{ global.anycast_gateway_mac | default(defaults.vxlan.global.anycast_gateway_mac) }} -{# ------------------------------------------------------ #} -{# Manageability Parameters #} -{# ------------------------------------------------------ #} -{% if global.dns_servers is defined and global.dns_servers %} -{% set dns_server_ips = [] %} -{% set dns_server_vrfs = [] %} -{% for dns in global.dns_servers %} -{% if dns.ip_address | string is defined and dns.ip_address %} -{% set dns_ip = dns.ip_address | string %} -{% set dns_server_ips = dns_server_ips.append(dns_ip) %} -{% endif %} -{% if dns.vrf | string is defined and dns.vrf %} -{% set dns_vrf = dns.vrf | string %} -{% set dns_server_vrfs = dns_server_vrfs.append(dns_vrf) %} -{% endif %} -{% endfor %} - DNS_SERVER_IP_LIST: {{ dns_server_ips | join(',') | default(omit) }} - DNS_SERVER_VRF: {{ dns_server_vrfs | join(',') | default(omit) }} -{% endif %} -{% if global.ntp_servers is defined and global.ntp_servers %} -{% set ntp_server_ips = [] %} -{% set ntp_server_vrfs = [] %} -{% for ntp in global.ntp_servers %} -{% if ntp.ip_address is defined and ntp.ip_address %} -{% set ntp_ip = ntp.ip_address | string %} -{% set ntp_server_ips = ntp_server_ips.append(ntp_ip) %} -{% endif %} -{% if ntp.vrf is defined and ntp.vrf %} -{% set ntp_vrf = ntp.vrf|string %} -{% set ntp_server_vrfs = ntp_server_vrfs.append(ntp_vrf) %} -{% endif %} -{% endfor %} - NTP_SERVER_IP_LIST: {{ ntp_server_ips | join(',') | default(omit) }} - NTP_SERVER_VRF: {{ ntp_server_vrfs | join(',') | default(omit) }} -{% endif %} -{% if global.syslog_servers is defined and global.syslog_servers %} -{% set syslog_server_ips = [] %} -{% set syslog_server_vrfs = [] %} -{% set syslog_server_sevs = [] %} -{% for syslog_server in global.syslog_servers %} -{% if syslog_server.ip_address is defined and syslog_server.ip_address %} -{% set syslog_server_ip = syslog_server.ip_address | string %} -{% set syslog_server_ips = syslog_server_ips.append(syslog_server_ip) %} -{% endif %} -{% if syslog_server.vrf is defined and syslog_server.vrf %} -{% set syslog_server_vrf = syslog_server.vrf | string %} -{% set syslog_server_vrfs = syslog_server_vrfs.append(syslog_server_vrf) %} -{% endif %} -{% if syslog_server.severity is defined and syslog_server.severity %} -{% set syslog_server_sev = syslog_server.severity %} -{% set syslog_server_sevs = syslog_server_sevs.append(syslog_server_sev) %} -{% endif %} -{% endfor %} - SYSLOG_SERVER_IP_LIST: {{ syslog_server_ips | join(',') | default(omit) }} -{% if syslog_server_ips is defined and syslog_server_ips %} - SYSLOG_SERVER_VRF: {{ syslog_server_vrfs | join(',') | default(omit) }} - SYSLOG_SEV: {{ syslog_server_sevs | join(',') | default(omit) }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# Bootstrap Parameters #} -{# ------------------------------------------------------ #} -{% if global.bootstrap is defined %} -{% if global.bootstrap.enable_bootstrap is defined and global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} - DHCP_ENABLE: {{ global.bootstrap.enable_local_dhcp_server }} - DHCP_IPV6_ENABLE: {{ global.bootstrap.dhcp_version }} - DHCP_START: {{ global.bootstrap.dhcp_v4.scope_start_address }} - DHCP_END: {{ global.bootstrap.dhcp_v4.scope_end_address }} - MGMT_GW: {{ global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} - MGMT_PREFIX: {{ global.bootstrap.dhcp_v4.mgmt_prefix }} - BOOTSTRAP_MULTISUBNET: {{ global.bootstrap.dhcp_v4.multi_subnet_scope }} -{% endif %} -{% if global.bootstrap.enable_bootstrap is defined and not global.bootstrap.enable_bootstrap %} - BOOTSTRAP_ENABLE: {{ global.bootstrap.enable_bootstrap }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# vPC Parameters #} -{# ------------------------------------------------------ #} - VPC_PEER_LINK_VLAN: {{ vxlan.global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} - VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} - VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} - VPC_DELAY_RESTORE_TIME: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_DOMAIN_ID_RANGE: {{ vxlan.global.vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} - VPC_DELAY_RESTORE: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} -{% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} - ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) }} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay General Parameters #} -{# ------------------------------------------------------ #} - ENABLE_SGT: false - ENABLE_PVLAN: false - BGP_LB_ID: {{ underlay.general.underlay_routing_loopback_id | default(defaults.vxlan.underlay.general.underlay_routing_loopback_id) }} - NVE_LB_ID: {{ underlay.general.underlay_vtep_loopback_id | default(defaults.vxlan.underlay.general.underlay_vtep_loopback_id) }} - FABRIC_MTU: {{ underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} - L2_HOST_INTF_MTU: {{ underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} - HOST_INTF_ADMIN_STATE: {{ underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} - FABRIC_INTERFACE_TYPE: {{ underlay.general.fabric_interface_numbering | default(defaults.vxlan.underlay.general.fabric_interface_numbering) }} - SUBNET_TARGET_MASK: {{ underlay.general.subnet_mask | default(defaults.vxlan.underlay.general.subnet_mask) }} - REPLICATION_MODE: {{ underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) | title }} -{% endif %} - LINK_STATE_ROUTING: {{ underlay.general.routing_protocol | default(defaults.vxlan.underlay.general.routing_protocol) }} - LINK_STATE_ROUTING_TAG: {{ underlay.general.underlay_routing_protocol_tag | default(defaults.vxlan.underlay.general.underlay_routing_protocol_tag) }} - UNDERLAY_IS_V6: {{ (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) }} - STATIC_UNDERLAY_IP_ALLOC: {{ (underlay.general.manual_underlay_allocation | default(defaults.vxlan.underlay.general.manual_underlay_allocation) | title)}} -{# ------------------------------------------------------ #} -{# Underlay Multicast Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) | title) == 'Multicast' %} - MULTICAST_GROUP_SUBNET: {{ underlay.multicast.group_subnet | default(defaults.vxlan.underlay.multicast.group_subnet) }} - RP_COUNT: {{ underlay.multicast.rendezvous_points | default(defaults.vxlan.underlay.multicast.rendezvous_points) }} - RP_MODE: {{ underlay.multicast.rp_mode | default(defaults.vxlan.underlay.multicast.rp_mode) }} - RP_LB_ID: {{ underlay.multicast.underlay_rp_loopback_id | default(defaults.vxlan.underlay.multicast.underlay_rp_loopback_id) }} - ENABLE_TRM: {{(underlay.multicast.trm_enable | default(defaults.vxlan.underlay.multicast.trm_enable) | title) }} -{% if (underlay.multicast.trm_enable | default(defaults.vxlan.underlay.multicast.trm_enable) | title) == 'True' %} - L3VNI_MCAST_GROUP: {{ underlay.multicast.trm_default_group | default(defaults.vxlan.underlay.multicast.trm_default_group) }} -{% endif %} -{% if underlay.multicast.rp_mode | default(defaults.vxlan.underlay.multicast.rp_mode) == 'bidir' %} - PHANTOM_RP_LB_ID1: {{ underlay.multicast.underlay_primary_rp_loopback_id | default(defaults.vxlan.underlay.multicast.underlay_primary_rp_loopback_id) }} - PHANTOM_RP_LB_ID2: {{ underlay.multicast.underlay_backup_rp_loopback_id | default(defaults.vxlan.underlay.multicast.underlay_backup_rp_loopback_id) }} -{% if underlay.multicast.rendezvous_points | default(defaults.vxlan.underlay.multicast.rendezvous_points) == 4 %} - PHANTOM_RP_LB_ID3: {{ underlay.multicast.underlay_second_backup_rp_loopback_id | default(defaults.vxlan.underlay.multicast.underlay_second_backup_rp_loopback_id) }} - PHANTOM_RP_LB_ID4: {{ underlay.multicast.underlay_third_backup_rp_loopback_id | default(defaults.vxlan.underlay.multicast.underlay_third_backup_rp_loopback_id) }} -{% endif %} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay ISIS Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.routing_protocol | default(defaults.vxlan.underlay.general.routing_protocol)) == 'is-is' %} - ISIS_LEVEL: {{ underlay.isis.level | default(defaults.vxlan.underlay.isis.level) }} - ISIS_AUTH_ENABLE: {{ (underlay.isis.authentication_enable | default(defaults.vxlan.underlay.isis.authentication_enable) | title) }} -{% if (underlay.isis.authentication_enable | default(defaults.vxlan.underlay.isis.authentication_enable) | title) == 'True' %} - ISIS_AUTH_KEYCHAIN_NAME: {{ underlay.isis.authentication_keychain_name | default(omit) }} - ISIS_AUTH_KEYCHAIN_KEY_ID: {{ underlay.isis.authentication_key_id | default(defaults.vxlan.underlay.isis.authentication_key_id) }} - ISIS_AUTH_KEY: {{ underlay.isis.authentication_key }} -{% endif %} - ISIS_OVERLOAD_ENABLE: {{ underlay.isis.overload_bit | default(defaults.vxlan.underlay.isis.overload_bit) }} -{% if (underlay.isis.overload_bit | default(defaults.vxlan.underlay.isis.overload_bit) | title) == 'True' %} - ISIS_OVERLOAD_ELAPSE_TIME: {{ underlay.isis.overload_bit_elapsed_time | default(defaults.vxlan.underlay.isis.overload_bit_elapsed_time) }} -{% endif %} - ISIS_P2P_ENABLE: {{ underlay.isis.network_point_to_point | default(defaults.vxlan.underlay.isis.network_point_to_point) }} -{% if (underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} - BFD_ISIS_ENABLE: {{ underlay.bfd.isis | default(defaults.vxlan.underlay.bfd.isis) }} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay OSPF Parameters #} -{# ------------------------------------------------------ #} -{% elif (underlay.general.routing_protocol | default(defaults.vxlan.underlay.general.routing_protocol)) == 'ospf' %} - OSPF_AREA_ID: {{ underlay.ospf.area_id | default(defaults.vxlan.underlay.ospf.area_id) }} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} - OSPF_AUTH_ENABLE: {{ (underlay.ospf.authentication_enable | default(defaults.vxlan.underlay.ospf.authentication_enable) | title) }} -{% endif %} -{% if (underlay.ospf.authentication_enable | default(defaults.vxlan.underlay.ospf.authentication_enable) | title) == 'True' %} - OSPF_AUTH_KEY_ID: {{ underlay.ospf.authentication_key_id | default(defaults.vxlan.underlay.ospf.authentication_key_id) }} - OSPF_AUTH_KEY: {{ underlay.ospf.authentication_key | default(omit) }} -{% endif %} -{% if (underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} - BFD_OSPF_ENABLE: {{ underlay.bfd.ospf | default(defaults.vxlan.underlay.bfd.ospf) }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay IPv4 Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.manual_underlay_allocation | default(defaults.vxlan.underlay.general.manual_underlay_allocation) | title) == 'False' %} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} - LOOPBACK0_IP_RANGE: {{ underlay.ipv4.underlay_routing_loopback_ip_range | default(defaults.vxlan.underlay.ipv4.underlay_routing_loopback_ip_range) }} - LOOPBACK1_IP_RANGE: {{ underlay.ipv4.underlay_vtep_loopback_ip_range | default(defaults.vxlan.underlay.ipv4.underlay_vtep_loopback_ip_range) }} - SUBNET_RANGE: {{ underlay.ipv4.underlay_subnet_ip_range | default(defaults.vxlan.underlay.ipv4.underlay_subnet_ip_range) }} -{% endif %} - ANYCAST_RP_IP_RANGE: {{ underlay.ipv4.underlay_rp_loopback_ip_range | default(defaults.vxlan.underlay.ipv4.underlay_rp_loopback_ip_range) }} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay IPv6 Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'True' %} - USE_LINK_LOCAL: {{ underlay.ipv6.enable_ipv6_link_local_address | default(defaults.vxlan.underlay.ipv6.enable_ipv6_link_local_address | title) }} -{% if (underlay.ipv6.enable_ipv6_link_local_address | default(defaults.vxlan.underlay.ipv6.enable_ipv6_link_local_address) | title) == 'False' %} - V6_SUBNET_TARGET_MASK: {{ underlay.ipv6.underlay_subnet_mask | default(defaults.vxlan.underlay.ipv6.underlay_subnet_mask) }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay BGP Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} - BGP_AUTH_ENABLE: {{ (underlay.bgp.authentication_enable | default(defaults.vxlan.underlay.bgp.authentication_enable) | title)}} -{% endif %} -{% if (underlay.bgp.authentication_enable | default(defaults.vxlan.underlay.bgp.authentication_enable) | title) == 'True' %} - BGP_AUTH_KEY_TYPE: {{ underlay.bgp.authentication_key_type | default(defaults.vxlan.underlay.bgp.authentication_key_type) }} - BGP_AUTH_KEY: {{ underlay.bgp.authentication_key | default(omit) }} -{% endif %} -{# ------------------------------------------------------ #} -{# Underlay BFD Parameters #} -{# ------------------------------------------------------ #} -{% if (underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'False' %} - BFD_ENABLE: {{ underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) }} -{% endif %} -{% if (underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} - BFD_IBGP_ENABLE: {{ underlay.bfd.ibgp | default(defaults.vxlan.underlay.bfd.ibgp) }} - BFD_PIM_ENABLE: {{ underlay.bfd.pim | default(defaults.vxlan.underlay.bfd.pim) }} - BFD_AUTH_ENABLE: {{ (underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title)}} -{% if (underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) == 'True' %} - BFD_AUTH_KEY: {{ underlay.bfd.authentication_key | default(omit) }} - BFD_AUTH_KEY_ID: {{ underlay.bfd.authentication_key_id | default(defaults.vxlan.underlay.bfd.authentication_key_id) }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# vPC Parameters #} -{# ------------------------------------------------------ #} - VPC_PEER_LINK_VLAN: {{ vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} - VPC_PEER_KEEP_ALIVE_OPTION: {{ vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} - VPC_AUTO_RECOVERY_TIME: {{ vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} - VPC_DELAY_RESTORE_TIME: {{ vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - VPC_PEER_LINK_PO: {{ vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_DOMAIN_ID_RANGE: {{ vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} - VPC_DELAY_RESTORE: {{ vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - ADVERTISE_PIP_BGP: {{ (vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} -{% if (vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} - ADVERTISE_PIP_ON_BORDER: {{ vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) }} -{% endif %} -{# ------------------------------------------------------ #} -{# STP Parameters #} -{# ------------------------------------------------------ #} -{# STP_ROOT_OPTION: {{ global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol) }} -{% if global.spanning_tree.root_bridge_protocol is defined and global.spanning_tree.root_bridge_protocol != 'unmanaged' %} -{% if (global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'rpvst+' %} - STP_VLAN_RANGE: {{ ndfc_utils.convert_ranges(global.spanning_tree.vlan_range, defaults.vxlan.global.spanning_tree.vlan_range) }} -{% elif (global.spanning_tree.root_bridge_protocol | default(defaults.vxlan.global.spanning_tree.root_bridge_protocol)) == 'mst' %} - MST_INSTANCE_RANGE: {{ ndfc_utils.convert_ranges(global.spanning_tree.mst_instance_range, defaults.vxlan.global.spanning_tree.mst_instance_range) }} -{% endif %} - STP_BRIDGE_PRIORITY: {{ global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} -{% endif %}#} -{# ------------------------------------------------------ #} -{# Manageability Parameters #} -{# ------------------------------------------------------ #} -{% if global.dns_servers is defined and global.dns_servers %} -{% set dns_server_ips = [] %} -{% set dns_server_vrfs = [] %} -{% for dns in global.dns_servers %} -{% if dns.ip_address | string is defined and dns.ip_address %} -{% set dns_ip = dns.ip_address | string %} -{% set dns_server_ips = dns_server_ips.append(dns_ip) %} -{% endif %} -{% if dns.vrf | string is defined and dns.vrf %} -{% set dns_vrf = dns.vrf | string %} -{% set dns_server_vrfs = dns_server_vrfs.append(dns_vrf) %} -{% endif %} -{% endfor %} - DNS_SERVER_IP_LIST: {{ dns_server_ips | join(',') | default(omit) }} - DNS_SERVER_VRF: {{ dns_server_vrfs | join(',') | default(omit) }} -{% endif %} -{% if global.ntp_servers is defined and global.ntp_servers %} -{% set ntp_server_ips = [] %} -{% set ntp_server_vrfs = [] %} -{% for ntp in global.ntp_servers %} -{% if ntp.ip_address is defined and ntp.ip_address %} -{% set ntp_ip = ntp.ip_address | string %} -{% set ntp_server_ips = ntp_server_ips.append(ntp_ip) %} -{% endif %} -{% if ntp.vrf is defined and ntp.vrf %} -{% set ntp_vrf = ntp.vrf|string %} -{% set ntp_server_vrfs = ntp_server_vrfs.append(ntp_vrf) %} -{% endif %} -{% endfor %} - NTP_SERVER_IP_LIST: {{ ntp_server_ips | join(',') | default(omit) }} - NTP_SERVER_VRF: {{ ntp_server_vrfs | join(',') | default(omit) }} -{% endif %} -{% if global.syslog_servers is defined and global.syslog_servers %} -{% set syslog_server_ips = [] %} -{% set syslog_server_vrfs = [] %} -{% set syslog_server_sevs = [] %} -{% for syslog_server in global.syslog_servers %} -{% if syslog_server.ip_address is defined and syslog_server.ip_address %} -{% set syslog_server_ip = syslog_server.ip_address | string %} -{% set syslog_server_ips = syslog_server_ips.append(syslog_server_ip) %} -{% endif %} -{% if syslog_server.vrf is defined and syslog_server.vrf %} -{% set syslog_server_vrf = syslog_server.vrf | string %} -{% set syslog_server_vrfs = syslog_server_vrfs.append(syslog_server_vrf) %} -{% endif %} -{% if syslog_server.severity is defined and syslog_server.severity %} -{% set syslog_server_sev = syslog_server.severity %} -{% set syslog_server_sevs = syslog_server_sevs.append(syslog_server_sev) %} -{% endif %} -{% endfor %} - SYSLOG_SERVER_IP_LIST: {{ syslog_server_ips | join(',') | default(omit) }} -{% if syslog_server_ips is defined and syslog_server_ips %} - SYSLOG_SERVER_VRF: {{ syslog_server_vrfs | join(',') | default(omit) }} - SYSLOG_SEV: {{ syslog_server_sevs | join(',') | default(omit) }} -{% endif %} -{% endif %} -{# ------------------------------------------------------ #} -{# Flow Monitor Parameters #} -{# ------------------------------------------------------ #} - ENABLE_NETFLOW: {{ global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} -{% if global.netflow.enable is defined and global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} -{% if global.netflow.exporter is defined %} -{% set exporter_dict = dict() %} -{% set _ = exporter_dict.update({ "NETFLOW_EXPORTER_LIST":[] }) %} -{% for e in global.netflow.exporter %} -{% set _ = exporter_dict["NETFLOW_EXPORTER_LIST"].append(dict(EXPORTER_NAME=e.name,IP=e.ip_address,VRF=e.vrf | default(""), SRC_IF_NAME=e.source_interface,UDP_PORT=e.udp_port)) %} -{% endfor %} - NETFLOW_EXPORTER_LIST: "{{ exporter_dict | tojson | replace('"', '\\"') }}" -{% endif %} -{% if global.netflow.record is defined %} -{% set record_dict = dict() %} -{% set _ = record_dict.update({ "NETFLOW_RECORD_LIST":[] }) %} -{% for r in global.netflow.record %} -{% set _ = record_dict["NETFLOW_RECORD_LIST"].append(dict(RECORD_NAME=r.name,RECORD_TEMPLATE =r.template,LAYER2_RECORD=r.layer2 | default(false) | string | lower)) %} -{% endfor %} - NETFLOW_RECORD_LIST: "{{ record_dict | tojson | replace('"', '\\"') }}" -{% endif %} -{% if global.netflow.monitor is defined %} -{% set monitor_dict = dict() %} -{% set _ = monitor_dict.update({ "NETFLOW_MONITOR_LIST":[] }) %} -{% for m in global.netflow.monitor %} -{% set _ = monitor_dict["NETFLOW_MONITOR_LIST"].append(dict(MONITOR_NAME=m.name,RECORD_NAME=m.record,EXPORTER1=m.exporter1,EXPORTER2=m.exporter2 | default(""))) %} -{% endfor %} - NETFLOW_MONITOR_LIST: "{{ monitor_dict | tojson | replace('"', '\\"') }}" -{% endif %} -{% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index ff5476780..9cb0152d2 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -1,7 +1,7 @@ --- -{#- This NDFC fabric config data structure is auto-generated #} -{#- DO NOT EDIT MANUALLY #} - +# This NDFC fabric config data structure is auto-generated +# DO NOT EDIT MANUALLY +# {% set vxlan = MD_Extended.vxlan %} {% if vxlan.fabric.type == 'VXLAN_EVPN' %} diff --git a/roles/dtc/common/templates/ndfc_fabric_links.j2 b/roles/dtc/common/templates/ndfc_fabric_links.j2 index 5fa064328..9c02086f8 100644 --- a/roles/dtc/common/templates/ndfc_fabric_links.j2 +++ b/roles/dtc/common/templates/ndfc_fabric_links.j2 @@ -1,8 +1,7 @@ --- -# This NDFC links for vPC Peering is auto-generated +# This NDFC fabric links config data structure is auto-generated # DO NOT EDIT MANUALLY # -#jinja2: trim_blocks: True, lstrip_blocks: False {% for link in MD_Extended.vxlan.topology.fabric_links %} - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" src_interface: "{{ link.source_interface }}" diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 1c11ea394..61a7cc58c 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -1,7 +1,7 @@ --- -{#- This NDFC fabric inventory config data structure is auto-generated #} -{#- DO NOT EDIT MANUALLY #} - +# This NDFC fabric inventory config data structure is auto-generated +# DO NOT EDIT MANUALLY +# {% set vxlan = MD_Extended.vxlan %} {% if vxlan.fabric.type == 'VXLAN_EVPN' %} diff --git a/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_fabric_peering_links.j2 similarity index 92% rename from roles/dtc/common/templates/ndfc_links_vpc_peering.j2 rename to roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_fabric_peering_links.j2 index d707b8b41..2abebf651 100644 --- a/roles/dtc/common/templates/ndfc_links_vpc_peering.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_fabric_peering_links.j2 @@ -1,8 +1,7 @@ --- -# This NDFC links for vPC Peering is auto-generated +# This NDFC config data that updates links for vPC Fabric Peering is auto-generated # DO NOT EDIT MANUALLY # -#jinja2: trim_blocks: True, lstrip_blocks: False {% for peers in MD_Extended.vxlan.topology.vpc_peers %} {% if peers['peer1_peerlink_interfaces'] is defined %} {% for interface_index in range(peers['peer1_peerlink_interfaces']|length) %} diff --git a/roles/dtc/common/templates/ndfc_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs.j2 similarity index 93% rename from roles/dtc/common/templates/ndfc_vpc_peering.j2 rename to roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs.j2 index 30418a7fc..fbd518267 100644 --- a/roles/dtc/common/templates/ndfc_vpc_peering.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs.j2 @@ -1,8 +1,7 @@ --- -# This NDFC vPC Peering config data structure is auto-generated +# This NDFC vPC Peering config data structure for vPC pairs is auto-generated # DO NOT EDIT MANUALLY # - {% if MD_Extended.vxlan.topology.vpc_peers is defined and MD_Extended.vxlan.topology.vpc_peers is not none %} {% for vpc_peer in MD_Extended.vxlan.topology.vpc_peers %} {% if MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv4_address is not none %} diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 b/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 similarity index 92% rename from roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 rename to roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 index 7b64ca088..e7d789b97 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 @@ -1,3 +1,6 @@ +# This NDFC VRF loopback config data structure is auto-generated +# DO NOT EDIT MANUALLY +# [ {% for vrf in MD_Extended.vxlan.overlay.vrfs %} {% if vrf['vrf_attach_group'] is defined %} From 650efef5968428a7c1d41455d356d9f90e1aaea3 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 28 Jan 2025 18:53:53 -0500 Subject: [PATCH 065/183] fix to isn fabric template --- .../prepare_plugins/prep_002_list_defaults.py | 2 -- .../bootstrap/isn_fabric_bootstrap.j2 | 24 +++++++++---------- .../flow_monitor/isn_fabric_flow_monitor.j2 | 16 ++++++------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py index 60a2ca5da..f8ea09de9 100644 --- a/plugins/action/common/prepare_plugins/prep_002_list_defaults.py +++ b/plugins/action/common/prepare_plugins/prep_002_list_defaults.py @@ -177,8 +177,6 @@ def prepare(self): # -------------------------------------------------------------------- # Fabric Global List Defaults # -------------------------------------------------------------------- - from pprint import pprint - fabric_type = self.model_data['vxlan']['fabric']['type'] # for path in paths: diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 index 73889b0b0..162627c2d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2 @@ -1,18 +1,18 @@ {# Auto-generated NDFC ISN Bootstrap config data structure for fabric {{ vxlan.fabric.name }} #} {# Most of these features are supported only on Cisco NX-OS switches #} {# Some of these features are supported only on Cisco Catalyst 9000 switches #} -{% if vxlan.multisite.isn.bootstrap is defined %} -{% if (vxlan.multisite.isn.bootstrap.enable_bootstrap is defined and vxlan.multisite.isn.bootstrap.enable_bootstrap | bool) or defaults.vxlan.multisite.isn.bootstrap.enable_bootstrap | bool %} - BOOTSTRAP_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_bootstrap | default(defaults.vxlan.multisite.isn.bootstrap.enable_bootstrap) | bool }} - INBAND_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_inband | default(defaults.vxlan.multisite.isn.bootstrap.enable_inband) | bool }} - DHCP_ENABLE: {{ vxlan.multisite.isn.bootstrap.enable_local_dhcp_server | default(defaults.vxlan.multisite.isn.bootstrap.enable_local_dhcp_server) | bool }} - DHCP_IPV6_ENABLE: {{ vxlan.multisite.isn.bootstrap.dhcp_version | default(defaults.vxlan.multisite.isn.bootstrap.dhcp_version) }} - DHCP_START: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.scope_start_address }} - DHCP_END: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.scope_end_address }} - MGMT_GW: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.switch_mgmt_default_gw }} - MGMT_PREFIX: {{ vxlan.multisite.isn.bootstrap.dhcp_v4.mgmt_prefix }} - BOOTSTRAP_MULTISUBNET: "{{ vxlan.multisite.isn.bootstrap.dhcp_v4.multi_subnet_scope }}" - ENABLE_AAA: {{ vxlan.multisite.isn.bootstrap.enable_aaa | default(defaults.vxlan.multisite.isn.bootstrap.enable_aaa) | bool }} +{% if vxlan.global.bootstrap is defined %} +{% if (vxlan.global.bootstrap.enable_bootstrap is defined and vxlan.global.bootstrap.enable_bootstrap | bool) or defaults.vxlan.global.bootstrap.enable_bootstrap | bool %} + BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap | default(defaults.vxlan.global.bootstrap.enable_bootstrap) | bool }} + INBAND_ENABLE: {{ vxlan.global.bootstrap.enable_inband | default(defaults.vxlan.global.bootstrap.enable_inband) | bool }} + DHCP_ENABLE: {{ vxlan.global.bootstrap.enable_local_dhcp_server | default(defaults.vxlan.global.bootstrap.enable_local_dhcp_server) | bool }} + DHCP_IPV6_ENABLE: {{ vxlan.global.bootstrap.dhcp_version | default(defaults.vxlan.global.bootstrap.dhcp_version) }} + DHCP_START: {{ vxlan.global.bootstrap.dhcp_v4.scope_start_address }} + DHCP_END: {{ vxlan.global.bootstrap.dhcp_v4.scope_end_address }} + MGMT_GW: {{ vxlan.global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} + MGMT_PREFIX: {{ vxlan.global.bootstrap.dhcp_v4.mgmt_prefix }} + BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" + ENABLE_AAA: {{ vxlan.global.bootstrap.enable_aaa | default(defaults.vxlan.global.bootstrap.enable_aaa) | bool }} {% endif %} {% else %} BOOTSTRAP_ENABLE: false diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 index 75e95771a..3dbcb883d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2 @@ -1,26 +1,26 @@ {# Auto-generated NDFC ISN Flow Monitor config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_NETFLOW: {{ vxlan.multisite.isn.netflow.enable | default(defaults.vxlan.multisite.isn.netflow.enable) }} -{% if vxlan.multisite.isn.netflow.enable is defined and vxlan.multisite.isn.netflow.enable | bool or defaults.vxlan.multisite.isn.netflow.enable | bool %} -{% if vxlan.multisite.isn.netflow.exporter is defined %} + ENABLE_NETFLOW: {{ vxlan.global.netflow.enable | default(defaults.vxlan.global.netflow.enable) }} +{% if vxlan.global.netflow.enable is defined and vxlan.global.netflow.enable | bool or defaults.vxlan.global.netflow.enable | bool %} +{% if vxlan.global.netflow.exporter is defined %} {% set exporter_dict = dict() %} {% set _ = exporter_dict.update({ "NETFLOW_EXPORTER_LIST":[] }) %} -{% for e in vxlan.multisite.isn.netflow.exporter %} +{% for e in vxlan.global.netflow.exporter %} {% set _ = exporter_dict["NETFLOW_EXPORTER_LIST"].append(dict(EXPORTER_NAME=e.name,IP=e.ip_address,VRF=e.vrf | default(""), SRC_IF_NAME=e.source_interface,UDP_PORT=e.udp_port)) %} {% endfor %} NETFLOW_EXPORTER_LIST: "{{ exporter_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if vxlan.multisite.isn.netflow.record is defined %} +{% if vxlan.global.netflow.record is defined %} {% set record_dict = dict() %} {% set _ = record_dict.update({ "NETFLOW_RECORD_LIST":[] }) %} -{% for r in vxlan.multisite.isn.netflow.record %} +{% for r in vxlan.global.netflow.record %} {% set _ = record_dict["NETFLOW_RECORD_LIST"].append(dict(RECORD_NAME=r.name,RECORD_TEMPLATE =r.template,LAYER2_RECORD=r.layer2 | default(false) | string | lower)) %} {% endfor %} NETFLOW_RECORD_LIST: "{{ record_dict | tojson | replace('"', '\\"') }}" {% endif %} -{% if vxlan.multisite.isn.netflow.monitor is defined %} +{% if vxlan.global.netflow.monitor is defined %} {% set monitor_dict = dict() %} {% set _ = monitor_dict.update({ "NETFLOW_MONITOR_LIST":[] }) %} -{% for m in vxlan.multisite.isn.netflow.monitor %} +{% for m in vxlan.global.netflow.monitor %} {% set _ = monitor_dict["NETFLOW_MONITOR_LIST"].append(dict(MONITOR_NAME=m.name,RECORD_NAME=m.record,EXPORTER1=m.exporter1,EXPORTER2=m.exporter2 | default(""))) %} {% endfor %} NETFLOW_MONITOR_LIST: "{{ monitor_dict | tojson | replace('"', '\\"') }}" From 3c9cc02add8c939d74a6ad2c6c0fca65418ae16d Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Tue, 28 Jan 2025 22:33:36 -0500 Subject: [PATCH 066/183] get fabric attributes, fix msd templates, & start work on mapping switch to fabric --- plugins/action/dtc/manage_child_fabrics.py | 8 +++++ plugins/action/dtc/map_msd_inventory.py | 3 ++ plugins/plugin_utils/helper_functions.py | 30 +++++++++++++++++++ .../msd_fabric/dci/msd_fabric_dci.j2 | 22 +++++++------- .../msd_fabric/general/msd_fabric_general.j2 | 2 +- .../resources/msd_fabric_resources.j2 | 10 +++---- 6 files changed, 58 insertions(+), 17 deletions(-) diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index 11f59bde0..80e47d02f 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -26,6 +26,7 @@ from ansible.utils.display import Display from ansible.plugins.action import ActionBase +from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes display = Display() @@ -36,6 +37,7 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False results['child_fabrics_moved'] = False + results['child_fabric_attributes'] = {} fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') parent_fabric_name = self._task.args['parent_fabric_name'] @@ -48,6 +50,8 @@ def run(self, tmp=None, task_vars=None): if fabric.get('fabricParent') == parent_fabric_name: associated_child_fabrics.append(fabric.get('fabricName')) + results['child_fabric_attributes'][fabric['fabricName']] = ndfc_get_fabric_attributes(self, task_vars, tmp, fabric['fabricName']) + if operation == 'add': for fabric in child_fabrics: if fabric.get('name') not in associated_child_fabrics: @@ -78,6 +82,8 @@ def run(self, tmp=None, task_vars=None): results['changed'] = True + results['child_fabric_attributes'][fabric] = ndfc_get_fabric_attributes(self, task_vars, tmp, fabric) + if operation == 'remove': for associated_child_fabric in associated_child_fabrics: if not any(associated_child_fabric == child_fabric['name'] for child_fabric in child_fabrics): @@ -100,6 +106,8 @@ def run(self, tmp=None, task_vars=None): results['changed'] = True + results['child_fabric_attributes'].pop(associated_child_fabric) + return results diff --git a/plugins/action/dtc/map_msd_inventory.py b/plugins/action/dtc/map_msd_inventory.py index e317ad246..64cc973c6 100644 --- a/plugins/action/dtc/map_msd_inventory.py +++ b/plugins/action/dtc/map_msd_inventory.py @@ -60,6 +60,9 @@ def run(self, tmp=None, task_vars=None): for switch in response: msd_switches.update({switch['hostName']: switch['ipAddress']}) msd_switches.update({switch['ipAddress']: switch['ipAddress']}) + msd_switches.update({switch['fabricName']: switch['fabricName']}) + + import epdb; epdb.st() # Cross reference msd_switches with the switches defined in # VRF and Network attach list. diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index bc632aae7..3b123e9dc 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -164,3 +164,33 @@ def ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, switch_serial_nu ] return policy_match + +def ndfc_get_fabric_attributes(self, task_vars, tmp, fabric): + """ + Get NDFC fabric attributes. + + :Parameters: + :self: Ansible action plugin instance object. + :task_vars (dict): Ansible task vars. + :tmp (None, optional): Ansible tmp object. Defaults to None via Action Plugin. + :fabric (str): The fabric name to be retrieved. + + :Returns: + :fabric_attributes: The NDFC fabric attributes data for the given fabric. + + :Raises: + N/A + """ + fabric_response = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}", + }, + task_vars=task_vars, + tmp=tmp + ) + + fabric_attributes = fabric_response['response']['DATA']['nvPairs'] + + return fabric_attributes diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 index 8867c1525..0811c7739 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/dci/msd_fabric_dci.j2 @@ -1,14 +1,14 @@ {# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.fabric.name }} #} - BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} - MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} -{% if vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) %} - ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} - ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) | lower }} - ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} + BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_dci.deployment_method | default(defaults.vxlan.multisite.overlay_dci.deployment_method) }} + MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.overlay_dci.underlay_autoconfig | default(defaults.vxlan.multisite.overlay_dci.underlay_autoconfig) }} +{% if (vxlan.multisite.overlay_dci.underlay_autoconfig | default(defaults.vxlan.multisite.overlay_dci.underlay_autoconfig) | ansible.builtin.bool) is sameas false %} + ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.overlay_dci.enable_bgp_send_community | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_send_community) }} + ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.overlay_dci.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_log_neighbor_change) | lower }} + ENABLE_BGP_BFD: {{ vxlan.multisite.overlay_dci.enable_bgp_bfd | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_bfd) }} {% endif %} - DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} - MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) }} -{% if vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) %} - MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.ebgp_password }} - MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.ebgp_password_encryption_type | default(defaults.vxlan.multisite.ebgp_password_encryption_type) }} + DELAY_RESTORE: {{ vxlan.multisite.overlay_dci.delay_restore | default(defaults.vxlan.multisite.overlay_dci.delay_restore) }} + MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.overlay_dci.enable_ebgp_password | default(defaults.vxlan.multisite.overlay_dci.enable_ebgp_password) }} +{% if vxlan.multisite.overlay_dci.enable_ebgp_password | default(defaults.vxlan.multisite.overlay_dci.enable_ebgp_password) %} + MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.overlay_dci.ebgp_password }} + MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.overlay_dci.ebgp_password_encryption_type }} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 index a593cfa1f..e9c31188d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/general/msd_fabric_general.j2 @@ -1,6 +1,6 @@ {# Auto-generated NDFC MSD General config data structure for fabric {{ vxlan.fabric.name }} #} VXLAN_UNDERLAY_IS_V6: {{ vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) }} -{% if not vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) %} +{% if (vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) | ansible.builtin.bool) is sameas false %} ENABLE_PVLAN: false {% endif %} ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index dc5d0db36..d713b60b3 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -1,10 +1,10 @@ {# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.fabric.name }} #} -{% if not defaults.vxlan.multisite.enable_ipv6_underlay %} +{% if (vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) | ansible.builtin.bool) is sameas false %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} - DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} - DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }} + DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_range) }} + DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask) }} {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} - V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} - V6_DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.ipv6_dci_subnet_mask) }} + V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv6_dci_subnet_range) }} + V6_DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.overlay_dci.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.overlay_dci.ipv6_dci_subnet_mask) }} {% endif %} \ No newline at end of file From 0ef58cd09f2804dbfb10dd42d6681603dd8bc852 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Wed, 29 Jan 2025 06:21:44 -0500 Subject: [PATCH 067/183] fix errors --- plugins/action/dtc/map_msd_inventory.py | 2 -- plugins/plugin_utils/helper_functions.py | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/action/dtc/map_msd_inventory.py b/plugins/action/dtc/map_msd_inventory.py index 64cc973c6..cdc46a268 100644 --- a/plugins/action/dtc/map_msd_inventory.py +++ b/plugins/action/dtc/map_msd_inventory.py @@ -62,8 +62,6 @@ def run(self, tmp=None, task_vars=None): msd_switches.update({switch['ipAddress']: switch['ipAddress']}) msd_switches.update({switch['fabricName']: switch['fabricName']}) - import epdb; epdb.st() - # Cross reference msd_switches with the switches defined in # VRF and Network attach list. # diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index 3b123e9dc..233163be3 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -165,6 +165,7 @@ def ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, switch_serial_nu return policy_match + def ndfc_get_fabric_attributes(self, task_vars, tmp, fabric): """ Get NDFC fabric attributes. From 938458d42deb7a11d994013acc2d965f7654446f Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 30 Jan 2025 08:01:59 -0500 Subject: [PATCH 068/183] refactor msite build for preprocessing for vrfs/networks attachments --- .../common/prepare_plugins/prep_001_fabric.py | 1 - plugins/action/dtc/manage_child_fabrics.py | 129 +++++++------- plugins/action/dtc/prepare_msite.py | 157 ++++++++++++++++++ plugins/plugin_utils/helper_functions.py | 38 +++++ ...fc_children.yml => ndfc_child_fabrics.yml} | 12 +- roles/dtc/common/tasks/sub_main_msd.yml | 20 +-- .../resources/msd_fabric_resources.j2 | 2 +- .../ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 | 13 +- roles/dtc/create/tasks/msd/child_fabrics.yml | 47 ++++-- roles/dtc/remove/tasks/msd/child_fabrics.yml | 10 +- 10 files changed, 326 insertions(+), 103 deletions(-) create mode 100644 plugins/action/dtc/prepare_msite.py rename roles/dtc/common/tasks/msd/{ndfc_children.yml => ndfc_child_fabrics.yml} (71%) diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 8dfd709b7..bdd5a71a9 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -122,7 +122,6 @@ def prepare(self): # For backwards compatibility, replace 'overlay_services' key with 'overlay' # NOTE: No prepare plugin, jinja2 template or ansible task should reference 'overlay_services' after this replacement. # NOTE: Rules are different since rules run BEFORE prepare plugins - # import epdb ; epdb.set_trace() parent_keys = ['vxlan', 'overlay_services'] dm_check = data_model_key_check(model_data, parent_keys) if 'overlay_services' in dm_check['keys_found']: diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index 80e47d02f..d3a81c504 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -27,6 +27,7 @@ from ansible.utils.display import Display from ansible.plugins.action import ActionBase from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes +from ...plugin_utils.helper_functions import ndfc_get_fabric_switches display = Display() @@ -37,76 +38,76 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False results['child_fabrics_moved'] = False - results['child_fabric_attributes'] = {} + # results['associated_child_fabrics'] = [] - fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') - parent_fabric_name = self._task.args['parent_fabric_name'] + # fabric_associations = self._task.args['fabric_associations'].get('response').get('DATA') + parent_fabric = self._task.args['parent_fabric'] child_fabrics = self._task.args['child_fabrics'] - operation = self._task.args['operation'] + state = self._task.args['state'] # Build a list of child fabrics that are associated with the parent fabric - associated_child_fabrics = [] - for fabric in fabric_associations: - if fabric.get('fabricParent') == parent_fabric_name: - associated_child_fabrics.append(fabric.get('fabricName')) + # associated_child_fabrics = [] + # for fabric in fabric_associations: + # if fabric.get('fabricParent') == parent_fabric_name: + # associated_child_fabrics.append(fabric.get('fabricName')) - results['child_fabric_attributes'][fabric['fabricName']] = ndfc_get_fabric_attributes(self, task_vars, tmp, fabric['fabricName']) - - if operation == 'add': + if state == 'present': + for fabric in child_fabrics: + # if fabric.get('name') not in associated_child_fabrics: + json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric, fabric) + add_fabric_result = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "POST", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", + "json_data": json_data + }, + task_vars=task_vars, + tmp=tmp + ) + + if add_fabric_result.get('failed'): + results['failed'] = True + results['msg'] = f"{add_fabric_result['msg']['MESSAGE']}: {add_fabric_result['msg']['DATA']}" + break + + # If a child fabric is successfully added under an MSD fabric set a flag + # indicating this so that it can be used later to prevent managing VRFs + # and Networks. If we dont prevent this then the VRFs and Networks could + # be removed as part of moving the child fabric. + # + # TBD: This flag is not actually being used currently. Discuss with team. + results['child_fabrics_moved'] = True + + results['changed'] = True + + # associated_child_fabrics.append(fabric['name']) + + if state == 'absent': for fabric in child_fabrics: - if fabric.get('name') not in associated_child_fabrics: - json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, fabric.get('name')) - add_fabric_result = self._execute_module( - module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "POST", - "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd", - "json_data": json_data - }, - task_vars=task_vars, - tmp=tmp - ) - - if add_fabric_result.get('failed'): - results['failed'] = True - results['msg'] = f"{add_fabric_result['msg']['MESSAGE']}: {add_fabric_result['msg']['DATA']}" - break - - # If a child fabric is successfully added under an MSD fabric set a flag - # indicating this so that it can be used later to prevent managing VRFs - # and Networks. If we dont prevent this then the VRFs and Networks could - # be removed as part of moving the child fabric. - # - # TBD: This flag is not actually being used currently. Discuss with team. - results['child_fabrics_moved'] = True - - results['changed'] = True - - results['child_fabric_attributes'][fabric] = ndfc_get_fabric_attributes(self, task_vars, tmp, fabric) - - if operation == 'remove': - for associated_child_fabric in associated_child_fabrics: - if not any(associated_child_fabric == child_fabric['name'] for child_fabric in child_fabrics): - json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric_name, associated_child_fabric) - remove_fabric_result = self._execute_module( - module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "POST", - "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit", - "json_data": json_data - }, - task_vars=task_vars, - tmp=tmp - ) - - if remove_fabric_result.get('failed'): - results['failed'] = True - results['msg'] = f"{remove_fabric_result['msg']['MESSAGE']}: {remove_fabric_result['msg']['DATA']}" - break - - results['changed'] = True - - results['child_fabric_attributes'].pop(associated_child_fabric) + # if not any(associated_child_fabric == child_fabric['name'] for child_fabric in child_fabrics): + json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric, fabric) + remove_fabric_result = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "POST", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit", + "json_data": json_data + }, + task_vars=task_vars, + tmp=tmp + ) + + if remove_fabric_result.get('failed'): + results['failed'] = True + results['msg'] = f"{remove_fabric_result['msg']['MESSAGE']}: {remove_fabric_result['msg']['DATA']}" + break + + results['changed'] = True + + # results['associated_child_fabrics'].pop(associated_child_fabric) + + # results['associated_child_fabrics'] = associated_child_fabrics return results diff --git a/plugins/action/dtc/prepare_msite.py b/plugins/action/dtc/prepare_msite.py new file mode 100644 index 000000000..557486a44 --- /dev/null +++ b/plugins/action/dtc/prepare_msite.py @@ -0,0 +1,157 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase +from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes +from ...plugin_utils.helper_functions import ndfc_get_fabric_switches + +display = Display() + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + results['failed'] = False + results['md_msite'] = {} + + model_data = self._task.args["model_data"] + parent_fabric = self._task.args["parent_fabric"] + child_fabrics = self._task.args["child_fabrics"] + + # This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD + # Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD) + msd_fabric_associations = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", + }, + task_vars=task_vars, + tmp=tmp + ) + + # Build a list of child fabrics that are associated with the parent fabric (MSD) + associated_child_fabrics = [] + for fabric in msd_fabric_associations.get('response').get('DATA'): + if fabric.get('fabricParent') == parent_fabric: + associated_child_fabrics.append(fabric.get('fabricName')) + + # Can probably remove this as I don't think it will be used + results['current_associated_child_fabrics'] = associated_child_fabrics + + # Build a list of child fabrics that are to be removed from the parent fabric (MSD) + child_fabrics_list = [child_fabric['name'] for child_fabric in child_fabrics] + child_fabrics_to_be_removed = [] + child_fabric_to_be_removed = [fabric for fabric in associated_child_fabrics if fabric not in child_fabrics_list] + child_fabrics_to_be_removed = child_fabrics_to_be_removed + child_fabric_to_be_removed + + results['child_fabrics_to_be_removed'] = child_fabrics_to_be_removed + + # Build a list of desired child fabrics that are not associated with the parent fabric (MSD) + child_fabrics_to_be_associated = [] + for fabric in child_fabrics: + if fabric.get('name') not in associated_child_fabrics: + child_fabrics_to_be_associated.append(fabric.get('name')) + + results['child_fabrics_to_be_associated'] = child_fabrics_to_be_associated + + # Merge the lists of currently associated child fabrics and child fabrics to be associated + # The assumption here is that the child fabric(s) that will be associated with the parent fabric (MSD) + # in the create role will either be sucessful and we have the prepared data to work with or + # the association will fail, resulting in runtime execution stopping, thus it doens't matter what prepared data we have. + associated_child_fabrics = associated_child_fabrics + child_fabrics_to_be_associated + + # Can probably remove this as I don't think it will be used + results['end_state_associated_child_fabrics'] = associated_child_fabrics + + child_fabrics_data = {} + for fabric in associated_child_fabrics: + child_fabrics_data.update({fabric: {}}) + child_fabrics_data[fabric].update({'attributes': ndfc_get_fabric_attributes(self, task_vars, tmp, fabric)}) + child_fabrics_data[fabric].update({'switches': ndfc_get_fabric_switches(self, task_vars, tmp, fabric)}) + + results['child_fabrics_data'] = child_fabrics_data + + # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into + # a structure that is easier to use just like MD_Extended. + vrf_grp_name_list = [] + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'] = {} + model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'] = [] + for grp in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] + vrf_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']]: + for child_fabric in child_fabrics_data.keys(): + for sw in child_fabrics_data[child_fabric]['switches']: + if switch['hostname'] == sw['hostname']: + switch['mgmt_ip_address'] = sw['mgmt_ip_address'] + + # Append switch to a flat list of switches for cross comparison later when we query the + # MSD fabric information. We need to stop execution if the list returned by the MSD query + # does not include one of these switches. + model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'].append(switch['hostname']) + + # Remove vrf_attach_group from vrf if the group_name is not defined + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: + if 'vrf_attach_group' in vrf: + if vrf.get('vrf_attach_group') not in vrf_grp_name_list: + del vrf['vrf_attach_group'] + + # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into + # a structure that is easier to use. + net_grp_name_list = [] + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'] = {} + model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'] = [] + for grp in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']] = [] + net_grp_name_list.append(grp['name']) + for switch in grp['switches']: + model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) + # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP + for switch in model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']]: + for child_fabric in child_fabrics_data.keys(): + for sw in child_fabrics_data[child_fabric]['switches']: + if switch['hostname'] == sw['hostname']: + switch['mgmt_ip_address'] = sw['mgmt_ip_address'] + # Append switch to a flat list of switches for cross comparison later when we query the + # MSD fabric information. We need to stop execution if the list returned by the MSD query + # does not include one of these switches. + model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'].append(switch['hostname']) + + # Remove network_attach_group from net if the group_name is not defined + for net in model_data['vxlan']['multisite']['overlay']['networks']: + if 'network_attach_group' in net: + if net.get('network_attach_group') not in net_grp_name_list: + del net['network_attach_group'] + + results['overlay_attach_groups'] = model_data['vxlan']['multisite']['overlay'] + + return results diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index 233163be3..7115e9d6a 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -195,3 +195,41 @@ def ndfc_get_fabric_attributes(self, task_vars, tmp, fabric): fabric_attributes = fabric_response['response']['DATA']['nvPairs'] return fabric_attributes + + +def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): + """ + Get NDFC fabric switches. + + :Parameters: + :self: Ansible action plugin instance object. + :task_vars (dict): Ansible task vars. + :tmp (None, optional): Ansible tmp object. Defaults to None via Action Plugin. + :fabric (str): The fabric name to be retrieved. + + :Returns: + :fabric_switches: The NDFC fabric switches data for the given fabric. + + :Raises: + N/A + """ + fabric_response = self._execute_module( + module_name="cisco.dcnm.dcnm_inventory", + module_args={ + "fabric": fabric, + "state": "query" + }, + task_vars=task_vars, + tmp=tmp + ) + + fabric_switches = [] + for fabric_switch in fabric_response['response']: + fabric_switches.append( + { + 'hostname': fabric_switch['hostName'], + 'mgmt_ip_address': fabric_switch['ipAddress'] + } + ) + + return fabric_switches diff --git a/roles/dtc/common/tasks/msd/ndfc_children.yml b/roles/dtc/common/tasks/msd/ndfc_child_fabrics.yml similarity index 71% rename from roles/dtc/common/tasks/msd/ndfc_children.yml rename to roles/dtc/common/tasks/msd/ndfc_child_fabrics.yml index 5ffba9e37..19eae49dc 100644 --- a/roles/dtc/common/tasks/msd/ndfc_children.yml +++ b/roles/dtc/common/tasks/msd/ndfc_child_fabrics.yml @@ -18,4 +18,14 @@ # - Create VXLAN / ISN Fabrics then MSD Fabric + Association # - Create MSD Fabric then VXLAN / ISN Fabrics + Association # - VRF / Network problem when child fabrics moved under MSD but MSD level VRF/Net model data is empty -# (Result is all VRF/Networks are removed after they get moved under MSD - can be controlled with flag) \ No newline at end of file +# (Result is all VRF/Networks are removed after they get moved under MSD - can be controlled with flag) + +- name: Prepare Multisite Data + cisco.nac_dc_vxlan.dtc.prepare_msite: + model_data: "{{ MD_Extended }}" + parent_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" + when: + - MD_Extended.vxlan.multisite.child_fabrics is defined + - MD_Extended.vxlan.multisite.child_fabrics + register: MD_Msite diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 5ea45ee70..d0eebb26d 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -50,19 +50,19 @@ # -------------------------------------------------------------------- - name: Build NDFC Child Fabric Inventory List From Template - ansible.builtin.import_tasks: msd/ndfc_children.yml + ansible.builtin.import_tasks: msd/ndfc_child_fabrics.yml -- name: Get Switch Inventory from MSD Fabric - cisco.nac_dc_vxlan.dtc.map_msd_inventory: - parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" - model_data_overlay: "{{ MD_Extended.vxlan.multisite.overlay }}" - register: msd_inventory +# - name: Get Switch Inventory from MSD Fabric +# cisco.nac_dc_vxlan.dtc.map_msd_inventory: +# parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" +# model_data_overlay: "{{ MD_Extended.vxlan.multisite.overlay }}" +# register: msd_inventory -- name: Set MSD Switches List - ansible.builtin.set_fact: - msd_switches: "{{ msd_inventory.msd_switches }}" +# - name: Set MSD Switches List +# ansible.builtin.set_fact: +# msd_switches: "{{ msd_inventory.msd_switches }}" -- debug: msg="{{ msd_switches }}" +# - debug: msg="{{ msd_switches }}" # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template diff --git a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 index d713b60b3..496f07d89 100644 --- a/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/msd_fabric/resources/msd_fabric_resources.j2 @@ -2,7 +2,7 @@ {% if (vxlan.multisite.enable_ipv6_underlay | default(defaults.vxlan.multisite.enable_ipv6_underlay) | ansible.builtin.bool) is sameas false %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_range) }} - DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask) }} + DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask) }} {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv6_dci_subnet_range) }} diff --git a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 index 1eb61cbc9..2531665f4 100644 --- a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2 @@ -1,6 +1,7 @@ {# Auto-generated NDFC MSD VRFs config data structure for fabric {{ vxlan.fabric.name }} #} {% if MD_Extended.vxlan.multisite.overlay.vrfs is defined and MD_Extended.vxlan.multisite.overlay.vrfs %} {% set vrfs = MD_Extended.vxlan.multisite.overlay.vrfs %} +{# This else block may not be needed after the prepare plugin work #} {% else %} {% set vrfs = [] %} {% endif %} @@ -28,18 +29,14 @@ {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} -{# Don't need to attach vrfs if there are no msd_switches #} -{% if msd_switches|length > 0 %} {% if vrf['vrf_attach_group'] is defined %} attach: -{% if MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict is defined and MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict %} -{% set vrf_attach_groups_dict = MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict %} +{% if MD_Msite.overlay_attach_groups.vrf_attach_groups_dict is defined and MD_Msite.overlay_attach_groups.vrf_attach_groups_dict %} +{% set vrf_attach_groups_dict = MD_Msite.overlay_attach_groups.vrf_attach_groups_dict %} {% endif %} {% for attach in vrf_attach_groups_dict[vrf['vrf_attach_group']] %} - - ip_address: {{ msd_switches[attach['hostname']] }} + - ip_address: {{ attach['mgmt_ip_address'] }} {% endfor %} - deploy: false -{% endif %} {% endif %} - + deploy: false {% endfor %} diff --git a/roles/dtc/create/tasks/msd/child_fabrics.yml b/roles/dtc/create/tasks/msd/child_fabrics.yml index a3129cf57..6e05df967 100644 --- a/roles/dtc/create/tasks/msd/child_fabrics.yml +++ b/roles/dtc/create/tasks/msd/child_fabrics.yml @@ -28,20 +28,41 @@ - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Get Fabric Association Data from NDFC - cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations - register: fabric_associations +# - name: Get Fabric Association Data from NDFC +# cisco.dcnm.dcnm_rest: +# method: GET +# path: /appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations +# register: fabric_associations -- ansible.builtin.debug: - var: fabric_associations +# - ansible.builtin.debug: +# var: fabric_associations - name: Add Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} cisco.nac_dc_vxlan.dtc.manage_child_fabrics: - fabric_associations: "{{ fabric_associations }}" - parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" - child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" - operation: add - when: fabric_associations is defined and fabric_associations - register: fabric_move_result + parent_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + child_fabrics: "{{ MD_Msite.child_fabrics_to_be_associated }}" + state: present + when: + - MD_Msite.child_fabrics_to_be_associated is defined + - MD_Msite.child_fabrics_to_be_associated + # register: managed_child_fabrics + +# - name: Set Associated Child Fabric Attribute Data +# ansible.builtin.set_fact: +# associated_child_fabric_data: "{{ child_fabric_results.child_fabric_data }}" +# when: child_fabric_results is defined and child_fabric_results + +# - ansible.builtin.debug: +# var: managed_child_fabrics + +# - name: Prepare Multisite Data +# cisco.nac_dc_vxlan.dtc.prepare_msite: +# model_data: "{{ MD_Extended }}" +# associated_child_fabrics: "{{ managed_child_fabrics.associated_child_fabrics }}" +# when: managed_child_fabrics.associated_child_fabrics is defined and managed_child_fabrics.associated_child_fabrics +# register: MD_Msite + +# - ansible.builtin.debug: +# var: MD_Msite + +# - ansible.builtin.meta: end_play diff --git a/roles/dtc/remove/tasks/msd/child_fabrics.yml b/roles/dtc/remove/tasks/msd/child_fabrics.yml index 0a14762a2..4c5dedf30 100644 --- a/roles/dtc/remove/tasks/msd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/msd/child_fabrics.yml @@ -37,12 +37,12 @@ - name: Remove Unmanaged Child Fabrics from NDFC cisco.nac_dc_vxlan.dtc.manage_child_fabrics: - fabric_associations: "{{ fabric_associations }}" - parent_fabric_name: "{{ MD_Extended.vxlan.fabric.name }}" - child_fabrics: "{{ MD_Extended.vxlan.multisite.child_fabrics }}" - operation: remove + parent_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + child_fabrics: "{{ MD_Msite.child_fabrics_to_be_removed }}" + state: absent when: - - fabric_associations is defined and fabric_associations + - MD_Msite.child_fabrics_to_be_removed is defined + - MD_Msite.child_fabrics_to_be_removed - (child_fabric_delete_mode is defined) and (child_fabric_delete_mode is true|bool) From f89bb1ba412b4277963f6c4f0ee486938fe84e9a Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 30 Jan 2025 08:15:45 -0500 Subject: [PATCH 069/183] fix lint errors --- plugins/action/dtc/manage_child_fabrics.py | 2 +- plugins/action/dtc/prepare_msite.py | 22 +++++++++++----------- tests/sanity/ignore-2.14.txt | 1 + tests/sanity/ignore-2.15.txt | 1 + tests/sanity/ignore-2.16.txt | 1 + 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index d3a81c504..cefbbb84d 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -81,7 +81,7 @@ def run(self, tmp=None, task_vars=None): results['changed'] = True - # associated_child_fabrics.append(fabric['name']) + # associated_child_fabrics.append(fabric['name']) if state == 'absent': for fabric in child_fabrics: diff --git a/plugins/action/dtc/prepare_msite.py b/plugins/action/dtc/prepare_msite.py index 557486a44..eaf2895bc 100644 --- a/plugins/action/dtc/prepare_msite.py +++ b/plugins/action/dtc/prepare_msite.py @@ -47,13 +47,13 @@ def run(self, tmp=None, task_vars=None): # Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD) msd_fabric_associations = self._execute_module( module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "GET", - "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", - }, - task_vars=task_vars, - tmp=tmp - ) + module_args={ + "method": "GET", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", + }, + task_vars=task_vars, + tmp=tmp + ) # Build a list of child fabrics that are associated with the parent fabric (MSD) associated_child_fabrics = [] @@ -77,12 +77,12 @@ def run(self, tmp=None, task_vars=None): for fabric in child_fabrics: if fabric.get('name') not in associated_child_fabrics: child_fabrics_to_be_associated.append(fabric.get('name')) - + results['child_fabrics_to_be_associated'] = child_fabrics_to_be_associated # Merge the lists of currently associated child fabrics and child fabrics to be associated # The assumption here is that the child fabric(s) that will be associated with the parent fabric (MSD) - # in the create role will either be sucessful and we have the prepared data to work with or + # in the create role will either be sucessful and we have the prepared data to work with or # the association will fail, resulting in runtime execution stopping, thus it doens't matter what prepared data we have. associated_child_fabrics = associated_child_fabrics + child_fabrics_to_be_associated @@ -112,7 +112,7 @@ def run(self, tmp=None, task_vars=None): for child_fabric in child_fabrics_data.keys(): for sw in child_fabrics_data[child_fabric]['switches']: if switch['hostname'] == sw['hostname']: - switch['mgmt_ip_address'] = sw['mgmt_ip_address'] + switch['mgmt_ip_address'] = sw['mgmt_ip_address'] # Append switch to a flat list of switches for cross comparison later when we query the # MSD fabric information. We need to stop execution if the list returned by the MSD query @@ -140,7 +140,7 @@ def run(self, tmp=None, task_vars=None): for child_fabric in child_fabrics_data.keys(): for sw in child_fabrics_data[child_fabric]['switches']: if switch['hostname'] == sw['hostname']: - switch['mgmt_ip_address'] = sw['mgmt_ip_address'] + switch['mgmt_ip_address'] = sw['mgmt_ip_address'] # Append switch to a flat list of switches for cross comparison later when we query the # MSD fabric information. We need to stop execution if the list returned by the MSD query # does not include one of these switches. diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 75bf9e02e..7a09377bc 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -15,6 +15,7 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/vpc_pair_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/verify_tags.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 75bf9e02e..7a09377bc 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -15,6 +15,7 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/vpc_pair_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/verify_tags.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 75bf9e02e..7a09377bc 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -15,6 +15,7 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/vpc_pair_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/verify_tags.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/diff_model_changes.py action-plugin-docs # action plugin has no matching module to provide documentation From 2cd93f032e9d6473c51728ee153e6cb5c85bc772 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 30 Jan 2025 11:03:11 -0500 Subject: [PATCH 070/183] add msd child fabric vrfs template & fix lint errors --- plugins/action/dtc/manage_child_fabrics.py | 2 -- plugins/action/dtc/prepare_msite.py | 3 +- roles/dtc/common/tasks/sub_main_msd.yml | 3 ++ .../dtc/common/templates/ndfc_attach_vrfs.j2 | 1 + .../child_fabric/msd_child_fabric_vrfs.j2 | 28 +++++++++++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2 diff --git a/plugins/action/dtc/manage_child_fabrics.py b/plugins/action/dtc/manage_child_fabrics.py index cefbbb84d..3eaf6870f 100644 --- a/plugins/action/dtc/manage_child_fabrics.py +++ b/plugins/action/dtc/manage_child_fabrics.py @@ -26,8 +26,6 @@ from ansible.utils.display import Display from ansible.plugins.action import ActionBase -from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes -from ...plugin_utils.helper_functions import ndfc_get_fabric_switches display = Display() diff --git a/plugins/action/dtc/prepare_msite.py b/plugins/action/dtc/prepare_msite.py index eaf2895bc..b36984fec 100644 --- a/plugins/action/dtc/prepare_msite.py +++ b/plugins/action/dtc/prepare_msite.py @@ -37,7 +37,6 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False - results['md_msite'] = {} model_data = self._task.args["model_data"] parent_fabric = self._task.args["parent_fabric"] @@ -89,6 +88,8 @@ def run(self, tmp=None, task_vars=None): # Can probably remove this as I don't think it will be used results['end_state_associated_child_fabrics'] = associated_child_fabrics + # Get the fabric attributes and switches for each child fabric + # These queries are potentially trying to get data for a fabric that is not associated with the parent fabric (MSD) yet child_fabrics_data = {} for fabric in associated_child_fabrics: child_fabrics_data.update({fabric: {}}) diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index d0eebb26d..497d4cbf5 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -71,6 +71,9 @@ - name: Build NDFC Fabric VRFs Attach List From Template ansible.builtin.import_tasks: msd/ndfc_vrfs.yml +- name: Build NDFC Fabric VRFs Attach List From Template + ansible.builtin.import_tasks: msd/ndfc_child_fabric_vrfs.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Networks Attach List From Template # -------------------------------------------------------------------- diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index 3c4d3367a..e25ac7097 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -12,6 +12,7 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2' %} +{# {% include '/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2' %} #} {# Supported fabric types are: DC VXLAN EVPN and ISN #} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2 new file mode 100644 index 000000000..4b32397af --- /dev/null +++ b/roles/dtc/common/templates/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2 @@ -0,0 +1,28 @@ +{# Auto-generated NDFC DC VXLAN EVPN VRFs config data structure for fabric {{ vxlan.fabric.name }} #} +{% set vrfs = [] %} +{% if MD_Extended.vxlan.multisite.overlay.vrfs is defined and MD_Extended.vxlan.multisite.overlay.vrfs %} +{% set vrfs = MD_Extended.vxlan.multisite.overlay.vrfs %} +{% endif %} +{% for vrf in vrfs %} +- vrf_name: {{ vrf['name'] }} +{# ------------------------------------------------------ #} +{# Properties Section #} +{# ------------------------------------------------------ #} + vrf_id: {{ vrf['vrf_id'] | default(omit) }} + vlan_id: {{ vrf['vlan_id'] | default(omit) }} + netflow_enable: {{ vrf['netflow_enable'] | default(defaults.vxlan.overlay.vrfs.netflow_enable) }} +{% if vrf['netflow_enable'] is defined and vrf['netflow_enable'] | bool %} + nf_monitor: {{ vrf['netflow_monitor'] }} +{% endif %} + no_rp: {{ vrf['no_rp'] | default(defaults.vxlan.overlay.vrfs.no_rp) }} + trm_enable: {{ vrf['trm_enable'] | default(defaults.vxlan.overlay.vrfs.trm_enable) }} +{% if vrf['trm_enable'] is defined and vrf['trm_enable'] | bool %} + overlay_mcast_group: {{ vrf['overlay_multicast_group'] | default(omit) }} + rp_address: {{ vrf['rp_address'] | default(omit) }} + rp_external: {{ vrf['rp_external'] | default(omit) }} + rp_loopback_id: {{ vrf['rp_loopback_id'] | default(omit) }} + trm_bgw_msite: {{ vrf['trm_bgw_msite'] | default(defaults.vxlan.overlay.vrfs.trm_bgw_msite) }} + underlay_mcast_ip: {{ vrf['underlay_mcast_ip'] | default(omit) }} +{% endif %} + +{% endfor %} From 5627f6b5b80a17c00eec1864cbed1ffa7d97b163 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 30 Jan 2025 12:14:41 -0500 Subject: [PATCH 071/183] fixes --- roles/dtc/common/tasks/sub_main_msd.yml | 4 ++-- .../templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/dtc/common/tasks/sub_main_msd.yml b/roles/dtc/common/tasks/sub_main_msd.yml index 497d4cbf5..50f215466 100644 --- a/roles/dtc/common/tasks/sub_main_msd.yml +++ b/roles/dtc/common/tasks/sub_main_msd.yml @@ -71,8 +71,8 @@ - name: Build NDFC Fabric VRFs Attach List From Template ansible.builtin.import_tasks: msd/ndfc_vrfs.yml -- name: Build NDFC Fabric VRFs Attach List From Template - ansible.builtin.import_tasks: msd/ndfc_child_fabric_vrfs.yml +# - name: Build NDFC Fabric VRFs Attach List From Template +# ansible.builtin.import_tasks: msd/ndfc_child_fabric_vrfs.yml # -------------------------------------------------------------------- # Build NDFC Fabric Networks Attach List From Template diff --git a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 index c3d190aa3..d9594eab7 100644 --- a/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/isn_fabric/isn_fabric_base.j2 @@ -13,7 +13,7 @@ {% include '/ndfc_fabric/isn_fabric/resources/isn_fabric_resources.j2' %} {# Include NDFC ISN Bootstrap Template #} -{# {% include '/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2' %} #} +{% include '/ndfc_fabric/isn_fabric/bootstrap/isn_fabric_bootstrap.j2' %} {# Include NDFC ISN Flow Monitor Template #} {% include '/ndfc_fabric/isn_fabric/flow_monitor/isn_fabric_flow_monitor.j2' %} From cf01600054d97f72a3bc66cd3d0695974ac4c9c6 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Thu, 30 Jan 2025 12:45:05 -0500 Subject: [PATCH 072/183] set msite prepare defaults --- plugins/action/dtc/prepare_msite.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/action/dtc/prepare_msite.py b/plugins/action/dtc/prepare_msite.py index b36984fec..df24cb982 100644 --- a/plugins/action/dtc/prepare_msite.py +++ b/plugins/action/dtc/prepare_msite.py @@ -37,6 +37,11 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) results['failed'] = False + results['current_associated_child_fabrics'] = [] + results['child_fabrics_to_be_removed'] = [] + results['child_fabrics_to_be_associated'] = [] + results['end_state_associated_child_fabrics'] = [] + results['child_fabrics_data'] = {} model_data = self._task.args["model_data"] parent_fabric = self._task.args["parent_fabric"] From 81156d2ce7e4589a8fa400d8c37b7e1795fc143f Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Sat, 1 Feb 2025 21:05:15 -0500 Subject: [PATCH 073/183] updated existing rules to allow empty vrfs & add first msite rule --- .../001_supported_via_child_fabric.py | 49 ++++++ .../vxlan/401_overlay_cross_reference.py | 128 ++++++++++++++ .../401_overlay_services_cross_reference.py | 166 ------------------ ...y_services_vrfs.py => 402_overlay_vrfs.py} | 6 - ...es_networks.py => 403_overlay_networks.py} | 0 5 files changed, 177 insertions(+), 172 deletions(-) create mode 100644 roles/validate/files/rules/multisite/001_supported_via_child_fabric.py create mode 100644 roles/validate/files/rules/vxlan/401_overlay_cross_reference.py delete mode 100644 roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py rename roles/validate/files/rules/vxlan/{402_overlay_services_vrfs.py => 402_overlay_vrfs.py} (94%) rename roles/validate/files/rules/vxlan/{403_overlay_services_networks.py => 403_overlay_networks.py} (100%) diff --git a/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py new file mode 100644 index 000000000..6059a9e27 --- /dev/null +++ b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py @@ -0,0 +1,49 @@ +class Rule: + id = "001" + description = "Verify the data model for what should be supported via child fabric(s)." + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + + # Keys supported via child fabric(s) + child_fabric_supported_keys = ['global', 'topology', 'underlay', 'overlay_extensions', 'policy'] + for child_fabric_supported_key in child_fabric_supported_keys: + check = cls.data_model_key_check(inventory, ['vxlan', child_fabric_supported_key]) + if child_fabric_supported_key in check['keys_found']: + results.append( + f"Key '{child_fabric_supported_key}' is supported via child fabric(s) respective host_vars data model file(s)." + ) + + return results + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict diff --git a/roles/validate/files/rules/vxlan/401_overlay_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_cross_reference.py new file mode 100644 index 000000000..ba1a400af --- /dev/null +++ b/roles/validate/files/rules/vxlan/401_overlay_cross_reference.py @@ -0,0 +1,128 @@ +class Rule: + id = "401" + description = "Cross Reference VRFs and Networks items in the Service Model" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + + switches = None + sm_networks = None + sm_vrfs = None + network_attach_groups = None + vrf_attach_groups = None + + switch_keys = ['vxlan', 'topology', 'switches'] + + # Remove the check for overlay_services after deprecation + # Remove lines 21 - 23 + overlay_key = 'overlay' + check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) + if overlay_key in check['keys_not_found'] or overlay_key in check['keys_no_data']: + overlay_key = 'overlay_services' + + check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) + if overlay_key in check['keys_found'] and overlay_key in check['keys_data']: + network_keys = ['vxlan', overlay_key, 'networks'] + vrf_keys = ['vxlan', overlay_key, 'vrfs'] + network_attach_keys = ['vxlan', overlay_key, 'network_attach_groups'] + vrf_attach_keys = ['vxlan', overlay_key, 'vrf_attach_groups'] + + # Check if vrfs, network and switch data is defined in the service model + check = cls.data_model_key_check(inventory, switch_keys) + if 'switches' in check['keys_data']: + switches = cls.safeget(inventory, switch_keys) + if not switches: + # No switches defined in the service model, no reason to continue + return results + + check = cls.data_model_key_check(inventory, network_keys) + if 'networks' in check['keys_data']: + sm_networks = cls.safeget(inventory, network_keys) + + check = cls.data_model_key_check(inventory, vrf_keys) + if 'vrfs' in check['keys_data']: + sm_vrfs = cls.safeget(inventory, vrf_keys) + + check = cls.data_model_key_check(inventory, vrf_attach_keys) + if 'vrf_attach_groups' in check['keys_data']: + vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) + + check = cls.data_model_key_check(inventory, network_attach_keys) + if 'network_attach_groups' in check['keys_data']: + network_attach_groups = cls.safeget(inventory, network_attach_keys) + + # Ensure Network is not referencing a VRF that is not defined in the service model + results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) + + if sm_vrfs and vrf_attach_groups: + results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) + if sm_networks and network_attach_groups: + results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict + + @classmethod + def cross_reference_vrfs_nets(cls, sm_vrfs, sm_networks, results): + if not sm_vrfs or not sm_networks: + return results + + vrf_names = [] + for vrf in sm_vrfs: + vrf_names.append(vrf.get("name")) + # Compare the two lists and generate an error message if a network is found + # in network_vrf_names that is not in vrf_names + for net in sm_networks: + if net.get("vrf_name") is not None: + if net.get("vrf_name") not in vrf_names: + results.append( + f"Network ({net.get('name')}) is referencing VRF ({net.get('vrf_name')}) " + "which is not defined in the service model. Add the VRF to the service model or remove the network from the service model " + "and re-run the playbook." + ) + + return results + + @classmethod + def cross_reference_switches(cls, attach_groups, switches, target, results): + # target is either vrf or network + for attach_group in attach_groups: + for switch in attach_group.get("switches"): + if switch.get("hostname"): + if not any(s.get("name") == switch.get("hostname") for s in switches): + if not any(s.get('management').get('management_ipv4_address') == switch.get("hostname") for s in switches): + if not any(s.get('management').get('management_ipv6_address') == switch.get("hostname") for s in switches): + ag = attach_group.get("name") + hn = switch.get("hostname") + results.append(f"{target} attach group {ag} hostname {hn} does not match any switch in the topology.") + + return results diff --git a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py b/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py deleted file mode 100644 index d651e2243..000000000 --- a/roles/validate/files/rules/vxlan/401_overlay_services_cross_reference.py +++ /dev/null @@ -1,166 +0,0 @@ -class Rule: - id = "401" - description = "Cross Reference VRFs and Networks items in the Service Model" - severity = "HIGH" - - @classmethod - def match(cls, inventory): - results = [] - - switches = None - sm_networks = None - sm_vrfs = None - network_attach_groups = None - vrf_attach_groups = None - - switch_keys = ['vxlan', 'topology', 'switches'] - - # Remove the check for overlay_services after deprecation - # Remove lines 21 - 23 - overlay_key = 'overlay' - check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) - if overlay_key in check['keys_not_found'] or overlay_key in check['keys_no_data']: - overlay_key = 'overlay_services' - check = cls.data_model_key_check(inventory, ['vxlan', overlay_key]) - if overlay_key in check['keys_not_found'] or overlay_key in check['keys_no_data']: - results.append('Overlay data not found!') - return results - - network_keys = ['vxlan', overlay_key, 'networks'] - vrf_keys = ['vxlan', overlay_key, 'vrfs'] - network_attach_keys = ['vxlan', overlay_key, 'network_attach_groups'] - vrf_attach_keys = ['vxlan', overlay_key, 'vrf_attach_groups'] - - # Check if vrfs, network and switch data is defined in the service model - check = cls.data_model_key_check(inventory, switch_keys) - if 'switches' in check['keys_data']: - switches = cls.safeget(inventory, switch_keys) - if not switches: - # No switches defined in the service model, no reason to continue - return results - - check = cls.data_model_key_check(inventory, network_keys) - if 'networks' in check['keys_data']: - sm_networks = cls.safeget(inventory, network_keys) - - check = cls.data_model_key_check(inventory, vrf_keys) - if 'vrfs' in check['keys_data']: - sm_vrfs = cls.safeget(inventory, vrf_keys) - - check = cls.data_model_key_check(inventory, vrf_attach_keys) - if 'vrf_attach_groups' in check['keys_data']: - vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) - - check = cls.data_model_key_check(inventory, network_attach_keys) - if 'network_attach_groups' in check['keys_data']: - network_attach_groups = cls.safeget(inventory, network_attach_keys) - - # Ensure Network is not referencing a VRF that is not defined in the service model - results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) - - if sm_vrfs and vrf_attach_groups: - results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) - if sm_networks and network_attach_groups: - results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) - - # For backwards compatibility - # Lines 54 - 88 will be removed after the deprecation in a future release - # sm_networks = None - # sm_vrfs = None - # network_attach_groups = None - # vrf_attach_groups = None - - # network_keys = ['vxlan', 'overlay_services', 'networks'] - # vrf_keys = ['vxlan', 'overlay_services', 'vrfs'] - # network_attach_keys = ['vxlan', 'overlay_services', 'network_attach_groups'] - # vrf_attach_keys = ['vxlan', 'overlay_services', 'vrf_attach_groups'] - - # check = cls.data_model_key_check(inventory, network_keys) - # if 'networks' in check['keys_data']: - # sm_networks = cls.safeget(inventory, network_keys) - - # check = cls.data_model_key_check(inventory, vrf_keys) - # if 'vrfs' in check['keys_data']: - # sm_vrfs = cls.safeget(inventory, vrf_keys) - - # check = cls.data_model_key_check(inventory, vrf_attach_keys) - # if 'vrf_attach_groups' in check['keys_data']: - # vrf_attach_groups = cls.safeget(inventory, vrf_attach_keys) - - # check = cls.data_model_key_check(inventory, network_attach_keys) - # if 'network_attach_groups' in check['keys_data']: - # network_attach_groups = cls.safeget(inventory, network_attach_keys) - - # # Ensure Network is not referencing a VRF that is not defined in the service model - # results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) - - # if sm_vrfs and vrf_attach_groups: - # results = cls.cross_reference_switches(vrf_attach_groups, switches, 'vrf', results) - # if sm_networks and network_attach_groups: - # results = cls.cross_reference_switches(network_attach_groups, switches, 'network', results) - - return results - - @classmethod - def data_model_key_check(cls, tested_object, keys): - dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} - for key in keys: - if tested_object and key in tested_object: - dm_key_dict['keys_found'].append(key) - tested_object = tested_object[key] - if tested_object: - dm_key_dict['keys_data'].append(key) - else: - dm_key_dict['keys_no_data'].append(key) - else: - dm_key_dict['keys_not_found'].append(key) - return dm_key_dict - - @classmethod - def safeget(cls, dict, keys): - # Utility function to safely get nested dictionary values - for key in keys: - if dict is None: - return None - if key in dict: - dict = dict[key] - else: - return None - - return dict - - @classmethod - def cross_reference_vrfs_nets(cls, sm_vrfs, sm_networks, results): - if not sm_vrfs or not sm_networks: - return results - - vrf_names = [] - for vrf in sm_vrfs: - vrf_names.append(vrf.get("name")) - # Compare the two lists and generate an error message if a network is found - # in network_vrf_names that is not in vrf_names - for net in sm_networks: - if net.get("vrf_name") is not None: - if net.get("vrf_name") not in vrf_names: - results.append( - f"Network ({net.get('name')}) is referencing VRF ({net.get('vrf_name')}) " - "which is not defined in the service model. Add the VRF to the service model or remove the network from the service model " - "and re-run the playbook." - ) - - return results - - @classmethod - def cross_reference_switches(cls, attach_groups, switches, target, results): - # target is either vrf or network - for attach_group in attach_groups: - for switch in attach_group.get("switches"): - if switch.get("hostname"): - if not any(s.get("name") == switch.get("hostname") for s in switches): - if not any(s.get('management').get('management_ipv4_address') == switch.get("hostname") for s in switches): - if not any(s.get('management').get('management_ipv6_address') == switch.get("hostname") for s in switches): - ag = attach_group.get("name") - hn = switch.get("hostname") - results.append(f"{target} attach group {ag} hostname {hn} does not match any switch in the topology.") - - return results diff --git a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py b/roles/validate/files/rules/vxlan/402_overlay_vrfs.py similarity index 94% rename from roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py rename to roles/validate/files/rules/vxlan/402_overlay_vrfs.py index 8a28aadc6..55a53b64f 100644 --- a/roles/validate/files/rules/vxlan/402_overlay_services_vrfs.py +++ b/roles/validate/files/rules/vxlan/402_overlay_vrfs.py @@ -29,12 +29,6 @@ def match(cls, inventory): if 'vrfs' in check['keys_data']: vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] - # if inventory["vxlan"].get("overlay", None) or inventory["vxlan"].get("overlay_services", None): - # if inventory["vxlan"].get("overlay").get("vrfs", None): - # vrfs = inventory["vxlan"]["overlay"]["vrfs"] - # elif inventory["vxlan"].get("overlay_services").get("vrfs", None): - # vrfs = inventory["vxlan"]["overlay_services"]["vrfs"] - for vrf in vrfs: current_vrf_netflow_status = vrf.get("netflow_enable", None) if current_vrf_netflow_status is not None: diff --git a/roles/validate/files/rules/vxlan/403_overlay_services_networks.py b/roles/validate/files/rules/vxlan/403_overlay_networks.py similarity index 100% rename from roles/validate/files/rules/vxlan/403_overlay_services_networks.py rename to roles/validate/files/rules/vxlan/403_overlay_networks.py From 5aa76773266b7fa62b8b025b8c66a831f8441676 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Sat, 1 Feb 2025 21:09:36 -0500 Subject: [PATCH 074/183] fix lint errors --- .../files/rules/multisite/001_supported_via_child_fabric.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py index 6059a9e27..ef9bb9611 100644 --- a/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py +++ b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py @@ -13,8 +13,8 @@ def match(cls, inventory): check = cls.data_model_key_check(inventory, ['vxlan', child_fabric_supported_key]) if child_fabric_supported_key in check['keys_found']: results.append( - f"Key '{child_fabric_supported_key}' is supported via child fabric(s) respective host_vars data model file(s)." - ) + f"Key '{child_fabric_supported_key}' "is supported via child fabric(s) respective host_vars data model file(s)." + ) return results From e29c17ea356d2834a4270c1fafd601054f382c20 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Sat, 1 Feb 2025 21:17:28 -0500 Subject: [PATCH 075/183] add msite cross-ref rule --- .../multisite/201_overlay_cross_reference.py | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 roles/validate/files/rules/multisite/201_overlay_cross_reference.py diff --git a/roles/validate/files/rules/multisite/201_overlay_cross_reference.py b/roles/validate/files/rules/multisite/201_overlay_cross_reference.py new file mode 100644 index 000000000..62e2c906f --- /dev/null +++ b/roles/validate/files/rules/multisite/201_overlay_cross_reference.py @@ -0,0 +1,78 @@ +class Rule: + id = "401" + description = "Cross Reference VRFs and Networks items in the Service Model" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + + sm_networks = None + sm_vrfs = None + + check = cls.data_model_key_check(inventory, ['vxlan', 'multisite', 'overlay']) + if 'overlay' in check['keys_found'] and 'overlay' in check['keys_data']: + network_keys = ['vxlan', 'multisite', 'overlay', 'networks'] + vrf_keys = ['vxlan', 'multisite', 'overlay', 'vrfs'] + + check = cls.data_model_key_check(inventory, network_keys) + if 'networks' in check['keys_data']: + sm_networks = cls.safeget(inventory, network_keys) + + check = cls.data_model_key_check(inventory, vrf_keys) + if 'vrfs' in check['keys_data']: + sm_vrfs = cls.safeget(inventory, vrf_keys) + + # Ensure Network is not referencing a VRF that is not defined in the service model + results = cls.cross_reference_vrfs_nets(sm_vrfs, sm_networks, results) + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict + + @classmethod + def cross_reference_vrfs_nets(cls, sm_vrfs, sm_networks, results): + if not sm_vrfs or not sm_networks: + return results + + vrf_names = [] + for vrf in sm_vrfs: + vrf_names.append(vrf.get("name")) + # Compare the two lists and generate an error message if a network is found + # in network_vrf_names that is not in vrf_names + for net in sm_networks: + if net.get("vrf_name") is not None: + if net.get("vrf_name") not in vrf_names: + results.append( + f"Network ({net.get('name')}) is referencing VRF ({net.get('vrf_name')}) " + "which is not defined in the service model. Add the VRF to the service model or remove the network from the service model " + "and re-run the playbook." + ) + + return results From fd4c73c85ef0f5dccba7f960a29cf56df9f9a75b Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Sat, 1 Feb 2025 21:18:44 -0500 Subject: [PATCH 076/183] fix typo --- .../files/rules/multisite/001_supported_via_child_fabric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py index ef9bb9611..968ccdd77 100644 --- a/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py +++ b/roles/validate/files/rules/multisite/001_supported_via_child_fabric.py @@ -13,7 +13,7 @@ def match(cls, inventory): check = cls.data_model_key_check(inventory, ['vxlan', child_fabric_supported_key]) if child_fabric_supported_key in check['keys_found']: results.append( - f"Key '{child_fabric_supported_key}' "is supported via child fabric(s) respective host_vars data model file(s)." + f"Key '{child_fabric_supported_key}' is supported via child fabric(s) respective host_vars data model file(s)." ) return results From 38f4a4fae7262dab0e8c5432458956140ea051ea Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 7 Feb 2025 10:52:20 +0000 Subject: [PATCH 077/183] Initial commit --- plugins/action/dtc/existing_links_check.py | 22 +++++++++- .../general/dc_external_fabric_general.j2 | 2 +- .../advanced/dc_vxlan_fabric_advanced.j2 | 12 +++++ .../dc_vxlan_fabric/dc_vxlan_fabric_base.j2 | 2 +- .../general/dc_vxlan_fabric_general.j2 | 2 +- .../protocols/dc_vxlan_fabric_protocols.j2 | 2 + .../vpc/dc_vxlan_fabric_vpc.j2 | 7 ++- .../common/templates/ndfc_interface_access.j2 | 2 +- .../templates/ndfc_interface_access_po.j2 | 2 +- .../templates/ndfc_interface_po_routed.j2 | 2 +- .../common/templates/ndfc_interface_routed.j2 | 2 +- .../common/templates/ndfc_interface_trunk.j2 | 2 +- .../templates/ndfc_interface_trunk_po.j2 | 2 +- .../common/templates/ndfc_interface_vpc.j2 | 4 ++ roles/dtc/common/templates/ndfc_inventory.j2 | 3 +- .../templates/ndfc_loopback_interfaces.j2 | 2 +- roles/dtc/common/templates/ndfc_policy.j2 | 2 +- .../templates/ndfc_sub_interface_routed.j2 | 2 +- .../dtc/common/templates/ndfc_vpc_peering.j2 | 12 +++++ roles/dtc/create/tasks/interfaces.yml | 44 +++++++++---------- roles/dtc/create/tasks/links.yml | 13 +----- roles/dtc/create/tasks/sub_main.yml | 35 +++++++++++---- roles/validate/files/defaults.yml | 12 ++++- 23 files changed, 131 insertions(+), 59 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 3f11d2eb9..917d7e0c2 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -40,6 +40,7 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] + required_links = [] not_required_links = [] for link in fabric_links: for existing_link in existing_links: @@ -53,6 +54,23 @@ def run(self, tmp=None, task_vars=None): existing_link['sw1-info']['if-name'] == link['dst_interface'] and existing_link['sw2-info']['sw-sys-name'] == link['src_device'] and existing_link['sw2-info']['if-name'] == link['src_interface'])): - not_required_links.append(link) - results['not_required_links'] = not_required_links + if 'templateName' not in existing_link: + not_required_links.append(link) + elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': + required_links.append(link) + elif existing_link['templateName'] == 'int_intra_fabric_num_link': + link['template'] = 'int_intra_fabric_num_link' + link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + else: + link['profile']['enable_macsec'] = 'false' + required_links.append(link) + else: + not_required_links.append(link) + if link not in required_links and link not in not_required_links: + required_links.append(link) + + results['required_links'] = required_links return results diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 index 35fb9d18e..988505f25 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/general/dc_external_fabric_general.j2 @@ -1,4 +1,4 @@ {# Auto-generated NDFC DC VXLAN EVPN General config data structure for fabric {{ vxlan.global.name }} #} - BGP_AS: {{ global.bgp_asn }} + BGP_AS: "{{ global.bgp_asn }}" {# #} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index ce09372fb..2d287f1f3 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -3,6 +3,18 @@ GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false AAA_REMOTE_IP_ENABLED: False + FEATURE_PTP: {{ global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} +{% if global.ptp.ptp_enable is defined and global.ptp.ptp_enable == 'true' %} + PTP_DOMAIN_ID: {{ global.ptp.ptp_domain_id }} + PTP_LB_ID: {{ global.ptp.ptp_lb_id }} + PTP_VLAN_ID: {{ global.ptp.ptp_vlan_id }} +{% endif %} + ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} + ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} +{% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} + CDP_ENABLE: global.bootstrap.cdp_enable +{% endif %} + SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} L2_HOST_INTF_MTU: {{ vxlan.underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 index 5798df5ee..d4ebbf13d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/dc_vxlan_fabric_base.j2 @@ -2,7 +2,7 @@ {% import 'ndfc_utils.j2' as ndfc_utils with context %} - FABRIC_NAME: {{ global.name }} FABRIC_TYPE: {{ fabric_type }} - DEPLOY: True + DEPLOY: False {# Include NDFC DC VXLAN EVPN General Template #} {% include '/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 index a11946d88..2e494c3b4 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/general/dc_vxlan_fabric_general.j2 @@ -1,5 +1,5 @@ {# Auto-generated NDFC DC VXLAN EVPN General config data structure for fabric {{ vxlan.global.name }} #} - BGP_AS: {{ global.bgp_asn }} + BGP_AS: "{{ global.bgp_asn }}" UNDERLAY_IS_V6: {{ (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) }} {% if (vxlan.underlay.general.enable_ipv6_underlay | default(defaults.vxlan.underlay.general.enable_ipv6_underlay) | title) == 'True' %} USE_LINK_LOCAL: {{ vxlan.underlay.ipv6.enable_ipv6_link_local_address | default(defaults.vxlan.underlay.ipv6.enable_ipv6_link_local_address | title) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 index a4f849992..0acebb3ae 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 @@ -43,7 +43,9 @@ {% endif %} {% if (vxlan.underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} BFD_IBGP_ENABLE: {{ vxlan.underlay.bfd.ibgp | default(defaults.vxlan.underlay.bfd.ibgp) }} +{% if (vxlan.underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) ) == 'multicast' %} BFD_PIM_ENABLE: {{ vxlan.underlay.bfd.pim | default(defaults.vxlan.underlay.bfd.pim) }} +{% endif %} BFD_AUTH_ENABLE: {{ (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) }} {% if (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) == 'True' %} BFD_AUTH_KEY: {{ vxlan.underlay.bfd.authentication_key | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 49105ed70..b690dd936 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -1,5 +1,9 @@ {# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.global.name }} #} ENABLE_FABRIC_VPC_DOMAIN_ID: False + FABRIC_VPC_QOS: {{ global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} +{% if global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) == 'false' %} + FABRIC_VPC_QOS_POLICY_NAME: {{ global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} +{% endif %} VPC_PEER_LINK_VLAN: {{ global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} VPC_PEER_KEEP_ALIVE_OPTION: {{ global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} VPC_AUTO_RECOVERY_TIME: {{ global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} @@ -10,4 +14,5 @@ ADVERTISE_PIP_BGP: {{ (global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} -{% endif %} \ No newline at end of file +{% endif %} + VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_interface_access.j2 b/roles/dtc/common/templates/ndfc_interface_access.j2 index 91e2c0508..d1d324974 100644 --- a/roles/dtc/common/templates/ndfc_interface_access.j2 +++ b/roles/dtc/common/templates/ndfc_interface_access.j2 @@ -21,7 +21,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interface_access_po.j2 b/roles/dtc/common/templates/ndfc_interface_access_po.j2 index b4a176b35..14e1a635e 100644 --- a/roles/dtc/common/templates/ndfc_interface_access_po.j2 +++ b/roles/dtc/common/templates/ndfc_interface_access_po.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interface_po_routed.j2 b/roles/dtc/common/templates/ndfc_interface_po_routed.j2 index 18cdeb836..dda768000 100644 --- a/roles/dtc/common/templates/ndfc_interface_po_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interface_po_routed.j2 @@ -24,7 +24,7 @@ ipv4_addr: {{ ipv4_address__mask[0] | default(omit) }} ipv4_mask_len: {{ ipv4_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interface_routed.j2 index 436205334..17c813c4d 100644 --- a/roles/dtc/common/templates/ndfc_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interface_routed.j2 @@ -29,7 +29,7 @@ ipv6_addr: {{ ipv6_address__mask[0] | default(omit) }} ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interface_trunk.j2 b/roles/dtc/common/templates/ndfc_interface_trunk.j2 index 86c814d20..c318fefd9 100644 --- a/roles/dtc/common/templates/ndfc_interface_trunk.j2 +++ b/roles/dtc/common/templates/ndfc_interface_trunk.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interface_trunk_po.j2 b/roles/dtc/common/templates/ndfc_interface_trunk_po.j2 index 4ccfa8084..be850c14a 100644 --- a/roles/dtc/common/templates/ndfc_interface_trunk_po.j2 +++ b/roles/dtc/common/templates/ndfc_interface_trunk_po.j2 @@ -23,7 +23,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interface_vpc.j2 b/roles/dtc/common/templates/ndfc_interface_vpc.j2 index c96acb087..76a285847 100644 --- a/roles/dtc/common/templates/ndfc_interface_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_interface_vpc.j2 @@ -34,6 +34,10 @@ pc_mode: {{ switches[peer1].pc_mode | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.pc_mode) }} peer1_members: {{ switches[peer1].members | to_json }} peer2_members: {{ switches[peer2].members | to_json }} + peer1_cmds: |2- + {{ switches[peer1].freeform_config | default('') | indent(6, false) }} + peer2_cmds: |2- + {{ switches[peer2].freeform_config | default('') | indent(6, false) }} peer1_description: "{{ switches[peer1].description | default(omit) }}" peer2_description: "{{ switches[peer2].description | default(omit) }}" bpdu_guard: {{ switches[peer1].enable_bpdu_guard | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enable_bpdu_guard) }} diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 48577757d..27e7e2142 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -35,7 +35,8 @@ version: {{ switch['poap']['preprovision']['version'] }} config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} - gateway: {{ switch['management']['default_gateway_v4'] }} + gateway: {{ switch['management']['default_gateway_v4'] }} + breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} hostname: {{ switch['name'] }} {% endif %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_loopback_interfaces.j2 b/roles/dtc/common/templates/ndfc_loopback_interfaces.j2 index 823820659..9f1844d16 100644 --- a/roles/dtc/common/templates/ndfc_loopback_interfaces.j2 +++ b/roles/dtc/common/templates/ndfc_loopback_interfaces.j2 @@ -24,7 +24,7 @@ mode: fabric {% endif %} int_vrf: {{ interface.vrf | default(omit) }} - description: {{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }} + description: "{{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }}" admin_state: {{ interface.enabled | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.enabled) }} ipv4_addr: {{ interface.ipv4_address | default(omit) }} ipv6_addr: {{ interface.ipv6_address | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index f512fa422..55b25b8b4 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -31,7 +31,7 @@ {{ key }}: |- {{ value | indent(14) }} {% else %} - {{ key }}: {{ value | to_nice_yaml(indent=2) | indent(10) | trim }} + {{ key }}: {{ value | to_nice_yaml(indent=2) | replace('...','') | indent(10) | trim }} {% endif %} {% endfor %} {% elif policy_match.filename is defined and policy_match.filename and (".yaml" in policy_match.filename or ".yml" in policy_match.filename) %} diff --git a/roles/dtc/common/templates/ndfc_sub_interface_routed.j2 b/roles/dtc/common/templates/ndfc_sub_interface_routed.j2 index 6e5b0b637..610588f4a 100644 --- a/roles/dtc/common/templates/ndfc_sub_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_sub_interface_routed.j2 @@ -30,7 +30,7 @@ ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} vlan: {{ interface['dot1q_id'] }} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_vpc_peering.j2 index f42fa9a10..0b7a7ed55 100644 --- a/roles/dtc/common/templates/ndfc_vpc_peering.j2 +++ b/roles/dtc/common/templates/ndfc_vpc_peering.j2 @@ -5,15 +5,27 @@ {% if MD.vxlan.topology.vpc_peers is defined and MD.vxlan.topology.vpc_peers is not none %} {% for vpc_peer in MD.vxlan.topology.vpc_peers %} +{% if MD_Extended.vxlan.topology.leaf is defined and vpc_peer.peer1 in MD_Extended.vxlan.topology.leaf %} {% if MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv4_address is not none %} - peerOneId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv4_address }} {% elif MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv6_address is not none %} - peerOneId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv6_address }} +{% else %} +- peerOneId: {{ vpc_peer.peer1 }} {% endif %} +{% else %} +- peerOneId: {{ vpc_peer.peer1 }} +{% endif %} +{% if MD_Extended.vxlan.topology.leaf is defined and vpc_peer.peer2 in MD_Extended.vxlan.topology.leaf %} {% if MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv4_address is not none %} peerTwoId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv4_address }} {% elif MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv6_address is not none %} peerTwoId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv6_address }} +{% else %} + peerTwoId: {{ vpc_peer.peer2 }} +{% endif %} +{% else %} + peerTwoId: {{ vpc_peer.peer2 }} {% endif %} {% if vpc_peer.fabric_peering is defined %} useVirtualPeerlink: {{ vpc_peer.fabric_peering }} diff --git a/roles/dtc/create/tasks/interfaces.yml b/roles/dtc/create/tasks/interfaces.yml index af086ecff..ac5d3bead 100644 --- a/roles/dtc/create/tasks/interfaces.yml +++ b/roles/dtc/create/tasks/interfaces.yml @@ -28,6 +28,28 @@ - "+ Manage Fabric Interfaces {{ MD.vxlan.global.name }}" - "----------------------------------------------------------------" +# -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.vxlan.global.name }}" + state: replaced + config: "{{ interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.vxlan.global.name }}" + state: replaced + config: "{{ interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- @@ -94,28 +116,6 @@ config: "{{ int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - # -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" - state: replaced - config: "{{ interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Access - cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" - state: replaced - config: "{{ interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - # -------------------------------------------------------------------- # Manage interface vPC Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/links.yml b/roles/dtc/create/tasks/links.yml index fc1763574..091e15e74 100644 --- a/roles/dtc/create/tasks/links.yml +++ b/roles/dtc/create/tasks/links.yml @@ -44,25 +44,16 @@ cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" fabric_links: "{{ fabric_links }}" - register: not_required_links + register: required_links when: result_links.response is defined -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest -- name: Set not_required_links if result_links.response is not defined - ansible.builtin.set_fact: - not_required_links: [] - when: result_links.response is not defined - -- name: remove unwanted links from required links input - ansible.builtin.set_fact: - required_links: "{{ fabric_links | difference(not_required_links['not_required_links']) }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- - name: Manage NDFC Fabric Links cisco.dcnm.dcnm_links: src_fabric: "{{ MD.vxlan.global.name }}" - config: "{{ required_links }}" + config: "{{ required_links['required_links'] }}" deploy: false state: merged register: manage_fabric_links_result diff --git a/roles/dtc/create/tasks/sub_main.yml b/roles/dtc/create/tasks/sub_main.yml index e4c73306f..bbc64bade 100644 --- a/roles/dtc/create/tasks/sub_main.yml +++ b/roles/dtc/create/tasks/sub_main.yml @@ -46,6 +46,13 @@ - changes_detected_inventory tags: "{{ nac_tags.create_switches }}" +- name: Manage NDFC Fabric Intra Links + ansible.builtin.import_tasks: links.yml + when: + - MD_Extended.vxlan.topology.fabric_links | length > 0 + - changes_detected_fabric_links + tags: "{{ nac_tags.create_links }}" + - name: Manage VPC Peering ansible.builtin.import_tasks: vpc_peering.yml when: @@ -53,6 +60,21 @@ - changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" +- name: Config-Save block + block: + - name: Config-Save for Fabric {{ MD.vxlan.global.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.global.name }}/config-save" + when: MD_Extended.vxlan.topology.switches | length > 0 + register: config_save + # TODO: Need to add logic to only save if changes are made + + rescue: + - name: Config-Save for Fabric {{ MD.vxlan.global.name }} - Failed + ansible.builtin.debug: + msg: "{{ config_save.msg.DATA }}" + - name: Manage NDFC Fabric Interfaces ansible.builtin.import_tasks: interfaces.yml when: @@ -63,20 +85,15 @@ - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: vrfs_networks.yml when: - - (MD.vxlan.overlay_services is defined) and (MD_Extended.vxlan.topology.switches | length > 0) + - (MD_Extended.vxlan.overlay_services is defined) and (MD_Extended.vxlan.topology.switches | length > 0) - changes_detected_vrfs or changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" -- name: Manage NDFC Fabric Intra Links - ansible.builtin.import_tasks: links.yml - when: - - MD_Extended.vxlan.topology.fabric_links | length > 0 - - changes_detected_fabric_links - tags: "{{ nac_tags.create_links }}" - - name: Manage NDFC Fabric Policies ansible.builtin.import_tasks: policies.yml when: - (MD_Extended.vxlan.policy is defined) and (MD_Extended.vxlan.policy.policies | length > 0) - changes_detected_policy - tags: "{{ nac_tags.create_policy }}" + tags: + - "{{ nac_tags.create_policy }}" + diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 2f4ffc69a..145091ed0 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -35,9 +35,12 @@ factory_defaults: advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 + fabric_vpc_qos: false + fabric_vpc_qos_policy_name: spine_qos_for_fabric_vpc_peering + enable_ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged - vlan_range: + vlan_range: - from: 1 to: 3967 mst_instance_range: @@ -46,6 +49,13 @@ factory_defaults: bridge_priority: 0 netflow: enable: false + ptp: + ptp_enable: false + enable_nxapi: true + enable_nxapi_http: true + snmp_server_host_trap: true + bootstrap: + cdp_enable: false topology: switches: routing_loopback_id: 0 From 9bdb61606ee7d9fcf7529f37806e900032d54e82 Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:51:40 +0000 Subject: [PATCH 078/183] Update dc_vxlan_fabric_advanced.j2 to add braces --- .../dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 2d287f1f3..4791b9929 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -12,7 +12,7 @@ ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} {% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} - CDP_ENABLE: global.bootstrap.cdp_enable + CDP_ENABLE: {{ global.bootstrap.cdp_enable }} {% endif %} SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} @@ -28,4 +28,4 @@ {% endif %} STP_BRIDGE_PRIORITY: {{ global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} {% endif %} -{% endif %} \ No newline at end of file +{% endif %} From 95bbaf3a258b89b791eab7ecd5544456496f7486 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 13 Feb 2025 09:47:38 +0000 Subject: [PATCH 079/183] revert policy change --- roles/dtc/common/templates/ndfc_policy.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index 55b25b8b4..f512fa422 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -31,7 +31,7 @@ {{ key }}: |- {{ value | indent(14) }} {% else %} - {{ key }}: {{ value | to_nice_yaml(indent=2) | replace('...','') | indent(10) | trim }} + {{ key }}: {{ value | to_nice_yaml(indent=2) | indent(10) | trim }} {% endif %} {% endfor %} {% elif policy_match.filename is defined and policy_match.filename and (".yaml" in policy_match.filename or ".yml" in policy_match.filename) %} From 71621e2c6150d69bd73d6b5174235231a3f5d390 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 13 Feb 2025 12:55:29 +0000 Subject: [PATCH 080/183] Added support to remove child fabrics --- roles/dtc/remove/tasks/main.yml | 7 ++ roles/dtc/remove/tasks/mfd/child_fabrics.yml | 74 ++++++++++++++++++++ roles/dtc/remove/tasks/sub_main_mfd.yml | 37 ++++++++++ roles/validate/tasks/sub_main.yml | 6 +- 4 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 roles/dtc/remove/tasks/mfd/child_fabrics.yml create mode 100644 roles/dtc/remove/tasks/sub_main_mfd.yml diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index 3c17da865..7d0becc92 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -43,6 +43,13 @@ (vars_common_msd.changes_detected_vrfs) or (vars_common_msd.changes_detected_networks) +- name: Import MFD Role Tasks + ansible.builtin.import_tasks: sub_main_mfd.yml + when: > + (MD_Extended.vxlan.fabric.type == 'MFD') and + (vars_common_mfd.changes_detected_vrfs) or + (vars_common_mfd.changes_detected_networks) + - name: Import ISN Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml when: > diff --git a/roles/dtc/remove/tasks/mfd/child_fabrics.yml b/roles/dtc/remove/tasks/mfd/child_fabrics.yml new file mode 100644 index 000000000..7c7976aee --- /dev/null +++ b/roles/dtc/remove/tasks/mfd/child_fabrics.yml @@ -0,0 +1,74 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Children Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Fabric Children {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" + +- name: Check if fabric already a member of NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' + register: member_result + +- name: debug member_result + ansible.builtin.debug: + var: member_result + +- name: Set fact for existing fabric names and cluster names + set_fact: + existing_fabrics: >- + {{ + member_result.response.DATA | map(attribute='fabrics') | map('dict2items') | flatten | list + }} + +- name: Set fact for child fabric names + set_fact: + child_fabric_names: >- + {{ + fabric_children | map(attribute='fabricName') | list + }} + +- name: Generate payload for fabrics to be removed + set_fact: + remove_payload: >- + [ + {% for fabric in existing_fabrics if fabric.key not in child_fabric_names %} + { + "operation": "remove", + "clusterName": "{{ fabric.value.clusterName }}", + "fabricName": "{{ fabric.key }}" + }{% if not loop.last %},{% endif %} + {% endfor %} + ] + +- name: Remove fabrics from NDFC + cisco.dcnm.dcnm_rest: + method: PUT + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' + json_data: '{{ item | to_json }}' + loop: "{{ remove_payload }}" + when: remove_payload | length > 0 diff --git a/roles/dtc/remove/tasks/sub_main_mfd.yml b/roles/dtc/remove/tasks/sub_main_mfd.yml new file mode 100644 index 000000000..7671a699a --- /dev/null +++ b/roles/dtc/remove/tasks/sub_main_mfd.yml @@ -0,0 +1,37 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.remove] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.remove] +" + - "----------------------------------------------------------------" + tags: "{{ nac_tags.remove }}" # Tags defined in roles/common_global/vars/main.yml + +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + tags: "{{ nac_tags.remove }}" + +- name: Remove Child Fabrics + ansible.builtin.import_tasks: mfd/child_fabrics.yml + # tags: "{{ nac_tags.remove_child_fabrics }}" diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index f573509e5..042e371cb 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -30,7 +30,7 @@ - ansible.builtin.debug: msg="Role Path - {{ role_path }}" -- ansible.builtin.debug: msg="Inventory Directory - {{ inventory_dir }}" +- ansible.builtin.debug: msg="Playbook Directory - {{ playbook_dir }}" - name: Validate NDFC Service Model Data ansible.builtin.debug: msg="Calling Role Validate - nac_dc_vxlan.validate" @@ -60,7 +60,7 @@ rules: "{{ rules_path }}" register: model_data vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + data_path: "{{ playbook_dir }}/host_vars/{{ inventory_hostname }}" rules_path: "{{ role_path }}/files/rules/" delegate_to: localhost @@ -70,7 +70,7 @@ mdata: "{{ data_path }}" rules: "{{ enhanced_rules_path }}" vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + data_path: "{{ playbook_dir }}/host_vars/{{ inventory_hostname }}" when: enhanced_rules_path is defined and enhanced_rules_path delegate_to: localhost From 135d8fd16c2de8a3208aa16cf84c3ec6562f969d Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:36:35 +0000 Subject: [PATCH 081/183] Update defaults.yml --- roles/validate/files/defaults.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 145091ed0..ab5c8793f 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -52,7 +52,7 @@ factory_defaults: ptp: ptp_enable: false enable_nxapi: true - enable_nxapi_http: true + enable_nxapi_http: false snmp_server_host_trap: true bootstrap: cdp_enable: false @@ -290,4 +290,4 @@ factory_defaults: as_override: false route_reflector_client: false default_originate: false - next_hop_self: false \ No newline at end of file + next_hop_self: false From d37a596669ba60b2de9b7f5dc57a090fe5149f4a Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Wed, 26 Feb 2025 09:48:38 +0000 Subject: [PATCH 082/183] Update ndfc_attach_vrfs_loopbacks_fed.j2 --- roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 index ae9ce69e4..ac04d779e 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 @@ -13,7 +13,7 @@ "extensionValues": "", "vlan": {{ vrf["vlan_id"] }}, "deployment": true, - "instanceValues": "{\"loopbackId\": \"{{ attach['loopback_id'] }}\", \"loopbackIpAddress\": \"{{ attach['loopback_ipv4'] | default('') }}\", \"loopbackIpV6Address\":\"{{ attach['loopback_ipv6'] | default('') }}\"}" + "instanceValues": "{\"loopbackId\": \"{{ attach['loopback_id'] | default('') }}\", \"loopbackIpAddress\": \"{{ attach['loopback_ipv4'] | default('') }}\", \"loopbackIpV6Address\":\"{{ attach['loopback_ipv6'] | default('') }}\"}" }{% if not loop.last %},{% endif %} {% endfor %} ] From 8f783a8370aedbb09b9b889ec743f9666141733e Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 28 Feb 2025 10:56:18 +0000 Subject: [PATCH 083/183] Update links_filter_and_remove.py --- plugins/action/dtc/links_filter_and_remove.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/action/dtc/links_filter_and_remove.py b/plugins/action/dtc/links_filter_and_remove.py index b74492086..e79b07cc8 100644 --- a/plugins/action/dtc/links_filter_and_remove.py +++ b/plugins/action/dtc/links_filter_and_remove.py @@ -44,7 +44,7 @@ def run(self, tmp=None, task_vars=None): links_to_be_removed = [] filtered_existing_links = [] for existing_link in existing_links: - if existing_link['templateName'] == "int_pre_provision_intra_fabric_link": + if existing_link.get('templateName') == "int_pre_provision_intra_fabric_link" or existing_link.get('templateName') == "int_intra_fabric_num_link": filtered_existing_links.append(existing_link) for link in fabric_links: if ('sw1-info' in existing_link and 'sw2-info' in existing_link and From 030595c83a43a5b4e84cd4fb5d67c3c6d18779be Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 3 Mar 2025 09:56:07 +0000 Subject: [PATCH 084/183] Update ndfc_vpc_peering.j2 --- roles/dtc/common/templates/ndfc_vpc_peering.j2 | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_vpc_peering.j2 index 0b7a7ed55..f42fa9a10 100644 --- a/roles/dtc/common/templates/ndfc_vpc_peering.j2 +++ b/roles/dtc/common/templates/ndfc_vpc_peering.j2 @@ -5,27 +5,15 @@ {% if MD.vxlan.topology.vpc_peers is defined and MD.vxlan.topology.vpc_peers is not none %} {% for vpc_peer in MD.vxlan.topology.vpc_peers %} -{% if MD_Extended.vxlan.topology.leaf is defined and vpc_peer.peer1 in MD_Extended.vxlan.topology.leaf %} {% if MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv4_address is not none %} - peerOneId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv4_address }} {% elif MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv6_address is not none %} - peerOneId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer1].management_ipv6_address }} -{% else %} -- peerOneId: {{ vpc_peer.peer1 }} {% endif %} -{% else %} -- peerOneId: {{ vpc_peer.peer1 }} -{% endif %} -{% if MD_Extended.vxlan.topology.leaf is defined and vpc_peer.peer2 in MD_Extended.vxlan.topology.leaf %} {% if MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv4_address is not none %} peerTwoId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv4_address }} {% elif MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv6_address is not none %} peerTwoId: {{ MD_Extended.vxlan.topology.leaf[vpc_peer.peer2].management_ipv6_address }} -{% else %} - peerTwoId: {{ vpc_peer.peer2 }} -{% endif %} -{% else %} - peerTwoId: {{ vpc_peer.peer2 }} {% endif %} {% if vpc_peer.fabric_peering is defined %} useVirtualPeerlink: {{ vpc_peer.fabric_peering }} From 0d3edac4451552715b3f2382ba9d52e468a2af2c Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 7 Mar 2025 10:23:05 +0000 Subject: [PATCH 085/183] Added functionality to remove VRFs and Networks on Federated ms fabrics --- .../prep_104_fabric_overlay.py | 2 + plugins/action/dtc/fed_overlay_check.py | 137 ++++++++++++++++++ plugins/plugin_utils/helper_functions.py | 6 + .../templates/ndfc_attach_networks_fed.j2 | 2 +- ...ndfc_attach_networks_switches_ports_fed.j2 | 14 +- roles/dtc/remove/tasks/mfd/networks_fed.yml | 81 +++++++++++ roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 82 +++++++++++ roles/dtc/remove/tasks/sub_main_mfd.yml | 25 ++++ 8 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 plugins/action/dtc/fed_overlay_check.py create mode 100644 roles/dtc/remove/tasks/mfd/networks_fed.yml create mode 100644 roles/dtc/remove/tasks/mfd/vrfs_fed.yml diff --git a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py index cf70df1cd..15cd33358 100644 --- a/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_104_fabric_overlay.py @@ -145,5 +145,7 @@ def prepare(self): if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] + model_data['vxlan']['multisite']['overlay_services'] = model_data['vxlan']['multisite']['overlay'] + model_data['vxlan']['overlay_services'] = model_data['vxlan']['multisite']['overlay'] self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py new file mode 100644 index 000000000..3f9ab737f --- /dev/null +++ b/plugins/action/dtc/fed_overlay_check.py @@ -0,0 +1,137 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function +import ast + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase +from ...plugin_utils.helper_functions import normalise_int_lists + +display = Display() + + +class ActionModule(ActionBase): + """ + This class is used to compare the existing links with the links that you are + looking to add to the fabric. If the link already exists, it will be added to + the not_required_links list. + """ + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + check_type = self._task.args['check_type'] + switch_data = self._task.args['switch_data'] + model_data = self._task.args['model_data'] + normal_model_data = [] + ndfc_data = self._task.args['ndfc_data'] + normal_ndfc_data = [] + restructured_data = [] + deployment = False + #normalise data for comparison + if check_type == 'network_attach': + for attached_network in ndfc_data: + for network_attached_group in attached_network['lanAttachList']: + if network_attached_group['isLanAttached'] == True: + normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + for network in model_data['vxlan']['overlay_services']['networks']: + for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name']: + for switch in network_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] + + # Restructure in case of just port removal + for item in difference: + if item['portNames'] != "": + for network in model_data['vxlan']['overlay_services']['networks']: + for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: + for switch in network_attach_group['switches']: + if switch['hostname'] == item['switchName']: + port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] + item['switchPorts'] = switch['ports'][0] + item['detachSwitchPorts'] = port_difference[0] + item['deployment'] = True + item.pop('portNames') + # Restructure the difference data into payload format + network_dict = {} + for item in difference: + network_name = item['networkName'] + if network_name not in network_dict: + network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} + network_dict[network_name]['lanAttachList'].append(item) + restructured_data = list(network_dict.values()) + + + elif check_type == 'vrf_attach': + for attached_vrf in ndfc_data: + for vrf_attached_group in attached_vrf['lanAttachList']: + if vrf_attached_group['isLanAttached'] == True: + normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) + for vrf in model_data['vxlan']['overlay_services']['vrfs']: + for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: + if vrf['vrf_attach_group'] == vrf_attach_group['name']: + for switch in vrf_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + instanceValues = {} + instanceValues['deviceSupportL3VniNoVlan'] = "false" + # if switch['loopback_id'] != "": + if switch.get('loopback_ipv4') != "": + instanceValues['loopbackIpV6Address'] = "" + instanceValues['loopbackId'] = switch['loopback_id'] + instanceValues['deviceSupportL3VniNoVlan'] = "false" + instanceValues['loopbackIpAddress'] = switch['loopback_ipv4'] + else: + instanceValues['deviceSupportL3VniNoVlan'] = "false" + normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] + + # Restructure the difference data + vrf_dict = {} + for item in difference: + vrf_name = item['vrfName'] + if vrf_name not in vrf_dict: + vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} + vrf_dict[vrf_name]['lanAttachList'].append(item) + restructured_data = list(vrf_dict.values()) + + elif check_type == 'network': + for network in model_data['vxlan']['overlay_services']['networks']: + normal_model_data.append(network['name']) + for network in ndfc_data: + normal_ndfc_data.append(network['networkName']) + network_difference = [network for network in normal_ndfc_data if network not in normal_model_data] + restructured_data = network_difference + elif check_type == 'vrf': + for vrf in model_data['vxlan']['overlay_services']['vrfs']: + normal_model_data.append(vrf['name']) + for vrf in ndfc_data: + normal_ndfc_data.append(vrf['vrfName']) + vrf_difference = [vrf for vrf in normal_ndfc_data if vrf not in normal_model_data] + restructured_data = vrf_difference + results['payload'] = restructured_data + return results + \ No newline at end of file diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index 8334353af..feadbd5b5 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -233,3 +233,9 @@ def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): ) return fabric_switches + +def normalise_int_lists(data): + for interface in data: + if interface.startswith(('Ethernet','ethernet','Eth','eth','E','e')): + interface = "Ethernet" + re.split(r'(?=\d)', interface, 1)[1] + return data \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 index bc95a6c60..b4162aace 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 @@ -6,7 +6,7 @@ "vrf":"{{ net['vrf_name'] }}", "networkTemplate":"Default_Network_Universal", "networkExtensionTemplate":"Default_Network_Extension_Universal", - "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address']}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.overlay_services.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.overlay_services.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.overlay_services.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name']}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", + "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address']}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.multisite.overlay.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.multisite.overlay.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.multisite.overlay.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.multisite.overlay.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name']}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['arp_suppress'] | default(defaults.vxlan.multisite.overlay.networks.arp_supress) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", "fabric":"{{ MD.vxlan.fabric.name }}", "type":null, "source":null, diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 index 1d8e11d79..9d0cabdc0 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 @@ -1,7 +1,8 @@ [ -{% for network in MD_Extended.vxlan.multisite.overlay.networks %} - {% for attach_group in MD_Extended.vxlan.multisite.overlay.network_attach_groups %} - {% if network.network_attach_group == attach_group.name %} +{% for network in MD_Extended.vxlan.overlay_services.networks %} +{% if network['network_attach_group'] is defined %} + {% for attach_group in MD_Extended.vxlan.overlay_services.network_attach_groups %} + {% if network.network_attach_group is defined and network.network_attach_group == attach_group.name %} {% for switch in attach_group['switches'] %} { 'networkName':'{{ network['name'] }}', @@ -18,7 +19,7 @@ {% set torString = '' %} {% set torPortString = '' %} {% for tor in switch.tors %} - {% if loop.last %} + {% if loop.last %} {% set torString = torString ~ tor.hostname %} {% set torPortString = torPortString ~ ' ' ~ tor.hostname ~ '(' ~ tor.ports | join(",") ~ ')' %} 'allSwitches':'["{{ switch['hostname'] }}","{{ switch_inv.intentedpeerName }}","{{ torString }}"]', @@ -37,8 +38,8 @@ {% endif %} {% endfor %} - - + + } {% if not loop.last %},{% endif %} @@ -46,5 +47,6 @@ {% endif %} {% endfor %} {% if not loop.last %},{% endif %} +{% endif %} {% endfor %} ] \ No newline at end of file diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml new file mode 100644 index 000000000..e52a3d111 --- /dev/null +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -0,0 +1,81 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Get network list + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" + register: networkList + +- name: Get network attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + register: networkAttachmentList + +- name: Filter network attachments to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ networkAttachmentList.response.DATA }}" + check_type: "network_attach" + switch_data: "{{ switch_list.response.DATA }}" + register: not_required_network_attachments + +- name: Remove network attachments + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + json_data: "{{ not_required_network_attachments.payload | to_json }}" + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Filter networks to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ networkList.response.DATA }}" + check_type: "network" + switch_data: "{{ switch_list.response.DATA }}" + register: not_required_networks + +- name: Remove networks + cisco.dcnm.dcnm_rest: + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/networks?network-names={{ not_required_networks.payload | join(',') }} + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_networks.payload | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "---------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" + - "---------------------------------------------------------------------------------------------------------------" + when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml new file mode 100644 index 000000000..4391dc141 --- /dev/null +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Get vrf list + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" + register: vrfList + +- name: Get vrf attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + register: vrfAttachmentList + +- name: Filter vrf attachments to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ vrfAttachmentList.response.DATA }}" + check_type: "vrf_attach" + switch_data: "{{ switch_list.response.DATA }}" + register: not_required_vrf_attachments + +- name: Remove vrf attachments + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + json_data: "{{ not_required_vrf_attachments.payload | to_json }}" + register: vrf_attachment_result + when: + - switch_list.response.DATA | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Filter vrfs to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ vrfList.response.DATA }}" + check_type: "vrf" + switch_data: "{{ switch_list.response.DATA }}" + register: not_required_vrfs + +- name: Remove vrfs + cisco.dcnm.dcnm_rest: + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/vrfs?vrf-names={{ not_required_vrfs.payload | join(',') }} + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_vrfs.payload | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + + +- ansible.builtin.debug: + msg: + - "--------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" + - "--------------------------------------------------------------------------------------------------------" + when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/sub_main_mfd.yml b/roles/dtc/remove/tasks/sub_main_mfd.yml index 7671a699a..7511394b9 100644 --- a/roles/dtc/remove/tasks/sub_main_mfd.yml +++ b/roles/dtc/remove/tasks/sub_main_mfd.yml @@ -32,6 +32,31 @@ - ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" tags: "{{ nac_tags.remove }}" +- ansible.builtin.debug: msg="Query NDFC for List of Fabric Switches" + tags: "{{ nac_tags.remove }}" + +- cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.fabric.name }}/inventory/switchesByFabric" + register: result + tags: "{{ nac_tags.remove }}" + +- name: set facts for result + ansible.builtin.set_fact: + switch_list: "{{result}}" + +- name: Remove Fabric Networks + ansible.builtin.import_tasks: mfd/networks_fed.yml + tags: "{{ nac_tags.remove_networks }}" + when: + - changes_detected_networks + +- name: Remove Fabric VRFs + ansible.builtin.import_tasks: mfd/vrfs_fed.yml + tags: "{{ nac_tags.remove_vrfs }}" + when: + - changes_detected_vrfs + - name: Remove Child Fabrics ansible.builtin.import_tasks: mfd/child_fabrics.yml # tags: "{{ nac_tags.remove_child_fabrics }}" From fe1eafe5b7725d1a10c38cc28314adb34fe57389 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 7 Feb 2025 10:52:20 +0000 Subject: [PATCH 086/183] Initial commit --- plugins/action/dtc/existing_links_check.py | 22 +++++++++- .../advanced/dc_vxlan_fabric_advanced.j2 | 12 ++++++ .../protocols/dc_vxlan_fabric_protocols.j2 | 2 + .../vpc/dc_vxlan_fabric_vpc.j2 | 7 ++- .../ndfc_interfaces/ndfc_interface_access.j2 | 2 +- .../ndfc_interface_access_po.j2 | 2 +- .../ndfc_interface_po_routed.j2 | 2 +- .../ndfc_interfaces/ndfc_interface_routed.j2 | 2 +- .../ndfc_interfaces/ndfc_interface_trunk.j2 | 2 +- .../ndfc_interface_trunk_po.j2 | 2 +- .../ndfc_interfaces/ndfc_interface_vpc.j2 | 4 ++ .../ndfc_loopback_interfaces.j2 | 2 +- .../ndfc_sub_interface_routed.j2 | 2 +- roles/dtc/common/templates/ndfc_inventory.j2 | 2 +- roles/dtc/create/tasks/common/links.yml | 17 ++------ .../dtc/create/tasks/external/interfaces.yml | 43 ++++++++++++------- roles/validate/files/defaults.yml | 12 +++++- 17 files changed, 95 insertions(+), 42 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 3f11d2eb9..917d7e0c2 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -40,6 +40,7 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] + required_links = [] not_required_links = [] for link in fabric_links: for existing_link in existing_links: @@ -53,6 +54,23 @@ def run(self, tmp=None, task_vars=None): existing_link['sw1-info']['if-name'] == link['dst_interface'] and existing_link['sw2-info']['sw-sys-name'] == link['src_device'] and existing_link['sw2-info']['if-name'] == link['src_interface'])): - not_required_links.append(link) - results['not_required_links'] = not_required_links + if 'templateName' not in existing_link: + not_required_links.append(link) + elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': + required_links.append(link) + elif existing_link['templateName'] == 'int_intra_fabric_num_link': + link['template'] = 'int_intra_fabric_num_link' + link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + else: + link['profile']['enable_macsec'] = 'false' + required_links.append(link) + else: + not_required_links.append(link) + if link not in required_links and link not in not_required_links: + required_links.append(link) + + results['required_links'] = required_links return results diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index ef484b65e..5e54c2090 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -3,6 +3,18 @@ GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false AAA_REMOTE_IP_ENABLED: False + FEATURE_PTP: {{ global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} +{% if global.ptp.ptp_enable is defined and global.ptp.ptp_enable == 'true' %} + PTP_DOMAIN_ID: {{ global.ptp.ptp_domain_id }} + PTP_LB_ID: {{ global.ptp.ptp_lb_id }} + PTP_VLAN_ID: {{ global.ptp.ptp_vlan_id }} +{% endif %} + ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} + ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} +{% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} + CDP_ENABLE: global.bootstrap.cdp_enable +{% endif %} + SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} L2_HOST_INTF_MTU: {{ vxlan.underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 index 87a895902..329a4f403 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 @@ -43,7 +43,9 @@ {% endif %} {% if (vxlan.underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} BFD_IBGP_ENABLE: {{ vxlan.underlay.bfd.ibgp | default(defaults.vxlan.underlay.bfd.ibgp) }} +{% if (vxlan.underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) ) == 'multicast' %} BFD_PIM_ENABLE: {{ vxlan.underlay.bfd.pim | default(defaults.vxlan.underlay.bfd.pim) }} +{% endif %} BFD_AUTH_ENABLE: {{ (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) }} {% if (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) == 'True' %} BFD_AUTH_KEY: {{ vxlan.underlay.bfd.authentication_key | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index f281c2183..9d1f41a27 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -1,5 +1,9 @@ {# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_FABRIC_VPC_DOMAIN_ID: False + FABRIC_VPC_QOS: {{ vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} +{% if vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) == 'false' %} + FABRIC_VPC_QOS_POLICY_NAME: {{ vxlan.global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} +{% endif %} VPC_PEER_LINK_VLAN: {{ vxlan.global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} @@ -10,4 +14,5 @@ ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} -{% endif %} \ No newline at end of file +{% endif %} + VPC_ENABLE_IPv6_ND_SYNC: {{ vxlan.global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 index 91e2c0508..d1d324974 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 @@ -21,7 +21,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 index b4a176b35..14e1a635e 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 index 18cdeb836..dda768000 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 @@ -24,7 +24,7 @@ ipv4_addr: {{ ipv4_address__mask[0] | default(omit) }} ipv4_mask_len: {{ ipv4_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 index 436205334..17c813c4d 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 @@ -29,7 +29,7 @@ ipv6_addr: {{ ipv6_address__mask[0] | default(omit) }} ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 index 86c814d20..c318fefd9 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 index 4ccfa8084..be850c14a 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 @@ -23,7 +23,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 index c96acb087..76a285847 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 @@ -34,6 +34,10 @@ pc_mode: {{ switches[peer1].pc_mode | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.pc_mode) }} peer1_members: {{ switches[peer1].members | to_json }} peer2_members: {{ switches[peer2].members | to_json }} + peer1_cmds: |2- + {{ switches[peer1].freeform_config | default('') | indent(6, false) }} + peer2_cmds: |2- + {{ switches[peer2].freeform_config | default('') | indent(6, false) }} peer1_description: "{{ switches[peer1].description | default(omit) }}" peer2_description: "{{ switches[peer2].description | default(omit) }}" bpdu_guard: {{ switches[peer1].enable_bpdu_guard | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enable_bpdu_guard) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 index 823820659..9f1844d16 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 @@ -24,7 +24,7 @@ mode: fabric {% endif %} int_vrf: {{ interface.vrf | default(omit) }} - description: {{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }} + description: "{{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }}" admin_state: {{ interface.enabled | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.enabled) }} ipv4_addr: {{ interface.ipv4_address | default(omit) }} ipv6_addr: {{ interface.ipv6_address | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 index 6e5b0b637..610588f4a 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 @@ -30,7 +30,7 @@ ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} vlan: {{ interface['dot1q_id'] }} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index 61a7cc58c..af2a3a86f 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -19,4 +19,4 @@ {% include '/ndfc_inventory/common/fabric_inventory.j2' %} {# Supported fabric types are: DC VXLAN EVPN and ISN #} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml index e50000144..a01af5fec 100644 --- a/roles/dtc/create/tasks/common/links.yml +++ b/roles/dtc/create/tasks/common/links.yml @@ -57,26 +57,17 @@ - name: Create a list of links that already exist cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" - fabric_links: "{{ vars_common_local.fabric_links }}" - register: not_required_links + fabric_links: "{{ fabric_links }}" + register: required_links when: result_links.response is defined -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest -- name: Set not_required_links if result_links.response is not defined - ansible.builtin.set_fact: - not_required_links: [] - when: result_links.response is not defined - -- name: remove unwanted links from required links input - ansible.builtin.set_fact: - required_links: "{{ vars_common_local.fabric_links | difference(not_required_links['not_required_links']) }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- - name: Manage NDFC Fabric Links cisco.dcnm.dcnm_links: - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ required_links }}" + src_fabric: "{{ MD.vxlan.global.name }}" + config: "{{ required_links['required_links'] }}" deploy: false state: merged register: manage_fabric_links_result diff --git a/roles/dtc/create/tasks/external/interfaces.yml b/roles/dtc/create/tasks/external/interfaces.yml index 9867e283b..b8e99b37f 100644 --- a/roles/dtc/create/tasks/external/interfaces.yml +++ b/roles/dtc/create/tasks/external/interfaces.yml @@ -28,6 +28,28 @@ - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" +# -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.vxlan.global.name }}" + state: replaced + config: "{{ interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.vxlan.global.name }}" + state: replaced + config: "{{ interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- @@ -94,27 +116,16 @@ config: "{{ vars_common_external.int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - # -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC # -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_external.interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC +# Manage interface vPC Configuration on NDFC # -------------------------------------------------------------------- -- name: Manage Interface Access +- name: Manage NDFC Fabric vPCs cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" + fabric: "{{ MD.vxlan.global.name }}" state: replaced - config: "{{ vars_common_external.interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + config: "{{ interface_vpc }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 ## Will discuss with team and switchover to the below code and remove the above code # # -------------------------------------------------------------------- diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 41e02f66f..2c15cb848 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -35,9 +35,12 @@ factory_defaults: advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 + fabric_vpc_qos: false + fabric_vpc_qos_policy_name: spine_qos_for_fabric_vpc_peering + enable_ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged - vlan_range: + vlan_range: - from: 1 to: 3967 mst_instance_range: @@ -46,6 +49,13 @@ factory_defaults: bridge_priority: 0 netflow: enable: false + ptp: + ptp_enable: false + enable_nxapi: true + enable_nxapi_http: true + snmp_server_host_trap: true + bootstrap: + cdp_enable: false topology: switches: routing_loopback_id: 0 From 3d231eb45b98a28c81405ffc6754826bff080393 Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:51:40 +0000 Subject: [PATCH 087/183] Update dc_vxlan_fabric_advanced.j2 to add braces --- .../dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 5e54c2090..64e1cc4fb 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -12,7 +12,7 @@ ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} {% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} - CDP_ENABLE: global.bootstrap.cdp_enable + CDP_ENABLE: {{ global.bootstrap.cdp_enable }} {% endif %} SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} @@ -28,4 +28,4 @@ {% endif %} STP_BRIDGE_PRIORITY: {{ vxlan.global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} {% endif %} -{% endif %} \ No newline at end of file +{% endif %} From 5925e54187ca8b0a131a9c6175d916640ecc1f67 Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:36:35 +0000 Subject: [PATCH 088/183] Update defaults.yml --- roles/validate/files/defaults.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 2c15cb848..cb44cc8cb 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -52,7 +52,7 @@ factory_defaults: ptp: ptp_enable: false enable_nxapi: true - enable_nxapi_http: true + enable_nxapi_http: false snmp_server_host_trap: true bootstrap: cdp_enable: false From 9620da9d235402f66d8259f4678d7ab6bfdd6bdd Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 7 Mar 2025 11:33:42 +0000 Subject: [PATCH 089/183] Update dc_external_fabric_advanced.j2 --- .../advanced/dc_external_fabric_advanced.j2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index ea85c02df..b8d8907c1 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -4,4 +4,8 @@ PTP_DOMAIN_ID: {{ vxlan.global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} PTP_LB_ID: {{ vxlan.global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} - ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} \ No newline at end of file + ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} + SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} +{% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.cdp_enable is defined %} + CDP_ENABLE: {{ vxlan.global.bootstrap.cdp_enable }} +{% endif %} \ No newline at end of file From 33667ee4619830b9cc5591a3c48fa1d56542b999 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 7 Mar 2025 14:04:24 +0000 Subject: [PATCH 090/183] Update order of interfaces and updating links to use MD_Extended --- roles/dtc/create/tasks/common/interfaces.yml | 44 ++++++++++---------- roles/dtc/create/tasks/common/links.yml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/roles/dtc/create/tasks/common/interfaces.yml b/roles/dtc/create/tasks/common/interfaces.yml index 1d378d151..4452e573d 100644 --- a/roles/dtc/create/tasks/common/interfaces.yml +++ b/roles/dtc/create/tasks/common/interfaces.yml @@ -42,6 +42,28 @@ - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" +# -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- @@ -108,28 +130,6 @@ config: "{{ vars_common_local.int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - # -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_local.interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Access - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_local.interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - # -------------------------------------------------------------------- # Manage interface vPC Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml index a01af5fec..52a5d7306 100644 --- a/roles/dtc/create/tasks/common/links.yml +++ b/roles/dtc/create/tasks/common/links.yml @@ -66,7 +66,7 @@ # -------------------------------------------------------------------- - name: Manage NDFC Fabric Links cisco.dcnm.dcnm_links: - src_fabric: "{{ MD.vxlan.global.name }}" + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ required_links['required_links'] }}" deploy: false state: merged From 4f251e59e33c891b155800167fc51213b6716c66 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 11 Mar 2025 15:16:45 +0000 Subject: [PATCH 091/183] Updates to add ports for NXAPI fields --- .../advanced/dc_external_fabric_advanced.j2 | 6 ++++-- .../dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 | 6 ++++-- roles/validate/files/defaults.yml | 2 -- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index b8d8907c1..faf3b762a 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -3,8 +3,10 @@ FEATURE_PTP: {{ vxlan.global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} PTP_DOMAIN_ID: {{ vxlan.global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} PTP_LB_ID: {{ vxlan.global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} - ENABLE_NXAPI: {{ vxlan.global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} - ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} + ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} + NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} + ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} + NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} {% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.cdp_enable is defined %} CDP_ENABLE: {{ vxlan.global.bootstrap.cdp_enable }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 64e1cc4fb..4539907b0 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -9,8 +9,10 @@ PTP_LB_ID: {{ global.ptp.ptp_lb_id }} PTP_VLAN_ID: {{ global.ptp.ptp_vlan_id }} {% endif %} - ENABLE_NXAPI: {{ global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} - ENABLE_NXAPI_HTTP: {{ global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} + ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} + NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} + ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} + NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} {% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} CDP_ENABLE: {{ global.bootstrap.cdp_enable }} {% endif %} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index cb44cc8cb..a0644724e 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -51,8 +51,6 @@ factory_defaults: enable: false ptp: ptp_enable: false - enable_nxapi: true - enable_nxapi_http: false snmp_server_host_trap: true bootstrap: cdp_enable: false From 7c91b4d232731c1c50cfd5eecba32b68f845648d Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Fri, 14 Mar 2025 13:16:11 +0000 Subject: [PATCH 092/183] Changes to support federated deploys and removals correctly --- plugins/action/dtc/fed_overlay_check.py | 31 +++++----- .../templates/ndfc_attach_networks_fed.j2 | 4 +- ...ndfc_attach_networks_switches_ports_fed.j2 | 8 +-- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 2 + roles/dtc/deploy/tasks/main.yml | 9 +++ roles/dtc/deploy/tasks/sub_main_mfd.yml | 61 +++++++++++++++++++ roles/dtc/remove/tasks/mfd/networks_fed.yml | 17 ++++++ roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 19 +++++- .../tasks/manage_model_files_previous.yml | 6 -- 9 files changed, 127 insertions(+), 30 deletions(-) create mode 100644 roles/dtc/deploy/tasks/sub_main_mfd.yml diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 3f9ab737f..34e25b815 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -47,13 +47,14 @@ def run(self, tmp=None, task_vars=None): normal_ndfc_data = [] restructured_data = [] deployment = False + deploy_payload = [] #normalise data for comparison if check_type == 'network_attach': - for attached_network in ndfc_data: + for attached_network in ndfc_data: for network_attached_group in attached_network['lanAttachList']: if network_attached_group['isLanAttached'] == True: normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) - for network in model_data['vxlan']['overlay_services']['networks']: + for network in model_data['vxlan']['overlay_services']['networks']: for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name']: for switch in network_attach_group['switches']: @@ -65,14 +66,17 @@ def run(self, tmp=None, task_vars=None): # Restructure in case of just port removal for item in difference: if item['portNames'] != "": - for network in model_data['vxlan']['overlay_services']['networks']: + for network in model_data['vxlan']['overlay_services']['networks']: for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: for switch in network_attach_group['switches']: if switch['hostname'] == item['switchName']: port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] - item['switchPorts'] = switch['ports'][0] - item['detachSwitchPorts'] = port_difference[0] + if switch.get('ports'): + item['switchPorts'] = ",".join(switch['ports']) + else: + item['switchPorts'] = "" + item['detachSwitchPorts'] = ",".join(port_difference) item['deployment'] = True item.pop('portNames') # Restructure the difference data into payload format @@ -82,11 +86,12 @@ def run(self, tmp=None, task_vars=None): if network_name not in network_dict: network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} network_dict[network_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) restructured_data = list(network_dict.values()) elif check_type == 'vrf_attach': - for attached_vrf in ndfc_data: + for attached_vrf in ndfc_data: for vrf_attached_group in attached_vrf['lanAttachList']: if vrf_attached_group['isLanAttached'] == True: normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) @@ -96,16 +101,6 @@ def run(self, tmp=None, task_vars=None): for switch in vrf_attach_group['switches']: for switch_entry in switch_data: if switch['hostname'] == switch_entry['logicalName']: - instanceValues = {} - instanceValues['deviceSupportL3VniNoVlan'] = "false" - # if switch['loopback_id'] != "": - if switch.get('loopback_ipv4') != "": - instanceValues['loopbackIpV6Address'] = "" - instanceValues['loopbackId'] = switch['loopback_id'] - instanceValues['deviceSupportL3VniNoVlan'] = "false" - instanceValues['loopbackIpAddress'] = switch['loopback_ipv4'] - else: - instanceValues['deviceSupportL3VniNoVlan'] = "false" normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) difference = [item for item in normal_ndfc_data if item not in normal_model_data] @@ -116,6 +111,7 @@ def run(self, tmp=None, task_vars=None): if vrf_name not in vrf_dict: vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} vrf_dict[vrf_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) restructured_data = list(vrf_dict.values()) elif check_type == 'network': @@ -133,5 +129,6 @@ def run(self, tmp=None, task_vars=None): vrf_difference = [vrf for vrf in normal_ndfc_data if vrf not in normal_model_data] restructured_data = vrf_difference results['payload'] = restructured_data + results['deploy_payload'] = set(deploy_payload) + return results - \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 index b4162aace..94ad6105a 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 @@ -3,10 +3,10 @@ { "networkName": "{{ net['name'] }}", "networkId":"{{ net['net_id'] }}", - "vrf":"{{ net['vrf_name'] }}", + "vrf":"{{ net['vrf_name'] | default('NA') }}", "networkTemplate":"Default_Network_Universal", "networkExtensionTemplate":"Default_Network_Extension_Universal", - "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address']}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.multisite.overlay.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.multisite.overlay.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.multisite.overlay.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.multisite.overlay.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name']}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['arp_suppress'] | default(defaults.vxlan.multisite.overlay.networks.arp_supress) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", + "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address'] | default('')}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"{{net['vlan_name'] | default(defaults.vxlan.overlay_services.networks.vlan_name)}}\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.overlay_services.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.overlay_services.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.overlay_services.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name'] | default('NA')}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['is_l2_only'] | default(defaults.vxlan.overlay_services.networks.is_l2_only) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", "fabric":"{{ MD.vxlan.fabric.name }}", "type":null, "source":null, diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 index 9d0cabdc0..aa87285e1 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 @@ -11,7 +11,7 @@ {% if switch_inv.logicalName == switch['hostname'] %} 'switchIP':'{{ switch_inv.ipAddress }}', 'switchSN':'{{ switch_inv.serialNumber }}', - 'peerSwitchName':'{{ switch_inv.intentedpeerName }}', + 'peerSwitchName':'{{ switch_inv.intentedpeerName | default("") }}', 'fabricName':'{{ switch_inv.fabricName }}', 'clusterName':'{{ switch_inv.clusterName }}', 'ndfcIpAddress':'{{ switch_inv.clusterIp }}', @@ -19,7 +19,7 @@ {% set torString = '' %} {% set torPortString = '' %} {% for tor in switch.tors %} - {% if loop.last %} + {% if loop.last %} {% set torString = torString ~ tor.hostname %} {% set torPortString = torPortString ~ ' ' ~ tor.hostname ~ '(' ~ tor.ports | join(",") ~ ')' %} 'allSwitches':'["{{ switch['hostname'] }}","{{ switch_inv.intentedpeerName }}","{{ torString }}"]', @@ -38,8 +38,8 @@ {% endif %} {% endfor %} - - + + } {% if not loop.last %},{% endif %} diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index a8d194f50..03aa03338 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -108,6 +108,7 @@ method: "POST" json_data: "{{ network_switches | to_json}}" when: + - network_switches is defined - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks @@ -118,6 +119,7 @@ method: "POST" json_data: "{{ network_switches_ports | to_json}}" when: + - network_switches_ports is defined - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.multisite.overlay.networks is defined - changes_detected_networks \ No newline at end of file diff --git a/roles/dtc/deploy/tasks/main.yml b/roles/dtc/deploy/tasks/main.yml index c3e858edd..1bad3a7c7 100644 --- a/roles/dtc/deploy/tasks/main.yml +++ b/roles/dtc/deploy/tasks/main.yml @@ -54,6 +54,15 @@ vars_common_msd.changes_detected_vrfs or vars_common_msd.changes_detected_networks) +- name: Import Role Tasks + ansible.builtin.import_tasks: sub_main_mfd.yml + tags: "{{ nac_tags.deploy }}" # Tags defined in roles/common_global/vars/main.yml + when: > + (MD_Extended.vxlan.fabric.type == 'MFD') and + (vars_common_mfd.changes_detected_fabric or + vars_common_mfd.changes_detected_vrfs or + vars_common_mfd.changes_detected_networks) + - name: Import Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml tags: "{{ nac_tags.deploy }}" # Tags defined in roles/common_global/vars/main.yml diff --git a/roles/dtc/deploy/tasks/sub_main_mfd.yml b/roles/dtc/deploy/tasks/sub_main_mfd.yml new file mode 100644 index 000000000..d89fc21df --- /dev/null +++ b/roles/dtc/deploy/tasks/sub_main_mfd.yml @@ -0,0 +1,61 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Role Entry Point - [cisco.nac_dc_vxlan.dtc.deploy] + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.deploy] +" + - "----------------------------------------------------------------" + +- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" + +- name: Config-Save block + block: + - name: Config-Save for Fabric {{ MD.vxlan.global.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + when: > + MD_Extended.vxlan.fabric.type == 'MFD' + + rescue: + - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} - Failed + ansible.builtin.debug: + msg: "{{ config_save.msg.DATA }}" + +- name: Extract serial numbers from switches_in_fabric + set_fact: + serial_numbers: "{{ switches_in_fabric | json_query('[*].serialNumber') }}" + +- name: Join serial numbers into a comma-separated list + set_fact: + serial_numbers_str: "{{ serial_numbers | join(',') }}" + +- name: Deploy for Federated Overlay + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{ serial_numbers_str }}?forceShowRun=false" + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index e52a3d111..9a8ab051c 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -53,6 +53,23 @@ register: network_attachment_result when: - switch_list.response.DATA | length > 0 + - not_required_network_attachments.payload | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Config-Save for Fabric {{ MD.vxlan.global.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + register: config_save + ignore_errors: True + +- name: Deploy for network attachments removal + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_network_attachments.deploy_payload | join(',') }}?forceShowRun=false + when: + - switch_list.response.DATA | length > 0 + - not_required_network_attachments.deploy_payload | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) - name: Filter networks to be removed diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index 4391dc141..d32a88fb9 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -53,6 +53,23 @@ register: vrf_attachment_result when: - switch_list.response.DATA | length > 0 + - not_required_vrf_attachments.payload | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Config-Save for Fabric {{ MD.vxlan.global.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + register: config_save + ignore_errors: True + +- name: Deploy for vrf attachments removal + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_vrf_attachments.deploy_payload | join(',') }}?forceShowRun=false + when: + - switch_list.response.DATA | length > 0 + - not_required_vrf_attachments.deploy_payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - name: Filter vrfs to be removed @@ -70,7 +87,7 @@ register: network_attachment_result when: - switch_list.response.DATA | length > 0 - - not_required_vrfs.payload | length > 0 + - not_required_vrfs.payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) diff --git a/roles/validate/tasks/manage_model_files_previous.yml b/roles/validate/tasks/manage_model_files_previous.yml index efce4f19b..a39028098 100644 --- a/roles/validate/tasks/manage_model_files_previous.yml +++ b/roles/validate/tasks/manage_model_files_previous.yml @@ -21,12 +21,6 @@ --- -- name: Check Roles - cisco.nac_dc_vxlan.common.check_roles: - role_list: "{{ ansible_play_role_names }}" - register: check_roles - delegate_to: localhost - # Check if golden and extended service model data files exist from previous runs - name: Stat the Golden Service Model Data ansible.builtin.stat: path="{{ role_path }}/files/{{ MD_Extended.vxlan.fabric.name }}_service_model_golden.json" From 02c7721ede19af08580719af98e4b03d3ad56aa7 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 21 Mar 2025 16:06:08 +0000 Subject: [PATCH 093/183] Updates to match new key names --- .../advanced/dc_external_fabric_advanced.j2 | 10 +++++----- .../advanced/dc_vxlan_fabric_advanced.j2 | 14 +++++++------- roles/validate/files/defaults.yml | 9 ++++++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index faf3b762a..6457f1bff 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -1,13 +1,13 @@ {# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} POWER_REDUNDANCY_MODE: ps-redundant - FEATURE_PTP: {{ vxlan.global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} - PTP_DOMAIN_ID: {{ vxlan.global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} - PTP_LB_ID: {{ vxlan.global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} + FEATURE_PTP: {{ vxlan.global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} + PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id | default(defaults.vxlan.global.ptp.domain_id) }} + PTP_LB_ID: {{ vxlan.global.ptp.lb_id | default(defaults.vxlan.global.ptp.lb_id) }} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} -{% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.cdp_enable is defined %} - CDP_ENABLE: {{ vxlan.global.bootstrap.cdp_enable }} +{% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.enable_cdp_mgmt is defined %} + CDP_ENABLE: {{ vxlan.global.bootstrap.enable_cdp_mgmt }} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 4539907b0..b92d44d40 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -3,18 +3,18 @@ GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false AAA_REMOTE_IP_ENABLED: False - FEATURE_PTP: {{ global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} -{% if global.ptp.ptp_enable is defined and global.ptp.ptp_enable == 'true' %} - PTP_DOMAIN_ID: {{ global.ptp.ptp_domain_id }} - PTP_LB_ID: {{ global.ptp.ptp_lb_id }} - PTP_VLAN_ID: {{ global.ptp.ptp_vlan_id }} + FEATURE_PTP: {{ global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} +{% if global.ptp.enable is defined and global.ptp.enable == 'true' %} + PTP_DOMAIN_ID: {{ global.ptp.domain_id }} + PTP_LB_ID: {{ global.ptp.lb_id }} + PTP_VLAN_ID: {{ global.ptp.vlan_id }} {% endif %} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} -{% if global.bootstrap is defined and global.bootstrap.cdp_enable is defined %} - CDP_ENABLE: {{ global.bootstrap.cdp_enable }} +{% if global.bootstrap is defined and global.bootstrap.enable_cdp_mgmt is defined %} + CDP_ENABLE: {{ global.bootstrap.enable_cdp_mgmt }} {% endif %} SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index a0644724e..6db483fd7 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -50,10 +50,10 @@ factory_defaults: netflow: enable: false ptp: - ptp_enable: false + enable: false snmp_server_host_trap: true bootstrap: - cdp_enable: false + enable_cdp_mgmt: false topology: switches: routing_loopback_id: 0 @@ -298,11 +298,14 @@ factory_defaults: ipv6_vtep_loopback_range: fd00::a10:0/120 overlay_dci: deployment_method: Direct_To_BGWS + route_server: + redistribute_direct: false + ip_tag: 54321 ipv4_dci_subnet_range: 10.10.1.0/24 ipv4_dci_subnet_mask: 30 ipv6_dci_subnet_range: fd00::a11:0/120 ipv6_dci_subnet_mask: 126 - underlay_autoconfig: true + underlay_autoconfig: true enable_bgp_send_community: false enable_bgp_log_neighbor_change: false enable_bgp_bfd: false From 9c4648f0aa743f775c4d0d860c89370390a435cc Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 26 Mar 2025 11:24:29 +0000 Subject: [PATCH 094/183] Updates to simplify fed overlay remove --- plugins/action/dtc/fed_overlay_check.py | 161 ++++++++++++-------- roles/dtc/remove/tasks/mfd/networks_fed.yml | 26 ++-- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 27 ++-- 3 files changed, 112 insertions(+), 102 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 34e25b815..8df82c10e 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -20,13 +20,11 @@ # SPDX-License-Identifier: MIT from __future__ import absolute_import, division, print_function -import ast __metaclass__ = type from ansible.utils.display import Display from ansible.plugins.action import ActionBase -from ...plugin_utils.helper_functions import normalise_int_lists display = Display() @@ -40,95 +38,124 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) check_type = self._task.args['check_type'] - switch_data = self._task.args['switch_data'] model_data = self._task.args['model_data'] normal_model_data = [] ndfc_data = self._task.args['ndfc_data'] + ndfc_attachment_data = self._task.args['ndfc_attachment_data'] normal_ndfc_data = [] restructured_data = [] + restructured_attachment_data = [] deployment = False deploy_payload = [] #normalise data for comparison - if check_type == 'network_attach': - for attached_network in ndfc_data: - for network_attached_group in attached_network['lanAttachList']: - if network_attached_group['isLanAttached'] == True: - normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) - for network in model_data['vxlan']['overlay_services']['networks']: - for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: - if network.get('network_attach_group') == network_attach_group['name']: - for switch in network_attach_group['switches']: - for switch_entry in switch_data: - if switch['hostname'] == switch_entry['logicalName']: - normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) - difference = [item for item in normal_ndfc_data if item not in normal_model_data] - - # Restructure in case of just port removal - for item in difference: - if item['portNames'] != "": - for network in model_data['vxlan']['overlay_services']['networks']: - for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: - if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: - for switch in network_attach_group['switches']: - if switch['hostname'] == item['switchName']: - port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] - if switch.get('ports'): - item['switchPorts'] = ",".join(switch['ports']) - else: - item['switchPorts'] = "" - item['detachSwitchPorts'] = ",".join(port_difference) - item['deployment'] = True - item.pop('portNames') - # Restructure the difference data into payload format - network_dict = {} - for item in difference: - network_name = item['networkName'] - if network_name not in network_dict: - network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} - network_dict[network_name]['lanAttachList'].append(item) - deploy_payload.append(item['serialNumber']) - restructured_data = list(network_dict.values()) + # if check_type == 'network_attach': + # for attached_network in ndfc_data: + # for network_attached_group in attached_network['lanAttachList']: + # if network_attached_group['isLanAttached'] == True: + # normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + # for network in model_data['vxlan']['overlay_services']['networks']: + # for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + # if network.get('network_attach_group') == network_attach_group['name']: + # for switch in network_attach_group['switches']: + # for switch_entry in switch_data: + # if switch['hostname'] == switch_entry['logicalName']: + # normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) + # difference = [item for item in normal_ndfc_data if item not in normal_model_data] + # # Restructure in case of just port removal + # # for item in difference: + # # if item['portNames'] != "": + # # for network in model_data['vxlan']['overlay_services']['networks']: + # # for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + # # if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: + # # for switch in network_attach_group['switches']: + # # if switch['hostname'] == item['switchName']: + # # port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] + # # if switch.get('ports'): + # # item['switchPorts'] = ",".join(switch['ports']) + # # else: + # # item['switchPorts'] = "" + # # item['detachSwitchPorts'] = ",".join(port_difference) + # # item['deployment'] = True + # # item.pop('portNames') + # # psuedo code for vpc pair removal when only 1 switch has changes + # # for switches in nddfc ndfc_data + # # if switch in ndfc has vpc = true and switch hostname = difference switch hostname + # # if found vpc serial is not in difference: + # # add vpc paired device payloiad from ndfc ndfc_data - elif check_type == 'vrf_attach': - for attached_vrf in ndfc_data: - for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf_attached_group['isLanAttached'] == True: - normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) - for vrf in model_data['vxlan']['overlay_services']['vrfs']: - for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: - if vrf['vrf_attach_group'] == vrf_attach_group['name']: - for switch in vrf_attach_group['switches']: - for switch_entry in switch_data: - if switch['hostname'] == switch_entry['logicalName']: - normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) - difference = [item for item in normal_ndfc_data if item not in normal_model_data] + # # Restructure the difference data into payload format + # network_dict = {} + # for item in difference: + # network_name = item['networkName'] + # if network_name not in network_dict: + # network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} + # network_dict[network_name]['lanAttachList'].append(item) + # deploy_payload.append(item['serialNumber']) + # restructured_data = list(network_dict.values()) - # Restructure the difference data - vrf_dict = {} - for item in difference: - vrf_name = item['vrfName'] - if vrf_name not in vrf_dict: - vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} - vrf_dict[vrf_name]['lanAttachList'].append(item) - deploy_payload.append(item['serialNumber']) - restructured_data = list(vrf_dict.values()) - - elif check_type == 'network': + if check_type == 'network': + network_attachment_dict = {} for network in model_data['vxlan']['overlay_services']['networks']: normal_model_data.append(network['name']) for network in ndfc_data: normal_ndfc_data.append(network['networkName']) network_difference = [network for network in normal_ndfc_data if network not in normal_model_data] restructured_data = network_difference + for network in network_difference: + for attached_network in ndfc_attachment_data: + for network_attached_group in attached_network['lanAttachList']: + if network == attached_network['networkName'] and network_attached_group['isLanAttached'] == True: + if network not in network_attachment_dict: + network_attachment_dict[network] = {'networkName': network, 'lanAttachList': []} + network_attachment_dict[network]['lanAttachList'].append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + restructured_attachment_data = list(network_attachment_dict.values()) + + # elif check_type == 'vrf_attach': + # for attached_vrf in ndfc_data: + # for vrf_attached_group in attached_vrf['lanAttachList']: + # if vrf_attached_group['isLanAttached'] == True: + # normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) + # for vrf in model_data['vxlan']['overlay_services']['vrfs']: + # for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: + # if vrf['vrf_attach_group'] == vrf_attach_group['name']: + # for switch in vrf_attach_group['switches']: + # for switch_entry in switch_data: + # if switch['hostname'] == switch_entry['logicalName']: + # normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) + # difference = [item for item in normal_ndfc_data if item not in normal_model_data] + + # # Restructure the difference data + # vrf_dict = {} + + # for item in difference: + # vrf_name = item['vrfName'] + # if vrf_name not in vrf_dict: + # vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} + # vrf_dict[vrf_name]['lanAttachList'].append(item) + # deploy_payload.append(item['serialNumber']) + # restructured_data = list(vrf_dict.values()) + elif check_type == 'vrf': + vrf_attachment_dict = {} for vrf in model_data['vxlan']['overlay_services']['vrfs']: normal_model_data.append(vrf['name']) for vrf in ndfc_data: normal_ndfc_data.append(vrf['vrfName']) vrf_difference = [vrf for vrf in normal_ndfc_data if vrf not in normal_model_data] restructured_data = vrf_difference + for vrf in vrf_difference: + for attached_vrf in ndfc_attachment_data: + for vrf_attached_group in attached_vrf['lanAttachList']: + if vrf == attached_vrf['vrfName'] and vrf_attached_group['isLanAttached'] == True: + if vrf not in vrf_attachment_dict: + vrf_attachment_dict[vrf] = {'vrfName': vrf, 'lanAttachList': []} + vrf_attachment_dict[vrf]['lanAttachList'].append({'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo'], "deployment":deployment, "fabric":vrf_attached_group['fabricName']}) + restructured_attachment_data = list(vrf_attachment_dict.values()) + results['payload'] = restructured_data + results['attachments_payload'] = restructured_attachment_data results['deploy_payload'] = set(deploy_payload) - + return results + \ No newline at end of file diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index 9a8ab051c..c68b9a206 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -37,23 +37,23 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList -- name: Filter network attachments to be removed +- name: Filter networks to be removed cisco.nac_dc_vxlan.dtc.fed_overlay_check: model_data: "{{ MD_Extended }}" - ndfc_data: "{{ networkAttachmentList.response.DATA }}" - check_type: "network_attach" - switch_data: "{{ switch_list.response.DATA }}" - register: not_required_network_attachments + ndfc_data: "{{ networkList.response.DATA }}" + ndfc_attachment_data: "{{ networkAttachmentList.response.DATA }}" + check_type: "network" + register: not_required_networks - name: Remove network attachments cisco.dcnm.dcnm_rest: method: POST path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments - json_data: "{{ not_required_network_attachments.payload | to_json }}" + json_data: "{{ not_required_networks.attachments_payload | to_json }}" register: network_attachment_result when: - switch_list.response.DATA | length > 0 - - not_required_network_attachments.payload | length > 0 + - not_required_networks.attachments_payload | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) - name: Config-Save for Fabric {{ MD.vxlan.global.name }} @@ -66,20 +66,12 @@ - name: Deploy for network attachments removal cisco.dcnm.dcnm_rest: method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_network_attachments.deploy_payload | join(',') }}?forceShowRun=false + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_networks.deploy_payload | join(',') }}?forceShowRun=false when: - switch_list.response.DATA | length > 0 - - not_required_network_attachments.deploy_payload | length > 0 + - not_required_networks.deploy_payload | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) -- name: Filter networks to be removed - cisco.nac_dc_vxlan.dtc.fed_overlay_check: - model_data: "{{ MD_Extended }}" - ndfc_data: "{{ networkList.response.DATA }}" - check_type: "network" - switch_data: "{{ switch_list.response.DATA }}" - register: not_required_networks - - name: Remove networks cisco.dcnm.dcnm_rest: method: DELETE diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index d32a88fb9..a17321d76 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -37,23 +37,23 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments register: vrfAttachmentList -- name: Filter vrf attachments to be removed +- name: Filter vrfs to be removed cisco.nac_dc_vxlan.dtc.fed_overlay_check: model_data: "{{ MD_Extended }}" - ndfc_data: "{{ vrfAttachmentList.response.DATA }}" - check_type: "vrf_attach" - switch_data: "{{ switch_list.response.DATA }}" - register: not_required_vrf_attachments + ndfc_data: "{{ vrfList.response.DATA }}" + ndfc_attachment_data: "{{ vrfAttachmentList.response.DATA }}" + check_type: "vrf" + register: not_required_vrfs - name: Remove vrf attachments cisco.dcnm.dcnm_rest: method: POST path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments - json_data: "{{ not_required_vrf_attachments.payload | to_json }}" + json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" register: vrf_attachment_result when: - switch_list.response.DATA | length > 0 - - not_required_vrf_attachments.payload | length > 0 + - not_required_vrfs.attachments_payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - name: Config-Save for Fabric {{ MD.vxlan.global.name }} @@ -66,20 +66,12 @@ - name: Deploy for vrf attachments removal cisco.dcnm.dcnm_rest: method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_vrf_attachments.deploy_payload | join(',') }}?forceShowRun=false + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false when: - switch_list.response.DATA | length > 0 - - not_required_vrf_attachments.deploy_payload | length > 0 + - not_required_vrfs.deploy_payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) -- name: Filter vrfs to be removed - cisco.nac_dc_vxlan.dtc.fed_overlay_check: - model_data: "{{ MD_Extended }}" - ndfc_data: "{{ vrfList.response.DATA }}" - check_type: "vrf" - switch_data: "{{ switch_list.response.DATA }}" - register: not_required_vrfs - - name: Remove vrfs cisco.dcnm.dcnm_rest: method: DELETE @@ -90,7 +82,6 @@ - not_required_vrfs.payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - - ansible.builtin.debug: msg: - "--------------------------------------------------------------------------------------------------------" From e7d3fcfc42206b7ff66ff64cdbacd97f2c7e1250 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 26 Mar 2025 11:37:19 +0000 Subject: [PATCH 095/183] Update prep_105_topology_interfaces.py --- .../common/prepare_plugins/prep_105_topology_interfaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index 7fff7be0b..af6c1c3aa 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -35,7 +35,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['ISN', 'MSD', 'MFD']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MFD']: return self.kwargs['results'] model_data['vxlan']['topology']['interfaces'] = {} From 428cee2b8ed447b5ac3eed70ee93897dce86368c Mon Sep 17 00:00:00 2001 From: Matt Thurston <77060448+mthurstocisco@users.noreply.github.com> Date: Wed, 26 Mar 2025 11:46:00 +0000 Subject: [PATCH 096/183] Edge connections msd (#316) * Updates for edge connections for external and vxlan fabrics * New files required for edge connections * bug fix for policy template * updates to the c Please enter the commit message for your changes. Lines starting * whitespace and end of line fixes * Update unmanaged_edge_connections.py * Updated to support ISN fabrics for edge conn and fixed comments from Charly * Corrected mistaken extra register command --------- Co-authored-by: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> --- .../prep_118_topology_edge_connections.py | 43 +++++ .../action/dtc/unmanaged_edge_connections.py | 149 ++++++++++++++++++ plugins/action/dtc/unmanaged_policy.py | 4 +- plugins/plugin_utils/data_model_keys.py | 19 ++- plugins/plugin_utils/helper_functions.py | 4 +- roles/common_global/defaults/main.yml | 1 + roles/common_global/vars/main.yml | 14 ++ .../tasks/common/ndfc_edge_connections.yml | 83 ++++++++++ roles/dtc/common/tasks/main.yml | 2 + roles/dtc/common/tasks/sub_main_external.yml | 5 + roles/dtc/common/tasks/sub_main_isn.yml | 7 + roles/dtc/common/tasks/sub_main_vxlan.yml | 10 ++ .../common/templates/ndfc_edge_connections.j2 | 47 ++++++ .../ndfc_interfaces/ndfc_interface_access.j2 | 2 +- .../ndfc_interface_access_po.j2 | 2 +- .../ndfc_interface_po_routed.j2 | 2 +- .../ndfc_interfaces/ndfc_interface_routed.j2 | 2 +- .../ndfc_interfaces/ndfc_interface_trunk.j2 | 2 +- .../ndfc_interface_trunk_po.j2 | 2 +- .../ndfc_loopback_interfaces.j2 | 2 +- .../ndfc_sub_interface_routed.j2 | 2 +- .../create/tasks/common/edge_connections.yml | 40 +++++ roles/dtc/create/tasks/common/interfaces.yml | 44 +++--- roles/dtc/create/tasks/sub_main_external.yml | 7 + roles/dtc/create/tasks/sub_main_isn.yml | 7 + roles/dtc/create/tasks/sub_main_vxlan.yml | 24 +++ roles/dtc/deploy/tasks/sub_main_external.yml | 6 +- .../remove/tasks/common/edge_connections.yml | 67 ++++++++ .../remove/tasks/{vxlan => common}/links.yml | 0 .../tasks/{vxlan => common}/vpc_peers.yml | 0 roles/dtc/remove/tasks/main.yml | 6 +- roles/dtc/remove/tasks/sub_main_external.yml | 18 +++ roles/dtc/remove/tasks/sub_main_isn.yml | 6 + roles/dtc/remove/tasks/sub_main_vxlan.yml | 10 +- tests/sanity/ignore-2.14.txt | 2 + tests/sanity/ignore-2.15.txt | 2 + tests/sanity/ignore-2.16.txt | 2 + tests/sanity/ignore-2.17.txt | 2 + 38 files changed, 603 insertions(+), 44 deletions(-) create mode 100644 plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py create mode 100644 plugins/action/dtc/unmanaged_edge_connections.py create mode 100644 roles/dtc/common/tasks/common/ndfc_edge_connections.yml create mode 100644 roles/dtc/common/templates/ndfc_edge_connections.j2 create mode 100644 roles/dtc/create/tasks/common/edge_connections.yml create mode 100644 roles/dtc/remove/tasks/common/edge_connections.yml rename roles/dtc/remove/tasks/{vxlan => common}/links.yml (100%) rename roles/dtc/remove/tasks/{vxlan => common}/vpc_peers.yml (100%) diff --git a/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py new file mode 100644 index 000000000..3bcf2fc5f --- /dev/null +++ b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py @@ -0,0 +1,43 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + + +class PreparePlugin: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.keys = [] + + def prepare(self): + model_data = self.kwargs['results']['model_extended'] + + # Ensure that vrf_lite's switches are mapping to their respective + # management IP address from topology switches + topology_switches = model_data['vxlan']['topology']['switches'] + for link in model_data['vxlan']['topology']['edge_connections']: + if any(sw['name'] == link['source_device'] for sw in topology_switches): + found_switch = next((item for item in topology_switches if item["name"] == link['source_device'])) + if found_switch.get('management').get('management_ipv4_address'): + link['source_device_ip'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + link['source_device_ip'] = found_switch['management']['management_ipv6_address'] + + self.kwargs['results']['model_extended'] = model_data + return self.kwargs['results'] diff --git a/plugins/action/dtc/unmanaged_edge_connections.py b/plugins/action/dtc/unmanaged_edge_connections.py new file mode 100644 index 000000000..77344d0db --- /dev/null +++ b/plugins/action/dtc/unmanaged_edge_connections.py @@ -0,0 +1,149 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.plugins.action import ActionBase +from ...plugin_utils.helper_functions import ndfc_get_switch_policy_using_desc + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + results['changed'] = False + + # List of switch serial numbes obtained directly from NDFC + ndfc_sw_data = self._task.args["switch_data"] + # Data from data model + edge_connections = self._task.args["edge_connections"][0]["switch"] + restructured_edge_connections = {} + # For each switch current_sw_policies will be used to store a list of policies currently associated to the switch + # For each switch that has unmanaged policies, the switch IP address and the list of unmanaged policies will be stored + # This default dict is the start of what is required for the NDFC policy module + unmanaged_edge_connections = [ + { + "switch": [] + } + ] + # Iterate over each item in the data list + for item in edge_connections: + ip = item['ip'] + # If the IP is not already a key in the dictionary, add it with an empty list + if ip not in restructured_edge_connections: + restructured_edge_connections[ip] = [] + # Iterate over each policy and collect the descriptions + for policy in item['policies']: + description = policy['description'] + restructured_edge_connections[ip].append(description) + + # Print the resulting dictionary + # print(restructured_edge_connections) + + for ndfc_sw in ndfc_sw_data: + + # Check if the serial number from NDFC matches any serial number for a switch in the data model + # If found, grab the specific switch entry from the data model + # Also if a match, set the IP mgmt information for the current switch found + + for ip in restructured_edge_connections: + if ndfc_sw["ipAddress"] == ip: + # print(ndfc_sw) + # Query NDFC for the current switch's serial number to get back any policy that exists for that switch + # with the description prepended with "nac_" + ndfc_policies_with_edge_desc = ndfc_get_switch_policy_using_desc(self, task_vars, tmp, ndfc_sw["serialNumber"], "edge_") + # print(ndfc_policies_with_edge_desc) + for policy in ndfc_policies_with_edge_desc: + if policy['description'] not in restructured_edge_connections[ip]: + unmanaged_edge_connections[0]["switch"].append( + { + "ip": ip + } + ) + # Grab the last index of a switch added + last_idx = len(unmanaged_edge_connections[0]["switch"]) - 1 + # Since initially found there is indeed an unmananged policy, build a list of unmanaged policy + _unmanaged_edge_connections = [ + { + "name": policy["policyId"], + "description": policy["description"] + } + ] + # Update the dictionary entry for the last switch with the expected policies key the NDFC policy module expects + unmanaged_edge_connections[0]["switch"][last_idx].update( + { + "policies": _unmanaged_edge_connections + } + ) + # Currently, check two things to determine an unmanaged policy: + # Check no matching policy in the data model against the policy returned from NDFC for the current switch + # This check uses the prepended "nac_" + # Additionally, as of now, check no matching policy is from the VRF Lite policy of the data model + # If found, do the following: + # Update Ansible result status + # Add the switch to unmanaged_policies payload + # Get the last index of where the switch was added + # Build specific unmanaged policy entry + # Add unmanaged policy entry to last switch added to list + # Update Ansible for a configuration change + results['changed'] = True + # Update unmanaged_policies with the IP address of the switch that now has unmanaged policy + # The NDFC policy module can take a list of various dictionaries with the switch key previously being pre-stored + # Given this, each update the switch element with a new switch entry is the zeroth reference location always in unmanaged_policies + # Example: + # [ + # { + # "switch": [ + # { + # "ip": , + # } + # ] + # } + # ] + # Example of unmanaged policy payload: + # [ + # { + # "switch": [ + # { + # "ip": '', + # "policies": [ + # { + # "name": , + # "description": "nac_" + # }, + # { + # "name": , + # "description": "nac_" + # }, + # ] + # }, + # ] + # } + # ] + + # Store the unmanaged policy payload for return and usage in the NDFC policy module to delete from NDFC + # print(unmanaged_edge_connections) + results['unmanaged_edge_connections'] = unmanaged_edge_connections + + return results diff --git a/plugins/action/dtc/unmanaged_policy.py b/plugins/action/dtc/unmanaged_policy.py index 4e0d24f22..eadb64066 100644 --- a/plugins/action/dtc/unmanaged_policy.py +++ b/plugins/action/dtc/unmanaged_policy.py @@ -25,7 +25,7 @@ __metaclass__ = type from ansible.plugins.action import ActionBase -from ...plugin_utils.helper_functions import ndfc_get_nac_switch_policy_using_desc +from ...plugin_utils.helper_functions import ndfc_get_switch_policy_using_desc class ActionModule(ActionBase): @@ -107,7 +107,7 @@ def run(self, tmp=None, task_vars=None): # Query NDFC for the current switch's serial number to get back any policy that exists for that switch # with the description prepended with "nac_" - ndfc_policies_with_nac_desc = ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, ndfc_sw_serial_number) + ndfc_policies_with_nac_desc = ndfc_get_switch_policy_using_desc(self, task_vars, tmp, ndfc_sw_serial_number, "nac_") # Currently, check two things to determine an unmanaged policy: # Check no matching policy in the data model against the policy returned from NDFC for the current switch diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 53c276852..6882e5586 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -26,10 +26,10 @@ # from ..helper_functions import do_something root_key = 'vxlan' + # Keys here match data model schema # type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') -model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MFD': {}, 'ISN': {}} - +model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MFD': {}, 'ISN': {}, 'External': {}} # VXLAN_EVPN KEYS @@ -85,6 +85,21 @@ model_keys['ISN']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] model_keys['ISN']['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] +# External KEYS + +model_keys['External']['topology'] = [root_key, 'topology', 'KEY'] +model_keys['External']['topology.edge_connections'] = [root_key, 'topology', 'edge_connections', 'LIST'] +model_keys['External']['topology.fabric_links'] = [root_key, 'topology', 'fabric_links', 'LIST'] +model_keys['External']['topology.switches'] = [root_key, 'topology', 'switches', 'LIST'] +model_keys['External']['topology.switches.freeform'] = [root_key, 'topology', 'switches', 'freeform', 'LIST_INDEX'] +model_keys['External']['topology.switches.interfaces'] = [root_key, 'topology', 'switches', 'interfaces', 'LIST_INDEX'] +model_keys['External']['topology.vpc_peers'] = [root_key, 'topology', 'vpc_peers', 'LIST'] +# --- +model_keys['External']['policy'] = [root_key, 'policy', 'KEY'] +model_keys['External']['policy.policies'] = [root_key, 'policy', 'policies', 'LIST'] +model_keys['External']['policy.groups'] = [root_key, 'policy', 'groups', 'LIST'] +model_keys['External']['policy.switches'] = [root_key, 'policy', 'switches', 'LIST'] + # MSD KEYS # --- diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index feadbd5b5..dcc119454 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -140,7 +140,7 @@ def ndfc_get_switch_policy_using_template(self, task_vars, tmp, switch_serial_nu return policy_match -def ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, switch_serial_number): +def ndfc_get_switch_policy_using_desc(self, task_vars, tmp, switch_serial_number, prefix): """ Get NDFC policy for a given managed switch by the switch's serial number and the prepanded string nac. @@ -160,7 +160,7 @@ def ndfc_get_nac_switch_policy_using_desc(self, task_vars, tmp, switch_serial_nu policy_match = [ item for item in policy_data["response"]["DATA"] - if item.get("description", None) and "nac_" in item.get("description", None) and item["source"] == "" + if item.get("description", None) and prefix in item.get("description", None) and item["source"] == "" ] return policy_match diff --git a/roles/common_global/defaults/main.yml b/roles/common_global/defaults/main.yml index 595dbf731..aa11025f6 100644 --- a/roles/common_global/defaults/main.yml +++ b/roles/common_global/defaults/main.yml @@ -38,6 +38,7 @@ interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false link_vpc_delete_mode: false +edge_connections_delete_mode: false multisite_child_fabric_delete_mode: false multisite_network_delete_mode: false multisite_vrf_delete_mode: false diff --git a/roles/common_global/vars/main.yml b/roles/common_global/vars/main.yml index a366e6d0a..bb5a06a96 100644 --- a/roles/common_global/vars/main.yml +++ b/roles/common_global/vars/main.yml @@ -32,12 +32,14 @@ nac_tags: - cr_manage_vrfs_networks - cr_manage_policy - cr_manage_links + - cr_manage_edge_connections # ------------------------- - rr_manage_interfaces - rr_manage_networks - rr_manage_vrfs - rr_manage_vpc_peers - rr_manage_links + - rr_manage_edge_connections - rr_manage_switches - rr_manage_policy # ------------------------- @@ -57,6 +59,8 @@ nac_tags: - cr_manage_interfaces - cr_manage_vrfs_networks - cr_manage_policy + - cr_manage_edge_connections + - rr_manage_edge_connections - rr_manage_interfaces - rr_manage_networks - rr_manage_vrfs @@ -76,6 +80,8 @@ nac_tags: - cr_manage_interfaces - cr_manage_vrfs_networks - cr_manage_policy + - cr_manage_edge_connections + - rr_manage_edge_connections - rr_manage_interfaces - rr_manage_networks - rr_manage_vrfs @@ -96,6 +102,8 @@ nac_tags: - cr_manage_interfaces - cr_manage_vrfs_networks - cr_manage_policy + - cr_manage_edge_connections + - rr_manage_edge_connections - rr_manage_interfaces - rr_manage_networks - rr_manage_vrfs @@ -112,6 +120,9 @@ nac_tags: - cr_manage_vrfs_networks - cr_manage_policy - cr_manage_links + - cr_manage_edge_connections + create_edge_connections: + - cr_manage_edge_connections create_fabric: - cr_manage_fabric create_switches: @@ -135,6 +146,9 @@ nac_tags: - rr_manage_links - rr_manage_switches - rr_manage_policy + - rr_manage_edge_connections + remove_edge_connections: + - rr_manage_edge_connections remove_interfaces: - rr_manage_interfaces remove_networks: diff --git a/roles/dtc/common/tasks/common/ndfc_edge_connections.yml b/roles/dtc/common/tasks/common/ndfc_edge_connections.yml new file mode 100644 index 000000000..f4ad3e73b --- /dev/null +++ b/roles/dtc/common/tasks/common/ndfc_edge_connections.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_edge_connections: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "{{ MD_Extended.vxlan.fabric.name }}_ndfc_edge_connections.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: Build Edge Connections + ansible.builtin.template: + src: ndfc_edge_connections.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set fabric_links Var default + ansible.builtin.set_fact: + edge_connections: [] + delegate_to: localhost + +- name: Set fabric_links Var + ansible.builtin.set_fact: + edge_connections: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.edge_connections | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_edge_connections: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 7575bd141..c4addbf6a 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -29,6 +29,7 @@ vars_common_vxlan: changes_detected_fabric: false changes_detected_fabric_links: false + changes_detected_edge_connections: false changes_detected_interface_access_po: false changes_detected_interface_access: false changes_detected_interfaces: false @@ -48,6 +49,7 @@ vars_common_isn: changes_detected_fabric: false changes_detected_fabric_links: false + changes_detected_edge_connections: false changes_detected_interface_access_po: false changes_detected_interface_access: false changes_detected_interfaces: false diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index 4790a2e6a..ab47632dd 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -85,6 +85,8 @@ - name: Build NDFC Policy List From Template ansible.builtin.import_tasks: common/ndfc_policy.yml +- name: Edge Connections List From Template + ansible.builtin.import_tasks: common/ndfc_edge_connections.yml # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere @@ -94,6 +96,7 @@ vars_common_external: changes_detected_fabric: "{{ changes_detected_fabric }}" changes_detected_inventory: "{{ changes_detected_inventory }}" + changes_detected_edge_connections: "{{ changes_detected_edge_connections }}" changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" changes_detected_interface_access: "{{ changes_detected_interface_access }}" changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" @@ -105,6 +108,7 @@ changes_detected_interfaces: "{{ changes_detected_interfaces }}" changes_detected_policy: "{{ changes_detected_policy }}" fabric_config: "{{ fabric_config }}" + edge_connections: "{{ edge_connections }}" interface_access_po: "{{ interface_access_po }}" interface_access: "{{ interface_access }}" interface_all: "{{ interface_all }}" @@ -125,6 +129,7 @@ - "----------------------------------------------------------------" - "+ Fabric Changes Detected - [ {{ vars_common_external.changes_detected_fabric }} ]" - "+ Inventory Changes Detected - [ {{ vars_common_external.changes_detected_inventory }} ]" + - "+ Edge Connections Changes Detected - [ {{ vars_common_external.changes_detected_edge_connections }} ]" - "+ ----- Interfaces -----" - "+ Interface Access Changes Detected - [ {{ vars_common_external.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_external.changes_detected_interface_access_po }} ]" diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml index 844c18f56..8eff75cfc 100644 --- a/roles/dtc/common/tasks/sub_main_isn.yml +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -136,6 +136,13 @@ - name: Build Fabric Links List From Template ansible.builtin.import_tasks: common/ndfc_fabric_links.yml +# -------------------------------------------------------------------- +# Build Edge Connections List From Template +# -------------------------------------------------------------------- + +- name: Edge Connections List From Template + ansible.builtin.import_tasks: common/ndfc_edge_connections.yml + # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere # -------------------------------------------------------------------- diff --git a/roles/dtc/common/tasks/sub_main_vxlan.yml b/roles/dtc/common/tasks/sub_main_vxlan.yml index aa1fbb6e5..d17b22b0a 100644 --- a/roles/dtc/common/tasks/sub_main_vxlan.yml +++ b/roles/dtc/common/tasks/sub_main_vxlan.yml @@ -164,6 +164,13 @@ - name: Build Fabric Links List From Template ansible.builtin.import_tasks: common/ndfc_fabric_links.yml +# -------------------------------------------------------------------- +# Build Edge Connections List From Template +# -------------------------------------------------------------------- + +- name: Edge Connections List From Template + ansible.builtin.import_tasks: common/ndfc_edge_connections.yml + # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere # -------------------------------------------------------------------- @@ -172,6 +179,7 @@ vars_common_vxlan: changes_detected_fabric: "{{ changes_detected_fabric }}" changes_detected_fabric_links: "{{ changes_detected_fabric_links }}" + changes_detected_edge_connections: "{{ changes_detected_edge_connections }}" changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" changes_detected_interface_access: "{{ changes_detected_interface_access }}" changes_detected_interfaces: "{{ changes_detected_interfaces }}" @@ -190,6 +198,7 @@ changes_detected_vrfs: "{{ changes_detected_vrfs }}" fabric_config: "{{ fabric_config }}" fabric_links: "{{ fabric_links }}" + edge_connections: "{{ edge_connections }}" interface_access_po: "{{ interface_access_po }}" interface_access: "{{ interface_access }}" interface_all: "{{ interface_all }}" @@ -236,6 +245,7 @@ - "+ Networks Changes Detected - [ {{ vars_common_vxlan.changes_detected_networks }} ]" - "+ Policy Changes Detected - [ {{ vars_common_vxlan.changes_detected_policy }} ]" - "+ Fabric Links Changes Detected - [ {{ vars_common_vxlan.changes_detected_fabric_links }} ]" + - "+ Edge Connections Changes Detected - [ {{ vars_common_vxlan.changes_detected_edge_connections }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 new file mode 100644 index 000000000..497f43d29 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -0,0 +1,47 @@ +--- +# This NDFC policy and switch attachments config data structure is auto-generated +# DO NOT EDIT MANUALLY +# +{% if MD_Extended.vxlan.topology.edge_connections | default([]) | length > 0 %} +- switch: +{% for link in MD_Extended.vxlan.topology.edge_connections%} + - ip: {{ link.source_device_ip }} + policies: + - create_additional_policy: False + description: {{ 'edge_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} + name: bgp_peer_template_dci_underlay_jython + policy_vars: + BGP_PASSWORD: "{{ link.bgp_section.bgp_password | default('') }}" + BGP_PASSWORD_ENABLE: {{ link.bgp_section.bgp_password_enable | default('true') }} + TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' }} + NEIGHBOR_ASN: "{{ link.bgp_section.neighbor_asn }}" + OVERRIDE_LOCAL_ASN: false + CONF: |2- + {{ link.bgp_section.peer_template_freeform | default('') | indent(14, false)}} + priority: 475 + - create_additional_policy: False + description: {{ 'edge_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} + name: ebgp_underlay_dci_template + policy_vars: + INTF_NAME: {{ link.source_interface }} + DESC: "{{ link.bgp_section.description | default ('Device ' + link.source_device + ' to Device ' + link.dest_device) }}" + IP_MASK: {{ link.local_ip }} + NEIGHBOR_IP: {{ link.neighbor_ip }} + FF_CONF: |2- + {{ link.bgp_section.bgp_freeform | default('') | indent(14, false)}} + SPEED: Auto + ADMIN_STATE: true + BGP_PASSWORD: "" + BGP_PASSWORD_ENABLE: false + OVERRIDE_LOCAL_ASN: false + POLICY_ID: "" + ROUTING_TAG: "{{ link.bgp_section.routing_tag | default('') }}" + SERIAL_NUMBER: "" + asn: "{{ MD_Extended.vxlan.global.bgp_asn }}" + BGP_TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' }} + INTF_CONF: |2- + {{ link.bgp_section.interface_freeform | default('') | indent(14, false)}} + FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} + priority: 500 +{% endfor %} +{% endif %} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 index 91e2c0508..d1d324974 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access.j2 @@ -21,7 +21,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 index b4a176b35..14e1a635e 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_access_po.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.enabled) }} mode: 'access' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 index 18cdeb836..dda768000 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_po_routed.j2 @@ -24,7 +24,7 @@ ipv4_addr: {{ ipv4_address__mask[0] | default(omit) }} ipv4_mask_len: {{ ipv4_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_po_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 index 436205334..17c813c4d 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_routed.j2 @@ -29,7 +29,7 @@ ipv6_addr: {{ ipv6_address__mask[0] | default(omit) }} ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_interface.mtu) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 index e4e77fac0..6f4de00f0 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk.j2 @@ -22,7 +22,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 index d7caaa07f..d8a81dc20 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_trunk_po.j2 @@ -23,7 +23,7 @@ profile: admin_state: {{ interface['enabled'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enabled) }} mode: 'trunk' - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.description) }}" mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.mtu) }} speed: {{ interface['speed'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.speed) }} port_type_fast: {{ interface['spanning_tree_portfast'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.spanning_tree_portfast) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 index 823820659..9f1844d16 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 @@ -24,7 +24,7 @@ mode: fabric {% endif %} int_vrf: {{ interface.vrf | default(omit) }} - description: {{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }} + description: "{{ interface.description | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.description) }}" admin_state: {{ interface.enabled | default(defaults.vxlan.topology.switches.interfaces.topology_switch_loopback_interface.enabled) }} ipv4_addr: {{ interface.ipv4_address | default(omit) }} ipv6_addr: {{ interface.ipv6_address | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 index 6e5b0b637..610588f4a 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_sub_interface_routed.j2 @@ -30,7 +30,7 @@ ipv6_mask_len: {{ ipv6_address__mask[1] | default(omit) }} {% endif %} vlan: {{ interface['dot1q_id'] }} - description: {{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }} + description: "{{ interface['description'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.description) }}" route_tag: {{ interface['ipv4_route_tag'] | default(omit) }} int_vrf: {{ interface['vrf'] | default(omit) }} mtu: {{ interface['mtu'] | default(defaults.vxlan.topology.switches.interfaces.topology_switch_routed_sub_interface.mtu) }} diff --git a/roles/dtc/create/tasks/common/edge_connections.yml b/roles/dtc/create/tasks/common/edge_connections.yml new file mode 100644 index 000000000..719d3adb5 --- /dev/null +++ b/roles/dtc/create/tasks/common/edge_connections.yml @@ -0,0 +1,40 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Manage Fabric Inter Fabric Links Entry Point + ansible.builtin.debug: + msg: + - "----------------------------------------------------------------" + - "+ Manage Inter Fabric Links {{ MD_Extended.vxlan.fabric.name }}" + - "----------------------------------------------------------------" +# -------------------------------------------------------------------- +# Manage Edge Connection Configuration on NDFC +# -------------------------------------------------------------------- +- name: Manage NDFC Inter Fabric Links + cisco.dcnm.dcnm_policy: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ edge_connections }}" + use_desc_as_key: true + deploy: false + state: merged + register: manage_edge_connections_result diff --git a/roles/dtc/create/tasks/common/interfaces.yml b/roles/dtc/create/tasks/common/interfaces.yml index 1d378d151..63d2acf39 100644 --- a/roles/dtc/create/tasks/common/interfaces.yml +++ b/roles/dtc/create/tasks/common/interfaces.yml @@ -42,6 +42,28 @@ - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" +# -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC +# -------------------------------------------------------------------- + +- name: Manage Interface Access + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_local.interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 + # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- @@ -108,28 +130,6 @@ config: "{{ vars_common_local.int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 - # -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_local.interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Access - cisco.dcnm.dcnm_interface: - fabric: "{{ MD_Extended.vxlan.fabric.name }}" - state: replaced - config: "{{ vars_common_local.interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - # -------------------------------------------------------------------- # Manage interface vPC Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index f4f499f60..f071cf675 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -48,6 +48,13 @@ - vars_common_external.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" +- name: Manage NDFC Fabric Inter Links + ansible.builtin.import_tasks: common/edge_connections.yml + when: + - MD_Extended.vxlan.topology.edge_connections | length > 0 + - changes_detected_edge_connections + tags: "{{ nac_tags.create_links }}" + - name: Manage NDFC External Fabric Interfaces ansible.builtin.import_tasks: common/interfaces.yml when: diff --git a/roles/dtc/create/tasks/sub_main_isn.yml b/roles/dtc/create/tasks/sub_main_isn.yml index 8b55e6716..67ac77961 100644 --- a/roles/dtc/create/tasks/sub_main_isn.yml +++ b/roles/dtc/create/tasks/sub_main_isn.yml @@ -47,6 +47,13 @@ - vars_common_isn.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" +- name: Manage NDFC Fabric Inter Links + ansible.builtin.import_tasks: common/edge_connections.yml + when: + - MD_Extended.vxlan.topology.edge_connections | length > 0 + - changes_detected_edge_connections + tags: "{{ nac_tags.create_links }}" + - name: Manage NDFC ISN Fabric Interfaces ansible.builtin.import_tasks: common/interfaces.yml when: diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index 35f4992b5..4ec29e5cc 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -55,6 +55,22 @@ - vars_common_vxlan.changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" +- name: Config-Save block to propagate vPC changes to the fabric + block: + - name: Config-Save for Fabric {{ MD.vxlan.fabric.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.fabric.name }}/config-save" + when: MD_Extended.vxlan.topology.switches | length > 0 + register: config_save + # TODO: Need to add logic to only save if changes are made + + rescue: + - name: Config-Save for Fabric {{ MD.vxlan.fabric.name }} - Failed + ansible.builtin.debug: + msg: "{{ config_save.msg.DATA }}" + + - name: Manage NDFC VXLAN Fabric Interfaces ansible.builtin.import_tasks: common/interfaces.yml when: @@ -62,6 +78,14 @@ - vars_common_vxlan.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" +- name: Manage NDFC Fabric Inter Links + ansible.builtin.import_tasks: common/edge_connections.yml + when: + - MD_Extended.vxlan.topology.edge_connections | length > 0 + - changes_detected_edge_connections + tags: "{{ nac_tags.create_links }}" + + - name: Manage NDFC VXLAN Fabric VRFs and Networks ansible.builtin.import_tasks: vxlan/vrfs_networks.yml when: diff --git a/roles/dtc/deploy/tasks/sub_main_external.yml b/roles/dtc/deploy/tasks/sub_main_external.yml index 3e0aca913..39d3fff6f 100644 --- a/roles/dtc/deploy/tasks/sub_main_external.yml +++ b/roles/dtc/deploy/tasks/sub_main_external.yml @@ -38,8 +38,7 @@ path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save when: > - (MD_Extended.vxlan.fabric.type == 'External' and - (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0)) + (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0) # TODO: Need to add logic to only save if changes are made rescue: @@ -55,6 +54,5 @@ ansible_command_timeout: 3000 ansible_connect_timeout: 3000 when: > - (MD_Extended.vxlan.fabric.type == 'External' and - (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0)) + (MD_Extended.vxlan.topology.switches is defined and MD_Extended.vxlan.topology.switches | length > 0) # TODO: Need to add logic to only deploy if changes are made diff --git a/roles/dtc/remove/tasks/common/edge_connections.yml b/roles/dtc/remove/tasks/common/edge_connections.yml new file mode 100644 index 000000000..72ed3a0eb --- /dev/null +++ b/roles/dtc/remove/tasks/common/edge_connections.yml @@ -0,0 +1,67 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + +- block: + - ansible.builtin.debug: msg="Removing Unmanaged Edge Connections From Switches. This could take several minutes..." + + - name: Build Unmanaged Edge Connection Payload + cisco.nac_dc_vxlan.dtc.unmanaged_edge_connections: + switch_data: "{{ switch_list.response.DATA }}" + edge_connections: "{{ edge_connections }}" + register: unmanaged_edge_connections_config + # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + + - name: Remove Unmanaged NDFC Edge Connections + cisco.dcnm.dcnm_policy: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + use_desc_as_key: true + config: "{{ unmanaged_edge_connections_config.unmanaged_edge_connections }}" + deploy: true + state: deleted + when: unmanaged_edge_connections_config.unmanaged_edge_connections | length > 0 + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - switch_list.response.DATA | length > 0 + - (edge_connections_delete_mode is defined) and (edge_connections_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "--------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Edge Connections from Switches task because edge_connections_delete_mode flag is set to False +" + - "--------------------------------------------------------------------------------------------------------" + when: not ((edge_connections_delete_mode is defined) and (edge_connections_delete_mode is true|bool)) diff --git a/roles/dtc/remove/tasks/vxlan/links.yml b/roles/dtc/remove/tasks/common/links.yml similarity index 100% rename from roles/dtc/remove/tasks/vxlan/links.yml rename to roles/dtc/remove/tasks/common/links.yml diff --git a/roles/dtc/remove/tasks/vxlan/vpc_peers.yml b/roles/dtc/remove/tasks/common/vpc_peers.yml similarity index 100% rename from roles/dtc/remove/tasks/vxlan/vpc_peers.yml rename to roles/dtc/remove/tasks/common/vpc_peers.yml diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index c0eb7168e..c860ad99c 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -33,7 +33,8 @@ vars_common_vxlan.changes_detected_networks or vars_common_vxlan.changes_detected_policy or vars_common_vxlan.changes_detected_vpc_peering or - vars_common_vxlan.changes_detected_vrfs) + vars_common_vxlan.changes_detected_vrfs or + vars_common_vxlan.changes_detected_edge_connections) - name: Import MSD Role Tasks ansible.builtin.import_tasks: sub_main_msd.yml @@ -64,7 +65,8 @@ (MD_Extended.vxlan.fabric.type == 'External') and (vars_common_external.changes_detected_interfaces or vars_common_external.changes_detected_inventory or - vars_common_external.changes_detected_policy) + vars_common_external.changes_detected_policy or + vars_common_external.changes_detected_edge_connections) - name: Mark Stage Role Remove Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/remove/tasks/sub_main_external.yml b/roles/dtc/remove/tasks/sub_main_external.yml index d270b24f2..2d21c08e2 100644 --- a/roles/dtc/remove/tasks/sub_main_external.yml +++ b/roles/dtc/remove/tasks/sub_main_external.yml @@ -38,6 +38,12 @@ register: switch_list tags: "{{ nac_tags.remove }}" +- name: Remove Edge Connections + ansible.builtin.import_tasks: common/edge_connections.yml + tags: "{{ nac_tags.remove_edge_connections }}" + when: + - vars_common_external.changes_detected_edge_connections + - name: Remove Fabric Policy ansible.builtin.import_tasks: common/policy.yml tags: "{{ nac_tags.remove_policy }}" @@ -50,6 +56,18 @@ when: - vars_common_external.changes_detected_interfaces +- name: Remove Fabric Links + ansible.builtin.import_tasks: common/links.yml + tags: "{{ nac_tags.remove_links }}" + when: + - vars_common_external.changes_detected_fabric_links + +- name: Remove Fabric vPC Peering + ansible.builtin.import_tasks: common/vpc_peers.yml + tags: "{{ nac_tags.remove_vpc_peers }}" + when: + - vars_common_external.changes_detected_vpc_peering + - name: Remove Fabric Switches ansible.builtin.import_tasks: common/switches.yml tags: "{{ nac_tags.remove_switches }}" diff --git a/roles/dtc/remove/tasks/sub_main_isn.yml b/roles/dtc/remove/tasks/sub_main_isn.yml index 00e736292..818edda86 100644 --- a/roles/dtc/remove/tasks/sub_main_isn.yml +++ b/roles/dtc/remove/tasks/sub_main_isn.yml @@ -38,6 +38,12 @@ register: switch_list tags: "{{ nac_tags.remove }}" +- name: Remove Edge Connections + ansible.builtin.import_tasks: common/edge_connections.yml + tags: "{{ nac_tags.remove_edge_connections }}" + when: + - vars_common_external.changes_detected_edge_connections + - name: Remove Fabric Policy ansible.builtin.import_tasks: common/policy.yml tags: "{{ nac_tags.remove_policy }}" diff --git a/roles/dtc/remove/tasks/sub_main_vxlan.yml b/roles/dtc/remove/tasks/sub_main_vxlan.yml index e9faf6db0..474cce2a5 100644 --- a/roles/dtc/remove/tasks/sub_main_vxlan.yml +++ b/roles/dtc/remove/tasks/sub_main_vxlan.yml @@ -38,6 +38,12 @@ register: switch_list tags: "{{ nac_tags.remove }}" +- name: Remove Edge Connections + ansible.builtin.import_tasks: common/edge_connections.yml + tags: "{{ nac_tags.remove_edge_connections }}" + when: + - vars_common_vxlan.changes_detected_edge_connections + - name: Remove Fabric Policy ansible.builtin.import_tasks: common/policy.yml tags: "{{ nac_tags.remove_policy }}" @@ -63,13 +69,13 @@ - vars_common_vxlan.changes_detected_vrfs - name: Remove Fabric Links - ansible.builtin.import_tasks: vxlan/links.yml + ansible.builtin.import_tasks: common/links.yml tags: "{{ nac_tags.remove_links }}" when: - vars_common_vxlan.changes_detected_fabric_links - name: Remove Fabric vPC Peering - ansible.builtin.import_tasks: vxlan/vpc_peers.yml + ansible.builtin.import_tasks: common/vpc_peers.yml tags: "{{ nac_tags.remove_vpc_peers }}" when: - vars_common_vxlan.changes_detected_vpc_peering diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index f06d010d4..4975daee1 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -8,6 +8,7 @@ plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plu plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_108_route_control.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -30,6 +31,7 @@ plugins/action/dtc/links_filter_and_remove.py action-plugin-docs # action plugin plugins/action/dtc/unmanaged_child_fabric_vrfs.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_child_fabric_networks.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/unmanaged_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/existing_links_check.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index f06d010d4..4975daee1 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -8,6 +8,7 @@ plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plu plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_108_route_control.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -30,6 +31,7 @@ plugins/action/dtc/links_filter_and_remove.py action-plugin-docs # action plugin plugins/action/dtc/unmanaged_child_fabric_vrfs.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_child_fabric_networks.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/unmanaged_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/existing_links_check.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index f06d010d4..4975daee1 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -8,6 +8,7 @@ plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plu plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_108_route_control.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -30,6 +31,7 @@ plugins/action/dtc/links_filter_and_remove.py action-plugin-docs # action plugin plugins/action/dtc/unmanaged_child_fabric_vrfs.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_child_fabric_networks.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/unmanaged_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/existing_links_check.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.17.txt b/tests/sanity/ignore-2.17.txt index f06d010d4..4975daee1 100644 --- a/tests/sanity/ignore-2.17.txt +++ b/tests/sanity/ignore-2.17.txt @@ -8,6 +8,7 @@ plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py action-plu plugins/action/common/prepare_plugins/prep_106_topology_vpc_interfaces.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_107_vrf_lites.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_108_route_control.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_plugins/prep_999_verify.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/prepare_service_model.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/get_credentials.py action-plugin-docs # action plugin has no matching module to provide documentation @@ -30,6 +31,7 @@ plugins/action/dtc/links_filter_and_remove.py action-plugin-docs # action plugin plugins/action/dtc/unmanaged_child_fabric_vrfs.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_child_fabric_networks.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/unmanaged_policy.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/unmanaged_edge_connections.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/get_poap_data.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/map_msd_inventory.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/existing_links_check.py action-plugin-docs # action plugin has no matching module to provide documentation From bedacd540da5461aed70d04574b51c7ebca44a37 Mon Sep 17 00:00:00 2001 From: Matt Thurston <77060448+mthurstocisco@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:54:45 +0000 Subject: [PATCH 097/183] Revert "Test extra fabric settings" (#318) --- plugins/action/dtc/existing_links_check.py | 22 +--------- .../advanced/dc_external_fabric_advanced.j2 | 16 +++---- .../advanced/dc_vxlan_fabric_advanced.j2 | 16 +------ .../protocols/dc_vxlan_fabric_protocols.j2 | 2 - .../vpc/dc_vxlan_fabric_vpc.j2 | 7 +-- .../ndfc_interfaces/ndfc_interface_vpc.j2 | 4 -- roles/dtc/common/templates/ndfc_inventory.j2 | 2 +- roles/dtc/create/tasks/common/interfaces.yml | 2 +- roles/dtc/create/tasks/common/links.yml | 15 +++++-- .../dtc/create/tasks/external/interfaces.yml | 43 +++++++------------ roles/validate/files/defaults.yml | 8 ---- 11 files changed, 39 insertions(+), 98 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 917d7e0c2..3f11d2eb9 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -40,7 +40,6 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] - required_links = [] not_required_links = [] for link in fabric_links: for existing_link in existing_links: @@ -54,23 +53,6 @@ def run(self, tmp=None, task_vars=None): existing_link['sw1-info']['if-name'] == link['dst_interface'] and existing_link['sw2-info']['sw-sys-name'] == link['src_device'] and existing_link['sw2-info']['if-name'] == link['src_interface'])): - if 'templateName' not in existing_link: - not_required_links.append(link) - elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': - required_links.append(link) - elif existing_link['templateName'] == 'int_intra_fabric_num_link': - link['template'] = 'int_intra_fabric_num_link' - link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] - link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] - if existing_link.get('nvPairs').get('ENABLE_MACSEC'): - link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] - else: - link['profile']['enable_macsec'] = 'false' - required_links.append(link) - else: - not_required_links.append(link) - if link not in required_links and link not in not_required_links: - required_links.append(link) - - results['required_links'] = required_links + not_required_links.append(link) + results['not_required_links'] = not_required_links return results diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index 6457f1bff..ea85c02df 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -1,13 +1,7 @@ {# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} POWER_REDUNDANCY_MODE: ps-redundant - FEATURE_PTP: {{ vxlan.global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} - PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id | default(defaults.vxlan.global.ptp.domain_id) }} - PTP_LB_ID: {{ vxlan.global.ptp.lb_id | default(defaults.vxlan.global.ptp.lb_id) }} - ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} - NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} - ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} - NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} - SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} -{% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.enable_cdp_mgmt is defined %} - CDP_ENABLE: {{ vxlan.global.bootstrap.enable_cdp_mgmt }} -{% endif %} \ No newline at end of file + FEATURE_PTP: {{ vxlan.global.ptp.ptp_enable | default(defaults.vxlan.global.ptp.ptp_enable) }} + PTP_DOMAIN_ID: {{ vxlan.global.ptp.ptp_domain_id | default(defaults.vxlan.global.ptp.ptp_domain_id) }} + PTP_LB_ID: {{ vxlan.global.ptp.ptp_lb_id | default(defaults.vxlan.global.ptp.ptp_lb_id) }} + ENABLE_NXAPI: {{ vxlan.global.enable_nxapi | default(defaults.vxlan.global.enable_nxapi) }} + ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http ) }} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 34f695eac..f6cd22e11 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -3,20 +3,6 @@ GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false AAA_REMOTE_IP_ENABLED: False - FEATURE_PTP: {{ global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} -{% if global.ptp.enable is defined and global.ptp.enable == 'true' %} - PTP_DOMAIN_ID: {{ global.ptp.domain_id }} - PTP_LB_ID: {{ global.ptp.lb_id }} - PTP_VLAN_ID: {{ global.ptp.vlan_id }} -{% endif %} - ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} - NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} - ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} - NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} -{% if global.bootstrap is defined and global.bootstrap.enable_cdp_mgmt is defined %} - CDP_ENABLE: {{ global.bootstrap.enable_cdp_mgmt }} -{% endif %} - SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} L2_HOST_INTF_MTU: {{ vxlan.underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} @@ -30,4 +16,4 @@ {% endif %} STP_BRIDGE_PRIORITY: {{ vxlan.global.spanning_tree.bridge_priority | default(defaults.vxlan.global.spanning_tree.bridge_priority) }} {% endif %} -{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 index 329a4f403..87a895902 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 @@ -43,9 +43,7 @@ {% endif %} {% if (vxlan.underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} BFD_IBGP_ENABLE: {{ vxlan.underlay.bfd.ibgp | default(defaults.vxlan.underlay.bfd.ibgp) }} -{% if (vxlan.underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) ) == 'multicast' %} BFD_PIM_ENABLE: {{ vxlan.underlay.bfd.pim | default(defaults.vxlan.underlay.bfd.pim) }} -{% endif %} BFD_AUTH_ENABLE: {{ (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) }} {% if (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) == 'True' %} BFD_AUTH_KEY: {{ vxlan.underlay.bfd.authentication_key | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 9d1f41a27..f281c2183 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -1,9 +1,5 @@ {# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.fabric.name }} #} ENABLE_FABRIC_VPC_DOMAIN_ID: False - FABRIC_VPC_QOS: {{ vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} -{% if vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) == 'false' %} - FABRIC_VPC_QOS_POLICY_NAME: {{ vxlan.global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} -{% endif %} VPC_PEER_LINK_VLAN: {{ vxlan.global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} @@ -14,5 +10,4 @@ ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} -{% endif %} - VPC_ENABLE_IPv6_ND_SYNC: {{ vxlan.global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 index 2d165df0b..01d8abd42 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 @@ -26,10 +26,6 @@ pc_mode: {{ switches[peer1].pc_mode | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.pc_mode) }} peer1_members: {{ switches[peer1].members | to_json }} peer2_members: {{ switches[peer2].members | to_json }} - peer1_cmds: |2- - {{ switches[peer1].freeform_config | default('') | indent(6, false) }} - peer2_cmds: |2- - {{ switches[peer2].freeform_config | default('') | indent(6, false) }} peer1_description: "{{ switches[peer1].description | default(omit) }}" peer2_description: "{{ switches[peer2].description | default(omit) }}" bpdu_guard: {{ switches[peer1].enable_bpdu_guard | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enable_bpdu_guard) }} diff --git a/roles/dtc/common/templates/ndfc_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory.j2 index af2a3a86f..61a7cc58c 100644 --- a/roles/dtc/common/templates/ndfc_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory.j2 @@ -19,4 +19,4 @@ {% include '/ndfc_inventory/common/fabric_inventory.j2' %} {# Supported fabric types are: DC VXLAN EVPN and ISN #} -{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/dtc/create/tasks/common/interfaces.yml b/roles/dtc/create/tasks/common/interfaces.yml index 4452e573d..63d2acf39 100644 --- a/roles/dtc/create/tasks/common/interfaces.yml +++ b/roles/dtc/create/tasks/common/interfaces.yml @@ -63,7 +63,7 @@ state: replaced config: "{{ vars_common_local.interface_access }}" when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - + # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml index 52a5d7306..e50000144 100644 --- a/roles/dtc/create/tasks/common/links.yml +++ b/roles/dtc/create/tasks/common/links.yml @@ -57,17 +57,26 @@ - name: Create a list of links that already exist cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" - fabric_links: "{{ fabric_links }}" - register: required_links + fabric_links: "{{ vars_common_local.fabric_links }}" + register: not_required_links when: result_links.response is defined +# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest +- name: Set not_required_links if result_links.response is not defined + ansible.builtin.set_fact: + not_required_links: [] + when: result_links.response is not defined + +- name: remove unwanted links from required links input + ansible.builtin.set_fact: + required_links: "{{ vars_common_local.fabric_links | difference(not_required_links['not_required_links']) }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- - name: Manage NDFC Fabric Links cisco.dcnm.dcnm_links: src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ required_links['required_links'] }}" + config: "{{ required_links }}" deploy: false state: merged register: manage_fabric_links_result diff --git a/roles/dtc/create/tasks/external/interfaces.yml b/roles/dtc/create/tasks/external/interfaces.yml index b8e99b37f..9867e283b 100644 --- a/roles/dtc/create/tasks/external/interfaces.yml +++ b/roles/dtc/create/tasks/external/interfaces.yml @@ -28,28 +28,6 @@ - "+ Manage Fabric Interfaces {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -# -------------------------------------------------------------------- -# Manage Interface Trunk Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Trunk - cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" - state: replaced - config: "{{ interface_trunk }}" - when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 - -# -------------------------------------------------------------------- -# Manage Interface Access Routed Configuration on NDFC -# -------------------------------------------------------------------- - -- name: Manage Interface Access - cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" - state: replaced - config: "{{ interface_access }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 - # -------------------------------------------------------------------- # Manage Interface Access Portchannel Configuration on NDFC # -------------------------------------------------------------------- @@ -116,16 +94,27 @@ config: "{{ vars_common_external.int_loopback_config }}" when: MD_Extended.vxlan.topology.interfaces.modes.loopback.count > 0 + # -------------------------------------------------------------------- +# Manage Interface Trunk Configuration on NDFC # -------------------------------------------------------------------- -# Manage interface vPC Configuration on NDFC + +- name: Manage Interface Trunk + cisco.dcnm.dcnm_interface: + fabric: "{{ MD_Extended.vxlan.fabric.name }}" + state: replaced + config: "{{ vars_common_external.interface_trunk }}" + when: MD_Extended.vxlan.topology.interfaces.modes.trunk.count > 0 + +# -------------------------------------------------------------------- +# Manage Interface Access Routed Configuration on NDFC # -------------------------------------------------------------------- -- name: Manage NDFC Fabric vPCs +- name: Manage Interface Access cisco.dcnm.dcnm_interface: - fabric: "{{ MD.vxlan.global.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ interface_vpc }}" - when: MD_Extended.vxlan.topology.interfaces.modes.access_vpc.count > 0 or MD_Extended.vxlan.topology.interfaces.modes.trunk_vpc.count > 0 + config: "{{ vars_common_external.interface_access }}" + when: MD_Extended.vxlan.topology.interfaces.modes.access.count > 0 ## Will discuss with team and switchover to the below code and remove the above code # # -------------------------------------------------------------------- diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 53186ae7a..4c6304b3f 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -39,9 +39,6 @@ factory_defaults: advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 - fabric_vpc_qos: false - fabric_vpc_qos_policy_name: spine_qos_for_fabric_vpc_peering - enable_ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged vlan_range: @@ -52,11 +49,6 @@ factory_defaults: bridge_priority: 0 netflow: enable: false - ptp: - enable: false - snmp_server_host_trap: true - bootstrap: - enable_cdp_mgmt: false topology: switches: routing_loopback_id: 0 From bd44980779ed1dd8bdd8bf4dbfcde4e7d7c2856c Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 31 Mar 2025 09:24:31 +0100 Subject: [PATCH 098/183] Corrected a few issues found after the merging of develop and the federated branches --- .../prep_118_topology_edge_connections.py | 24 ++++++++++--------- .../templates/ndfc_attach_networks_fed.j2 | 2 +- ...ndfc_attach_networks_switches_ports_fed.j2 | 4 ++-- .../advanced/dc_external_fabric_advanced.j2 | 4 ++++ .../advanced/dc_vxlan_fabric_advanced.j2 | 4 ++++ roles/dtc/common/templates/ndfc_policy.j2 | 4 ++-- roles/dtc/create/tasks/sub_main_vxlan.yml | 6 ++--- roles/dtc/remove/tasks/sub_main_external.yml | 6 ----- 8 files changed, 29 insertions(+), 25 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py index 3bcf2fc5f..2ac1cd7d6 100644 --- a/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py +++ b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py @@ -28,16 +28,18 @@ def __init__(self, **kwargs): def prepare(self): model_data = self.kwargs['results']['model_extended'] - # Ensure that vrf_lite's switches are mapping to their respective - # management IP address from topology switches - topology_switches = model_data['vxlan']['topology']['switches'] - for link in model_data['vxlan']['topology']['edge_connections']: - if any(sw['name'] == link['source_device'] for sw in topology_switches): - found_switch = next((item for item in topology_switches if item["name"] == link['source_device'])) - if found_switch.get('management').get('management_ipv4_address'): - link['source_device_ip'] = found_switch['management']['management_ipv4_address'] - elif found_switch.get('management').get('management_ipv6_address'): - link['source_device_ip'] = found_switch['management']['management_ipv6_address'] + if model_data['vxlan'].get('topology', None) is not None: - self.kwargs['results']['model_extended'] = model_data + # Ensure that vrf_lite's switches are mapping to their respective + # management IP address from topology switches + topology_switches = model_data['vxlan']['topology']['switches'] + for link in model_data['vxlan']['topology']['edge_connections']: + if any(sw['name'] == link['source_device'] for sw in topology_switches): + found_switch = next((item for item in topology_switches if item["name"] == link['source_device'])) + if found_switch.get('management').get('management_ipv4_address'): + link['source_device_ip'] = found_switch['management']['management_ipv4_address'] + elif found_switch.get('management').get('management_ipv6_address'): + link['source_device_ip'] = found_switch['management']['management_ipv6_address'] + + self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 index 94ad6105a..4a1254ef4 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 @@ -6,7 +6,7 @@ "vrf":"{{ net['vrf_name'] | default('NA') }}", "networkTemplate":"Default_Network_Universal", "networkExtensionTemplate":"Default_Network_Extension_Universal", - "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address'] | default('')}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"{{net['vlan_name'] | default(defaults.vxlan.overlay_services.networks.vlan_name)}}\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.overlay_services.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.overlay_services.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.overlay_services.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.overlay_services.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name'] | default('NA')}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['is_l2_only'] | default(defaults.vxlan.overlay_services.networks.is_l2_only) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", + "networkTemplateConfig":"{\"gatewayIpAddress\":\"{{net['gw_ip_address'] | default('')}}\",\"gatewayIpV6Address\":\"\",\"vlanName\":\"{{net['vlan_name'] | default(defaults.vxlan.multisite.overlay.networks.vlan_name)}}\",\"intfDescription\":\"{{net['int_desc'] | default(defaults.vxlan.multisite.overlay.networks.net_description)}}\",\"mtu\":\"{{net['mtu_l3intf'] | default(defaults.vxlan.multisite.overlay.networks.mtu_l3intf)}}\",\"secondaryGW1\":\"\",\"secondaryGW2\":\"\",\"secondaryGW3\":\"\",\"secondaryGW4\":\"\",\"type\":\"\",\"suppressArp\":{{net['arp_suppress'] | default(defaults.vxlan.multisite.overlay.networks.arp_supress)|string|lower}},\"tag\":\"{{net['route_tag'] | default(defaults.vxlan.multisite.overlay.networks.route_tag)}}\",\"rtBothAuto\":\"false\",\"vlanId\":\"{{net['vlan_id']}}\",\"segmentId\":\"{{ net['name']}}\",\"vrfName\":\"{{net['vrf_name'] | default('NA')}}\",\"networkName\":\"{{net['name']}}\",\"nveId\":\"1\",\"isLayer2Only\":{{net['is_l2_only'] | default(defaults.vxlan.multisite.overlay.networks.is_l2_only) |string|lower}},\"gen_address\":\"\",\"gen_mask\":\"\",\"flagSet\":\"\",\"isIpDhcpRelay\":\"\",\"isIp6DhcpRelay\":\"\",\"switchRole\":\"\"}", "fabric":"{{ MD.vxlan.fabric.name }}", "type":null, "source":null, diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 index aa87285e1..605271403 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 @@ -1,7 +1,7 @@ [ -{% for network in MD_Extended.vxlan.overlay_services.networks %} +{% for network in MD_Extended.vxlan.multisite.overlay.networks %} {% if network['network_attach_group'] is defined %} - {% for attach_group in MD_Extended.vxlan.overlay_services.network_attach_groups %} + {% for attach_group in MD_Extended.vxlan.multisite.overlay.network_attach_groups %} {% if network.network_attach_group is defined and network.network_attach_group == attach_group.name %} {% for switch in attach_group['switches'] %} { diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index 6457f1bff..3380e7b94 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -4,9 +4,13 @@ PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id | default(defaults.vxlan.global.ptp.domain_id) }} PTP_LB_ID: {{ vxlan.global.ptp.lb_id | default(defaults.vxlan.global.ptp.lb_id) }} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} +{% if vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) %} NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} +{% endif %} ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} +{% if vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) %} NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} +{% endif %} SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} {% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.enable_cdp_mgmt is defined %} CDP_ENABLE: {{ vxlan.global.bootstrap.enable_cdp_mgmt }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 34f695eac..96333fffc 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -10,9 +10,13 @@ PTP_VLAN_ID: {{ global.ptp.vlan_id }} {% endif %} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} +{% if vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) %} NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} +{% endif %} ENABLE_NXAPI_HTTP: {{ vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) }} +{% if vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) %} NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} +{% endif %} {% if global.bootstrap is defined and global.bootstrap.enable_cdp_mgmt is defined %} CDP_ENABLE: {{ global.bootstrap.enable_cdp_mgmt }} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index 0869b3478..74386a8a9 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -25,8 +25,8 @@ {% if policy_match.template_vars is defined and policy_match.template_vars %} {% for key, value in policy_match.template_vars.items() %} {% if key == "CONF" and policy_match.template_name != "switch_freeform" %} - {{ key }}: |2- - {{ value | indent(16) }} + {{ key }}: |2- + {{ value | indent(14) }} {% elif key == "CONF" %} {{ key }}: |- {{ value | indent(14) }} diff --git a/roles/dtc/create/tasks/sub_main_vxlan.yml b/roles/dtc/create/tasks/sub_main_vxlan.yml index 4ec29e5cc..9307faeb6 100644 --- a/roles/dtc/create/tasks/sub_main_vxlan.yml +++ b/roles/dtc/create/tasks/sub_main_vxlan.yml @@ -57,16 +57,16 @@ - name: Config-Save block to propagate vPC changes to the fabric block: - - name: Config-Save for Fabric {{ MD.vxlan.fabric.name }} + - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD.vxlan.fabric.name }}/config-save" + path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" when: MD_Extended.vxlan.topology.switches | length > 0 register: config_save # TODO: Need to add logic to only save if changes are made rescue: - - name: Config-Save for Fabric {{ MD.vxlan.fabric.name }} - Failed + - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} - Failed ansible.builtin.debug: msg: "{{ config_save.msg.DATA }}" diff --git a/roles/dtc/remove/tasks/sub_main_external.yml b/roles/dtc/remove/tasks/sub_main_external.yml index 2d21c08e2..e5c113ae9 100644 --- a/roles/dtc/remove/tasks/sub_main_external.yml +++ b/roles/dtc/remove/tasks/sub_main_external.yml @@ -56,12 +56,6 @@ when: - vars_common_external.changes_detected_interfaces -- name: Remove Fabric Links - ansible.builtin.import_tasks: common/links.yml - tags: "{{ nac_tags.remove_links }}" - when: - - vars_common_external.changes_detected_fabric_links - - name: Remove Fabric vPC Peering ansible.builtin.import_tasks: common/vpc_peers.yml tags: "{{ nac_tags.remove_vpc_peers }}" From 7de965d3f42e8eba50b6b43b8ac4d0ae9ce751d5 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Mon, 31 Mar 2025 10:01:54 +0100 Subject: [PATCH 099/183] Fixed usage of old fabric name in deploy and remove --- roles/dtc/deploy/tasks/sub_main_mfd.yml | 6 +++--- roles/dtc/remove/tasks/mfd/networks_fed.yml | 4 ++-- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/roles/dtc/deploy/tasks/sub_main_mfd.yml b/roles/dtc/deploy/tasks/sub_main_mfd.yml index d89fc21df..b98157587 100644 --- a/roles/dtc/deploy/tasks/sub_main_mfd.yml +++ b/roles/dtc/deploy/tasks/sub_main_mfd.yml @@ -32,10 +32,10 @@ - name: Config-Save block block: - - name: Config-Save for Fabric {{ MD.vxlan.global.name }} + - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" when: > MD_Extended.vxlan.fabric.type == 'MFD' @@ -55,7 +55,7 @@ - name: Deploy for Federated Overlay cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{ serial_numbers_str }}?forceShowRun=false" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ serial_numbers_str }}?forceShowRun=false" vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index c68b9a206..4acd20351 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -56,10 +56,10 @@ - not_required_networks.attachments_payload | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) -- name: Config-Save for Fabric {{ MD.vxlan.global.name }} +- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save ignore_errors: True diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index a17321d76..fba8bc061 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -56,17 +56,17 @@ - not_required_vrfs.attachments_payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) -- name: Config-Save for Fabric {{ MD.vxlan.global.name }} +- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-save" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save ignore_errors: True - name: Deploy for vrf attachments removal cisco.dcnm.dcnm_rest: method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false when: - switch_list.response.DATA | length > 0 - not_required_vrfs.deploy_payload | length > 0 From c5469f02704f47eb7bfb3aee1a48eaa8a2c9608f Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 1 Apr 2025 10:32:31 +0100 Subject: [PATCH 100/183] Added fabric settings --- .../ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index f281c2183..7f4a0cda6 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -1,5 +1,4 @@ {# Auto-generated NDFC DC VXLAN EVPN vPC config data structure for fabric {{ vxlan.fabric.name }} #} - ENABLE_FABRIC_VPC_DOMAIN_ID: False VPC_PEER_LINK_VLAN: {{ vxlan.global.vpc.peer_link_vlan | default(defaults.vxlan.global.vpc.peer_link_vlan) }} VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} @@ -10,4 +9,10 @@ ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} +{% endif %} + ENABLE_FABRIC_VPC_DOMAIN_ID: False + VPC_DOMAIN_ID_RANGE: {{ vxlan.global.vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} + FABRIC_VPC_QOS: {{ vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} +{% if (vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) | title) == 'True' %} + FABRIC_VPC_QOS_POLICY_NAME: {{ vxlan.global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} {% endif %} \ No newline at end of file From c23b9df806e575c00322c7fe304ba3e753032d72 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 3 Apr 2025 15:54:20 +0100 Subject: [PATCH 101/183] Added missing nd_sync_v6 paramater and fixes j2 issue --- .../advanced/dc_vxlan_fabric_advanced.j2 | 16 ++++++++-------- .../dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 | 3 ++- roles/validate/files/defaults.yml | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 index 96333fffc..7f4531cd8 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/advanced/dc_vxlan_fabric_advanced.j2 @@ -3,11 +3,11 @@ GRFIELD_DEBUG_FLAG: Enable ENABLE_PVLAN: false AAA_REMOTE_IP_ENABLED: False - FEATURE_PTP: {{ global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} -{% if global.ptp.enable is defined and global.ptp.enable == 'true' %} - PTP_DOMAIN_ID: {{ global.ptp.domain_id }} - PTP_LB_ID: {{ global.ptp.lb_id }} - PTP_VLAN_ID: {{ global.ptp.vlan_id }} + FEATURE_PTP: {{ vxlan.global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} +{% if vxlan.global.ptp.enable is defined and vxlan.global.ptp.enable == 'true' %} + PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id }} + PTP_LB_ID: {{ vxlan.global.ptp.lb_id }} + PTP_VLAN_ID: {{ vxlan.global.ptp.vlan_id }} {% endif %} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} {% if vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) %} @@ -17,10 +17,10 @@ {% if vxlan.global.enable_nxapi_http | default(defaults.vxlan.global.enable_nxapi_http) %} NXAPI_HTTP_PORT: {{ vxlan.global.nxapi_http_port | default(defaults.vxlan.global.nxapi_http_port) }} {% endif %} -{% if global.bootstrap is defined and global.bootstrap.enable_cdp_mgmt is defined %} - CDP_ENABLE: {{ global.bootstrap.enable_cdp_mgmt }} +{% if vxlan.global.bootstrap is defined and vxlan.global.bootstrap.enable_cdp_mgmt is defined %} + CDP_ENABLE: {{ vxlan.global.bootstrap.enable_cdp_mgmt }} {% endif %} - SNMP_SERVER_HOST_TRAP: {{ global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} + SNMP_SERVER_HOST_TRAP: {{ vxlan.global.snmp_server_host_trap | default(defaults.vxlan.global.snmp_server_host_trap) }} FABRIC_MTU: {{ vxlan.underlay.general.intra_fabric_interface_mtu | default(defaults.vxlan.underlay.general.intra_fabric_interface_mtu) }} L2_HOST_INTF_MTU: {{ vxlan.underlay.general.layer2_host_interfacde_mtu | default(defaults.vxlan.underlay.general.layer2_host_interfacde_mtu) }} HOST_INTF_ADMIN_STATE: {{ vxlan.underlay.general.unshut_host_interfaces | default(defaults.vxlan.underlay.general.unshut_host_interfaces) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 7f4a0cda6..ea036cbd8 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -15,4 +15,5 @@ FABRIC_VPC_QOS: {{ vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} {% if (vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) | title) == 'True' %} FABRIC_VPC_QOS_POLICY_NAME: {{ vxlan.global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} -{% endif %} \ No newline at end of file +{% endif %} + VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} \ No newline at end of file diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 4c6304b3f..bbfcf2e76 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -39,6 +39,7 @@ factory_defaults: advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 + enable_ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged vlan_range: From 43edce536f1f24c48012454d67a3819c64b57533 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 3 Apr 2025 16:00:41 +0100 Subject: [PATCH 102/183] Modified the order in the jinja --- .../ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index ea036cbd8..27a8de17e 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -3,9 +3,9 @@ VPC_PEER_KEEP_ALIVE_OPTION: {{ vxlan.global.vpc.peer_keep_alive | default(defaults.vxlan.global.vpc.peer_keep_alive) }} VPC_AUTO_RECOVERY_TIME: {{ vxlan.global.vpc.auto_recovery_time | default(defaults.vxlan.global.vpc.auto_recovery_time) }} VPC_DELAY_RESTORE_TIME: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} - VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_DOMAIN_ID_RANGE: {{ vxlan.global.vpc.domain_id_range | default(defaults.vxlan.global.vpc.domain_id_range) }} VPC_DELAY_RESTORE: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} + VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} + VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} @@ -15,5 +15,4 @@ FABRIC_VPC_QOS: {{ vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) }} {% if (vxlan.global.vpc.fabric_vpc_qos | default(defaults.vxlan.global.vpc.fabric_vpc_qos) | title) == 'True' %} FABRIC_VPC_QOS_POLICY_NAME: {{ vxlan.global.vpc.fabric_vpc_qos_policy_name | default(defaults.vxlan.global.vpc.fabric_vpc_qos_policy_name) }} -{% endif %} - VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} \ No newline at end of file +{% endif %} \ No newline at end of file From e6c2b3f550cd3c4b182fd4d47ff2896bebb4874a Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 3 Apr 2025 16:03:57 +0100 Subject: [PATCH 103/183] Updated name reference to match new data model name --- .../ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 | 2 +- roles/validate/files/defaults.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 27a8de17e..7b1bb7a2c 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -5,7 +5,7 @@ VPC_DELAY_RESTORE_TIME: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} VPC_DELAY_RESTORE: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.enable_ipv6_nd_sync | default(defaults.vxlan.global.vpc.enable_ipv6_nd_sync) }} + VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.ipv6_nd_sync | default(defaults.vxlan.global.vpc.ipv6_nd_sync) }} ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index bbfcf2e76..8b08545d6 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -39,7 +39,7 @@ factory_defaults: advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 - enable_ipv6_nd_sync: true + ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged vlan_range: From 120b6e03e28bb723343bdb465cf5820c7b09a5e4 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 3 Apr 2025 16:31:10 +0100 Subject: [PATCH 104/183] Updated to use playbook_dir --- roles/validate/tasks/sub_main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/validate/tasks/sub_main.yml b/roles/validate/tasks/sub_main.yml index 55b2bfbec..1b56ac1a0 100644 --- a/roles/validate/tasks/sub_main.yml +++ b/roles/validate/tasks/sub_main.yml @@ -60,7 +60,7 @@ rules: "{{ rules_path }}" register: model_data vars: - data_path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" + data_path: "{{ playbook_dir }}/host_vars/{{ inventory_hostname }}" rules_path: "{{ role_path }}/files/rules/" delegate_to: localhost From 6d2f0dd181019da964dc68571458e1633be4e5d9 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 3 Apr 2025 16:39:52 +0100 Subject: [PATCH 105/183] Added vxlan prefix to jinja --- .../ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 index 7b1bb7a2c..69e6de87d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/vpc/dc_vxlan_fabric_vpc.j2 @@ -5,7 +5,7 @@ VPC_DELAY_RESTORE_TIME: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} VPC_DELAY_RESTORE: {{ vxlan.global.vpc.delay_restore_time | default(defaults.vxlan.global.vpc.delay_restore_time) }} VPC_PEER_LINK_PO: {{ vxlan.global.vpc.peer_link_port_channel_id | default(defaults.vxlan.global.vpc.peer_link_port_channel_id) }} - VPC_ENABLE_IPv6_ND_SYNC: {{ global.vpc.ipv6_nd_sync | default(defaults.vxlan.global.vpc.ipv6_nd_sync) }} + VPC_ENABLE_IPv6_ND_SYNC: {{ vxlan.global.vpc.ipv6_nd_sync | default(defaults.vxlan.global.vpc.ipv6_nd_sync) }} ADVERTISE_PIP_BGP: {{ (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) }} {% if (vxlan.global.vpc.advertise_pip | default(defaults.vxlan.global.vpc.advertise_pip) | title) == 'False' %} ADVERTISE_PIP_ON_BORDER: {{ vxlan.global.vpc.advertise_pip_border_only | default(defaults.vxlan.global.vpc.advertise_pip_border_only) | title }} From 30b6b36d9c56c2ff61ab15b1c6fcdfae3299d54d Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 4 Apr 2025 14:15:56 +0100 Subject: [PATCH 106/183] Added some missing defaults and links defaults --- roles/dtc/common/templates/ndfc_fabric_links.j2 | 4 ++-- roles/validate/files/defaults.yml | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric_links.j2 b/roles/dtc/common/templates/ndfc_fabric_links.j2 index 9c02086f8..089f82a84 100644 --- a/roles/dtc/common/templates/ndfc_fabric_links.j2 +++ b/roles/dtc/common/templates/ndfc_fabric_links.j2 @@ -10,8 +10,8 @@ dst_device: "{{ link.dest_device }}" template: "{{ link.template }}" profile: - admin_state: "{{ link.admin_state }}" - mtu: "{{ link.mtu }}" + admin_state: "{{ link.admin_state | default(defaults.vxlan.topology.fabric_links.admin_state) }}" + mtu: "{{ link.mtu | default(defaults.vxlan.topology.fabric_links.mtu) }}" peer1_description: "{{ link.source_description | default('') }}" peer2_description: "{{ link.destination_description | default('') }}" {% endfor %} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 8b08545d6..55596a516 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -40,6 +40,8 @@ factory_defaults: advertise_pip_border_only: true domain_id_range: 1-1000 ipv6_nd_sync: true + fabric_vpc_qos: false + fabric_vpc_qos_policy_name: spine_qos_for_fabric_vpc_peering spanning_tree: root_bridge_protocol: unmanaged vlan_range: @@ -50,6 +52,9 @@ factory_defaults: bridge_priority: 0 netflow: enable: false + ptp: + enable: false + snmp_server_host_trap: true topology: switches: routing_loopback_id: 0 @@ -111,6 +116,8 @@ factory_defaults: vpc_peers: domain_id: 1 fabric_links: + mtu: 9216 + admin_state: true edge_connections: underlay: general: From eb9bf79f321cf53d47b520129205596a90daef7a Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 15 Apr 2025 11:05:32 +0100 Subject: [PATCH 107/183] changes of prefix from edge to nace and policy changes requried --- plugins/action/dtc/unmanaged_edge_connections.py | 14 +++++++++++--- .../dtc/common/templates/ndfc_edge_connections.j2 | 4 ++-- roles/dtc/common/templates/ndfc_policy.j2 | 4 +++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/action/dtc/unmanaged_edge_connections.py b/plugins/action/dtc/unmanaged_edge_connections.py index 77344d0db..39c0f2f08 100644 --- a/plugins/action/dtc/unmanaged_edge_connections.py +++ b/plugins/action/dtc/unmanaged_edge_connections.py @@ -71,10 +71,18 @@ def run(self, tmp=None, task_vars=None): if ndfc_sw["ipAddress"] == ip: # print(ndfc_sw) # Query NDFC for the current switch's serial number to get back any policy that exists for that switch - # with the description prepended with "nac_" + # with the description prepended with "nace_" or "edge_" + # First call with "edge_" prefix for backwards compatibility ndfc_policies_with_edge_desc = ndfc_get_switch_policy_using_desc(self, task_vars, tmp, ndfc_sw["serialNumber"], "edge_") - # print(ndfc_policies_with_edge_desc) - for policy in ndfc_policies_with_edge_desc: + + # Second call with new prefix nac edge connection prefix nace_ + ndfc_policies_with_nac_desc = ndfc_get_switch_policy_using_desc(self, task_vars, tmp, ndfc_sw["serialNumber"], "nace_") + + # Combine the results from both calls + combined_policies = ndfc_policies_with_edge_desc + ndfc_policies_with_nac_desc + + # Use the combined results in the subsequent logic + for policy in combined_policies: if policy['description'] not in restructured_edge_connections[ip]: unmanaged_edge_connections[0]["switch"].append( { diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 index 497f43d29..194d3bcab 100644 --- a/roles/dtc/common/templates/ndfc_edge_connections.j2 +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -8,7 +8,7 @@ - ip: {{ link.source_device_ip }} policies: - create_additional_policy: False - description: {{ 'edge_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} + description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} name: bgp_peer_template_dci_underlay_jython policy_vars: BGP_PASSWORD: "{{ link.bgp_section.bgp_password | default('') }}" @@ -20,7 +20,7 @@ {{ link.bgp_section.peer_template_freeform | default('') | indent(14, false)}} priority: 475 - create_additional_policy: False - description: {{ 'edge_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} + description: {{ 'nace_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} name: ebgp_underlay_dci_template policy_vars: INTF_NAME: {{ link.source_interface }} diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index 74386a8a9..72abd0f68 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -24,7 +24,7 @@ policy_vars: {% if policy_match.template_vars is defined and policy_match.template_vars %} {% for key, value in policy_match.template_vars.items() %} -{% if key == "CONF" and policy_match.template_name != "switch_freeform" %} +{% if (key == "CONF" or key == "DOMAIN_CONF") and policy_match.template_name != "switch_freeform" %} {{ key }}: |2- {{ value | indent(14) }} {% elif key == "CONF" %} @@ -35,6 +35,8 @@ {% elif value is iterable and '\n' in value %} {{ key }}: |- {{ value | indent(14) }} +{% elif value == "" %} + {{ key }}: "" {% else %} {{ key }}: {{ value | string | indent(12) | trim }} {% endif %} From 2015f8d67abc89cfb145b5c3ccddcd86c99bbc30 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 16 Apr 2025 15:30:26 +0100 Subject: [PATCH 108/183] fix for network and vrf attachments in create role and dci fabric settings --- plugins/action/dtc/fed_overlay_check.py | 136 +++++++++--------- .../mfd_fabric/dci/mfd_fabric_dci.j2 | 31 ++-- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 54 +++++++ roles/dtc/create/tasks/sub_main_mfd.yml | 16 ++- 4 files changed, 156 insertions(+), 81 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 8df82c10e..3edf51fd3 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -48,51 +48,52 @@ def run(self, tmp=None, task_vars=None): deployment = False deploy_payload = [] #normalise data for comparison - # if check_type == 'network_attach': - # for attached_network in ndfc_data: - # for network_attached_group in attached_network['lanAttachList']: - # if network_attached_group['isLanAttached'] == True: - # normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) - # for network in model_data['vxlan']['overlay_services']['networks']: - # for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: - # if network.get('network_attach_group') == network_attach_group['name']: - # for switch in network_attach_group['switches']: - # for switch_entry in switch_data: - # if switch['hostname'] == switch_entry['logicalName']: - # normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) - # difference = [item for item in normal_ndfc_data if item not in normal_model_data] + if check_type == 'network_attach': + switch_data = ndfc_data + for attached_network in ndfc_attachment_data: + for network_attached_group in attached_network['lanAttachList']: + if network_attached_group['isLanAttached'] == True: + normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + for network in model_data['vxlan']['overlay_services']['networks']: + for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name']: + for switch in network_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] - # # Restructure in case of just port removal - # # for item in difference: - # # if item['portNames'] != "": - # # for network in model_data['vxlan']['overlay_services']['networks']: - # # for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: - # # if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: - # # for switch in network_attach_group['switches']: - # # if switch['hostname'] == item['switchName']: - # # port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] - # # if switch.get('ports'): - # # item['switchPorts'] = ",".join(switch['ports']) - # # else: - # # item['switchPorts'] = "" - # # item['detachSwitchPorts'] = ",".join(port_difference) - # # item['deployment'] = True - # # item.pop('portNames') - # # psuedo code for vpc pair removal when only 1 switch has changes - # # for switches in nddfc ndfc_data - # # if switch in ndfc has vpc = true and switch hostname = difference switch hostname - # # if found vpc serial is not in difference: - # # add vpc paired device payloiad from ndfc ndfc_data + # Restructure in case of just port removal + for item in difference: + if item['portNames'] != "": + for network in model_data['vxlan']['overlay_services']['networks']: + for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: + for switch in network_attach_group['switches']: + if switch['hostname'] == item['switchName']: + port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] + if switch.get('ports'): + item['switchPorts'] = ",".join(switch['ports']) + else: + item['switchPorts'] = "" + item['detachSwitchPorts'] = ",".join(port_difference) + item['deployment'] = True + item.pop('portNames') + # psuedo code for vpc pair removal when only 1 switch has changes + # for switches in nddfc ndfc_data + # if switch in ndfc has vpc = true and switch hostname = difference switch hostname + # if found vpc serial is not in difference: + # add vpc paired device payloiad from ndfc ndfc_data - # # Restructure the difference data into payload format - # network_dict = {} - # for item in difference: - # network_name = item['networkName'] - # if network_name not in network_dict: - # network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} - # network_dict[network_name]['lanAttachList'].append(item) - # deploy_payload.append(item['serialNumber']) - # restructured_data = list(network_dict.values()) + # Restructure the difference data into payload format + network_dict = {} + for item in difference: + network_name = item['networkName'] + if network_name not in network_dict: + network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} + network_dict[network_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) + restructured_attachment_data = list(network_dict.values()) if check_type == 'network': network_attachment_dict = {} @@ -111,30 +112,31 @@ def run(self, tmp=None, task_vars=None): network_attachment_dict[network]['lanAttachList'].append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) restructured_attachment_data = list(network_attachment_dict.values()) - # elif check_type == 'vrf_attach': - # for attached_vrf in ndfc_data: - # for vrf_attached_group in attached_vrf['lanAttachList']: - # if vrf_attached_group['isLanAttached'] == True: - # normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) - # for vrf in model_data['vxlan']['overlay_services']['vrfs']: - # for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: - # if vrf['vrf_attach_group'] == vrf_attach_group['name']: - # for switch in vrf_attach_group['switches']: - # for switch_entry in switch_data: - # if switch['hostname'] == switch_entry['logicalName']: - # normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) - # difference = [item for item in normal_ndfc_data if item not in normal_model_data] + elif check_type == 'vrf_attach': + switch_data = ndfc_data + for attached_vrf in ndfc_attachment_data: + for vrf_attached_group in attached_vrf['lanAttachList']: + if vrf_attached_group['isLanAttached'] == True: + normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) + for vrf in model_data['vxlan']['overlay_services']['vrfs']: + for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: + if vrf['vrf_attach_group'] == vrf_attach_group['name']: + for switch in vrf_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] - # # Restructure the difference data - # vrf_dict = {} + # Restructure the difference data + vrf_dict = {} - # for item in difference: - # vrf_name = item['vrfName'] - # if vrf_name not in vrf_dict: - # vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} - # vrf_dict[vrf_name]['lanAttachList'].append(item) - # deploy_payload.append(item['serialNumber']) - # restructured_data = list(vrf_dict.values()) + for item in difference: + vrf_name = item['vrfName'] + if vrf_name not in vrf_dict: + vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} + vrf_dict[vrf_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) + restructured_attachment_data = list(vrf_dict.values()) elif check_type == 'vrf': vrf_attachment_dict = {} @@ -153,9 +155,11 @@ def run(self, tmp=None, task_vars=None): vrf_attachment_dict[vrf]['lanAttachList'].append({'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo'], "deployment":deployment, "fabric":vrf_attached_group['fabricName']}) restructured_attachment_data = list(vrf_attachment_dict.values()) + if deploy_payload != []: + deploy_payload = set(deploy_payload) results['payload'] = restructured_data results['attachments_payload'] = restructured_attachment_data - results['deploy_payload'] = set(deploy_payload) + results['deploy_payload'] = deploy_payload return results \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 index 51272f948..ab0376b2d 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 @@ -1,16 +1,25 @@ {# Auto-generated NDFC MSD DCI config data structure for fabric {{ vxlan.fabric.name }} #} - BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_ifc | default(defaults.vxlan.multisite.overlay_ifc) }} - MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) }} -{% if vxlan.multisite.underlay_autoconfig | default(defaults.vxlan.multisite.underlay_autoconfig) %} - ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.enable_bgp_send_community | default(defaults.vxlan.multisite.enable_bgp_send_community) }} - ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.enable_bgp_log_neighbor_change) | lower }} - ENABLE_BGP_BFD: {{ vxlan.multisite.enable_bgp_bfd | default(defaults.vxlan.multisite.enable_bgp_bfd) }} + BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_dci.deployment_method | default(defaults.vxlan.multisite.overlay_dci.deployment_method) }} +{% if ( (vxlan.multisite.overlay_dci.deployment_method | default(defaults.vxlan.multisite.overlay_dci.deployment_method) == 'Centralized_To_Route_Server') and + (vxlan.multisite.overlay_dci.route_server is defined and vxlan.multisite.overlay_dci.route_server) ) %} + RP_SERVER_IP: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='ip_address') | list | join(", ") | trim }}" + BGP_RP_ASN: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='bgp_asn') | list | join(", ") | trim }}" + ENABLE_RS_REDIST_DIRECT: {{ vxlan.multisite.overlay_dci.route_server.redistribute_direct | default(defaults.vxlan.multisite.overlay_dci.route_server.redistribute_direct) }} +{% if vxlan.multisite.overlay_dci.route_server.redistribute_direct | default(defaults.vxlan.multisite.overlay_dci.route_server.redistribute_direct) %} + RS_ROUTING_TAG: {{ vxlan.multisite.overlay_dci.route_server.ip_tag | default(defaults.vxlan.multisite.overlay_dci.route_server.ip_tag) }} {% endif %} - DELAY_RESTORE: {{ vxlan.multisite.delay_restore | default(defaults.vxlan.multisite.delay_restore) }} - MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) }} -{% if vxlan.multisite.enable_ebgp_password | default(defaults.vxlan.multisite.enable_ebgp_password) %} - MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.ebgp_password }} - MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.ebgp_password_encryption_type | default(defaults.vxlan.multisite.ebgp_password_encryption_type) }} +{% endif %} + MS_UNDERLAY_AUTOCONFIG: {{ vxlan.multisite.overlay_dci.underlay_autoconfig | default(defaults.vxlan.multisite.overlay_dci.underlay_autoconfig) }} +{% if (vxlan.multisite.overlay_dci.underlay_autoconfig | default(defaults.vxlan.multisite.overlay_dci.underlay_autoconfig) | ansible.builtin.bool) is sameas false %} + ENABLE_BGP_SEND_COMM: {{ vxlan.multisite.overlay_dci.enable_bgp_send_community | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_send_community) }} + ENABLE_BGP_LOG_NEIGHBOR_CHANGE: {{ vxlan.multisite.overlay_dci.enable_bgp_log_neighbor_change | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_log_neighbor_change) | lower }} + ENABLE_BGP_BFD: {{ vxlan.multisite.overlay_dci.enable_bgp_bfd | default(defaults.vxlan.multisite.overlay_dci.enable_bgp_bfd) }} +{% endif %} + DELAY_RESTORE: {{ vxlan.multisite.overlay_dci.delay_restore | default(defaults.vxlan.multisite.overlay_dci.delay_restore) }} + MS_IFC_BGP_PASSWORD_ENABLE: {{ vxlan.multisite.overlay_dci.enable_ebgp_password | default(defaults.vxlan.multisite.overlay_dci.enable_ebgp_password) }} +{% if vxlan.multisite.overlay_dci.enable_ebgp_password | default(defaults.vxlan.multisite.overlay_dci.enable_ebgp_password) %} + MS_IFC_BGP_PASSWORD: {{ vxlan.multisite.overlay_dci.ebgp_password }} + MS_IFC_BGP_AUTH_KEY_TYPE: {{ vxlan.multisite.overlay_dci.ebgp_password_encryption_type }} {% else %} MS_IFC_BGP_PASSWORD: "" MS_IFC_BGP_AUTH_KEY_TYPE: "" diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 03aa03338..ad2b856ff 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -79,6 +79,27 @@ - MD.vxlan.multisite.overlay.vrfs is defined - MD.vxlan.fabric.type == 'MFD' +- name: Get vrf attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + register: vrfAttachmentList + +- name: Filter vrf attachments to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ switch_list_create.response.DATA }}" + ndfc_attachment_data: "{{ vrfAttachmentList.response.DATA }}" + check_type: "vrf_attach" + register: not_required_vrfs + +- name: Remove vrf attachments + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" + register: vrf_attachment_result + # -------------------------------------------------------------------- # Manage Network Configuration for Federated NDFCs # -------------------------------------------------------------------- @@ -118,6 +139,39 @@ path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/multiattach" method: "POST" json_data: "{{ network_switches_ports | to_json}}" + when: + - network_switches_ports is defined + - MD.vxlan.fabric.type == 'MFD' + - MD.vxlan.multisite.overlay.networks is defined + - changes_detected_networks + +- name: Get network attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + register: networkAttachmentList + when: + - MD.vxlan.fabric.type == 'MFD' + - MD.vxlan.multisite.overlay.networks is defined + - changes_detected_networks + +- name: Filter network attachments to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ switch_list_create.response.DATA }}" + ndfc_attachment_data: "{{ networkAttachmentList.response.DATA }}" + check_type: "network_attach" + register: network_attachments_payload + when: + - MD.vxlan.fabric.type == 'MFD' + - MD.vxlan.multisite.overlay.networks is defined + - changes_detected_networks + +- name: Attach network to switches and ports for all networks + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - network_switches_ports is defined - MD.vxlan.fabric.type == 'MFD' diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mfd.yml index 92d9a8a83..cdbdd9db0 100644 --- a/roles/dtc/create/tasks/sub_main_mfd.yml +++ b/roles/dtc/create/tasks/sub_main_mfd.yml @@ -38,10 +38,18 @@ - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" -# - name: Manage NDFC MFD Fabric Child Fabrics -# ansible.builtin.import_tasks: mfd/child_fabrics.yml -# when: -# - MD_Extended.vxlan.multisite.child_fabrics is defined and MD_Extended.vxlan.multisite.child_fabrics | length > 0 +- ansible.builtin.debug: msg="Query NDFC for List of Fabric Switches" + tags: "{{ nac_tags.create }}" + +- cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" + register: result + tags: "{{ nac_tags.create }}" + +- name: set facts for result + ansible.builtin.set_fact: + switch_list_create: "{{result}}" - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: mfd/vrfs_networks.yml From 4c83d21f296282ab699051ff0230d2a97cd0622d Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 17 Apr 2025 14:18:13 +0100 Subject: [PATCH 109/183] fix for vxlan and MFD fabric settings --- .../dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 | 2 ++ .../templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 index 87a895902..329a4f403 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/protocols/dc_vxlan_fabric_protocols.j2 @@ -43,7 +43,9 @@ {% endif %} {% if (vxlan.underlay.bfd.enable | default(defaults.vxlan.underlay.bfd.enable) | title) == 'True' %} BFD_IBGP_ENABLE: {{ vxlan.underlay.bfd.ibgp | default(defaults.vxlan.underlay.bfd.ibgp) }} +{% if (vxlan.underlay.general.replication_mode | default(defaults.vxlan.underlay.general.replication_mode) ) == 'multicast' %} BFD_PIM_ENABLE: {{ vxlan.underlay.bfd.pim | default(defaults.vxlan.underlay.bfd.pim) }} +{% endif %} BFD_AUTH_ENABLE: {{ (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) }} {% if (vxlan.underlay.bfd.authentication_enable | default(defaults.vxlan.underlay.bfd.authentication_enable) | title) == 'True' %} BFD_AUTH_KEY: {{ vxlan.underlay.bfd.authentication_key | default(omit) }} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 index ab0376b2d..f9778341e 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 @@ -2,8 +2,8 @@ BORDER_GWY_CONNECTIONS: {{ vxlan.multisite.overlay_dci.deployment_method | default(defaults.vxlan.multisite.overlay_dci.deployment_method) }} {% if ( (vxlan.multisite.overlay_dci.deployment_method | default(defaults.vxlan.multisite.overlay_dci.deployment_method) == 'Centralized_To_Route_Server') and (vxlan.multisite.overlay_dci.route_server is defined and vxlan.multisite.overlay_dci.route_server) ) %} - RP_SERVER_IP: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='ip_address') | list | join(", ") | trim }}" - BGP_RP_ASN: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='bgp_asn') | list | join(", ") | trim }}" + RP_SERVER_IP: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='ip_address') | list | join(",") | trim }}" + BGP_RP_ASN: "{{ vxlan.multisite.overlay_dci.route_server.peers | map(attribute='bgp_asn') | list | join(",") | trim }}" ENABLE_RS_REDIST_DIRECT: {{ vxlan.multisite.overlay_dci.route_server.redistribute_direct | default(defaults.vxlan.multisite.overlay_dci.route_server.redistribute_direct) }} {% if vxlan.multisite.overlay_dci.route_server.redistribute_direct | default(defaults.vxlan.multisite.overlay_dci.route_server.redistribute_direct) %} RS_ROUTING_TAG: {{ vxlan.multisite.overlay_dci.route_server.ip_tag | default(defaults.vxlan.multisite.overlay_dci.route_server.ip_tag) }} From b84146d1e3b3e0c33e05fe43fbe46061a7991c59 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 23 Apr 2025 11:26:20 +0100 Subject: [PATCH 110/183] fixed code for new model structure --- plugins/action/dtc/fed_overlay_check.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 3edf51fd3..6eb51f7ad 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -54,8 +54,8 @@ def run(self, tmp=None, task_vars=None): for network_attached_group in attached_network['lanAttachList']: if network_attached_group['isLanAttached'] == True: normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) - for network in model_data['vxlan']['overlay_services']['networks']: - for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + for network in model_data['vxlan']['multisite']['overlay']['networks']: + for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name']: for switch in network_attach_group['switches']: for switch_entry in switch_data: @@ -66,8 +66,8 @@ def run(self, tmp=None, task_vars=None): # Restructure in case of just port removal for item in difference: if item['portNames'] != "": - for network in model_data['vxlan']['overlay_services']['networks']: - for network_attach_group in model_data['vxlan']['overlay_services']['network_attach_groups']: + for network in model_data['vxlan']['multisite']['overlay']['networks']: + for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: for switch in network_attach_group['switches']: if switch['hostname'] == item['switchName']: @@ -97,7 +97,7 @@ def run(self, tmp=None, task_vars=None): if check_type == 'network': network_attachment_dict = {} - for network in model_data['vxlan']['overlay_services']['networks']: + for network in model_data['vxlan']['multisite']['overlay']['networks']: normal_model_data.append(network['name']) for network in ndfc_data: normal_ndfc_data.append(network['networkName']) @@ -118,8 +118,8 @@ def run(self, tmp=None, task_vars=None): for vrf_attached_group in attached_vrf['lanAttachList']: if vrf_attached_group['isLanAttached'] == True: normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) - for vrf in model_data['vxlan']['overlay_services']['vrfs']: - for vrf_attach_group in model_data['vxlan']['overlay_services']['vrf_attach_groups']: + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: + for vrf_attach_group in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: if vrf['vrf_attach_group'] == vrf_attach_group['name']: for switch in vrf_attach_group['switches']: for switch_entry in switch_data: @@ -140,7 +140,7 @@ def run(self, tmp=None, task_vars=None): elif check_type == 'vrf': vrf_attachment_dict = {} - for vrf in model_data['vxlan']['overlay_services']['vrfs']: + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: normal_model_data.append(vrf['name']) for vrf in ndfc_data: normal_ndfc_data.append(vrf['vrfName']) From 468c07a8a5ad7fee8236f8e07f37c4caec8c1fd5 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 23 Apr 2025 12:04:35 +0100 Subject: [PATCH 111/183] fixed bug for deploy payload and reference to old model --- plugins/action/dtc/fed_overlay_check.py | 6 ++++-- roles/dtc/remove/tasks/mfd/networks_fed.yml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 6eb51f7ad..cc2a8a6a1 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -106,10 +106,11 @@ def run(self, tmp=None, task_vars=None): for network in network_difference: for attached_network in ndfc_attachment_data: for network_attached_group in attached_network['lanAttachList']: - if network == attached_network['networkName'] and network_attached_group['isLanAttached'] == True: + if network == attached_network['networkName'] and network == network_attached_group['networkName'] and network_attached_group['isLanAttached'] == True: if network not in network_attachment_dict: network_attachment_dict[network] = {'networkName': network, 'lanAttachList': []} network_attachment_dict[network]['lanAttachList'].append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + deploy_payload.append(network_attached_group['switchSerialNo']) restructured_attachment_data = list(network_attachment_dict.values()) elif check_type == 'vrf_attach': @@ -149,10 +150,11 @@ def run(self, tmp=None, task_vars=None): for vrf in vrf_difference: for attached_vrf in ndfc_attachment_data: for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf == attached_vrf['vrfName'] and vrf_attached_group['isLanAttached'] == True: + if vrf == attached_vrf['vrfName'] and vrf == vrf_attached_group['vrfName'] and vrf_attached_group['isLanAttached'] == True: if vrf not in vrf_attachment_dict: vrf_attachment_dict[vrf] = {'vrfName': vrf, 'lanAttachList': []} vrf_attachment_dict[vrf]['lanAttachList'].append({'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo'], "deployment":deployment, "fabric":vrf_attached_group['fabricName']}) + deploy_payload.append(vrf_attached_group['switchSerialNo']) restructured_attachment_data = list(vrf_attachment_dict.values()) if deploy_payload != []: diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index 4acd20351..a8087e1f0 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -66,7 +66,7 @@ - name: Deploy for network attachments removal cisco.dcnm.dcnm_rest: method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.global.name }}/config-deploy/{{not_required_networks.deploy_payload | join(',') }}?forceShowRun=false + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{not_required_networks.deploy_payload | join(',') }}?forceShowRun=false when: - switch_list.response.DATA | length > 0 - not_required_networks.deploy_payload | length > 0 From d1fa8f89aee957dba12ef6bb5bd168da7a32a028 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 23 Apr 2025 16:17:38 +0100 Subject: [PATCH 112/183] Increased deploy timeout --- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index fba8bc061..8efd95bfc 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -67,6 +67,9 @@ cisco.dcnm.dcnm_rest: method: POST path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 when: - switch_list.response.DATA | length > 0 - not_required_vrfs.deploy_payload | length > 0 From e141e1ca43b600bfc649b2067230d3c8dd294770 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 24 Apr 2025 17:40:48 +0100 Subject: [PATCH 113/183] insert missing changes detected variable for external fabric VPCs --- roles/dtc/common/tasks/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index c4addbf6a..282eeb83a 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -84,6 +84,7 @@ changes_detected_interface_vpc: false changes_detected_sub_interface_routed: false changes_detected_policy: false + changes_detected_vpc_peering: false tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - name: Import Role Tasks for VXLAN Fabric From 206e0bff1c96d53ec868331ebf253af4cb919e12 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 29 Apr 2025 11:41:57 +0100 Subject: [PATCH 114/183] Added support for bootstrap but no DHCP server --- .../bootstrap/dc_external_fabric_bootstrap.j2 | 2 ++ .../dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 index cde315389..ed219a54b 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/bootstrap/dc_external_fabric_bootstrap.j2 @@ -2,6 +2,7 @@ {% if vxlan.global.bootstrap is defined %} {% if vxlan.global.bootstrap.enable_bootstrap is defined and vxlan.global.bootstrap.enable_bootstrap %} BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} +{% if vxlan.global.bootstrap.enable_local_dhcp_server is defined and vxlan.global.bootstrap.enable_local_dhcp_server %} DHCP_ENABLE: {{ vxlan.global.bootstrap.enable_local_dhcp_server }} DHCP_IPV6_ENABLE: {{ vxlan.global.bootstrap.dhcp_version }} DHCP_START: {{ vxlan.global.bootstrap.dhcp_v4.scope_start_address }} @@ -11,6 +12,7 @@ BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" DOMAIN_NAME: "{{ vxlan.global.bootstrap.dhcp_v4.domain_name }}" {% endif %} +{% endif %} {% if vxlan.global.bootstrap.enable_bootstrap is defined and not vxlan.global.bootstrap.enable_bootstrap %} BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 index 116f4c996..ed219a54b 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 @@ -2,6 +2,7 @@ {% if vxlan.global.bootstrap is defined %} {% if vxlan.global.bootstrap.enable_bootstrap is defined and vxlan.global.bootstrap.enable_bootstrap %} BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} +{% if vxlan.global.bootstrap.enable_local_dhcp_server is defined and vxlan.global.bootstrap.enable_local_dhcp_server %} DHCP_ENABLE: {{ vxlan.global.bootstrap.enable_local_dhcp_server }} DHCP_IPV6_ENABLE: {{ vxlan.global.bootstrap.dhcp_version }} DHCP_START: {{ vxlan.global.bootstrap.dhcp_v4.scope_start_address }} @@ -9,6 +10,8 @@ MGMT_GW: {{ vxlan.global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} MGMT_PREFIX: {{ vxlan.global.bootstrap.dhcp_v4.mgmt_prefix }} BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" + DOMAIN_NAME: "{{ vxlan.global.bootstrap.dhcp_v4.domain_name }}" +{% endif %} {% endif %} {% if vxlan.global.bootstrap.enable_bootstrap is defined and not vxlan.global.bootstrap.enable_bootstrap %} BOOTSTRAP_ENABLE: {{ vxlan.global.bootstrap.enable_bootstrap }} From 71664031bb594a684e09800778c2555d8c796470 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 1 May 2025 09:54:21 +0100 Subject: [PATCH 115/183] links check fix, VNI ranges and defaults --- plugins/action/dtc/existing_links_check.py | 38 ++++++++++++++----- .../resources/dc_vxlan_fabric_resources.j2 | 3 ++ .../mfd_fabric/general/mfd_fabric_general.j2 | 4 +- roles/dtc/common/templates/ndfc_policy.j2 | 2 +- roles/dtc/create/tasks/common/links.yml | 15 ++------ roles/validate/files/defaults.yml | 28 ++++++++++---- 6 files changed, 57 insertions(+), 33 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 3f11d2eb9..d2b4ef1db 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -40,19 +40,37 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] + required_links = [] not_required_links = [] for link in fabric_links: for existing_link in existing_links: if ('sw1-info' in existing_link and 'sw2-info' in existing_link and 'sw-sys-name' in existing_link['sw1-info'] and 'sw-sys-name' in existing_link['sw2-info'] and - (existing_link['sw1-info']['sw-sys-name'] == link['src_device'] and - existing_link['sw1-info']['if-name'] == link['src_interface'] and - existing_link['sw2-info']['sw-sys-name'] == link['dst_device'] and - existing_link['sw2-info']['if-name'] == link['dst_interface']) or - (existing_link['sw1-info']['sw-sys-name'] == link['dst_device'] and - existing_link['sw1-info']['if-name'] == link['dst_interface'] and - existing_link['sw2-info']['sw-sys-name'] == link['src_device'] and - existing_link['sw2-info']['if-name'] == link['src_interface'])): - not_required_links.append(link) - results['not_required_links'] = not_required_links + (existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or + (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): + if 'templateName' not in existing_link: + not_required_links.append(link) + elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': + required_links.append(link) + elif existing_link['templateName'] == 'int_intra_fabric_num_link': + link['template'] = 'int_intra_fabric_num_link' + link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + else: + link['profile']['enable_macsec'] = 'false' + required_links.append(link) + else: + not_required_links.append(link) + if link not in required_links and link not in not_required_links: + required_links.append(link) + + results['required_links'] = required_links return results diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 index 3075edc56..c6625294b 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/resources/dc_vxlan_fabric_resources.j2 @@ -8,3 +8,6 @@ {% endif %} ANYCAST_RP_IP_RANGE: {{ vxlan.underlay.ipv4.underlay_rp_loopback_ip_range | default(defaults.vxlan.underlay.ipv4.underlay_rp_loopback_ip_range) }} {% endif %} + L2_SEGMENT_ID_RANGE: "{{ (vxlan.global.layer2_vni_range.from | default(defaults.vxlan.global.layer2_vni_range.from)) ~ "-" ~ (vxlan.global.layer2_vni_range.to | default(defaults.vxlan.global.layer2_vni_range.to)) }}" + L3_PARTITION_ID_RANGE: "{{ (vxlan.global.layer3_vni_range.from | default(defaults.vxlan.global.layer3_vni_range.from)) ~ "-" ~ (vxlan.global.layer3_vni_range.to | default(defaults.vxlan.global.layer3_vni_range.to)) }}" + \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 index 3757362d1..121d16220 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 @@ -10,8 +10,8 @@ FF: "MSD" FABRIC_TYPE: "MFD" FABRIC_NAME: "{{ vxlan.fabric.name }}" - L2_SEGMENT_ID_RANGE: {{ vxlan.multisite.layer2_vni_range | default(defaults.vxlan.multisite.layer2_vni_range) }} - L3_PARTITION_ID_RANGE: {{ vxlan.multisite.layer3_vni_range | default(defaults.vxlan.multisite.layer3_vni_range) }} + L2_SEGMENT_ID_RANGE: "{{ (vxlan.multisite.layer2_vni_range.from | default(defaults.vxlan.multisite.layer2_vni_range.from)) ~ "-" ~ (vxlan.multisite.layer2_vni_range.to | default(defaults.vxlan.multisite.layer2_vni_range.to)) }}" + L3_PARTITION_ID_RANGE: "{{ (vxlan.multisite.layer3_vni_range.from | default(defaults.vxlan.multisite.layer3_vni_range.from)) ~ "-" ~ (vxlan.multisite.layer3_vni_range.to | default(defaults.vxlan.multisite.layer3_vni_range.to)) }}" default_vrf: "Default_VRF_Universal" default_network: "Default_Network_Universal" vrf_extension_template: "Default_VRF_Extension_Universal" diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index 72abd0f68..9ddc2f343 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -30,7 +30,7 @@ {% elif key == "CONF" %} {{ key }}: |- {{ value | indent(14) }} -{% elif key in ["asn", "BGP_AS", "BGP_ASN", "NEIGHBOR_ASN"] %} +{% elif key in ["asn", "BGP_AS", "BGP_ASN", "NEIGHBOR_ASN", "COM"] %} {{ key }}: "{{ value | string | indent(12) | trim }}" {% elif value is iterable and '\n' in value %} {{ key }}: |- diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml index e50000144..52a5d7306 100644 --- a/roles/dtc/create/tasks/common/links.yml +++ b/roles/dtc/create/tasks/common/links.yml @@ -57,26 +57,17 @@ - name: Create a list of links that already exist cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" - fabric_links: "{{ vars_common_local.fabric_links }}" - register: not_required_links + fabric_links: "{{ fabric_links }}" + register: required_links when: result_links.response is defined -# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest -- name: Set not_required_links if result_links.response is not defined - ansible.builtin.set_fact: - not_required_links: [] - when: result_links.response is not defined - -- name: remove unwanted links from required links input - ansible.builtin.set_fact: - required_links: "{{ vars_common_local.fabric_links | difference(not_required_links['not_required_links']) }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- - name: Manage NDFC Fabric Links cisco.dcnm.dcnm_links: src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ required_links }}" + config: "{{ required_links['required_links'] }}" deploy: false state: merged register: manage_fabric_links_result diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 55596a516..e74f4f757 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -30,18 +30,25 @@ factory_defaults: nxapi_http_port: 80 enable_nxapi_https: true nxapi_https_port: 443 + layer2_vni_range: + from: 30000 + to: 49000 + layer3_vni_range: + from: 50000 + to: 59000 vpc: peer_link_vlan: 3600 peer_keep_alive: management auto_recovery_time: 360 delay_restore_time: 150 peer_link_port_channel_id: 500 + ipv6_nd_sync: true advertise_pip: false advertise_pip_border_only: true domain_id_range: 1-1000 - ipv6_nd_sync: true fabric_vpc_qos: false fabric_vpc_qos_policy_name: spine_qos_for_fabric_vpc_peering + enable_ipv6_nd_sync: true spanning_tree: root_bridge_protocol: unmanaged vlan_range: @@ -55,6 +62,10 @@ factory_defaults: ptp: enable: false snmp_server_host_trap: true + bootstrap: + enable_bootstrap: false + enable_local_dhcp_server: false + enable_cdp_mgmt: false topology: switches: routing_loopback_id: 0 @@ -296,15 +307,13 @@ factory_defaults: enable_ipv6_underlay: false anycast_gateway_mac: 20:20:00:00:00:aa vtep_loopback_id: 100 + bgw_ip_tag: 54321 ipv4_vtep_loopback_range: 10.10.0.0/24 ipv4_dci_subnet_range: 10.10.1.0/24 ipv4_dci_subnet_mask: 30 ipv6_vtep_loopback_range: fd00::a10:0/120 ipv6_dci_subnet_range: fd00::a11:0/120 ipv6_dci_subnet_mask: 126 - layer2_vni_range: 30000-49000 - layer3_vni_range: 50000-59000 - bgw_ip_tag: 54321 overlay_ifc: Direct_To_BGWS underlay_autoconfig: true enable_bgp_send_community: false @@ -343,10 +352,13 @@ factory_defaults: route_target_both: false route_tag: 12345 trm_enable: false - vrf_attach_groups: - switches: [] - network_attach_groups: - switches: [] + net_description: "Configured by Ansible NetAsCode" + layer2_vni_range: + from: 30000 + to: 49000 + layer3_vni_range: + from: 50000 + to: 59000 overlay_dci: deployment_method: Direct_To_BGWS route_server: From 624a89038abcb42faca6a6c9193677b04197c78a Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 2 May 2025 10:07:47 +0100 Subject: [PATCH 116/183] Removed domain name as not needed in easy fabric --- .../dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 index ed219a54b..b2f9b4e1b 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_vxlan_fabric/bootstrap/dc_vxlan_fabric_bootstrap.j2 @@ -10,7 +10,6 @@ MGMT_GW: {{ vxlan.global.bootstrap.dhcp_v4.switch_mgmt_default_gw }} MGMT_PREFIX: {{ vxlan.global.bootstrap.dhcp_v4.mgmt_prefix }} BOOTSTRAP_MULTISUBNET: "{{ vxlan.global.bootstrap.dhcp_v4.multi_subnet_scope }}" - DOMAIN_NAME: "{{ vxlan.global.bootstrap.dhcp_v4.domain_name }}" {% endif %} {% endif %} {% if vxlan.global.bootstrap.enable_bootstrap is defined and not vxlan.global.bootstrap.enable_bootstrap %} From 4b2a453f783da3bf02a0a494cc459a9d79b2c297 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 6 May 2025 10:53:25 +0100 Subject: [PATCH 117/183] fix for different case in ethernet interface name --- plugins/action/dtc/links_filter_and_remove.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/action/dtc/links_filter_and_remove.py b/plugins/action/dtc/links_filter_and_remove.py index 78b57e384..dfafcf918 100644 --- a/plugins/action/dtc/links_filter_and_remove.py +++ b/plugins/action/dtc/links_filter_and_remove.py @@ -51,14 +51,14 @@ def run(self, tmp=None, task_vars=None): for link in fabric_links: if ('sw1-info' in existing_link and 'sw2-info' in existing_link and 'sw-sys-name' in existing_link['sw1-info'] and 'sw-sys-name' in existing_link['sw2-info'] and - (existing_link['sw1-info']['sw-sys-name'] == link['src_device'] and - existing_link['sw1-info']['if-name'] == link['src_interface'] and - existing_link['sw2-info']['sw-sys-name'] == link['dst_device'] and - existing_link['sw2-info']['if-name'] == link['dst_interface']) or - (existing_link['sw1-info']['sw-sys-name'] == link['dst_device'] and - existing_link['sw1-info']['if-name'] == link['dst_interface'] and - existing_link['sw2-info']['sw-sys-name'] == link['src_device'] and - existing_link['sw2-info']['if-name'] == link['src_interface'])): + (existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or + (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): required_links.append(existing_link) for link in filtered_existing_links: link_found = False From c8b52a67082642243c3dc37b23310218eb68d539 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 6 May 2025 14:49:16 +0100 Subject: [PATCH 118/183] Comment out some logic for existing links check --- plugins/action/dtc/existing_links_check.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index d2b4ef1db..446d4f8aa 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -58,15 +58,15 @@ def run(self, tmp=None, task_vars=None): not_required_links.append(link) elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': required_links.append(link) - elif existing_link['templateName'] == 'int_intra_fabric_num_link': - link['template'] = 'int_intra_fabric_num_link' - link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] - link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] - if existing_link.get('nvPairs').get('ENABLE_MACSEC'): - link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] - else: - link['profile']['enable_macsec'] = 'false' - required_links.append(link) + # elif existing_link['templateName'] == 'int_intra_fabric_num_link': + # link['template'] = 'int_intra_fabric_num_link' + # link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + # link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + # if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + # link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + # else: + # link['profile']['enable_macsec'] = 'False' + # required_links.append(link) else: not_required_links.append(link) if link not in required_links and link not in not_required_links: From 0a6ec01e4d45cb9028eef69410d29967ef628c46 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 7 May 2025 15:52:34 +0100 Subject: [PATCH 119/183] external fabric fix for no PTP and commenting back in existing link updates for intra fabric links --- plugins/action/dtc/existing_links_check.py | 18 +++++++++--------- .../advanced/dc_external_fabric_advanced.j2 | 6 ++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 446d4f8aa..40862311d 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -58,15 +58,15 @@ def run(self, tmp=None, task_vars=None): not_required_links.append(link) elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': required_links.append(link) - # elif existing_link['templateName'] == 'int_intra_fabric_num_link': - # link['template'] = 'int_intra_fabric_num_link' - # link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] - # link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] - # if existing_link.get('nvPairs').get('ENABLE_MACSEC'): - # link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] - # else: - # link['profile']['enable_macsec'] = 'False' - # required_links.append(link) + elif existing_link['templateName'] == 'int_intra_fabric_num_link': + link['template'] = 'int_intra_fabric_num_link' + link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + else: + link['profile']['enable_macsec'] = 'False' + required_links.append(link) else: not_required_links.append(link) if link not in required_links and link not in not_required_links: diff --git a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 index 182b11a95..f91d0cdf5 100644 --- a/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/dc_external_fabric/advanced/dc_external_fabric_advanced.j2 @@ -1,8 +1,10 @@ {# Auto-generated NDFC DC VXLAN EVPN Advanced config data structure for fabric {{ vxlan.fabric.name }} #} POWER_REDUNDANCY_MODE: ps-redundant FEATURE_PTP: {{ vxlan.global.ptp.enable | default(defaults.vxlan.global.ptp.enable) }} - PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id | default(defaults.vxlan.global.ptp.domain_id) }} - PTP_LB_ID: {{ vxlan.global.ptp.lb_id | default(defaults.vxlan.global.ptp.lb_id) }} +{% if vxlan.global.ptp.enable | default(defaults.vxlan.global.ptp.enable) %} + PTP_DOMAIN_ID: {{ vxlan.global.ptp.domain_id }} + PTP_LB_ID: {{ vxlan.global.ptp.lb_id }} +{% endif %} ENABLE_NXAPI: {{ vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) }} {% if vxlan.global.enable_nxapi_https | default(defaults.vxlan.global.enable_nxapi_https) %} NXAPI_HTTPS_PORT: {{ vxlan.global.nxapi_https_port | default(defaults.vxlan.global.nxapi_https_port) }} From 8be0f48affac9cb8245ecf21b9b9755ccb03c248 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Fri, 9 May 2025 12:22:56 +0100 Subject: [PATCH 120/183] adding breakout field back into inventory templates --- .../common/templates/ndfc_inventory/common/fabric_inventory.j2 | 1 + .../dc_external_fabric/dc_external_fabric_inventory.j2 | 1 + .../ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 | 1 + 3 files changed, 3 insertions(+) diff --git a/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 index 6e300cc7a..ad6a1c6b4 100644 --- a/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 @@ -33,6 +33,7 @@ config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} gateway: {{ switch['management']['default_gateway_v4'] }} + breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} hostname: {{ switch['name'] }} {% endif %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 index 636e4534b..e38561180 100644 --- a/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 @@ -32,6 +32,7 @@ config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} gateway: {{ switch['management']['default_gateway_v4'] }} + breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} hostname: {{ switch['name'] }} {% endif %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 index 6e300cc7a..ad6a1c6b4 100644 --- a/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/dc_vxlan_fabric/dc_vxlan_fabric_inventory.j2 @@ -33,6 +33,7 @@ config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} gateway: {{ switch['management']['default_gateway_v4'] }} + breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} hostname: {{ switch['name'] }} {% endif %} {% endif %} From e7fa7054eebeaeab94d05d49dd3800e12b19af7c Mon Sep 17 00:00:00 2001 From: Peter Lewis - Cisco <74906052+peter8498@users.noreply.github.com> Date: Tue, 13 May 2025 17:10:55 +0100 Subject: [PATCH 121/183] Update ndfc_interface_vpc.j2 Added support for freeform on vpc interface --- .../common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 index 01d8abd42..2d165df0b 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_vpc.j2 @@ -26,6 +26,10 @@ pc_mode: {{ switches[peer1].pc_mode | default(defaults.vxlan.topology.switches.interfaces.topology_switch_access_po_interface.pc_mode) }} peer1_members: {{ switches[peer1].members | to_json }} peer2_members: {{ switches[peer2].members | to_json }} + peer1_cmds: |2- + {{ switches[peer1].freeform_config | default('') | indent(6, false) }} + peer2_cmds: |2- + {{ switches[peer2].freeform_config | default('') | indent(6, false) }} peer1_description: "{{ switches[peer1].description | default(omit) }}" peer2_description: "{{ switches[peer2].description | default(omit) }}" bpdu_guard: {{ switches[peer1].enable_bpdu_guard | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enable_bpdu_guard) }} From 3d44f090c97a625e27e69f01405bd5ab277cf0b3 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Tue, 13 May 2025 17:14:30 +0100 Subject: [PATCH 122/183] update to match new model location for keys --- .../mfd_fabric/resources/mfd_fabric_resources.j2 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 index c423b71bc..8ba6bad0e 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 @@ -1,13 +1,13 @@ {# Auto-generated NDFC MSD Resources config data structure for fabric {{ vxlan.fabric.name }} #} {% if not defaults.vxlan.multisite.enable_ipv6_underlay %} LOOPBACK100_IP_RANGE: {{ vxlan.multisite.ipv4_vtep_loopback_range | default(defaults.vxlan.multisite.ipv4_vtep_loopback_range) }} - DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.ipv4_dci_subnet_range) }} - DCI_SUBNET_TARGET_MASK: "{{ vxlan.multisite.ipv4_dci_subnet_mask | default(defaults.vxlan.multisite.ipv4_dci_subnet_mask) }}" + DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_range) }} + DCI_SUBNET_TARGET_MASK: "{{ vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask | default(defaults.vxlan.multisite.overlay_dci.ipv4_dci_subnet_mask) }}" LOOPBACK100_IPV6_RANGE: "" V6_DCI_SUBNET_RANGE: "" V6_DCI_SUBNET_TARGET_MASK: "" {% else %} LOOPBACK100_IPV6_RANGE: {{ vxlan.multisite.ipv6_vtep_loopback_range | default(defaults.vxlan.multisite.ipv6_vtep_loopback_range) }} - V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.ipv6_dci_subnet_range) }} - V6_DCI_SUBNET_TARGET_MASK: {{ vxlan.multisite.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.ipv6_dci_subnet_mask) }} + V6_DCI_SUBNET_RANGE: {{ vxlan.multisite.overlay_dci.ipv6_dci_subnet_range | default(defaults.vxlan.multisite.overlay_dci.ipv6_dci_subnet_range) }} + V6_DCI_SUBNET_TARGET_MASK: "{{ vxlan.multisite.overlay_dci.ipv6_dci_subnet_mask | default(defaults.vxlan.multisite.overlay_dci.ipv6_dci_subnet_mask) }}" {% endif %} \ No newline at end of file From 896add0b46246682401a6067a15c0402d2ae0e22 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 29 May 2025 15:26:58 +0100 Subject: [PATCH 123/183] Corrected a couple of minor issues --- roles/dtc/common/templates/ndfc_policy.j2 | 5 +++++ .../ndfc_route_control/ndfc_prefix_list.j2 | 4 ++-- roles/dtc/create/tasks/mfd/child_fabrics.yml | 13 ------------- roles/dtc/create/tasks/mfd/fabric.yml | 13 +++++++++++++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_policy.j2 b/roles/dtc/common/templates/ndfc_policy.j2 index 9ddc2f343..dbe794032 100644 --- a/roles/dtc/common/templates/ndfc_policy.j2 +++ b/roles/dtc/common/templates/ndfc_policy.j2 @@ -30,6 +30,11 @@ {% elif key == "CONF" %} {{ key }}: |- {{ value | indent(14) }} +{% elif key == "BANNER" %} + {{ key }}: | + {{ value | indent(14) }} +{% elif key in ["BANNERDELIMITER"] %} + {{ key }}: "{{ value }}" {% elif key in ["asn", "BGP_AS", "BGP_ASN", "NEIGHBOR_ASN", "COM"] %} {{ key }}: "{{ value | string | indent(12) | trim }}" {% elif value is iterable and '\n' in value %} diff --git a/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 b/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 index d110a8c6b..a761d4156 100644 --- a/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 +++ b/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 @@ -28,9 +28,9 @@ ip prefix-list {{ ipv4_prefix_list["name"] }} description {{ ipv4_prefix_list["d {% set _ = options.append("mask " ~ entry["mask"] ) %} {% endif %} {% if options | length > 0 %} -ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] | ipaddr('network/prefix') }} {{ options | join(" ") }} +ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] }} {{ options | join(" ") }} {% else %} -ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] | ipaddr('network/prefix') }} +ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] }} {% endif %} {% endfor %} {% endif %} diff --git a/roles/dtc/create/tasks/mfd/child_fabrics.yml b/roles/dtc/create/tasks/mfd/child_fabrics.yml index e05fb32de..91cd8c916 100644 --- a/roles/dtc/create/tasks/mfd/child_fabrics.yml +++ b/roles/dtc/create/tasks/mfd/child_fabrics.yml @@ -28,19 +28,6 @@ - "+ Manage Fabric Children {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Check if fabric already a member of NDFC - cisco.dcnm.dcnm_rest: - method: GET - path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' - register: member_result - -- name: Set fact for existing fabric names - set_fact: - existing_fabric_names: >- - {{ - member_result.response.DATA | map(attribute='fabrics') | map('dict2items') | flatten | map(attribute='key') | list - }} - - name: Manage fabric Federated {{ MD_Extended.vxlan.fabric.name }} in NDFC (PUT) cisco.dcnm.dcnm_rest: method: PUT diff --git a/roles/dtc/create/tasks/mfd/fabric.yml b/roles/dtc/create/tasks/mfd/fabric.yml index 4f79802e6..f5affd10d 100644 --- a/roles/dtc/create/tasks/mfd/fabric.yml +++ b/roles/dtc/create/tasks/mfd/fabric.yml @@ -65,6 +65,19 @@ - ansible.builtin.debug: var: fabric_children +- name: Check if fabric already a member of NDFC + cisco.dcnm.dcnm_rest: + method: GET + path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' + register: member_result + +- name: Set fact for existing fabric names + set_fact: + existing_fabric_names: >- + {{ + member_result.response.DATA | map(attribute='fabrics') | map('dict2items') | flatten | map(attribute='key') | list + }} + - name: Add Child Fabrics To Fabric - {{ MD_Extended.vxlan.fabric.name }} include_tasks: child_fabrics.yml loop: "{{ fabric_children }}" From 531f1a6397878fdf06b51c60e62e3e71d0477976 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Wed, 4 Jun 2025 16:20:59 +0100 Subject: [PATCH 124/183] Removed VPC peering removal as not created for external fabrics --- roles/dtc/remove/tasks/sub_main_external.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/dtc/remove/tasks/sub_main_external.yml b/roles/dtc/remove/tasks/sub_main_external.yml index e5c113ae9..e6a93a4ed 100644 --- a/roles/dtc/remove/tasks/sub_main_external.yml +++ b/roles/dtc/remove/tasks/sub_main_external.yml @@ -56,11 +56,11 @@ when: - vars_common_external.changes_detected_interfaces -- name: Remove Fabric vPC Peering - ansible.builtin.import_tasks: common/vpc_peers.yml - tags: "{{ nac_tags.remove_vpc_peers }}" - when: - - vars_common_external.changes_detected_vpc_peering +# - name: Remove Fabric vPC Peering +# ansible.builtin.import_tasks: common/vpc_peers.yml +# tags: "{{ nac_tags.remove_vpc_peers }}" +# when: +# - vars_common_external.changes_detected_vpc_peering - name: Remove Fabric Switches ansible.builtin.import_tasks: common/switches.yml From 169053488b2302ca469332f0d23058d3e714a9ae Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 12 Jun 2025 12:09:41 +0100 Subject: [PATCH 125/183] updates to support vrf vlan name --- roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 index 00b49787f..ba262e39d 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 @@ -5,7 +5,7 @@ "vrfName":"{{ vrf.name}}", "vrfId":"{{ vrf.vrf_id }}", "vrfTemplate":"Default_VRF_Universal", - "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vlan_id }}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vlan_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", + "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vrf_vlan_name | default(vrf.vlan_id)}}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vrf_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", "serviceVrfTemplate": null, "serviceVrfTemplate": null, "displayName": "{{ vrf.name}}", From a78d0e67cb63029b1c6a5388b8cf71c795c6be33 Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 12 Jun 2025 12:16:41 +0100 Subject: [PATCH 126/183] Added support for VPC peering in external fabric --- plugins/action/dtc/fed_overlay_check.py | 14 ++- .../tasks/external/ndfc_vpc_peering_pairs.yml | 94 +++++++++++++++++++ roles/dtc/common/tasks/sub_main_external.yml | 12 ++- .../common/templates/ndfc_edge_connections.j2 | 10 ++ .../ndfc_vpc_peering_pairs_external.j2 | 31 ++++++ roles/dtc/create/tasks/sub_main_external.yml | 7 ++ roles/dtc/remove/tasks/common/policy.yml | 2 +- roles/validate/files/defaults.yml | 4 + 8 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml create mode 100644 roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index cc2a8a6a1..fbf46b0e3 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -60,7 +60,19 @@ def run(self, tmp=None, task_vars=None): for switch in network_attach_group['switches']: for switch_entry in switch_data: if switch['hostname'] == switch_entry['logicalName']: - normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) + if switch.get('tors'): + main = f"{switch['hostname']}({','.join(switch['ports'])})" + # Format each tor entry + tors = ' '.join( + f"{tor['hostname']}({','.join(tor['ports'])})" + for tor in switch.get('tors', []) + ) + # Combine main and tors + ports = f"{main} {tors}".strip() + + normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':ports,"deployment":deployment, "fabric":switch_entry['fabricName']}) + else: + normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) difference = [item for item in normal_ndfc_data if item not in normal_model_data] # Restructure in case of just port removal diff --git a/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml b/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml new file mode 100644 index 000000000..a67ef2419 --- /dev/null +++ b/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml @@ -0,0 +1,94 @@ +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +--- + +- name: Initialize changes_detected Var + ansible.builtin.set_fact: + changes_detected_vpc_peering: false + delegate_to: localhost + +- name: Set file_name Var + ansible.builtin.set_fact: + file_name: "ndfc_vpc_peering.yml" + delegate_to: localhost + +- name: Stat Previous File If It Exists + ansible.builtin.stat: + path: "{{ path_name }}{{ file_name }}" + register: data_file_previous + delegate_to: localhost + +- name: Backup Previous Data File If It Exists + ansible.builtin.copy: + src: "{{ path_name }}{{ file_name }}" + dest: "{{ path_name }}{{ file_name }}.old" + when: data_file_previous.stat.exists + +- name: Delete Previous Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + when: data_file_previous.stat.exists + +- name: debud MD_Extended.vxlan.topology.vpc_peers + ansible.builtin.debug: + msg: "{{ MD_Extended.vxlan.topology.vpc_peers }}" + when: MD_Extended.vxlan.topology.vpc_peers | length > 0 + delegate_to: localhost + +- name: Build vPC Peering + ansible.builtin.template: + src: ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 + dest: "{{ path_name }}{{ file_name }}" + delegate_to: localhost + +- name: Set vpc_peering Var default + ansible.builtin.set_fact: + vpc_peering: [] + delegate_to: localhost + +- name: Set link_vpc_peering Var default as not used for external fabric + ansible.builtin.set_fact: + link_vpc_peering: [] + delegate_to: localhost + +- name: Set vpc_peering Var + ansible.builtin.set_fact: + vpc_peering: "{{ lookup('file', path_name + file_name) | from_yaml }}" + when: MD_Extended.vxlan.topology.vpc_peers | length > 0 + delegate_to: localhost + +- name: Diff Previous and Current Data Files + cisco.nac_dc_vxlan.dtc.diff_model_changes: + file_name_previous: "{{ path_name }}{{ file_name }}.old" + file_name_current: "{{ path_name }}{{ file_name }}" + register: file_diff_result + delegate_to: localhost + +- name: Set File Change Flag Based on File Diff Result + ansible.builtin.set_fact: + changes_detected_vpc_peering: true + delegate_to: localhost + when: + - file_diff_result.file_data_changed + - check_roles['save_previous'] \ No newline at end of file diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index ab47632dd..e50155f88 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -83,11 +83,18 @@ ansible.builtin.import_tasks: common/ndfc_interface_all.yml - name: Build NDFC Policy List From Template - ansible.builtin.import_tasks: common/ndfc_policy.yml + ansible.builtin.import_tasks: common/ndfc_policy.yml - name: Edge Connections List From Template ansible.builtin.import_tasks: common/ndfc_edge_connections.yml +# -------------------------------------------------------------------- +# Build vPC Peering parameter List From Template +# -------------------------------------------------------------------- + +- name: Build vPC Peering Parameters + ansible.builtin.import_tasks: external/ndfc_vpc_peering_pairs.yml + # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere # -------------------------------------------------------------------- @@ -107,6 +114,7 @@ changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" changes_detected_interfaces: "{{ changes_detected_interfaces }}" changes_detected_policy: "{{ changes_detected_policy }}" + changes_detected_vpc_peering: "{{ changes_detected_vpc_peering }}" fabric_config: "{{ fabric_config }}" edge_connections: "{{ edge_connections }}" interface_access_po: "{{ interface_access_po }}" @@ -122,6 +130,7 @@ policy_config: "{{ policy_config }}" sub_interface_routed: "{{ sub_interface_routed }}" updated_inv_config: "{{ updated_inv_config }}" + vpc_peering: "{{ vpc_peering }}" - name: Run Diff Flags ansible.builtin.debug: @@ -130,6 +139,7 @@ - "+ Fabric Changes Detected - [ {{ vars_common_external.changes_detected_fabric }} ]" - "+ Inventory Changes Detected - [ {{ vars_common_external.changes_detected_inventory }} ]" - "+ Edge Connections Changes Detected - [ {{ vars_common_external.changes_detected_edge_connections }} ]" + - "+ vPC Peer Changes Detected - [ {{ vars_common_external.changes_detected_vpc_peering }} ]" - "+ ----- Interfaces -----" - "+ Interface Access Changes Detected - [ {{ vars_common_external.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_external.changes_detected_interface_access_po }} ]" diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 index 194d3bcab..eafe0374b 100644 --- a/roles/dtc/common/templates/ndfc_edge_connections.j2 +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -8,17 +8,26 @@ - ip: {{ link.source_device_ip }} policies: - create_additional_policy: False +{% if '.' in link.source_interface %} + description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device + '_' + link.source_interface.split('.')[1] }} +{% else %} description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} +{% endif %} name: bgp_peer_template_dci_underlay_jython policy_vars: BGP_PASSWORD: "{{ link.bgp_section.bgp_password | default('') }}" BGP_PASSWORD_ENABLE: {{ link.bgp_section.bgp_password_enable | default('true') }} +{% if '.' in link.source_interface %} + TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' + '_' + link.source_interface.split('.')[1] }} +{% else %} TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' }} +{% endif %} NEIGHBOR_ASN: "{{ link.bgp_section.neighbor_asn }}" OVERRIDE_LOCAL_ASN: false CONF: |2- {{ link.bgp_section.peer_template_freeform | default('') | indent(14, false)}} priority: 475 +{% if '.' not in link.source_interface %} - create_additional_policy: False description: {{ 'nace_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} name: ebgp_underlay_dci_template @@ -43,5 +52,6 @@ {{ link.bgp_section.interface_freeform | default('') | indent(14, false)}} FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} priority: 500 +{% endif %} {% endfor %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 new file mode 100644 index 000000000..56df2ad04 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -0,0 +1,31 @@ +--- +# This NDFC vPC Peering config data structure for vPC pairs is auto-generated +# DO NOT EDIT MANUALLY +# +{% if MD_Extended.vxlan.topology.vpc_peers is defined and MD_Extended.vxlan.topology.vpc_peers is not none %} +{% for vpc_peers_pair in MD_Extended.vxlan.topology.vpc_peers %} +- peerOneId: {{ vpc_peers_pair.peer1_mgmt_ip_address }} + peerTwoId: {{ vpc_peers_pair.peer2_mgmt_ip_address }} + templateName: "vpc_pair" + profile: + ADMIN_STATE: {{ vpc_peers_pair.enabled }} + ALLOWED_VLANS: "{{ vpc_peers_pair.trunk_allowed_vlans }}" + DOMAIN_ID: {{ vpc_peers_pair.domain_id }} + FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} + KEEP_ALIVE_HOLD_TIMEOUT: {{ vpc_peers_pair.keepalive_holdout_time | default(defaults.vxlan.topology.vpc_peers.keepalive_holdout_time) }} + KEEP_ALIVE_VRF: {{ vpc_peers_pair.keepalive_vrfname }} + PC_MODE: {{ vpc_peers_pair.port_channel_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} + PEER1_DOMAIN_CONF: "{{ vpc_peers_pair.peer1_domain_conf | default('') }}" + PEER1_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer1_keepalive_ipv4 }} + PEER1_PO_CONF: "{{ vpc_peers_pair.peer1_po_channel_conf | default('') }}" + PEER1_PO_DESC: "{{ vpc_peers_pair.peer1_po_channel_desc | default('') }}" + PEER2_DOMAIN_CONF: "{{ vpc_peers_pair.peer2_domain_conf | default('') }}" + PEER2_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer2_keepalive_ipv4 }} + PEER2_PO_CONF: "{{ vpc_peers_pair.peer2_po_channel_conf | default('') }}" + PEER2_PO_DESC: "{{ vpc_peers_pair.peer2_po_channel_desc | default('') }}" + PEER1_PCID: {{ vpc_peers_pair.peer1_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_port_channel_id) }} + PEER2_PCID: {{ vpc_peers_pair.peer2_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_port_channel_id) }} + PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" + PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" +{% endfor %} +{% endif %} diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index f071cf675..7f7bf88af 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -48,6 +48,13 @@ - vars_common_external.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" +- name: Manage NDFC External VPC Peering + ansible.builtin.import_tasks: common/vpc_peering.yml + when: + - MD_Extended.vxlan.topology.vpc_peers | length > 0 + - vars_common_external.changes_detected_vpc_peering + tags: "{{ nac_tags.create_vpc_peers }}" + - name: Manage NDFC Fabric Inter Links ansible.builtin.import_tasks: common/edge_connections.yml when: diff --git a/roles/dtc/remove/tasks/common/policy.yml b/roles/dtc/remove/tasks/common/policy.yml index 09dbc73bd..794631e05 100644 --- a/roles/dtc/remove/tasks/common/policy.yml +++ b/roles/dtc/remove/tasks/common/policy.yml @@ -54,7 +54,7 @@ fabric: "{{ MD_Extended.vxlan.fabric.name }}" use_desc_as_key: true config: "{{ unmanaged_policy_config.unmanaged_policies }}" - deploy: true + deploy: false state: deleted when: unmanaged_policy_config.unmanaged_policies | length > 0 vars: diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index e74f4f757..c3a087a69 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -126,6 +126,10 @@ factory_defaults: enabled: true vpc_peers: domain_id: 1 + keepalive_holdout_time: 3 + port_channel_mode: active + peer1_port_channel_id: 500 + peer2_port_channel_id: 500 fabric_links: mtu: 9216 admin_state: true From 9905e1bd7f998866a06ccd1df6a7cabacbcf0a6f Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 21 Jul 2025 14:43:01 +0100 Subject: [PATCH 127/183] Adding new changes --- roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml b/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml index a67ef2419..5644a2bfe 100644 --- a/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml +++ b/roles/dtc/common/tasks/external/ndfc_vpc_peering_pairs.yml @@ -50,7 +50,7 @@ delegate_to: localhost when: data_file_previous.stat.exists -- name: debud MD_Extended.vxlan.topology.vpc_peers +- name: debug MD_Extended.vxlan.topology.vpc_peers ansible.builtin.debug: msg: "{{ MD_Extended.vxlan.topology.vpc_peers }}" when: MD_Extended.vxlan.topology.vpc_peers | length > 0 From 2562c5d9387876c075b8df8cdb3a413224a6ab98 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 21 Jul 2025 14:43:36 +0100 Subject: [PATCH 128/183] Added VRF freeform changes --- .../common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 b/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 index daa9ea439..1c99dded3 100644 --- a/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/ndfc_attach_vrfs_loopbacks.j2 @@ -22,7 +22,7 @@ "serialNumber": "{{ switch.serial_number }}", {% endif %} {% endfor %} - "freeformConfig": "", + "freeformConfig": "{{ attach['freeform_config'] | default('') }}", "extensionValues": "", "vlan": "{{ vrf["vlan_id"] }}", "deployment": true, From 78fbd2ab45c350c2ba3b5f23effd5fdfcf25968d Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 21 Jul 2025 14:44:08 +0100 Subject: [PATCH 129/183] Added VRF freeform changes --- roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 index ac04d779e..eda05c702 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 @@ -9,7 +9,7 @@ "serialNumber": "{{ switch.serialNumber }}", {% endif %} {% endfor %} - "freeformConfig": "", + "freeformConfig": "{{ attach['freeform_config'] | default('') }}", "extensionValues": "", "vlan": {{ vrf["vlan_id"] }}, "deployment": true, From 54153b47e082cac23ad8caf9f7249ff073ca9f58 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 11:09:19 +0100 Subject: [PATCH 130/183] Adding support for breakout of pre-provisioned switches --- .../prep_105_topology_interfaces.py | 11 +++--- .../tasks/common/ndfc_interface_all.yml | 2 +- .../tasks/common/ndfc_interface_breakout.yml | 21 +++++++++++ .../ndfc_interface_breakout.j2 | 3 +- .../ndfc_interface_breakout_remove.j2 | 37 +++++++++++++++++++ 5 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 diff --git a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py index 279afa726..cb660463e 100644 --- a/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_105_topology_interfaces.py @@ -95,11 +95,12 @@ def prepare(self): if switch.get('interface_breakouts'): for breakout in switch.get('interface_breakouts'): - if breakout.get('to'): - nb_int = breakout['to'] - breakout['from'] - model_data['vxlan']['topology']['interfaces']['modes']['breakout']['count'] += nb_int + 1 - else: - model_data['vxlan']['topology']['interfaces']['modes']['breakout']['count'] += 1 + if not breakout.get('enable_during_bootstrap'): + if breakout.get('to'): + nb_int = breakout['to'] - breakout['from'] + model_data['vxlan']['topology']['interfaces']['modes']['breakout']['count'] += nb_int + 1 + else: + model_data['vxlan']['topology']['interfaces']['modes']['breakout']['count'] += 1 self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/roles/dtc/common/tasks/common/ndfc_interface_all.yml b/roles/dtc/common/tasks/common/ndfc_interface_all.yml index 6a0f4eef5..039c65504 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_all.yml @@ -57,7 +57,7 @@ - name: Set interface_all Var ansible.builtin.set_fact: - interface_all: "{{ interface_breakout + interface_access + interface_access_po + interface_trunk + interface_trunk_po + interface_routed + interface_po_routed + sub_interface_routed + interface_vpc + int_loopback_config + interface_dot1q }}" + interface_all: "{{ interface_breakout_remove + interface_access + interface_access_po + interface_trunk + interface_trunk_po + interface_routed + interface_po_routed + sub_interface_routed + interface_vpc + int_loopback_config + interface_dot1q }}" when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 delegate_to: localhost diff --git a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml index 958f22d89..06bb61b46 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml @@ -29,6 +29,7 @@ - name: Set file_name Var ansible.builtin.set_fact: file_name: "ndfc_interface_breakout.yml" + file_name_remove: "ndfc_interface_breakout_remove.yml" delegate_to: localhost - name: Stat Previous File If It Exists @@ -50,15 +51,29 @@ delegate_to: localhost when: data_file_previous.stat.exists +- name: Delete Previous Remove Data File If It Exists + ansible.builtin.file: + state: absent + path: "{{ path_name }}{{ file_name_remove }}" + delegate_to: localhost + when: data_file_previous.stat.exists + - name: Build Interface ansible.builtin.template: src: ndfc_interfaces/ndfc_interface_breakout.j2 dest: "{{ path_name }}{{ file_name }}" delegate_to: localhost +- name: Build Interface Remove breakout + ansible.builtin.template: + src: ndfc_interfaces/ndfc_interface_breakout_remove.j2 + dest: "{{ path_name }}{{ file_name_remove }}" + delegate_to: localhost + - name: Initialize interface_breakout Var ansible.builtin.set_fact: interface_breakout: [] + interface_breakout_remove: [] delegate_to: localhost - name: Set interface_breakout Var @@ -67,6 +82,12 @@ when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 delegate_to: localhost +- name: Set interface_breakout_remove Var + ansible.builtin.set_fact: + interface_breakout_remove: "{{ lookup('file', path_name + file_name_remove) | from_yaml }}" + when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 + delegate_to: localhost + - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: file_name_previous: "{{ path_name }}{{ file_name }}.old" diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout.j2 index 4f1e336e2..8c8804c4d 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout.j2 @@ -2,10 +2,10 @@ # This NDFC breakout interface data structure is auto-generated # DO NOT EDIT MANUALLY # - {% for switch in MD_Extended.vxlan.topology.switches %} {% if switch.interface_breakouts is defined %} {% for breakout in switch.interface_breakouts %} +{% if not (breakout.enable_during_bootstrap | default(false)) %} {% if breakout.to is defined %} {% for port in range(breakout.from, breakout.to + 1) %} - name: Ethernet{{ breakout.module }}/{{ port }} @@ -33,6 +33,7 @@ profile: map: {{ breakout.map }} {% endif %} +{% endif %} {% endfor %} {% endif %} {% endfor %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 new file mode 100644 index 000000000..065bc1a43 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 @@ -0,0 +1,37 @@ +--- +# This NDFC breakout interface data structure is auto-generated +# DO NOT EDIT MANUALLY +# +{% for switch in MD_Extended.vxlan.topology.switches %} +{% if switch.interface_breakouts is defined %} +{% for breakout in switch.interface_breakouts %} +{% if breakout.to is defined %} +{% for port in range(breakout.from, breakout.to + 1) %} +- name: Ethernet{{ breakout.module }}/{{ port }} + type: breakout + switch: +{% if switch.management.management_ipv4_address is defined %} + - {{ switch.management.management_ipv4_address }} +{% elif (switch.management.management_ipv4_address is not defined) and (switch.management.management_ipv6_address is defined) %} + - {{ switch.management.management_ipv6_address }} +{% endif %} + deploy: true + profile: + map: {{ breakout.map }} +{% endfor %} +{% else %} +- name: Ethernet{{ breakout.module }}/{{ breakout.from }} + type: breakout + switch: +{% if switch.management.management_ipv4_address is defined %} + - {{ switch.management.management_ipv4_address }} +{% elif (switch.management.management_ipv4_address is not defined) and (switch.management.management_ipv6_address is defined) %} + - {{ switch.management.management_ipv6_address }} +{% endif %} + deploy: true + profile: + map: {{ breakout.map }} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} \ No newline at end of file From adb97da6ccfaac278fdb5e36d8fbefd356d49cb0 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 11:16:40 +0100 Subject: [PATCH 131/183] Added support for breakout of pre-prov inventory --- .../ndfc_inventory/common/fabric_inventory.j2 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 index fc91521c5..8cb3b2a50 100644 --- a/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/common/fabric_inventory.j2 @@ -45,7 +45,20 @@ config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} gateway: {{ switch['management']['default_gateway_v4'] | ansible.utils.ipaddr('address') }}/{{ switch['management']['subnet_mask_ipv4'] }} - breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} +{% if switch.interface_breakouts is defined %} +{% set breakout_commands = [] %} +{% for breakout in switch.interface_breakouts %} +{% if breakout.enable_during_bootstrap is defined and breakout.enable_during_bootstrap %} +{% if breakout.to is defined %} +{% set port_range = breakout.from|string + "-" + breakout.to|string %} +{% else %} +{% set port_range = breakout.from|string %} +{% endif %} +{% set _ = breakout_commands.append("interface breakout module " + breakout.module|string + " port " + port_range + " map " + breakout.map) %} +{% endif %} +{% endfor %} + breakout: "{{ breakout_commands | join('\\n') }}" +{% endif %} hostname: {{ switch['name'] }} {% else %} poap: @@ -59,4 +72,4 @@ {% endif %} {# Global Bootstrap Section End #} {# ---------------------------- #} -{% endfor %} +{% endfor %} From bb175eb4b2075171f6a6649516193b6cb98a0be7 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 11:19:31 +0100 Subject: [PATCH 132/183] Added remove role filtering for breakout --- roles/dtc/remove/tasks/common/interfaces.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/roles/dtc/remove/tasks/common/interfaces.yml b/roles/dtc/remove/tasks/common/interfaces.yml index 3f375ce6a..3b66a62ac 100644 --- a/roles/dtc/remove/tasks/common/interfaces.yml +++ b/roles/dtc/remove/tasks/common/interfaces.yml @@ -39,11 +39,21 @@ - switch_list.response.DATA | length > 0 - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) +- name: Filter out breakout interfaces for unreachable switches + ansible.builtin.set_fact: + filtered_interface_all: "{{ vars_common_local.interface_all | rejectattr('type', 'equalto', 'breakout') | list + (vars_common_local.interface_all | selectattr('type', 'equalto', 'breakout') | rejectattr('switch.0', 'in', unreachable_switch_ips) | list) }}" + vars: + unreachable_switch_ips: "{{ switch_list.response.DATA | selectattr('status', 'equalto', 'Unreachable') | map(attribute='ipAddress') | list }}" + when: + - switch_list.response.DATA | length > 0 + - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) + - vars_common_local.interface_all is defined + - name: Remove Unmanaged Fabric Interfaces cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ vars_common_local.interface_all }}" + config: "{{ filtered_interface_all | default(vars_common_local.interface_all) }}" # deploy: false vars: ansible_command_timeout: 3000 From 8ea340dd99b4b377636feefdbb5b5c5e7c0f42af Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 11:21:46 +0100 Subject: [PATCH 133/183] Added support for VPC peering on external fabric --- roles/dtc/common/tasks/sub_main_isn.yml | 26 ++++++++++++++------ roles/dtc/create/tasks/sub_main_external.yml | 14 +++++------ roles/dtc/remove/tasks/common/vpc_peers.yml | 18 ++++++++++++-- roles/dtc/remove/tasks/sub_main_external.yml | 12 ++++----- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/roles/dtc/common/tasks/sub_main_isn.yml b/roles/dtc/common/tasks/sub_main_isn.yml index 5c822b6d2..ebb30b873 100644 --- a/roles/dtc/common/tasks/sub_main_isn.yml +++ b/roles/dtc/common/tasks/sub_main_isn.yml @@ -52,6 +52,13 @@ - name: Build NDFC Fabric Switch Inventory List From Template ansible.builtin.import_tasks: common/ndfc_inventory.yml +# -------------------------------------------------------------------- +# Build NDFC Fabric Breakout Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Breakout Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_breakout.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Loopback Interfaces List From Template # -------------------------------------------------------------------- @@ -108,6 +115,13 @@ - name: Build Access Interfaces List From Template ansible.builtin.import_tasks: common/ndfc_interface_access.yml +# -------------------------------------------------------------------- +# Build Dot1q Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build Dot1q Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_dot1q.yml + # -------------------------------------------------------------------- # Build Fabric interface vPC List From Template # -------------------------------------------------------------------- @@ -136,13 +150,6 @@ - name: Build Edge Connections List From Template ansible.builtin.import_tasks: common/ndfc_edge_connections.yml -# -------------------------------------------------------------------- -# Build Edge Connections List From Template -# -------------------------------------------------------------------- - -- name: Edge Connections List From Template - ansible.builtin.import_tasks: common/ndfc_edge_connections.yml - # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere # -------------------------------------------------------------------- @@ -155,15 +162,18 @@ changes_detected_interface_access: "{{ changes_detected_interface_access }}" changes_detected_interfaces: "{{ changes_detected_interfaces }}" changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" + changes_detected_interface_breakout: "{{ changes_detected_interface_breakout }}" changes_detected_interface_po_routed: "{{ changes_detected_interface_po_routed }}" changes_detected_interface_routed: "{{ changes_detected_interface_routed }}" changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" changes_detected_interface_vpc: "{{ changes_detected_interface_vpc }}" + changes_detected_interface_dot1q: "{{ changes_detected_interface_dot1q }}" changes_detected_inventory: "{{ changes_detected_inventory }}" changes_detected_policy: "{{ changes_detected_policy }}" changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" fabric_config: "{{ fabric_config }}" + interface_breakout: "{{ interface_breakout }}" interface_access_po: "{{ interface_access_po }}" interface_access: "{{ interface_access }}" interface_all: "{{ interface_all }}" @@ -173,6 +183,7 @@ interface_trunk_po: "{{ interface_trunk_po }}" interface_trunk: "{{ interface_trunk }}" interface_vpc: "{{ interface_vpc }}" + interface_dot1q: "{{ interface_dot1q }}" inv_config: "{{ inv_config }}" poap_data: "{{ poap_data }}" policy_config: "{{ policy_config }}" @@ -186,6 +197,7 @@ - "+ Fabric Changes Detected - [ {{ vars_common_isn.changes_detected_fabric }} ]" - "+ Inventory Changes Detected - [ {{ vars_common_isn.changes_detected_inventory }} ]" - "+ ----- Interfaces -----" + - "+ Interface breakout Changes Detected - [ {{ vars_common_isn.changes_detected_interface_breakout }} ]" - "+ Interface vPC Changes Detected - [ {{ vars_common_isn.changes_detected_interface_vpc }} ]" - "+ Interface Access Changes Detected - [ {{ vars_common_isn.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_isn.changes_detected_interface_access_po }} ]" diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 7f7bf88af..012193273 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -48,13 +48,6 @@ - vars_common_external.changes_detected_inventory tags: "{{ nac_tags.create_switches }}" -- name: Manage NDFC External VPC Peering - ansible.builtin.import_tasks: common/vpc_peering.yml - when: - - MD_Extended.vxlan.topology.vpc_peers | length > 0 - - vars_common_external.changes_detected_vpc_peering - tags: "{{ nac_tags.create_vpc_peers }}" - - name: Manage NDFC Fabric Inter Links ansible.builtin.import_tasks: common/edge_connections.yml when: @@ -69,6 +62,13 @@ - vars_common_external.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" +- name: Manage NDFC External VPC Peering + ansible.builtin.import_tasks: common/vpc_peering.yml + when: + - MD_Extended.vxlan.topology.vpc_peers | length > 0 + - vars_common_external.changes_detected_vpc_peering + tags: "{{ nac_tags.create_vpc_peers }}" + - name: Manage NDFC External Fabric Policies ansible.builtin.import_tasks: common/policies.yml when: diff --git a/roles/dtc/remove/tasks/common/vpc_peers.yml b/roles/dtc/remove/tasks/common/vpc_peers.yml index 298ac9e23..c96ef9d2c 100644 --- a/roles/dtc/remove/tasks/common/vpc_peers.yml +++ b/roles/dtc/remove/tasks/common/vpc_peers.yml @@ -20,6 +20,20 @@ # SPDX-License-Identifier: MIT --- +- name: Choose vars_common Based On Fabric Type + ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_vxlan }}" + when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_msd }}" + when: MD_Extended.vxlan.fabric.type == "MSD" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_isn }}" + when: MD_Extended.vxlan.fabric.type == "ISN" +- ansible.builtin.set_fact: + vars_common_local: "{{ vars_common_external }}" + when: MD_Extended.vxlan.fabric.type == "External" + - ansible.builtin.debug: msg="Removing Unmanaged vPC Peering. This could take several minutes..." when: - switch_list.response.DATA | length > 0 @@ -28,9 +42,9 @@ - name: Remove Unmanaged vPC Peering cisco.dcnm.dcnm_vpc_pair: src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - deploy: true + deploy: false state: overridden - config: "{{ vars_common_vxlan.vpc_peering }}" + config: "{{ vars_common_local.vpc_peering }}" vars: ansible_command_timeout: 1000 ansible_connect_timeout: 1000 diff --git a/roles/dtc/remove/tasks/sub_main_external.yml b/roles/dtc/remove/tasks/sub_main_external.yml index 7f0371cf5..e5c113ae9 100644 --- a/roles/dtc/remove/tasks/sub_main_external.yml +++ b/roles/dtc/remove/tasks/sub_main_external.yml @@ -56,13 +56,11 @@ when: - vars_common_external.changes_detected_interfaces -# Feature not implemented yet, currently vars_common_external.changes_detected_vpc_peering is not being set so will -# currently cause an undefined variable error. -# - name: Remove Fabric vPC Peering -# ansible.builtin.import_tasks: common/vpc_peers.yml -# tags: "{{ nac_tags.remove_vpc_peers }}" -# when: -# - vars_common_external.changes_detected_vpc_peering +- name: Remove Fabric vPC Peering + ansible.builtin.import_tasks: common/vpc_peers.yml + tags: "{{ nac_tags.remove_vpc_peers }}" + when: + - vars_common_external.changes_detected_vpc_peering - name: Remove Fabric Switches ansible.builtin.import_tasks: common/switches.yml From 755eb637db7f6ab8de964c5ea7e505943b491c4f Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 11:26:48 +0100 Subject: [PATCH 134/183] Fixing bug when vpc_domain not defined --- roles/dtc/create/tasks/common/vpc_peering.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roles/dtc/create/tasks/common/vpc_peering.yml b/roles/dtc/create/tasks/common/vpc_peering.yml index 081f32223..1b01059bf 100644 --- a/roles/dtc/create/tasks/common/vpc_peering.yml +++ b/roles/dtc/create/tasks/common/vpc_peering.yml @@ -51,7 +51,9 @@ state: merged fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ vars_common_vxlan.vpc_domain_id_resource }}" - when: vars_common_vxlan.vpc_domain_id_resource | length > 0 + when: + - vars_common_vxlan.vpc_domain_id_resource is defined + - vars_common_vxlan.vpc_domain_id_resource | length > 0 # -------------------------------------------------------------------- # Manage Intra Fabric Links Configuration on NDFC (prepare links for vpc peering) From e01fc16855e448405384795bedda58c72723ec5a Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 1 Aug 2025 12:18:50 +0100 Subject: [PATCH 135/183] Added corrections and some breakout support --- .../dc_external_fabric_inventory.j2 | 33 +++++++++++++++++-- roles/dtc/create/tasks/main.yml | 2 +- roles/dtc/deploy/tasks/sub_main_mfd.yml | 1 + 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 index c0af431af..72224ead6 100644 --- a/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 +++ b/roles/dtc/common/templates/ndfc_inventory/dc_external_fabric/dc_external_fabric_inventory.j2 @@ -11,8 +11,12 @@ max_hops: 0 # this is the default value as it is not defined into the data model role: {{ switch['role'] }} preserve_config: true +{# ------------------------------ #} +{# Global Bootstrap Section Start #} {% if MD_Extended.vxlan.global.bootstrap is defined %} {% if MD_Extended.vxlan.global.bootstrap.enable_bootstrap is defined and MD_Extended.vxlan.global.bootstrap.enable_bootstrap %} +{# ------------------------- #} +{# Switch POAP Section Start #} {% if switch.poap is defined and switch.poap.bootstrap %} {% if poap_data[switch['serial_number']] is defined %} {% set pdata = poap_data[switch['serial_number']] %} @@ -24,7 +28,14 @@ config_data: modulesModel: {{ pdata['modulesModel'] }} gateway: {{ pdata['gateway'] }} -{% elif switch['poap']['preprovision'] is defined %} +{% endif %} +{% endif %} +{# ---------------------------------- #} +{# Switch POAP Section End #} +{##} +{# ---------------------------------- #} +{# Switch Pre-Provision Section Start #} +{% if switch['poap']['preprovision'] is defined %} poap: - preprovision_serial: {{ switch['poap']['preprovision']['serial_number'] }} model: {{ switch['poap']['preprovision']['model'] }} @@ -32,10 +43,26 @@ config_data: modulesModel: {{ switch['poap']['preprovision']['modulesModel'] }} gateway: {{ switch['management']['default_gateway_v4'] | ansible.utils.ipaddr('address') }}/{{ switch['management']['subnet_mask_ipv4'] }} - breakout: {{ switch['poap']['preprovision']['breakout'] | default('') }} - hostname: {{ switch['name'] }} +{% if switch.interface_breakouts is defined %} +{% set breakout_commands = [] %} +{% for breakout in switch.interface_breakouts %} +{% if breakout.enable_during_bootstrap is defined and breakout.enable_during_bootstrap %} +{% if breakout.to is defined %} +{% set port_range = breakout.from|string + "-" + breakout.to|string %} +{% else %} +{% set port_range = breakout.from|string %} +{% endif %} +{% set _ = breakout_commands.append("interface breakout module " + breakout.module|string + " port " + port_range + " map " + breakout.map) %} {% endif %} +{% endfor %} + breakout: "{{ breakout_commands | join('\\n') }}" +{% endif %} + hostname: {{ switch['name'] }} {% endif %} +{# Switch Pre-Provision Section End #} +{# ---------------------------------- #} {% endif %} {% endif %} +{# Global Bootstrap Section End #} +{# ---------------------------- #} {% endfor %} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index eb37303a3..603db830c 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -47,7 +47,7 @@ ansible.builtin.import_tasks: sub_main_msd.yml when: > (MD_Extended.vxlan.fabric.type == 'MSD') and - (vars_common_msd.changes_detected_fabric) or + ((vars_common_msd.changes_detected_fabric) or (vars_common_msd.changes_detected_bgw_anycast_vip) or (vars_common_msd.changes_detected_vrfs) or (vars_common_msd.changes_detected_networks)) diff --git a/roles/dtc/deploy/tasks/sub_main_mfd.yml b/roles/dtc/deploy/tasks/sub_main_mfd.yml index b98157587..6e3b5e1f8 100644 --- a/roles/dtc/deploy/tasks/sub_main_mfd.yml +++ b/roles/dtc/deploy/tasks/sub_main_mfd.yml @@ -36,6 +36,7 @@ cisco.dcnm.dcnm_rest: method: POST path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" + register: config_save when: > MD_Extended.vxlan.fabric.type == 'MFD' From d9671c6a0cb099e82cd7c7a80b5517f3b57148af Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 5 Aug 2025 15:11:26 +0100 Subject: [PATCH 136/183] updates for child fabric vrf/networks on fed --- .../dtc/manage_child_fabric_networks.py | 16 +++- .../action/dtc/manage_child_fabric_vrfs.py | 19 +++-- plugins/action/dtc/prepare_msite_data.py | 81 +++++++++++++------ .../action/dtc/unmanaged_edge_connections.py | 2 +- plugins/plugin_utils/helper_functions.py | 67 +++++++++++++++ .../common/templates/ndfc_attach_vrfs_fed.j2 | 2 +- .../ndfc_attach_vrfs_loopbacks_fed.j2 | 2 +- .../ndfc_loopback_interfaces.j2 | 15 +++- .../ndfc_vpc_peering_pairs_external.j2 | 12 --- .../ndfc_vrf_lite/ndfc_vrf_lite_ebgp.j2 | 3 + roles/dtc/create/tasks/mfd/vrfs_networks.yml | 52 +++++++----- roles/dtc/create/tasks/sub_main_mfd.yml | 20 +++-- 12 files changed, 214 insertions(+), 77 deletions(-) diff --git a/plugins/action/dtc/manage_child_fabric_networks.py b/plugins/action/dtc/manage_child_fabric_networks.py index b536127e3..53a76a4a7 100644 --- a/plugins/action/dtc/manage_child_fabric_networks.py +++ b/plugins/action/dtc/manage_child_fabric_networks.py @@ -47,6 +47,7 @@ def run(self, tmp=None, task_vars=None): results['child_fabrics_changed'] = [] msite_data = self._task.args["msite_data"] + fabric_type = self._task.args["fabric_type"] networks = msite_data['overlay_attach_groups']['networks'] network_attach_groups_dict = msite_data['overlay_attach_groups']['network_attach_groups'] @@ -73,6 +74,7 @@ def run(self, tmp=None, task_vars=None): if child_fabric_type in ['Switch_Fabric']: child_fabric_attributes = child_fabrics[child_fabric]['attributes'] child_fabric_switches = child_fabrics[child_fabric]['switches'] + child_fabric_cluster = child_fabrics[child_fabric].get('cluster') child_fabric_switches_mgmt_ip_addresses = [child_fabric_switch['mgmt_ip_address'] for child_fabric_switch in child_fabric_switches] is_intersection = set(network_attach_group_switches_mgmt_ip_addresses).intersection(set(child_fabric_switches_mgmt_ip_addresses)) @@ -128,12 +130,15 @@ def run(self, tmp=None, task_vars=None): # results['failed'] = True # results['msg'] = error_msg # return results - + if fabric_type == 'MFD': + get_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" + else: + get_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" ndfc_net = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "GET", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}", + "path": get_path, }, task_vars=task_vars, tmp=tmp @@ -182,12 +187,15 @@ def run(self, tmp=None, task_vars=None): # Render the template with the combined variables rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) - + if fabric_type == 'MFD': + put_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" + else: + put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" ndfc_net_update = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "PUT", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}", + "path": put_path, "data": rendered_to_nice_json }, task_vars=task_vars, diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index 6ee32c1c9..84dcf9ca2 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -47,6 +47,7 @@ def run(self, tmp=None, task_vars=None): results['child_fabrics_changed'] = [] msite_data = self._task.args["msite_data"] + fabric_type = self._task.args["fabric_type"] vrfs = msite_data['overlay_attach_groups']['vrfs'] vrf_attach_groups_dict = msite_data['overlay_attach_groups']['vrf_attach_groups'] @@ -73,6 +74,7 @@ def run(self, tmp=None, task_vars=None): if child_fabric_type in ['Switch_Fabric']: child_fabric_attributes = child_fabrics[child_fabric]['attributes'] child_fabric_switches = child_fabrics[child_fabric]['switches'] + child_fabric_cluster = child_fabrics[child_fabric].get('cluster') child_fabric_switches_mgmt_ip_addresses = [child_fabric_switch['mgmt_ip_address'] for child_fabric_switch in child_fabric_switches] is_intersection = set(vrf_attach_group_switches_mgmt_ip_addresses).intersection(set(child_fabric_switches_mgmt_ip_addresses)) @@ -128,12 +130,15 @@ def run(self, tmp=None, task_vars=None): # results['failed'] = True # results['msg'] = error_msg # return results - + if fabric_type == 'MFD': + get_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" + else: + get_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" ndfc_vrf = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "GET", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" + "path": get_path, }, task_vars=task_vars, tmp=tmp @@ -141,7 +146,7 @@ def run(self, tmp=None, task_vars=None): ndfc_vrf_response_data = ndfc_vrf['response']['DATA'] ndfc_vrf_template_config = json.loads(ndfc_vrf_response_data['vrfTemplateConfig']) - + print(ndfc_vrf_template_config) # Check for differences between the data model and the template config from NDFC for the # attributes that are configurable by the user in a child fabric. # Note: This excludes IPv6 related attributes at this time as they are not yet supported fully in the data model. @@ -193,12 +198,16 @@ def run(self, tmp=None, task_vars=None): # Render the template with the combined variables rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) - + + if fabric_type == 'MFD': + put_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" + else: + put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" ndfc_vrf_update = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "PUT", - "path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}", + "path": put_path, "data": rendered_to_nice_json }, task_vars=task_vars, diff --git a/plugins/action/dtc/prepare_msite_data.py b/plugins/action/dtc/prepare_msite_data.py index fb26150a4..5608e0880 100644 --- a/plugins/action/dtc/prepare_msite_data.py +++ b/plugins/action/dtc/prepare_msite_data.py @@ -28,6 +28,8 @@ from ansible.plugins.action import ActionBase from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes from ...plugin_utils.helper_functions import ndfc_get_fabric_switches +from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes_onepath +from ...plugin_utils.helper_functions import ndfc_get_fabric_switches_onepath import re display = Display() @@ -46,34 +48,63 @@ def run(self, tmp=None, task_vars=None): # This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD # Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD) - msd_fabric_associations = self._execute_module( - module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "GET", - "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", - }, - task_vars=task_vars, - tmp=tmp - ) - - # Build a list of child fabrics that are associated with the parent fabric (MSD) - associated_child_fabrics = [] - for fabric in msd_fabric_associations.get('response').get('DATA'): - if fabric.get('fabricParent') == parent_fabric: - associated_child_fabrics.append(fabric.get('fabricName')) + if model_data["vxlan"]["fabric"]["type"] == "MFD": + mfd_fabric_associations = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics", + }, + task_vars=task_vars, + tmp=tmp + ) + associated_child_fabrics = [] + for fabric in mfd_fabric_associations.get('response').get('DATA'): + if fabric.get('fabricName') == parent_fabric: + for member in fabric["members"]: + associated_child_fabrics.append({'fabric':member.get('fabricName'), 'cluster':member.get('clusterName'), 'type':member.get('fabricType')}) + + + child_fabrics_data = {} + for fabric in associated_child_fabrics: + fabric_name = fabric['fabric'] + child_fabrics_data.update({fabric_name: {}}) + child_fabrics_data[fabric_name].update({'type': fabric['type']}) + child_fabrics_data[fabric_name].update({'attributes': ndfc_get_fabric_attributes_onepath(self, task_vars, tmp, fabric_name, fabric['cluster'])}) + child_fabrics_data[fabric_name].update({'switches': ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric_name, fabric['cluster'])}) + child_fabrics_data[fabric_name].update({'cluster': fabric['cluster']}) + + results['child_fabrics_data'] = child_fabrics_data + + else: + msd_fabric_associations = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", + }, + task_vars=task_vars, + tmp=tmp + ) + + # Build a list of child fabrics that are associated with the parent fabric (MSD) + associated_child_fabrics = [] + for fabric in msd_fabric_associations.get('response').get('DATA'): + if fabric.get('fabricParent') == parent_fabric: + associated_child_fabrics.append(fabric.get('fabricName')) # Get the fabric attributes and switches for each child fabric # These queries are potentially trying to get data for a fabric that is not associated with the parent fabric (MSD) yet - child_fabrics_data = {} - for fabric in associated_child_fabrics: - child_fabrics_data.update({fabric: {}}) - child_fabrics_data[fabric].update( - {'type': [_fabric['fabricType'] for _fabric in msd_fabric_associations['response']['DATA'] if _fabric['fabricName'] == fabric][0]} - ) - child_fabrics_data[fabric].update({'attributes': ndfc_get_fabric_attributes(self, task_vars, tmp, fabric)}) - child_fabrics_data[fabric].update({'switches': ndfc_get_fabric_switches(self, task_vars, tmp, fabric)}) - - results['child_fabrics_data'] = child_fabrics_data + child_fabrics_data = {} + for fabric in associated_child_fabrics: + child_fabrics_data.update({fabric: {}}) + child_fabrics_data[fabric].update( + {'type': [_fabric['fabricType'] for _fabric in msd_fabric_associations['response']['DATA'] if _fabric['fabricName'] == fabric][0]} + ) + child_fabrics_data[fabric].update({'attributes': ndfc_get_fabric_attributes(self, task_vars, tmp, fabric)}) + child_fabrics_data[fabric].update({'switches': ndfc_get_fabric_switches(self, task_vars, tmp, fabric)}) + + results['child_fabrics_data'] = child_fabrics_data # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into # a structure that is easier to use just like MD_Extended. diff --git a/plugins/action/dtc/unmanaged_edge_connections.py b/plugins/action/dtc/unmanaged_edge_connections.py index 39c0f2f08..816f769c9 100644 --- a/plugins/action/dtc/unmanaged_edge_connections.py +++ b/plugins/action/dtc/unmanaged_edge_connections.py @@ -37,7 +37,7 @@ def run(self, tmp=None, task_vars=None): # List of switch serial numbes obtained directly from NDFC ndfc_sw_data = self._task.args["switch_data"] # Data from data model - edge_connections = self._task.args["edge_connections"][0]["switch"] + edge_connections = self._task.args.get("edge_connections", [{}])[0].get("switch", []) restructured_edge_connections = {} # For each switch current_sw_policies will be used to store a list of policies currently associated to the switch # For each switch that has unmanaged policies, the switch IP address and the list of unmanaged policies will be stored diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index a047275b1..719b0d547 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -196,6 +196,35 @@ def ndfc_get_fabric_attributes(self, task_vars, tmp, fabric): return fabric_attributes +def ndfc_get_fabric_attributes_onepath(self, task_vars, tmp, fabric, cluster): + """ + Get NDFC fabric attributes. + + :Parameters: + :self: Ansible action plugin instance object. + :task_vars (dict): Ansible task vars. + :tmp (None, optional): Ansible tmp object. Defaults to None via Action Plugin. + :fabric (str): The fabric name to be retrieved. + + :Returns: + :fabric_attributes: The NDFC fabric attributes data for the given fabric. + + :Raises: + N/A + """ + fabric_response = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": f"/onepath/{cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}", + }, + task_vars=task_vars, + tmp=tmp + ) + fabric_attributes = fabric_response['response']['DATA']['nvPairs'] + + return fabric_attributes + def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): """ @@ -235,6 +264,44 @@ def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): return fabric_switches +def ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric, cluster): + """ + Get NDFC fabric switches. + + :Parameters: + :self: Ansible action plugin instance object. + :task_vars (dict): Ansible task vars. + :tmp (None, optional): Ansible tmp object. Defaults to None via Action Plugin. + :fabric (str): The fabric name to be retrieved. + + :Returns: + :fabric_switches: The NDFC fabric switches data for the given fabric. + + :Raises: + N/A + """ + fabric_response = self._execute_module( + module_name="cisco.dcnm.dcnm_rest", + module_args={ + "method": "GET", + "path": f"/onepath/{cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}/inventory/switchesByFabric", + }, + task_vars=task_vars, + tmp=tmp + ) + + fabric_switches = [] + for fabric_switch in fabric_response['response']['DATA']: + if 'logicalName' in fabric_switch: + fabric_switches.append( + { + 'hostname': fabric_switch['logicalName'], + 'mgmt_ip_address': fabric_switch['ipAddress'] + } + ) + + return fabric_switches + def normalise_int_lists(data): for interface in data: if interface.startswith(('Ethernet','ethernet','Eth','eth','E','e')): diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 index ba262e39d..3709253da 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 @@ -5,7 +5,7 @@ "vrfName":"{{ vrf.name}}", "vrfId":"{{ vrf.vrf_id }}", "vrfTemplate":"Default_VRF_Universal", - "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vrf_vlan_name | default(vrf.vlan_id)}}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vrf_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", + "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vrf_vlan_name | default(vrf.vlan_id)}}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vrf_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", "serviceVrfTemplate": null, "serviceVrfTemplate": null, "displayName": "{{ vrf.name}}", diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 index eda05c702..093c2c78b 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 @@ -9,7 +9,7 @@ "serialNumber": "{{ switch.serialNumber }}", {% endif %} {% endfor %} - "freeformConfig": "{{ attach['freeform_config'] | default('') }}", + "freeformConfig": "{{ attach['freeform_config'] | default('') | replace('\n', '\\n') | replace('"', '\\"') }}", "extensionValues": "", "vlan": {{ vrf["vlan_id"] }}, "deployment": true, diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 index 73a2ae381..c49a61252 100644 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 +++ b/roles/dtc/common/templates/ndfc_interfaces/ndfc_loopback_interfaces.j2 @@ -2,17 +2,26 @@ # This NDFC loopback interface data structure is auto-generated # DO NOT EDIT MANUALLY # +{% set is_manual_allocation = false %} +{% set skip = false %} +{% if MD_Extended.vxlan.underlay is defined %} +{% set is_manual_allocation = MD_Extended.vxlan.underlay.general.manual_underlay_allocation | default(defaults.vxlan.underlay.general.manual_underlay_allocation) %} {% set routing_lo_id = MD_Extended.vxlan.underlay.general.underlay_routing_loopback_id %} {% set vtep_lo_id = MD_Extended.vxlan.underlay.general.underlay_vtep_loopback_id %} +{% endif %} {% for switch in MD_Extended.vxlan.topology.switches %} {% if switch.interfaces is defined %} {% for interface in switch.interfaces %} {% if interface.mode is defined and interface.mode in ['loopback', 'mpls_loopback', 'fabric_loopback'] %} {% set intf_lower = interface.name.lower() %} -{% if not ((intf_lower == "loopback" ~ vtep_lo_id or intf_lower == "lo" ~ vtep_lo_id or - intf_lower == "loopback" ~ routing_lo_id or intf_lower == "lo" ~ routing_lo_id) - and MD_Extended.vxlan.underlay.general.manual_underlay_allocation is true) %} +{# Exclude Loopback when use as Routing / VTEP Loopback with manual_underlay_allocation for VXLAN_EVPN #} +{% if is_manual_allocation is true %} +{% if (intf_lower == "loopback" ~ vtep_lo_id or intf_lower == "lo" ~ vtep_lo_id or intf_lower == "loopback" ~ routing_lo_id or intf_lower == "lo" ~ routing_lo_id) %} +{% set skip = true %} +{% endif %} +{% endif %} +{% if skip is false %} - name: {{ interface.name }} type: lo switch: diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 index 56df2ad04..d2b170c1c 100644 --- a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -8,24 +8,12 @@ peerTwoId: {{ vpc_peers_pair.peer2_mgmt_ip_address }} templateName: "vpc_pair" profile: - ADMIN_STATE: {{ vpc_peers_pair.enabled }} - ALLOWED_VLANS: "{{ vpc_peers_pair.trunk_allowed_vlans }}" DOMAIN_ID: {{ vpc_peers_pair.domain_id }} FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} KEEP_ALIVE_HOLD_TIMEOUT: {{ vpc_peers_pair.keepalive_holdout_time | default(defaults.vxlan.topology.vpc_peers.keepalive_holdout_time) }} KEEP_ALIVE_VRF: {{ vpc_peers_pair.keepalive_vrfname }} - PC_MODE: {{ vpc_peers_pair.port_channel_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} PEER1_DOMAIN_CONF: "{{ vpc_peers_pair.peer1_domain_conf | default('') }}" PEER1_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer1_keepalive_ipv4 }} - PEER1_PO_CONF: "{{ vpc_peers_pair.peer1_po_channel_conf | default('') }}" - PEER1_PO_DESC: "{{ vpc_peers_pair.peer1_po_channel_desc | default('') }}" - PEER2_DOMAIN_CONF: "{{ vpc_peers_pair.peer2_domain_conf | default('') }}" PEER2_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer2_keepalive_ipv4 }} - PEER2_PO_CONF: "{{ vpc_peers_pair.peer2_po_channel_conf | default('') }}" - PEER2_PO_DESC: "{{ vpc_peers_pair.peer2_po_channel_desc | default('') }}" - PEER1_PCID: {{ vpc_peers_pair.peer1_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_port_channel_id) }} - PEER2_PCID: {{ vpc_peers_pair.peer2_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_port_channel_id) }} - PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" - PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" {% endfor %} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_vrf_lite/ndfc_vrf_lite_ebgp.j2 b/roles/dtc/common/templates/ndfc_vrf_lite/ndfc_vrf_lite_ebgp.j2 index ecd1b6129..e5c14fafa 100644 --- a/roles/dtc/common/templates/ndfc_vrf_lite/ndfc_vrf_lite_ebgp.j2 +++ b/roles/dtc/common/templates/ndfc_vrf_lite/ndfc_vrf_lite_ebgp.j2 @@ -68,6 +68,9 @@ router bgp {{ MD_Extended.vxlan.global.bgp_asn }} {% if switch_redist.source == 'static' and switch_redist.route_map_ipv4 %} redistribute static route-map {{ switch_redist.route_map_ipv4 }} {% endif %} + {% if switch_redist.source == 'ospf' and switch_redist.route_map_ipv4 %} + redistribute ospf {{ switch_redist.protocol_tag }} route-map {{ switch_redist.route_map_ipv4 }} + {% endif %} {% endfor %} {% endif %} ! diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index ad2b856ff..7b87d7977 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -31,15 +31,15 @@ # Manage VRF Configuration for Federated NDFCs # -------------------------------------------------------------------- -- name: set filename for federated - set_fact: +- name: Set filename for federated + ansible.builtin.set_fact: file_name: "ndfc_fed_attach_vrfs.yml" when: - MD.vxlan.multisite.overlay.vrfs is defined - changes_detected_vrfs - MD.vxlan.fabric.type == 'MFD' -- name: load VRF federated details from file +- name: Load VRF federated details from file ansible.builtin.set_fact: fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" when: @@ -58,7 +58,7 @@ - MD.vxlan.fabric.type == 'MFD' - name: Manage NDFC Fabric VRFs for Federated - include_tasks: vrf_fed_config.yml + ansible.builtin.include_tasks: vrf_fed_config.yml loop: "{{ fed_vrf_config }}" loop_control: loop_var: vrf @@ -71,7 +71,7 @@ # Manage Loopback VRF attachments on NDFC (MFD) # -------------------------------------------------------------------- - name: Attach VRF Loopbacks per VRF - include_tasks: vrf_loopbacks.yml + ansible.builtin.include_tasks: vrf_loopbacks.yml loop_control: loop_var: vrf loop: "{{ MD.vxlan.multisite.overlay.vrfs }}" @@ -81,8 +81,8 @@ - name: Get vrf attachments list cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments register: vrfAttachmentList - name: Filter vrf attachments to be removed @@ -95,18 +95,24 @@ - name: Remove vrf attachments cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments - json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" register: vrf_attachment_result +- name: Manage NDFC Child Fabric VRFs + cisco.nac_dc_vxlan.dtc.manage_child_fabric_vrfs: + msite_data: "{{ MD_Multisite }}" + fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" + register: child_fabric_vrf_results + # -------------------------------------------------------------------- # Manage Network Configuration for Federated NDFCs # -------------------------------------------------------------------- - name: Query existing network.switches_to_attach.split in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{MD.vxlan.fabric.name}}/networks" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/networks" register: fed_networks_existing when: - MD.vxlan.multisite.overlay.networks is defined @@ -114,7 +120,7 @@ - MD.vxlan.fabric.type == 'MFD' - name: Manage NDFC Fabric Networks for Federated - include_tasks: network_fed_config.yml + ansible.builtin.include_tasks: network_fed_config.yml loop: "{{ net_config }}" loop_control: loop_var: network @@ -127,7 +133,7 @@ cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/attachments" method: "POST" - json_data: "{{ network_switches | to_json}}" + json_data: "{{ network_switches | to_json }}" when: - network_switches is defined - MD.vxlan.fabric.type == 'MFD' @@ -138,7 +144,7 @@ cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/multiattach" method: "POST" - json_data: "{{ network_switches_ports | to_json}}" + json_data: "{{ network_switches_ports | to_json }}" when: - network_switches_ports is defined - MD.vxlan.fabric.type == 'MFD' @@ -147,8 +153,8 @@ - name: Get network attachments list cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList when: - MD.vxlan.fabric.type == 'MFD' @@ -169,11 +175,17 @@ - name: Attach network to switches and ports for all networks cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments - json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - network_switches_ports is defined - MD.vxlan.fabric.type == 'MFD' - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks \ No newline at end of file + - changes_detected_networks + +- name: Manage NDFC Child Fabric Networks + cisco.nac_dc_vxlan.dtc.manage_child_fabric_networks: + msite_data: "{{ MD_Multisite }}" + fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" + register: child_fabric_network_results diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mfd.yml index cdbdd9db0..d10ed2804 100644 --- a/roles/dtc/create/tasks/sub_main_mfd.yml +++ b/roles/dtc/create/tasks/sub_main_mfd.yml @@ -28,7 +28,8 @@ - "----------------------------------------------------------------" tags: "{{ nac_tags.create }}" # Tags defined in roles/common_global/vars/main.yml -- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" +- name: Debug message + ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" tags: "{{ nac_tags.create }}" - name: Create NDFC Fabric @@ -38,18 +39,27 @@ - changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" -- ansible.builtin.debug: msg="Query NDFC for List of Fabric Switches" +- name: Debug message + ansible.builtin.debug: msg="Query NDFC for List of Fabric Switches" tags: "{{ nac_tags.create }}" -- cisco.dcnm.dcnm_rest: +- name: Collect switch data from NDFC + cisco.dcnm.dcnm_rest: method: GET path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" register: result tags: "{{ nac_tags.create }}" -- name: set facts for result +- name: Set facts for result ansible.builtin.set_fact: - switch_list_create: "{{result}}" + switch_list_create: "{{ result }}" + +- name: Prepare Multisite Data + cisco.nac_dc_vxlan.dtc.prepare_msite_data: + model_data: "{{ MD_Extended }}" + parent_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + register: MD_Multisite + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: mfd/vrfs_networks.yml From 7ab9a0bd1380b813612667cc781be260370463e1 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 7 Aug 2025 10:17:05 +0100 Subject: [PATCH 137/183] Added corrections to vpc pairing and updarted fed for child fabric settings pre-work --- roles/dtc/common/tasks/sub_main_external.yml | 44 +++++++++++++++---- .../ndfc_vpc_peering_pairs_external.j2 | 12 +++++ roles/dtc/create/tasks/sub_main_external.yml | 14 +++--- roles/dtc/create/tasks/sub_main_msd.yml | 2 +- roles/dtc/remove/tasks/mfd/networks_fed.yml | 26 +++++------ roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 24 +++++----- 6 files changed, 81 insertions(+), 41 deletions(-) diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index 49c0dbfc1..d84ad02b7 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -52,6 +52,20 @@ - name: Build NDFC Fabric Switch Inventory List From Template ansible.builtin.import_tasks: common/ndfc_inventory.yml +# -------------------------------------------------------------------- +# Build vPC Peering parameter List From Template +# -------------------------------------------------------------------- + +- name: Build vPC Peering Parameters + ansible.builtin.import_tasks: external/ndfc_vpc_peering_pairs.yml + +# -------------------------------------------------------------------- +# Build NDFC Fabric Breakout Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build NDFC Fabric Breakout Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_breakout.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Access Port-Channel Interfaces List From Template # -------------------------------------------------------------------- @@ -66,6 +80,13 @@ - name: Build Access Interfaces List From Template ansible.builtin.import_tasks: common/ndfc_interface_access.yml +# -------------------------------------------------------------------- +# Build Dot1q Interfaces List From Template +# -------------------------------------------------------------------- + +- name: Build Dot1q Interfaces List From Template + ansible.builtin.import_tasks: common/ndfc_interface_dot1q.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Loopback Interfaces List From Template # -------------------------------------------------------------------- @@ -98,7 +119,7 @@ # Build Trunk Interfaces List From Template # -------------------------------------------------------------------- -- name: Build Trunk Interfaces List From Template +- name: Build Trunk Interfaces List From Template ansible.builtin.import_tasks: common/ndfc_interface_trunk.yml # -------------------------------------------------------------------- @@ -122,18 +143,19 @@ - name: Build Fabric interface All List From Template ansible.builtin.import_tasks: common/ndfc_interface_all.yml +# -------------------------------------------------------------------- +# Build Policy List From Template +# -------------------------------------------------------------------- + - name: Build NDFC Policy List From Template ansible.builtin.import_tasks: common/ndfc_policy.yml -- name: Edge Connections List From Template - ansible.builtin.import_tasks: common/ndfc_edge_connections.yml - # -------------------------------------------------------------------- -# Build vPC Peering parameter List From Template +# Build Edge Connections List From Template # -------------------------------------------------------------------- -- name: Build vPC Peering Parameters - ansible.builtin.import_tasks: external/ndfc_vpc_peering_pairs.yml +- name: Build Edge Connections List From Template + ansible.builtin.import_tasks: common/ndfc_edge_connections.yml # -------------------------------------------------------------------- # Save Local Variables To NameSpace Dict For Use Elsewhere @@ -147,16 +169,20 @@ changes_detected_interface_access_po: "{{ changes_detected_interface_access_po }}" changes_detected_interface_access: "{{ changes_detected_interface_access }}" changes_detected_interface_loopback: "{{ changes_detected_interface_loopback }}" + changes_detected_interface_breakout: "{{ changes_detected_interface_breakout }}" changes_detected_interface_po_routed: "{{ changes_detected_interface_po_routed }}" changes_detected_interface_routed: "{{ changes_detected_interface_routed }}" changes_detected_interface_trunk_po: "{{ changes_detected_interface_trunk_po }}" changes_detected_interface_trunk: "{{ changes_detected_interface_trunk }}" changes_detected_sub_interface_routed: "{{ changes_detected_sub_interface_routed }}" + changes_detected_interface_dot1q: "{{ changes_detected_interface_dot1q }}" + changes_detected_interface_vpc: "{{ changes_detected_interface_vpc }}" changes_detected_interfaces: "{{ changes_detected_interfaces }}" changes_detected_policy: "{{ changes_detected_policy }}" changes_detected_vpc_peering: "{{ changes_detected_vpc_peering }}" fabric_config: "{{ fabric_config }}" edge_connections: "{{ edge_connections }}" + interface_breakout: "{{ interface_breakout }}" interface_access_po: "{{ interface_access_po }}" interface_access: "{{ interface_access }}" interface_all: "{{ interface_all }}" @@ -165,6 +191,8 @@ interface_routed: "{{ interface_routed }}" interface_trunk_po: "{{ interface_trunk_po }}" interface_trunk: "{{ interface_trunk }}" + interface_dot1q: "{{ interface_dot1q }}" + interface_vpc: "{{ interface_vpc }}" inv_config: "{{ inv_config }}" poap_data: "{{ poap_data }}" policy_config: "{{ policy_config }}" @@ -179,8 +207,8 @@ - "+ Fabric Changes Detected - [ {{ vars_common_external.changes_detected_fabric }} ]" - "+ Inventory Changes Detected - [ {{ vars_common_external.changes_detected_inventory }} ]" - "+ Edge Connections Changes Detected - [ {{ vars_common_external.changes_detected_edge_connections }} ]" - - "+ vPC Peer Changes Detected - [ {{ vars_common_external.changes_detected_vpc_peering }} ]" - "+ ----- Interfaces -----" + - "+ Interface breakout Changes Detected - [ {{ vars_common_external.changes_detected_interface_breakout }} ]" - "+ Interface Access Changes Detected - [ {{ vars_common_external.changes_detected_interface_access }} ]" - "+ Interface Access PO Changes Detected - [ {{ vars_common_external.changes_detected_interface_access_po }} ]" - "+ Interface Loopback Changes Detected - [ {{ vars_common_external.changes_detected_interface_loopback }} ]" diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 index d2b170c1c..56df2ad04 100644 --- a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -8,12 +8,24 @@ peerTwoId: {{ vpc_peers_pair.peer2_mgmt_ip_address }} templateName: "vpc_pair" profile: + ADMIN_STATE: {{ vpc_peers_pair.enabled }} + ALLOWED_VLANS: "{{ vpc_peers_pair.trunk_allowed_vlans }}" DOMAIN_ID: {{ vpc_peers_pair.domain_id }} FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} KEEP_ALIVE_HOLD_TIMEOUT: {{ vpc_peers_pair.keepalive_holdout_time | default(defaults.vxlan.topology.vpc_peers.keepalive_holdout_time) }} KEEP_ALIVE_VRF: {{ vpc_peers_pair.keepalive_vrfname }} + PC_MODE: {{ vpc_peers_pair.port_channel_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} PEER1_DOMAIN_CONF: "{{ vpc_peers_pair.peer1_domain_conf | default('') }}" PEER1_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer1_keepalive_ipv4 }} + PEER1_PO_CONF: "{{ vpc_peers_pair.peer1_po_channel_conf | default('') }}" + PEER1_PO_DESC: "{{ vpc_peers_pair.peer1_po_channel_desc | default('') }}" + PEER2_DOMAIN_CONF: "{{ vpc_peers_pair.peer2_domain_conf | default('') }}" PEER2_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer2_keepalive_ipv4 }} + PEER2_PO_CONF: "{{ vpc_peers_pair.peer2_po_channel_conf | default('') }}" + PEER2_PO_DESC: "{{ vpc_peers_pair.peer2_po_channel_desc | default('') }}" + PEER1_PCID: {{ vpc_peers_pair.peer1_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_port_channel_id) }} + PEER2_PCID: {{ vpc_peers_pair.peer2_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_port_channel_id) }} + PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" + PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" {% endfor %} {% endif %} diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 012193273..5f1862346 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -55,13 +55,6 @@ - changes_detected_edge_connections tags: "{{ nac_tags.create_links }}" -- name: Manage NDFC External Fabric Interfaces - ansible.builtin.import_tasks: common/interfaces.yml - when: - - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) - - vars_common_external.changes_detected_interfaces - tags: "{{ nac_tags.create_interfaces }}" - - name: Manage NDFC External VPC Peering ansible.builtin.import_tasks: common/vpc_peering.yml when: @@ -69,6 +62,13 @@ - vars_common_external.changes_detected_vpc_peering tags: "{{ nac_tags.create_vpc_peers }}" +- name: Manage NDFC External Fabric Interfaces + ansible.builtin.import_tasks: common/interfaces.yml + when: + - (MD_Extended.vxlan.topology.interfaces.modes.all.count >0) and (MD_Extended.vxlan.topology.switches | length > 0) + - vars_common_external.changes_detected_interfaces + tags: "{{ nac_tags.create_interfaces }}" + - name: Manage NDFC External Fabric Policies ansible.builtin.import_tasks: common/policies.yml when: diff --git a/roles/dtc/create/tasks/sub_main_msd.yml b/roles/dtc/create/tasks/sub_main_msd.yml index 6f0eae7cd..12911e389 100644 --- a/roles/dtc/create/tasks/sub_main_msd.yml +++ b/roles/dtc/create/tasks/sub_main_msd.yml @@ -64,7 +64,7 @@ | selectattr('value.attributes.STATIC_UNDERLAY_IP_ALLOC', 'defined') | selectattr('value.attributes.STATIC_UNDERLAY_IP_ALLOC', 'in', ["true", true]) | map(attribute='key') - | list + | list | length > 0) and (vars_common_msd.bgw_anycast_vip | length > 0) diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index a8087e1f0..848b0596c 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -28,13 +28,13 @@ - name: Get network list cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" register: networkList - name: Get network attachments list cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList - name: Filter networks to be removed @@ -47,9 +47,9 @@ - name: Remove network attachments cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments - json_data: "{{ not_required_networks.attachments_payload | to_json }}" + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + json_data: "{{ not_required_networks.attachments_payload | to_json }}" register: network_attachment_result when: - switch_list.response.DATA | length > 0 @@ -58,15 +58,15 @@ - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: - method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save - ignore_errors: True + ignore_errors: true - name: Deploy for network attachments removal cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{not_required_networks.deploy_payload | join(',') }}?forceShowRun=false + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_networks.deploy_payload | join(',') }}?forceShowRun=false when: - switch_list.response.DATA | length > 0 - not_required_networks.deploy_payload | length > 0 @@ -74,8 +74,8 @@ - name: Remove networks cisco.dcnm.dcnm_rest: - method: DELETE - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/networks?network-names={{ not_required_networks.payload | join(',') }} + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/networks?network-names={{ not_required_networks.payload | join(',') }} register: network_attachment_result when: - switch_list.response.DATA | length > 0 diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index 8efd95bfc..fbf7e1d39 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -33,8 +33,8 @@ - name: Get vrf attachments list cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments register: vrfAttachmentList - name: Filter vrfs to be removed @@ -47,9 +47,9 @@ - name: Remove vrf attachments cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments - json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" register: vrf_attachment_result when: - switch_list.response.DATA | length > 0 @@ -58,15 +58,15 @@ - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} cisco.dcnm.dcnm_rest: - method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save - ignore_errors: True + ignore_errors: true - name: Deploy for vrf attachments removal cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 @@ -77,8 +77,8 @@ - name: Remove vrfs cisco.dcnm.dcnm_rest: - method: DELETE - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/vrfs?vrf-names={{ not_required_vrfs.payload | join(',') }} + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/vrfs?vrf-names={{ not_required_vrfs.payload | join(',') }} register: network_attachment_result when: - switch_list.response.DATA | length > 0 From 404b572b918cec0d068d097d8245621aeaacb25c Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 8 Aug 2025 09:48:32 +0100 Subject: [PATCH 138/183] More VPC for external updates --- .../ndfc_vpc_peering_pairs_external.j2 | 20 +++++++++++-------- roles/dtc/create/tasks/sub_main_external.yml | 14 ++++++------- roles/validate/files/defaults.yml | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 index 56df2ad04..18f3dde7e 100644 --- a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -15,17 +15,21 @@ KEEP_ALIVE_HOLD_TIMEOUT: {{ vpc_peers_pair.keepalive_holdout_time | default(defaults.vxlan.topology.vpc_peers.keepalive_holdout_time) }} KEEP_ALIVE_VRF: {{ vpc_peers_pair.keepalive_vrfname }} PC_MODE: {{ vpc_peers_pair.port_channel_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} - PEER1_DOMAIN_CONF: "{{ vpc_peers_pair.peer1_domain_conf | default('') }}" + PEER1_DOMAIN_CONF: |2- + {{ vpc_peers_pair.peer1_domain_conf | default('') | indent(6, false) }} PEER1_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer1_keepalive_ipv4 }} - PEER1_PO_CONF: "{{ vpc_peers_pair.peer1_po_channel_conf | default('') }}" PEER1_PO_DESC: "{{ vpc_peers_pair.peer1_po_channel_desc | default('') }}" - PEER2_DOMAIN_CONF: "{{ vpc_peers_pair.peer2_domain_conf | default('') }}" + PEER2_DOMAIN_CONF: |2- + {{ vpc_peers_pair.peer2_domain_conf | default('') | indent(6, false)}} PEER2_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer2_keepalive_ipv4 }} - PEER2_PO_CONF: "{{ vpc_peers_pair.peer2_po_channel_conf | default('') }}" + PEER1_PO_CONF: |2- + {{ vpc_peers_pair.peer1_po_channel_conf | default('') | indent(6, false) }} + PEER2_PO_CONF: |2- + {{ vpc_peers_pair.peer2_po_channel_conf | default('') | indent(6, false) }} PEER2_PO_DESC: "{{ vpc_peers_pair.peer2_po_channel_desc | default('') }}" - PEER1_PCID: {{ vpc_peers_pair.peer1_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_port_channel_id) }} - PEER2_PCID: {{ vpc_peers_pair.peer2_port_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_port_channel_id) }} - PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" - PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default('') }}" + PEER1_PCID: {{ vpc_peers_pair.peer1_po_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_po_channel_id) }} + PEER2_PCID: {{ vpc_peers_pair.peer2_po_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_po_channel_id) }} + PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default([]) | join(',') }}" + PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer2_member_interfaces | default([]) | join(',') }}" {% endfor %} {% endif %} diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 5f1862346..012193273 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -55,13 +55,6 @@ - changes_detected_edge_connections tags: "{{ nac_tags.create_links }}" -- name: Manage NDFC External VPC Peering - ansible.builtin.import_tasks: common/vpc_peering.yml - when: - - MD_Extended.vxlan.topology.vpc_peers | length > 0 - - vars_common_external.changes_detected_vpc_peering - tags: "{{ nac_tags.create_vpc_peers }}" - - name: Manage NDFC External Fabric Interfaces ansible.builtin.import_tasks: common/interfaces.yml when: @@ -69,6 +62,13 @@ - vars_common_external.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" +- name: Manage NDFC External VPC Peering + ansible.builtin.import_tasks: common/vpc_peering.yml + when: + - MD_Extended.vxlan.topology.vpc_peers | length > 0 + - vars_common_external.changes_detected_vpc_peering + tags: "{{ nac_tags.create_vpc_peers }}" + - name: Manage NDFC External Fabric Policies ansible.builtin.import_tasks: common/policies.yml when: diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index b8093c013..2001569cc 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -158,8 +158,8 @@ factory_defaults: domain_id: 1 keepalive_holdout_time: 3 port_channel_mode: active - peer1_port_channel_id: 500 - peer2_port_channel_id: 500 + peer1_po_channel_id: 500 + peer2_po_channel_id: 500 fabric_links: mtu: 9216 admin_state: true From be8311e79b97eb036b7b246183077b5dff4e5746 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 18 Aug 2025 09:57:33 +0100 Subject: [PATCH 139/183] expose admin state --- roles/dtc/common/templates/ndfc_edge_connections.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 index 1917adad9..48b09e8a3 100644 --- a/roles/dtc/common/templates/ndfc_edge_connections.j2 +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -44,7 +44,7 @@ FF_CONF: |2- {{ link.bgp_section.bgp_freeform | default('') | indent(14, false)}} SPEED: Auto - ADMIN_STATE: true + ADMIN_STATE: {{ link.source_interface_enabled | default(true) }} BGP_PASSWORD: "" BGP_PASSWORD_ENABLE: false OVERRIDE_LOCAL_ASN: false From 21917a25411d0fc0f4189dd4f4d8925bc06e7ae2 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 18 Aug 2025 10:42:23 +0100 Subject: [PATCH 140/183] a few updates from develop --- plugins/action/dtc/existing_links_check.py | 58 +++++++----- plugins/action/dtc/links_filter_and_remove.py | 35 +++++--- .../action/dtc/unmanaged_edge_connections.py | 30 +++++-- roles/dtc/create/tasks/common/fabric.yml | 22 +++-- roles/dtc/create/tasks/common/links.yml | 24 ++--- roles/dtc/remove/tasks/common/links.yml | 88 ++++++++++--------- 6 files changed, 153 insertions(+), 104 deletions(-) diff --git a/plugins/action/dtc/existing_links_check.py b/plugins/action/dtc/existing_links_check.py index 40862311d..0c307a749 100644 --- a/plugins/action/dtc/existing_links_check.py +++ b/plugins/action/dtc/existing_links_check.py @@ -40,35 +40,45 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] + switch_list = self._task.args['switch_data_model'] required_links = [] not_required_links = [] for link in fabric_links: for existing_link in existing_links: - if ('sw1-info' in existing_link and 'sw2-info' in existing_link and - 'sw-sys-name' in existing_link['sw1-info'] and 'sw-sys-name' in existing_link['sw2-info'] and - (existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and - existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and - existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and - existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or - (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and - existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and - existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and - existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): - if 'templateName' not in existing_link: - not_required_links.append(link) - elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': - required_links.append(link) - elif existing_link['templateName'] == 'int_intra_fabric_num_link': - link['template'] = 'int_intra_fabric_num_link' - link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] - link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] - if existing_link.get('nvPairs').get('ENABLE_MACSEC'): - link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + if ( + 'sw1-info' in existing_link and + 'sw2-info' in existing_link and + 'sw-sys-name' in existing_link['sw1-info'] and + 'sw-sys-name' in existing_link['sw2-info'] + ): + for switch in switch_list: + if existing_link['sw1-info']['sw-sys-name'].lower() == switch['name'].lower(): + existing_link['sw1-info']['sw-sys-name'] = switch['management']['management_ipv4_address'] + if existing_link['sw2-info']['sw-sys-name'].lower() == switch['name'].lower(): + existing_link['sw2-info']['sw-sys-name'] = switch['management']['management_ipv4_address'] + if ((existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or + (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): + if 'templateName' not in existing_link: + not_required_links.append(link) + elif existing_link['templateName'] == 'int_pre_provision_intra_fabric_link': + required_links.append(link) + elif existing_link['templateName'] == 'int_intra_fabric_num_link': + link['template'] = 'int_intra_fabric_num_link' + link['profile']['peer1_ipv4_addr'] = existing_link['nvPairs']['PEER1_IP'] + link['profile']['peer2_ipv4_addr'] = existing_link['nvPairs']['PEER2_IP'] + if existing_link.get('nvPairs').get('ENABLE_MACSEC'): + link['profile']['enable_macsec'] = existing_link['nvPairs']['ENABLE_MACSEC'] + else: + link['profile']['enable_macsec'] = 'false' + required_links.append(link) else: - link['profile']['enable_macsec'] = 'False' - required_links.append(link) - else: - not_required_links.append(link) + not_required_links.append(link) if link not in required_links and link not in not_required_links: required_links.append(link) diff --git a/plugins/action/dtc/links_filter_and_remove.py b/plugins/action/dtc/links_filter_and_remove.py index dfafcf918..def00622f 100644 --- a/plugins/action/dtc/links_filter_and_remove.py +++ b/plugins/action/dtc/links_filter_and_remove.py @@ -40,7 +40,7 @@ def run(self, tmp=None, task_vars=None): results = super(ActionModule, self).run(tmp, task_vars) existing_links = self._task.args['existing_links'] fabric_links = self._task.args['fabric_links'] - + switch_list = self._task.args['switch_data_model'] required_links = [] links_to_be_removed = [] filtered_existing_links = [] @@ -48,18 +48,27 @@ def run(self, tmp=None, task_vars=None): # Cannot assume the existing_link has the 'templateName' key so use get for safety if existing_link.get('templateName') == "int_pre_provision_intra_fabric_link" or existing_link.get('templateName') == "int_intra_fabric_num_link": filtered_existing_links.append(existing_link) - for link in fabric_links: - if ('sw1-info' in existing_link and 'sw2-info' in existing_link and - 'sw-sys-name' in existing_link['sw1-info'] and 'sw-sys-name' in existing_link['sw2-info'] and - (existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and - existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and - existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and - existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or - (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and - existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and - existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and - existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): - required_links.append(existing_link) + if ( + 'sw1-info' in existing_link and + 'sw2-info' in existing_link and + 'sw-sys-name' in existing_link['sw1-info'] and + 'sw-sys-name' in existing_link['sw2-info'] + ): + for switch in switch_list: + if existing_link['sw1-info']['sw-sys-name'].lower() == switch['name'].lower(): + existing_link['sw1-info']['sw-sys-name'] = switch['management']['management_ipv4_address'] + if existing_link['sw2-info']['sw-sys-name'].lower() == switch['name'].lower(): + existing_link['sw2-info']['sw-sys-name'] = switch['management']['management_ipv4_address'] + for link in fabric_links: + if ((existing_link['sw1-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['src_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['dst_interface'].lower()) or + (existing_link['sw1-info']['sw-sys-name'].lower() == link['dst_device'].lower() and + existing_link['sw1-info']['if-name'].lower() == link['dst_interface'].lower() and + existing_link['sw2-info']['sw-sys-name'].lower() == link['src_device'].lower() and + existing_link['sw2-info']['if-name'].lower() == link['src_interface'].lower())): + required_links.append(existing_link) for link in filtered_existing_links: link_found = False for required_link in required_links: diff --git a/plugins/action/dtc/unmanaged_edge_connections.py b/plugins/action/dtc/unmanaged_edge_connections.py index 816f769c9..6b9784aaf 100644 --- a/plugins/action/dtc/unmanaged_edge_connections.py +++ b/plugins/action/dtc/unmanaged_edge_connections.py @@ -25,7 +25,7 @@ __metaclass__ = type from ansible.plugins.action import ActionBase -from ...plugin_utils.helper_functions import ndfc_get_switch_policy_using_desc +from ansible_collections.cisco.nac_dc_vxlan.plugins.plugin_utils.helper_functions import ndfc_get_switch_policy_using_desc class ActionModule(ActionBase): @@ -37,7 +37,9 @@ def run(self, tmp=None, task_vars=None): # List of switch serial numbes obtained directly from NDFC ndfc_sw_data = self._task.args["switch_data"] # Data from data model - edge_connections = self._task.args.get("edge_connections", [{}])[0].get("switch", []) + edge_connections = self._task.args["edge_connections"] + if edge_connections: + edge_connections = edge_connections[0]["switch"] restructured_edge_connections = {} # For each switch current_sw_policies will be used to store a list of policies currently associated to the switch # For each switch that has unmanaged policies, the switch IP address and the list of unmanaged policies will be stored @@ -48,15 +50,25 @@ def run(self, tmp=None, task_vars=None): } ] # Iterate over each item in the data list - for item in edge_connections: - ip = item['ip'] - # If the IP is not already a key in the dictionary, add it with an empty list + # for item in edge_connections: + # ip = item['ip'] + # # If the IP is not already a key in the dictionary, add it with an empty list + # if ip not in restructured_edge_connections: + # restructured_edge_connections[ip] = [] + # # Iterate over each policy and collect the descriptions + # for policy in item['policies']: + # description = policy['description'] + # restructured_edge_connections[ip].append(description) + + for switch in ndfc_sw_data: + ip = switch['ipAddress'] if ip not in restructured_edge_connections: restructured_edge_connections[ip] = [] - # Iterate over each policy and collect the descriptions - for policy in item['policies']: - description = policy['description'] - restructured_edge_connections[ip].append(description) + for item in edge_connections: + if ip == item['ip']: + for policy in item['policies']: + description = policy['description'] + restructured_edge_connections[ip].append(description) # Print the resulting dictionary # print(restructured_edge_connections) diff --git a/roles/dtc/create/tasks/common/fabric.yml b/roles/dtc/create/tasks/common/fabric.yml index b20babfc5..1d1b65de7 100644 --- a/roles/dtc/create/tasks/common/fabric.yml +++ b/roles/dtc/create/tasks/common/fabric.yml @@ -21,17 +21,20 @@ --- -- name: Choose vars_common Based On Fabric Type +- name: Choose vars_common Based On Fabric Type - VXLAN_EVPN/iBGP_VXLAN ansible.builtin.set_fact: vars_common_local: "{{ vars_common_vxlan }}" when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - MSD + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_msd }}" when: MD_Extended.vxlan.fabric.type == "MSD" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - ISN + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_isn }}" when: MD_Extended.vxlan.fabric.type == "ISN" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - External + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_external }}" when: MD_Extended.vxlan.fabric.type == "External" @@ -42,19 +45,22 @@ - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Manage Fabric {{ MD_Extended.vxlan.fabric.name }} in NDFC +- name: Manage Fabric in Nexus Dashboard cisco.dcnm.dcnm_fabric: state: merged + skip_validation: "{{ True if MD_Extended.vxlan.fabric.type == 'ISN' else omit }}" config: "{{ vars_common_local.fabric_config }}" -- name: Create ANYCAST_RP {{ vxlan.underlay.multicast.ipv4.anycast_rp }} for {{ vxlan.fabric.name }} in NDFC +- name: Create ANYCAST_RP in Nexus Dashboard cisco.dcnm.dcnm_resource_manager: state: merged - fabric: "{{ vxlan.fabric.name }}" + fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: - entity_name: "ANYCAST_RP" pool_type: "IP" pool_name: "ANYCAST_RP_IP_POOL" scope_type: "fabric" resource: "{{ vxlan.underlay.multicast.ipv4.anycast_rp }}" - when: vxlan.underlay.general.manual_underlay_allocation is defined and vxlan.underlay.general.manual_underlay_allocation == True + when: + - vxlan.underlay.general.manual_underlay_allocation is defined + - vxlan.underlay.general.manual_underlay_allocation diff --git a/roles/dtc/create/tasks/common/links.yml b/roles/dtc/create/tasks/common/links.yml index 52a5d7306..59d3b4984 100644 --- a/roles/dtc/create/tasks/common/links.yml +++ b/roles/dtc/create/tasks/common/links.yml @@ -21,17 +21,20 @@ --- -- name: Choose vars_common Based On Fabric Type +- name: Choose vars_common Based On Fabric Type - VXLAN_EVPN/iBGP_VXLAN ansible.builtin.set_fact: vars_common_local: "{{ vars_common_vxlan }}" when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - MSD + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_msd }}" when: MD_Extended.vxlan.fabric.type == "MSD" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - ISN + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_isn }}" when: MD_Extended.vxlan.fabric.type == "ISN" -- ansible.builtin.set_fact: +- name: Choose vars_common Based On Fabric Type - External + ansible.builtin.set_fact: vars_common_local: "{{ vars_common_external }}" when: MD_Extended.vxlan.fabric.type == "External" @@ -42,29 +45,30 @@ - "+ Manage Fabric Links {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Query Links - with Src & Dst Fabric +- name: Query Links with Src & Dst Fabrics in Nexus Dashboard cisco.dcnm.dcnm_links: - state: query # choose from [merged, replaced, deleted, query] + state: query src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: - - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric + - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" register: result_links - name: Create empty result List ansible.builtin.set_fact: required_links: [] -- name: Create a list of links that already exist +- name: Create a List of Links that Already Exist from Nexus Dashboard cisco.nac_dc_vxlan.dtc.existing_links_check: existing_links: "{{ result_links.response }}" fabric_links: "{{ fabric_links }}" + switch_data_model: "{{ MD_Extended.vxlan.topology.switches }}" register: required_links when: result_links.response is defined # -------------------------------------------------------------------- -# Manage VRF Configuration on NDFC +# Manage Links Configuration in Nexus Dashboard # -------------------------------------------------------------------- -- name: Manage NDFC Fabric Links +- name: Manage Fabric Links in Nexus Dashboard cisco.dcnm.dcnm_links: src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ required_links['required_links'] }}" diff --git a/roles/dtc/remove/tasks/common/links.yml b/roles/dtc/remove/tasks/common/links.yml index a9667d854..0250e36e1 100644 --- a/roles/dtc/remove/tasks/common/links.yml +++ b/roles/dtc/remove/tasks/common/links.yml @@ -20,60 +20,68 @@ # SPDX-License-Identifier: MIT --- -- ansible.builtin.debug: msg="Removing Unmanaged vpc peer Links. This could take several minutes..." +- name: Display Removing Unmanaged vPC Peer Links Message + ansible.builtin.debug: + msg: "Removing Unmanaged vPC Peer Links. This could take several minutes..." when: - switch_list.response.DATA | length > 0 - (link_vpc_delete_mode is defined) and (link_vpc_delete_mode is true|bool) -- name: Remove Intra Fabric Links for vPC Peering +- name: Remove Intra Fabric Links for vPC Peering in Nexus Dashboard cisco.dcnm.dcnm_links: state: replaced src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" config: "{{ vars_common_vxlan.link_vpc_peering }}" vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 when: - switch_list.response.DATA | length > 0 - (link_vpc_delete_mode is defined) and (link_vpc_delete_mode is true|bool) -- block: - - ansible.builtin.debug: msg="Removing Unmanaged Fabric Links. This could take several minutes..." - - name: Query Links - with Src & Dst Fabric - cisco.dcnm.dcnm_links: - state: query # choose from [merged, replaced, deleted, query] - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: - - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric - register: result_links +- name: Unmanaged Fabric Links in Nexus Dashboard + when: + - switch_list.response.DATA | length > 0 + - (link_fabric_delete_mode is defined) and (link_fabric_delete_mode is true|bool) + block: + - name: Display Removing Unmanaged Fabric Links Message + ansible.builtin.debug: + msg: "Removing Unmanaged Fabric Links. This could take several minutes..." - - name: Create empty result List - ansible.builtin.set_fact: - required_links: [] + - name: Query Links with Src & Dst Fabric from Nexus Dashboard + cisco.dcnm.dcnm_links: + state: query # choose from [merged, replaced, deleted, query] + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: + - dst_fabric: "{{ MD_Extended.vxlan.fabric.name }}" # Destination fabric + register: result_links - - name: Create a list of links that already exist - cisco.nac_dc_vxlan.dtc.links_filter_and_remove: - existing_links: "{{ result_links.response }}" - fabric_links: "{{ vars_common_vxlan.fabric_links }}" - register: links_to_be_removed - when: result_links.response is defined + - name: Create empty result List + ansible.builtin.set_fact: + required_links: [] - # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest - - name: Set not_required_links if result_links.response is not defined - ansible.builtin.set_fact: - links_to_be_removed: [] - when: result_links.response is not defined - # -------------------------------------------------------------------- - # Manage VRF Configuration on NDFC - # -------------------------------------------------------------------- - - name: Manage NDFC Fabric Links - cisco.dcnm.dcnm_links: - src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - config: "{{ links_to_be_removed['links_to_be_removed'] }}" - deploy: false - state: deleted - register: delete_fabric_links_result + - name: Create a List of Links That Already Exist + cisco.nac_dc_vxlan.dtc.links_filter_and_remove: + existing_links: "{{ result_links.response }}" + fabric_links: "{{ vars_common_vxlan.fabric_links }}" + switch_data_model: "{{ MD_Extended.vxlan.topology.switches }}" + register: links_to_be_removed + when: result_links.response is defined - when: - - switch_list.response.DATA | length > 0 - - (link_fabric_delete_mode is defined) and (link_fabric_delete_mode is true|bool) + # do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest + - name: Set not_required_links if result_links.response is not defined + ansible.builtin.set_fact: + links_to_be_removed: [] + when: result_links.response is not defined + + # -------------------------------------------------------------------- + # Unmanage Fabric Links in Nexus Dashboard + # -------------------------------------------------------------------- + + - name: Unmanage Fabric Links in Nexus Dashboard + cisco.dcnm.dcnm_links: + src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" + config: "{{ links_to_be_removed['links_to_be_removed'] }}" + deploy: false + state: deleted + register: delete_fabric_links_result From 77d7176719d43a9f526053861b6f6ae390971c00 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 18 Aug 2025 10:47:06 +0100 Subject: [PATCH 141/183] fabric type to msd child fabric play --- roles/dtc/create/tasks/msd/vrfs_networks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/roles/dtc/create/tasks/msd/vrfs_networks.yml b/roles/dtc/create/tasks/msd/vrfs_networks.yml index 0fa048f12..1ef7b23d3 100644 --- a/roles/dtc/create/tasks/msd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/msd/vrfs_networks.yml @@ -105,6 +105,7 @@ - name: Manage NDFC Child Fabric VRFs cisco.nac_dc_vxlan.dtc.manage_child_fabric_vrfs: msite_data: "{{ MD_Multisite }}" + fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_vrf_results # -------------------------------------------------------------------- @@ -139,6 +140,7 @@ - name: Manage NDFC Child Fabric Networks cisco.nac_dc_vxlan.dtc.manage_child_fabric_networks: msite_data: "{{ MD_Multisite }}" + fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_network_results - ansible.builtin.set_fact: From b77c89b57cdf48c1b6e37794233f65ed53da7b21 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 18 Aug 2025 11:48:36 +0100 Subject: [PATCH 142/183] helper function update --- plugins/plugin_utils/helper_functions.py | 4 ++-- .../templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index 719b0d547..fa07bfe8a 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -254,10 +254,10 @@ def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): fabric_switches = [] for fabric_switch in fabric_response['response']: - if 'hostName' in fabric_switch: + if 'logicalName' in fabric_switch: fabric_switches.append( { - 'hostname': fabric_switch['hostName'], + 'hostname': fabric_switch['logicalName'], 'mgmt_ip_address': fabric_switch['ipAddress'] } ) diff --git a/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 index 8f0caf93d..10051a667 100644 --- a/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 +++ b/roles/dtc/common/templates/ndfc_networks/msd_fabric/msd_fabric_networks.j2 @@ -37,7 +37,7 @@ int_desc: {{ net['int_desc'] | default(defaults.vxlan.overlay.networks.net_description) }} mtu_l3intf: {{ net['mtu_l3intf'] | default(defaults.vxlan.overlay.networks.mtu_l3intf) }} route_target_both: {{ net['route_target_both'] | default(defaults.vxlan.overlay.networks.route_target_both) }} - route_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} + routing_tag: {{ net['route_tag'] | default(defaults.vxlan.overlay.networks.route_tag) }} {# ------------------------------------------------------ #} {# Attach Group Section #} {# ------------------------------------------------------ #} From 6360e41fb42b02fe9fb3d47f9d56f9cef955f862 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 21 Aug 2025 17:35:23 +0100 Subject: [PATCH 143/183] rules for external fabric --- plugins/action/common/nac_dc_validate.py | 4 +- roles/dtc/common/tasks/sub_main_external.yml | 6 + .../rules/external/204_global_bootstrap.py | 4 +- .../external/301_topology_switch_serial.py | 38 ++ .../302_topology_switch_management.py | 32 ++ .../external/303_topology_switch_role.py | 19 + ...pology_switch_interfaces_members_unique.py | 94 +++++ .../305_topology_switch_interfaces_vpc.py | 204 ++++++++++ .../external/306_topology_switch_vpc_peers.py | 73 ++++ .../307_topology_switch_preprovision.py | 38 ++ .../external/308_topology_switch_duplex.py | 78 ++++ .../309_topology_switch_vpc_orphan.py | 58 +++ ...310_topology_switch_interface_breakouts.py | 87 +++++ .../external/501_policy_cross_reference.py | 80 ++++ .../502_policy_vrf_lite_cross_reference.py | 369 ++++++++++++++++++ .../503_route_control_check_ipaddress.py | 178 +++++++++ .../505_policy_route_control_route_map.py | 353 +++++++++++++++++ .../files/rules/isn/204_global_bootstrap.py | 3 +- .../files/rules/vxlan/204_global_bootstrap.py | 3 +- 19 files changed, 1716 insertions(+), 5 deletions(-) create mode 100644 roles/validate/files/rules/external/301_topology_switch_serial.py create mode 100644 roles/validate/files/rules/external/302_topology_switch_management.py create mode 100644 roles/validate/files/rules/external/303_topology_switch_role.py create mode 100644 roles/validate/files/rules/external/304_topology_switch_interfaces_members_unique.py create mode 100644 roles/validate/files/rules/external/305_topology_switch_interfaces_vpc.py create mode 100644 roles/validate/files/rules/external/306_topology_switch_vpc_peers.py create mode 100644 roles/validate/files/rules/external/307_topology_switch_preprovision.py create mode 100644 roles/validate/files/rules/external/308_topology_switch_duplex.py create mode 100644 roles/validate/files/rules/external/309_topology_switch_vpc_orphan.py create mode 100644 roles/validate/files/rules/external/310_topology_switch_interface_breakouts.py create mode 100644 roles/validate/files/rules/external/501_policy_cross_reference.py create mode 100644 roles/validate/files/rules/external/502_policy_vrf_lite_cross_reference.py create mode 100644 roles/validate/files/rules/external/503_route_control_check_ipaddress.py create mode 100644 roles/validate/files/rules/external/505_policy_route_control_route_map.py diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 3e2eff7f4..1d674743e 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -121,8 +121,10 @@ def run(self, tmp=None, task_vars=None): rules_list.append(f'{rules}vxlan/') elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MFD'): rules_list.append(f'{rules}multisite/') - elif results['data']['vxlan']['global']['fabric_type'] in ('ISN', 'External'): + elif results['data']['vxlan']['global']['fabric_type'] in ('ISN'): rules_list.append(f'{rules}isn/') + elif results['data']['vxlan']['global']['fabric_type'] in ('External'): + rules_list.append(f'{rules}external/') else: results['failed'] = True results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['global']['fabric_type']} is not a supported fabric type." diff --git a/roles/dtc/common/tasks/sub_main_external.yml b/roles/dtc/common/tasks/sub_main_external.yml index d84ad02b7..b62e54f68 100644 --- a/roles/dtc/common/tasks/sub_main_external.yml +++ b/roles/dtc/common/tasks/sub_main_external.yml @@ -52,6 +52,11 @@ - name: Build NDFC Fabric Switch Inventory List From Template ansible.builtin.import_tasks: common/ndfc_inventory.yml +# We need to also build an inventory list without bootstrap settings +# This will be used for device removal. +- name: Build NDFC Fabric Switch Inventory List From Template - No Bootstrap + ansible.builtin.import_tasks: common/ndfc_inventory_no_bootstrap.yml + # -------------------------------------------------------------------- # Build vPC Peering parameter List From Template # -------------------------------------------------------------------- @@ -198,6 +203,7 @@ policy_config: "{{ policy_config }}" sub_interface_routed: "{{ sub_interface_routed }}" updated_inv_config: "{{ updated_inv_config }}" + updated_inv_config_no_bootstrap: "{{ updated_inv_config_no_bootstrap }}" vpc_peering: "{{ vpc_peering }}" - name: Run Diff Flags diff --git a/roles/validate/files/rules/external/204_global_bootstrap.py b/roles/validate/files/rules/external/204_global_bootstrap.py index 1c54549fb..6b4a02cec 100644 --- a/roles/validate/files/rules/external/204_global_bootstrap.py +++ b/roles/validate/files/rules/external/204_global_bootstrap.py @@ -12,8 +12,8 @@ def match(cls, inventory): check = cls.data_model_key_check(inventory, bootstrap_keys) if 'enable_bootstrap' in check['keys_found']: bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server'] - check = cls.data_model_key_check(inventory, bootstrap_keys) - if 'enable_local_dhcp_server' in check['keys_found']: + enable_local_dhcp_server = cls.safeget(inventory, ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server']) + if 'enable_local_dhcp_server' in check['keys_found'] and enable_local_dhcp_server: bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'dhcp_version'] check = cls.data_model_key_check(inventory, bootstrap_keys) if 'dhcp_version' in check['keys_found']: diff --git a/roles/validate/files/rules/external/301_topology_switch_serial.py b/roles/validate/files/rules/external/301_topology_switch_serial.py new file mode 100644 index 000000000..206f55fc1 --- /dev/null +++ b/roles/validate/files/rules/external/301_topology_switch_serial.py @@ -0,0 +1,38 @@ +class Rule: + id = "301" + description = "Verify a switch's serial number exists in the topology inventory" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + + check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches']) + if 'switches' in check['keys_data']: + switches = inventory.get("vxlan").get("topology").get("switches") + else: + return results + + for switch in switches: + if not switch.get("serial_number", False): + results.append( + f"vxlan.topology.switches.{switch['name']} serial number must be defined at least once in the topology inventory." + ) + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict diff --git a/roles/validate/files/rules/external/302_topology_switch_management.py b/roles/validate/files/rules/external/302_topology_switch_management.py new file mode 100644 index 000000000..7e5fc8593 --- /dev/null +++ b/roles/validate/files/rules/external/302_topology_switch_management.py @@ -0,0 +1,32 @@ +class Rule: + id = "302" + description = "Verify at least either a mgmt IPv4 or IPv6 address is configured" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + management_defined = [] + switches = [] + if inventory.get("vxlan", None): + if inventory["vxlan"].get("topology", None): + if inventory.get("vxlan").get("topology").get("switches", None): + switches = inventory.get("vxlan").get("topology").get("switches") + for switch in switches: + if not switch.get("management", False): + results.append( + f"vxlan.topology.switches.{switch['name']}.management must be defined" + ) + else: + management_defined.append(switch) + + for switch in management_defined: + if not ( + switch["management"].get("management_ipv4_address", False) + or switch["management"].get("management_ipv6_address", False) + ): + results.append( + f"vxlan.topology.switches.{switch['name']}.management " + f"must define either management_ipv4_address or management_ipv6_address" + ) + return results diff --git a/roles/validate/files/rules/external/303_topology_switch_role.py b/roles/validate/files/rules/external/303_topology_switch_role.py new file mode 100644 index 000000000..ceed3dd5e --- /dev/null +++ b/roles/validate/files/rules/external/303_topology_switch_role.py @@ -0,0 +1,19 @@ +class Rule: + id = "303" + description = "Verify switch role is defined" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + if inventory.get("vxlan", None): + if inventory["vxlan"].get("topology", None): + if inventory.get("vxlan").get("topology").get("switches", None): + switches = inventory.get("vxlan").get("topology").get("switches") + for switch in switches: + if not switch.get("role", False): + results.append( + f"vxlan.topology.switches.{switch['name']}.role must be defined" + ) + return results diff --git a/roles/validate/files/rules/external/304_topology_switch_interfaces_members_unique.py b/roles/validate/files/rules/external/304_topology_switch_interfaces_members_unique.py new file mode 100644 index 000000000..964f086b4 --- /dev/null +++ b/roles/validate/files/rules/external/304_topology_switch_interfaces_members_unique.py @@ -0,0 +1,94 @@ +import re + + +class Rule: + id = "304" + description = "\n1)Verify Interface names are Unique per switch\n2)Verify member interfaces are not repeated within a switch\n" + severity = "HIGH" + + # Check if interface names are unique per switch and member interfaces are not repeated within a switch + @classmethod + def match(cls, inventory): + results = [] + # Check if fabric topology switches are defined + switches = [] + if inventory.get("vxlan", None): + if inventory["vxlan"].get("topology", None): + if inventory.get("vxlan").get("topology").get("switches", None): + switches = inventory.get("vxlan").get("topology").get("switches") + for switch in switches: + # Check if interfaces are defined + if switch.get("interfaces"): + # Initialize lists to store interface names and member interface names + interface_names = [] + member_interface_names = [] + # Iterate through interfaces + for interface in switch.get("interfaces"): + # Normalize interface name + interface_name = cls.normalize_interface_name(interface.get("name")) + # Check if interface name is unique, by checking the list of interface names already parsed + if interface_name in interface_names: + # Append error message to results + results.append( + f"vxlan.topology.switches.{switch['name']}.interfaces.{interface_name}. " + "This interface is defined more than once within this switch. Duplicate encountered" + ) + # Append interface name to list of interface names if unique + else: + interface_names.append(interface_name) + # Check if member interfaces are defined + if interface.get("members"): + # Iterate through member interfaces + for member_interface in interface.get("members"): + # Normalize member interface name + member_interface_name = cls.normalize_interface_name( + member_interface + ) + # Check if member interface name is repeated within the switch, by checking the list of member interface names already parsed + if member_interface_name in member_interface_names: + # Append error message to results + results.append( + f"vxlan.topology.switches.{switch['name']}.interfaces.{interface_name}.members.{member_interface_name}. " + "This interface is defined as a member of more than one Port-channel interfaces" + ) + # Append member interface name to list of member interface names if unique + else: + member_interface_names.append(member_interface_name) + return results + + # Normalize interface name + @classmethod + def normalize_interface_name(cls, interface_name): + # Replace 'eth' or 'e' followed by digits with 'Ethernet' followed by the same digits + interface_name = re.sub( + r"(?i)^(?:e|eth(?:ernet)?)(\d(?:\/\d+){1,2})$", + r"Ethernet\1", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'Po' followed by digits with 'Port-channel' followed by the same digits + interface_name = re.sub( + r"(?i)^(po|port-channel)([1-9]|[1-9][0-9]{1,3}|[1-3][0-9]{3}|40([0-8][0-9]|9[0-6]))$", + r"Port-channel\2", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'eth' or 'e' followed by digits with 'Ethernet' followed by the same digits (for sub interface) + interface_name = re.sub( + r"(?i)^(?:e|eth(?:ernet)?)(\d(?:\/\d+){1,2}\.\d{1,4})$", + r"Ethernet\1", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'Lo' or 'Loopback' followed by digits with 'Loopback' followed by the same digits + interface_name = re.sub( + r"(?i)^(lo|loopback)([0-9]|[1-9][0-9]{1,2}|10[0-1][0-9]|102[0-3])$", + r"Loopback\2", + interface_name, + flags=re.IGNORECASE, + ) + + return interface_name diff --git a/roles/validate/files/rules/external/305_topology_switch_interfaces_vpc.py b/roles/validate/files/rules/external/305_topology_switch_interfaces_vpc.py new file mode 100644 index 000000000..5117a6b97 --- /dev/null +++ b/roles/validate/files/rules/external/305_topology_switch_interfaces_vpc.py @@ -0,0 +1,204 @@ +import re + + +class Rule: + id = "305" + description = ( + "Verify vPC interfaces are compliant with vPC configuration requirements" + ) + severity = "HIGH" + + # Check if vPC interfaces are compliant with vPC configuration requirements + @classmethod + def match(cls, inventory): + # initialize results list, vpc_interfaces_dict and vpc_interfaces_dict_parameters dictionaries, vpc_params_to_match list and vpc_peers_list + results = [] + vpc_interfaces_dict = {} + vpc_interfaces_dict_parameters = {} + vpc_params_to_match = [ + "mtu", + "speed", + "enabled", + "spanning_tree_portfast", + "pc_mode", + ] + vpc_peers_list = cls.get_vpc_peers(inventory) + # Check if fabric topology switches are defined + switches = [] + if inventory.get("vxlan", None): + if inventory["vxlan"].get("topology", None): + if inventory.get("vxlan").get("topology").get("switches", None): + switches = inventory.get("vxlan").get("topology").get("switches") + for switch in switches: + switch_name = switch["name"] + # Check if interfaces are defined + if switch.get("interfaces"): + vpc_ids = [] + # Iterate through interfaces + for interface in switch.get("interfaces"): + # Normalize interface name + interface_name = cls.normalize_interface_name(interface.get("name")) + # Check if vPC id is defined + if interface.get("vpc_id"): + vpc_id = interface.get("vpc_id") + # Check if vPC id is referenced by more than 1 Port-channel on the switch + if vpc_id in vpc_ids: + results.append( + f"vpc_id : {vpc_id} is referenced by more than 1 Port-channel on switch {switch_name}" + ) + else: + vpc_ids.append(vpc_id) + # create vpc_interfaces_dict in below format + # { + # "45": { + # "dc2-leaf2": "Port-channel33", + # "dc2-leaf1": "Port-channel33" + # }, + # "46": { + # "dc2-leaf2": "Port-channel34" + # }, + # "47": { + # "dc2-leaf2": "Port-channel35", + # "dc2-leaf1": "Port-channel35", + # "dc2-leaf3": "Port-channel35" + # } + # } + vpc_interfaces_dict[vpc_id] = vpc_interfaces_dict.get( + vpc_id, {} + ) + vpc_interfaces_dict[vpc_id][switch_name] = vpc_interfaces_dict[ + vpc_id + ].get(switch_name, "") + vpc_interfaces_dict[vpc_id][switch_name] = interface_name + # create vpc_interfaces_dict_parameters in below format + # { + # "45": { + # "interfaces": { + # "dc2-leaf2:Port-channel33": { + # "mtu": "default", + # "speed": "auto", + # "enabled": false, + # "spanning_tree_portfast": true, + # "pc_mode": "active" + # }, + # "dc2-leaf1:Port-channel33": { + # "mtu": "jumbo", + # "speed": null, + # "enabled": true, + # "spanning_tree_portfast": true, + # "pc_mode": "active" + # } + # } + # }, + # "46": { + # "interfaces": { + # "dc2-leaf2:Port-channel34": { + # "mtu": "default", + # "speed": "auto", + # "enabled": false, + # "spanning_tree_portfast": true, + # "pc_mode": "active" + # } + # } + # } + # } + vpc_interfaces_dict_parameters[ + vpc_id + ] = vpc_interfaces_dict_parameters.get(vpc_id, {}) + vpc_id_int = switch_name + ":" + interface_name + vpc_interfaces_dict_parameters[vpc_id][ + "interfaces" + ] = vpc_interfaces_dict_parameters[vpc_id].get("interfaces", {}) + vpc_interfaces_dict_parameters[vpc_id]["interfaces"][ + vpc_id_int + ] = vpc_interfaces_dict_parameters[vpc_id]["interfaces"].get( + vpc_id_int, {} + ) + for param in vpc_params_to_match: + vpc_interfaces_dict_parameters[vpc_id]["interfaces"][ + vpc_id_int + ][param] = interface.get(param) + + for vpc_id, switch_interfaces in vpc_interfaces_dict.items(): + # Check if vPC id is referenced by more than 2 switches + for pairs in vpc_peers_list: + switch_interfaces_pair = {} + for pair in pairs: + if pair in switch_interfaces: + switch_interfaces_pair.update({pair: switch_interfaces[pair]}) + + # Check if vPC id is only referenced by a single switch but must be referenced by both vPC peer switches + if len(switch_interfaces_pair) > 0 and len(switch_interfaces_pair) < 2: + results.append( + f"vpc_id : {vpc_id} is only referenced by a single switch {', '.join(switch_interfaces_pair.keys())} " + "but must be referenced by both vPC peer switches" + ) + + for vpc_id, interfaces in vpc_interfaces_dict_parameters.items(): + # Check if vPC interfaces have same values for parameters on vpc_params_to_match list + if len(interfaces["interfaces"]) == 2: + for param in vpc_params_to_match: + if ( + interfaces["interfaces"][ + list(interfaces["interfaces"].keys())[0] + ][param] + != interfaces["interfaces"][ + list(interfaces["interfaces"].keys())[1] + ][param] + ): + results.append( + f"vpc_id : {vpc_id} interfaces {', '.join(interfaces['interfaces'].keys())} have different {param} values" + ) + return results + + # Normalize interface name + @classmethod + def normalize_interface_name(cls, interface_name): + # Replace 'eth' or 'e' followed by digits with 'Ethernet' followed by the same digits + interface_name = re.sub( + r"(?i)^(?:e|eth(?:ernet)?)(\d(?:\/\d+){1,2})$", + r"Ethernet\1", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'Po' followed by digits with 'Port-channel' followed by the same digits + interface_name = re.sub( + r"(?i)^(po|port-channel)([1-9]|[1-9][0-9]{1,3}|[1-3][0-9]{3}|40([0-8][0-9]|9[0-6]))$", + r"Port-channel\2", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'eth' or 'e' followed by digits with 'Ethernet' followed by the same digits (for sub interface) + interface_name = re.sub( + r"(?i)^(?:e|eth(?:ernet)?)(\d(?:\/\d+){1,2}\.\d{1,4})$", + r"Ethernet\1", + interface_name, + flags=re.IGNORECASE, + ) + + # Replace 'Lo' or 'Loopback' followed by digits with 'Loopback' followed by the same digits + interface_name = re.sub( + r"(?i)^(lo|loopback)([0-9]|[1-9][0-9]{1,2}|10[0-1][0-9]|102[0-3])$", + r"Loopback\2", + interface_name, + flags=re.IGNORECASE, + ) + + return interface_name + + # Get vpc pairs from fabric topology vpc_peers + @classmethod + def get_vpc_peers(cls, inventory): + vpc_peers_list = [] + if inventory.get("vxlan", None): + if inventory["vxlan"].get("topology", None): + if inventory.get("vxlan").get("topology").get("vpc_peers", None): + for vpc_peers in ( + inventory.get("vxlan").get("topology").get("vpc_peers") + ): + vpc_peers_list.append( + sorted([vpc_peers.get("peer1"), vpc_peers.get("peer2")]) + ) + return vpc_peers_list diff --git a/roles/validate/files/rules/external/306_topology_switch_vpc_peers.py b/roles/validate/files/rules/external/306_topology_switch_vpc_peers.py new file mode 100644 index 000000000..d5b4f2a66 --- /dev/null +++ b/roles/validate/files/rules/external/306_topology_switch_vpc_peers.py @@ -0,0 +1,73 @@ +class Rule: + id = "306" + description = "Verify a vPC peer exists in the topology.switches inventory" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + vpc_peers_pairs = [] + + dm_check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches']) + if 'switches' in dm_check['keys_data']: + switches = inventory['vxlan']['topology']['switches'] + else: + return results + + # Set vpc_range with value in the data source or default "1-1000" + dm_check = cls.data_model_key_check(inventory, ['vxlan', 'global', 'vpc', 'domain_id_range']) + if 'domain_id_range' in dm_check['keys_data']: + vpc_range = inventory['vxlan']['global']['vpc']['domain_id_range'] + else: + vpc_range = "1-1000" + vpc_range_split = vpc_range.split("-") + vpc_domain_list = [] + + vpc_peers_keys = ['vxlan', 'topology', 'vpc_peers'] + dm_check = cls.data_model_key_check(inventory, vpc_peers_keys) + if 'vpc_peers' in dm_check['keys_found'] and 'vpc_peers' in dm_check['keys_data']: + vpc_peers_pairs = inventory['vxlan']['topology']['vpc_peers'] + for vpc_peers_pair in vpc_peers_pairs: + if any(sw['name'] == vpc_peers_pair['peer1'] for sw in switches): + pass + else: + results.append( + f"vxlan.topology.vpc_peers switch {vpc_peers_pair['peer1']} not found in the topology inventory." + ) + if any(sw['name'] == vpc_peers_pair['peer2'] for sw in switches): + pass + else: + results.append( + f"vxlan.topology.vpc_peers switch {vpc_peers_pair['peer2']} not found in the topology inventory." + ) + + # Check VPC Domain ID is in the range + if 'domain_id' in vpc_peers_pair: + if vpc_peers_pair['domain_id'] > int(vpc_range_split[1]) or vpc_peers_pair['domain_id'] < int(vpc_range_split[0]): + results.append( + f"vxlan.topology.vpc_peers Domain ID {vpc_peers_pair['domain_id']} between {vpc_peers_pair['peer1']} {vpc_peers_pair['peer2']} " + f"vpc domain not in range: " + vpc_range + "." + ) + + if vpc_peers_pair['domain_id'] not in vpc_domain_list: + vpc_domain_list.append(vpc_peers_pair['domain_id']) + else: + results.append( + f"vxlan.topology.vpc_peers Domain ID {vpc_peers_pair['domain_id']} is duplicated.") + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict diff --git a/roles/validate/files/rules/external/307_topology_switch_preprovision.py b/roles/validate/files/rules/external/307_topology_switch_preprovision.py new file mode 100644 index 000000000..2dcd9364d --- /dev/null +++ b/roles/validate/files/rules/external/307_topology_switch_preprovision.py @@ -0,0 +1,38 @@ +class Rule: + id = "307" + description = "Verify subnet is defined when preprovision is set" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + + dm_check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches']) + if 'switches' in dm_check['keys_data']: + switches = inventory['vxlan']['topology']['switches'] + + for switch in switches: + dm_check = cls.data_model_key_check(switch, ['poap', 'preprovision']) + if 'preprovision' in dm_check['keys_data']: + dm_check = cls.data_model_key_check(switch, ['management', 'subnet_mask_ipv4']) + if 'subnet_mask_ipv4' in dm_check['keys_not_found'] or 'subnet_mask_ipv4' in dm_check['keys_no_data']: + results.append( + f"vxlan.topology.switches.{switch['name']}.subnet_mask_ipv4 must be defined when preprovision is used." + ) + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict diff --git a/roles/validate/files/rules/external/308_topology_switch_duplex.py b/roles/validate/files/rules/external/308_topology_switch_duplex.py new file mode 100644 index 000000000..fff26af00 --- /dev/null +++ b/roles/validate/files/rules/external/308_topology_switch_duplex.py @@ -0,0 +1,78 @@ +class Rule: + id = "308" + description = "Verify duplex mode" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + + # Check for the 'switches' key in the data model + dm_check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches']) + if 'switches' in dm_check['keys_data']: + switches = inventory['vxlan']['topology']['switches'] + + # Iterate through switches and their interfaces + for switch in switches: + if switch.get("interfaces"): + for interface in switch["interfaces"]: + interface_name = interface.get('name') + + # Extract duplex and speed values + duplex = interface.get('duplex') + speed = interface.get('speed') + + # Condition 1: duplex is not supported without speed + # (EXCEPT when duplex is 'auto') + if duplex and duplex != 'auto' and not speed: + results.append( + f"vxlan.topology.switches.interfaces.{interface_name}.duplex " + "is not supported without speed" + ) + + # Condition 2: duplex: 'half' or 'full' is not supported if speed == 'auto' + if duplex in ['half', 'full'] and speed == 'auto': + results.append( + f"vxlan.topology.switches.interfaces.{interface_name}.duplex " + "'{duplex}' is not supported with speed 'auto'" + ) + + # Condition 3: duplex: 'half' is only supported with speed: '100mb' + if duplex == 'half' and speed != '100mb': + results.append( + f"vxlan.topology.switches.interfaces.{interface_name}.duplex 'half' " + "is only supported with speed '100mb'" + ) + + # Condition 4: duplex: 'auto' supports all speed values (or no speed at all) + if duplex == 'auto': + # No validation needed as all speed values (or absence of speed) + # are supported + continue + + # Condition 5: speed: 'auto' supports all duplex values (or no duplex at all) + if speed == 'auto': + # No validation needed as all speed values (or absence of speed) + # are supported + continue + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + """ + Helper method to check the presence of keys in a nested dictionary structure. + """ + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict diff --git a/roles/validate/files/rules/external/309_topology_switch_vpc_orphan.py b/roles/validate/files/rules/external/309_topology_switch_vpc_orphan.py new file mode 100644 index 000000000..910c54489 --- /dev/null +++ b/roles/validate/files/rules/external/309_topology_switch_vpc_orphan.py @@ -0,0 +1,58 @@ +class Rule: + id = "309" + description = "Verify orphan ports for non-VPC switches" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + + # Check for the 'switches' key in the data model + dm_check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches']) + if 'switches' in dm_check['keys_data']: + switches = inventory['vxlan']['topology']['switches'] + + # Extract all VPC peer switch names from vxlan.topology.vpc_peers + vpc_peers = set() + vpc_peers_check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'vpc_peers']) + if 'vpc_peers' in vpc_peers_check['keys_data']: + for peer in inventory['vxlan']['topology']['vpc_peers']: + vpc_peers.add(peer['peer1']) + vpc_peers.add(peer['peer2']) + + # Iterate through switches and their interfaces + for switch in switches: + switch_name = switch.get('name') + if switch.get("interfaces"): + for interface in switch["interfaces"]: + interface_name = interface.get('name') + + # Check if orphan_port is true + if interface.get('orphan_port', False): + # Fail if switch.name is not in vpc_peers + if switch_name not in vpc_peers: + results.append( + f"Switch '{switch_name}' with interface '{interface_name}' " + "has orphan_port: true, but the switch is not part of any VPC peer." + ) + + return results + + @classmethod + def data_model_key_check(cls, tested_object, keys): + """ + Helper method to check the presence of keys in a nested dictionary structure. + """ + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict diff --git a/roles/validate/files/rules/external/310_topology_switch_interface_breakouts.py b/roles/validate/files/rules/external/310_topology_switch_interface_breakouts.py new file mode 100644 index 000000000..2b32fd241 --- /dev/null +++ b/roles/validate/files/rules/external/310_topology_switch_interface_breakouts.py @@ -0,0 +1,87 @@ +class Rule: + id = "310" + description = "Verify if interfaces with sub-levels are part of the defined interface breakouts" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + # Reset results at the start of each call to avoid retaining previous results + results = [] + + # Extract switches from the inventory + switches = inventory.get("vxlan", {}).get("topology", {}).get("switches", []) + + # Process each switch + for switch in switches: + # Extract interface breakouts and interfaces + interface_breakouts = switch.get("interface_breakouts", []) + interfaces = switch.get("interfaces", []) + + # Check for invalid breakout configurations + for breakout in interface_breakouts: + if "to" in breakout and breakout["from"] > breakout["to"]: + results.append( + f"Invalid breakout configuration on vxlan.topology.switches." + f"{switch['name']}.interface_breakouts: " + f"'from' ({breakout['from']}) is greater than 'to' ({breakout['to']})" + ) + + # Check each interface + for interface in interfaces: + interface_name = interface.get("name", "") + normalized_interface = interface_name.lower().replace("ethernet", "e").replace("eth", "e") + + # Skip interfaces without sub-levels (e.g., E1/x) + if cls.has_sub_level(normalized_interface): + if not cls.is_interface_in_breakouts(normalized_interface, interface_breakouts): + results.append( + f"Interface {interface_name} on vxlan.topology.switches." + f"{switch['name']} is not part of the interface breakouts" + ) + + return results + + @staticmethod + def has_sub_level(interface_name): + """ + Check if an interface has a sub-level (e.g., E1/x/y). + + Parameters: + - interface_name (str): The interface name to check. + + Returns: + - bool: True if the interface has a sub-level, False otherwise. + """ + parts = interface_name.split("/") + return len(parts) == 3 # Check if the interface has exactly 3 parts (e.g., E1/x/y) + + @staticmethod + def is_interface_in_breakouts(interface_name, breakouts): + """ + Check if the given interface is part of the interface_breakouts. + + Parameters: + - interface_name (str): The interface name to check (e.g., e1/100/3, Eth1/99/3). + - breakouts (list): List of interface breakout definitions. + + Returns: + - bool: True if the interface is part of the breakouts, False otherwise. + """ + # Extract module and port details from the normalized interface name + try: + module, port, sub_level = interface_name.split("/") + port = int(port) # Convert port to an integer + except ValueError: + return False # If the interface name is invalid or port conversion fails, return False + + # Check each breakout definition + for breakout in breakouts: + # Ensure the 'from' value is less than or equal to the 'to' value + if breakout["module"] == int(module[1:]): # Compare module numbers + if "to" in breakout: # Range breakout + if breakout["from"] <= port <= breakout["to"]: + return True + elif breakout["from"] == port: # Single-port breakout + return True + + return False diff --git a/roles/validate/files/rules/external/501_policy_cross_reference.py b/roles/validate/files/rules/external/501_policy_cross_reference.py new file mode 100644 index 000000000..2a2619d91 --- /dev/null +++ b/roles/validate/files/rules/external/501_policy_cross_reference.py @@ -0,0 +1,80 @@ +class Rule: + id = "501" + description = "Verify Policy Cross Reference Between Policies, Groups, and Switches" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + policies = [] + groups = [] + topology_switches = [] + results = [] + + if inventory.get("vxlan", None): + if inventory["vxlan"].get("policy", None): + if inventory["vxlan"].get("policy").get("policies", None): + policies = inventory["vxlan"]["policy"]["policies"] + for policy in policies: + filename = policy.get("filename", None) + + if ((filename and policy.get("template_name", None) and policy.get("template_vars", None)) or + (filename and policy.get("template_vars", None))): + results.append( + "Policy definition filenames with .config or .cfg default template_name to NDFC freeform whereas " + "filenames with .yaml or .yml requires template_name to be defined per NDFC standards and " + "template_name and template_vars must not be defined together per NDFC standards." + ) + break + + if (filename and filename.endswith(('.config', '.cfg', '.yaml', '.yml'))) and policy.get("template_vars", None): + results.append( + f"Policy filename {filename} is of .config, .cfg, .yaml, or .yml extension. The template_vars parameter must not be defined." + ) + break + + if (filename and filename.endswith(('.yaml', '.yml'))) and not policy.get("template_name", None): + results.append( + f"Policy filename {filename} is of .yaml, or .yml extension. The template_name parameter must be defined." + ) + break + + if inventory["vxlan"].get("policy").get("groups", None): + groups = inventory["vxlan"]["policy"]["groups"] + for group in groups: + group_policies = group.get("policies", []) + for group_policy in group_policies: + if not any(policy['name'] == group_policy['name'] for policy in policies): + results.append( + f"Policy name {group_policy['name']} is defined in a group and must be defined in the policies section." + ) + break + + if inventory["vxlan"].get("policy").get("switches", None): + switches = inventory["vxlan"]["policy"]["switches"] + + if inventory.get("vxlan"): + if inventory["vxlan"].get("topology"): + if inventory.get("vxlan").get("topology").get("switches"): + topology_switches = inventory.get("vxlan").get("topology").get("switches") + for switch in switches: + if not ((any(topology_switch['name'] == switch['name'] for topology_switch in topology_switches)) or + (any(topology_switch['management'].get('management_ipv4_address', None) == switch['name'] + for topology_switch in topology_switches)) or + (any(topology_switch['management'].get('management_ipv6_address', None) == switch['name'] + for topology_switch in topology_switches))): + results.append( + f"Switch name {switch['name']} is defined and must be defined in the topology switches section." + ) + break + + switch_groups = switch.get("groups", []) + for switch_group in switch_groups: + for group in groups: + if not (any(group['name'] == switch_group for group in groups)): + results.append( + f"Policy group name {switch_group} is defined for switch {switch['name']} and " + "must be defined in the policy groups section." + ) + break + + return results diff --git a/roles/validate/files/rules/external/502_policy_vrf_lite_cross_reference.py b/roles/validate/files/rules/external/502_policy_vrf_lite_cross_reference.py new file mode 100644 index 000000000..52eee6d0a --- /dev/null +++ b/roles/validate/files/rules/external/502_policy_vrf_lite_cross_reference.py @@ -0,0 +1,369 @@ +""" +Validation Rules scenarios: +1. Switches in the vxlan.overlay_extensions.vrf_lites.switches should be defined in the vxlan.topology.switches +2. BGP and OSPF should be defined in two different policy. + vxlan.overlay_extensions.vrf_lites.ospf + vxlan.overlay_extensions.vrf_lites.bgp + vxlan.overlay_extensions.vrf_lites.switches.bgp + vxlan.overlay_extensions.vrf_lites.switches.bgp_peers + vxlan.overlay_extensions.vrf_lites.switches.interfaces.ospf +3. route_reflector_client for AF IPv4 and IPv6 config should not be allowed. + vxlan.overlay_extensions.vrf_lites.switches.bgp_peers.address_family_ipv4_unicast.route_reflector_client + vxlan.overlay_extensions.vrf_lites.switches.bgp_peers.address_family_ipv6_unicast.route_reflector_client +4. Check if OSPF Authentication is enabled, key must be provided + vxlan.overlay_extensions.vrf_lites.switches.interfaces.ospf.auth_key +5. Check AREA 0 is standard + vxlan.overlay_extensions.vrf_lites.ospf.areas.area_type +6. Check static routes across Policies + vxlan.overlay_extensions.vrf_lites.switches.static_routes +7. Check ospf network type for Loopback + vxlan.overlay_extensions.vrf_lites.switches.interfaces.ospf.network_type +""" + + +class Rule: + """ + Class 502 - Verify VRF-Lites Cross Reference Between Policies, Groups, and Switches + """ + + id = "502" + description = ( + "Verify VRF-Lites Cross Reference Between Policies, Groups, and Switches" + ) + severity = "HIGH" + results = [] + + @classmethod + def match(cls, data): + """ + function used by iac-validate + """ + vrf_lites = [] + topology_switches = [] + policies = [] + switch_policy = [] + static_routes_compliance = [] + + # Get fabric switches + if data.get("vxlan", {}).get("topology", {}).get("switches") is not None: + topology_switches = data["vxlan"]["topology"]["switches"] + + # Get vrf-lites policies + if data.get("vxlan", {}).get("overlay_extensions", {}).get("vrf_lites") is not None: + vrf_lites = data["vxlan"]["overlay_extensions"]["vrf_lites"] + + # Check Global Level + for policy in vrf_lites: + if policy.get("name", None): + policies.append(policy["name"]) + cls.check_global_ospf_process(policy) + cls.check_global_ospf_and_bgp(policy) + cls.check_global_ospf_area(policy) + # Check switch Level and update static_routes_compliance if exists + if policy.get("switches"): + for switch_policy in policy["switches"]: + cls.check_switch_level( + switch_policy, + policy, + data["vxlan"]["global"]["bgp_asn"], + topology_switches, + static_routes_compliance, + ) + cls.check_route_compliance_across_policies(static_routes_compliance) + + return cls.results + + @classmethod + def check_global_ospf_and_bgp(cls, policy): + """ + Check if OSPF and BGP is enabled in the global policy + """ + if {"ospf", "bgp"}.issubset(policy): + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy['name']}.ospf, " + f"vxlan.overlay_extensions.vrf_lites.{policy['name']}.bgp. " + "BGP and OSPF are defined in the same vrf-lite entry; " + "please use two different vrf-lite entries." + ) + + @classmethod + def check_global_ospf_process(cls, policy): + """ + Check OSPF Process + """ + if policy.get("ospf") and not policy["ospf"].get("process"): + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy['name']}.ospf.process. " + f"OSPF process is not defined." + ) + + @classmethod + def check_global_ospf_area(cls, policy): + """ + Check OSPF if backbone area is standard + """ + if policy.get("ospf") and not policy["ospf"].get("areas"): + for area in policy["ospf"]["areas"]: + if "id" in area and area.get("area_type"): + # Check if AREA 0 is not standard + if area["id"] in (0, "0.0.0.0") and area["area_type"] != "standard": + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy['name']}.ospf.areas.id.0. " + f"area_type is defined to {area['area_type']}. " + "Backbone area is always standard" + ) + elif area["area_type"] == "nssa": + cls.check_global_ospf_nssa(area, policy["name"]) + + @classmethod + def check_global_ospf_nssa(cls, area, policy): + """ + Check NSSA parameters + """ + if "nssa" in area: + if "translate" in area["nssa"]: + translate = area["nssa"]["translate"] + if "never" in translate and translate["never"] is True: + if ("supress_fa" in translate or "always" in translate) and ( + translate["supress_fa"] is True or translate["always"] is True + ): + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.ospf.areas.id.{area['id']}. " + f"NSSA translate type 7 never, cannot be enabled with always or supress" + ) + if "route_map" in area["nssa"] and ( + "default_information_originate" not in area["nssa"] + or area["nssa"]["default_information_originate"] is False + ): + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.ospf.areas.id.{area['id']}. " + f"route-map couldn't be used without default_information_originate" + ) + + @classmethod + def check_switch_level( + cls, + switch_policy, + policy, + infra_bgp_asn, + topology_switches, + static_routes_compliance, + ): + """ + Check switch level + """ + ospf = False + bgp = False + + # Check (bgp or bgp_peer) at the switch level + if "bgp" in switch_policy or "bgp_peers" in switch_policy: + bgp = True + if "bgp_peers" in switch_policy: + cls.check_switch_bgp_route_reflector( + switch=switch_policy["name"], + bgp_peers=switch_policy["bgp_peers"], + fabric_asn=infra_bgp_asn, + policy=policy["name"], + ) + + # Check OSPF at the switch level + if switch_policy.get("interfaces", None): + for interface in switch_policy["interfaces"]: + if interface.get("ospf"): + ospf = True + cls.check_switch_ospf( + interface["ospf"], + switch_policy["name"], + interface["name"], + policy["name"], + ) + + # Check if OSPF and BGP is enabled + if ospf is True and bgp is True: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy['name']}.switches.{switch_policy['name']}. " + "BGP and OSPF are configured in the same policy at the switch level. " + "Please use two different policies" + ) + + # Check if switch exists in topology + cls.check_switch_in_topology( + switch_policy["name"], topology_switches, policy["name"] + ) + + # Check Static routes + if "static_routes" in switch_policy: + static_routes_compliance.append( + { + "policy": policy["name"], + "vrf": policy["vrf"], + "switch": switch_policy["name"], + "prefix": switch_policy["static_routes"], + }) + + @classmethod + def check_switch_in_topology(cls, switch, topology_switches, policy): + """ + Check if switch is in the topology + """ + if list(filter(lambda topo: topo["name"] == switch, topology_switches)): + pass + else: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch} " + "is not defined in vxlan.topology.switches" + ) + + @classmethod + def check_switch_ospf(cls, ospf, switch, interface=None, policy=None): + """ + Check OSPF parameters + """ + # Check if key exists if authentication is enabled + if "auth_type" in ospf and ospf["auth_type"] is not None: + if "auth_key" not in ospf: + cls.results.append( + f"In the policy: {policy}, auth_type is {ospf['auth_type']} " + "but auth_key is missing" + ) + + # Check if Network type for Loopback interface is not Broadcast + if ospf.get("network_type"): + if (interface.startswith("Lo") or interface.startswith("lo")) and ospf[ + "network_type" + ] == "broadcast": + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch}.interfaces.{interface}.ospf. " + f"network_type: {ospf['network_type']}" + " is not supported with Loopback" + ) + + # Check if Adversise-subnet is used only for Loopback in ospf + if ospf.get("advertise_subnet"): + if ( + not (interface.startswith("Lo") or interface.startswith("lo")) + and ospf["advertise_subnet"] + ): + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch}.interfaces.{interface}.ospf. " + f"advertise_subnet: True is only supported with Loopback" + ) + + # Check if passive-interface is used only for Loopback in ospf + if ospf.get("passive_interface"): + if (interface.startswith("Lo") or interface.startswith("lo")) and ospf[ + "passive_interface" + ]: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch}.interfaces.{interface}.ospf. " + f"passive_interface: True is not supported with Loopback" + ) + + @classmethod + def check_switch_bgp_route_reflector(cls, switch, bgp_peers, fabric_asn, policy): + """ + Check if route-reflector is enabled in eBGP + """ + for bgp_peer in bgp_peers: + # Check RR for AF IPv4 + if bgp_peer.get("address_family_ipv4_unicast"): + if bgp_peer["address_family_ipv4_unicast"].get( + "route_reflector_client" + ): + if ( + bgp_peer["address_family_ipv4_unicast"][ + "route_reflector_client" + ] + is True + ): + if bgp_peer["remote_as"] != fabric_asn: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch}.bgp_peers.{bgp_peer['address']}.address_family_ipv4_unicast" + f"route_reflector_client: {bgp_peer['address_family_ipv4_unicast']['route_reflector_client']} " + "is not allowed in eBGP" + ) + + # Check RR for AF IPv6 + if bgp_peer.get("address_family_ipv6_unicast"): + if bgp_peer["address_family_ipv6_unicast"].get( + "route_reflector_client" + ): + if ( + bgp_peer["address_family_ipv6_unicast"][ + "route_reflector_client" + ] + is True + ): + if bgp_peer["remote_as"] != fabric_asn: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{policy}.switches.{switch}.bgp_peers.{bgp_peer['address']}.address_family_ipv6_unicast" + f"route_reflector_client: {bgp_peer['address_family_ipv6_unicast']['route_reflector_client']} " + "is not allowed in eBGP" + ) + + @classmethod + def check_route_compliance_across_policies(cls, routes): + """ + Check routes compliance across policies + """ + + def sort_prefixes_and_next_hops(data_input): + """ + Sort prefixes and next_hops + """ + for item in data_input: + # Sort static_ipv4 prefixes + if 'static_ipv4' in item['prefix']: + for static_ipv4_entry in item['prefix']['static_ipv4']: + # Sort next_hops by 'ip' + if "next_hops" in static_ipv4_entry: + static_ipv4_entry['next_hops'] = sorted( + static_ipv4_entry['next_hops'], + key=lambda x: x['ip'] + ) + else: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{item['policy']}.switches.{item['switch']}" + f".static_routes.static_ipv4.{static_ipv4_entry} " + f"next_hops is not defined." + ) + + # Sort static_ipv4 by 'prefix' + item['prefix']['static_ipv4'] = sorted( + item['prefix']['static_ipv4'], + key=lambda x: x['prefix'] + ) + # Sort static_ipv6 prefixes + if 'static_ipv6' in item['prefix']: + for static_ipv6_entry in item['prefix']['static_ipv6']: + # Sort next_hops by 'ip' + if "next_hops" in static_ipv6_entry: + static_ipv6_entry['next_hops'] = sorted( + static_ipv6_entry['next_hops'], + key=lambda x: x['ip'] + ) + else: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{item['policy']}.switches.{item['switch']}" + f".static_routes.static_ipv6.{static_ipv6_entry} " + f"next_hops is not defined." + ) + + # Sort static_ipv6 by 'prefix' + item['prefix']['static_ipv6'] = sorted( + item['prefix']['static_ipv6'], + key=lambda x: x['prefix'] + ) + + return data_input + + sorted_data = sort_prefixes_and_next_hops(routes) + + for data in sorted_data: + for data2 in sorted_data: + if data['vrf'] == data2['vrf'] and data['switch'] == data2['switch']: + if data['prefix'] != data2['prefix']: + cls.results.append( + f"vxlan.overlay_extensions.vrf_lites.{data['policy']} and vxlan.overlay_extensions.vrf_lites.{data2['policy']} " + f"use the same VRF and switch with different static routes" + ) diff --git a/roles/validate/files/rules/external/503_route_control_check_ipaddress.py b/roles/validate/files/rules/external/503_route_control_check_ipaddress.py new file mode 100644 index 000000000..17ff8e643 --- /dev/null +++ b/roles/validate/files/rules/external/503_route_control_check_ipaddress.py @@ -0,0 +1,178 @@ +"""Rule 503 to check IP format""" +import ipaddress +import re + + +class Rule: + """ + Class 503 - Verify IP address format for Route-Control + """ + + id = "503" + description = ( + "Verify IP address format for Route-Control" + ) + severity = "HIGH" + results = [] + + @classmethod + def match(cls, data): + """ + Matches and validates IP prefixes in the data based on provided keys and their entries. + """ + cls.validate_prefix_lists(data, "ipv4_prefix_lists", "IPv4") + cls.validate_prefix_lists(data, "ipv6_prefix_lists", "IPv6") + cls.validate_acls(data, "ipv4_access_lists", "IPv4") + cls.validate_acls(data, "ipv6_access_lists", "IPv6") + + return cls.results + + @classmethod + def validate_acls(cls, data, acls_key, address_family): + """ + Validates ACL entries for both 'source' and 'destination' host fields. + + :param data: The input data dictionary. + :param acls_key: The key for the ACLs (e.g., 'ipv4_acls' or 'ipv6_acls'). + :param address_family: The address family label (e.g., 'IPv4' or 'IPv6'). + """ + acls = cls.safeget(data, ["vxlan", "overlay_extensions", "route_control", acls_key]) + if acls: + for acl in acls: + if "entries" in acl: + for entry in acl["entries"]: + # Validate the 'source' field + cls.validate_host_field(acl["name"], entry, "source", address_family) + # Validate the 'destination' field + cls.validate_host_field(acl["name"], entry, "destination", address_family) + + @classmethod + def validate_host_field(cls, acl_name, entry, field, address_family): + """ + Validates the 'host' or 'ip' field in the given ACL entry for either + 'source' or 'destination'. + + :param acl_name: The name of the ACL being validated. + :param entry: The ACL entry dictionary. + :param field: The field to validate ('source' or 'destination'). + :param address_family: The address family label (e.g., 'IPv4' or 'IPv6'). + """ + if field not in entry: + return # Skip validation if the field is not present in the entry + + # Validate the 'host' field + cls._validate_host_field(acl_name, entry, field, address_family) + + # Validate the 'ip' field and handle wildcard configuration + cls._validate_ip_field(acl_name, entry, field, address_family) + + @classmethod + def _validate_host_field(cls, acl_name, entry, field, address_family): + """ + Validates the 'host' field in the ACL entry. + """ + host = entry[field].get("host") + if host: + # Valid IPv4 or IPv6 host regex + host_regex = r"^(?:\d{1,3}\.){3}\d{1,3}$|^[\da-fA-F:]+$" + + # Check if the host matches the expected regex + if not re.match(host_regex, host): + message = f"Invalid format. '{host}' must not include a CIDR prefix." + cls.results.append(f"In {address_family} ACL: {acl_name} {message}") + + @classmethod + def _validate_ip_field(cls, acl_name, entry, field, address_family): + """ + Validates the 'ip' field in the ACL entry and handles wildcard configuration. + """ + ip = entry[field].get("ip") + wildcard = entry[field].get("wildcard") + + if ip and wildcard: + # Valid IPv4 or IPv6 host regex + ip_regex = r"^(?:\d{1,3}\.){3}\d{1,3}$|^[\da-fA-F:]+$" + + # Check if the IP matches the expected regex + if not re.match(ip_regex, ip): + message = f"""Invalid format. '{ip + }' must not include a CIDR prefix when wildcard is configured.""" + cls.results.append(f"In {address_family} ACL: {acl_name} {message}") + + elif ip: + # Validate the IP as a CIDR if no wildcard is provided + is_valid, message = cls.is_ip_cidr(ip) + if not is_valid: + cls.results.append(f"""In {address_family} ACL: {acl_name} {message + } or use wildcard.""") + + @classmethod + def validate_prefix_lists(cls, data, prefix_list_key, address_family): + """ + Validates IPv4 or IPv6 prefix lists in the given data. + + :param data: The input data dictionary. + :param prefix_list_key: The key for the prefix list + (e.g., "ipv4_prefix_lists" or "ipv6_prefix_lists"). + :param address_family: The address family label (e.g., "IPv4" or "IPv6"). + """ + prefix_lists = cls.safeget(data, [ + "vxlan", "overlay_extensions", "route_control", prefix_list_key]) + if prefix_lists: + for prefix in prefix_lists: + if "entries" in prefix: + for entry in prefix["entries"]: + if "prefix" in entry: + is_valid, message = cls.is_ip_cidr(entry["prefix"]) + if not is_valid: + cls.results.append(f"""In {address_family + } Prefix-List: {prefix['name']} {message}""") + + @classmethod + def is_ip_cidr(cls, ip_cidr): + """ + Validates if the input string is a valid CIDR notation (IPv4/IPv6). + """ + # Regular expression for validating CIDR notation + cidr_regex = r"^(?:\d{1,3}\.){3}\d{1,3}/\d{1,2}$|^[\da-fA-F:]+/\d{1,3}$" + + # Check if the input matches the CIDR regex pattern + if not re.match(cidr_regex, ip_cidr): + return False, f"""Invalid format. '{ip_cidr + }' must include a CIDR prefix (e.g., /24 for IPv4 or /64 for IPv6)""" + + try: + # Check if it can be parsed as a valid IPv4 or IPv6 network + ipaddress.ip_network(ip_cidr, strict=True) + return True, f"'{ip_cidr}' is a valid IP address with CIDR prefix." + except ValueError as e: + return False, f"Invalid IP or CIDR: {e}" + + @classmethod + def data_model_key_check(cls, tested_object, keys): + """ + Checks for the presence of specific keys in the nested data model and categorizes them. + """ + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dictionary, keys): + """ + Safely retrieves nested values from a dictionary using a list of keys. + """ + for key in keys: + if dictionary is None or key not in dictionary: + return None + dictionary = dictionary[key] + return dictionary diff --git a/roles/validate/files/rules/external/505_policy_route_control_route_map.py b/roles/validate/files/rules/external/505_policy_route_control_route_map.py new file mode 100644 index 000000000..00894585c --- /dev/null +++ b/roles/validate/files/rules/external/505_policy_route_control_route_map.py @@ -0,0 +1,353 @@ +""" +Validation Rules scenarios: +1. Switches in the vxlan.overlay_extensions.route_control.switches should be defined in the vxlan.topology.switches +2. Groups in the vxlan.overlay_extensions.route_control.switches.group should be defined in the vxlan.overlay_extensions.route_control.groups +3. Route maps in the vxlan.overlay_extensions.route_control.groups.route_maps should be defined in the vxlan.overlay_extensions.route_control.route_maps +4. MAC list in vxlan.overlay_extensions.route_control.groups.mac_lists should be defined in vxlan.overlay_extensions.route_control.mac_lists +5. Standard community lists in the vxlan.overlay_extensions.route_control.groups.standard_community_lists should be defined in the + vxlan.overlay_extensions.route_control.standard_community_lists +6. Extended community lists in the vxlan.overlay_extensions.route_control.groups.extended_community_lists should be defined in the + vxlan.overlay_extensions.route_control.extended_community_lists +7. IPv4 prefix lists in the vxlan.overlay_extensions.route_control.groups.ipv4_prefix_lists should be defined in the + vxlan.overlay_extensions.route_control.ipv4_prefix_lists +8. IPv6 prefix lists in the vxlan.overlay_extensions.route_control.groups.ipv6_prefix_lists should be defined in the + vxlan.overlay_extensions.route_control.ipv6_prefix_lists +9. IPv4 access lists in the vxlan.overlay_extensions.route_control.groups.ipv4_access_lists should be defined in the + vxlan.overlay_extensions.route_control.ipv4_access_lists +10. Time ranges in the vxlan.overlay_extensions.route_control.groups.time_ranges should be defined in the vxlan.overlay_extensions.route_control.time_ranges +11. IPv4 object groups in the vxlan.overlay_extensions.route_control.groups.ipv4_object_groups should be defined in the + vxlan.overlay_extensions.route_control.ipv4_object_groups +12. IPv6 object groups in the vxlan.overlay_extensions.route_control.groups.ipv6_object_groups should be defined in the + vxlan.overlay_extensions.route_control.ipv6_object_groups. +13. Name for each of these policies should be unique when they are consumed in a group +14. Check if in the set_metric route map only metric bandwith is used or alternatively all the five metrics are used: bandwidth, delay, reliability, load, mtu +15. Check if in set ip/ipv6 next-hop verify-availability route map next-hops is configured +""" + + +class Rule: + """ + Class 505 - Verify Route-Control Cross Reference Integrity Between Policies, Groups, and Switches + """ + + id = "505" + description = ( + "Verify Route-Control Cross Reference Integrity Between Policies, Groups, and Switches" + ) + severity = "HIGH" + results = [] + + route_control_objects_names = ["ip_as_path_access_lists", "route_maps", + "mac_list", "standard_community_lists", "extended_community_lists", + "ipv4_access_lists", "ipv6_access_lists", + "ipv4_prefix_lists", "ipv6_prefix_lists", + "time_range", "ipv4_object_groups", "ipv6_object_groups" + ] + + @classmethod + def match(cls, data): + """ + function used by iac-validate + """ + route_control = {} + topology_switches = [] + switch_policy = [] + route_maps = [] + group_policies = [] + + # Get route_control policies + if data.get("vxlan", None): + if data["vxlan"].get("overlay_extensions", None): + if data["vxlan"].get("overlay_extensions").get("route_control", None): + route_control = data["vxlan"]["overlay_extensions"]["route_control"] + # Get groups policies + if data["vxlan"].get("overlay_extensions").get("route_control").get("groups", None): + group_policies = data["vxlan"]["overlay_extensions"]["route_control"]["groups"] + else: + # group is empty + return cls.results + else: + # route control is empty + return cls.results + + # Get fabric switches + if data.get("vxlan"): + if data["vxlan"].get("topology"): + if data.get("vxlan").get("topology").get("switches"): + topology_switches = ( + data.get("vxlan").get("topology").get("switches") + ) + + # Check switch Level + if route_control.get("switches"): + for switch_policy in route_control["switches"]: + cls.check_switch_level( + switch_policy, + topology_switches, + group_policies + ) + + # Check groups integrity + cls.check_groups( + group_policies, + route_control + ) + + # Check route maps integrity + rm_keys = ['overlay_extensions', 'route_control', 'route_maps'] + check = cls.data_model_key_check(data["vxlan"], rm_keys) + if 'route_maps' in check['keys_data']: + route_maps = data["vxlan"]["overlay_extensions"]["route_control"]["route_maps"] + cls.check_route_maps( + route_maps + ) + + return cls.results + + @classmethod + def check_switch_level( + cls, + switch_policy, + topology_switches, + group_policies + ): + """ + Check switch level + """ + + # Check if switch exists in topology + cls.check_switch_in_topology( + switch_policy["name"], topology_switches + ) + + # Check if group in switch is defined in route_control group + if switch_policy.get("groups"): + for switch_group in switch_policy["groups"]: + cls.check_group_in_switch( + switch_group, + group_policies + ) + + @classmethod + def check_switch_in_topology( + cls, + switch, + topology_switches + ): + """ + Check if switch is in the topology + """ + if list(filter(lambda topo: topo["name"] == switch, topology_switches)): + pass + else: + cls.results.append( + f"vxlan.overlay_extensions.route_control.switches.{switch} " + "is not defined in vxlan.topology.switches" + ) + + @classmethod + def check_group_in_switch( + cls, + switch_group, + group_policies + ): + """ + Check if group in switch is defined in route_control group + """ + if list(filter(lambda group: group["name"] == switch_group, group_policies)): + pass + else: + cls.results.append( + f"vxlan.overlay_extensions.route_control.switches.groups.{switch_group} " + "is not defined in vxlan.overlay_extensions.route_control.groups" + ) + + @classmethod + def validate_unique_names( + cls, + route_control_object, + label + ): + """ + Checks if route control object uses policy with unique name + """ + + # Track seen names + seen_names = set() + # Check for duplicates + for policy in route_control_object: + name = policy.get('name') + if name in seen_names: + cls.results.append( + "For vxlan.overlay_extensions.route_control." + label + name + " can be defined only one time") + seen_names.add(name) + + @classmethod + def validate_group_objects( + cls, + route_control_object, + policy_name, + route_control + ): + """ + Check if route_control_objects in group is defined in route_control + """ + for policy in route_control_object: + # The policy exist in the group. Check if exists under route control + if route_control.get(policy_name, None): + if list(filter(lambda group, policy=policy: group['name'] == policy['name'], route_control[policy_name])): + pass + else: + cls.results.append( + f"vxlan.overlay_extensions.route_control.switches.groups.{policy_name}.{policy['name']} " + f"is not defined in vxlan.overlay_extensions.route_control.{policy_name}" + ) + else: + cls.results.append( + f"vxlan.overlay_extensions.route_control.groups.{policy_name} " + "is not defined in vxlan.overlay_extensions.route_control" + ) + + @classmethod + def check_groups( + cls, + group_policies, + route_control + ): + """ + Check group policy integrity + """ + for switch in group_policies: + for policy_name in cls.route_control_objects_names: + if switch.get(policy_name, None): + # Check uniquiness of route_control_object whitin a group + route_control_object = switch.get(policy_name) + cls.validate_unique_names( + route_control_object, + "groups." + switch["name"] + "." + policy_name + ".", + ) + + # Check if route_control_object in group is defined in route_control + cls.validate_group_objects( + route_control_object, + policy_name, + route_control + ) + + @classmethod + def check_route_maps( + cls, + route_maps + ): + """ + Check if route_maps integrity + """ + # Check route maps + for route_map in route_maps: + if route_map.get("entries", None): + # Check set metric integrity + cls.check_route_maps_entries( + route_map["entries"] + ) + + @classmethod + def check_route_maps_entries( + cls, + entries + ): + """ + Check if route_maps entries integrity + """ + + # Check route maps entries + for seq_numer in entries: + if seq_numer.get("set", None): + for rm_set in seq_numer["set"]: + # Check set metric integrity + cls.check_set_metric_integrity( + rm_set + ) + + # Check set metric integrity + cls.check_set_next_hop_verify_availability( + rm_set + ) + + @classmethod + def check_set_next_hop_verify_availability( + cls, + rm_set, + ): + """ + Check if in the set_next_hop_verify_availability route map has next-hop ip defined + """ + if rm_set.get("ipv4"): + set_ip = rm_set["ipv4"] + if 'next_hop' in set_ip: + if 'verify_availability' in set_ip["next_hop"]: + if set_ip["next_hop"]['verify_availability']: + # Ip address should be defined in verify_availability + if 'address' not in set_ip["next_hop"]: + cls.results.append( + "For vxlan.overlay_extensions.route_control.route_maps.entries.set.ipv4.next_hop.verify_availability to be used, " + + "ipv4 address should be configured" + ) + if rm_set.get("ipv6"): + set_ip = rm_set["ipv6"] + if 'next_hop' in set_ip: + if 'verify_availability' in set_ip["next_hop"]: + if set_ip["next_hop"]['verify_availability']: + # Ip address should be defined in verify_availability + if 'address' not in set_ip["next_hop"]: + cls.results.append( + "For vxlan.overlay_extensions.route_control.route_maps.entries.set.ipv6.next_hop.verify_availability to be used, " + + "ipv6 address should be configured" + ) + + @classmethod + def check_set_metric_integrity( + cls, + rm_set + ): + """ + Check if in the set_metric route map if we use metric bandwith or all the five metrics: bandwidth, delay, reliability, load, mtu + """ + if rm_set.get("metric", None): + set_metric = rm_set["metric"] + metrics = ['bandwidth', 'delay', 'reliability', 'load', 'mtu'] + if 'bandwidth' in set_metric and len(set_metric) == 1: + pass + else: + for metric in metrics: + if metric not in set_metric: + cls.results.append( + "For vxlan.overlay_extensions.route_control.route_maps.entries.set.metric to be enabled, " + + metric + " should be set in the metric.") + + @classmethod + def data_model_key_check(cls, tested_object, keys): + dm_key_dict = {'keys_found': [], 'keys_not_found': [], 'keys_data': [], 'keys_no_data': []} + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict + + @classmethod + def safeget(cls, dict, keys): + # Utility function to safely get nested dictionary values + for key in keys: + if dict is None: + return None + if key in dict: + dict = dict[key] + else: + return None + + return dict diff --git a/roles/validate/files/rules/isn/204_global_bootstrap.py b/roles/validate/files/rules/isn/204_global_bootstrap.py index 2f36545a1..7e9adcef0 100644 --- a/roles/validate/files/rules/isn/204_global_bootstrap.py +++ b/roles/validate/files/rules/isn/204_global_bootstrap.py @@ -13,7 +13,8 @@ def match(cls, inventory): if 'enable_bootstrap' in check['keys_found']: bootstrap_keys = ['vxlan', 'multisite', 'isn', 'bootstrap', 'enable_local_dhcp_server'] check = cls.data_model_key_check(inventory, bootstrap_keys) - if 'enable_local_dhcp_server' in check['keys_found']: + enable_local_dhcp_server = cls.safeget(inventory, ['vxlan', 'multisite', 'isn', 'bootstrap', 'enable_local_dhcp_server']) + if 'enable_local_dhcp_server' in check['keys_found'] and enable_local_dhcp_server: bootstrap_keys = ['vxlan', 'multisite', 'isn', 'bootstrap', 'dhcp_version'] check = cls.data_model_key_check(inventory, bootstrap_keys) if 'dhcp_version' in check['keys_found']: diff --git a/roles/validate/files/rules/vxlan/204_global_bootstrap.py b/roles/validate/files/rules/vxlan/204_global_bootstrap.py index 78196e94e..e5d9b0a48 100644 --- a/roles/validate/files/rules/vxlan/204_global_bootstrap.py +++ b/roles/validate/files/rules/vxlan/204_global_bootstrap.py @@ -13,7 +13,8 @@ def match(cls, inventory): if 'enable_bootstrap' in check['keys_found']: bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server'] check = cls.data_model_key_check(inventory, bootstrap_keys) - if 'enable_local_dhcp_server' in check['keys_found']: + enable_local_dhcp_server = cls.safeget(inventory, ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server']) + if 'enable_local_dhcp_server' in check['keys_found'] and enable_local_dhcp_server: bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'dhcp_version'] check = cls.data_model_key_check(inventory, bootstrap_keys) if 'dhcp_version' in check['keys_found']: From 0af05513acbd9aa7bf611037e1e38185946157b4 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 26 Aug 2025 12:59:15 +0100 Subject: [PATCH 144/183] Added files related to vpc_external fixes --- .../ndfc_vpc_peering_pairs_external.j2 | 34 ++-- roles/validate/files/defaults.yml | 1 + ...logy_switch_vpc_portchannel_consistency.py | 172 ++++++++++++++++++ 3 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 index 18f3dde7e..425350ba9 100644 --- a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -8,28 +8,38 @@ peerTwoId: {{ vpc_peers_pair.peer2_mgmt_ip_address }} templateName: "vpc_pair" profile: - ADMIN_STATE: {{ vpc_peers_pair.enabled }} - ALLOWED_VLANS: "{{ vpc_peers_pair.trunk_allowed_vlans }}" DOMAIN_ID: {{ vpc_peers_pair.domain_id }} FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} KEEP_ALIVE_HOLD_TIMEOUT: {{ vpc_peers_pair.keepalive_holdout_time | default(defaults.vxlan.topology.vpc_peers.keepalive_holdout_time) }} KEEP_ALIVE_VRF: {{ vpc_peers_pair.keepalive_vrfname }} - PC_MODE: {{ vpc_peers_pair.port_channel_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} PEER1_DOMAIN_CONF: |2- {{ vpc_peers_pair.peer1_domain_conf | default('') | indent(6, false) }} PEER1_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer1_keepalive_ipv4 }} - PEER1_PO_DESC: "{{ vpc_peers_pair.peer1_po_channel_desc | default('') }}" PEER2_DOMAIN_CONF: |2- {{ vpc_peers_pair.peer2_domain_conf | default('') | indent(6, false)}} PEER2_KEEP_ALIVE_LOCAL_IP: {{ vpc_peers_pair.peer2_keepalive_ipv4 }} +{% set peer1_switch = MD_Extended.vxlan.topology.switches | selectattr('name', 'equalto', vpc_peers_pair.peer1) | first %} +{% set peer2_switch = MD_Extended.vxlan.topology.switches | selectattr('name', 'equalto', vpc_peers_pair.peer2) | first %} +{% if peer1_switch.interfaces is defined %} +{% set peer1_vpc_interface = peer1_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_pair') | first | default({}) %} +{% endif %} +{% if peer2_switch.interfaces is defined %} +{% set peer2_vpc_interface = peer2_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_pair') | first | default({}) %} +{% endif %} +{% if peer1_vpc_interface.name is defined %} PEER1_PO_CONF: |2- - {{ vpc_peers_pair.peer1_po_channel_conf | default('') | indent(6, false) }} - PEER2_PO_CONF: |2- - {{ vpc_peers_pair.peer2_po_channel_conf | default('') | indent(6, false) }} - PEER2_PO_DESC: "{{ vpc_peers_pair.peer2_po_channel_desc | default('') }}" - PEER1_PCID: {{ vpc_peers_pair.peer1_po_channel_id | default(defaults.vxlan.topology.vpc_peers.peer1_po_channel_id) }} - PEER2_PCID: {{ vpc_peers_pair.peer2_po_channel_id | default(defaults.vxlan.topology.vpc_peers.peer2_po_channel_id) }} - PEER1_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer1_member_interfaces | default([]) | join(',') }}" - PEER2_MEMBER_INTERFACES: "{{ vpc_peers_pair.peer2_member_interfaces | default([]) | join(',') }}" + {{ peer1_vpc_interface.freeform_config | default('') | indent(6, false) }} + PEER2_PO_CONF: |2- + {{ peer2_vpc_interface.freeform_config | default('') | indent(6, false) }} + PC_MODE: {{ peer1_vpc_interface.pc_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} + PEER1_PO_DESC: "{{ peer1_vpc_interface.description | default('') }}" + PEER2_PO_DESC: "{{ peer2_vpc_interface.description | default('') }}" + PEER1_PCID: {{ peer1_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default(defaults.vxlan.topology.vpc_peers.peer1_po_channel_id) }} + PEER2_PCID: {{ peer2_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default(defaults.vxlan.topology.vpc_peers.peer2_po_channel_id) }} + PEER1_MEMBER_INTERFACES: "{{ peer1_vpc_interface.members | default([]) | join(',') }}" + PEER2_MEMBER_INTERFACES: "{{ peer2_vpc_interface.members | default([]) | join(',') }}" + ALLOWED_VLANS: "{{ peer1_vpc_interface.trunk_allowed_vlans | default(defaults.vxlan.topology.vpc_peers.trunk_allowed_vlans) }}" + ADMIN_STATE: {{ peer1_vpc_interface.enabled }} +{% endif %} {% endfor %} {% endif %} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 2001569cc..4da62c923 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -158,6 +158,7 @@ factory_defaults: domain_id: 1 keepalive_holdout_time: 3 port_channel_mode: active + trunk_allowed_vlans: all peer1_po_channel_id: 500 peer2_po_channel_id: 500 fabric_links: diff --git a/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py b/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py new file mode 100644 index 000000000..482806733 --- /dev/null +++ b/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py @@ -0,0 +1,172 @@ +class Rule: + id = "311" + description = "Verify VPC port-channel consistency between peer switches" + severity = "HIGH" + + @classmethod + def match(cls, inventory): + results = [] + switches = [] + + # Check for the 'switches' key in the data model + dm_check = cls.data_model_key_check( + inventory, ['vxlan', 'topology', 'switches'] + ) + if 'switches' in dm_check['keys_data']: + switches = inventory['vxlan']['topology']['switches'] + + # Check for VPC peers + vpc_peers_check = cls.data_model_key_check( + inventory, ['vxlan', 'topology', 'vpc_peers'] + ) + if 'vpc_peers' not in vpc_peers_check['keys_data']: + return results # No VPC peers defined, nothing to validate + + vpc_peers = inventory['vxlan']['topology']['vpc_peers'] + + # Create a lookup dictionary for switches by name + switch_lookup = {switch.get('name'): switch for switch in switches} + + # Iterate through VPC peer pairs + for vpc_pair in vpc_peers: + peer1_name = vpc_pair.get('peer1') + peer2_name = vpc_pair.get('peer2') + domain_id = vpc_pair.get('domain_id') + + peer1_switch = switch_lookup.get(peer1_name) + peer2_switch = switch_lookup.get(peer2_name) + + if not peer1_switch or not peer2_switch: + continue # Skip if switches not found + + # Find VPC port-channels on each switch + peer1_vpc_channels = cls.find_vpc_port_channels(peer1_switch) + peer2_vpc_channels = cls.find_vpc_port_channels(peer2_switch) + + # Check if one peer has VPC port-channels but the other doesn't + if peer1_vpc_channels and not peer2_vpc_channels: + pc_names = [pc['name'] for pc in peer1_vpc_channels] + results.append( + f"VPC pair (domain {domain_id}): Switch '{peer1_name}' " + f"has VPC port-channel(s) {pc_names}, but peer switch " + f"'{peer2_name}' has no VPC port-channels defined." + ) + elif peer2_vpc_channels and not peer1_vpc_channels: + pc_names = [pc['name'] for pc in peer2_vpc_channels] + results.append( + f"VPC pair (domain {domain_id}): Switch '{peer2_name}' " + f"has VPC port-channel(s) {pc_names}, but peer switch " + f"'{peer1_name}' has no VPC port-channels defined." + ) + elif peer1_vpc_channels and peer2_vpc_channels: + # Both peers have VPC port-channels, validate they match + results.extend(cls.validate_vpc_channel_consistency( + peer1_name, peer1_vpc_channels, peer2_name, + peer2_vpc_channels, domain_id + )) + + return results + + @classmethod + def find_vpc_port_channels(cls, switch): + """Find all port-channels with mode 'vpc_pair' on a switch""" + vpc_channels = [] + if switch.get('interfaces'): + for interface in switch['interfaces']: + interface_name = interface.get('name', '') + is_pc = (interface_name.startswith('port-channel') or + interface_name.startswith('po')) + if is_pc and interface.get('mode') == 'vpc_pair': + vpc_channels.append(interface) + return vpc_channels + + @classmethod + def validate_vpc_channel_consistency(cls, peer1_name, peer1_channels, + peer2_name, peer2_channels, + domain_id): + """Validate that VPC port-channels are consistent between peers""" + results = [] + + # Check if the number of VPC port-channels match + if len(peer1_channels) != len(peer2_channels): + results.append( + f"VPC pair (domain {domain_id}): Mismatch in number of " + f"VPC port-channels - '{peer1_name}' has " + f"{len(peer1_channels)}, '{peer2_name}' has " + f"{len(peer2_channels)}" + ) + return results + + # Sort channels by port-channel ID for comparison + def get_pc_id(interface): + return cls.extract_pc_id(interface.get('name', '')) + + peer1_sorted = sorted(peer1_channels, key=get_pc_id) + peer2_sorted = sorted(peer2_channels, key=get_pc_id) + + # Compare each pair of port-channels + for peer1_pc, peer2_pc in zip(peer1_sorted, peer2_sorted): + peer1_pc_id = cls.extract_pc_id(peer1_pc.get('name', '')) + peer2_pc_id = cls.extract_pc_id(peer2_pc.get('name', '')) + + # Check if port-channel IDs match + if peer1_pc_id != peer2_pc_id: + results.append( + f"VPC pair (domain {domain_id}): Port-channel ID " + f"mismatch - '{peer1_name}' has " + f"'{peer1_pc.get('name')}', '{peer2_name}' has " + f"'{peer2_pc.get('name')}'" + ) + + # Check if pc_mode matches (if defined on both) + peer1_pc_mode = peer1_pc.get('pc_mode') + peer2_pc_mode = peer2_pc.get('pc_mode') + if (peer1_pc_mode and peer2_pc_mode and + peer1_pc_mode != peer2_pc_mode): + results.append( + f"VPC pair (domain {domain_id}): Port-channel mode " + f"mismatch on PC{peer1_pc_id} - '{peer1_name}' has " + f"'{peer1_pc_mode}', '{peer2_name}' has " + f"'{peer2_pc_mode}'" + ) + + # Check if trunk_allowed_vlans matches (if defined on both) + peer1_vlans = peer1_pc.get('trunk_allowed_vlans') + peer2_vlans = peer2_pc.get('trunk_allowed_vlans') + if peer1_vlans and peer2_vlans and peer1_vlans != peer2_vlans: + results.append( + f"VPC pair (domain {domain_id}): VLAN configuration " + f"mismatch on PC{peer1_pc_id} - '{peer1_name}' allows " + f"'{peer1_vlans}', '{peer2_name}' allows " + f"'{peer2_vlans}'" + ) + + return results + + @classmethod + def extract_pc_id(cls, interface_name): + """Extract port-channel ID from interface name""" + import re + match = re.search(r'(?:port-channel|po)(\d+)', interface_name.lower()) + return int(match.group(1)) if match else 0 + + @classmethod + def data_model_key_check(cls, tested_object, keys): + """ + Helper method to check the presence of keys in a nested dictionary. + """ + dm_key_dict = { + 'keys_found': [], 'keys_not_found': [], + 'keys_data': [], 'keys_no_data': [] + } + for key in keys: + if tested_object and key in tested_object: + dm_key_dict['keys_found'].append(key) + tested_object = tested_object[key] + if tested_object: + dm_key_dict['keys_data'].append(key) + else: + dm_key_dict['keys_no_data'].append(key) + else: + dm_key_dict['keys_not_found'].append(key) + return dm_key_dict From a79f5e1e668c19bdb5c721e7c02240d56602d053 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 26 Aug 2025 13:11:47 +0100 Subject: [PATCH 145/183] external fabric vpc rule --- .../external/310_topology_switch_vpc_portchannel_consistency.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py diff --git a/roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py b/roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py new file mode 100644 index 000000000..e69de29bb From 3a85faec99bace73a6803432c77088695319a810 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 26 Aug 2025 13:51:25 +0100 Subject: [PATCH 146/183] delete duplicate rule --- .../external/310_topology_switch_vpc_portchannel_consistency.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py diff --git a/roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py b/roles/validate/files/rules/external/310_topology_switch_vpc_portchannel_consistency.py deleted file mode 100644 index e69de29bb..000000000 From ac59cc4ef666a7e7399eb0ef00e9ee0d9b891bcd Mon Sep 17 00:00:00 2001 From: Matt Thurston Date: Thu, 28 Aug 2025 15:17:57 +0100 Subject: [PATCH 147/183] Update vrfs_networks.yml --- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 7b87d7977..1d67d4bc6 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -102,6 +102,7 @@ - name: Manage NDFC Child Fabric VRFs cisco.nac_dc_vxlan.dtc.manage_child_fabric_vrfs: + nd_version: "{{ nd_version }}" msite_data: "{{ MD_Multisite }}" fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_vrf_results @@ -186,6 +187,7 @@ - name: Manage NDFC Child Fabric Networks cisco.nac_dc_vxlan.dtc.manage_child_fabric_networks: + nd_version: "{{ nd_version }}" msite_data: "{{ MD_Multisite }}" fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_network_results From dd4cabfc943ce1d6502beb5a0249f1f089f9c59b Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 2 Sep 2025 11:07:29 +0100 Subject: [PATCH 148/183] external VPC changes --- .../ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 | 14 +++++++------- roles/validate/files/defaults.yml | 4 ---- ..._topology_switch_vpc_portchannel_consistency.py | 8 ++++---- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 index 425350ba9..6c0b6ea6a 100644 --- a/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 +++ b/roles/dtc/common/templates/ndfc_vpc/ndfc_vpc_peering_pairs_external.j2 @@ -21,25 +21,25 @@ {% set peer1_switch = MD_Extended.vxlan.topology.switches | selectattr('name', 'equalto', vpc_peers_pair.peer1) | first %} {% set peer2_switch = MD_Extended.vxlan.topology.switches | selectattr('name', 'equalto', vpc_peers_pair.peer2) | first %} {% if peer1_switch.interfaces is defined %} -{% set peer1_vpc_interface = peer1_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_pair') | first | default({}) %} +{% set peer1_vpc_interface = peer1_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_peer_link') | first | default({}) %} {% endif %} {% if peer2_switch.interfaces is defined %} -{% set peer2_vpc_interface = peer2_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_pair') | first | default({}) %} +{% set peer2_vpc_interface = peer2_switch.interfaces | selectattr('name', 'match', '^(port-channel|po)') | selectattr('mode', 'equalto', 'vpc_peer_link') | first | default({}) %} {% endif %} {% if peer1_vpc_interface.name is defined %} PEER1_PO_CONF: |2- {{ peer1_vpc_interface.freeform_config | default('') | indent(6, false) }} PEER2_PO_CONF: |2- {{ peer2_vpc_interface.freeform_config | default('') | indent(6, false) }} - PC_MODE: {{ peer1_vpc_interface.pc_mode | default(defaults.vxlan.topology.vpc_peers.port_channel_mode) }} + PC_MODE: {{ peer1_vpc_interface.pc_mode | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.pc_mode)}} PEER1_PO_DESC: "{{ peer1_vpc_interface.description | default('') }}" PEER2_PO_DESC: "{{ peer2_vpc_interface.description | default('') }}" - PEER1_PCID: {{ peer1_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default(defaults.vxlan.topology.vpc_peers.peer1_po_channel_id) }} - PEER2_PCID: {{ peer2_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default(defaults.vxlan.topology.vpc_peers.peer2_po_channel_id) }} + PEER1_PCID: {{ peer1_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default('') }} + PEER2_PCID: {{ peer2_vpc_interface.name | default('') | regex_replace('^(port-channel|po)', '') | default('') }} PEER1_MEMBER_INTERFACES: "{{ peer1_vpc_interface.members | default([]) | join(',') }}" PEER2_MEMBER_INTERFACES: "{{ peer2_vpc_interface.members | default([]) | join(',') }}" - ALLOWED_VLANS: "{{ peer1_vpc_interface.trunk_allowed_vlans | default(defaults.vxlan.topology.vpc_peers.trunk_allowed_vlans) }}" - ADMIN_STATE: {{ peer1_vpc_interface.enabled }} + ALLOWED_VLANS: "{{ peer1_vpc_interface.trunk_allowed_vlans | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.trunk_allowed_vlans) }}" + ADMIN_STATE: {{ peer1_vpc_interface.enabled | default(defaults.vxlan.topology.switches.interfaces.topology_switch_trunk_po_interface.enabled)}} {% endif %} {% endfor %} {% endif %} diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index b2bcc9fff..3d162d065 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -167,10 +167,6 @@ factory_defaults: vpc_peers: domain_id: 1 keepalive_holdout_time: 3 - port_channel_mode: active - trunk_allowed_vlans: all - peer1_po_channel_id: 500 - peer2_po_channel_id: 500 fabric_links: mtu: 9216 admin_state: true diff --git a/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py b/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py index 482806733..a38650fc9 100644 --- a/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py +++ b/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py @@ -69,14 +69,14 @@ def match(cls, inventory): @classmethod def find_vpc_port_channels(cls, switch): - """Find all port-channels with mode 'vpc_pair' on a switch""" + """Find all port-channels with mode 'vpc_peer_link' on a switch""" vpc_channels = [] if switch.get('interfaces'): for interface in switch['interfaces']: interface_name = interface.get('name', '') is_pc = (interface_name.startswith('port-channel') or interface_name.startswith('po')) - if is_pc and interface.get('mode') == 'vpc_pair': + if is_pc and interface.get('mode') == 'vpc_peer_link': vpc_channels.append(interface) return vpc_channels @@ -86,7 +86,7 @@ def validate_vpc_channel_consistency(cls, peer1_name, peer1_channels, domain_id): """Validate that VPC port-channels are consistent between peers""" results = [] - + # Check if the number of VPC port-channels match if len(peer1_channels) != len(peer2_channels): results.append( @@ -100,7 +100,7 @@ def validate_vpc_channel_consistency(cls, peer1_name, peer1_channels, # Sort channels by port-channel ID for comparison def get_pc_id(interface): return cls.extract_pc_id(interface.get('name', '')) - + peer1_sorted = sorted(peer1_channels, key=get_pc_id) peer2_sorted = sorted(peer2_channels, key=get_pc_id) From c4d65a8ca43abdcb59ddac554e71cee369d35924 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Wed, 3 Sep 2025 09:56:24 +0100 Subject: [PATCH 149/183] Refactor to remove loopbacks loop and standardise formatting --- .../action/dtc/manage_child_fabric_vrfs.py | 1 - roles/common_global/vars/main.yml | 2 +- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 31 +++- roles/dtc/common/tasks/mfd/ndfc_vrfs.yml | 40 +++-- roles/dtc/common/tasks/sub_main_mfd.yml | 10 +- .../common/templates/ndfc_attach_networks.j2 | 7 +- .../dtc/common/templates/ndfc_attach_vrfs.j2 | 7 +- .../mfd_fabric/ndfc_attach_networks.j2} | 0 .../ndfc_attach_networks_switches.j2} | 0 .../ndfc_attach_networks_switches_ports.j2} | 0 .../mfd_fabric/ndfc_attach_vrfs.j2} | 1 - .../mfd_fabric/ndfc_attach_vrfs_loopbacks.j2} | 11 +- .../create/tasks/mfd/network_fed_config.yml | 5 +- roles/dtc/create/tasks/mfd/vrf_fed_config.yml | 14 +- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 138 ++++++++++-------- roles/dtc/create/tasks/sub_main_mfd.yml | 8 +- .../dtc/create/tasks/vxlan/vrfs_networks.yml | 2 +- roles/dtc/remove/tasks/sub_main_mfd.yml | 6 +- 18 files changed, 186 insertions(+), 97 deletions(-) rename roles/dtc/common/templates/{ndfc_attach_networks_fed.j2 => ndfc_networks/mfd_fabric/ndfc_attach_networks.j2} (100%) rename roles/dtc/common/templates/{ndfc_attach_networks_switches_fed.j2 => ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2} (100%) rename roles/dtc/common/templates/{ndfc_attach_networks_switches_ports_fed.j2 => ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2} (100%) rename roles/dtc/common/templates/{ndfc_attach_vrfs_fed.j2 => ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2} (98%) rename roles/dtc/common/templates/{ndfc_attach_vrfs_loopbacks_fed.j2 => ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2} (77%) diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index febd77046..3e6c78dab 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -184,7 +184,6 @@ def run(self, tmp=None, task_vars=None): ndfc_vrf_response_data = ndfc_vrf['response']['DATA'] ndfc_vrf_template_config = json.loads(ndfc_vrf_response_data['vrfTemplateConfig']) - print(ndfc_vrf_template_config) # Check for differences between the data model and the template config from NDFC for the # attributes that are configurable by the user in a child fabric. # Note: This excludes IPv6 related attributes at this time as they are not yet supported fully in the data model. diff --git a/roles/common_global/vars/main.yml b/roles/common_global/vars/main.yml index bb5a06a96..b4c601f47 100644 --- a/roles/common_global/vars/main.yml +++ b/roles/common_global/vars/main.yml @@ -131,7 +131,7 @@ nac_tags: - cr_manage_vpc_peers create_interfaces: - cr_manage_interfaces - create_vrfs_networks: + create_vrfs_networks: - cr_manage_vrfs_networks create_policy: - cr_manage_policy diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index 7ec852a1e..e3fc702ae 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -27,7 +27,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "ndfc_fed_attach_networks.yml" + file_name: "ndfc_attach_networks.yml" delegate_to: localhost - name: Stat Previous File If It Exists @@ -51,8 +51,9 @@ - name: Build Networks Attach List From Template ansible.builtin.template: - src: ndfc_attach_networks_fed.j2 + src: "{{ role_path }}/../common/templates/ndfc_attach_networks.j2" dest: "{{ path_name }}{{ file_name }}" + mode: '0644' delegate_to: localhost - name: Set net_config Var @@ -83,24 +84,38 @@ - name: Set file_name Var for switches and port attachments ansible.builtin.set_fact: - file_name: "attach_network_switches_ports.yml" - file_name2: "attach_network_switches.yml" + file_name: "ndfc_attach_network_switches_ports.yml" + file_name2: "ndfc_attach_network_switches.yml" switches: [] networks: [] delegate_to: localhost -- name: Build Network attach list for switches on Federated +- name: Build VRFs Attach List for switches From Template ansible.builtin.template: - src: ndfc_attach_networks_switches_fed.j2 + src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2" dest: "{{ path_name }}{{ file_name }}" + mode: '0644' delegate_to: localhost -- name: Build Network attach list for switches and ports on Federated +- name: Build VRFs Attach List for switches and ports From Template ansible.builtin.template: - src: ndfc_attach_networks_switches_ports_fed.j2 + src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2" dest: "{{ path_name }}{{ file_name2 }}" + mode: '0644' delegate_to: localhost +# - name: Build Network attach list for switches on Federated +# ansible.builtin.template: +# src: ndfc_attach_networks_switches_fed.j2 +# dest: "{{ path_name }}{{ file_name }}" +# delegate_to: localhost + +# - name: Build Network attach list for switches and ports on Federated +# ansible.builtin.template: +# src: ndfc_attach_networks_switches_ports_fed.j2 +# dest: "{{ path_name }}{{ file_name2 }}" +# delegate_to: localhost + - name: Set network_switches Var ansible.builtin.set_fact: network_switches: "{{ lookup('file', path_name + file_name) | from_yaml }}" diff --git a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml index abd6aa695..6e91dfc57 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml @@ -27,7 +27,7 @@ - name: Set file_name Var ansible.builtin.set_fact: - file_name: "ndfc_fed_attach_vrfs.yml" + file_name: "ndfc_attach_vrfs.yml" delegate_to: localhost - name: Stat Previous File If It Exists @@ -49,10 +49,17 @@ delegate_to: localhost when: data_file_previous.stat.exists +# - name: Build VRFs Attach List From Template +# ansible.builtin.template: +# src: ndfc_attach_vrfs_fed.j2 +# dest: "{{ path_name }}{{ file_name }}" +# delegate_to: localhost + - name: Build VRFs Attach List From Template ansible.builtin.template: - src: ndfc_attach_vrfs_fed.j2 + src: "{{ role_path }}/../common/templates/ndfc_attach_vrfs.j2" dest: "{{ path_name }}{{ file_name }}" + mode: '0644' delegate_to: localhost - name: Create Empty vrf_config Var @@ -83,14 +90,29 @@ - name: Set file_name Var for loopback attachments ansible.builtin.set_fact: - file_name: "attach_vrfs_loopbacks.yml" + file_name: "ndfc_attach_vrfs_loopbacks.yml" delegate_to: localhost -- name: Build VRFs Attach List From Template for loopback on Federated +- name: Build VRFs Loopback Attach List From Template ansible.builtin.template: - src: ndfc_attach_vrfs_loopbacks_fed.j2 - dest: "{{ path_name }}{{ vrf.name }}_{{ file_name }}" + src: "{{ role_path }}/../common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2" + dest: "{{ path_name }}{{ file_name }}" + mode: '0644' + delegate_to: localhost + +# - name: Build VRFs Attach List From Template for loopback on Federated +# ansible.builtin.template: +# src: ndfc_attach_vrfs_loopbacks_fed.j2 +# dest: "{{ path_name }}{{ file_name }}" +# delegate_to: localhost + +- name: Create Empty vrf_loopbacks Var + ansible.builtin.set_fact: + vrf_attach_config: [] + delegate_to: localhost + +- name: Set vrf_attach_config Var + ansible.builtin.set_fact: + vrf_attach_config: "{{ lookup('file', path_name + file_name ) | from_yaml }}" + when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 delegate_to: localhost - loop: "{{ MD_Extended.vxlan.multisite.overlay.vrfs }}" - loop_control: - loop_var: vrf diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml index cc4f0e420..19e267272 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -72,12 +72,20 @@ - name: Build NDFC Fabric Networks Attach List From Template ansible.builtin.import_tasks: mfd/ndfc_networks.yml -- name: Set facts for missed changes_detected flags for Federated Fabric +- name: Save Local Variables With Namespace Context ansible.builtin.set_fact: vars_common_mfd: changes_detected_fabric: "{{ changes_detected_fabric | default(false) }}" changes_detected_vrfs: "{{ changes_detected_vrfs }}" changes_detected_networks: "{{ changes_detected_networks }}" + fabric_config: "{{ fabric_config }}" + fabric_children: "{{ fabric_children }}" + switches_in_fabric: "{{ switches_in_fabric }}" + net_config: "{{ net_config }}" + network_switches: "{{ network_switches }}" + network_switches_ports: "{{ network_switches_ports }}" + vrf_config: "{{ vrf_config }}" + vrf_attach_config: "{{ vrf_attach_config }}" - name: Run Diff Flags ansible.builtin.debug: msg: diff --git a/roles/dtc/common/templates/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_attach_networks.j2 index 3d0570203..e6bab6e86 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks.j2 @@ -13,5 +13,10 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_networks/msd_fabric/msd_fabric_networks.j2' %} -{# Supported fabric types are: DC VXLAN EVPN and MSDs #} +{% elif vxlan.fabric.type == 'MFD'%} + +{# Include NDFC MFD Base Template #} +{% include '/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN, MSDs and MFDs #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index e25ac7097..b7dc982a1 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -14,5 +14,10 @@ {% include '/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2' %} {# {% include '/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2' %} #} -{# Supported fabric types are: DC VXLAN EVPN and ISN #} +{% elif vxlan.fabric.type == 'MFD'%} + +{# Include NDFC MFD Base Template #} +{% include '/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2' %} + +{# Supported fabric types are: DC VXLAN EVPN, MSDs and MFDs #} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_attach_networks_fed.j2 b/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_attach_networks_fed.j2 rename to roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2 diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 b/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_attach_networks_switches_fed.j2 rename to roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2 diff --git a/roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 b/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_attach_networks_switches_ports_fed.j2 rename to roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2 diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 b/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2 similarity index 98% rename from roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 rename to roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2 index 3709253da..c47444268 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_fed.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2 @@ -7,7 +7,6 @@ "vrfTemplate":"Default_VRF_Universal", "vrfTemplateConfig": "{\"vrfVlanName\":\"{{ vrf.vrf_vlan_name | default(vrf.vlan_id)}}\",\"vrfIntfDescription\":\"{{ vrf.vrf_intf_desc | default(defaults.vxlan.multisite.overlay.vrfs.vrf_intf_desc) }}\",\"vrfDescription\":\"{{ vrf.vrf_description | default(defaults.vxlan.multisite.overlay.vrfs.vrf_description) }}\",\"mtu\":\"{{ vrf.vrf_int_mtu | default(defaults.vxlan.multisite.overlay.vrfs.vrf_int_mtu) }}\",\"tag\":\"{{ vrf.loopback_route_tag | default(defaults.vxlan.multisite.overlay.vrfs.loopback_route_tag)}}\",\"vrfRouteMap\":\"{{ vrf.redist_direct_routemap | default(defaults.vxlan.multisite.overlay.vrfs.redist_direct_routemap) }}\",\"v6VrfRouteMap\":\"\",\"maxBgpPaths\":\"{{ vrf.max_bgp_paths | default(defaults.vxlan.multisite.overlay.vrfs.max_bgp_paths) }}\",\"maxIbgpPaths\":\"{{ vrf['max_ibgp_paths'] | default(defaults.vxlan.multisite.overlay.vrfs.max_ibgp_paths) }}\",\"ipv6LinkLocalFlag\":\"{{ vrf['ipv6_linklocal_enable'] | default(defaults.vxlan.multisite.overlay.vrfs.ipv6_linklocal_enable) }}\",\"disableRtAuto\":\"{{ vrf['disable_rt_auto'] | default(defaults.vxlan.multisite.overlay.vrfs.disable_rt_auto)}}\",\"routeTargetImport\":\"\",\"routeTargetExport\":\"\",\"routeTargetImportEvpn\":\"\",\"routeTargetExportEvpn\":\"\",\"vrfName\":\"{{ vrf.name }}\",\"vrfVlanId\":\"{{ vrf.vlan_id }}\",\"vrfSegmentId\":\"{{ vrf.vrf_id }}\",\"nveId\":\"1\",\"asn\":\"\"}", "serviceVrfTemplate": null, - "serviceVrfTemplate": null, "displayName": "{{ vrf.name}}", "vrfExtensionTemplate":"Default_VRF_Extension_Universal" }{% if not loop.last %},{% endif %} diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2 similarity index 77% rename from roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 rename to roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2 index 093c2c78b..a94e57ebe 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 +++ b/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2 @@ -1,4 +1,10 @@ [ + {% for vrf in MD_Extended.vxlan.multisite.overlay.vrfs %} + {% if vrf['vrf_attach_group'] is defined %} + { + "vrfName": "{{ vrf["name"] }}", + "lanAttachList": + [ {% for attach in MD_Extended.vxlan.multisite.overlay.vrf_attach_groups_dict[vrf["vrf_attach_group"]] %} { @@ -15,6 +21,9 @@ "deployment": true, "instanceValues": "{\"loopbackId\": \"{{ attach['loopback_id'] | default('') }}\", \"loopbackIpAddress\": \"{{ attach['loopback_ipv4'] | default('') }}\", \"loopbackIpV6Address\":\"{{ attach['loopback_ipv6'] | default('') }}\"}" }{% if not loop.last %},{% endif %} + {% endfor %} + ] + }{% if not loop.last %},{% endif %} + {% endif %} {% endfor %} ] - diff --git a/roles/dtc/create/tasks/mfd/network_fed_config.yml b/roles/dtc/create/tasks/mfd/network_fed_config.yml index 4729c784c..b35a99f6e 100644 --- a/roles/dtc/create/tasks/mfd/network_fed_config.yml +++ b/roles/dtc/create/tasks/mfd/network_fed_config.yml @@ -26,7 +26,7 @@ - "----------------------------------------------------------------" - "+ Manage Networks for Federated Fabrics {{ MD.vxlan.fabric.name }}" - "----------------------------------------------------------------" - + tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- # Manage Network Configuration on NDFC # -------------------------------------------------------------------- @@ -36,6 +36,7 @@ network_id_list: "{{ fed_networks_existing | json_query(network_query) }}" vars: network_query: "response.DATA[?displayName=='{{network.displayName}}'].networkId" + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Update Network for Federated NDFCs cisco.dcnm.dcnm_rest: @@ -43,6 +44,7 @@ method: "PUT" json_data: "{{ network | to_json}}" when: network_id_list|default(None)|length != 0 + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Configure Network for Federated NDFCs cisco.dcnm.dcnm_rest: @@ -50,3 +52,4 @@ method: "POST" json_data: "{{ network | to_json}}" when: network_id_list|default(None)|length == 0 + tags: "{{ nac_tags.create_vrfs_networks }}" \ No newline at end of file diff --git a/roles/dtc/create/tasks/mfd/vrf_fed_config.yml b/roles/dtc/create/tasks/mfd/vrf_fed_config.yml index 8cfd07db6..53b92ad32 100644 --- a/roles/dtc/create/tasks/mfd/vrf_fed_config.yml +++ b/roles/dtc/create/tasks/mfd/vrf_fed_config.yml @@ -25,9 +25,9 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage VRFs for Federated Fabrics {{ MD.vxlan.fabric.name }}" + - "+ Manage VRFs for Federated Fabrics {{ MD_Extended.vxlan.fabric.name }} and {{ vrf.displayName }} " - "----------------------------------------------------------------" - + tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- # Manage VRF Configuration on NDFC # -------------------------------------------------------------------- @@ -35,25 +35,29 @@ - name: Get existing VRFs in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" register: dcnm_vrf_existing + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Check if VRF Exists set_fact: vrf_exist_result: "{{ dcnm_vrf_existing | json_query(vrf_query) }}" vars: vrf_query: "response.DATA[?vrfName=='{{vrf.displayName}}'].vrfName" + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Update VRF for Federated NDFCs cisco.dcnm.dcnm_rest: - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/{{ vrf.displayName }}" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/{{ vrf.displayName }}" method: "PUT" json_data: "{{ vrf | to_json}}" when: vrf_exist_result|default(None)|length != 0 + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Configure VRF for Federated NDFCs cisco.dcnm.dcnm_rest: - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" method: "POST" json_data: "{{ vrf | to_json}}" when: vrf_exist_result|default(None)|length == 0 + tags: "{{ nac_tags.create_vrfs_networks }}" \ No newline at end of file diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 1d67d4bc6..8b831d690 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -26,64 +26,70 @@ - "----------------------------------------------------------------" - "+ Manage VRFs and Networks MFD Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" - + tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- # Manage VRF Configuration for Federated NDFCs # -------------------------------------------------------------------- -- name: Set filename for federated - ansible.builtin.set_fact: - file_name: "ndfc_fed_attach_vrfs.yml" - when: - - MD.vxlan.multisite.overlay.vrfs is defined - - changes_detected_vrfs - - MD.vxlan.fabric.type == 'MFD' - -- name: Load VRF federated details from file - ansible.builtin.set_fact: - fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" - when: - - MD.vxlan.multisite.overlay.vrfs is defined - - changes_detected_vrfs - - MD.vxlan.fabric.type == 'MFD' +# - name: Set filename for federated +# ansible.builtin.set_fact: +# file_name: "ndfc_fed_attach_vrfs.yml" +# when: +# - MD_Extended.vxlan.multisite.overlay.vrfs is defined +# - changes_detected_vrfs +# - MD_Extended.vxlan.fabric.type == 'MFD' + +# - name: Load VRF federated details from file +# ansible.builtin.set_fact: +# fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" +# when: +# - MD_Extended.vxlan.multisite.overlay.vrfs is defined +# - changes_detected_vrfs +# - MD_Extended.vxlan.fabric.type == 'MFD' - name: Get existing VRFs in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" register: dcnm_vrf_existing when: - - MD.vxlan.multisite.overlay.vrfs is defined - - changes_detected_vrfs - - MD.vxlan.fabric.type == 'MFD' + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric VRFs for Federated ansible.builtin.include_tasks: vrf_fed_config.yml - loop: "{{ fed_vrf_config }}" + loop: "{{ vars_common_mfd.vrf_config }}" loop_control: loop_var: vrf when: - - MD.vxlan.multisite.overlay.vrfs is defined - - changes_detected_vrfs - - MD.vxlan.fabric.type == 'MFD' + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- # Manage Loopback VRF attachments on NDFC (MFD) # -------------------------------------------------------------------- -- name: Attach VRF Loopbacks per VRF - ansible.builtin.include_tasks: vrf_loopbacks.yml - loop_control: - loop_var: vrf - loop: "{{ MD.vxlan.multisite.overlay.vrfs }}" + +- name: Call API to attach VRF to Leaf Switches for Federated NDFCs + cisco.dcnm.dcnm_rest: + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + method: POST + json_data: "{{ vars_common_mfd.vrf_attach_config | to_json }}" when: - - MD.vxlan.multisite.overlay.vrfs is defined - - MD.vxlan.fabric.type == 'MFD' + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get vrf attachments list cisco.dcnm.dcnm_rest: method: GET path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments register: vrfAttachmentList + when: + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter vrf attachments to be removed cisco.nac_dc_vxlan.dtc.fed_overlay_check: @@ -92,6 +98,10 @@ ndfc_attachment_data: "{{ vrfAttachmentList.response.DATA }}" check_type: "vrf_attach" register: not_required_vrfs + when: + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Remove vrf attachments cisco.dcnm.dcnm_rest: @@ -99,6 +109,10 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" register: vrf_attachment_result + when: + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric VRFs cisco.nac_dc_vxlan.dtc.manage_child_fabric_vrfs: @@ -106,6 +120,10 @@ msite_data: "{{ MD_Multisite }}" fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_vrf_results + when: + - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - vars_common_mfd.changes_detected_vrfs + tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- # Manage Network Configuration for Federated NDFCs @@ -113,44 +131,44 @@ - name: Query existing network.switches_to_attach.split in Federated Fabric cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/networks" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" register: fed_networks_existing when: - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks - - MD.vxlan.fabric.type == 'MFD' + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Networks for Federated ansible.builtin.include_tasks: network_fed_config.yml - loop: "{{ net_config }}" + loop: "{{ vars_common_mfd.net_config }}" loop_control: loop_var: network when: - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach switches for all networks cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/attachments" method: "POST" - json_data: "{{ network_switches | to_json }}" + json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - - network_switches is defined - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - vars_common_mfd.network_switches is defined + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/multiattach" method: "POST" - json_data: "{{ network_switches_ports | to_json }}" + json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" when: - - network_switches_ports is defined - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - vars_common_mfd.network_switches_ports is defined + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get network attachments list cisco.dcnm.dcnm_rest: @@ -158,9 +176,9 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList when: - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter network attachments to be removed cisco.nac_dc_vxlan.dtc.fed_overlay_check: @@ -170,9 +188,10 @@ check_type: "network_attach" register: network_attachments_payload when: - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - MD_Extended.vxlan.fabric.type == 'MFD' + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks cisco.dcnm.dcnm_rest: @@ -180,10 +199,10 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - - network_switches_ports is defined - - MD.vxlan.fabric.type == 'MFD' - - MD.vxlan.multisite.overlay.networks is defined - - changes_detected_networks + - vars_common_mfd.network_switches_ports is defined + - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.changes_detected_networks + tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric Networks cisco.nac_dc_vxlan.dtc.manage_child_fabric_networks: @@ -191,3 +210,4 @@ msite_data: "{{ MD_Multisite }}" fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_network_results + tags: "{{ nac_tags.create_vrfs_networks }}" \ No newline at end of file diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mfd.yml index d10ed2804..4765a14d6 100644 --- a/roles/dtc/create/tasks/sub_main_mfd.yml +++ b/roles/dtc/create/tasks/sub_main_mfd.yml @@ -36,7 +36,7 @@ ansible.builtin.import_tasks: mfd/fabric.yml when: - MD_Extended.vxlan.fabric.name is defined - - changes_detected_fabric + - vars_common_mfd.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Debug message @@ -64,6 +64,6 @@ - name: Manage NDFC Fabric VRFs and Networks ansible.builtin.import_tasks: mfd/vrfs_networks.yml when: - - MD.vxlan.multisite.overlay is defined - - changes_detected_vrfs or changes_detected_networks - tags: "{{ nac_tags.create_vrfs_networks }}" + - MD_Extended.vxlan.multisite.overlay is defined + - vars_common_mfd.changes_detected_vrfs or vars_common_mfd.changes_detected_networks + diff --git a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml index 4c3cc5494..6215074f3 100644 --- a/roles/dtc/create/tasks/vxlan/vrfs_networks.yml +++ b/roles/dtc/create/tasks/vxlan/vrfs_networks.yml @@ -61,7 +61,7 @@ cisco.dcnm.dcnm_vrf: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: replaced - config: "{{ vars_common_vxlan.vrf_config }}" + config: "{{ vars_common_mfd.vrf_config }}" register: manage_vrf_result when: - MD_Extended.vxlan.overlay.vrfs is defined diff --git a/roles/dtc/remove/tasks/sub_main_mfd.yml b/roles/dtc/remove/tasks/sub_main_mfd.yml index 7511394b9..09bfb40ad 100644 --- a/roles/dtc/remove/tasks/sub_main_mfd.yml +++ b/roles/dtc/remove/tasks/sub_main_mfd.yml @@ -37,7 +37,7 @@ - cisco.dcnm.dcnm_rest: method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.fabric.name }}/inventory/switchesByFabric" + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/inventory/switchesByFabric" register: result tags: "{{ nac_tags.remove }}" @@ -49,13 +49,13 @@ ansible.builtin.import_tasks: mfd/networks_fed.yml tags: "{{ nac_tags.remove_networks }}" when: - - changes_detected_networks + - vars_common_mfd.changes_detected_networks - name: Remove Fabric VRFs ansible.builtin.import_tasks: mfd/vrfs_fed.yml tags: "{{ nac_tags.remove_vrfs }}" when: - - changes_detected_vrfs + - vars_common_mfd.changes_detected_vrfs - name: Remove Child Fabrics ansible.builtin.import_tasks: mfd/child_fabrics.yml From 1ba50d40e5474b3edeb46847e3c85fd2c34b989f Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Wed, 3 Sep 2025 11:33:57 +0100 Subject: [PATCH 150/183] fixing santies --- plugins/action/dtc/fed_overlay_check.py | 93 +++++++++++++++---- .../dtc/manage_child_fabric_networks.py | 6 +- .../action/dtc/manage_child_fabric_vrfs.py | 6 +- plugins/action/dtc/prepare_msite_data.py | 8 +- plugins/plugin_utils/data_model_keys.py | 1 - plugins/plugin_utils/helper_functions.py | 10 +- roles/dtc/create/tasks/sub_main_mfd.yml | 1 - roles/dtc/remove/tasks/mfd/networks_fed.yml | 1 + roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 1 + roles/validate/files/defaults.yml | 7 -- tests/sanity/ignore-2.14.txt | 2 + tests/sanity/ignore-2.15.txt | 2 + tests/sanity/ignore-2.16.txt | 2 + tests/sanity/ignore-2.17.txt | 2 + 14 files changed, 104 insertions(+), 38 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index fbf46b0e3..6366c2ef5 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -47,14 +47,21 @@ def run(self, tmp=None, task_vars=None): restructured_attachment_data = [] deployment = False deploy_payload = [] - #normalise data for comparison + # normalise data for comparison if check_type == 'network_attach': switch_data = ndfc_data - for attached_network in ndfc_attachment_data: + for attached_network in ndfc_attachment_data: for network_attached_group in attached_network['lanAttachList']: - if network_attached_group['isLanAttached'] == True: - normal_ndfc_data.append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) - for network in model_data['vxlan']['multisite']['overlay']['networks']: + if network_attached_group['isLanAttached'] is True: + normal_ndfc_data.append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) + for network in model_data['vxlan']['multisite']['overlay']['networks']: for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name']: for switch in network_attach_group['switches']: @@ -70,15 +77,29 @@ def run(self, tmp=None, task_vars=None): # Combine main and tors ports = f"{main} {tors}".strip() - normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':ports,"deployment":deployment, "fabric":switch_entry['fabricName']}) + normal_model_data.append({ + 'networkName': network['name'], + 'switchName': switch['hostname'], + 'serialNumber': switch_entry['serialNumber'], + 'portNames': ports, + 'deployment': deployment, + 'fabric': switch_entry['fabricName'] + }) else: - normal_model_data.append({'networkName':network['name'],'switchName':switch['hostname'],'serialNumber':switch_entry['serialNumber'],'portNames':(",".join(switch['ports'])),"deployment":deployment, "fabric":switch_entry['fabricName']}) + normal_model_data.append({ + 'networkName': network['name'], + 'switchName': switch['hostname'], + 'serialNumber': switch_entry['serialNumber'], + 'portNames': (",".join(switch['ports'])), + 'deployment': deployment, + 'fabric': switch_entry['fabricName'] + }) difference = [item for item in normal_ndfc_data if item not in normal_model_data] # Restructure in case of just port removal for item in difference: if item['portNames'] != "": - for network in model_data['vxlan']['multisite']['overlay']['networks']: + for network in model_data['vxlan']['multisite']['overlay']['networks']: for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: for switch in network_attach_group['switches']: @@ -118,26 +139,56 @@ def run(self, tmp=None, task_vars=None): for network in network_difference: for attached_network in ndfc_attachment_data: for network_attached_group in attached_network['lanAttachList']: - if network == attached_network['networkName'] and network == network_attached_group['networkName'] and network_attached_group['isLanAttached'] == True: + if (network == attached_network['networkName'] and + network == network_attached_group['networkName'] and + network_attached_group['isLanAttached'] is True): if network not in network_attachment_dict: - network_attachment_dict[network] = {'networkName': network, 'lanAttachList': []} - network_attachment_dict[network]['lanAttachList'].append({'networkName': network_attached_group['networkName'],'switchName': network_attached_group['switchName'],'serialNumber':network_attached_group['switchSerialNo'],'portNames':network_attached_group['portNames'], "deployment":deployment, "fabric":network_attached_group['fabricName']}) + network_attachment_dict[network] = { + 'networkName': network, + 'lanAttachList': [] + } + network_attachment_dict[network]['lanAttachList'].append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) + network_attachment_dict[network]['lanAttachList'].append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) deploy_payload.append(network_attached_group['switchSerialNo']) restructured_attachment_data = list(network_attachment_dict.values()) elif check_type == 'vrf_attach': switch_data = ndfc_data - for attached_vrf in ndfc_attachment_data: + for attached_vrf in ndfc_attachment_data: for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf_attached_group['isLanAttached'] == True: - normal_ndfc_data.append({"fabric":vrf_attached_group['fabricName'],'deployment': deployment, 'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo']}) + if vrf_attached_group['isLanAttached'] is True: + normal_ndfc_data.append({ + 'fabric': vrf_attached_group['fabricName'], + 'deployment': deployment, + 'vrfName': vrf_attached_group['vrfName'], + 'serialNumber': vrf_attached_group['switchSerialNo'] + }) for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: for vrf_attach_group in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: if vrf['vrf_attach_group'] == vrf_attach_group['name']: for switch in vrf_attach_group['switches']: for switch_entry in switch_data: if switch['hostname'] == switch_entry['logicalName']: - normal_model_data.append({"fabric":switch_entry['fabricName'],'deployment': deployment,'vrfName':vrf['name'],'serialNumber':switch_entry['serialNumber']}) + normal_model_data.append({ + 'fabric': switch_entry['fabricName'], + 'deployment': deployment, + 'vrfName': vrf['name'], + 'serialNumber': switch_entry['serialNumber'] + }) difference = [item for item in normal_ndfc_data if item not in normal_model_data] # Restructure the difference data @@ -162,10 +213,15 @@ def run(self, tmp=None, task_vars=None): for vrf in vrf_difference: for attached_vrf in ndfc_attachment_data: for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf == attached_vrf['vrfName'] and vrf == vrf_attached_group['vrfName'] and vrf_attached_group['isLanAttached'] == True: + if vrf == attached_vrf['vrfName'] and vrf == vrf_attached_group['vrfName'] and vrf_attached_group['isLanAttached'] is True: if vrf not in vrf_attachment_dict: vrf_attachment_dict[vrf] = {'vrfName': vrf, 'lanAttachList': []} - vrf_attachment_dict[vrf]['lanAttachList'].append({'vrfName': vrf_attached_group['vrfName'],'serialNumber':vrf_attached_group['switchSerialNo'], "deployment":deployment, "fabric":vrf_attached_group['fabricName']}) + vrf_attachment_dict[vrf]['lanAttachList'].append({ + 'vrfName': vrf_attached_group['vrfName'], + 'serialNumber': vrf_attached_group['switchSerialNo'], + 'deployment': deployment, + 'fabric': vrf_attached_group['fabricName'] + }) deploy_payload.append(vrf_attached_group['switchSerialNo']) restructured_attachment_data = list(vrf_attachment_dict.values()) @@ -174,6 +230,5 @@ def run(self, tmp=None, task_vars=None): results['payload'] = restructured_data results['attachments_payload'] = restructured_attachment_data results['deploy_payload'] = deploy_payload - + return results - \ No newline at end of file diff --git a/plugins/action/dtc/manage_child_fabric_networks.py b/plugins/action/dtc/manage_child_fabric_networks.py index 4e9c764f7..a79baf25e 100644 --- a/plugins/action/dtc/manage_child_fabric_networks.py +++ b/plugins/action/dtc/manage_child_fabric_networks.py @@ -158,7 +158,8 @@ def run(self, tmp=None, task_vars=None): # results['msg'] = error_msg # return results if fabric_type == 'MFD': - get_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" + get_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" + f"rest/top-down/fabrics/{child_fabric}/networks/{network['name']}") else: get_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" ndfc_net = self._execute_module( @@ -226,7 +227,8 @@ def run(self, tmp=None, task_vars=None): rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) if fabric_type == 'MFD': - put_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" + put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" + f"rest/top-down/fabrics/{child_fabric}/networks/{network['name']}") else: put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" ndfc_net_update = self._execute_module( diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index 3e6c78dab..3475b59aa 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -169,7 +169,8 @@ def run(self, tmp=None, task_vars=None): # results['msg'] = error_msg # return results if fabric_type == 'MFD': - get_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" + get_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" + f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: get_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" ndfc_vrf = self._execute_module( @@ -239,7 +240,8 @@ def run(self, tmp=None, task_vars=None): rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) if fabric_type == 'MFD': - put_path = f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" + put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" + f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" ndfc_vrf_update = self._execute_module( diff --git a/plugins/action/dtc/prepare_msite_data.py b/plugins/action/dtc/prepare_msite_data.py index 910f4739d..370ea4b7a 100644 --- a/plugins/action/dtc/prepare_msite_data.py +++ b/plugins/action/dtc/prepare_msite_data.py @@ -62,8 +62,11 @@ def run(self, tmp=None, task_vars=None): for fabric in mfd_fabric_associations.get('response').get('DATA'): if fabric.get('fabricName') == parent_fabric: for member in fabric["members"]: - associated_child_fabrics.append({'fabric':member.get('fabricName'), 'cluster':member.get('clusterName'), 'type':member.get('fabricType')}) - + associated_child_fabrics.append({ + 'fabric': member.get('fabricName'), + 'cluster': member.get('clusterName'), + 'type': member.get('fabricType') + }) child_fabrics_data = {} for fabric in associated_child_fabrics: @@ -73,7 +76,6 @@ def run(self, tmp=None, task_vars=None): child_fabrics_data[fabric_name].update({'attributes': ndfc_get_fabric_attributes_onepath(self, task_vars, tmp, fabric_name, fabric['cluster'])}) child_fabrics_data[fabric_name].update({'switches': ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric_name, fabric['cluster'])}) child_fabrics_data[fabric_name].update({'cluster': fabric['cluster']}) - results['child_fabrics_data'] = child_fabrics_data else: diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index ac12aa72b..0dacd322d 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -125,4 +125,3 @@ model_keys['MFD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] model_keys['MFD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] model_keys['MFD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] - diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index fa07bfe8a..b8a44d6ec 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -26,6 +26,7 @@ # from ..helper_functions import do_something import re + def data_model_key_check(tested_object, keys): """ Check if key(s) are found and exist in the data model. @@ -196,6 +197,7 @@ def ndfc_get_fabric_attributes(self, task_vars, tmp, fabric): return fabric_attributes + def ndfc_get_fabric_attributes_onepath(self, task_vars, tmp, fabric, cluster): """ Get NDFC fabric attributes. @@ -264,6 +266,7 @@ def ndfc_get_fabric_switches(self, task_vars, tmp, fabric): return fabric_switches + def ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric, cluster): """ Get NDFC fabric switches. @@ -299,11 +302,12 @@ def ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric, cluster): 'mgmt_ip_address': fabric_switch['ipAddress'] } ) - + return fabric_switches + def normalise_int_lists(data): for interface in data: - if interface.startswith(('Ethernet','ethernet','Eth','eth','E','e')): + if interface.startswith(('Ethernet', 'ethernet', 'Eth', 'eth', 'E', 'e')): interface = "Ethernet" + re.split(r'(?=\d)', interface, 1)[1] - return data \ No newline at end of file + return data diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mfd.yml index 4765a14d6..25bd53fbb 100644 --- a/roles/dtc/create/tasks/sub_main_mfd.yml +++ b/roles/dtc/create/tasks/sub_main_mfd.yml @@ -66,4 +66,3 @@ when: - MD_Extended.vxlan.multisite.overlay is defined - vars_common_mfd.changes_detected_vrfs or vars_common_mfd.changes_detected_networks - diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index 848b0596c..122f34820 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -88,3 +88,4 @@ - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" - "---------------------------------------------------------------------------------------------------------------" when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) + \ No newline at end of file diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index fbf7e1d39..a1d7bc421 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -91,3 +91,4 @@ - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" - "--------------------------------------------------------------------------------------------------------" when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) + \ No newline at end of file diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 3d162d065..70bbc7b13 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -418,13 +418,6 @@ factory_defaults: route_target_both: false route_tag: 12345 trm_enable: false - net_description: "Configured by Ansible NetAsCode" - layer2_vni_range: - from: 30000 - to: 49000 - layer3_vni_range: - from: 50000 - to: 59000 overlay_dci: deployment_method: Direct_To_BGWS route_server: diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index a35fe069a..f9890f03f 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -15,6 +15,8 @@ plugins/action/common/get_credentials.py action-plugin-docs # action plugin has plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index a35fe069a..f9890f03f 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -15,6 +15,8 @@ plugins/action/common/get_credentials.py action-plugin-docs # action plugin has plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index a35fe069a..f9890f03f 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -15,6 +15,8 @@ plugins/action/common/get_credentials.py action-plugin-docs # action plugin has plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.17.txt b/tests/sanity/ignore-2.17.txt index a35fe069a..f9890f03f 100644 --- a/tests/sanity/ignore-2.17.txt +++ b/tests/sanity/ignore-2.17.txt @@ -15,6 +15,8 @@ plugins/action/common/get_credentials.py action-plugin-docs # action plugin has plugins/action/common/run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation +plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation From 4bdbf18db07ce1197d74e2b392f3122a8f5f8a3f Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Wed, 3 Sep 2025 11:41:48 +0100 Subject: [PATCH 151/183] more fixing santies --- plugins/action/dtc/fed_overlay_check.py | 468 +++++++++--------- .../action/dtc/manage_child_fabric_vrfs.py | 2 +- plugins/action/dtc/prepare_msite_data.py | 2 +- roles/dtc/remove/tasks/mfd/networks_fed.yml | 180 +++---- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 186 +++---- 5 files changed, 419 insertions(+), 419 deletions(-) diff --git a/plugins/action/dtc/fed_overlay_check.py b/plugins/action/dtc/fed_overlay_check.py index 6366c2ef5..57bd25ddf 100644 --- a/plugins/action/dtc/fed_overlay_check.py +++ b/plugins/action/dtc/fed_overlay_check.py @@ -1,234 +1,234 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.utils.display import Display -from ansible.plugins.action import ActionBase - -display = Display() - - -class ActionModule(ActionBase): - """ - This class is used to compare the existing links with the links that you are - looking to add to the fabric. If the link already exists, it will be added to - the not_required_links list. - """ - def run(self, tmp=None, task_vars=None): - results = super(ActionModule, self).run(tmp, task_vars) - check_type = self._task.args['check_type'] - model_data = self._task.args['model_data'] - normal_model_data = [] - ndfc_data = self._task.args['ndfc_data'] - ndfc_attachment_data = self._task.args['ndfc_attachment_data'] - normal_ndfc_data = [] - restructured_data = [] - restructured_attachment_data = [] - deployment = False - deploy_payload = [] - # normalise data for comparison - if check_type == 'network_attach': - switch_data = ndfc_data - for attached_network in ndfc_attachment_data: - for network_attached_group in attached_network['lanAttachList']: - if network_attached_group['isLanAttached'] is True: - normal_ndfc_data.append({ - 'networkName': network_attached_group['networkName'], - 'switchName': network_attached_group['switchName'], - 'serialNumber': network_attached_group['switchSerialNo'], - 'portNames': network_attached_group['portNames'], - 'deployment': deployment, - 'fabric': network_attached_group['fabricName'] - }) - for network in model_data['vxlan']['multisite']['overlay']['networks']: - for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: - if network.get('network_attach_group') == network_attach_group['name']: - for switch in network_attach_group['switches']: - for switch_entry in switch_data: - if switch['hostname'] == switch_entry['logicalName']: - if switch.get('tors'): - main = f"{switch['hostname']}({','.join(switch['ports'])})" - # Format each tor entry - tors = ' '.join( - f"{tor['hostname']}({','.join(tor['ports'])})" - for tor in switch.get('tors', []) - ) - # Combine main and tors - ports = f"{main} {tors}".strip() - - normal_model_data.append({ - 'networkName': network['name'], - 'switchName': switch['hostname'], - 'serialNumber': switch_entry['serialNumber'], - 'portNames': ports, - 'deployment': deployment, - 'fabric': switch_entry['fabricName'] - }) - else: - normal_model_data.append({ - 'networkName': network['name'], - 'switchName': switch['hostname'], - 'serialNumber': switch_entry['serialNumber'], - 'portNames': (",".join(switch['ports'])), - 'deployment': deployment, - 'fabric': switch_entry['fabricName'] - }) - difference = [item for item in normal_ndfc_data if item not in normal_model_data] - - # Restructure in case of just port removal - for item in difference: - if item['portNames'] != "": - for network in model_data['vxlan']['multisite']['overlay']['networks']: - for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: - if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: - for switch in network_attach_group['switches']: - if switch['hostname'] == item['switchName']: - port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] - if switch.get('ports'): - item['switchPorts'] = ",".join(switch['ports']) - else: - item['switchPorts'] = "" - item['detachSwitchPorts'] = ",".join(port_difference) - item['deployment'] = True - item.pop('portNames') - # psuedo code for vpc pair removal when only 1 switch has changes - # for switches in nddfc ndfc_data - # if switch in ndfc has vpc = true and switch hostname = difference switch hostname - # if found vpc serial is not in difference: - # add vpc paired device payloiad from ndfc ndfc_data - - # Restructure the difference data into payload format - network_dict = {} - for item in difference: - network_name = item['networkName'] - if network_name not in network_dict: - network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} - network_dict[network_name]['lanAttachList'].append(item) - deploy_payload.append(item['serialNumber']) - restructured_attachment_data = list(network_dict.values()) - - if check_type == 'network': - network_attachment_dict = {} - for network in model_data['vxlan']['multisite']['overlay']['networks']: - normal_model_data.append(network['name']) - for network in ndfc_data: - normal_ndfc_data.append(network['networkName']) - network_difference = [network for network in normal_ndfc_data if network not in normal_model_data] - restructured_data = network_difference - for network in network_difference: - for attached_network in ndfc_attachment_data: - for network_attached_group in attached_network['lanAttachList']: - if (network == attached_network['networkName'] and - network == network_attached_group['networkName'] and - network_attached_group['isLanAttached'] is True): - if network not in network_attachment_dict: - network_attachment_dict[network] = { - 'networkName': network, - 'lanAttachList': [] - } - network_attachment_dict[network]['lanAttachList'].append({ - 'networkName': network_attached_group['networkName'], - 'switchName': network_attached_group['switchName'], - 'serialNumber': network_attached_group['switchSerialNo'], - 'portNames': network_attached_group['portNames'], - 'deployment': deployment, - 'fabric': network_attached_group['fabricName'] - }) - network_attachment_dict[network]['lanAttachList'].append({ - 'networkName': network_attached_group['networkName'], - 'switchName': network_attached_group['switchName'], - 'serialNumber': network_attached_group['switchSerialNo'], - 'portNames': network_attached_group['portNames'], - 'deployment': deployment, - 'fabric': network_attached_group['fabricName'] - }) - deploy_payload.append(network_attached_group['switchSerialNo']) - restructured_attachment_data = list(network_attachment_dict.values()) - - elif check_type == 'vrf_attach': - switch_data = ndfc_data - for attached_vrf in ndfc_attachment_data: - for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf_attached_group['isLanAttached'] is True: - normal_ndfc_data.append({ - 'fabric': vrf_attached_group['fabricName'], - 'deployment': deployment, - 'vrfName': vrf_attached_group['vrfName'], - 'serialNumber': vrf_attached_group['switchSerialNo'] - }) - for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: - for vrf_attach_group in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: - if vrf['vrf_attach_group'] == vrf_attach_group['name']: - for switch in vrf_attach_group['switches']: - for switch_entry in switch_data: - if switch['hostname'] == switch_entry['logicalName']: - normal_model_data.append({ - 'fabric': switch_entry['fabricName'], - 'deployment': deployment, - 'vrfName': vrf['name'], - 'serialNumber': switch_entry['serialNumber'] - }) - difference = [item for item in normal_ndfc_data if item not in normal_model_data] - - # Restructure the difference data - vrf_dict = {} - - for item in difference: - vrf_name = item['vrfName'] - if vrf_name not in vrf_dict: - vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} - vrf_dict[vrf_name]['lanAttachList'].append(item) - deploy_payload.append(item['serialNumber']) - restructured_attachment_data = list(vrf_dict.values()) - - elif check_type == 'vrf': - vrf_attachment_dict = {} - for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: - normal_model_data.append(vrf['name']) - for vrf in ndfc_data: - normal_ndfc_data.append(vrf['vrfName']) - vrf_difference = [vrf for vrf in normal_ndfc_data if vrf not in normal_model_data] - restructured_data = vrf_difference - for vrf in vrf_difference: - for attached_vrf in ndfc_attachment_data: - for vrf_attached_group in attached_vrf['lanAttachList']: - if vrf == attached_vrf['vrfName'] and vrf == vrf_attached_group['vrfName'] and vrf_attached_group['isLanAttached'] is True: - if vrf not in vrf_attachment_dict: - vrf_attachment_dict[vrf] = {'vrfName': vrf, 'lanAttachList': []} - vrf_attachment_dict[vrf]['lanAttachList'].append({ - 'vrfName': vrf_attached_group['vrfName'], - 'serialNumber': vrf_attached_group['switchSerialNo'], - 'deployment': deployment, - 'fabric': vrf_attached_group['fabricName'] - }) - deploy_payload.append(vrf_attached_group['switchSerialNo']) - restructured_attachment_data = list(vrf_attachment_dict.values()) - - if deploy_payload != []: - deploy_payload = set(deploy_payload) - results['payload'] = restructured_data - results['attachments_payload'] = restructured_attachment_data - results['deploy_payload'] = deploy_payload - - return results +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible.utils.display import Display +from ansible.plugins.action import ActionBase + +display = Display() + + +class ActionModule(ActionBase): + """ + This class is used to compare the existing links with the links that you are + looking to add to the fabric. If the link already exists, it will be added to + the not_required_links list. + """ + def run(self, tmp=None, task_vars=None): + results = super(ActionModule, self).run(tmp, task_vars) + check_type = self._task.args['check_type'] + model_data = self._task.args['model_data'] + normal_model_data = [] + ndfc_data = self._task.args['ndfc_data'] + ndfc_attachment_data = self._task.args['ndfc_attachment_data'] + normal_ndfc_data = [] + restructured_data = [] + restructured_attachment_data = [] + deployment = False + deploy_payload = [] + # normalise data for comparison + if check_type == 'network_attach': + switch_data = ndfc_data + for attached_network in ndfc_attachment_data: + for network_attached_group in attached_network['lanAttachList']: + if network_attached_group['isLanAttached'] is True: + normal_ndfc_data.append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) + for network in model_data['vxlan']['multisite']['overlay']['networks']: + for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name']: + for switch in network_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + if switch.get('tors'): + main = f"{switch['hostname']}({','.join(switch['ports'])})" + # Format each tor entry + tors = ' '.join( + f"{tor['hostname']}({','.join(tor['ports'])})" + for tor in switch.get('tors', []) + ) + # Combine main and tors + ports = f"{main} {tors}".strip() + + normal_model_data.append({ + 'networkName': network['name'], + 'switchName': switch['hostname'], + 'serialNumber': switch_entry['serialNumber'], + 'portNames': ports, + 'deployment': deployment, + 'fabric': switch_entry['fabricName'] + }) + else: + normal_model_data.append({ + 'networkName': network['name'], + 'switchName': switch['hostname'], + 'serialNumber': switch_entry['serialNumber'], + 'portNames': (",".join(switch['ports'])), + 'deployment': deployment, + 'fabric': switch_entry['fabricName'] + }) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] + + # Restructure in case of just port removal + for item in difference: + if item['portNames'] != "": + for network in model_data['vxlan']['multisite']['overlay']['networks']: + for network_attach_group in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: + if network.get('network_attach_group') == network_attach_group['name'] and item['networkName'] == network['name']: + for switch in network_attach_group['switches']: + if switch['hostname'] == item['switchName']: + port_difference = [port for port in item['portNames'].split(',') if port not in switch['ports']] + if switch.get('ports'): + item['switchPorts'] = ",".join(switch['ports']) + else: + item['switchPorts'] = "" + item['detachSwitchPorts'] = ",".join(port_difference) + item['deployment'] = True + item.pop('portNames') + # psuedo code for vpc pair removal when only 1 switch has changes + # for switches in nddfc ndfc_data + # if switch in ndfc has vpc = true and switch hostname = difference switch hostname + # if found vpc serial is not in difference: + # add vpc paired device payloiad from ndfc ndfc_data + + # Restructure the difference data into payload format + network_dict = {} + for item in difference: + network_name = item['networkName'] + if network_name not in network_dict: + network_dict[network_name] = {'networkName': network_name, 'lanAttachList': []} + network_dict[network_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) + restructured_attachment_data = list(network_dict.values()) + + if check_type == 'network': + network_attachment_dict = {} + for network in model_data['vxlan']['multisite']['overlay']['networks']: + normal_model_data.append(network['name']) + for network in ndfc_data: + normal_ndfc_data.append(network['networkName']) + network_difference = [network for network in normal_ndfc_data if network not in normal_model_data] + restructured_data = network_difference + for network in network_difference: + for attached_network in ndfc_attachment_data: + for network_attached_group in attached_network['lanAttachList']: + if (network == attached_network['networkName'] and + network == network_attached_group['networkName'] and + network_attached_group['isLanAttached'] is True): + if network not in network_attachment_dict: + network_attachment_dict[network] = { + 'networkName': network, + 'lanAttachList': [] + } + network_attachment_dict[network]['lanAttachList'].append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) + network_attachment_dict[network]['lanAttachList'].append({ + 'networkName': network_attached_group['networkName'], + 'switchName': network_attached_group['switchName'], + 'serialNumber': network_attached_group['switchSerialNo'], + 'portNames': network_attached_group['portNames'], + 'deployment': deployment, + 'fabric': network_attached_group['fabricName'] + }) + deploy_payload.append(network_attached_group['switchSerialNo']) + restructured_attachment_data = list(network_attachment_dict.values()) + + elif check_type == 'vrf_attach': + switch_data = ndfc_data + for attached_vrf in ndfc_attachment_data: + for vrf_attached_group in attached_vrf['lanAttachList']: + if vrf_attached_group['isLanAttached'] is True: + normal_ndfc_data.append({ + 'fabric': vrf_attached_group['fabricName'], + 'deployment': deployment, + 'vrfName': vrf_attached_group['vrfName'], + 'serialNumber': vrf_attached_group['switchSerialNo'] + }) + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: + for vrf_attach_group in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: + if vrf['vrf_attach_group'] == vrf_attach_group['name']: + for switch in vrf_attach_group['switches']: + for switch_entry in switch_data: + if switch['hostname'] == switch_entry['logicalName']: + normal_model_data.append({ + 'fabric': switch_entry['fabricName'], + 'deployment': deployment, + 'vrfName': vrf['name'], + 'serialNumber': switch_entry['serialNumber'] + }) + difference = [item for item in normal_ndfc_data if item not in normal_model_data] + + # Restructure the difference data + vrf_dict = {} + + for item in difference: + vrf_name = item['vrfName'] + if vrf_name not in vrf_dict: + vrf_dict[vrf_name] = {'vrfName': vrf_name, 'lanAttachList': []} + vrf_dict[vrf_name]['lanAttachList'].append(item) + deploy_payload.append(item['serialNumber']) + restructured_attachment_data = list(vrf_dict.values()) + + elif check_type == 'vrf': + vrf_attachment_dict = {} + for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: + normal_model_data.append(vrf['name']) + for vrf in ndfc_data: + normal_ndfc_data.append(vrf['vrfName']) + vrf_difference = [vrf for vrf in normal_ndfc_data if vrf not in normal_model_data] + restructured_data = vrf_difference + for vrf in vrf_difference: + for attached_vrf in ndfc_attachment_data: + for vrf_attached_group in attached_vrf['lanAttachList']: + if vrf == attached_vrf['vrfName'] and vrf == vrf_attached_group['vrfName'] and vrf_attached_group['isLanAttached'] is True: + if vrf not in vrf_attachment_dict: + vrf_attachment_dict[vrf] = {'vrfName': vrf, 'lanAttachList': []} + vrf_attachment_dict[vrf]['lanAttachList'].append({ + 'vrfName': vrf_attached_group['vrfName'], + 'serialNumber': vrf_attached_group['switchSerialNo'], + 'deployment': deployment, + 'fabric': vrf_attached_group['fabricName'] + }) + deploy_payload.append(vrf_attached_group['switchSerialNo']) + restructured_attachment_data = list(vrf_attachment_dict.values()) + + if deploy_payload != []: + deploy_payload = set(deploy_payload) + results['payload'] = restructured_data + results['attachments_payload'] = restructured_attachment_data + results['deploy_payload'] = deploy_payload + + return results diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index 3475b59aa..e29219bbf 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -238,7 +238,7 @@ def run(self, tmp=None, task_vars=None): # Render the template with the combined variables rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) - + if fabric_type == 'MFD': put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") diff --git a/plugins/action/dtc/prepare_msite_data.py b/plugins/action/dtc/prepare_msite_data.py index 370ea4b7a..dc2fc0b14 100644 --- a/plugins/action/dtc/prepare_msite_data.py +++ b/plugins/action/dtc/prepare_msite_data.py @@ -77,7 +77,7 @@ def run(self, tmp=None, task_vars=None): child_fabrics_data[fabric_name].update({'switches': ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric_name, fabric['cluster'])}) child_fabrics_data[fabric_name].update({'cluster': fabric['cluster']}) results['child_fabrics_data'] = child_fabrics_data - + else: msd_fabric_associations = self._execute_module( module_name="cisco.dcnm.dcnm_rest", diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index 122f34820..eb37ab156 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -1,91 +1,91 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." - when: - - switch_list.response.DATA | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) - -- name: Get network list - cisco.dcnm.dcnm_rest: - method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" - register: networkList - -- name: Get network attachments list - cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments - register: networkAttachmentList - -- name: Filter networks to be removed - cisco.nac_dc_vxlan.dtc.fed_overlay_check: - model_data: "{{ MD_Extended }}" - ndfc_data: "{{ networkList.response.DATA }}" - ndfc_attachment_data: "{{ networkAttachmentList.response.DATA }}" - check_type: "network" - register: not_required_networks - -- name: Remove network attachments - cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments - json_data: "{{ not_required_networks.attachments_payload | to_json }}" - register: network_attachment_result - when: - - switch_list.response.DATA | length > 0 - - not_required_networks.attachments_payload | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) - -- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} - cisco.dcnm.dcnm_rest: - method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" - register: config_save - ignore_errors: true - -- name: Deploy for network attachments removal - cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_networks.deploy_payload | join(',') }}?forceShowRun=false - when: - - switch_list.response.DATA | length > 0 - - not_required_networks.deploy_payload | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) - -- name: Remove networks - cisco.dcnm.dcnm_rest: - method: DELETE - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/networks?network-names={{ not_required_networks.payload | join(',') }} - register: network_attachment_result - when: - - switch_list.response.DATA | length > 0 - - not_required_networks.payload | length > 0 - - (network_delete_mode is defined) and (network_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "---------------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" - - "---------------------------------------------------------------------------------------------------------------" - when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Get network list + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" + register: networkList + +- name: Get network attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + register: networkAttachmentList + +- name: Filter networks to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ networkList.response.DATA }}" + ndfc_attachment_data: "{{ networkAttachmentList.response.DATA }}" + check_type: "network" + register: not_required_networks + +- name: Remove network attachments + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments + json_data: "{{ not_required_networks.attachments_payload | to_json }}" + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_networks.attachments_payload | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" + register: config_save + ignore_errors: true + +- name: Deploy for network attachments removal + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_networks.deploy_payload | join(',') }}?forceShowRun=false + when: + - switch_list.response.DATA | length > 0 + - not_required_networks.deploy_payload | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- name: Remove networks + cisco.dcnm.dcnm_rest: + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/networks?network-names={{ not_required_networks.payload | join(',') }} + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_networks.payload | length > 0 + - (network_delete_mode is defined) and (network_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "---------------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" + - "---------------------------------------------------------------------------------------------------------------" + when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) \ No newline at end of file diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index a1d7bc421..cb5ffbde0 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -1,94 +1,94 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT ---- - -- ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." - when: - - switch_list.response.DATA | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - -- name: Get vrf list - cisco.dcnm.dcnm_rest: - method: GET - path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" - register: vrfList - -- name: Get vrf attachments list - cisco.dcnm.dcnm_rest: - method: GET - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments - register: vrfAttachmentList - -- name: Filter vrfs to be removed - cisco.nac_dc_vxlan.dtc.fed_overlay_check: - model_data: "{{ MD_Extended }}" - ndfc_data: "{{ vrfList.response.DATA }}" - ndfc_attachment_data: "{{ vrfAttachmentList.response.DATA }}" - check_type: "vrf" - register: not_required_vrfs - -- name: Remove vrf attachments - cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments - json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" - register: vrf_attachment_result - when: - - switch_list.response.DATA | length > 0 - - not_required_vrfs.attachments_payload | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - -- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} - cisco.dcnm.dcnm_rest: - method: POST - path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" - register: config_save - ignore_errors: true - -- name: Deploy for vrf attachments removal - cisco.dcnm.dcnm_rest: - method: POST - path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false - vars: - ansible_command_timeout: 3000 - ansible_connect_timeout: 3000 - when: - - switch_list.response.DATA | length > 0 - - not_required_vrfs.deploy_payload | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - -- name: Remove vrfs - cisco.dcnm.dcnm_rest: - method: DELETE - path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/vrfs?vrf-names={{ not_required_vrfs.payload | join(',') }} - register: network_attachment_result - when: - - switch_list.response.DATA | length > 0 - - not_required_vrfs.payload | length > 0 - - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) - -- ansible.builtin.debug: - msg: - - "--------------------------------------------------------------------------------------------------------" - - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" - - "--------------------------------------------------------------------------------------------------------" - when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) +# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT +--- + +- ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." + when: + - switch_list.response.DATA | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Get vrf list + cisco.dcnm.dcnm_rest: + method: GET + path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs" + register: vrfList + +- name: Get vrf attachments list + cisco.dcnm.dcnm_rest: + method: GET + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + register: vrfAttachmentList + +- name: Filter vrfs to be removed + cisco.nac_dc_vxlan.dtc.fed_overlay_check: + model_data: "{{ MD_Extended }}" + ndfc_data: "{{ vrfList.response.DATA }}" + ndfc_attachment_data: "{{ vrfAttachmentList.response.DATA }}" + check_type: "vrf" + register: not_required_vrfs + +- name: Remove vrf attachments + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments + json_data: "{{ not_required_vrfs.attachments_payload | to_json }}" + register: vrf_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_vrfs.attachments_payload | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} + cisco.dcnm.dcnm_rest: + method: POST + path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" + register: config_save + ignore_errors: true + +- name: Deploy for vrf attachments removal + cisco.dcnm.dcnm_rest: + method: POST + path: /appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-deploy/{{ not_required_vrfs.deploy_payload | join(',') }}?forceShowRun=false + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: + - switch_list.response.DATA | length > 0 + - not_required_vrfs.deploy_payload | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- name: Remove vrfs + cisco.dcnm.dcnm_rest: + method: DELETE + path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/bulk-delete/vrfs?vrf-names={{ not_required_vrfs.payload | join(',') }} + register: network_attachment_result + when: + - switch_list.response.DATA | length > 0 + - not_required_vrfs.payload | length > 0 + - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) + +- ansible.builtin.debug: + msg: + - "--------------------------------------------------------------------------------------------------------" + - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" + - "--------------------------------------------------------------------------------------------------------" + when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) \ No newline at end of file From 9dc17683814b2f37e730e2187ccb11e50eba5de4 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Wed, 3 Sep 2025 11:49:30 +0100 Subject: [PATCH 152/183] more fixing santies --- plugins/plugin_utils/data_model_keys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 0dacd322d..3c7220c1b 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -27,7 +27,7 @@ root_key = 'vxlan' # Keys here match data model schema -# type: enum('VXLAN_EVPN', 'MSD', 'MCF', 'ISN') +# type: enum('VXLAN_EVPN', 'MSD', 'MFD', 'ISN', 'External') model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MFD': {}, 'ISN': {}, 'External': {}} From 1f5187a43d76a8ffa924f1c731732fd47c18bec1 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Wed, 3 Sep 2025 15:51:23 +0100 Subject: [PATCH 153/183] reverting change to edge connections --- roles/dtc/common/templates/ndfc_edge_connections.j2 | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 index 48b09e8a3..690b68c06 100644 --- a/roles/dtc/common/templates/ndfc_edge_connections.j2 +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -13,26 +13,17 @@ - ip: {{ link.source_device_ip }} policies: - create_additional_policy: False -{% if '.' in link.source_interface %} - description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device + '_' + link.source_interface.split('.')[1] }} -{% else %} description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} -{% endif %} name: bgp_peer_template_dci_underlay_jython policy_vars: BGP_PASSWORD: "{{ link.bgp_section.bgp_password | default('') }}" BGP_PASSWORD_ENABLE: {{ link.bgp_section.bgp_password_enable | default('true') }} -{% if '.' in link.source_interface %} - TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' + '_' + link.source_interface.split('.')[1] }} -{% else %} TEMPLATE_NAME: {{ MD_Extended.vxlan.fabric.name + '-' + link.dest_fabric + '-IPV4-EBGP' }} -{% endif %} NEIGHBOR_ASN: "{{ link.bgp_section.neighbor_asn }}" OVERRIDE_LOCAL_ASN: false CONF: |2- {{ link.bgp_section.peer_template_freeform | default('') | indent(14, false)}} priority: 475 -{% if '.' not in link.source_interface %} - create_additional_policy: False description: {{ 'nace_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} name: ebgp_underlay_dci_template @@ -57,6 +48,5 @@ {{ link.bgp_section.interface_freeform | default('') | indent(14, false)}} FABRIC_NAME: {{ MD_Extended.vxlan.fabric.name }} priority: 500 -{% endif %} {% endfor %} {% endif %} From a1bd52bceebf1f88a017290e195ce8cdf3799547 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 9 Sep 2025 11:04:59 +0100 Subject: [PATCH 154/183] move attach loopsback vrf template --- roles/dtc/common/tasks/msd/ndfc_vrfs.yml | 9 +++++---- .../common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 | 0 roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 diff --git a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml index 21849224a..1c204f92a 100644 --- a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml @@ -86,14 +86,15 @@ - name: Set file_name Var for loopback attachments ansible.builtin.set_fact: - file_name: "{{ MD_Extended.vxlan.fabric.name }}_attach_vrfs_loopbacks.yml" + file_name: "attach_vrfs_loopbacks.yml" delegate_to: localhost # Check with Matt and Pete on how we want to handle VRF loopbacks for MSD -# - name: Build VRFs Attach List From Template for loopback +# - name: Build VRFs Attach List From Template # ansible.builtin.template: -# src: ndfc_attach_vrfs_loopbacks.j2 +# src: "{{ role_path }}/../common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2" # dest: "{{ path_name }}{{ file_name }}" +# mode: '0644' # delegate_to: localhost # - name: Create Empty vrf_config Var @@ -105,5 +106,5 @@ # ansible.builtin.set_fact: # vrf_attach_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" # when: > -# (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 +# (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 # delegate_to: localhost diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 new file mode 100644 index 000000000..e69de29bb diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index cb5ffbde0..60f24ffdd 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -91,4 +91,3 @@ - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" - "--------------------------------------------------------------------------------------------------------" when: not ((vrf_delete_mode is defined) and (vrf_delete_mode is true|bool)) - \ No newline at end of file From 5485c90ce651898eef245dbfb23f4276d57bbaac Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 9 Sep 2025 17:15:42 +0100 Subject: [PATCH 155/183] edge connections update --- roles/dtc/common/templates/ndfc_edge_connections.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_edge_connections.j2 b/roles/dtc/common/templates/ndfc_edge_connections.j2 index 690b68c06..c168c7eb9 100644 --- a/roles/dtc/common/templates/ndfc_edge_connections.j2 +++ b/roles/dtc/common/templates/ndfc_edge_connections.j2 @@ -13,7 +13,7 @@ - ip: {{ link.source_device_ip }} policies: - create_additional_policy: False - description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.dest_device }} + description: {{ 'nace_bgp_peer_template_dci_underlay_jython_' + link.source_device + '_' + link.source_interface + '_' + link.dest_device }} name: bgp_peer_template_dci_underlay_jython policy_vars: BGP_PASSWORD: "{{ link.bgp_section.bgp_password | default('') }}" @@ -25,7 +25,7 @@ {{ link.bgp_section.peer_template_freeform | default('') | indent(14, false)}} priority: 475 - create_additional_policy: False - description: {{ 'nace_ebgp_underlay_dci_template_' + link.source_device + '_' + link.dest_device }} + description: {{ 'nace_ebgp_underlay_dci_template_' + link.source_device + '_' + link.source_interface + '_' + link.dest_device }} name: ebgp_underlay_dci_template policy_vars: INTF_NAME: {{ link.source_interface }} From 030d98f25a8958b4ff5a670e1e7b26723b24ade5 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 16 Sep 2025 15:02:44 +0100 Subject: [PATCH 156/183] Aligning with pre-prov breakout changes --- roles/dtc/common/tasks/common/ndfc_interface_all.yml | 2 +- .../common/tasks/common/ndfc_interface_breakout.yml | 2 +- roles/dtc/remove/tasks/common/interfaces.yml | 12 +----------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/roles/dtc/common/tasks/common/ndfc_interface_all.yml b/roles/dtc/common/tasks/common/ndfc_interface_all.yml index 6c8cf7120..a66f9bc6c 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_all.yml @@ -70,7 +70,7 @@ interface_vpc + int_loopback_config + interface_dot1q }}" - when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 + # when: MD_Extended.vxlan.topology.interfaces.modes.all.count > 0 delegate_to: localhost - name: Save interface_all diff --git a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml index a8bbdc5eb..cd47a0bed 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml @@ -87,7 +87,7 @@ - name: Set interface_breakout_remove Var ansible.builtin.set_fact: interface_breakout_remove: "{{ lookup('file', path_name + file_name_remove) | from_yaml }}" - when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 + # when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 delegate_to: localhost - name: Diff Previous and Current Data Files diff --git a/roles/dtc/remove/tasks/common/interfaces.yml b/roles/dtc/remove/tasks/common/interfaces.yml index 049da0ce4..c48421c42 100644 --- a/roles/dtc/remove/tasks/common/interfaces.yml +++ b/roles/dtc/remove/tasks/common/interfaces.yml @@ -44,21 +44,11 @@ - switch_list.response.DATA | length > 0 - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) -- name: Filter out breakout interfaces for unreachable switches - ansible.builtin.set_fact: - filtered_interface_all: "{{ vars_common_local.interface_all | rejectattr('type', 'equalto', 'breakout') | list + (vars_common_local.interface_all | selectattr('type', 'equalto', 'breakout') | rejectattr('switch.0', 'in', unreachable_switch_ips) | list) }}" - vars: - unreachable_switch_ips: "{{ switch_list.response.DATA | selectattr('status', 'equalto', 'Unreachable') | map(attribute='ipAddress') | list }}" - when: - - switch_list.response.DATA | length > 0 - - (interface_delete_mode is defined) and (interface_delete_mode is true|bool) - - vars_common_local.interface_all is defined - - name: Remove Unmanaged Fabric Interfaces in Nexus Dashboard cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ filtered_interface_all | default(vars_common_local.interface_all) }}" + config: "{{ vars_common_local.interface_all | default(vars_common_local.interface_all) }}" # deploy: false vars: ansible_command_timeout: 3000 From 0d84fc480606245c9bffa527a640aa1e2c139aa7 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 09:24:16 +0100 Subject: [PATCH 157/183] few small bugs --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 4 ++-- roles/dtc/common/tasks/sub_main_mfd.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index e3fc702ae..1805ae094 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -86,8 +86,8 @@ ansible.builtin.set_fact: file_name: "ndfc_attach_network_switches_ports.yml" file_name2: "ndfc_attach_network_switches.yml" - switches: [] - networks: [] + network_switches: [] + network_switches_ports: [] delegate_to: localhost - name: Build VRFs Attach List for switches From Template diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mfd.yml index 19e267272..c30b77038 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mfd.yml @@ -83,7 +83,7 @@ switches_in_fabric: "{{ switches_in_fabric }}" net_config: "{{ net_config }}" network_switches: "{{ network_switches }}" - network_switches_ports: "{{ network_switches_ports }}" + network_switches_ports: "{{ network_switches_ports }}" vrf_config: "{{ vrf_config }}" vrf_attach_config: "{{ vrf_attach_config }}" - name: Run Diff Flags From ff2e3e1f9ab659ee4fd4ae7cfa4c5423ea426024 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 09:35:32 +0100 Subject: [PATCH 158/183] another variable undefined bug --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index 1805ae094..cbeacadbf 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -86,18 +86,20 @@ ansible.builtin.set_fact: file_name: "ndfc_attach_network_switches_ports.yml" file_name2: "ndfc_attach_network_switches.yml" + switches: [] + networks: [] network_switches: [] network_switches_ports: [] delegate_to: localhost -- name: Build VRFs Attach List for switches From Template +- name: Build Network Attach List for switches From Template ansible.builtin.template: src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2" dest: "{{ path_name }}{{ file_name }}" mode: '0644' delegate_to: localhost -- name: Build VRFs Attach List for switches and ports From Template +- name: Build Network Attach List for switches and ports From Template ansible.builtin.template: src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2" dest: "{{ path_name }}{{ file_name2 }}" From cfced28dd67e2a6917d6e5b1aa36e1e6d1fd1b67 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 09:55:38 +0100 Subject: [PATCH 159/183] more bugs around network refactoring --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 4 ++-- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index cbeacadbf..720f0ce43 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -86,8 +86,8 @@ ansible.builtin.set_fact: file_name: "ndfc_attach_network_switches_ports.yml" file_name2: "ndfc_attach_network_switches.yml" - switches: [] - networks: [] + switches: [] # check why this is defined here to be used in the template + networks: [] # same for this network_switches: [] network_switches_ports: [] delegate_to: localhost diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 8b831d690..6e89a72ce 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -78,7 +78,7 @@ json_data: "{{ vars_common_mfd.vrf_attach_config | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - - vars_common_mfd.changes_detected_vrfs + - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get vrf attachments list @@ -154,8 +154,8 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - - vars_common_mfd.network_switches is defined - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.network_switches is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -165,8 +165,8 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" when: - - vars_common_mfd.network_switches_ports is defined - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.network_switches_ports is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -188,7 +188,6 @@ check_type: "network_attach" register: network_attachments_payload when: - - MD_Extended.vxlan.fabric.type == 'MFD' - MD_Extended.vxlan.multisite.overlay.networks is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -199,8 +198,8 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - - vars_common_mfd.network_switches_ports is defined - MD_Extended.vxlan.multisite.overlay.networks is defined + - vars_common_mfd.network_switches_ports is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -210,4 +209,5 @@ msite_data: "{{ MD_Multisite }}" fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_network_results - tags: "{{ nac_tags.create_vrfs_networks }}" \ No newline at end of file + tags: "{{ nac_tags.create_vrfs_networks }}" + \ No newline at end of file From f49b86107f224d4d3f843ade9b90f3e7c9a8f31c Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 10:00:00 +0100 Subject: [PATCH 160/183] removed some when clauses that weren't required --- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 6e89a72ce..81fc45e3a 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -155,7 +155,6 @@ json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.network_switches is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -166,7 +165,6 @@ json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.network_switches_ports is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -199,7 +197,6 @@ json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.network_switches_ports is defined - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" @@ -210,4 +207,3 @@ fabric_type: "{{ MD_Extended.vxlan.fabric.type }}" register: child_fabric_network_results tags: "{{ nac_tags.create_vrfs_networks }}" - \ No newline at end of file From 5b3a14a443f6897ff6b823230132a0b8cb800052 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 10:20:22 +0100 Subject: [PATCH 161/183] fix clause for multisite overlay keys --- roles/dtc/common/tasks/mfd/ndfc_networks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mfd/ndfc_networks.yml index 720f0ce43..0d8add6a1 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mfd/ndfc_networks.yml @@ -122,5 +122,5 @@ ansible.builtin.set_fact: network_switches: "{{ lookup('file', path_name + file_name) | from_yaml }}" network_switches_ports: "{{ lookup('file', path_name + file_name2) | from_yaml }}" - when: (MD_Extended.vxlan.overlay.networks | default([])) | length > 0 + when: (MD_Extended.vxlan.multisite.overlay.networks | default([])) | length > 0 delegate_to: localhost From 2c44a225912d99d6a7e078d5b5937ca2a21a52d4 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 10:24:02 +0100 Subject: [PATCH 162/183] changing all clauses to AND in network create --- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 21 +++++++------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 81fc45e3a..c06bc8dfc 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -134,8 +134,7 @@ path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" register: fed_networks_existing when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Networks for Federated @@ -144,8 +143,7 @@ loop_control: loop_var: network when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach switches for all networks @@ -154,8 +152,7 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks @@ -164,8 +161,7 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get network attachments list @@ -174,8 +170,7 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter network attachments to be removed @@ -186,8 +181,7 @@ check_type: "network_attach" register: network_attachments_payload when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks @@ -196,8 +190,7 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined - - vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric Networks From 9a7b7467c8ac7a6c83692eeb48b5556cb865e2bf Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 10:26:42 +0100 Subject: [PATCH 163/183] clause test --- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index c06bc8dfc..5eac4b709 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -152,7 +152,7 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks and vars_common_mfd.network_switches != [] tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks From 75d93bdab69c34b62c7ab561da13b31e5ddd27c4 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 10:44:33 +0100 Subject: [PATCH 164/183] updated all clauses in networks and vrf create --- roles/dtc/create/tasks/mfd/vrfs_networks.yml | 35 ++++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mfd/vrfs_networks.yml index 5eac4b709..e73ed3e80 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mfd/vrfs_networks.yml @@ -54,6 +54,7 @@ register: dcnm_vrf_existing when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -64,6 +65,7 @@ loop_var: vrf when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -78,6 +80,7 @@ json_data: "{{ vars_common_mfd.vrf_attach_config | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -88,6 +91,7 @@ register: vrfAttachmentList when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -100,6 +104,7 @@ register: not_required_vrfs when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -111,6 +116,7 @@ register: vrf_attachment_result when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -122,6 +128,7 @@ register: child_fabric_vrf_results when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined + - MD_Extended.vxlan.multisite.overlay.vrfs - vars_common_mfd.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" @@ -134,7 +141,9 @@ path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks" register: fed_networks_existing when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Networks for Federated @@ -143,7 +152,9 @@ loop_control: loop_var: network when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach switches for all networks @@ -152,7 +163,9 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks and vars_common_mfd.network_switches != [] + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks @@ -161,7 +174,9 @@ method: "POST" json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get network attachments list @@ -170,7 +185,9 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments register: networkAttachmentList when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter network attachments to be removed @@ -181,7 +198,9 @@ check_type: "network_attach" register: network_attachments_payload when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks @@ -190,7 +209,9 @@ path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/networks/attachments json_data: "{{ network_attachments_payload.attachments_payload | to_json }}" when: - - MD_Extended.vxlan.multisite.overlay.networks is defined and vars_common_mfd.changes_detected_networks + - MD_Extended.vxlan.multisite.overlay.networks is defined + - MD_Extended.vxlan.multisite.overlay.networks + - vars_common_mfd.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric Networks From 0e9fd98df04b69a53a13e4b33739144c9869a0b9 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 18 Sep 2025 17:42:36 +0100 Subject: [PATCH 165/183] Added default of interface_all --- roles/dtc/common/tasks/common/ndfc_interface_all.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/common/tasks/common/ndfc_interface_all.yml b/roles/dtc/common/tasks/common/ndfc_interface_all.yml index a66f9bc6c..6eaf628b6 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_all.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_all.yml @@ -59,7 +59,7 @@ - name: Set interface_all Var ansible.builtin.set_fact: interface_all: "{{ - interface_breakout_remove + + (interface_breakout_remove | default([]) | list) + interface_access + interface_access_po + interface_trunk + From 6be27bdc64f42525a1e8518d67eb2404c9173d7c Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 19 Sep 2025 15:22:16 +0100 Subject: [PATCH 166/183] quoting a couple of values --- .../ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 index 121d16220..ebb452421 100644 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 +++ b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 @@ -4,8 +4,8 @@ ENABLE_PVLAN: false {% endif %} ANYCAST_GW_MAC: {{ vxlan.multisite.anycast_gateway_mac | default(defaults.vxlan.multisite.anycast_gateway_mac) }} - MS_LOOPBACK_ID: {{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }} - BGW_ROUTING_TAG: {{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }} + MS_LOOPBACK_ID: "{{ vxlan.multisite.vtep_loopback_id | default(defaults.vxlan.multisite.vtep_loopback_id) }}" + BGW_ROUTING_TAG: "{{ vxlan.multisite.bgw_ip_tag | default(defaults.vxlan.multisite.bgw_ip_tag) }}" TOR_AUTO_DEPLOY: false FF: "MSD" FABRIC_TYPE: "MFD" From 39c88cedb5e7d159042ff6c9e2248828f32a10ca Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 22 Sep 2025 16:08:10 +0100 Subject: [PATCH 167/183] Removed white spaces --- plugins/action/dtc/manage_child_fabric_networks.py | 4 ++-- plugins/action/dtc/manage_child_fabric_vrfs.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/action/dtc/manage_child_fabric_networks.py b/plugins/action/dtc/manage_child_fabric_networks.py index 28ea6e1b7..da45453e6 100644 --- a/plugins/action/dtc/manage_child_fabric_networks.py +++ b/plugins/action/dtc/manage_child_fabric_networks.py @@ -221,7 +221,7 @@ def run(self, tmp=None, task_vars=None): f"rest/top-down/fabrics/{child_fabric}/networks/{network['name']}") else: put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}" - + ndfc_net_update = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ @@ -231,7 +231,7 @@ def run(self, tmp=None, task_vars=None): }, task_vars=task_vars, tmp=tmp - ) + ) # Successful response: # { diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index fe937114a..a63a2a281 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -159,7 +159,7 @@ def run(self, tmp=None, task_vars=None): f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: get_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" - + ndfc_vrf = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ @@ -228,11 +228,10 @@ def run(self, tmp=None, task_vars=None): rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) if fabric_type == 'MFD': - put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" - f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") + put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" - + ndfc_vrf_update = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ From 55639460fb246b7621d757c57cfff01f669b9ac1 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 22 Sep 2025 16:13:19 +0100 Subject: [PATCH 168/183] splitting lines --- plugins/action/dtc/manage_child_fabric_vrfs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index a63a2a281..8a93f8443 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -228,7 +228,8 @@ def run(self, tmp=None, task_vars=None): rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) if fabric_type == 'MFD': - put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") + put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" + f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: put_path = f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}" From dd235bf12e242846eeb15bcf9bbc0cb2cce73d95 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 22 Sep 2025 16:38:22 +0100 Subject: [PATCH 169/183] removing old file --- ...logy_switch_vpc_portchannel_consistency.py | 172 ------------------ 1 file changed, 172 deletions(-) delete mode 100644 roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py diff --git a/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py b/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py deleted file mode 100644 index a38650fc9..000000000 --- a/roles/validate/files/rules/external/311_topology_switch_vpc_portchannel_consistency.py +++ /dev/null @@ -1,172 +0,0 @@ -class Rule: - id = "311" - description = "Verify VPC port-channel consistency between peer switches" - severity = "HIGH" - - @classmethod - def match(cls, inventory): - results = [] - switches = [] - - # Check for the 'switches' key in the data model - dm_check = cls.data_model_key_check( - inventory, ['vxlan', 'topology', 'switches'] - ) - if 'switches' in dm_check['keys_data']: - switches = inventory['vxlan']['topology']['switches'] - - # Check for VPC peers - vpc_peers_check = cls.data_model_key_check( - inventory, ['vxlan', 'topology', 'vpc_peers'] - ) - if 'vpc_peers' not in vpc_peers_check['keys_data']: - return results # No VPC peers defined, nothing to validate - - vpc_peers = inventory['vxlan']['topology']['vpc_peers'] - - # Create a lookup dictionary for switches by name - switch_lookup = {switch.get('name'): switch for switch in switches} - - # Iterate through VPC peer pairs - for vpc_pair in vpc_peers: - peer1_name = vpc_pair.get('peer1') - peer2_name = vpc_pair.get('peer2') - domain_id = vpc_pair.get('domain_id') - - peer1_switch = switch_lookup.get(peer1_name) - peer2_switch = switch_lookup.get(peer2_name) - - if not peer1_switch or not peer2_switch: - continue # Skip if switches not found - - # Find VPC port-channels on each switch - peer1_vpc_channels = cls.find_vpc_port_channels(peer1_switch) - peer2_vpc_channels = cls.find_vpc_port_channels(peer2_switch) - - # Check if one peer has VPC port-channels but the other doesn't - if peer1_vpc_channels and not peer2_vpc_channels: - pc_names = [pc['name'] for pc in peer1_vpc_channels] - results.append( - f"VPC pair (domain {domain_id}): Switch '{peer1_name}' " - f"has VPC port-channel(s) {pc_names}, but peer switch " - f"'{peer2_name}' has no VPC port-channels defined." - ) - elif peer2_vpc_channels and not peer1_vpc_channels: - pc_names = [pc['name'] for pc in peer2_vpc_channels] - results.append( - f"VPC pair (domain {domain_id}): Switch '{peer2_name}' " - f"has VPC port-channel(s) {pc_names}, but peer switch " - f"'{peer1_name}' has no VPC port-channels defined." - ) - elif peer1_vpc_channels and peer2_vpc_channels: - # Both peers have VPC port-channels, validate they match - results.extend(cls.validate_vpc_channel_consistency( - peer1_name, peer1_vpc_channels, peer2_name, - peer2_vpc_channels, domain_id - )) - - return results - - @classmethod - def find_vpc_port_channels(cls, switch): - """Find all port-channels with mode 'vpc_peer_link' on a switch""" - vpc_channels = [] - if switch.get('interfaces'): - for interface in switch['interfaces']: - interface_name = interface.get('name', '') - is_pc = (interface_name.startswith('port-channel') or - interface_name.startswith('po')) - if is_pc and interface.get('mode') == 'vpc_peer_link': - vpc_channels.append(interface) - return vpc_channels - - @classmethod - def validate_vpc_channel_consistency(cls, peer1_name, peer1_channels, - peer2_name, peer2_channels, - domain_id): - """Validate that VPC port-channels are consistent between peers""" - results = [] - - # Check if the number of VPC port-channels match - if len(peer1_channels) != len(peer2_channels): - results.append( - f"VPC pair (domain {domain_id}): Mismatch in number of " - f"VPC port-channels - '{peer1_name}' has " - f"{len(peer1_channels)}, '{peer2_name}' has " - f"{len(peer2_channels)}" - ) - return results - - # Sort channels by port-channel ID for comparison - def get_pc_id(interface): - return cls.extract_pc_id(interface.get('name', '')) - - peer1_sorted = sorted(peer1_channels, key=get_pc_id) - peer2_sorted = sorted(peer2_channels, key=get_pc_id) - - # Compare each pair of port-channels - for peer1_pc, peer2_pc in zip(peer1_sorted, peer2_sorted): - peer1_pc_id = cls.extract_pc_id(peer1_pc.get('name', '')) - peer2_pc_id = cls.extract_pc_id(peer2_pc.get('name', '')) - - # Check if port-channel IDs match - if peer1_pc_id != peer2_pc_id: - results.append( - f"VPC pair (domain {domain_id}): Port-channel ID " - f"mismatch - '{peer1_name}' has " - f"'{peer1_pc.get('name')}', '{peer2_name}' has " - f"'{peer2_pc.get('name')}'" - ) - - # Check if pc_mode matches (if defined on both) - peer1_pc_mode = peer1_pc.get('pc_mode') - peer2_pc_mode = peer2_pc.get('pc_mode') - if (peer1_pc_mode and peer2_pc_mode and - peer1_pc_mode != peer2_pc_mode): - results.append( - f"VPC pair (domain {domain_id}): Port-channel mode " - f"mismatch on PC{peer1_pc_id} - '{peer1_name}' has " - f"'{peer1_pc_mode}', '{peer2_name}' has " - f"'{peer2_pc_mode}'" - ) - - # Check if trunk_allowed_vlans matches (if defined on both) - peer1_vlans = peer1_pc.get('trunk_allowed_vlans') - peer2_vlans = peer2_pc.get('trunk_allowed_vlans') - if peer1_vlans and peer2_vlans and peer1_vlans != peer2_vlans: - results.append( - f"VPC pair (domain {domain_id}): VLAN configuration " - f"mismatch on PC{peer1_pc_id} - '{peer1_name}' allows " - f"'{peer1_vlans}', '{peer2_name}' allows " - f"'{peer2_vlans}'" - ) - - return results - - @classmethod - def extract_pc_id(cls, interface_name): - """Extract port-channel ID from interface name""" - import re - match = re.search(r'(?:port-channel|po)(\d+)', interface_name.lower()) - return int(match.group(1)) if match else 0 - - @classmethod - def data_model_key_check(cls, tested_object, keys): - """ - Helper method to check the presence of keys in a nested dictionary. - """ - dm_key_dict = { - 'keys_found': [], 'keys_not_found': [], - 'keys_data': [], 'keys_no_data': [] - } - for key in keys: - if tested_object and key in tested_object: - dm_key_dict['keys_found'].append(key) - tested_object = tested_object[key] - if tested_object: - dm_key_dict['keys_data'].append(key) - else: - dm_key_dict['keys_no_data'].append(key) - else: - dm_key_dict['keys_not_found'].append(key) - return dm_key_dict From 9c91d7dd72b04ce18048f1cb0b639fd2fd1a9ca4 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 22 Sep 2025 16:39:59 +0100 Subject: [PATCH 170/183] removing duplicate lines --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index f7389fbef..ad89f2359 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,6 @@ interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false link_vpc_delete_mode: false -multisite_network_delete_mode: false -multisite_vrf_delete_mode: false network_delete_mode: false policy_delete_mode: false vpc_delete_mode: false From dd6b2d0638c6a184cfeaffeab798475eca8febfb Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 22 Sep 2025 11:45:37 -0400 Subject: [PATCH 171/183] shift lists back to * --- README.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index ad89f2359..e816ff3f6 100644 --- a/README.md +++ b/README.md @@ -301,9 +301,9 @@ export NDFC_SW_PASSWORD=Admin_123 This collection supports flexible credential management for network switches with three security levels: -- **🔐 Ansible Vault**: Encrypted credentials for production deployments -- **✅ Environment Variables**: Secure credential injection for CI/CD pipelines -- **⚠️ Plain Text**: Simple credentials for lab testing only +* **🔐 Ansible Vault**: Encrypted credentials for production deployments +* **✅ Environment Variables**: Secure credential injection for CI/CD pipelines +* **⚠️ Plain Text**: Simple credentials for lab testing only The system supports both switch-specific credentials and group-level defaults with automatic fallback. Environment variable lookups can be configured in group_vars for enhanced security and automation compatibility. @@ -317,19 +317,19 @@ The following quickstart repository is available to provide a step by step guide This collection is intended for use with the following release versions: -- `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.1` -- `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.2` -- `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.3` -- `Cisco Nexus Dashboard Release 4.1.1g` - Unified Nexus Dashboard Tech Preview +* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.1` +* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.2` +* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.3` +* `Cisco Nexus Dashboard Release 4.1.1g` - Unified Nexus Dashboard Tech Preview ## Ansible Version Compatibility This collection has been tested against following Ansible Core versions: -- `2.14.x` -- `2.15.x` -- `2.16.x` -- `2.17.x` +* `2.14.x` +* `2.15.x` +* `2.16.x` +* `2.17.x` Plugins, roles and modules within a collection may be tested with only specific Ansible versions. A collection may contain metadata that identifies these versions. @@ -413,19 +413,19 @@ For example, if VRFs and Networks are added/changed/removed in the model data fi This capability is not available under the following conditions: -- Control flag `force_run_all` under group_vars is set to `true`. -- When using ansible tags to control execution. -- When one of the following roles failed to complete on the previous run. - - `cisco.nac_dc_vxlan.validate` - - `cisco.nac_dc_vxlan.create` - - `cisco.nac_dc_vxlan.deploy` - - `cisco.nac_dc_vxlan.remove` +* Control flag `force_run_all` under group_vars is set to `true`. +* When using ansible tags to control execution. +* When one of the following roles failed to complete on the previous run. + * `cisco.nac_dc_vxlan.validate` + * `cisco.nac_dc_vxlan.create` + * `cisco.nac_dc_vxlan.deploy` + * `cisco.nac_dc_vxlan.remove` If any of these conditions is true then all roles/sections will be run. ### See Also -- [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details. +* [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details. ## Multi-Site Domain for VXLAN BGP EVPN Fabrics @@ -448,14 +448,14 @@ We welcome community contributions to this collection. If you find problems, ple ## Changelogs -- [Changelog](https://github.com/netascode/ansible-dc-vxlan/blob/develop/CHANGELOG.rst) +* [Changelog](https://github.com/netascode/ansible-dc-vxlan/blob/develop/CHANGELOG.rst) ## More Information -- [Cisco Nexus Dashboard and Services Deployment and Upgrade Guide](https://www.cisco.com/c/en/us/td/docs/dcn/nd/3x/deployment/cisco-nexus-dashboard-and-services-deployment-guide-321.html) -- [Cisco Nexus Dashboard Fabric Controller (NDFC) User Content for LAN Configuration Guide](https://www.cisco.com/c/en/us/td/docs/dcn/ndfc/1222/collections/ndfc-user-content-1222-lan.html) -- [Ansible User Guide](https://docs.ansible.com/ansible/latest/user_guide/index.html) -- [Ansible Developer Guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html) +* [Cisco Nexus Dashboard and Services Deployment and Upgrade Guide](https://www.cisco.com/c/en/us/td/docs/dcn/nd/3x/deployment/cisco-nexus-dashboard-and-services-deployment-guide-321.html) +* [Cisco Nexus Dashboard Fabric Controller (NDFC) User Content for LAN Configuration Guide](https://www.cisco.com/c/en/us/td/docs/dcn/ndfc/1222/collections/ndfc-user-content-1222-lan.html) +* [Ansible User Guide](https://docs.ansible.com/ansible/latest/user_guide/index.html) +* [Ansible Developer Guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html) ## Licensing From 26f1b1f9bf2caccb41c5d16943eb9bd072f64266 Mon Sep 17 00:00:00 2001 From: Matt Tarkington Date: Mon, 22 Sep 2025 15:01:22 -0400 Subject: [PATCH 172/183] remove unused detection var --- roles/common_global/defaults/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/common_global/defaults/main.yml b/roles/common_global/defaults/main.yml index aa11025f6..d18479b72 100644 --- a/roles/common_global/defaults/main.yml +++ b/roles/common_global/defaults/main.yml @@ -33,7 +33,6 @@ force_run_all: false # Parameters to enable/disable remove role tasks -child_fabric_delete_mode: false interface_delete_mode: false inventory_delete_mode: false link_fabric_delete_mode: false From d0b01f56fbd492f3f7efa7d4f0796df553cbef93 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 23 Sep 2025 09:57:52 +0100 Subject: [PATCH 173/183] various updates to remove old config --- .../tasks/common/ndfc_interface_breakout.yml | 21 ----------- roles/dtc/common/tasks/msd/ndfc_vrfs.yml | 9 ++--- .../ndfc_attach_vrfs_loopbacks_fed.j2 | 0 .../ndfc_interface_breakout_remove.j2 | 37 ------------------- .../ndfc_route_control/ndfc_prefix_list.j2 | 4 +- roles/dtc/create/tasks/main.yml | 12 +++--- roles/dtc/create/tasks/sub_main_external.yml | 7 ---- roles/dtc/remove/tasks/common/interfaces.yml | 2 +- roles/dtc/remove/tasks/common/vpc_peers.yml | 16 +------- 9 files changed, 14 insertions(+), 94 deletions(-) delete mode 100644 roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 delete mode 100644 roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 diff --git a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml index cd47a0bed..562fee504 100644 --- a/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml +++ b/roles/dtc/common/tasks/common/ndfc_interface_breakout.yml @@ -29,7 +29,6 @@ - name: Set file_name Var ansible.builtin.set_fact: file_name: "ndfc_interface_breakout.yml" - file_name_remove: "ndfc_interface_breakout_remove.yml" delegate_to: localhost - name: Stat Previous File If It Exists @@ -52,13 +51,6 @@ delegate_to: localhost when: data_file_previous.stat.exists -- name: Delete Previous Remove Data File If It Exists - ansible.builtin.file: - state: absent - path: "{{ path_name }}{{ file_name_remove }}" - delegate_to: localhost - when: data_file_previous.stat.exists - - name: Build Interface ansible.builtin.template: src: ndfc_interfaces/ndfc_interface_breakout.j2 @@ -66,16 +58,9 @@ mode: '0644' delegate_to: localhost -- name: Build Interface Remove breakout - ansible.builtin.template: - src: ndfc_interfaces/ndfc_interface_breakout_remove.j2 - dest: "{{ path_name }}{{ file_name_remove }}" - delegate_to: localhost - - name: Initialize interface_breakout Var ansible.builtin.set_fact: interface_breakout: [] - interface_breakout_remove: [] delegate_to: localhost - name: Set interface_breakout Var @@ -84,12 +69,6 @@ when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 delegate_to: localhost -- name: Set interface_breakout_remove Var - ansible.builtin.set_fact: - interface_breakout_remove: "{{ lookup('file', path_name + file_name_remove) | from_yaml }}" - # when: MD_Extended.vxlan.topology.interfaces.modes.breakout.count > 0 - delegate_to: localhost - - name: Diff Previous and Current Data Files cisco.nac_dc_vxlan.dtc.diff_model_changes: file_name_previous: "{{ path_name }}{{ file_name }}.old" diff --git a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml index 1c204f92a..21849224a 100644 --- a/roles/dtc/common/tasks/msd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/msd/ndfc_vrfs.yml @@ -86,15 +86,14 @@ - name: Set file_name Var for loopback attachments ansible.builtin.set_fact: - file_name: "attach_vrfs_loopbacks.yml" + file_name: "{{ MD_Extended.vxlan.fabric.name }}_attach_vrfs_loopbacks.yml" delegate_to: localhost # Check with Matt and Pete on how we want to handle VRF loopbacks for MSD -# - name: Build VRFs Attach List From Template +# - name: Build VRFs Attach List From Template for loopback # ansible.builtin.template: -# src: "{{ role_path }}/../common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2" +# src: ndfc_attach_vrfs_loopbacks.j2 # dest: "{{ path_name }}{{ file_name }}" -# mode: '0644' # delegate_to: localhost # - name: Create Empty vrf_config Var @@ -106,5 +105,5 @@ # ansible.builtin.set_fact: # vrf_attach_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" # when: > -# (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 +# (MD_Extended.vxlan.overlay.vrfs | default([])) | length > 0 # delegate_to: localhost diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs_loopbacks_fed.j2 deleted file mode 100644 index e69de29bb..000000000 diff --git a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 b/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 deleted file mode 100644 index 065bc1a43..000000000 --- a/roles/dtc/common/templates/ndfc_interfaces/ndfc_interface_breakout_remove.j2 +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This NDFC breakout interface data structure is auto-generated -# DO NOT EDIT MANUALLY -# -{% for switch in MD_Extended.vxlan.topology.switches %} -{% if switch.interface_breakouts is defined %} -{% for breakout in switch.interface_breakouts %} -{% if breakout.to is defined %} -{% for port in range(breakout.from, breakout.to + 1) %} -- name: Ethernet{{ breakout.module }}/{{ port }} - type: breakout - switch: -{% if switch.management.management_ipv4_address is defined %} - - {{ switch.management.management_ipv4_address }} -{% elif (switch.management.management_ipv4_address is not defined) and (switch.management.management_ipv6_address is defined) %} - - {{ switch.management.management_ipv6_address }} -{% endif %} - deploy: true - profile: - map: {{ breakout.map }} -{% endfor %} -{% else %} -- name: Ethernet{{ breakout.module }}/{{ breakout.from }} - type: breakout - switch: -{% if switch.management.management_ipv4_address is defined %} - - {{ switch.management.management_ipv4_address }} -{% elif (switch.management.management_ipv4_address is not defined) and (switch.management.management_ipv6_address is defined) %} - - {{ switch.management.management_ipv6_address }} -{% endif %} - deploy: true - profile: - map: {{ breakout.map }} -{% endif %} -{% endfor %} -{% endif %} -{% endfor %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 b/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 index a761d4156..d110a8c6b 100644 --- a/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 +++ b/roles/dtc/common/templates/ndfc_route_control/ndfc_prefix_list.j2 @@ -28,9 +28,9 @@ ip prefix-list {{ ipv4_prefix_list["name"] }} description {{ ipv4_prefix_list["d {% set _ = options.append("mask " ~ entry["mask"] ) %} {% endif %} {% if options | length > 0 %} -ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] }} {{ options | join(" ") }} +ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] | ipaddr('network/prefix') }} {{ options | join(" ") }} {% else %} -ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] }} +ip prefix-list {{ ipv4_prefix_list["name"] }} seq {{ entry["seq_number"] }} {{ entry["operation"] }} {{ entry["prefix"] | ipaddr('network/prefix') }} {% endif %} {% endfor %} {% endif %} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index 165a59d67..a92db41a4 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -25,7 +25,7 @@ ansible.builtin.import_tasks: sub_main_vxlan.yml when: > (MD_Extended.vxlan.fabric.type == 'VXLAN_EVPN') and - ((vars_common_vxlan.changes_detected_fabric) or + (vars_common_vxlan.changes_detected_fabric) or (vars_common_vxlan.changes_detected_inventory) or (vars_common_vxlan.changes_detected_vpc_peering) or (vars_common_vxlan.changes_detected_interfaces) or @@ -35,7 +35,7 @@ (vars_common_vxlan.changes_detected_policy) or (vars_common_vxlan.changes_detected_edge_connections) or (vars_common_vxlan.changes_detected_fabric_links) or - (vars_common_vxlan.changes_detected_underlay_ip_address)) + (vars_common_vxlan.changes_detected_underlay_ip_address) - name: Import eBGP VXLAN Fabric Role Tasks ansible.builtin.import_tasks: sub_main_ebgp_vxlan.yml @@ -68,16 +68,16 @@ ansible.builtin.import_tasks: sub_main_mfd.yml when: > (MD_Extended.vxlan.fabric.type == 'MFD') and - ((vars_common_mfd.changes_detected_fabric) or + (vars_common_mfd.changes_detected_fabric) or (vars_common_mfd.changes_detected_vrfs) or - (vars_common_mfd.changes_detected_networks)) + (vars_common_mfd.changes_detected_networks) # Check with Matt and Pete on External Fabrics - name: Import External Fabric Role Tasks ansible.builtin.import_tasks: sub_main_external.yml when: > (MD_Extended.vxlan.fabric.type == 'External') and - ((vars_common_external.changes_detected_inventory) or + (vars_common_external.changes_detected_inventory) or (vars_common_external.changes_detected_interfaces) or (vars_common_external.changes_detected_fabric) or (vars_common_external.changes_detected_vpc_peering) or @@ -89,7 +89,7 @@ (vars_common_external.changes_detected_interface_trunk_po) or (vars_common_external.changes_detected_interface_trunk) or (vars_common_external.changes_detected_sub_interface_routed) or - (vars_common_external.changes_detected_policy)) + (vars_common_external.changes_detected_policy) - name: Mark Stage Role Create Completed cisco.nac_dc_vxlan.common.run_map: diff --git a/roles/dtc/create/tasks/sub_main_external.yml b/roles/dtc/create/tasks/sub_main_external.yml index 3e46beeb9..fa53ee952 100644 --- a/roles/dtc/create/tasks/sub_main_external.yml +++ b/roles/dtc/create/tasks/sub_main_external.yml @@ -72,13 +72,6 @@ - vars_common_external.changes_detected_interfaces tags: "{{ nac_tags.create_interfaces }}" -- name: Manage External Fabric VPC Peering - ansible.builtin.import_tasks: common/vpc_peering.yml - when: - - MD_Extended.vxlan.topology.vpc_peers | length > 0 - - vars_common_external.changes_detected_vpc_peering - tags: "{{ nac_tags.create_vpc_peers }}" - - name: Manage External Fabric Policies in Nexus Dashboard ansible.builtin.import_tasks: common/policies.yml when: diff --git a/roles/dtc/remove/tasks/common/interfaces.yml b/roles/dtc/remove/tasks/common/interfaces.yml index e97f6104e..475c9c998 100644 --- a/roles/dtc/remove/tasks/common/interfaces.yml +++ b/roles/dtc/remove/tasks/common/interfaces.yml @@ -50,7 +50,7 @@ cisco.dcnm.dcnm_interface: fabric: "{{ MD_Extended.vxlan.fabric.name }}" state: overridden - config: "{{ vars_common_local.interface_all | default(vars_common_local.interface_all) }}" + config: "{{ vars_common_local.interface_all }}" # deploy: false vars: ansible_command_timeout: 3000 diff --git a/roles/dtc/remove/tasks/common/vpc_peers.yml b/roles/dtc/remove/tasks/common/vpc_peers.yml index 1558bf410..03df440e9 100644 --- a/roles/dtc/remove/tasks/common/vpc_peers.yml +++ b/roles/dtc/remove/tasks/common/vpc_peers.yml @@ -36,20 +36,6 @@ vars_common_local: "{{ vars_common_ebgp_vxlan }}" when: MD_Extended.vxlan.fabric.type == "eBGP_VXLAN" -- name: Choose vars_common Based On Fabric Type - ansible.builtin.set_fact: - vars_common_local: "{{ vars_common_vxlan }}" - when: MD_Extended.vxlan.fabric.type == "VXLAN_EVPN" -- ansible.builtin.set_fact: - vars_common_local: "{{ vars_common_msd }}" - when: MD_Extended.vxlan.fabric.type == "MSD" -- ansible.builtin.set_fact: - vars_common_local: "{{ vars_common_isn }}" - when: MD_Extended.vxlan.fabric.type == "ISN" -- ansible.builtin.set_fact: - vars_common_local: "{{ vars_common_external }}" - when: MD_Extended.vxlan.fabric.type == "External" - - name: Display Removing Unmanaged vPC Peering Message ansible.builtin.debug: msg: "Removing Unmanaged vPC Peering. This could take several minutes..." @@ -60,7 +46,7 @@ - name: Remove Unmanaged vPC Peering from Nexus Dashboard cisco.dcnm.dcnm_vpc_pair: src_fabric: "{{ MD_Extended.vxlan.fabric.name }}" - deploy: false + deploy: true state: overridden config: "{{ vars_common_local.vpc_peering }}" vars: From 694d181eab2a672bf6e6cac6388e7608374b57fe Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 23 Sep 2025 13:54:59 +0100 Subject: [PATCH 174/183] remove old file --- plugins/action/dtc/prepare_msite.py | 163 ---------------------------- 1 file changed, 163 deletions(-) delete mode 100644 plugins/action/dtc/prepare_msite.py diff --git a/plugins/action/dtc/prepare_msite.py b/plugins/action/dtc/prepare_msite.py deleted file mode 100644 index df24cb982..000000000 --- a/plugins/action/dtc/prepare_msite.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# SPDX-License-Identifier: MIT - -from __future__ import absolute_import, division, print_function - - -__metaclass__ = type - -from ansible.utils.display import Display -from ansible.plugins.action import ActionBase -from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes -from ...plugin_utils.helper_functions import ndfc_get_fabric_switches - -display = Display() - - -class ActionModule(ActionBase): - - def run(self, tmp=None, task_vars=None): - results = super(ActionModule, self).run(tmp, task_vars) - results['failed'] = False - results['current_associated_child_fabrics'] = [] - results['child_fabrics_to_be_removed'] = [] - results['child_fabrics_to_be_associated'] = [] - results['end_state_associated_child_fabrics'] = [] - results['child_fabrics_data'] = {} - - model_data = self._task.args["model_data"] - parent_fabric = self._task.args["parent_fabric"] - child_fabrics = self._task.args["child_fabrics"] - - # This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD - # Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD) - msd_fabric_associations = self._execute_module( - module_name="cisco.dcnm.dcnm_rest", - module_args={ - "method": "GET", - "path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations", - }, - task_vars=task_vars, - tmp=tmp - ) - - # Build a list of child fabrics that are associated with the parent fabric (MSD) - associated_child_fabrics = [] - for fabric in msd_fabric_associations.get('response').get('DATA'): - if fabric.get('fabricParent') == parent_fabric: - associated_child_fabrics.append(fabric.get('fabricName')) - - # Can probably remove this as I don't think it will be used - results['current_associated_child_fabrics'] = associated_child_fabrics - - # Build a list of child fabrics that are to be removed from the parent fabric (MSD) - child_fabrics_list = [child_fabric['name'] for child_fabric in child_fabrics] - child_fabrics_to_be_removed = [] - child_fabric_to_be_removed = [fabric for fabric in associated_child_fabrics if fabric not in child_fabrics_list] - child_fabrics_to_be_removed = child_fabrics_to_be_removed + child_fabric_to_be_removed - - results['child_fabrics_to_be_removed'] = child_fabrics_to_be_removed - - # Build a list of desired child fabrics that are not associated with the parent fabric (MSD) - child_fabrics_to_be_associated = [] - for fabric in child_fabrics: - if fabric.get('name') not in associated_child_fabrics: - child_fabrics_to_be_associated.append(fabric.get('name')) - - results['child_fabrics_to_be_associated'] = child_fabrics_to_be_associated - - # Merge the lists of currently associated child fabrics and child fabrics to be associated - # The assumption here is that the child fabric(s) that will be associated with the parent fabric (MSD) - # in the create role will either be sucessful and we have the prepared data to work with or - # the association will fail, resulting in runtime execution stopping, thus it doens't matter what prepared data we have. - associated_child_fabrics = associated_child_fabrics + child_fabrics_to_be_associated - - # Can probably remove this as I don't think it will be used - results['end_state_associated_child_fabrics'] = associated_child_fabrics - - # Get the fabric attributes and switches for each child fabric - # These queries are potentially trying to get data for a fabric that is not associated with the parent fabric (MSD) yet - child_fabrics_data = {} - for fabric in associated_child_fabrics: - child_fabrics_data.update({fabric: {}}) - child_fabrics_data[fabric].update({'attributes': ndfc_get_fabric_attributes(self, task_vars, tmp, fabric)}) - child_fabrics_data[fabric].update({'switches': ndfc_get_fabric_switches(self, task_vars, tmp, fabric)}) - - results['child_fabrics_data'] = child_fabrics_data - - # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into - # a structure that is easier to use just like MD_Extended. - vrf_grp_name_list = [] - model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'] = {} - model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'] = [] - for grp in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups']: - model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']] = [] - vrf_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['multisite']['overlay']['vrf_attach_groups_dict'][grp['name']]: - for child_fabric in child_fabrics_data.keys(): - for sw in child_fabrics_data[child_fabric]['switches']: - if switch['hostname'] == sw['hostname']: - switch['mgmt_ip_address'] = sw['mgmt_ip_address'] - - # Append switch to a flat list of switches for cross comparison later when we query the - # MSD fabric information. We need to stop execution if the list returned by the MSD query - # does not include one of these switches. - model_data['vxlan']['multisite']['overlay']['vrf_attach_switches_list'].append(switch['hostname']) - - # Remove vrf_attach_group from vrf if the group_name is not defined - for vrf in model_data['vxlan']['multisite']['overlay']['vrfs']: - if 'vrf_attach_group' in vrf: - if vrf.get('vrf_attach_group') not in vrf_grp_name_list: - del vrf['vrf_attach_group'] - - # Rebuild sm_data['vxlan']['overlay']['network_attach_groups'] into - # a structure that is easier to use. - net_grp_name_list = [] - model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'] = {} - model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'] = [] - for grp in model_data['vxlan']['multisite']['overlay']['network_attach_groups']: - model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']] = [] - net_grp_name_list.append(grp['name']) - for switch in grp['switches']: - model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']].append(switch) - # If the switch is in the switch list and a hostname is used, replace the hostname with the management IP - for switch in model_data['vxlan']['multisite']['overlay']['network_attach_groups_dict'][grp['name']]: - for child_fabric in child_fabrics_data.keys(): - for sw in child_fabrics_data[child_fabric]['switches']: - if switch['hostname'] == sw['hostname']: - switch['mgmt_ip_address'] = sw['mgmt_ip_address'] - # Append switch to a flat list of switches for cross comparison later when we query the - # MSD fabric information. We need to stop execution if the list returned by the MSD query - # does not include one of these switches. - model_data['vxlan']['multisite']['overlay']['network_attach_switches_list'].append(switch['hostname']) - - # Remove network_attach_group from net if the group_name is not defined - for net in model_data['vxlan']['multisite']['overlay']['networks']: - if 'network_attach_group' in net: - if net.get('network_attach_group') not in net_grp_name_list: - del net['network_attach_group'] - - results['overlay_attach_groups'] = model_data['vxlan']['multisite']['overlay'] - - return results From aec5097f46e79837a6a4d92a780e184f3b9031e2 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 23 Sep 2025 15:07:01 +0100 Subject: [PATCH 175/183] remove unused variables and clean up defaults --- .../action/common/prepare_plugins/prep_001_fabric.py | 1 - .../prepare_plugins/prep_105_fabric_overlay.py | 2 -- plugins/action/dtc/manage_child_fabric_networks.py | 2 -- plugins/action/dtc/manage_child_fabric_vrfs.py | 2 -- plugins/plugin_utils/helper_functions.py | 9 --------- roles/validate/files/defaults.yml | 12 ------------ 6 files changed, 28 deletions(-) diff --git a/plugins/action/common/prepare_plugins/prep_001_fabric.py b/plugins/action/common/prepare_plugins/prep_001_fabric.py index 4970174c9..b2bdd8136 100644 --- a/plugins/action/common/prepare_plugins/prep_001_fabric.py +++ b/plugins/action/common/prepare_plugins/prep_001_fabric.py @@ -131,7 +131,6 @@ def prepare(self): ) display.deprecated(msg=deprecated_msg, version="1.0.0", collection_name='cisco.nac_dc_vxlan') model_data['vxlan']['overlay'] = model_data['vxlan']['overlay_services'] - model_data['vxlan']['multisite']['overlay'] = model_data['vxlan']['overlay_services'] del model_data['vxlan']['overlay_services'] parent_keys = ['vxlan', 'multisite', 'overlay'] diff --git a/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py index 020c5885d..d3499dd18 100644 --- a/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py @@ -142,7 +142,5 @@ def prepare(self): if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] - model_data['vxlan']['multisite']['overlay_services'] = model_data['vxlan']['multisite']['overlay'] - model_data['vxlan']['overlay_services'] = model_data['vxlan']['multisite']['overlay'] self.kwargs['results']['model_extended'] = model_data return self.kwargs['results'] diff --git a/plugins/action/dtc/manage_child_fabric_networks.py b/plugins/action/dtc/manage_child_fabric_networks.py index da45453e6..4ebef8a33 100644 --- a/plugins/action/dtc/manage_child_fabric_networks.py +++ b/plugins/action/dtc/manage_child_fabric_networks.py @@ -89,9 +89,7 @@ def run(self, tmp=None, task_vars=None): child_fabric_type = child_fabrics[child_fabric]['type'] if child_fabric_type in ['Switch_Fabric']: child_fabric_attributes = child_fabrics[child_fabric]['attributes'] - child_fabric_switches = child_fabrics[child_fabric]['switches'] child_fabric_cluster = child_fabrics[child_fabric].get('cluster') - child_fabric_switches_mgmt_ip_addresses = [child_fabric_switch['mgmt_ip_address'] for child_fabric_switch in child_fabric_switches] network_child_fabric = [] if network_child_fabrics: diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index 8a93f8443..29daa3f0b 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -100,9 +100,7 @@ def run(self, tmp=None, task_vars=None): child_fabric_type = child_fabrics[child_fabric]['type'] if child_fabric_type in ['Switch_Fabric']: child_fabric_attributes = child_fabrics[child_fabric]['attributes'] - child_fabric_switches = child_fabrics[child_fabric]['switches'] child_fabric_cluster = child_fabrics[child_fabric].get('cluster') - child_fabric_switches_mgmt_ip_addresses = [child_fabric_switch['mgmt_ip_address'] for child_fabric_switch in child_fabric_switches] vrf_child_fabric = [] if vrf_child_fabrics: diff --git a/plugins/plugin_utils/helper_functions.py b/plugins/plugin_utils/helper_functions.py index b8a44d6ec..ec2596195 100644 --- a/plugins/plugin_utils/helper_functions.py +++ b/plugins/plugin_utils/helper_functions.py @@ -24,8 +24,6 @@ # # For example in prepare_serice_model.py we can do the following: # from ..helper_functions import do_something -import re - def data_model_key_check(tested_object, keys): """ @@ -304,10 +302,3 @@ def ndfc_get_fabric_switches_onepath(self, task_vars, tmp, fabric, cluster): ) return fabric_switches - - -def normalise_int_lists(data): - for interface in data: - if interface.startswith(('Ethernet', 'ethernet', 'Eth', 'eth', 'E', 'e')): - interface = "Ethernet" + re.split(r'(?=\d)', interface, 1)[1] - return data diff --git a/roles/validate/files/defaults.yml b/roles/validate/files/defaults.yml index 2dc954cd6..7982bb6c0 100644 --- a/roles/validate/files/defaults.yml +++ b/roles/validate/files/defaults.yml @@ -447,19 +447,7 @@ factory_defaults: vtep_loopback_id: 100 bgw_ip_tag: 54321 ipv4_vtep_loopback_range: 10.10.0.0/24 - ipv4_dci_subnet_range: 10.10.1.0/24 - ipv4_dci_subnet_mask: 30 ipv6_vtep_loopback_range: fd00::a10:0/120 - ipv6_dci_subnet_range: fd00::a11:0/120 - ipv6_dci_subnet_mask: 126 - overlay_ifc: Direct_To_BGWS - underlay_autoconfig: true - enable_bgp_send_community: false - enable_bgp_log_neighbor_change: false - enable_bgp_bfd: false - delay_restore: 300 - enable_ebgp_password: false - enable_trm: false overlay: vrfs: vrf_description: "Configured by Ansible NetAsCode" From 323b8680e50ca37d5bf6ef615051948ac695c9cf Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Tue, 23 Sep 2025 15:16:28 +0100 Subject: [PATCH 176/183] fix sanity ignores --- tests/sanity/ignore-2.14.txt | 1 - tests/sanity/ignore-2.15.txt | 1 - tests/sanity/ignore-2.16.txt | 1 - tests/sanity/ignore-2.17.txt | 1 - 4 files changed, 4 deletions(-) diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 77aa28072..1ff368e43 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -17,7 +17,6 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 77aa28072..1ff368e43 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -17,7 +17,6 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 77aa28072..1ff368e43 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -17,7 +17,6 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation diff --git a/tests/sanity/ignore-2.17.txt b/tests/sanity/ignore-2.17.txt index 77aa28072..1ff368e43 100644 --- a/tests/sanity/ignore-2.17.txt +++ b/tests/sanity/ignore-2.17.txt @@ -17,7 +17,6 @@ plugins/action/common/run_map.py action-plugin-docs # action plugin has no match plugins/action/common/read_run_map.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/common/merge_defaults.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/fed_overlay_check.py action-plugin-docs # action plugin has no matching module to provide documentation -plugins/action/dtc/prepare_msite.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/add_device_check.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/manage_child_fabrics.py action-plugin-docs # action plugin has no matching module to provide documentation plugins/action/dtc/prepare_msite_child_fabrics_data.py action-plugin-docs # action plugin has no matching module to provide documentation From d7bd1bb28fafcd5bf2a42902223c7fd8e42c10f0 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 26 Sep 2025 14:26:45 +0100 Subject: [PATCH 177/183] remove whitespace and unneeded debug --- roles/common_global/vars/main.yml | 2 +- roles/dtc/remove/tasks/mfd/child_fabrics.yml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/roles/common_global/vars/main.yml b/roles/common_global/vars/main.yml index b4c601f47..bb5a06a96 100644 --- a/roles/common_global/vars/main.yml +++ b/roles/common_global/vars/main.yml @@ -131,7 +131,7 @@ nac_tags: - cr_manage_vpc_peers create_interfaces: - cr_manage_interfaces - create_vrfs_networks: + create_vrfs_networks: - cr_manage_vrfs_networks create_policy: - cr_manage_policy diff --git a/roles/dtc/remove/tasks/mfd/child_fabrics.yml b/roles/dtc/remove/tasks/mfd/child_fabrics.yml index 7c7976aee..e3536a186 100644 --- a/roles/dtc/remove/tasks/mfd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/mfd/child_fabrics.yml @@ -34,10 +34,6 @@ path: '/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/members' register: member_result -- name: debug member_result - ansible.builtin.debug: - var: member_result - - name: Set fact for existing fabric names and cluster names set_fact: existing_fabrics: >- From a0aebd75a49fc432f6b8a68eb11f8f417b462dba Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 26 Sep 2025 14:32:57 +0100 Subject: [PATCH 178/183] updating task names and ansible module calls --- roles/dtc/remove/tasks/mfd/child_fabrics.yml | 6 +++--- roles/dtc/remove/tasks/mfd/networks_fed.yml | 7 ++++--- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 6 ++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/roles/dtc/remove/tasks/mfd/child_fabrics.yml b/roles/dtc/remove/tasks/mfd/child_fabrics.yml index e3536a186..d98d1ea29 100644 --- a/roles/dtc/remove/tasks/mfd/child_fabrics.yml +++ b/roles/dtc/remove/tasks/mfd/child_fabrics.yml @@ -35,21 +35,21 @@ register: member_result - name: Set fact for existing fabric names and cluster names - set_fact: + ansible.builtin.set_fact: existing_fabrics: >- {{ member_result.response.DATA | map(attribute='fabrics') | map('dict2items') | flatten | list }} - name: Set fact for child fabric names - set_fact: + ansible.builtin.set_fact: child_fabric_names: >- {{ fabric_children | map(attribute='fabricName') | list }} - name: Generate payload for fabrics to be removed - set_fact: + ansible.builtin.set_fact: remove_payload: >- [ {% for fabric in existing_fabrics if fabric.key not in child_fabric_names %} diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mfd/networks_fed.yml index eb37ab156..ceba659c3 100644 --- a/roles/dtc/remove/tasks/mfd/networks_fed.yml +++ b/roles/dtc/remove/tasks/mfd/networks_fed.yml @@ -20,7 +20,8 @@ # SPDX-License-Identifier: MIT --- -- ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." +- name: Initial network remove message + ansible.builtin.debug: msg="Removing Unmanaged Fabric Networks. This could take several minutes..." when: - switch_list.response.DATA | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) @@ -82,10 +83,10 @@ - not_required_networks.payload | length > 0 - (network_delete_mode is defined) and (network_delete_mode is true|bool) -- ansible.builtin.debug: +- name: Networks skipping message + ansible.builtin.debug: msg: - "---------------------------------------------------------------------------------------------------------------" - "+ SKIPPING Remove Unmanaged Fabric Networks task because network_delete_mode flag is set to False +" - "---------------------------------------------------------------------------------------------------------------" when: not ((network_delete_mode is defined) and (network_delete_mode is true|bool)) - \ No newline at end of file diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index 60f24ffdd..6718015d1 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -20,7 +20,8 @@ # SPDX-License-Identifier: MIT --- -- ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." +- name: Initial VRF remove message + ansible.builtin.debug: msg="Removing Unmanaged Fabric VRFs. This could take several minutes..." when: - switch_list.response.DATA | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) @@ -85,7 +86,8 @@ - not_required_vrfs.payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) -- ansible.builtin.debug: +- name: Skipping message + ansible.builtin.debug: msg: - "--------------------------------------------------------------------------------------------------------" - "+ SKIPPING Remove Unmanaged Fabric VRFs task because vrf_delete_mode flag is set to False +" From 3c08b73b2e429930fd8bcbd3475ef05ae6d34b2c Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 26 Sep 2025 14:33:14 +0100 Subject: [PATCH 179/183] updating task names and ansible module calls --- roles/dtc/remove/tasks/mfd/vrfs_fed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml index 6718015d1..7d5ed7fba 100644 --- a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml +++ b/roles/dtc/remove/tasks/mfd/vrfs_fed.yml @@ -86,7 +86,7 @@ - not_required_vrfs.payload | length > 0 - (vrf_delete_mode is defined) and (vrf_delete_mode is true|bool) -- name: Skipping message +- name: VRF skipping message ansible.builtin.debug: msg: - "--------------------------------------------------------------------------------------------------------" From a03458fea777a582678ad8e2e23f790096bce9d5 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 26 Sep 2025 14:38:20 +0100 Subject: [PATCH 180/183] updating task names and ansible module calls --- roles/dtc/deploy/tasks/sub_main_mfd.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/roles/dtc/deploy/tasks/sub_main_mfd.yml b/roles/dtc/deploy/tasks/sub_main_mfd.yml index 6e3b5e1f8..3b250bd5b 100644 --- a/roles/dtc/deploy/tasks/sub_main_mfd.yml +++ b/roles/dtc/deploy/tasks/sub_main_mfd.yml @@ -28,7 +28,9 @@ - "+ Calling Role - [cisco.nac_dc_vxlan.dtc.deploy] +" - "----------------------------------------------------------------" -- ansible.builtin.debug: msg="Configuring NXOS Devices using NDFC (Direct to Controller)" +- name: Message + ansible.builtin.debug: + msg: "Configuring NXOS Devices using NDFC (Direct to Controller)" - name: Config-Save block block: @@ -46,11 +48,11 @@ msg: "{{ config_save.msg.DATA }}" - name: Extract serial numbers from switches_in_fabric - set_fact: + ansible.builtin.set_fact: serial_numbers: "{{ switches_in_fabric | json_query('[*].serialNumber') }}" - name: Join serial numbers into a comma-separated list - set_fact: + ansible.builtin.set_fact: serial_numbers_str: "{{ serial_numbers | join(',') }}" - name: Deploy for Federated Overlay From ee59cf09e29544c0c7d50ae6f9a794e4d1db3aba Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Fri, 26 Sep 2025 15:47:44 +0100 Subject: [PATCH 181/183] update from MFD to MCFG --- plugins/action/common/nac_dc_validate.py | 4 +- .../prep_104_topology_switches.py | 2 +- .../prep_105_fabric_overlay.py | 4 +- .../prep_106_topology_interfaces.py | 2 +- .../prep_118_topology_edge_connections.py | 2 +- .../dtc/manage_child_fabric_networks.py | 4 +- .../action/dtc/manage_child_fabric_vrfs.py | 4 +- plugins/action/dtc/prepare_msite_data.py | 6 +-- plugins/plugin_utils/data_model_keys.py | 22 ++++---- roles/dtc/common/tasks/main.yml | 8 +-- .../tasks/{mfd => mcfg}/ndfc_children.yml | 2 +- .../tasks/{mfd => mcfg}/ndfc_fabric.yml | 0 .../{mfd => mcfg}/ndfc_get_inventory.yml | 6 +-- .../tasks/{mfd => mcfg}/ndfc_networks.yml | 4 +- .../common/tasks/{mfd => mcfg}/ndfc_vrfs.yml | 4 +- .../{sub_main_mfd.yml => sub_main_mcfg.yml} | 20 ++++---- .../common/templates/ndfc_attach_networks.j2 | 8 +-- .../dtc/common/templates/ndfc_attach_vrfs.j2 | 8 +-- roles/dtc/common/templates/ndfc_fabric.j2 | 8 +-- .../{mfd_fabric => mcfg_fabric}/.gitkeep | 0 .../{mfd_fabric => mcfg_fabric}/dci/.gitkeep | 0 .../dci/mcfg_fabric_dci.j2} | 0 .../general/.gitkeep | 0 .../general/mcfg_fabric_general.j2} | 0 .../mcfg_fabric/mcfg_fabric_base.j2 | 13 +++++ .../resources/.gitkeep | 0 .../resources/mcfg_fabric_resources.j2} | 0 .../security/.gitkeep | 0 .../security/mcfg_fabric_security.j2} | 0 .../ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 | 13 ----- .../ndfc_attach_networks.j2 | 0 .../ndfc_attach_networks_switches.j2 | 0 .../ndfc_attach_networks_switches_ports.j2 | 0 .../ndfc_attach_vrfs.j2 | 0 .../ndfc_attach_vrfs_loopbacks.j2 | 0 roles/dtc/create/tasks/main.yml | 12 ++--- .../tasks/{mfd => mcfg}/child_fabrics.yml | 0 .../dtc/create/tasks/{mfd => mcfg}/fabric.yml | 2 +- .../{mfd => mcfg}/network_fed_config.yml | 0 .../tasks/{mfd => mcfg}/vrf_fed_config.yml | 0 .../tasks/{mfd => mcfg}/vrf_loopbacks.yml | 12 +---- .../tasks/{mfd => mcfg}/vrfs_networks.yml | 50 +++++++++---------- .../{sub_main_mfd.yml => sub_main_mcfg.yml} | 8 +-- roles/dtc/deploy/tasks/main.yml | 12 ++--- .../{sub_main_mfd.yml => sub_main_mcfg.yml} | 2 +- roles/dtc/remove/tasks/main.yml | 10 ++-- .../tasks/{mfd => mcfg}/child_fabrics.yml | 0 .../tasks/{mfd => mcfg}/networks_fed.yml | 0 .../remove/tasks/{mfd => mcfg}/vrfs_fed.yml | 0 .../{sub_main_mfd.yml => sub_main_mcfg.yml} | 10 ++-- 50 files changed, 127 insertions(+), 135 deletions(-) rename roles/dtc/common/tasks/{mfd => mcfg}/ndfc_children.yml (98%) rename roles/dtc/common/tasks/{mfd => mcfg}/ndfc_fabric.yml (100%) rename roles/dtc/common/tasks/{mfd => mcfg}/ndfc_get_inventory.yml (92%) rename roles/dtc/common/tasks/{mfd => mcfg}/ndfc_networks.yml (95%) rename roles/dtc/common/tasks/{mfd => mcfg}/ndfc_vrfs.yml (95%) rename roles/dtc/common/tasks/{sub_main_mfd.yml => sub_main_mcfg.yml} (89%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric => mcfg_fabric}/.gitkeep (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric => mcfg_fabric}/dci/.gitkeep (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric/dci/mfd_fabric_dci.j2 => mcfg_fabric/dci/mcfg_fabric_dci.j2} (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric => mcfg_fabric}/general/.gitkeep (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric/general/mfd_fabric_general.j2 => mcfg_fabric/general/mcfg_fabric_general.j2} (100%) create mode 100644 roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/mcfg_fabric_base.j2 rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric => mcfg_fabric}/resources/.gitkeep (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric/resources/mfd_fabric_resources.j2 => mcfg_fabric/resources/mcfg_fabric_resources.j2} (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric => mcfg_fabric}/security/.gitkeep (100%) rename roles/dtc/common/templates/ndfc_fabric/{mfd_fabric/security/mfd_fabric_security.j2 => mcfg_fabric/security/mcfg_fabric_security.j2} (100%) delete mode 100644 roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 rename roles/dtc/common/templates/ndfc_networks/{mfd_fabric => mcfg_fabric}/ndfc_attach_networks.j2 (100%) rename roles/dtc/common/templates/ndfc_networks/{mfd_fabric => mcfg_fabric}/ndfc_attach_networks_switches.j2 (100%) rename roles/dtc/common/templates/ndfc_networks/{mfd_fabric => mcfg_fabric}/ndfc_attach_networks_switches_ports.j2 (100%) rename roles/dtc/common/templates/ndfc_vrfs/{mfd_fabric => mcfg_fabric}/ndfc_attach_vrfs.j2 (100%) rename roles/dtc/common/templates/ndfc_vrfs/{mfd_fabric => mcfg_fabric}/ndfc_attach_vrfs_loopbacks.j2 (100%) rename roles/dtc/create/tasks/{mfd => mcfg}/child_fabrics.yml (100%) rename roles/dtc/create/tasks/{mfd => mcfg}/fabric.yml (97%) rename roles/dtc/create/tasks/{mfd => mcfg}/network_fed_config.yml (100%) rename roles/dtc/create/tasks/{mfd => mcfg}/vrf_fed_config.yml (100%) rename roles/dtc/create/tasks/{mfd => mcfg}/vrf_loopbacks.yml (85%) rename roles/dtc/create/tasks/{mfd => mcfg}/vrfs_networks.yml (86%) rename roles/dtc/create/tasks/{sub_main_mfd.yml => sub_main_mcfg.yml} (91%) rename roles/dtc/deploy/tasks/{sub_main_mfd.yml => sub_main_mcfg.yml} (98%) rename roles/dtc/remove/tasks/{mfd => mcfg}/child_fabrics.yml (100%) rename roles/dtc/remove/tasks/{mfd => mcfg}/networks_fed.yml (100%) rename roles/dtc/remove/tasks/{mfd => mcfg}/vrfs_fed.yml (100%) rename roles/dtc/remove/tasks/{sub_main_mfd.yml => sub_main_mcfg.yml} (90%) diff --git a/plugins/action/common/nac_dc_validate.py b/plugins/action/common/nac_dc_validate.py index 261f522c1..8a5929db3 100644 --- a/plugins/action/common/nac_dc_validate.py +++ b/plugins/action/common/nac_dc_validate.py @@ -107,7 +107,7 @@ def run(self, tmp=None, task_vars=None): rules_list.append(f'{rules}common') rules_list.append(f'{rules}ebgp_vxlan/') rules_list.append(f'{rules}common_vxlan') - elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MFD'): + elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCFG'): rules_list.append(f'{rules}multisite/') elif results['data']['vxlan']['fabric']['type'] in ('ISN'): rules_list.append(f'{rules}isn/') @@ -134,7 +134,7 @@ def run(self, tmp=None, task_vars=None): if results['data']['vxlan']['global']['fabric_type'] in ('VXLAN_EVPN'): rules_list.append(f'{rules}ibgp_vxlan/') - elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MFD'): + elif results['data']['vxlan']['global']['fabric_type'] in ('MSD', 'MCFG'): rules_list.append(f'{rules}multisite/') elif results['data']['vxlan']['global']['fabric_type'] in ('ISN'): rules_list.append(f'{rules}isn/') diff --git a/plugins/action/common/prepare_plugins/prep_104_topology_switches.py b/plugins/action/common/prepare_plugins/prep_104_topology_switches.py index 35034b7cc..6c184f7dc 100644 --- a/plugins/action/common/prepare_plugins/prep_104_topology_switches.py +++ b/plugins/action/common/prepare_plugins/prep_104_topology_switches.py @@ -31,7 +31,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['MSD', 'MFD']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MCFG']: return self.kwargs['results'] else: switches = model_data['vxlan']['topology']['switches'] diff --git a/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py b/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py index d3499dd18..3585b16bd 100644 --- a/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py +++ b/plugins/action/common/prepare_plugins/prep_105_fabric_overlay.py @@ -28,7 +28,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # We don't have switches for Multisite fabrics so need special handling - if model_data['vxlan']['fabric']['type'] in ('MSD', 'MFD'): + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCFG'): switches = [] else: switches = model_data['vxlan']['topology']['switches'] @@ -82,7 +82,7 @@ def prepare(self): if net.get('network_attach_group') not in net_grp_name_list: del net['network_attach_group'] - if model_data['vxlan']['fabric']['type'] in ('MSD', 'MFD'): + if model_data['vxlan']['fabric']['type'] in ('MSD', 'MCFG'): # Rebuild sm_data['vxlan']['multisite']['overlay']['vrf_attach_groups'] into # a structure that is easier to use. vrf_grp_name_list = [] diff --git a/plugins/action/common/prepare_plugins/prep_106_topology_interfaces.py b/plugins/action/common/prepare_plugins/prep_106_topology_interfaces.py index 2ca8c4540..7f922ee76 100644 --- a/plugins/action/common/prepare_plugins/prep_106_topology_interfaces.py +++ b/plugins/action/common/prepare_plugins/prep_106_topology_interfaces.py @@ -37,7 +37,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['MSD', 'MFD']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MCFG']: return self.kwargs['results'] model_data['vxlan']['topology']['interfaces'] = {} diff --git a/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py index 23c6d3af4..e3e0755b7 100644 --- a/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py +++ b/plugins/action/common/prepare_plugins/prep_118_topology_edge_connections.py @@ -28,7 +28,7 @@ def prepare(self): model_data = self.kwargs['results']['model_extended'] # This plugin does not apply to the follwing fabric types - if model_data['vxlan']['fabric']['type'] in ['MSD', 'MFD']: + if model_data['vxlan']['fabric']['type'] in ['MSD', 'MCFG']: return self.kwargs['results'] else: switches = model_data['vxlan']['topology']['switches'] diff --git a/plugins/action/dtc/manage_child_fabric_networks.py b/plugins/action/dtc/manage_child_fabric_networks.py index 4ebef8a33..cc6fafd8f 100644 --- a/plugins/action/dtc/manage_child_fabric_networks.py +++ b/plugins/action/dtc/manage_child_fabric_networks.py @@ -141,7 +141,7 @@ def run(self, tmp=None, task_vars=None): # results['failed'] = True # results['msg'] = error_msg # return results - if fabric_type == 'MFD': + if fabric_type == 'MCFG': get_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" f"rest/top-down/fabrics/{child_fabric}/networks/{network['name']}") else: @@ -214,7 +214,7 @@ def run(self, tmp=None, task_vars=None): rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) - if fabric_type == 'MFD': + if fabric_type == 'MCFG': put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" f"rest/top-down/fabrics/{child_fabric}/networks/{network['name']}") else: diff --git a/plugins/action/dtc/manage_child_fabric_vrfs.py b/plugins/action/dtc/manage_child_fabric_vrfs.py index 29daa3f0b..ccabfb16f 100644 --- a/plugins/action/dtc/manage_child_fabric_vrfs.py +++ b/plugins/action/dtc/manage_child_fabric_vrfs.py @@ -152,7 +152,7 @@ def run(self, tmp=None, task_vars=None): # results['failed'] = True # results['msg'] = error_msg # return results - if fabric_type == 'MFD': + if fabric_type == 'MCFG': get_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: @@ -225,7 +225,7 @@ def run(self, tmp=None, task_vars=None): rendered_content = templar.template(template_content) rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content) - if fabric_type == 'MFD': + if fabric_type == 'MCFG': put_path = (f"/onepath/{child_fabric_cluster}/appcenter/cisco/ndfc/api/v1/lan-fabric/" f"rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}") else: diff --git a/plugins/action/dtc/prepare_msite_data.py b/plugins/action/dtc/prepare_msite_data.py index dc2fc0b14..902d27ca4 100644 --- a/plugins/action/dtc/prepare_msite_data.py +++ b/plugins/action/dtc/prepare_msite_data.py @@ -48,8 +48,8 @@ def run(self, tmp=None, task_vars=None): # This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD # Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD) - if model_data["vxlan"]["fabric"]["type"] == "MFD": - mfd_fabric_associations = self._execute_module( + if model_data["vxlan"]["fabric"]["type"] == "MCFG": + mcfg_fabric_associations = self._execute_module( module_name="cisco.dcnm.dcnm_rest", module_args={ "method": "GET", @@ -59,7 +59,7 @@ def run(self, tmp=None, task_vars=None): tmp=tmp ) associated_child_fabrics = [] - for fabric in mfd_fabric_associations.get('response').get('DATA'): + for fabric in mcfg_fabric_associations.get('response').get('DATA'): if fabric.get('fabricName') == parent_fabric: for member in fabric["members"]: associated_child_fabrics.append({ diff --git a/plugins/plugin_utils/data_model_keys.py b/plugins/plugin_utils/data_model_keys.py index 202370946..a08459146 100644 --- a/plugins/plugin_utils/data_model_keys.py +++ b/plugins/plugin_utils/data_model_keys.py @@ -26,7 +26,7 @@ # from ..helper_functions import do_something root_key = 'vxlan' -model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MFD': {}, 'ISN': {}, 'External': {}, 'eBGP_VXLAN': {}} +model_keys = {'VXLAN_EVPN': {}, 'MSD': {}, 'MCFG': {}, 'ISN': {}, 'External': {}, 'eBGP_VXLAN': {}} # VXLAN_EVPN KEYS # iBGP VXLAN KEYS @@ -151,15 +151,15 @@ model_keys['MSD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] model_keys['MSD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] -# MFD KEYS +# MCFG KEYS # --- -model_keys['MFD']['multisite'] = [root_key, 'multisite', 'KEY'] -model_keys['MFD']['multisite.child_fabrics'] = [root_key, 'multisite', 'child_fabrics', 'KEY'] -model_keys['MFD']['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] -model_keys['MFD']['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] -model_keys['MFD']['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] -model_keys['MFD']['multisite.overlay.vrf_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'switches', 'LIST_INDEX'] -model_keys['MFD']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] -model_keys['MFD']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] -model_keys['MFD']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] +model_keys['MCFG']['multisite'] = [root_key, 'multisite', 'KEY'] +model_keys['MCFG']['multisite.child_fabrics'] = [root_key, 'multisite', 'child_fabrics', 'KEY'] +model_keys['MCFG']['multisite.overlay'] = [root_key, 'multisite', 'overlay', 'KEY'] +model_keys['MCFG']['multisite.overlay.vrfs'] = [root_key, 'multisite', 'overlay', 'vrfs', 'LIST'] +model_keys['MCFG']['multisite.overlay.vrf_attach_groups'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'LIST'] +model_keys['MCFG']['multisite.overlay.vrf_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'vrf_attach_groups', 'switches', 'LIST_INDEX'] +model_keys['MCFG']['multisite.overlay.networks'] = [root_key, 'multisite', 'overlay', 'networks', 'LIST'] +model_keys['MCFG']['multisite.overlay.network_attach_groups'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'LIST'] +model_keys['MCFG']['multisite.overlay.network_attach_groups.switches'] = [root_key, 'multisite', 'overlay', 'network_attach_groups', 'switches', 'LIST_INDEX'] diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 0fb929382..768bca051 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -70,7 +70,7 @@ changes_detected_bgw_anycast_vip: false changes_detected_vrfs: false changes_detected_networks: false - vars_common_mfd: + vars_common_mcfg: changes_detected_fabric: false changes_detected_vrfs: false changes_detected_networks: false @@ -133,10 +133,10 @@ tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml when: MD_Extended.vxlan.fabric.type == 'MSD' -- name: Import Role Tasks for MFD Fabric - ansible.builtin.import_tasks: sub_main_mfd.yml +- name: Import Role Tasks for MCFG Fabric + ansible.builtin.import_tasks: sub_main_mcfg.yml tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml - when: MD_Extended.vxlan.fabric.type == 'MFD' + when: MD_Extended.vxlan.fabric.type == 'MCFG' - name: Import Role Tasks for External Fabric ansible.builtin.import_tasks: sub_main_external.yml diff --git a/roles/dtc/common/tasks/mfd/ndfc_children.yml b/roles/dtc/common/tasks/mcfg/ndfc_children.yml similarity index 98% rename from roles/dtc/common/tasks/mfd/ndfc_children.yml rename to roles/dtc/common/tasks/mcfg/ndfc_children.yml index 546ff5806..39b61cfd9 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_children.yml +++ b/roles/dtc/common/tasks/mcfg/ndfc_children.yml @@ -20,7 +20,7 @@ # SPDX-License-Identifier: MIT --- -- debug: msg="Building NDFC MSD Child Fabric Data" +- debug: msg="Building NDFC MCFG Child Fabric Data" - name: Initialize changes_detected Var ansible.builtin.set_fact: diff --git a/roles/dtc/common/tasks/mfd/ndfc_fabric.yml b/roles/dtc/common/tasks/mcfg/ndfc_fabric.yml similarity index 100% rename from roles/dtc/common/tasks/mfd/ndfc_fabric.yml rename to roles/dtc/common/tasks/mcfg/ndfc_fabric.yml diff --git a/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml b/roles/dtc/common/tasks/mcfg/ndfc_get_inventory.yml similarity index 92% rename from roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml rename to roles/dtc/common/tasks/mcfg/ndfc_get_inventory.yml index 4921d3f1c..4892db628 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_get_inventory.yml +++ b/roles/dtc/common/tasks/mcfg/ndfc_get_inventory.yml @@ -21,7 +21,7 @@ --- -- name: Get all the switches in the Federated Fabric +- name: Get all the switches in the MCFG Fabric Group cisco.dcnm.dcnm_rest: method: GET path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD.vxlan.fabric.name }}/inventory/switchesByFabric" @@ -29,7 +29,7 @@ delegate_to: "{{ inventory_hostname }}" failed_when: false -- name: Store switches in the fabric for Federated Fabric +- name: Store switches in the fabric for MCFG Fabric Group ansible.builtin.set_fact: switches_in_fabric: "{{ switch_results.response.DATA }}" when: switch_results is defined and switch_results.response.DATA is defined @@ -37,4 +37,4 @@ - name: Set switches_in_fabric to empty list if no switches are found ansible.builtin.set_fact: switches_in_fabric: [] - when: switch_results is not defined or switch_results.response.DATA is not defined \ No newline at end of file + when: switch_results is not defined or switch_results.response.DATA is not defined diff --git a/roles/dtc/common/tasks/mfd/ndfc_networks.yml b/roles/dtc/common/tasks/mcfg/ndfc_networks.yml similarity index 95% rename from roles/dtc/common/tasks/mfd/ndfc_networks.yml rename to roles/dtc/common/tasks/mcfg/ndfc_networks.yml index 0d8add6a1..2c35cc08c 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_networks.yml +++ b/roles/dtc/common/tasks/mcfg/ndfc_networks.yml @@ -94,14 +94,14 @@ - name: Build Network Attach List for switches From Template ansible.builtin.template: - src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2" + src: "{{ role_path }}/../common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches.j2" dest: "{{ path_name }}{{ file_name }}" mode: '0644' delegate_to: localhost - name: Build Network Attach List for switches and ports From Template ansible.builtin.template: - src: "{{ role_path }}/../common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2" + src: "{{ role_path }}/../common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches_ports.j2" dest: "{{ path_name }}{{ file_name2 }}" mode: '0644' delegate_to: localhost diff --git a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml b/roles/dtc/common/tasks/mcfg/ndfc_vrfs.yml similarity index 95% rename from roles/dtc/common/tasks/mfd/ndfc_vrfs.yml rename to roles/dtc/common/tasks/mcfg/ndfc_vrfs.yml index 6e91dfc57..1414fa87e 100644 --- a/roles/dtc/common/tasks/mfd/ndfc_vrfs.yml +++ b/roles/dtc/common/tasks/mcfg/ndfc_vrfs.yml @@ -95,7 +95,7 @@ - name: Build VRFs Loopback Attach List From Template ansible.builtin.template: - src: "{{ role_path }}/../common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2" + src: "{{ role_path }}/../common/templates/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs_loopbacks.j2" dest: "{{ path_name }}{{ file_name }}" mode: '0644' delegate_to: localhost @@ -113,6 +113,6 @@ - name: Set vrf_attach_config Var ansible.builtin.set_fact: - vrf_attach_config: "{{ lookup('file', path_name + file_name ) | from_yaml }}" + vrf_attach_config: "{{ lookup('file', path_name + file_name) | from_yaml }}" when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 delegate_to: localhost diff --git a/roles/dtc/common/tasks/sub_main_mfd.yml b/roles/dtc/common/tasks/sub_main_mcfg.yml similarity index 89% rename from roles/dtc/common/tasks/sub_main_mfd.yml rename to roles/dtc/common/tasks/sub_main_mcfg.yml index c30b77038..6c376196f 100644 --- a/roles/dtc/common/tasks/sub_main_mfd.yml +++ b/roles/dtc/common/tasks/sub_main_mcfg.yml @@ -29,7 +29,7 @@ # -------------------------------------------------------------------- - name: Set path_name Var ansible.builtin.set_fact: - path_name: "{{ role_path }}/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/" + path_name: "{{ role_path }}/files/mcfg/{{ MD_Extended.vxlan.fabric.name }}/" delegate_to: localhost - name: Cleanup Files from Previous Run if run_map requires it @@ -42,39 +42,39 @@ # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: mfd/ndfc_fabric.yml + ansible.builtin.import_tasks: mcfg/ndfc_fabric.yml # -------------------------------------------------------------------- # Build Create Fabric Children Parameter List From Template # -------------------------------------------------------------------- - name: Build Fabric Create Parameters - ansible.builtin.import_tasks: mfd/ndfc_children.yml + ansible.builtin.import_tasks: mcfg/ndfc_children.yml # -------------------------------------------------------------------- # Build NDFC Fabric Get Switch Inventory when Federated Fabric # -------------------------------------------------------------------- - name: Build NDFC Fabric Switch inventory - ansible.builtin.import_tasks: mfd/ndfc_get_inventory.yml + ansible.builtin.import_tasks: mcfg/ndfc_get_inventory.yml # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric VRFs Attach List From Template - ansible.builtin.import_tasks: mfd/ndfc_vrfs.yml + ansible.builtin.import_tasks: mcfg/ndfc_vrfs.yml # -------------------------------------------------------------------- # Build NDFC Fabric Networks Attach List From Template # -------------------------------------------------------------------- - name: Build NDFC Fabric Networks Attach List From Template - ansible.builtin.import_tasks: mfd/ndfc_networks.yml + ansible.builtin.import_tasks: mcfg/ndfc_networks.yml - name: Save Local Variables With Namespace Context ansible.builtin.set_fact: - vars_common_mfd: + vars_common_mcfg: changes_detected_fabric: "{{ changes_detected_fabric | default(false) }}" changes_detected_vrfs: "{{ changes_detected_vrfs }}" changes_detected_networks: "{{ changes_detected_networks }}" @@ -90,9 +90,9 @@ ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Fabric Changes Detected - [ {{ vars_common_mfd.changes_detected_fabric }} ]" - - "+ VRFs Changes Detected - [ {{ vars_common_mfd.changes_detected_vrfs }} ]" - - "+ Networks Changes Detected - [ {{ vars_common_mfd.changes_detected_networks }} ]" + - "+ Fabric Changes Detected - [ {{ vars_common_mcfg.changes_detected_fabric }} ]" + - "+ VRFs Changes Detected - [ {{ vars_common_mcfg.changes_detected_vrfs }} ]" + - "+ Networks Changes Detected - [ {{ vars_common_mcfg.changes_detected_networks }} ]" - "+ ----- Run Map -----" - "+ Run Map Diff Run - [ {{ run_map_read_result.diff_run }} ]" - "+ Force Run Flag - [ {{ force_run_all }} ]" diff --git a/roles/dtc/common/templates/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_attach_networks.j2 index df7032456..7d2d774af 100644 --- a/roles/dtc/common/templates/ndfc_attach_networks.j2 +++ b/roles/dtc/common/templates/ndfc_attach_networks.j2 @@ -13,10 +13,10 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_networks/msd_fabric/msd_fabric_networks.j2' %} -{% elif vxlan.fabric.type == 'MFD'%} +{% elif vxlan.fabric.type == 'MCFG'%} -{# Include NDFC MFD Base Template #} -{% include '/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2' %} +{# Include NDFC MCFG Base Template #} +{% include '/ndfc_networks/mcfg_fabric/ndfc_attach_networks.j2' %} -{# Supported fabric types are: DC VXLAN EVPN, MSDs and MFDs #} +{# Supported fabric types are: DC VXLAN EVPN, MSDs and MCFGs #} {% endif %} \ No newline at end of file diff --git a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 index eed774d48..b2a4b67ae 100644 --- a/roles/dtc/common/templates/ndfc_attach_vrfs.j2 +++ b/roles/dtc/common/templates/ndfc_attach_vrfs.j2 @@ -14,10 +14,10 @@ {% include '/ndfc_vrfs/msd_fabric/msd_fabric_vrfs.j2' %} {# {% include '/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrfs.j2' %} #} -{% elif vxlan.fabric.type == 'MFD'%} +{% elif vxlan.fabric.type == 'MCFG'%} -{# Include NDFC MFD Base Template #} -{% include '/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2' %} +{# Include NDFC MCFG Base Template #} +{% include '/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs.j2' %} -{# Supported fabric types are: DC VXLAN EVPN, MSDs and MFDs #} +{# Supported fabric types are: DC VXLAN EVPN, MSDs and MCFGs #} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric.j2 b/roles/dtc/common/templates/ndfc_fabric.j2 index 68dcc4f42..40251a2c6 100644 --- a/roles/dtc/common/templates/ndfc_fabric.j2 +++ b/roles/dtc/common/templates/ndfc_fabric.j2 @@ -19,10 +19,10 @@ {# Include NDFC MSD Base Template #} {% include '/ndfc_fabric/msd_fabric/msd_fabric_base.j2' %} -{% elif vxlan.fabric.type == 'MFD'%} +{% elif vxlan.fabric.type == 'MCFG'%} -{# Include NDFC MFD Base Template #} -{% include '/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2' %} +{# Include NDFC MCFG Base Template #} +{% include '/ndfc_fabric/mcfg_fabric/mcfg_fabric_base.j2' %} {% elif vxlan.fabric.type == 'ISN'%} @@ -34,5 +34,5 @@ {# Include NDFC External Fabric Base Template #} {% include '/ndfc_fabric/dc_external_fabric/dc_external_fabric_base.j2' %} -{# Supported fabric types are: DC VXLAN EVPN, MSD, MFD, ISN, External #} +{# Supported fabric types are: DC VXLAN EVPN, MSD, MCFG, ISN, External #} {% endif %} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/.gitkeep similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/.gitkeep rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/.gitkeep diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/dci/.gitkeep similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/.gitkeep rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/dci/.gitkeep diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/dci/mcfg_fabric_dci.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2 rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/dci/mcfg_fabric_dci.j2 diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/general/.gitkeep similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/.gitkeep rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/general/.gitkeep diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/general/mcfg_fabric_general.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2 rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/general/mcfg_fabric_general.j2 diff --git a/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/mcfg_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/mcfg_fabric_base.j2 new file mode 100644 index 000000000..414aca7f9 --- /dev/null +++ b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/mcfg_fabric_base.j2 @@ -0,0 +1,13 @@ +{# Auto-generated NDFC MultiSite Federated Domain (MCFG) Base config data structure for fabric {{ vxlan.fabric.name }} #} + +{# Include NDFC DC VXLAN EVPN General Template #} +{% include '/ndfc_fabric/mcfg_fabric/general/mcfg_fabric_general.j2' %} + +{# Include NDFC DC VXLAN EVPN DCI Template #} +{% include '/ndfc_fabric/mcfg_fabric/dci/mcfg_fabric_dci.j2' %} + +{# Include NDFC DC VXLAN EVPN Security Template #} +{% include '/ndfc_fabric/mcfg_fabric/security/mcfg_fabric_security.j2' %} + +{# Include NDFC DC VXLAN EVPN Resources Template #} +{% include '/ndfc_fabric/mcfg_fabric/resources/mcfg_fabric_resources.j2' %} diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/resources/.gitkeep similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/.gitkeep rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/resources/.gitkeep diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/resources/mcfg_fabric_resources.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2 rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/resources/mcfg_fabric_resources.j2 diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/.gitkeep b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/security/.gitkeep similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/.gitkeep rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/security/.gitkeep diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 b/roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/security/mcfg_fabric_security.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2 rename to roles/dtc/common/templates/ndfc_fabric/mcfg_fabric/security/mcfg_fabric_security.j2 diff --git a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 b/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 deleted file mode 100644 index cdaa4075c..000000000 --- a/roles/dtc/common/templates/ndfc_fabric/mfd_fabric/mfd_fabric_base.j2 +++ /dev/null @@ -1,13 +0,0 @@ -{# Auto-generated NDFC MultiSite Federated Domain (MFD) Base config data structure for fabric {{ vxlan.fabric.name }} #} - -{# Include NDFC DC VXLAN EVPN General Template #} -{% include '/ndfc_fabric/mfd_fabric/general/mfd_fabric_general.j2' %} - -{# Include NDFC DC VXLAN EVPN DCI Template #} -{% include '/ndfc_fabric/mfd_fabric/dci/mfd_fabric_dci.j2' %} - -{# Include NDFC DC VXLAN EVPN Security Template #} -{% include '/ndfc_fabric/mfd_fabric/security/mfd_fabric_security.j2' %} - -{# Include NDFC DC VXLAN EVPN Resources Template #} -{% include '/ndfc_fabric/mfd_fabric/resources/mfd_fabric_resources.j2' %} diff --git a/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2 b/roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks.j2 rename to roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks.j2 diff --git a/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2 b/roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches.j2 rename to roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches.j2 diff --git a/roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2 b/roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches_ports.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_networks/mfd_fabric/ndfc_attach_networks_switches_ports.j2 rename to roles/dtc/common/templates/ndfc_networks/mcfg_fabric/ndfc_attach_networks_switches_ports.j2 diff --git a/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2 b/roles/dtc/common/templates/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs.j2 rename to roles/dtc/common/templates/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs.j2 diff --git a/roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2 b/roles/dtc/common/templates/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs_loopbacks.j2 similarity index 100% rename from roles/dtc/common/templates/ndfc_vrfs/mfd_fabric/ndfc_attach_vrfs_loopbacks.j2 rename to roles/dtc/common/templates/ndfc_vrfs/mcfg_fabric/ndfc_attach_vrfs_loopbacks.j2 diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index a92db41a4..29105f9fb 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -64,13 +64,13 @@ when: > (MD_Extended.vxlan.fabric.type == 'MSD') -- name: Import MFD Role Tasks - ansible.builtin.import_tasks: sub_main_mfd.yml +- name: Import MCFG Role Tasks + ansible.builtin.import_tasks: sub_main_mcfg.yml when: > - (MD_Extended.vxlan.fabric.type == 'MFD') and - (vars_common_mfd.changes_detected_fabric) or - (vars_common_mfd.changes_detected_vrfs) or - (vars_common_mfd.changes_detected_networks) + (MD_Extended.vxlan.fabric.type == 'MCFG') and + (vars_common_mcfg.changes_detected_fabric) or + (vars_common_mcfg.changes_detected_vrfs) or + (vars_common_mcfg.changes_detected_networks) # Check with Matt and Pete on External Fabrics - name: Import External Fabric Role Tasks diff --git a/roles/dtc/create/tasks/mfd/child_fabrics.yml b/roles/dtc/create/tasks/mcfg/child_fabrics.yml similarity index 100% rename from roles/dtc/create/tasks/mfd/child_fabrics.yml rename to roles/dtc/create/tasks/mcfg/child_fabrics.yml diff --git a/roles/dtc/create/tasks/mfd/fabric.yml b/roles/dtc/create/tasks/mcfg/fabric.yml similarity index 97% rename from roles/dtc/create/tasks/mfd/fabric.yml rename to roles/dtc/create/tasks/mcfg/fabric.yml index f5affd10d..296743248 100644 --- a/roles/dtc/create/tasks/mfd/fabric.yml +++ b/roles/dtc/create/tasks/mcfg/fabric.yml @@ -28,7 +28,7 @@ - "+ Manage Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" -- name: Check if fabric MFD {{ MD_Extended.vxlan.fabric.name }} exists in NDFC +- name: Check if fabric MCFG {{ MD_Extended.vxlan.fabric.name }} exists in NDFC cisco.dcnm.dcnm_rest: method: GET path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}" diff --git a/roles/dtc/create/tasks/mfd/network_fed_config.yml b/roles/dtc/create/tasks/mcfg/network_fed_config.yml similarity index 100% rename from roles/dtc/create/tasks/mfd/network_fed_config.yml rename to roles/dtc/create/tasks/mcfg/network_fed_config.yml diff --git a/roles/dtc/create/tasks/mfd/vrf_fed_config.yml b/roles/dtc/create/tasks/mcfg/vrf_fed_config.yml similarity index 100% rename from roles/dtc/create/tasks/mfd/vrf_fed_config.yml rename to roles/dtc/create/tasks/mcfg/vrf_fed_config.yml diff --git a/roles/dtc/create/tasks/mfd/vrf_loopbacks.yml b/roles/dtc/create/tasks/mcfg/vrf_loopbacks.yml similarity index 85% rename from roles/dtc/create/tasks/mfd/vrf_loopbacks.yml rename to roles/dtc/create/tasks/mcfg/vrf_loopbacks.yml index 4235c2f44..d05daa984 100644 --- a/roles/dtc/create/tasks/mfd/vrf_loopbacks.yml +++ b/roles/dtc/create/tasks/mcfg/vrf_loopbacks.yml @@ -39,13 +39,13 @@ - name: Stat Previous File If It Exists ansible.builtin.stat: - path: "{{ role_path }}/../common/files/mfd/{{ MD.vxlan.fabric.name}}/{{ file_name }}" + path: "{{ role_path }}/../common/files/mcfg/{{ MD.vxlan.fabric.name}}/{{ file_name }}" register: data_file_previous delegate_to: localhost - name: Set vrf_loopback_config Var ansible.builtin.set_fact: - vrf_loopback_config: "{{ lookup('file', role_path + '/../common/files/mfd/'+ fabric_name +'/' + file_name) | from_json }}" + vrf_loopback_config: "{{ lookup('file', role_path + '/../common/files/mcfg/'+ fabric_name +'/' + file_name) | from_json }}" when: (MD_Extended.vxlan.multisite.overlay.vrfs | default([])) | length > 0 and data_file_previous.stat.exists delegate_to: localhost @@ -53,19 +53,11 @@ set_fact: attach_payload: "{{ attach_payload | default([]) + [{'vrfName':vrf.name, 'lanAttachList':vrf_loopback_config}]}}" -- name: Call API to attach VRF to Leaf Switches - cisco.dcnm.dcnm_rest: - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/v2/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/attachments" - method: "POST" - json_data: "{{ attach_payload | to_json}}" - when: MD.vxlan.fabric.type != 'MFD' - - name: Call API to attach VRF to Leaf Switches for Federated NDFCs cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD.vxlan.fabric.name }}/vrfs/attachments" method: "POST" json_data: "{{ attach_payload | to_json}}" - when: MD.vxlan.fabric.type == 'MFD' - name: Clear payload set_fact: diff --git a/roles/dtc/create/tasks/mfd/vrfs_networks.yml b/roles/dtc/create/tasks/mcfg/vrfs_networks.yml similarity index 86% rename from roles/dtc/create/tasks/mfd/vrfs_networks.yml rename to roles/dtc/create/tasks/mcfg/vrfs_networks.yml index e73ed3e80..e7e90cdfd 100644 --- a/roles/dtc/create/tasks/mfd/vrfs_networks.yml +++ b/roles/dtc/create/tasks/mcfg/vrfs_networks.yml @@ -20,11 +20,11 @@ # SPDX-License-Identifier: MIT --- -- name: Manage VRFs and Networks for MFD Entry Point +- name: Manage VRFs and Networks for MCFG Entry Point ansible.builtin.debug: msg: - "----------------------------------------------------------------" - - "+ Manage VRFs and Networks MFD Fabric {{ MD_Extended.vxlan.fabric.name }}" + - "+ Manage VRFs and Networks MCFG Fabric {{ MD_Extended.vxlan.fabric.name }}" - "----------------------------------------------------------------" tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- @@ -37,15 +37,15 @@ # when: # - MD_Extended.vxlan.multisite.overlay.vrfs is defined # - changes_detected_vrfs -# - MD_Extended.vxlan.fabric.type == 'MFD' +# - MD_Extended.vxlan.fabric.type == 'MCFG' # - name: Load VRF federated details from file # ansible.builtin.set_fact: -# fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mfd/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" +# fed_vrf_config: "{{ lookup('file', role_path + '/../common/files/mcfg/{{ MD_Extended.vxlan.fabric.name }}/' + file_name) | from_json }}" # when: # - MD_Extended.vxlan.multisite.overlay.vrfs is defined # - changes_detected_vrfs -# - MD_Extended.vxlan.fabric.type == 'MFD' +# - MD_Extended.vxlan.fabric.type == 'MCFG' - name: Get existing VRFs in Federated Fabric cisco.dcnm.dcnm_rest: @@ -55,33 +55,33 @@ when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric VRFs for Federated ansible.builtin.include_tasks: vrf_fed_config.yml - loop: "{{ vars_common_mfd.vrf_config }}" + loop: "{{ vars_common_mcfg.vrf_config }}" loop_control: loop_var: vrf when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- -# Manage Loopback VRF attachments on NDFC (MFD) +# Manage Loopback VRF attachments on NDFC (MCFG) # -------------------------------------------------------------------- - name: Call API to attach VRF to Leaf Switches for Federated NDFCs cisco.dcnm.dcnm_rest: path: /appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/{{ MD_Extended.vxlan.fabric.name }}/vrfs/attachments method: POST - json_data: "{{ vars_common_mfd.vrf_attach_config | to_json }}" + json_data: "{{ vars_common_mcfg.vrf_attach_config | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get vrf attachments list @@ -92,7 +92,7 @@ when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter vrf attachments to be removed @@ -105,7 +105,7 @@ when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Remove vrf attachments @@ -117,7 +117,7 @@ when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric VRFs @@ -129,7 +129,7 @@ when: - MD_Extended.vxlan.multisite.overlay.vrfs is defined - MD_Extended.vxlan.multisite.overlay.vrfs - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs tags: "{{ nac_tags.create_vrfs_networks }}" # -------------------------------------------------------------------- @@ -143,40 +143,40 @@ when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric Networks for Federated ansible.builtin.include_tasks: network_fed_config.yml - loop: "{{ vars_common_mfd.net_config }}" + loop: "{{ vars_common_mcfg.net_config }}" loop_control: loop_var: network when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach switches for all networks cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/attachments" method: "POST" - json_data: "{{ vars_common_mfd.network_switches | to_json }}" + json_data: "{{ vars_common_mcfg.network_switches | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks cisco.dcnm.dcnm_rest: path: "/appcenter/cisco/ndfc/api/v1/onemanage/top-down/fabrics/networks/multiattach" method: "POST" - json_data: "{{ vars_common_mfd.network_switches_ports | to_json }}" + json_data: "{{ vars_common_mcfg.network_switches_ports | to_json }}" when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Get network attachments list @@ -187,7 +187,7 @@ when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Filter network attachments to be removed @@ -200,7 +200,7 @@ when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Attach network to switches and ports for all networks @@ -211,7 +211,7 @@ when: - MD_Extended.vxlan.multisite.overlay.networks is defined - MD_Extended.vxlan.multisite.overlay.networks - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Child Fabric Networks diff --git a/roles/dtc/create/tasks/sub_main_mfd.yml b/roles/dtc/create/tasks/sub_main_mcfg.yml similarity index 91% rename from roles/dtc/create/tasks/sub_main_mfd.yml rename to roles/dtc/create/tasks/sub_main_mcfg.yml index 25bd53fbb..480320ad1 100644 --- a/roles/dtc/create/tasks/sub_main_mfd.yml +++ b/roles/dtc/create/tasks/sub_main_mcfg.yml @@ -33,10 +33,10 @@ tags: "{{ nac_tags.create }}" - name: Create NDFC Fabric - ansible.builtin.import_tasks: mfd/fabric.yml + ansible.builtin.import_tasks: mcfg/fabric.yml when: - MD_Extended.vxlan.fabric.name is defined - - vars_common_mfd.changes_detected_fabric + - vars_common_mcfg.changes_detected_fabric tags: "{{ nac_tags.create_fabric }}" - name: Debug message @@ -62,7 +62,7 @@ tags: "{{ nac_tags.create_vrfs_networks }}" - name: Manage NDFC Fabric VRFs and Networks - ansible.builtin.import_tasks: mfd/vrfs_networks.yml + ansible.builtin.import_tasks: mcfg/vrfs_networks.yml when: - MD_Extended.vxlan.multisite.overlay is defined - - vars_common_mfd.changes_detected_vrfs or vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_vrfs or vars_common_mcfg.changes_detected_networks diff --git a/roles/dtc/deploy/tasks/main.yml b/roles/dtc/deploy/tasks/main.yml index ce39c969d..874682d00 100644 --- a/roles/dtc/deploy/tasks/main.yml +++ b/roles/dtc/deploy/tasks/main.yml @@ -58,14 +58,14 @@ (child_fabrics_vrfs_networks_changed is defined and child_fabrics_vrfs_networks_changed | length > 0) or vars_common_msd.changes_detected_bgw_anycast_vip) -- name: Import MFD Fabric Role Tasks - ansible.builtin.import_tasks: sub_main_mfd.yml +- name: Import MCFG Fabric Role Tasks + ansible.builtin.import_tasks: sub_main_mcfg.yml tags: "{{ nac_tags.deploy }}" # Tags defined in roles/common_global/vars/main.yml when: > - (MD_Extended.vxlan.fabric.type == 'MFD') and - (vars_common_mfd.changes_detected_fabric or - vars_common_mfd.changes_detected_vrfs or - vars_common_mfd.changes_detected_networks) + (MD_Extended.vxlan.fabric.type == 'MCFG') and + (vars_common_mcfg.changes_detected_fabric or + vars_common_mcfg.changes_detected_vrfs or + vars_common_mcfg.changes_detected_networks) - name: Import ISN Fabric Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml diff --git a/roles/dtc/deploy/tasks/sub_main_mfd.yml b/roles/dtc/deploy/tasks/sub_main_mcfg.yml similarity index 98% rename from roles/dtc/deploy/tasks/sub_main_mfd.yml rename to roles/dtc/deploy/tasks/sub_main_mcfg.yml index 3b250bd5b..11e915054 100644 --- a/roles/dtc/deploy/tasks/sub_main_mfd.yml +++ b/roles/dtc/deploy/tasks/sub_main_mcfg.yml @@ -40,7 +40,7 @@ path: "/appcenter/cisco/ndfc/api/v1/onemanage/fabrics/{{ MD_Extended.vxlan.fabric.name }}/config-save" register: config_save when: > - MD_Extended.vxlan.fabric.type == 'MFD' + MD_Extended.vxlan.fabric.type == 'MCFG' rescue: - name: Config-Save for Fabric {{ MD_Extended.vxlan.fabric.name }} - Failed diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index aa5f5ea25..10fbcabb4 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -43,12 +43,12 @@ (vars_common_msd.changes_detected_vrfs) or (vars_common_msd.changes_detected_networks) -- name: Import MFD Role Tasks - ansible.builtin.import_tasks: sub_main_mfd.yml +- name: Import MCFG Role Tasks + ansible.builtin.import_tasks: sub_main_mcfg.yml when: > - (MD_Extended.vxlan.fabric.type == 'MFD') and - (vars_common_mfd.changes_detected_vrfs) or - (vars_common_mfd.changes_detected_networks) + (MD_Extended.vxlan.fabric.type == 'MCFG') and + (vars_common_mcfg.changes_detected_vrfs) or + (vars_common_mcfg.changes_detected_networks) - name: Import ISN Fabric Role Tasks ansible.builtin.import_tasks: sub_main_isn.yml diff --git a/roles/dtc/remove/tasks/mfd/child_fabrics.yml b/roles/dtc/remove/tasks/mcfg/child_fabrics.yml similarity index 100% rename from roles/dtc/remove/tasks/mfd/child_fabrics.yml rename to roles/dtc/remove/tasks/mcfg/child_fabrics.yml diff --git a/roles/dtc/remove/tasks/mfd/networks_fed.yml b/roles/dtc/remove/tasks/mcfg/networks_fed.yml similarity index 100% rename from roles/dtc/remove/tasks/mfd/networks_fed.yml rename to roles/dtc/remove/tasks/mcfg/networks_fed.yml diff --git a/roles/dtc/remove/tasks/mfd/vrfs_fed.yml b/roles/dtc/remove/tasks/mcfg/vrfs_fed.yml similarity index 100% rename from roles/dtc/remove/tasks/mfd/vrfs_fed.yml rename to roles/dtc/remove/tasks/mcfg/vrfs_fed.yml diff --git a/roles/dtc/remove/tasks/sub_main_mfd.yml b/roles/dtc/remove/tasks/sub_main_mcfg.yml similarity index 90% rename from roles/dtc/remove/tasks/sub_main_mfd.yml rename to roles/dtc/remove/tasks/sub_main_mcfg.yml index 09bfb40ad..829f0454c 100644 --- a/roles/dtc/remove/tasks/sub_main_mfd.yml +++ b/roles/dtc/remove/tasks/sub_main_mcfg.yml @@ -46,17 +46,17 @@ switch_list: "{{result}}" - name: Remove Fabric Networks - ansible.builtin.import_tasks: mfd/networks_fed.yml + ansible.builtin.import_tasks: mcfg/networks_fed.yml tags: "{{ nac_tags.remove_networks }}" when: - - vars_common_mfd.changes_detected_networks + - vars_common_mcfg.changes_detected_networks - name: Remove Fabric VRFs - ansible.builtin.import_tasks: mfd/vrfs_fed.yml + ansible.builtin.import_tasks: mcfg/vrfs_fed.yml tags: "{{ nac_tags.remove_vrfs }}" when: - - vars_common_mfd.changes_detected_vrfs + - vars_common_mcfg.changes_detected_vrfs - name: Remove Child Fabrics - ansible.builtin.import_tasks: mfd/child_fabrics.yml + ansible.builtin.import_tasks: mcfg/child_fabrics.yml # tags: "{{ nac_tags.remove_child_fabrics }}" From 329a8761afe64bff288948e8a479a6628ed81dfe Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Thu, 2 Oct 2025 15:56:32 +0100 Subject: [PATCH 182/183] updating rules for external fabrics --- roles/validate/files/rules/common/204_global_bootstrap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/validate/files/rules/common/204_global_bootstrap.py b/roles/validate/files/rules/common/204_global_bootstrap.py index a4b38e443..f0e25603b 100644 --- a/roles/validate/files/rules/common/204_global_bootstrap.py +++ b/roles/validate/files/rules/common/204_global_bootstrap.py @@ -12,6 +12,7 @@ def match(cls, data_model): fabric_type_map = { "VXLAN_EVPN": "ibgp", "eBGP_VXLAN": "ebgp", + "External": "external" } fabric_type = fabric_type_map.get(data_model['vxlan']['fabric']['type']) @@ -61,9 +62,10 @@ def match(cls, data_model): ) return results - if 'domain_name' in check['keys_found']: + if 'domain_name' in check['keys_found'] and fabric_type == ("ibgp" or "ebgp"): results.append(f"vxlan.global.bootstrap.{dhcp}.domain_name is not supported for bootstrap in a VXLAN type fabric.") - + elif 'domain_name' in check['keys_not_found'] and fabric_type == "external": + results.append(f"vxlan.global.bootstrap.{dhcp}.domain_name is required for bootstrap in an External type fabric.") return results @classmethod From 55d9480921ffff3fda95e29e465c5bffc7bed442 Mon Sep 17 00:00:00 2001 From: Peter Lewis Date: Mon, 6 Oct 2025 10:06:14 +0100 Subject: [PATCH 183/183] Corrected if statement --- roles/validate/files/rules/common/204_global_bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/validate/files/rules/common/204_global_bootstrap.py b/roles/validate/files/rules/common/204_global_bootstrap.py index f0e25603b..41de981fc 100644 --- a/roles/validate/files/rules/common/204_global_bootstrap.py +++ b/roles/validate/files/rules/common/204_global_bootstrap.py @@ -62,7 +62,7 @@ def match(cls, data_model): ) return results - if 'domain_name' in check['keys_found'] and fabric_type == ("ibgp" or "ebgp"): + if 'domain_name' in check['keys_found'] and fabric_type in ("ibgp", "ebgp"): results.append(f"vxlan.global.bootstrap.{dhcp}.domain_name is not supported for bootstrap in a VXLAN type fabric.") elif 'domain_name' in check['keys_not_found'] and fabric_type == "external": results.append(f"vxlan.global.bootstrap.{dhcp}.domain_name is required for bootstrap in an External type fabric.")