Skip to content

Commit bd8c085

Browse files
authored
Fix setting hostname if host_11_1 template policy not found (#642)
* set hostname if host_11_1 template policy not found * start refactor of action plugin * refactor setting hostname * refactor setting hostname * default plugin defaults * fix encoding * remove epdb
1 parent 5d3b490 commit bd8c085

File tree

3 files changed

+151
-48
lines changed

3 files changed

+151
-48
lines changed
Lines changed: 142 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates
1+
# Copyright (c) 2025 Cisco Systems, Inc. and its affiliates
22
#
33
# Permission is hereby granted, free of charge, to any person obtaining a copy of
44
# this software and associated documentation files (the "Software"), to deal in
@@ -24,47 +24,164 @@
2424

2525
__metaclass__ = type
2626

27+
import json
28+
2729
from ansible.plugins.action import ActionBase
2830
from ansible_collections.cisco.nac_dc_vxlan.plugins.plugin_utils.helper_functions import ndfc_get_switch_policy_using_template
2931

3032

3133
class ActionModule(ActionBase):
34+
"""
35+
Action plugin to manage switch hostname policy, host_11_1,
36+
in Nexus Dashboard (ND) through comparison with the desired
37+
switch name in the data model to switch hostname policy in ND
38+
if it exists, or create it if it does not exist.
39+
"""
40+
def __init__(self, *args, **kwargs):
41+
super(ActionModule, self).__init__(*args, **kwargs)
42+
self.tmp = None
43+
self.task_vars = None
44+
self.results = {}
45+
self.results['failed'] = False
46+
self.results['changed'] = False
47+
# self.policy_add = {}
48+
self.policy_update = {}
49+
50+
def _get_switch_policy(self, switch_serial_number, template_name):
51+
"""
52+
Get switch hostname policy from Nexus Dashboard using
53+
template name (host_11_1) and switch serial number.
54+
"""
55+
return ndfc_get_switch_policy_using_template(
56+
self=self,
57+
task_vars=self.task_vars,
58+
tmp=self.tmp,
59+
switch_serial_number=switch_serial_number,
60+
template_name=template_name
61+
)
62+
63+
def nd_policy_add(self, switch_name, switch_serial_number):
64+
"""
65+
Add switch hostname policy in Nexus Dashboard.
66+
"""
67+
policy = {
68+
"nvPairs": {
69+
"SWITCH_NAME": switch_name
70+
},
71+
"entityName": "SWITCH",
72+
"entityType": "SWITCH",
73+
"source": "",
74+
"priority": "100",
75+
"description": "",
76+
"templateName": "host_11_1",
77+
"serialNumber": switch_serial_number
78+
}
79+
80+
nd_policy_add = self._execute_module(
81+
module_name="cisco.dcnm.dcnm_rest",
82+
module_args={
83+
"method": "POST",
84+
"path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies",
85+
"data": json.dumps(policy)
86+
},
87+
task_vars=self.task_vars,
88+
tmp=self.tmp
89+
)
90+
91+
if nd_policy_add.get('response'):
92+
if nd_policy_add['response']['RETURN_CODE'] == 200:
93+
self.results['changed'] = True
94+
95+
if nd_policy_add.get('msg'):
96+
if nd_policy_add['msg']['RETURN_CODE'] != 200:
97+
self.results['failed'] = True
98+
self.results['msg'] = f"For switch {switch_name} addition; {nd_policy_add['msg']['DATA']['message']}"
99+
100+
def build_policy_update(self, policy, switch_name, switch_serial_number):
101+
"""
102+
Build switch hostname policy update data structure.
103+
"""
104+
policy["nvPairs"]["SWITCH_NAME"] = switch_name
105+
self.policy_update.update({switch_serial_number: policy})
106+
107+
def nd_policy_update(self):
108+
"""
109+
Bulk update switch hostname policy in Nexus Dashboard.
110+
"""
111+
policy_ids = ",".join([str(value["policyId"]) for key, value in self.policy_update.items()])
112+
113+
nd_policy_update = self._execute_module(
114+
module_name="cisco.dcnm.dcnm_rest",
115+
module_args={
116+
"method": "PUT",
117+
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{policy_ids}/bulk",
118+
"data": json.dumps(list(self.policy_update.values()))
119+
},
120+
task_vars=self.task_vars,
121+
tmp=self.tmp
122+
)
123+
124+
if nd_policy_update.get('response'):
125+
if nd_policy_update['response']['RETURN_CODE'] == 200:
126+
self.results['changed'] = True
127+
128+
if nd_policy_update.get('msg'):
129+
if nd_policy_update['msg']['RETURN_CODE'] != 200:
130+
self.results['failed'] = True
131+
self.results['msg'] = f"Bulk update failed; {nd_policy_update['msg']['DATA']['message']}"
32132

33133
def run(self, tmp=None, task_vars=None):
34134
results = super(ActionModule, self).run(tmp, task_vars)
35135
results['changed'] = False
36136

137+
self.task_vars = task_vars
138+
self.tmp = tmp
139+
37140
model_data = self._task.args["model_data"]
38-
switch_serial_numbers = self._task.args["switch_serial_numbers"]
39141
template_name = self._task.args["template_name"]
40142

41-
policy_update = {}
143+
dm_switches = []
144+
switch_serial_numbers = []
145+
if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN', 'eBGP_VXLAN', 'ISN', 'External'):
146+
dm_switches = model_data["vxlan"]["topology"]["switches"]
147+
switch_serial_numbers = [dm_switch['serial_number'] for dm_switch in dm_switches]
42148

43149
for switch_serial_number in switch_serial_numbers:
44-
policy_match = ndfc_get_switch_policy_using_template(
45-
self=self,
46-
task_vars=task_vars,
47-
tmp=tmp,
48-
switch_serial_number=switch_serial_number,
49-
template_name=template_name
50-
)
51-
52-
dm_switches = []
53-
if model_data["vxlan"]["fabric"]["type"] in ('VXLAN_EVPN', 'eBGP_VXLAN', 'ISN', 'External'):
54-
dm_switches = model_data["vxlan"]["topology"]["switches"]
55-
# elif model_data["vxlan"]["fabric"]["type"] in ('ISN'):
56-
# dm_switches = model_data["vxlan"]["multisite"]["isn"]["topology"]["switches"]
150+
policy_match = self._get_switch_policy(switch_serial_number, template_name)
57151

58152
switch_match = next((item for item in dm_switches if item["serial_number"] == switch_serial_number))
59153

60-
if policy_match["nvPairs"]["SWITCH_NAME"] != switch_match["name"]:
61-
results['changed'] = True
62-
policy_match["nvPairs"]["SWITCH_NAME"] = switch_match["name"]
63-
policy_update.update({switch_serial_number: policy_match})
64-
65-
if policy_update:
66-
results['changed'] = True
67-
68-
results['policy_update'] = policy_update
154+
if not policy_match:
155+
self.nd_policy_add(
156+
switch_name=switch_match['name'],
157+
switch_serial_number=switch_serial_number
158+
)
159+
160+
if self.results['failed']:
161+
results['failed'] = self.results['failed']
162+
results['msg'] = self.results['msg']
163+
return results
164+
165+
if self.results['changed']:
166+
results['changed'] = self.results['changed']
167+
168+
if policy_match:
169+
if policy_match["nvPairs"]["SWITCH_NAME"] != switch_match['name']:
170+
self.build_policy_update(
171+
policy=policy_match,
172+
switch_name=switch_match['name'],
173+
switch_serial_number=switch_serial_number
174+
)
175+
176+
if self.policy_update:
177+
self.nd_policy_update()
178+
179+
if self.results['failed']:
180+
results['failed'] = self.results['failed']
181+
results['msg'] = self.results['msg']
182+
return results
183+
184+
if self.results['changed']:
185+
results['changed'] = self.results['changed']
69186

70187
return results

plugins/plugin_utils/helper_functions.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,12 @@ def ndfc_get_switch_policy_using_template(self, task_vars, tmp, switch_serial_nu
133133
(item for item in policy_data["response"]["DATA"] if item["templateName"] == template_name and item['serialNumber'] == switch_serial_number)
134134
)
135135
except StopIteration:
136-
err_msg = f"Policy for template {template_name} and switch {switch_serial_number} not found!"
137-
err_msg += f" Please ensure switch with serial number {switch_serial_number} is part of the fabric."
138-
raise Exception(err_msg)
136+
if template_name == "host_11_1":
137+
policy_match = None
138+
else:
139+
err_msg = f"Policy for template {template_name} and switch {switch_serial_number} not found!"
140+
err_msg += f" Please ensure switch with serial number {switch_serial_number} is part of the fabric."
141+
raise Exception(err_msg)
139142

140143
return policy_match
141144

roles/dtc/create/tasks/common/devices_discovery.yml

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -115,31 +115,14 @@
115115
ansible_connect_timeout: 3000
116116
when:
117117
- MD_Extended.vxlan.topology.switches | length > 0
118+
- MD_Extended.vxlan.underlay.general.manual_underlay_allocation is defined
119+
- MD_Extended.vxlan.underlay.general.manual_underlay_allocation
118120
- change_flags.changes_detected_inventory or
119121
(change_flags.changes_detected_underlay_ip_address is defined and change_flags.changes_detected_underlay_ip_address)
120122

121-
- name: Create List of Switch Serial Numbers from Data Model
122-
ansible.builtin.set_fact:
123-
md_serial_numbers: "{{ MD_Extended.vxlan.topology.switches | map(attribute='serial_number') | list }}"
124-
delegate_to: localhost
125-
126123
- name: Build Switch Hostname Policy Payload from Data Model Update
127124
cisco.nac_dc_vxlan.dtc.update_switch_hostname_policy:
128125
model_data: "{{ MD_Extended }}"
129-
switch_serial_numbers: "{{ md_serial_numbers }}"
130126
template_name: host_11_1
131-
register: results
127+
when: MD_Extended.vxlan.topology.switches | length > 0
132128
# do not delegate_to: localhost as this action plugin uses Python to execute cisco.dcnm.dcnm_rest
133-
134-
- name: Join List of Switch Hostname Policy IDs from Nexus Dashboard
135-
ansible.builtin.set_fact:
136-
policy_ids: "{{ results.policy_update.values() | map(attribute='policyId') | list | join('%2C') }}"
137-
when: results.policy_update | length > 0
138-
delegate_to: localhost
139-
140-
- name: Update Switch Hostname Policy in Nexus Dashboard
141-
cisco.dcnm.dcnm_rest:
142-
method: PUT
143-
path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/policies/{{ policy_ids }}/bulk"
144-
json_data: "{{ results.policy_update.values() | list | to_json }}"
145-
when: results.policy_update | length > 0

0 commit comments

Comments
 (0)