From 19a2a49f23438bbc7ee1f0a15c1846106fad44ea Mon Sep 17 00:00:00 2001 From: Enrique Estrada Date: Thu, 26 Feb 2026 18:38:37 -0600 Subject: [PATCH] issue NewValidation: CSCwq28721 Fixes #316 fixed --- aci-preupgrade-validation-script.py | 36 ++++++ docs/docs/validations.md | 13 +++ .../datetimePol-neg.json | 86 ++++++++++++++ .../datetimePol-pos.json | 86 ++++++++++++++ .../fabricRsTimePol.json | 56 +++++++++ .../test_ntp_server_bd_svi_check.py | 106 ++++++++++++++++++ 6 files changed, 383 insertions(+) create mode 100644 tests/checks/ntp_server_bd_svi_check/datetimePol-neg.json create mode 100644 tests/checks/ntp_server_bd_svi_check/datetimePol-pos.json create mode 100644 tests/checks/ntp_server_bd_svi_check/fabricRsTimePol.json create mode 100644 tests/checks/ntp_server_bd_svi_check/test_ntp_server_bd_svi_check.py diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 4b83f4c..d93f80e 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6025,6 +6025,41 @@ def apic_downgrade_compat_warning_check(cversion, tversion, **kwargs): return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) +@check_wrapper(check_title="NTP Server BD SVI Check") +def ntp_server_bd_svi_check(cversion, tversion, **kargs): + result = FAIL_UF + headers = ["Fabric Time Pol", "NTP Pol Name"] + data = [] + recommended_action = 'Use the in-band or out-of-band management IP address of the leaf switch as the NTP server IP address.' + doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#ntp-server-bd-svi" + + if not tversion: + return Result(result=MANUAL, msg=TVER_MISSING) + + if cversion.older_than("6.1(1f)") or cversion.newer_than("6.1(5e)"): + return Result(result=NA, msg='Version not affected') + + if tversion.older_than("6.1(1f)") or tversion.newer_than("6.1(5e)"): + return Result(result=NA, msg='Version not affected') + + fabric_time_pols = icurl('class', 'fabricRsTimePol.json') + datetime_pols = icurl('class', 'datetimePol.json') + + fabric_time_pol_regex = r'uni/fabric/funcprof/podpgrp-(?P[^/]+)/rsTimePol' + for datetime_pol in datetime_pols: + for fabric_time_pol in fabric_time_pols: + if ( + datetime_pol['datetimePol']['attributes']['dn'] == fabric_time_pol['fabricRsTimePol']['attributes']['tDn'] + ) and( + datetime_pol['datetimePol']['attributes']['serverState'] == 'enabled' + ): + fp = re.search(fabric_time_pol_regex, fabric_time_pol['fabricRsTimePol']['attributes']['dn']) + data.append([fp.group("podgroup"), datetime_pol['datetimePol']['attributes']['name']]) + + if not data: + result = PASS + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + # ---- Script Execution ---- @@ -6188,6 +6223,7 @@ class CheckManager: standby_sup_sync_check, isis_database_byte_check, configpush_shard_check, + ntp_server_bd_svi_check, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 68ca1c0..21c88d9 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -193,6 +193,8 @@ Items | Defect | This Script [Stale pconsRA Object][d26] | CSCwp22212 | :warning:{title="Deprecated"} | :no_entry_sign: [ISIS DTEPs Byte Size][d27] | CSCwp15375 | :white_check_mark: | :no_entry_sign: [Policydist configpushShardCont Crash][d28] | CSCwp95515 | :white_check_mark: | +[NTP Server BD SVI][d25] | CSCwp92030 | :white_check_mark: | :no_entry_sign: + [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -222,6 +224,7 @@ Items | Defect | This Script [d26]: #stale-pconsra-object [d27]: #isis-dteps-byte-size [d28]: #policydist-configpushshardcont-crash +[d29]: #ntp-server-bd-svi ## General Check Details @@ -2648,6 +2651,15 @@ Due to [CSCwp95515][59], upgrading to an affected version while having any `conf If any instances of `configpushShardCont` are flagged by this script, Cisco TAC must be contacted to identify and resolve the underlying issue before performing the upgrade. +#### NTP Server BD SVI + +In ACI, Leaf Switches can be configured as NTP servers, allowing Endpoints in ACI to act as NTP clients and sync their datetime with the Fabric. The Leaf switch uses it's BD SVI IP address to send NTP traffic. + +Due to [CSCwp92030][62], after a policy upgrade NTP can stop working between Endpoint clients and NTP Server (ACI Leaf), Client reach the NTP server by it's BD SVI IP address, but the server replies on a Loopback address. + +If you see the check alerting about Datetime Policies, apply the workaround to prevent NTP issues post-upgrade. + + [0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script [1]: https://www.cisco.com/c/dam/en/us/td/docs/Website/datacenter/apicmatrix/index.html [2]: https://www.cisco.com/c/en/us/support/switches/nexus-9000-series-switches/products-release-notes-list.html @@ -2710,3 +2722,4 @@ If any instances of `configpushShardCont` are flagged by this script, Cisco TAC [59]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp95515 [60]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#Inter [61]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#EnablePolicyCompression +[62]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp92030 \ No newline at end of file diff --git a/tests/checks/ntp_server_bd_svi_check/datetimePol-neg.json b/tests/checks/ntp_server_bd_svi_check/datetimePol-neg.json new file mode 100644 index 0000000..ace8a85 --- /dev/null +++ b/tests/checks/ntp_server_bd_svi_check/datetimePol-neg.json @@ -0,0 +1,86 @@ +[ + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "disabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "", + "dn": "uni/fabric/time-default", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2026-02-03T15:12:35.361-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "default", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-default", + "serverState": "disabled", + "status": "", + "uid": "0", + "userdom": "" + } + } + }, + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "enabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "NTP for fabric in Vercruz", + "dn": "uni/fabric/time-fabric_ntp", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2026-02-03T15:12:35.361-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "fabric_ntp", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-fabric_ntp", + "serverState": "disabled", + "status": "", + "uid": "23653", + "userdom": "" + } + } + }, + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "enabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "", + "dn": "uni/fabric/time-calo-NTP", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2023-01-02T10:36:19.837-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "calo-NTP", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-calo-NTP", + "serverState": "disabled", + "status": "", + "uid": "15374", + "userdom": ":all:" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/ntp_server_bd_svi_check/datetimePol-pos.json b/tests/checks/ntp_server_bd_svi_check/datetimePol-pos.json new file mode 100644 index 0000000..a10f3f5 --- /dev/null +++ b/tests/checks/ntp_server_bd_svi_check/datetimePol-pos.json @@ -0,0 +1,86 @@ +[ + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "disabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "", + "dn": "uni/fabric/time-default", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2026-02-03T15:12:35.361-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "default", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-default", + "serverState": "disabled", + "status": "", + "uid": "0", + "userdom": "" + } + } + }, + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "enabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "NTP for fabric in Vercruz", + "dn": "uni/fabric/time-fabric_ntp", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2026-02-03T15:12:35.361-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "fabric_ntp", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-fabric_ntp", + "serverState": "enabled", + "status": "", + "uid": "23653", + "userdom": "" + } + } + }, + { + "datetimePol": { + "attributes": { + "StratumValue": "8", + "adminSt": "enabled", + "annotation": "", + "authSt": "disabled", + "childAction": "", + "configIssues": "", + "descr": "", + "dn": "uni/fabric/time-calo-NTP", + "extMngdBy": "", + "lcOwn": "local", + "masterMode": "disabled", + "modTs": "2023-01-02T10:36:19.837-06:00", + "monPolDn": "uni/fabric/monfab-default", + "name": "calo-NTP", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "", + "rn": "time-calo-NTP", + "serverState": "disabled", + "status": "", + "uid": "15374", + "userdom": ":all:" + } + } + } + ] \ No newline at end of file diff --git a/tests/checks/ntp_server_bd_svi_check/fabricRsTimePol.json b/tests/checks/ntp_server_bd_svi_check/fabricRsTimePol.json new file mode 100644 index 0000000..131598a --- /dev/null +++ b/tests/checks/ntp_server_bd_svi_check/fabricRsTimePol.json @@ -0,0 +1,56 @@ +[ + { + "fabricRsTimePol": { + "attributes": { + "annotation": "", + "childAction": "", + "dn": "uni/fabric/funcprof/podpgrp-calo-d-polGrp/rsTimePol", + "extMngdBy": "", + "forceResolve": "yes", + "lcOwn": "local", + "modTs": "2023-01-02T10:36:41.882-06:00", + "monPolDn": "uni/fabric/monfab-default", + "rType": "mo", + "rn": "rsTimePol", + "state": "formed", + "stateQual": "none", + "status": "", + "tCl": "datetimePol", + "tContextDn": "", + "tDn": "uni/fabric/time-calo-NTP", + "tRn": "time-calo-NTP", + "tType": "name", + "tnDatetimePolName": "calo-NTP", + "uid": "0", + "userdom": "all" + } + } + }, + { + "fabricRsTimePol": { + "attributes": { + "annotation": "", + "childAction": "", + "dn": "uni/fabric/funcprof/podpgrp-PodPolicy-Fabric/rsTimePol", + "extMngdBy": "", + "forceResolve": "yes", + "lcOwn": "local", + "modTs": "2026-02-03T15:12:35.361-06:00", + "monPolDn": "uni/fabric/monfab-default", + "rType": "mo", + "rn": "rsTimePol", + "state": "formed", + "stateQual": "none", + "status": "", + "tCl": "datetimePol", + "tContextDn": "", + "tDn": "uni/fabric/time-fabric_ntp", + "tRn": "time-fabric_ntp", + "tType": "name", + "tnDatetimePolName": "fabric_ntp", + "uid": "0", + "userdom": "" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/ntp_server_bd_svi_check/test_ntp_server_bd_svi_check.py b/tests/checks/ntp_server_bd_svi_check/test_ntp_server_bd_svi_check.py new file mode 100644 index 0000000..960bccc --- /dev/null +++ b/tests/checks/ntp_server_bd_svi_check/test_ntp_server_bd_svi_check.py @@ -0,0 +1,106 @@ +import os +import pytest +import logging +import importlib +from helpers.utils import read_data + +script = importlib.import_module("aci-preupgrade-validation-script") + +log = logging.getLogger(__name__) +dir = os.path.dirname(os.path.abspath(__file__)) + +test_function = "ntp_server_bd_svi_check" + +# icurl queries +fabric_time_pol = "fabricRsTimePol.json" +datetime_pol = "datetimePol.json" + + +@pytest.mark.parametrize( + "icurl_outputs, cversion, tversion, expected_result", + [ + # MANUAL - Tversion not found. + ( + { + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.1(1f)", + None, + script.MANUAL, + ), + # NA Versions not affected + # NA Cversion not affected OLD. + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.0(1g)", + "6.0(9f)", + script.NA, + ), + # NA Cversion not affected. NEW + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.1(5g)", + "6.0(9f)", + script.NA, + ), + # NA Tversion not affected OLD. + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.1(4g)", + "6.0(9f)", + script.NA, + ), + # NA Tversion not affected. NEW. + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.1(3g)", + "6.1(9f)", + script.NA, + ), + # PASS - Versions affected, negative datetimePol MO. + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-neg.json"), + }, + "6.1(2g)", + "6.1(5d)", + script.PASS, + ), + # FAIL_UF - Versions affected, positive datetimePol MO. + ( + { + + fabric_time_pol: read_data(dir, "fabricRsTimePol.json"), + datetime_pol: read_data(dir, "datetimePol-pos.json"), + }, + "6.1(2g)", + "6.1(5d)", + script.FAIL_UF, + ), + ], +) +def test_logic(run_check, mock_icurl, cversion, tversion, expected_result): + result = run_check( + cversion=script.AciVersion(cversion), + tversion=script.AciVersion(tversion) if tversion else None, + ) + assert result.result == expected_result