Skip to content

Commit dfdeb1d

Browse files
Resolving dcnm vpc pair keyError with ipAddress (#460)
* Resolving dcnm vpc pair keyError with ipAddress * Integration test changes for dcnm vpc_pair * Correcting IT changes and resolving useVirtualPeerLink unanimous valuing * Changes from PR comments
1 parent 28c16fe commit dfdeb1d

File tree

6 files changed

+146
-46
lines changed

6 files changed

+146
-46
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
all:
2+
vars:
3+
ansible_user: "admin"
4+
ansible_password: "password-secret"
5+
ansible_python_interpreter: python
6+
ansible_httpapi_validate_certs: False
7+
ansible_httpapi_use_ssl: True
8+
children:
9+
dcnm:
10+
vars:
11+
ansible_it_fabric: fabric-stage
12+
ansible_connection: ansible.netcommon.httpapi
13+
ansible_network_os: cisco.dcnm.dcnm
14+
ansible_httpapi_validate_certs: no
15+
hosts:
16+
nac-ndfc1:
17+
ansible_host: 10.10.5.1
18+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
# This playbook can be used to execute integration tests for
3+
# the role located in:
4+
#
5+
# tests/integration/targets/dcnm_image_policy
6+
#
7+
# Modify the hosts and vars sections with details for your testing
8+
# setup and uncomment the testcase you want to run.
9+
#
10+
- hosts: dcnm
11+
gather_facts: no
12+
connection: ansible.netcommon.httpapi
13+
14+
vars:
15+
switch_username: admin
16+
switch_password: "password-secret"
17+
ansible_it_fabric: fabric-stage
18+
ansible_switch1: 192.168.1.1
19+
ansible_switch2: 192.168.1.2
20+
ansible_peer1_ip: 192.168.1.1
21+
ansible_peer2_ip: 192.168.1.2
22+
ansible_vxlan_vpc_domain_id: 1000
23+
24+
config:
25+
- peerOneId: "{{ ansible_switch1 }}"
26+
peerTwoId: "{{ ansible_switch2 }}"
27+
templateName: "vpc_pair" # Using the correct template name
28+
profile:
29+
# Required fields for VPC template
30+
ADMIN_STATE: true
31+
ALLOWED_VLANS: "all"
32+
DOMAIN_ID: "{{ ansible_vxlan_vpc_domain_id }}"
33+
FABRIC_NAME: "{{ ansible_it_fabric }}"
34+
KEEP_ALIVE_HOLD_TIMEOUT: 3
35+
KEEP_ALIVE_VRF: "management"
36+
PC_MODE: "active"
37+
PEER1_KEEP_ALIVE_LOCAL_IP: "{{ ansible_peer1_ip }}"
38+
PEER1_MEMBER_INTERFACES: "eth1/1"
39+
PEER1_PCID: 1
40+
PEER2_KEEP_ALIVE_LOCAL_IP: "{{ ansible_peer2_ip }}"
41+
PEER2_MEMBER_INTERFACES: "eth1/1"
42+
PEER2_PCID: 2
43+
44+
# Additional required fields
45+
peer1Ip: "{{ ansible_peer1_ip }}"
46+
peer2Ip: "{{ ansible_peer2_ip }}"
47+
vpcDomainId: "{{ ansible_vxlan_vpc_domain_id }}"
48+
adminState: true
49+
keepAliveVrf: "management"
50+
keepAliveHoldTimeout: 3
51+
keepAliveLocalIp: "{{ ansible_peer1_ip }}"
52+
keepAliveRemoteIp: "{{ ansible_peer2_ip }}"
53+
54+
# Template specific fields
55+
templateName: "vpc_pair"
56+
templatePropId: ""
57+
templatePropName: "vpc_pair"
58+
templatePropDescription: "VPC Template"
59+
templatePropDataType: "JSON"
60+
templatePropDefaultValue: ""
61+
templatePropDisplayName: "VPC Configuration"
62+
templatePropIsMandatory: true
63+
templatePropIsMultiSelect: false
64+
templatePropIsPassword: false
65+
templatePropIsReadOnly: false
66+
templatePropIsRequired: true
67+
templatePropIsSecure: false
68+
templatePropIsSortable: false
69+
templatePropIsVisible: true
70+
templatePropOptions: []
71+
templatePropRange: []
72+
templatePropValue: ""
73+
templatePropValueType: "STRING"
74+
templateIPAddress: "{{ ansible_peer1_ip }}"
75+
76+
77+
roles:
78+
- dcnm_vpc_pair

plugins/module_utils/network/dcnm/dcnm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"long": "int",
4949
"ipV4Address": "ipv4",
5050
"ipV6Address": "ipv6",
51+
"ipAddress": "ipv4",
5152
"interfaceRange": "list",
5253
"boolean": "bool",
5354
"enum": "str",

plugins/module_utils/network/dcnm/dcnm_vpc_pair_utils.py

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -389,40 +389,43 @@ def dcnm_vpc_pair_compare_vpc_pair_objects(self, wobj, hobj):
389389

390390
mismatch_reasons = []
391391
for key in wobj:
392-
393392
if "_defaulted" in key:
394393
continue
395394

396-
if str(hobj.get(key, None)).lower() != str(wobj[key]).lower():
397-
if key == "nvPairs":
398-
continue
399-
400-
# We found an object that matched all other key values, but differs in one of the params.
401-
mismatch_reasons.append(
402-
{key.upper() + "_MISMATCH": [wobj[key], hobj.get(key, None)]}
403-
)
395+
# Special handling for useVirtualPeerlink to treat None and False as equivalent
396+
if key == "useVirtualPeerlink":
397+
# Cast both values to boolean to treat None and False equivalently
398+
hval = bool(hobj.get(key, False))
399+
wval = bool(wobj[key])
400+
if hval != wval:
401+
mismatch_reasons.append(
402+
{key.upper() + "_MISMATCH": [wobj[key], hobj.get(key, None)]}
403+
)
404+
elif key != "nvPairs": # Skip nvPairs here as it's handled separately
405+
if str(hobj.get(key, False)).lower() != str(wobj[key]).lower():
406+
mismatch_reasons.append(
407+
{key.upper() + "_MISMATCH": [wobj[key], hobj.get(key, None)]}
408+
)
404409

405410
if wobj.get("nvPairs", None) is not None:
406-
407411
for key in wobj["nvPairs"]:
408-
409412
if "_defaulted" in key:
410413
continue
411414

412-
if (
413-
str(hobj["nvPairs"].get(key, None)).lower()
414-
!= str(wobj["nvPairs"][key]).lower()
415-
):
416-
# We found an object that matched all other key values, but differs in one of the params.
417-
mismatch_reasons.append(
418-
{
419-
key.upper()
420-
+ "_MISMATCH": [
421-
wobj["nvPairs"][key],
422-
hobj["nvPairs"].get(key, None),
423-
]
424-
}
425-
)
415+
# Special handling for useVirtualPeerlink to treat None and False as equivalent
416+
if key == "useVirtualPeerlink":
417+
# Apply same boolean logic to useVirtualPeerlink in nvPairs
418+
hval = bool(hobj["nvPairs"].get(key, False))
419+
wval = bool(wobj["nvPairs"][key])
420+
if hval != wval:
421+
mismatch_reasons.append(
422+
{key.upper() + "_MISMATCH": [wval, hval]}
423+
)
424+
else:
425+
if str(hobj["nvPairs"].get(key, False)).lower() != str(wobj["nvPairs"][key]).lower():
426+
mismatch_reasons.append(
427+
{key.upper() + "_MISMATCH": [wobj["nvPairs"][key], hobj["nvPairs"].get(key, None)]}
428+
)
426429

427430
if mismatch_reasons != []:
428431
return "DCNM_VPC_PAIR_MERGE", mismatch_reasons, hobj

tests/unit/modules/dcnm/fixtures/dcnm_vpc_pair/dcnm_vpc_pair_data.json

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@
5959
"peerOneId": "SAL1820SDPP",
6060
"peerTwoId": "SAL1819S6K3",
6161
"templateName": "vpc_pair",
62-
"useVirtualPeerLink": "None"
62+
"useVirtualPeerLink": false
6363
},
6464

