Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Federated fabric initial overlay management #205

Draft
wants to merge 28 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
45ca203
inital changes to support pre provisioned switches and links
mthurstocisco Oct 4, 2024
7fb269e
Added support for the VRF loopback ID and IP assignments
mthurstocisco Oct 9, 2024
4e02d85
Merge branch 'develop' into Pete&Matt
mthurstocisco Oct 9, 2024
1863fd7
removed whitespace
mthurstocisco Oct 9, 2024
f047b32
test
mthurstocisco Oct 9, 2024
5b1251c
Refactored links addition
mthurstocisco Oct 9, 2024
cc5a19f
fixed typo
mthurstocisco Oct 9, 2024
1ae1537
Fixed a further typo
mthurstocisco Oct 9, 2024
26b057a
Added additional clauses to catch apparent NDFC bug
mthurstocisco Oct 9, 2024
db355ac
Changed IP address for VRF loopback names to show ipv4 and ipv6
mthurstocisco Oct 10, 2024
c073cf5
Added fabric links create required to main.yaml in create
mthurstocisco Oct 10, 2024
ca12007
updates to turn on virtual peer link for vpc pairs
mthurstocisco Oct 11, 2024
c27e13b
Merge branch 'develop' into Pete&Matt
mthurstocisco Oct 15, 2024
9d1aa85
many changes made for federated fabric overlay management
mthurstocisco Oct 16, 2024
c0bf452
update to only add POAP section inventory if POAP exists in new Schema
mthurstocisco Oct 18, 2024
7eb2582
Merge branch 'Pete&Matt' into federated_fabric
mthurstocisco Oct 18, 2024
5670890
updates to structure so main is where fed and none fed fabrics branch
mthurstocisco Oct 18, 2024
5a27329
Pete&matt (#218)
mthurstocisco Nov 6, 2024
78a715b
Revert "Pete&matt (#218)" (#219)
mthurstocisco Nov 6, 2024
0dc816c
Reapply "Pete&matt (#218)" (#219)
mthurstocisco Nov 6, 2024
8d68eed
Added support for save and deploy using federated onemanage
mthurstocisco Nov 8, 2024
c0d835a
Latest fixes
mthurstocisco Dec 4, 2024
2ee4103
Allowing for updates to networks and VRFs
mthurstocisco Dec 5, 2024
c0bddfe
Fixed issues with defaults and support for ToR
mthurstocisco Dec 6, 2024
b6f6a39
Merge branch 'develop' into federated_fabric
mthurstocisco Jan 7, 2025
2e7b15c
removed whitespace bug and old fix for tags issue
mthurstocisco Jan 8, 2025
922d5ca
Merge branch 'federated_fabric' of https://github.com/netascode/ansib…
mthurstocisco Jan 8, 2025
6157db2
fixed prep_103 to support topology not exising for fed fabrics
mthurstocisco Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions plugins/action/common/prepare_plugins/prep_001_list_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,28 @@ def prepare(self):

# 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'] = []
if self.model_data['vxlan'].get('topology', None) is not None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had planned to address the fact that there might not be topology data in a slightly different way. The changes are not in the develop branch yet but they are in our msd branch. Instead of the if check here, earlier I add the following check and set the topology data to an empty dict. That way we still build out the entire structure even if it's empty.

https://github.com/netascode/ansible-dc-vxlan/blob/msd/plugins/action/common/prepare_plugins/prep_001_list_defaults.py#L76

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
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'] = []
if self.model_data['vxlan'].get('topology', None) is not None:
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
list_index += 1

# --------------------------------------------------------------------
# Fabric Overlay List Defaults
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,34 @@ def __init__(self, **kwargs):
def prepare(self):
model_data = self.kwargs['results']['model_extended']
# Loop over all the roles in vxlan.topology.switches.role
model_data['vxlan']['topology']['spine'] = {}
model_data['vxlan']['topology']['leaf'] = {}
model_data['vxlan']['topology']['border'] = {}
model_data['vxlan']['topology']['border_spine'] = {}
model_data['vxlan']['topology']['border_gateway'] = {}
model_data['vxlan']['topology']['border_gateway_spine'] = {}
model_data['vxlan']['topology']['super_spine'] = {}
model_data['vxlan']['topology']['border_super_spine'] = {}
model_data['vxlan']['topology']['border_gateway_super_spine'] = {}
model_data['vxlan']['topology']['tor'] = {}
model_data['vxlan']['topology']['core_router'] = {}
sm_switches = model_data['vxlan']['topology']['switches']
for switch in sm_switches:
# Build list of switch IP's based on role keyed by switch name
name = switch.get('name')
role = switch.get('role')
model_data['vxlan']['topology'][role][name] = {}
v4_key = 'management_ipv4_address'
v6_key = 'management_ipv6_address'
v4ip = switch.get('management').get(v4_key)
v6ip = switch.get('management').get(v6_key)
model_data['vxlan']['topology'][role][name][v4_key] = v4ip
model_data['vxlan']['topology'][role][name][v6_key] = v6ip

model_data = hostname_to_ip_mapping(model_data)

if model_data['vxlan'].get('topology', None) is not None:
model_data['vxlan']['topology']['spine'] = {}
model_data['vxlan']['topology']['leaf'] = {}
model_data['vxlan']['topology']['border'] = {}
model_data['vxlan']['topology']['border_spine'] = {}
model_data['vxlan']['topology']['border_gateway'] = {}
model_data['vxlan']['topology']['border_gateway_spine'] = {}
model_data['vxlan']['topology']['super_spine'] = {}
model_data['vxlan']['topology']['border_super_spine'] = {}
model_data['vxlan']['topology']['border_gateway_super_spine'] = {}
model_data['vxlan']['topology']['tor'] = {}
model_data['vxlan']['topology']['core_router'] = {}
sm_switches = model_data['vxlan']['topology']['switches']
for switch in sm_switches:
# Build list of switch IP's based on role keyed by switch name
name = switch.get('name')
role = switch.get('role')
model_data['vxlan']['topology'][role][name] = {}
v4_key = 'management_ipv4_address'
v6_key = 'management_ipv6_address'
v4ip = switch.get('management').get(v4_key)
v6ip = switch.get('management').get(v6_key)
model_data['vxlan']['topology'][role][name][v4_key] = v4ip
model_data['vxlan']['topology'][role][name][v6_key] = v6ip


model_data = hostname_to_ip_mapping(model_data)

self.kwargs['results']['model_extended'] = model_data

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ def __init__(self, **kwargs):

def prepare(self):
model_data = self.kwargs['results']['model_extended']
switches = model_data['vxlan']['topology']['switches']
if model_data['vxlan'].get('topology', None) is not None:
switches = model_data['vxlan']['topology']['switches']
else:
switches = []

# Rebuild sm_data['vxlan']['overlay_services']['vrf_attach_groups'] into
# a structure that is easier to use.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,54 @@ def __init__(self, **kwargs):
def prepare(self):
model_data = self.kwargs['results']['model_extended']

model_data['vxlan']['topology']['interfaces'] = {}
model_data['vxlan']['topology']['interfaces']['modes'] = {}
if model_data['vxlan'].get('topology', None) is not None:
model_data['vxlan']['topology']['interfaces'] = {}
model_data['vxlan']['topology']['interfaces']['modes'] = {}

# loop through interface modes and initialize with interface count 0
for mode in self.mode_direct:
model_data['vxlan']['topology']['interfaces']['modes'][mode] = {}
model_data['vxlan']['topology']['interfaces']['modes'][mode]['count'] = 0
for mode in self.mode_indirect:
model_data['vxlan']['topology']['interfaces']['modes'][mode] = {}
model_data['vxlan']['topology']['interfaces']['modes'][mode]['count'] = 0
# loop through interface modes and initialize with interface count 0
for mode in self.mode_direct:
model_data['vxlan']['topology']['interfaces']['modes'][mode] = {}
model_data['vxlan']['topology']['interfaces']['modes'][mode]['count'] = 0
for mode in self.mode_indirect:
model_data['vxlan']['topology']['interfaces']['modes'][mode] = {}
model_data['vxlan']['topology']['interfaces']['modes'][mode]['count'] = 0

for switch in model_data.get('vxlan').get('topology').get('switches'):
# loop through interfaces
for interface in switch.get('interfaces'):
# loop through interface modes direct and count
for interface_mode in self.mode_direct:
# if interface mode is a direct match, then increment the count for that mode
if interface_mode == interface.get('mode'):
model_data['vxlan']['topology']['interfaces']['modes'][interface_mode]['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# loop through interface modes indirect along with additional validation and count
if interface.get('mode') == 'access':
# if interface name starts with 'po' and has vpc_id, then it is a vpc access interface
if interface.get('name').lower().startswith('po') and interface.get('vpc_id'):
model_data['vxlan']['topology']['interfaces']['modes']['access_vpc']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# if interface name starts with 'po', then it is a port-channel access interface
elif interface.get('name').lower().startswith('po'):
model_data['vxlan']['topology']['interfaces']['modes']['access_po']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# else it is a regular access interface
else:
model_data['vxlan']['topology']['interfaces']['modes']['access']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
if interface.get('mode') == 'trunk':
# if interface name starts with 'po' and has vpc_id, then it is a vpc trunk interface
if interface.get('name').lower().startswith('po') and interface.get('vpc_id'):
model_data['vxlan']['topology']['interfaces']['modes']['trunk_vpc']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# if interface name starts with 'po', then it is a port-channel trunk interface
elif interface.get('name').lower().startswith('po'):
model_data['vxlan']['topology']['interfaces']['modes']['trunk_po']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# else it is a regular trunk interface
else:
model_data['vxlan']['topology']['interfaces']['modes']['trunk']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
for switch in model_data.get('vxlan').get('topology').get('switches'):
# loop through interfaces
for interface in switch.get('interfaces'):
# loop through interface modes direct and count
for interface_mode in self.mode_direct:
# if interface mode is a direct match, then increment the count for that mode
if interface_mode == interface.get('mode'):
model_data['vxlan']['topology']['interfaces']['modes'][interface_mode]['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# loop through interface modes indirect along with additional validation and count
if interface.get('mode') == 'access':
# if interface name starts with 'po' and has vpc_id, then it is a vpc access interface
if interface.get('name').lower().startswith('po') and interface.get('vpc_id'):
model_data['vxlan']['topology']['interfaces']['modes']['access_vpc']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# if interface name starts with 'po', then it is a port-channel access interface
elif interface.get('name').lower().startswith('po'):
model_data['vxlan']['topology']['interfaces']['modes']['access_po']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# else it is a regular access interface
else:
model_data['vxlan']['topology']['interfaces']['modes']['access']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
if interface.get('mode') == 'trunk':
# if interface name starts with 'po' and has vpc_id, then it is a vpc trunk interface
if interface.get('name').lower().startswith('po') and interface.get('vpc_id'):
model_data['vxlan']['topology']['interfaces']['modes']['trunk_vpc']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# if interface name starts with 'po', then it is a port-channel trunk interface
elif interface.get('name').lower().startswith('po'):
model_data['vxlan']['topology']['interfaces']['modes']['trunk_po']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1
# else it is a regular trunk interface
else:
model_data['vxlan']['topology']['interfaces']['modes']['trunk']['count'] += 1
model_data['vxlan']['topology']['interfaces']['modes']['all']['count'] += 1

self.kwargs['results']['model_extended'] = model_data
return self.kwargs['results']
15 changes: 12 additions & 3 deletions roles/dtc/common/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,16 @@
# SPDX-License-Identifier: MIT

---

- name: Import Role Tasks
- name: Import Role Tasks None Federated Fabric
ansible.builtin.import_tasks: sub_main.yml
tags: "{{ nac_tags.common_role }}" # Tags defined in roles/common_global/vars/main.yml
tags: "{{ nac_tags.all }}" # Tags defined in roles/common_global/vars/main.yml
delegate_to: localhost
when:
- MD.vxlan.global.fabric_type != 'MFD'

- name: Import Role Tasks Federated Fabric
ansible.builtin.import_tasks: sub_main_fed.yml
tags: "{{ nac_tags.all }}" # Tags defined in roles/common_global/vars/main.yml
delegate_to: localhost
when:
- MD.vxlan.global.fabric_type == 'MFD'
34 changes: 34 additions & 0 deletions roles/dtc/common/tasks/ndfc_get_inventory.yml
Original file line number Diff line number Diff line change
@@ -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 }}"
3 changes: 1 addition & 2 deletions roles/dtc/common/tasks/ndfc_networks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
# SPDX-License-Identifier: MIT

---

- name: Initialize changes_detected Var
ansible.builtin.set_fact:
changes_detected_networks: false
Expand Down Expand Up @@ -80,4 +79,4 @@
delegate_to: localhost
when:
- file_diff_result.file_data_changed
- check_roles['save_previous']
- check_roles['save_previous']
Loading
Loading