From e1ad4e6f9dcac0b5a6f2ef454768bf2e59e1dfa6 Mon Sep 17 00:00:00 2001 From: rrahimm <39684933+rrahimm@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:45:47 +0530 Subject: [PATCH] VPC_Peering (#71) * add filter for non-vpc peer interfaces * Create ndfc_vpc_peering.yml * Create ndfc_vpc_peering.j2 * Update vpc_peering.yml * Update ndfc_interface_vpc_peer_link.j2 * Update main.yml * Update main.yml * Create ndfc_interface_vpc_peering.j2 * Update vpc_peering.yml * update vpc files * Update main.yml * adjust title heading in ndfc_interface_vpc_peering.j2 * update j2 file descriptions * set deploy to false for vpc peering interface list build * limit vpc peering paramters to just what is supported by vxlan fabric --------- Co-authored-by: Matt Tarkington --- roles/dtc/common/tasks/main.yml | 21 ++++-- roles/dtc/common/tasks/ndfc_vpc_peering.yml | 36 +++++++++++ .../templates/ndfc_interface_vpc_peering.j2 | 37 +++++++++++ .../dtc/common/templates/ndfc_vpc_peering.j2 | 19 ++++++ roles/dtc/create/tasks/main.yml | 6 +- roles/dtc/create/tasks/setup_vpc_peer.yml | 58 ----------------- roles/dtc/create/tasks/vpc.yml | 64 ------------------- roles/dtc/create/tasks/vpc_peering.yml | 37 +++++++++++ .../templates/ndfc_interface_vpc_peer_link.j2 | 20 ++++++ roles/dtc/remove/tasks/main.yml | 8 +++ 10 files changed, 174 insertions(+), 132 deletions(-) create mode 100644 roles/dtc/common/tasks/ndfc_vpc_peering.yml create mode 100644 roles/dtc/common/templates/ndfc_interface_vpc_peering.j2 create mode 100644 roles/dtc/common/templates/ndfc_vpc_peering.j2 delete mode 100644 roles/dtc/create/tasks/setup_vpc_peer.yml delete mode 100644 roles/dtc/create/tasks/vpc.yml create mode 100644 roles/dtc/create/tasks/vpc_peering.yml create mode 100644 roles/dtc/create/templates/ndfc_interface_vpc_peer_link.j2 diff --git a/roles/dtc/common/tasks/main.yml b/roles/dtc/common/tasks/main.yml index 0da770cd..3c300370 100644 --- a/roles/dtc/common/tasks/main.yml +++ b/roles/dtc/common/tasks/main.yml @@ -20,6 +20,13 @@ path: "{{ role_path }}/files/.gitkeep" state: touch +# -------------------------------------------------------------------- +# Build Create Fabric parameter List From Template +# -------------------------------------------------------------------- + +- name: Build Fabric Create Parameters + ansible.builtin.include_tasks: ndfc_fabric.yml + # -------------------------------------------------------------------- # Build NDFC Fabric Switch Inventory List From Template # -------------------------------------------------------------------- @@ -27,6 +34,13 @@ - name: Build NDFC Fabric Switch Inventory List From Template ansible.builtin.include_tasks: ndfc_inventory.yml +# -------------------------------------------------------------------- +# Build VPC Peering parameter List From Template +# -------------------------------------------------------------------- + +- name: Build VPC Peering Parameters + ansible.builtin.include_tasks: ndfc_vpc_peering.yml + # -------------------------------------------------------------------- # Build NDFC Fabric VRFs Attach List From Template # -------------------------------------------------------------------- @@ -110,10 +124,3 @@ - name: Build Fabric interface All List From Template ansible.builtin.include_tasks: ndfc_interface_all.yml - -# -------------------------------------------------------------------- -# Build Create Fabric parameter List From Template -# -------------------------------------------------------------------- - -- name: Build Fabric Create Parameters - ansible.builtin.include_tasks: ndfc_fabric.yml diff --git a/roles/dtc/common/tasks/ndfc_vpc_peering.yml b/roles/dtc/common/tasks/ndfc_vpc_peering.yml new file mode 100644 index 00000000..ce8b9b40 --- /dev/null +++ b/roles/dtc/common/tasks/ndfc_vpc_peering.yml @@ -0,0 +1,36 @@ +--- +- name: Set interface_vpc_peering_file_name Var + ansible.builtin.set_fact: + interface_vpc_peering_file_name: "{{ MD.fabric.global.name }}_ndfc_interface_vpc_peering_.yml" + +- name: Build Interfaces for VPC Peering + ansible.builtin.template: + src: ndfc_interface_vpc_peering.j2 + dest: "{{ role_path }}/files/{{ interface_vpc_peering_file_name }}" + +- name: Set interface_vpc_peering Var default + ansible.builtin.set_fact: + interface_vpc_peering: [] + +- name: Set interface_vpc_peering Var + ansible.builtin.set_fact: + interface_vpc_peering: "{{ lookup('file', interface_vpc_peering_file_name) | from_yaml }}" + when: MD_Extended.fabric.topology.vpc_peers | length > 0 + +- name: Set vpc_peering_file_name Var + ansible.builtin.set_fact: + vpc_peering_file_name: "{{ MD.fabric.global.name }}_ndfc_vpc_peering.yml" + +- name: Build vPC Peering + ansible.builtin.template: + src: ndfc_vpc_peering.j2 + dest: "{{ role_path }}/files/{{ vpc_peering_file_name }}" + +- name: Set vpc_peering Var default + ansible.builtin.set_fact: + vpc_peering: [] + +- name: Set vpc_peering Var + ansible.builtin.set_fact: + vpc_peering: "{{ lookup('file', vpc_peering_file_name) | from_yaml }}" + when: MD_Extended.fabric.topology.vpc_peers | length > 0 diff --git a/roles/dtc/common/templates/ndfc_interface_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_interface_vpc_peering.j2 new file mode 100644 index 00000000..f725be4b --- /dev/null +++ b/roles/dtc/common/templates/ndfc_interface_vpc_peering.j2 @@ -0,0 +1,37 @@ +--- +# This NDFC interface vPC Peering config data structure is auto-generated +# DO NOT EDIT MANUALLY +# +#jinja2: trim_blocks: True, lstrip_blocks: False +{% for peers in MD_Extended.fabric.topology.vpc_peers %} +{% for interface in peers['peer1_peerlink_interfaces'] %} +- name : {{ interface['name'] }} + type: eth + switch: +{% set switch = MD_Extended.fabric.topology.leaf[peers.peer1] %} +{% if switch.management_ipv4_address is defined %} + - {{ switch.management_ipv4_address}} +{% elif (switch.management_ipv4_address is not defined) and (switch.management_ipv6_address is defined) %} + - {{ switch.management_ipv6_address}} +{% endif %} + deploy: false + profile: + admin_state: True + mode: 'trunk' +{% endfor %} +{% for interface in peers['peer2_peerlink_interfaces'] %} +- name : {{ interface['name'] }} + type: eth + switch: +{% set switch = MD_Extended.fabric.topology.leaf[peers.peer2] %} +{% if switch.management_ipv4_address is defined %} + - {{ switch.management_ipv4_address}} +{% elif (switch.management_ipv4_address is not defined) and (switch.management_ipv6_address is defined) %} + - {{ switch.management_ipv6_address}} +{% endif %} + deploy: true + profile: + admin_state: True + mode: 'trunk' +{% endfor %} +{% endfor %} diff --git a/roles/dtc/common/templates/ndfc_vpc_peering.j2 b/roles/dtc/common/templates/ndfc_vpc_peering.j2 new file mode 100644 index 00000000..9b8de14b --- /dev/null +++ b/roles/dtc/common/templates/ndfc_vpc_peering.j2 @@ -0,0 +1,19 @@ +--- +# This NDFC vPC Peering config data structure is auto-generated +# DO NOT EDIT MANUALLY +# + +{% if MD.fabric.topology.vpc_peers is defined and MD.fabric.topology.vpc_peers is not none %} +{% for vpc_peer in MD.fabric.topology.vpc_peers %} +{% if MD_Extended.fabric.topology.leaf[vpc_peer.peer1].management_ipv4_address is not none %} +- peerOneId: {{ MD_Extended.fabric.topology.leaf[vpc_peer.peer1].management_ipv4_address }} +{% elif MD_Extended.fabric.topology.leaf[vpc_peer.peer1].management_ipv6_address is not none %} +- peerOneId: {{ MD_Extended.fabric.topology.leaf[vpc_peer.peer1].management_ipv6_address }} +{% endif %} +{% if MD_Extended.fabric.topology.leaf[vpc_peer.peer2].management_ipv4_address is not none %} + peerTwoId: {{ MD_Extended.fabric.topology.leaf[vpc_peer.peer2].management_ipv4_address }} +{% elif MD_Extended.fabric.topology.leaf[vpc_peer.peer2].management_ipv6_address is not none %} + peerTwoId: {{ MD_Extended.fabric.topology.leaf[vpc_peer.peer2].management_ipv6_address }} +{% endif %} +{% endfor %} +{% endif %} diff --git a/roles/dtc/create/tasks/main.yml b/roles/dtc/create/tasks/main.yml index 2ae599f7..4621f238 100644 --- a/roles/dtc/create/tasks/main.yml +++ b/roles/dtc/create/tasks/main.yml @@ -18,9 +18,9 @@ ansible.builtin.include_tasks: devices.yml when: MD_Extended.fabric.topology.switches | length > 0 -# - name: Manage VPC Peering -# ansible.builtin.include_tasks: vpc.yml -# when: MD.fabric.overlay_services is defined +- name: Manage VPC Peering + ansible.builtin.include_tasks: vpc_peering.yml + when: MD_Extended.fabric.topology.vpc_peers | length > 0 - name: Manage NDFC Fabric Interfaces ansible.builtin.include_tasks: interfaces.yml diff --git a/roles/dtc/create/tasks/setup_vpc_peer.yml b/roles/dtc/create/tasks/setup_vpc_peer.yml deleted file mode 100644 index 80a1ff44..00000000 --- a/roles/dtc/create/tasks/setup_vpc_peer.yml +++ /dev/null @@ -1,58 +0,0 @@ ---- -# - name: Query Fabric {{ MD.fabric.global.name }} Leaf1 and Leaf2 for VPC Configuration -# cisco.dcnm.dcnm_inventory: -# fabric: "{{ MD.fabric.global.name }}" -# state: query -# config: -# - seed_ip: "{{ MD.fabric.topology.leaf[item.peer1].management_ipv4_address }}" -# - seed_ip: "{{ MD.fabric.topology.leaf[item.peer2].management_ipv4_address }}" -# register: query_result -# loop: "{{ MD.fabric.topology.vpc_peers }}" - -- name: query leaf serial number of {{ MD.fabric.global.name }} - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD.fabric.global.name }}" - state: query - config: - - seed_ip: "{{ MD.fabric.topology.leaf['dc1-leaf1'].management_ipv4_address }}" - - seed_ip: "{{ MD.fabric.topology.leaf['dc1-leaf2'].management_ipv4_address }}" - register: leaf_sws - -- name: enable peer link on leaf switches of {{ MD.fabric.global.name }} - cisco.dcnm.dcnm_interface: - fabric: "{{ MD.fabric.global.name }}" - state: merged - config: - - name: "{{ MD.fabric.topology.leaf[leaf.peer1_peerlink_interfaces[0].name] }}" - type: eth - admin_state: true - switch: - - "{{ MD.fabric.topology.leaf[leaf.peer1].management_ipv4_address }}" - profile: - mode: trunk - - name: eth1/4 - type: eth - admin_state: true - switch: - - "{{ MD.fabric.topology.leaf[leaf.peer2].management_ipv4_address }}" - profile: - mode: trunk - ignore_errors: true - loop_control: - loop_var: leaf - loop: "{{ MD.fabric.topology.vpc_peers }}" - # loop: - # - ip: "{{ MD.fabric.topology.leaf[leaf.peer1].management_ipv4_address }}" - # - ip: "{{ MD.fabric.topology.leaf[leaf.peer2].management_ipv4_address }}" - -- name: "create VPC peer on leaf {{ MD.fabric.topology.leaf['dc1-leaf1'].management_ipv4_address }}|{{ MD.fabric.topology.leaf['dc1-leaf2'].management_ipv4_address }}" - vars: - payload: - peerOneId: "{{leaf_sws.response[0].serialNumber}}" - peerTwoId: "{{leaf_sws.response[1].serialNumber}}" - useVirtualPeerlink: false - cisco.dcnm.dcnm_rest: - method: POST - path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/vpcpair" - json_data: "{{ payload | to_json }}" - ignore_errors: true \ No newline at end of file diff --git a/roles/dtc/create/tasks/vpc.yml b/roles/dtc/create/tasks/vpc.yml deleted file mode 100644 index 54f779e7..00000000 --- a/roles/dtc/create/tasks/vpc.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- - -- name: Manage vPC Pairs - ansible.builtin.debug: - msg: - - "----------------------------------------------------------------" - - "+ Manage vPC Pairs Fabric {{ MD.fabric.global.name }}" - - "----------------------------------------------------------------" - -- debug: msg="{{ item.peer1 }}, {{ item.peer2 }}" - loop: "{{ MD.fabric.topology.vpc_peers }}" - - -- name: Query Fabric {{ MD.fabric.global.name }} Peers for VPC Configuration - cisco.dcnm.dcnm_inventory: - fabric: "{{ MD.fabric.global.name }}" - state: query - config: - - seed_ip: "{{ MD.fabric.topology.leaf[item.peer1].management_ipv4_address }}" - - seed_ip: "{{ MD.fabric.topology.leaf[item.peer2].management_ipv4_address }}" - register: vpc_data - loop: "{{ MD.fabric.topology.vpc_peers }}" - -- name: Check vPC Pair Status - cisco.nac_dc_vxlan.dtc.vpc_pair_check: - vpc_data: "{{ vpc_data }}" - - -- meta: end_play - -# Use flag variable 'setup_vpc' to track if you need to setup vpc. -# If it's already setup you can skip it -- ansible.builtin.set_fact: - setup_vpc: True - -- ansible.builtin.set_fact: - setup_vpc: False - when: item.isVpcConfigured == true - loop: "{{ vpc_data.results[0].response }}" - loop_control: - label: "{{ item.isVpcConfigured }}" - -- debug: msg="Setup VPC IS - {{ setup_vpc }}" - - -- name: Setup VPC Peer If Not Already Setup - block: - - name: Include Tasks To Create VPC Peer Between Devices - ansible.builtin.import_tasks: setup_vpc_peer.yml - when: setup_vpc - -# - name: Query Fabric {{ MD.fabric.global.name }} Leaf Devices Until vPC Pair Is Configured -# cisco.dcnm.dcnm_inventory: -# fabric: "{{ MD.fabric.global.name }}" -# state: query -# config: -# - seed_ip: "{{ MD.fabric.topology.leaf['dc1-leaf1'].management_ipv4_address }}" -# - seed_ip: "{{ MD.fabric.topology.leaf['dc1-leaf2'].management_ipv4_address }}" -# register: query_result -# until: -# - query_result.response[0].isVpcConfigured -# - query_result.response[1].isVpcConfigured -# retries: 120 -# delay: 5 diff --git a/roles/dtc/create/tasks/vpc_peering.yml b/roles/dtc/create/tasks/vpc_peering.yml new file mode 100644 index 00000000..ad900c5d --- /dev/null +++ b/roles/dtc/create/tasks/vpc_peering.yml @@ -0,0 +1,37 @@ +--- + +- name: Query for vPC Peering Interfaces + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.fabric.global.name }}" + state: query + config: "{{ interface_vpc_peering }}" + register: interface_vpc_peering_query + +- name: Get Interfaces Not Associated to vPC Peering Policy + ansible.builtin.set_fact: + interface_not_vpc_policy: "{{ interface_vpc_peering_query.response | community.general.json_query(vpc_peer_policy_query) }}" + vars: + vpc_peer_policy_query: "[?(@.policy!=`int_vpc_peer_link_po_member_11_1`)]" + +- name: Generate Config Payload Update for Interfaces Not Associated to vPC Peering Policy + ansible.builtin.set_fact: + interface_vpc_peering_payload: "{{ lookup('template', 'ndfc_interface_vpc_peer_link.j2') }}" + when: interface_not_vpc_policy | length > 0 + +- name: Manage Interfaces for vPC Peering + cisco.dcnm.dcnm_interface: + fabric: "{{ MD.fabric.global.name }}" + state: replaced + config: "{{ interface_vpc_peering_payload | from_yaml }}" + deploy: true + vars: + ansible_command_timeout: 3000 + ansible_connect_timeout: 3000 + when: interface_not_vpc_policy | length > 0 + +- name: Manage vPC Peering + cisco.dcnm.dcnm_vpc_pair: + src_fabric: "{{ MD.fabric.global.name }}" + deploy: false + state: replaced + config: "{{ vpc_peering }}" diff --git a/roles/dtc/create/templates/ndfc_interface_vpc_peer_link.j2 b/roles/dtc/create/templates/ndfc_interface_vpc_peer_link.j2 new file mode 100644 index 00000000..33f451f2 --- /dev/null +++ b/roles/dtc/create/templates/ndfc_interface_vpc_peer_link.j2 @@ -0,0 +1,20 @@ +# This NDFC vPC peer-link interface config data structure is auto-generated +# DO NOT EDIT MANUALLY +# + +{% for item in interface_not_vpc_peering %} +{% set switch_serial_number = item.interfaces[0].serialNumber %} +{% set query = "[?(@.serial_number==`" ~ switch_serial_number ~ "`)].management" %} +{% set switch_management = (MD.fabric.topology.switches | community.general.json_query(query))[0] %} +- name: {{ item.interfaces[0].ifName }} + type: eth + 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 %} + profile: + admin_state: true + mode: trunk +{% endfor %} diff --git a/roles/dtc/remove/tasks/main.yml b/roles/dtc/remove/tasks/main.yml index 0eb4265c..71940bea 100644 --- a/roles/dtc/remove/tasks/main.yml +++ b/roles/dtc/remove/tasks/main.yml @@ -42,3 +42,11 @@ vars: ansible_command_timeout: 3000 ansible_connect_timeout: 3000 + +- debug: msg="Removing all Unmanaged vPC Peering. This could take several minutes..." +- name: Remove vPC Peering + cisco.dcnm.dcnm_vpc_pair: + src_fabric: "{{ MD.fabric.global.name }}" + deploy: false + state: overridden + config: "{{ vpc_peering }}" \ No newline at end of file