From d83ae1e3dce79200a89dda3926878b35b0f3f314 Mon Sep 17 00:00:00 2001 From: jingwenxie Date: Wed, 6 Apr 2022 17:46:41 -0700 Subject: [PATCH] [yang] Fix yang validation failure when table contains empty value (#10431) Why I did it Fix #9746 How I did it Split the check condition based on non-exist and zero length. How to verify it Run verification script when table contains empty value --- src/sonic-yang-mgmt/sonic_yang_ext.py | 23 +++++++++++-------- .../libyang-python-tests/test_sonic_yang.py | 15 ++++++++++++ .../tests/files/sample_config_db.json | 8 ++++++- .../tests/yang_model_tests/tests/tacacs.json | 4 ++-- .../yang-models/sonic-device_metadata.yang | 2 +- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/sonic-yang-mgmt/sonic_yang_ext.py b/src/sonic-yang-mgmt/sonic_yang_ext.py index aa36ee0a1951..d43e52970302 100644 --- a/src/sonic-yang-mgmt/sonic_yang_ext.py +++ b/src/sonic-yang-mgmt/sonic_yang_ext.py @@ -591,18 +591,23 @@ def _xlateListInContainer(self, model, yang, configC, table, exceptionList): """ def _xlateContainerInContainer(self, model, yang, configC, table): ccontainer = model - #print(ccontainer['@name']) - yang[ccontainer['@name']] = dict() - if not configC.get(ccontainer['@name']): + ccName = ccontainer['@name'] + yang[ccName] = dict() + if ccName not in configC: + # Inner container doesn't exist in config return - self.sysLog(msg="xlateProcessListOfContainer: {}".format(ccontainer['@name'])) - self._xlateContainer(ccontainer, yang[ccontainer['@name']], \ - configC[ccontainer['@name']], table) + if len(configC[ccName]) == 0: + # Empty container, clean config and return + del configC[ccName] + return + self.sysLog(msg="xlateProcessListOfContainer: {}".format(ccName)) + self._xlateContainer(ccontainer, yang[ccName], \ + configC[ccName], table) # clean empty container - if len(yang[ccontainer['@name']]) == 0: - del yang[ccontainer['@name']] + if len(yang[ccName]) == 0: + del yang[ccName] # remove copy after processing - del configC[ccontainer['@name']] + del configC[ccName] return diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py index 3eb396594e80..a13d4c02e9a0 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py @@ -364,5 +364,20 @@ def test_table_with_no_yang(self, sonic_yang_data): return + def test_special_json_with_yang(self, sonic_yang_data): + # in this test, we validate unusual json config and check if + # loadData works successfully + test_file = sonic_yang_data['test_file'] + syc = sonic_yang_data['syc'] + + # read config + jIn = self.readIjsonInput(test_file, 'SAMPLE_CONFIG_DB_SPECIAL_CASE') + jIn = json.loads(jIn) + + # load config and create Data tree + syc.loadData(jIn) + + return + def teardown_class(self): pass diff --git a/src/sonic-yang-models/tests/files/sample_config_db.json b/src/sonic-yang-models/tests/files/sample_config_db.json index ff99fc7335df..6618ed8232b7 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -304,7 +304,7 @@ "switch_id": "2", "switch_type": "voq", "max_cores": "8", - "sub_role": "FrondEnd", + "sub_role": "FrontEnd", "dhcp_server": "disabled" } }, @@ -1694,5 +1694,11 @@ "UNKNOWN_TABLE": { "Error": "This Table is for testing, This Table does not have YANG models." } + }, + "SAMPLE_CONFIG_DB_SPECIAL_CASE": { + "TACPLUS": { + "global": { + } + } } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/tacacs.json b/src/sonic-yang-models/tests/yang_model_tests/tests/tacacs.json index 5236aab596fe..6888a4e3f326 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/tacacs.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/tacacs.json @@ -4,7 +4,7 @@ }, "TACPLUS_INVALID_TIMEOUT_TEST": { "desc": "Tacplus global configuration with invalid timeout value in TACPLUS table.", - "eStr": "TACACS timeout must be 1..60" + "eStr": "TACACS timeout must be 1..60" }, "TACPLUS_NOT_PRESENT_SRC_INTF_TEST": { "desc": "Tacplus global configuration with a non existent port in TACPLUS table.", @@ -15,7 +15,7 @@ }, "TACPLUS_SERVER_INVALID_PRIORITY_TEST": { "desc": "Tacplus server configuration with invalid priority value in TACPLUS_SERVER table.", - "eStr": "TACACS server priority must be 1..64" + "eStr": "TACACS server priority must be 1..64" }, "TACPLUS_SERVER_INVALID_TIMEOUT_TEST" : { "desc": "Tacplus server configuration with invalid timeout value in TACPLUS_SERVER table.", diff --git a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang index 618ed19cd81f..a349a3eb9366 100644 --- a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang +++ b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang @@ -129,7 +129,7 @@ module sonic-device_metadata { leaf sub_role { type string; - description "sub_role indicates if ASIC is FrondEnd or BackEnd."; + description "sub_role indicates if ASIC is FrontEnd or BackEnd."; } leaf downstream_subrole {