Skip to content

Commit cfbb0d8

Browse files
authored
Replaced changed flag #424 (#448)
* Handled edge cases for network attachment states, corrected replaced changed flag for empty attachments * fixed deletion of pending networks with attachments. Updated templates to ensure deploy flag is correct. Removed test case which is no longer applicable * modified unit test * set a consistent timer for wait_for_del_ready
1 parent 2a510f4 commit cfbb0d8

File tree

10 files changed

+137
-76
lines changed

10 files changed

+137
-76
lines changed

plugins/modules/dcnm_network.py

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ class DcnmNetwork:
495495
"GET_NET": "/rest/top-down/fabrics/{}/networks",
496496
"GET_NET_NAME": "/rest/top-down/fabrics/{}/networks/{}",
497497
"GET_VLAN": "/rest/resource-manager/vlan/{}?vlanUsageType=TOP_DOWN_NETWORK_VLAN",
498+
"GET_NET_STATUS": "/rest/top-down/fabrics/{}/networks/{}/status",
499+
"GET_NET_SWITCH_DEPLOY": "/rest/top-down/fabrics/networks/deploy"
498500
},
499501
12: {
500502
"GET_VRF": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{}/vrfs",
@@ -504,6 +506,8 @@ class DcnmNetwork:
504506
"GET_NET": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{}/networks",
505507
"GET_NET_NAME": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{}/networks/{}",
506508
"GET_VLAN": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/resource-manager/vlan/{}?vlanUsageType=TOP_DOWN_NETWORK_VLAN",
509+
"GET_NET_STATUS": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{}/networks/{}/status",
510+
"GET_NET_SWITCH_DEPLOY": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/networks/deploy"
507511
},
508512
}
509513

