From da4e9aa221fae99f174b0cfb4d2d46230342eaec Mon Sep 17 00:00:00 2001 From: anvitha-jain Date: Wed, 28 Aug 2024 11:13:12 -0700 Subject: [PATCH] [ignore_changes] Fixes idempotancy of mac_sec_keys on update. --- plugins/modules/ndo_mac_sec_policy.py | 111 +++++++++++------- .../targets/ndo_mac_sec_policy/tasks/main.yml | 58 ++++----- 2 files changed, 100 insertions(+), 69 deletions(-) diff --git a/plugins/modules/ndo_mac_sec_policy.py b/plugins/modules/ndo_mac_sec_policy.py index 08594842..88d4e056 100644 --- a/plugins/modules/ndo_mac_sec_policy.py +++ b/plugins/modules/ndo_mac_sec_policy.py @@ -106,7 +106,8 @@ psk: description: - The Pre-Shared Key (PSK) for the MACSec Key. - - PSK has to be 64 chars long. + - PSK has to be 64 chars long if cipher suite is 256_gcm_aes or 256_gcm_aes_xpn. + - PSK has to be 32 chars long if cipher suite is 128_gcm_aes or 128_gcm_aes_xpn. - PSK has to be Hex chars [0-9a-fA-F] type: str required: true @@ -114,6 +115,7 @@ description: - The start time for the MACSec Key. - The date time format - YYYY-MM-DD HH:MM:SS or 'now' + - The start time for each key_name should be unique. - The default value is now. type: str end_time: @@ -310,31 +312,48 @@ def main(): ops.append(dict(op="replace", path="{0}/{1}/macsecParams/keyServerPrio".format(path, match.index), value=key_server_priority)) match.details["macsecParams"]["keyServerPrio"] = key_server_priority - # if mac_sec_keys: - # mac_sec_keys_list = [] - # for mac_sec_key in mac_sec_keys: - # # if mac_sec_key.get("key_name") and match.details.get("macsecParams")["macsecKeys"]: - - # keyname = mac_sec_key.get("key_name") - # psk = mac_sec_key.get("psk") - # start = mac_sec_key.get("start_time") - # end = mac_sec_key.get("end_time") - - # mac_sec_keys_list.append( - # dict( - # keyname=keyname, - # psk=psk, - # start=start, - # end=end, - # ) - # ) - # ops.append(dict(op="replace", path="{0}/{1}/macsecKeys".format(path, match.index), value=mac_sec_keys_list)) - # match.details["macsecParams"]["macsecKeys"] = mac_sec_keys_list - + if mac_sec_keys: + mac_sec_keys_list = [] + existing_keys = match.details.get("macsecKeys", []) + + for mac_sec_key in mac_sec_keys: + key_found = False + for key in existing_keys: + if key.get("keyname") == mac_sec_key.get("key_name"): + key_found = True + # Check if the existing key needs to be updated + if ((key.get("start") != mac_sec_key.get("start") and mac_sec_key.get("start") != None) or (key.get("end") != mac_sec_key.get("end") and mac_sec_key.get("end") != None)): + mac_sec_key_dict = { + "keyname": mac_sec_key.get("key_name"), + "psk": mac_sec_key.get("psk"), + "start": mac_sec_key.get("start"), + "end": mac_sec_key.get("end"), + } + mac_sec_keys_list.append(mac_sec_key_dict) + else: + # If no update is needed, append the existing key + mac_sec_keys_list.append(key) + break + if not key_found: + # Add new mac_sec_key to the list + mac_sec_keys_list.append( + dict( + keyname=mac_sec_key.get("key_name"), + psk=mac_sec_key.get("psk"), + start=mac_sec_key.get("start"), + end=mac_sec_key.get("end"), + ) + ) + mso.stdout += str("\n mac_sec_keys_list ") + str(mac_sec_keys_list) + + ops.append(dict(op="replace", path="{0}/{1}/macsecKeys".format(path, match.index), value=mac_sec_keys_list)) + mso.stdout += str("\n REPLACEops ") + str(ops) + match.details["macsecKeys"] = mac_sec_keys mso.sanitize(match.details) else: + mso.stdout += str("\n IN ELSE PRESENT ") mac_sec_param_map ={} payload = {"name": mac_sec_policy, "templateId": mso_template.template.get("templateId"), "schemaId": mso_template.template.get("schemaId")} @@ -359,28 +378,37 @@ def main(): if key_server_priority: mac_sec_param_map["keyServerPrio"] = key_server_priority - payload["macsecParams"] = mac_sec_param_map - - mac_sec_keys_list = [] - if mac_sec_keys: - for mac_sec_key in mac_sec_keys: - keyname = mac_sec_key.get("key_name") - psk = mac_sec_key.get("psk") - start = mac_sec_key.get("start_time") - end = mac_sec_key.get("end_time") - - mac_sec_keys_list.append( - dict( - keyname=keyname, - psk=psk, - start=start, - end=end, - ) - ) - payload["macsecKeys"] = mac_sec_keys_list + payload["macsecParams"] = mac_sec_param_map + + mac_sec_keys_list = [] + if mac_sec_keys: + for mac_sec_key in mac_sec_keys: + mac_sec_key_dict = { + "keyname": mac_sec_key.get("key_name"), + "psk": mac_sec_key.get("psk"), + } + if mac_sec_key.get("start_time"): + mac_sec_key_dict["startTime"] = mac_sec_key.get("start_time") + if mac_sec_key.get("end_time"): + mac_sec_key_dict["endTime"] = mac_sec_key.get("end_time") + mac_sec_keys_list.append(mac_sec_key_dict) + + # mac_sec_keys_list.append( + # dict( + # keyname=keyname, + # psk=psk, + # start=start, + # end=end, + # ) + # ) + payload["macsecKeys"] = mac_sec_keys_list + + mso.stdout += str("\n mac_sec_keys_list ") + str(mac_sec_keys_list) + mso.stdout += str("\n payload ") + str(payload) ops.append(dict(op="add", path="{0}/-".format(path), value=copy.deepcopy(payload))) + mso.stdout += str("\n\n CREATE ops ") + str(ops) mso.sanitize(payload) @@ -392,6 +420,7 @@ def main(): mso.existing = {} if not module.check_mode and ops: + msos = mso_template.template.get("schemaId") mso.request(mso_template.template_path, method="PATCH", data=ops) mso.stdout += str("\n\n ops ") + str(ops) + str("\n request ") + str(mso_template.template_path) diff --git a/tests/integration/targets/ndo_mac_sec_policy/tasks/main.yml b/tests/integration/targets/ndo_mac_sec_policy/tasks/main.yml index 06155174..f2718e65 100644 --- a/tests/integration/targets/ndo_mac_sec_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_mac_sec_policy/tasks/main.yml @@ -88,17 +88,14 @@ template: ansible_fabric_policy_template mac_sec_policy: ansible_mac_sec_policy_2 type: access - # mac_sec_key: - # - key_name: abc12 - # psk: 1111111111111111111111111111111111111111111111111111111111111111 - # start_time: now - # end_time: infinite - # - key_name: ABC99 - # psk: AA111111111111111111111111111111111111111111111111111111111111aa - # start_time: now - # end_time: infinite - # start_time: 2024-12-12 12:12:12 # YYYY-MM-DD HH:MM:SS - # end_time: 2024-12-31 23:59:59 + mac_sec_key: + - key_name: abc12 + psk: 'AA111111111111111111111111111111111111111111111111111111111111aa' + start_time: '2029-12-11 11:12:13' + - key_name: ABC + psk: AAabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdaa + start_time: '2024-12-11 11:12:11' + # end_time: infinite 2024-12-12 12:12:12 # YYYY-MM-DD HH:MM:SS state: present register: nm_add_mac_sec_policy_2 @@ -114,6 +111,11 @@ sak_expiry_time: 100 confidentiality_offset: 30 key_server_priority: 10 + mac_sec_key: + - key_name: abc12 + psk: 'AAabcdabcdabcdabcdabcdabcdabcdab' + - key_name: ABC + psk: 'AAabcdabcdabcdabcdabcdabcdabcdab' state: present check_mode: true register: cm_update_mac_sec_policy @@ -142,7 +144,7 @@ # - cm_update_mac_sec_policy.previous.macsecParams.keyServerPrio == 0 # -> showing 16 - cm_update_mac_sec_policy.current.description == cm_update_mac_sec_policy.proposed.description == 'Updated description' - cm_update_mac_sec_policy.current.adminState == cm_update_mac_sec_policy.proposed.adminState == 'disabled' - - cm_update_mac_sec_policy.current.macsecParams.cipherSuite == cm_update_mac_sec_policy.proposed.macsecParams.cipherSuite == '128GcmAes' + - cm_update_mac_sec_policy.current.macsecParams.cipherSuite == cm_update_mac_sec_policy.proposed.macsecParams.cipherSuite == '256GcmAes' - cm_update_mac_sec_policy.current.macsecParams.windowSize == cm_update_mac_sec_policy.proposed.macsecParams.windowSize == 110 - cm_update_mac_sec_policy.current.macsecParams.securityPol == cm_update_mac_sec_policy.proposed.macsecParams.securityPol == 'mustSecure' - cm_update_mac_sec_policy.current.macsecParams.sakExpiryTime == cm_update_mac_sec_policy.proposed.macsecParams.sakExpiryTime == 100 @@ -159,7 +161,7 @@ # - nm_update_mac_sec_policy.previous.macsecParams.keyServerPrio == 0 # -> showing 16 - nm_update_mac_sec_policy.current.description =='Updated description' - nm_update_mac_sec_policy.current.adminState == 'disabled' - - nm_update_mac_sec_policy.current.macsecParams.cipherSuite == '128GcmAes' + - nm_update_mac_sec_policy.current.macsecParams.cipherSuite == '256GcmAes' - nm_update_mac_sec_policy.current.macsecParams.windowSize == 110 - nm_update_mac_sec_policy.current.macsecParams.securityPol == 'mustSecure' - nm_update_mac_sec_policy.current.macsecParams.sakExpiryTime == 100 @@ -213,21 +215,21 @@ - query_all is not changed - query_all.current | length >= 2 - - name: Query a syncE MACsec policy with mac_sec_policy uuid - cisco.mso.ndo_mac_sec_policy: - <<: *mso_info - template: ansible_fabric_policy_template - mac_sec_policy_uuid: '{{ nm_update_mac_sec_policy_again.current.uuid }}' - state: query - register: query_uuid - - - name: Assert that the MACsec policy was queried with mac_sec_policy uuid - assert: - that: - - query_uuid is not changed - - query_uuid.current.name == 'ansible_mac_sec_policy_changed' - - query_uuid.current.type == 'fabric' - - query_uuid.current.description == '' + # - name: Query a syncE MACsec policy with mac_sec_policy uuid + # cisco.mso.ndo_mac_sec_policy: + # <<: *mso_info + # template: ansible_fabric_policy_template + # mac_sec_policy_uuid: '{{ nm_update_mac_sec_policy_again.current.uuid }}' + # state: query + # register: query_uuid + + # - name: Assert that the MACsec policy was queried with mac_sec_policy uuid + # assert: + # that: + # - query_uuid is not changed + # - query_uuid.current.name == 'ansible_mac_sec_policy_changed' + # - query_uuid.current.type == 'fabric' + # - query_uuid.current.description == '' # DELETE - name: Delete a MACsec policy of type 'fabric' (check mode)