6565
"vpc_pair_want":
6666
{
6767
"peerOneId": "SAL1820SDPP",
6868
"peerTwoId": "SAL1819S6K3",
6969
"templateName": "vpc_pair",
70-
"useVirtualPeerLink": "None",
70+
"useVirtualPeerLink": false,
7171
"nvPairs": {
7272
"PEER2_MEMBER_INTERFACES_defaulted": false,
7373
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -110,7 +110,7 @@
110110
"peerOneId": "SAL1820SDPP",
111111
"peerTwoId": "SAL1819S6K3",
112112
"templateName": "vpc_pair",
113-
"useVirtualPeerLink": "None",
113+
"useVirtualPeerLink": false,
114114
"nvPairs": {
115115
"PEER2_MEMBER_INTERFACES_defaulted": false,
116116
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -205,7 +205,7 @@
205205
"peerOneId": "SAL1820SDPP",
206206
"peerTwoId": "SAL1819S6K3",
207207
"templateName": "vpc_pair",
208-
"useVirtualPeerLink": "None"
208+
"useVirtualPeerLink": false
209209
},
210210

211211
"vpc_pair_query_cfg_00003_11":[
@@ -246,7 +246,7 @@
246246
"peerOneId": "SAL1820SDPP",
247247
"peerTwoId": "SAL1819S6K3",
248248
"templateName": "vpc_pair",
249-
"useVirtualPeerLink": "None",
249+
"useVirtualPeerLink": false,
250250
"nvPairs": {
251251
"PEER2_MEMBER_INTERFACES_defaulted": false,
252252
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -289,7 +289,7 @@
289289
"peerOneId": "SAL1820SDPP",
290290
"peerTwoId": "SAL1819S6K3",
291291
"templateName": "vpc_pair",
292-
"useVirtualPeerLink": "None"
292+
"useVirtualPeerLink": false
293293
},
294294

295295
"vpc_pair_vpc_info_00005":
@@ -298,7 +298,7 @@
298298
"peerOneId": "10.122.84.174",
299299
"peerTwoId": "10.122.84.175",
300300
"templateName": "vpc_pair",
301-
"useVirtualPeerLink": "None",
301+
"useVirtualPeerLink": false,
302302
"profile": {
303303
"ADMIN_STATE": true,
304304
"ALLOWED_VLANS": "",
@@ -339,7 +339,7 @@
339339
"peerOneId": "10.122.85.174",
340340
"peerTwoId": "10.122.85.175",
341341
"templateName": "vpc_pair",
342-
"useVirtualPeerLink": "None",
342+
"useVirtualPeerLink": false,
343343
"profile": {
344344
"ADMIN_STATE": true,
345345
"ALLOWED_VLANS": "",
@@ -380,7 +380,7 @@
380380
"peerOneId": "10.122.86.174",
381381
"peerTwoId": "10.122.86.175",
382382
"templateName": "vpc_pair",
383-
"useVirtualPeerLink": "None",
383+
"useVirtualPeerLink": false,
384384
"profile": {
385385
"ADMIN_STATE": true,
386386
"ALLOWED_VLANS": "",
@@ -497,7 +497,7 @@
497497
"peerOneId": "SAL1820SDPP",
498498
"peerTwoId": "SAL1819S6K3",
499499
"templateName": "vpc_pair",
500-
"useVirtualPeerLink": "None",
500+
"useVirtualPeerLink": false,
501501
"nvPairs": {
502502
"PEER2_MEMBER_INTERFACES_defaulted": false,
503503
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -538,7 +538,7 @@
538538
"peerOneId": "SAL1820SDPP",
539539
"peerTwoId": "SAL1819S6K3",
540540
"templateName": "vpc_pair",
541-
"useVirtualPeerLink": "None",
541+
"useVirtualPeerLink": false,
542542
"nvPairs": {
543543
"PEER2_MEMBER_INTERFACES_defaulted": false,
544544
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -579,7 +579,7 @@
579579
"peerOneId": "SAL1820SDPQ",
580580
"peerTwoId": "SAL1819S6K4",
581581
"templateName": "vpc_pair",
582-
"useVirtualPeerLink": "None",
582+
"useVirtualPeerLink": false,
583583
"profile": {
584584
"PEER2_MEMBER_INTERFACES_defaulted": false,
585585
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -620,7 +620,7 @@
620620
"peerOneId": "SAL1820SDPR",
621621
"peerTwoId": "SAL1819S6K5",
622622
"templateName": "vpc_pair",
623-
"useVirtualPeerLink": "None",
623+
"useVirtualPeerLink": false,
624624
"profile": {
625625
"PEER2_MEMBER_INTERFACES_defaulted": false,
626626
"PEER1_MEMBER_INTERFACES_defaulted": false,
@@ -1001,7 +1001,7 @@
10011001
"peerOneId": "SAL1820SDPP",
10021002
"peerTwoId": "SAL1819S6K3",
10031003
"templateName": "vpc_pair",
1004-
"useVirtualPeerLink": null
1004+
"useVirtualPeerLink": false
10051005
},
10061006

10071007
"vpc_pair_del_list_1": [
@@ -1025,7 +1025,7 @@
10251025
"peerOneId": "SAL1820SDPP",
10261026
"peerTwoId": "SAL1819S6K3",
10271027
"templateName": "vpc_pair",
1028-
"useVirtualPeerLink":null,
1028+
"useVirtualPeerLink": false,
10291029
"nvPairs": {
10301030
"ADMIN_STATE": true,
10311031
"ALLOWED_VLANS": "all",
@@ -1062,7 +1062,7 @@
10621062
"peerOneId": "SAL1820SDPQ",
10631063
"peerTwoId": "SAL1819S6K4",
10641064
"templateName": "vpc_pair",
1065-
"useVirtualPeerLink":null,
1065+
"useVirtualPeerLink": false,
10661066
"nvPairs": {
10671067
"ADMIN_STATE": true,
10681068
"ALLOWED_VLANS": "all",
@@ -1099,7 +1099,7 @@
10991099
"peerOneId": "SAL1820SDPR",
11001100
"peerTwoId": "SAL1819S6K5",
11011101
"templateName": "vpc_pair",
1102-
"useVirtualPeerLink":null,
1102+
"useVirtualPeerLink": false,
11031103
"nvPairs": {
11041104
"ADMIN_STATE": true,
11051105
"ALLOWED_VLANS": "all",
@@ -1138,7 +1138,7 @@
11381138
"peerOneId": "SAL1820SDPP",
11391139
"peerTwoId": "SAL1819S6K3",
11401140
"templateName": "vpc_pair",
1141-
"useVirtualPeerLink":null,
1141+
"useVirtualPeerLink": false,
11421142
"nvPairs": {
11431143
"ADMIN_STATE": true,
11441144
"ALLOWED_VLANS": "all",
@@ -1175,7 +1175,7 @@
11751175
"peerOneId": "SAL1820SDPQ",
11761176
"peerTwoId": "SAL1819S6K4",
11771177
"templateName": "vpc_pair",
1178-
"useVirtualPeerLink":null,
1178+
"useVirtualPeerLink": false,
11791179
"nvPairs": {
11801180
"ADMIN_STATE": true,
11811181
"ALLOWED_VLANS": "all",
@@ -1212,7 +1212,7 @@
12121212
"peerOneId": "SAL1820SDPR",
12131213
"peerTwoId": "SAL1819S6K5",
12141214
"templateName": "vpc_pair",
1215-
"useVirtualPeerLink":null,
1215+
"useVirtualPeerLink": false,
12161216
"nvPairs": {
12171217
"ADMIN_STATE": true,
12181218
"ALLOWED_VLANS": "all",

tests/unit/modules/dcnm/fixtures/dcnm_vpc_pair/dcnm_vpc_pair_response.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@
12081208
"recommendationReason": "Switches have same role and support Virtual Fabric Peering",
12091209
"recommended": "True",
12101210
"serialNumber": "FDO24020JMT",
1211-
"useVirtualPeerlink": "False",
1211+
"useVirtualPeerlink": false,
12121212
"uuid": "None",
12131213
"vdcId": 0,
12141214
"vdcName": "None"

0 commit comments

Comments
 (0)