@@ -593,6 +597,8 @@ def find_dict_in_list_by_key_value(search: list, key: str, value: str):
593597
# -> None
594598
```
595599
"""
600+
if search is None:
601+
return None
596602
match = (d for d in search if d[key] == value)
597603
return next(match, None)
598604

@@ -1466,10 +1472,10 @@ def get_have(self):
14661472
dep_net = ""
14671473
for attach in attach_list:
14681474
torlist = []
1469-
attach_state = False if attach["lanAttachState"] == "NA" else True
1470-
deploy = attach["isLanAttached"]
1475+
attach_state = bool(attach.get("isLanAttached", False))
1476+
deploy = attach_state
14711477
deployed = False
1472-
if bool(deploy) and (attach["lanAttachState"] == "OUT-OF-SYNC" or attach["lanAttachState"] == "PENDING"):
1478+
if attach_state and (attach["lanAttachState"] == "OUT-OF-SYNC" or attach["lanAttachState"] == "PENDING"):
14731479
deployed = False
14741480
else:
14751481
deployed = True
@@ -1799,16 +1805,25 @@ def get_diff_replace(self):
17991805
diff_attach.append(r_net_dict)
18001806
all_nets += have_a["networkName"] + ","
18011807

1808+
if all_nets:
1809+
modified_all_nets = copy.deepcopy(all_nets[:-1].split(","))
1810+
# If the playbook sets the deploy key to False, then we need to remove the network from the deploy list.
1811+
for net in all_nets[:-1].split(","):
1812+
want_net_data = self.find_dict_in_list_by_key_value(search=self.config, key="net_name", value=net)
1813+
if (want_net_data is not None) and (want_net_data.get("deploy") is False):
1814+
modified_all_nets.remove(net)
1815+
all_nets = ",".join(modified_all_nets)
1816+
18021817
if not all_nets:
18031818
self.diff_create = diff_create
18041819
self.diff_attach = diff_attach
18051820
self.diff_deploy = diff_deploy
18061821
return warn_msg
18071822

18081823
if not self.diff_deploy:
1809-
diff_deploy.update({"networkNames": all_nets[:-1]})
1824+
diff_deploy.update({"networkNames": all_nets})
18101825
else:
1811-
nets = self.diff_deploy["networkNames"] + "," + all_nets[:-1]
1826+
nets = self.diff_deploy["networkNames"] + "," + all_nets
18121827
diff_deploy.update({"networkNames": nets})
18131828

18141829
self.diff_create = diff_create
@@ -2311,28 +2326,74 @@ def get_diff_query(self):
23112326

23122327
self.query = query
23132328

2329+
def detach_and_deploy_for_del(self, net):
2330+
method = "GET"
2331+
2332+
payload_net = {}
2333+
deploy_payload = {}
2334+
payload_net["networkName"] = net["networkName"]
2335+
payload_net["lanAttachList"] = []
2336+
attach_list = net["switchList"]
2337+
for atch in attach_list:
2338+
payload_atch = {}
2339+
if atch["lanAttachedState"].upper() == "PENDING":
2340+
payload_atch["serialNumber"] = atch["serialNumber"]
2341+
payload_atch["networkName"] = net["networkName"]
2342+
payload_atch["fabric"] = net["fabric"]
2343+
payload_atch["deployment"] = False
2344+
payload_net["lanAttachList"].append(payload_atch)
2345+
2346+
deploy_payload[atch["serialNumber"]] = net["networkName"]
2347+
2348+
if payload_net["lanAttachList"]:
2349+
payload = [payload_net]
2350+
method = "POST"
2351+
path = self.paths["GET_NET"].format(self.fabric) + "/attachments"
2352+
resp = dcnm_send(self.module, method, path, json.dumps(payload))
2353+
self.result["response"].append(resp)
2354+
fail, dummy_changed = self.handle_response(resp, "attach")
2355+
if fail:
2356+
self.failure(resp)
2357+
2358+
method = "POST"
2359+
path = self.paths["GET_NET_SWITCH_DEPLOY"].format(self.fabric)
2360+
resp = dcnm_send(self.module, method, path, json.dumps(deploy_payload))
2361+
self.result["response"].append(resp)
2362+
fail, dummy_changed = self.handle_response(resp, "deploy")
2363+
if fail:
2364+
self.failure(resp)
2365+
23142366
def wait_for_del_ready(self):
23152367

23162368
method = "GET"
23172369
if self.diff_delete:
23182370
for net in self.diff_delete:
23192371
state = False
2320-
path = self.paths["GET_NET_ATTACH"].format(self.fabric, net)
2321-
while not state:
2372+
path = self.paths["GET_NET_STATUS"].format(self.fabric, net)
2373+
retry = max(100 // self.WAIT_TIME_FOR_DELETE_LOOP, 1)
2374+
deploy_started = False
2375+
while not state and retry >= 0:
2376+
retry -= 1
23222377
resp = dcnm_send(self.module, method, path)
23232378
state = True
23242379
if resp["DATA"]:
2325-
attach_list = resp["DATA"][0]["lanAttachList"]
2380+
if resp["DATA"]["networkStatus"].upper() == "PENDING" and not deploy_started:
2381+
self.detach_and_deploy_for_del(resp["DATA"])
2382+
deploy_started = True
2383+
attach_list = resp["DATA"]["switchList"]
23262384
for atch in attach_list:
2327-
if atch["lanAttachState"] == "OUT-OF-SYNC" or atch["lanAttachState"] == "FAILED":
2385+
if atch["lanAttachedState"].upper() == "OUT-OF-SYNC" or atch["lanAttachedState"].upper() == "FAILED":
23282386
self.diff_delete.update({net: "OUT-OF-SYNC"})
23292387
break
2330-
if atch["lanAttachState"] != "NA":
2388+
if atch["lanAttachedState"].upper() != "NA":
23312389
self.diff_delete.update({net: "DEPLOYED"})
23322390
state = False
23332391
time.sleep(self.WAIT_TIME_FOR_DELETE_LOOP)
23342392
break
23352393
self.diff_delete.update({net: "NA"})
2394+
if retry < 0:
2395+
self.diff_delete.update({net: "TIMEOUT"})
2396+
return False
23362397

23372398
return True
23382399

@@ -2376,7 +2437,8 @@ def push_to_remote(self, is_rollback=False):
23762437

23772438
for d_a in self.diff_detach:
23782439
for v_a in d_a["lanAttachList"]:
2379-
del v_a["is_deploy"]
2440+
if v_a.get("is_deploy"):
2441+
del v_a["is_deploy"]
23802442

23812443
resp = dcnm_send(self.module, method, detach_path, json.dumps(self.diff_detach))
23822444
self.result["response"].append(resp)
@@ -2396,7 +2458,7 @@ def push_to_remote(self, is_rollback=False):
23962458
# the state of the network is "OUT-OF-SYNC"
23972459
self.wait_for_del_ready()
23982460
for net, state in self.diff_delete.items():
2399-
if state == "OUT-OF-SYNC":
2461+
if state.upper() == "OUT-OF-SYNC":
24002462
resp = dcnm_send(self.module, method, deploy_path, json.dumps(self.diff_undeploy))
24012463

24022464
self.result["response"].append(resp)
@@ -2410,9 +2472,14 @@ def push_to_remote(self, is_rollback=False):
24102472
method = "DELETE"
24112473
del_failure = ""
24122474
if self.diff_delete and self.wait_for_del_ready():
2475+
resp = ""
24132476
for net, state in self.diff_delete.items():
2414-
if state == "OUT-OF-SYNC":
2477+
if state.upper() == "OUT-OF-SYNC" or state == "TIMEOUT":
24152478
del_failure += net + ","
2479+
if state == "TIMEOUT":
2480+
resp = "Timeout waiting for network to be in delete ready state.\n"
2481+
if state == "OUT-OF-SYNC":
2482+
resp += "Network is out of sync.\n"
24162483
continue
24172484
delete_path = path + "/" + net
24182485
resp = dcnm_send(self.module, method, delete_path)
@@ -2498,7 +2565,8 @@ def push_to_remote(self, is_rollback=False):
24982565

24992566
for d_a in self.diff_attach:
25002567
for v_a in d_a["lanAttachList"]:
2501-
del v_a["is_deploy"]
2568+
if v_a.get("is_deploy"):
2569+
del v_a["is_deploy"]
25022570

25032571
for attempt in range(0, 50):
25042572
resp = dcnm_send(self.module, method, attach_path, json.dumps(self.diff_attach))

tests/integration/targets/dcnm_network/templates/self-contained-tests/net1_dhcp_conf.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626
attach:
2727
- ip_address: "{{ test_data_common.sw1 }}"
2828
ports: []
29-
deploy: false
29+
deploy: {{ test_data_common.deploy | bool }}

tests/integration/targets/dcnm_network/tests/dcnm/replaced.yaml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,11 @@
127127
register: result
128128
tags: replaced
129129

130-
# Possible bug, changed flag is not set to true when deleting attachments
131-
# - name: REPLACED - TC1 - ASSERT - Check if changed flag is true
132-
# assert:
133-
# that:
134-
# - result.changed == true
135-
# tags: replaced
130+
- name: REPLACED - TC1 - ASSERT - Check if changed flag is true
131+
assert:
132+
that:
133+
- result.changed == true
134+
tags: replaced
136135

137136
- name: REPLACED - TC1 - QUERY - Get network state in NDFC
138137
cisco.dcnm.dcnm_network:
@@ -254,11 +253,11 @@
254253
register: result
255254
tags: replaced
256255

257-
# - name: REPLACED - TC3 - ASSERT - Check if changed flag is true
258-
# assert:
259-
# that:
260-
# - result.changed == true
261-
# tags: replaced
256+
- name: REPLACED - TC3 - ASSERT - Check if changed flag is true
257+
assert:
258+
that:
259+
- result.changed == true
260+
tags: replaced
262261

263262
- name: REPLACED - TC3 - QUERY - Get network state in NDFC
264263
cisco.dcnm.dcnm_network:

tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/ingress_replication_networks.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,6 @@
129129

130130
- name: MERGED - setup - remove any networks
131131
cisco.dcnm.dcnm_network:
132-
fabric: "{{ test_fabric }}"
132+
fabric: "{{ test_data_common.fabric }}"
133133
state: deleted
134134
when: test_ing_fabric is defined

tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_dhcp_update.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
dcnm_network_merged_net1_dhcp_conf: "{{ lookup('file', '{{ test_data.net1_dhcp_conf_file }}') | from_yaml }}"
5151
delegate_to: localhost
5252

53-
# below deploy is true, reason is in comment above idempotence checl
5453
- name: SM_DHCP_UPDATE - Create New Network with many params
5554
cisco.dcnm.dcnm_network: &conf
5655
fabric: "{{ test_data_common.fabric }}"
@@ -83,7 +82,7 @@
8382

8483
- name: SM_DHCP_UPDATE - Change dhcp parameter values
8584
cisco.dcnm.dcnm_network:
86-
fabric: "{{ test_fabric }}"
85+
fabric: "{{ test_data_common.fabric }}"
8786
state: merged
8887
config: "{{ dcnm_network_merged_net1_dhcp_changed_conf }}"
8988
register: result

tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_update.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383

8484
- name: SM_MCAST_UPDATE - Change mcast parameter values
8585
cisco.dcnm.dcnm_network:
86-
fabric: "{{ test_fabric }}"
86+
fabric: "{{ test_data_common.fabric }}"
8787
state: merged
8888
config: "{{ dcnm_network_merged_net1_mcast_changed_conf }}"
8989
register: result

tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/so_dhcp_update.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
dcnm_network_merged_double_net_dhcp_conf: "{{ lookup('file', '{{ test_data.double_net_dhcp_conf_file }}') | from_yaml }}"
5151
delegate_to: localhost
5252

53-
# below deploy is true, reason is in comment above idempotence checl
5453
- name: SO_DHCP_UPDATE - Create New Network with many params
5554
cisco.dcnm.dcnm_network: &conf
5655
fabric: "{{ test_data_common.fabric }}"
@@ -83,7 +82,7 @@
8382

8483
- name: SO_DHCP_UPDATE - Override network config
8584
cisco.dcnm.dcnm_network:
86-
fabric: "{{ test_fabric }}"
85+
fabric: "{{ test_data_common.fabric }}"
8786
state: overridden
8887
config: "{{ dcnm_network_merged_double_net_dhcp_changed_conf }}"
8988
register: result

tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/so_mcast_update.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383

8484
- name: SO_MCAST_UPDATE - Override network config
8585
cisco.dcnm.dcnm_network:
86-
fabric: "{{ test_fabric }}"
86+
fabric: "{{ test_data_common.fabric }}"
8787
state: overridden
8888
config: "{{ dcnm_network_merged_double_net_mcast_changed_conf }}"
8989
register: result

0 commit comments

Comments
 (0)