diff --git a/src/sonic-yang-mgmt/sonic_yang_ext.py b/src/sonic-yang-mgmt/sonic_yang_ext.py index 6fd4f4ef4e..c1624e6958 100644 --- a/src/sonic-yang-mgmt/sonic_yang_ext.py +++ b/src/sonic-yang-mgmt/sonic_yang_ext.py @@ -378,10 +378,17 @@ class SonicYangExtMixin: #choices, this is tricky, since leafs are under cases in tree. choices = model.get('choice') if choices: - for choice in choices: - cases = choice['case'] + # If single choice exists in container/list + if isinstance(choices, dict): + cases = choices['case'] for case in cases: self._fillLeafDict(case.get('leaf'), leafDict) + # If multiple choices exist in container/list + else: + for choice in choices: + cases = choice['case'] + for case in cases: + self._fillLeafDict(case.get('leaf'), leafDict) # leaf-lists self._fillLeafDict(model.get('leaf-list'), leafDict, True) @@ -535,6 +542,29 @@ class SonicYangExtMixin: continue return + """ + Process container inside a List. + This function will call xlateContainer based on Container(s) present + in outer List. + """ + def _xlateContainerInList(self, model, yang, configC, table): + ccontainer = model + ccName = ccontainer.get('@name') + if ccName not in configC: + # Inner container doesn't exist in config + return + + if bool(configC[ccName]): + # Empty container - return + return + + self.sysLog(msg="xlateProcessListOfContainer: {}".format(ccName)) + self.elementPath.append(ccName) + self._xlateContainer(ccontainer, yang, configC[ccName], table) + self.elementPath.pop() + + return + """ Xlate a list This function will xlate from a dict in config DB to a Yang JSON list @@ -553,6 +583,9 @@ class SonicYangExtMixin: self._xlateType1MapList(model, yang, config, table, exceptionList) return + # For handling of container(s) in list + ccontainer = model.get('container') + #create a dict to map each key under primary key with a dict yang model. #This is done to improve performance of mapping from values of TABLEs in #config DB to leaf in YANG LIST. @@ -572,6 +605,19 @@ class SonicYangExtMixin: keyDict = self._extractKey(pkey, listKeys) # fill rest of the values in keyDict for vKey in config[pkey]: + if ccontainer and vKey == ccontainer.get('@name'): + self.sysLog(syslog.LOG_DEBUG, "xlateList Handle container {} in list {}".\ + format(vKey, table)) + yangContainer = dict() + if isinstance(ccontainer, dict) and bool(config): + self._xlateContainerInList(ccontainer, yangContainer, config[pkey], table) + # If multi-list exists in container, + elif ccontainer and isinstance(ccontainer, list) and bool(config): + for modelContainer in ccontainer: + self._xlateContainerInList(modelContainer, yangContainer, config[pkey], table) + if len(yangContainer): + keyDict[vKey] = yangContainer + continue self.elementPath.append(vKey) self.sysLog(syslog.LOG_DEBUG, "xlateList vkey {}".format(vKey)) try: @@ -617,7 +663,7 @@ class SonicYangExtMixin: """ def _xlateContainerInContainer(self, model, yang, configC, table): ccontainer = model - ccName = ccontainer['@name'] + ccName = ccontainer.get('@name') yang[ccName] = dict() if ccName not in configC: # Inner container doesn't exist in config @@ -876,6 +922,9 @@ class SonicYangExtMixin: self._revXlateType1MapList(model, yang, config, table) return + # For handling of container(s) in list + ccontainer = model.get('container') + # get keys from YANG model list itself listKeys = model['key']['@value'] # create a dict to map each key under primary key with a dict yang model. @@ -894,6 +943,17 @@ class SonicYangExtMixin: # fill rest of the entries for key in entry: if key not in pkeydict: + if ccontainer and key == ccontainer['@name']: + self.sysLog(syslog.LOG_DEBUG, "revXlateList handle container {} in list {}".format(pkey, table)) + # IF container has only one inner container + if isinstance(ccontainer, dict): + self._revXlateContainerInContainer(ccontainer, entry, config[pkey], table) + # IF container has many inner container + elif isinstance(ccontainer, list): + for modelContainer in ccontainer: + self._revXlateContainerInContainer(modelContainer, entry, config[pkey], table) + continue + self.elementPath.append(key) config[pkey][key] = self._revFindYangTypedValue(key, \ entry[key], leafDict) diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json b/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json index 8a4eaed176..154ef21b49 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json @@ -256,5 +256,39 @@ } ] } + }, + + "test-yang-structure:test-yang-container": { + "test-yang-structure:YANG_STRUCT_TEST": { + "YANG_LIST_TEST_LIST": [{ + "name" : "Vlan1001", + "leaf-list-test": [ + "fc02:2000::1", + "fc02:2000::2" + ], + "container-in-list-test": { + "leaf-1": true, + "leaf-2": "test1", + "mc-case-leaf-1": 55, + "mc-case-leaf-3": 1234 + }, + "case-leaf-1": 101 + }, + { + "name" : "Test123", + "leaf-list-test": [ + "3003:2000::1", + "2002:2001::2" + ], + "container-in-list-test": { + "leaf-1": false, + "leaf-2": "test2", + "mc-case-leaf-2": 77, + "mc-case-leaf-3": 4321 + }, + "case-leaf-2": 1001 + } + ] + } } } diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang b/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang new file mode 100755 index 0000000000..1f57ae337a --- /dev/null +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang @@ -0,0 +1,105 @@ +module test-yang-structure { + + namespace "http://github.com/sonic-net/test"; + prefix yangstructtest; + + yang-version 1.1; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import test-head { + prefix head; + revision-date 2019-07-01; + } + + revision 2021-10-30 { + description "First Revision"; + } + + container test-yang-container { + + container YANG_STRUCT_TEST { + + description "sample test container"; + + list YANG_LIST_TEST_LIST { + + key "name"; + + leaf name { + type string; + } + + leaf-list leaf-list-test { + description "Test leaf-list statement"; + type inet:ipv6-address; + } + + container container-in-list-test { + leaf leaf-1 { + description "test leaf in container"; + type string { + pattern "false|true"; + } + } + + leaf leaf-2 { + description "test leaf in container"; + type string; + } + + choice multi-choice-in-container-test-1 { + case mc-case-test-1 { + leaf mc-case-leaf-1 { + description "test leaf in multi choice"; + type uint32; + } + } + + case mc-case-test-2 { + leaf mc-case-leaf-2 { + description "test leaf in multi choice"; + type uint8; + } + } + } + + choice multi-choice-in-container-test-2 { + case mc-case-test-3 { + leaf mc-case-leaf-3 { + description "test leaf in multi choice"; + type uint16; + } + } + } + } + + choice single-choice-in-list-test { + case case-test-1 { + leaf case-leaf-1 { + description "test leaf in single choice"; + type uint32; + } + } + + case case-test-2 { + leaf case-leaf-2 { + description "test leaf in single choice"; + type uint16; + } + } + } + } + /* end of YANG_LIST_TEST_LIST */ + } + /* end of container YANG_STRUCT_TEST */ + } + /* end of container test-yang-container */ +} +/* end of module test-yang-structure */ diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json index b62322d50b..2376c357b7 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json @@ -168,6 +168,10 @@ { "file" : "test-vlan.yang", "module" : "test-vlan" + }, + { + "file" : "test-yang-structure.yang", + "module" : "test-yang-structure" } ], "new_nodes" : [ @@ -244,6 +248,10 @@ { "module_name" : "test-vlan", "module_prefix" : "vlan" + }, + { + "module_name" : "test-yang-structure", + "module_prefix" : "yangstructtest" } ], "schema_dependencies" : [