diff --git a/src/sonic-yang-mgmt/sonic_yang.py b/src/sonic-yang-mgmt/sonic_yang.py index 16aeb8a9ff8a..ad38692b75ee 100644 --- a/src/sonic-yang-mgmt/sonic_yang.py +++ b/src/sonic-yang-mgmt/sonic_yang.py @@ -45,6 +45,10 @@ def __init__(self, yang_dir, debug=False, print_log_enabled=True): # all yang modules, such as grouping. self.preProcessedYang = dict() + self.elementPath = [] + + self.leaf_list_with_string_value_set = set() + try: self.ctx = ly.Context(yang_dir) except Exception as e: diff --git a/src/sonic-yang-mgmt/sonic_yang_ext.py b/src/sonic-yang-mgmt/sonic_yang_ext.py index aa36ee0a1951..31dac74adc4f 100644 --- a/src/sonic-yang-mgmt/sonic_yang_ext.py +++ b/src/sonic-yang-mgmt/sonic_yang_ext.py @@ -407,6 +407,9 @@ def _yangConvert(val): # if it is a leaf-list do it for each element if leafDict[key]['__isleafList']: vValue = list() + if isinstance(value, str): + self.leaf_list_with_string_value_set.add(tuple(self.elementPath)) + value = (x.strip() for x in value.split(',')) for v in value: vValue.append(_yangConvert(v)) else: @@ -545,6 +548,7 @@ def _xlateList(self, model, yang, config, table, exceptionList): primaryKeys = list(config.keys()) for pkey in primaryKeys: try: + self.elementPath.append(pkey) vKey = None self.sysLog(syslog.LOG_DEBUG, "xlateList Extract pkey:{}".\ format(pkey)) @@ -552,9 +556,13 @@ def _xlateList(self, model, yang, config, table, exceptionList): keyDict = self._extractKey(pkey, listKeys) # fill rest of the values in keyDict for vKey in config[pkey]: + self.elementPath.append(vKey) self.sysLog(syslog.LOG_DEBUG, "xlateList vkey {}".format(vKey)) - keyDict[vKey] = self._findYangTypedValue(vKey, \ - config[pkey][vKey], leafDict) + try: + keyDict[vKey] = self._findYangTypedValue(vKey, \ + config[pkey][vKey], leafDict) + finally: + self.elementPath.pop() yang.append(keyDict) # delete pkey from config, done to match one key with one list del config[pkey] @@ -566,6 +574,8 @@ def _xlateList(self, model, yang, config, table, exceptionList): exceptionList.append(str(e)) # with multilist, we continue matching other keys. continue + finally: + self.elementPath.pop() return @@ -596,8 +606,10 @@ def _xlateContainerInContainer(self, model, yang, configC, table): if not configC.get(ccontainer['@name']): return self.sysLog(msg="xlateProcessListOfContainer: {}".format(ccontainer['@name'])) + self.elementPath.append(ccontainer['@name']) self._xlateContainer(ccontainer, yang[ccontainer['@name']], \ configC[ccontainer['@name']], table) + self.elementPath.pop() # clean empty container if len(yang[ccontainer['@name']]) == 0: del yang[ccontainer['@name']] @@ -645,8 +657,10 @@ def _xlateContainer(self, model, yang, config, table): for vKey in vKeys: #vkey must be a leaf\leaf-list\choice in container if leafDict.get(vKey): + self.elementPath.append(vKey) self.sysLog(syslog.LOG_DEBUG, "xlateContainer vkey {}".format(vKey)) yang[vKey] = self._findYangTypedValue(vKey, configC[vKey], leafDict) + self.elementPath.pop() # delete entry from copy of config del configC[vKey] @@ -676,8 +690,10 @@ def _xlateConfigDBtoYang(self, jIn, yangJ): yangJ[key] = dict() if yangJ.get(key) is None else yangJ[key] yangJ[key][subkey] = dict() self.sysLog(msg="xlateConfigDBtoYang {}:{}".format(key, subkey)) + self.elementPath.append(table) self._xlateContainer(cmap['container'], yangJ[key][subkey], \ jIn[table], table) + self.elementPath = [] return @@ -734,9 +750,12 @@ def _revYangConvert(val): # if it is a leaf-list do it for each element if leafDict[key]['__isleafList']: - vValue = list() - for v in value: - vValue.append(_revYangConvert(v)) + if tuple(self.elementPath) in self.leaf_list_with_string_value_set: + vValue = ','.join((_revYangConvert(x) for x in value)) + else: + vValue = list() + for v in value: + vValue.append(_revYangConvert(v)) elif leafDict[key]['type']['@name'] == 'boolean': vValue = 'true' if value else 'false' else: @@ -845,12 +864,16 @@ def _revXlateList(self, model, yang, config, table): # create key of config DB table pkey, pkeydict = self._createKey(entry, listKeys) self.sysLog(syslog.LOG_DEBUG, "revXlateList pkey:{}".format(pkey)) + self.elementPath.append(pkey) config[pkey]= dict() # fill rest of the entries for key in entry: if key not in pkeydict: + self.elementPath.append(key) config[pkey][key] = self._revFindYangTypedValue(key, \ entry[key], leafDict) + self.elementPath.pop() + self.elementPath.pop() return @@ -874,8 +897,10 @@ def _revXlateContainerInContainer(self, model, yang, config, table): if yang.get(modelContainer['@name']): config[modelContainer['@name']] = dict() self.sysLog(msg="revXlateContainerInContainer {}".format(modelContainer['@name'])) + self.elementPath.append(modelContainer['@name']) self._revXlateContainer(modelContainer, yang[modelContainer['@name']], \ config[modelContainer['@name']], table) + self.elementPath.pop() return """ @@ -907,7 +932,9 @@ def _revXlateContainer(self, model, yang, config, table): #vkey must be a leaf\leaf-list\choice in container if leafDict.get(vKey): self.sysLog(syslog.LOG_DEBUG, "revXlateContainer vkey {}".format(vKey)) + self.elementPath.append(vKey) config[vKey] = self._revFindYangTypedValue(vKey, yang[vKey], leafDict) + self.elementPath.pop() return @@ -935,8 +962,10 @@ def _revXlateYangtoConfigDB(self, yangJ, cDbJson): cDbJson[table] = dict() #print(key + "--" + subkey) self.sysLog(msg="revXlateYangtoConfigDB {}".format(table)) + self.elementPath.append(table) self._revXlateContainer(cmap['container'], yangJ[module_top][container], \ cDbJson[table], table) + self.elementPath = [] return 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 920181646c46..620158c61f02 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -432,7 +432,10 @@ "description": "", "speed": "11100", "tpid": "0x8100", - "admin_status": "up" + "admin_status": "up", + "autoneg": "on", + "adv_speeds": "100000,50000", + "adv_interface_types": "CR,CR4" }, "Ethernet2": { "alias": "Eth1/3", @@ -440,7 +443,10 @@ "description": "", "speed": "11100", "tpid": "0x8100", - "admin_status": "up" + "admin_status": "up", + "autoneg": "on", + "adv_speeds": "all", + "adv_interface_types": "all" }, "Ethernet3": { "alias": "Eth1/4",