Fixes "Missing container in list support in YANG Model https://github.com/sonic-net/sonic-buildimage/issues/16704" Why I did it Adds support for container in list How I did it Identify container in list's leaf and add its data. Fixes "Update dhcpv6 option yang model" #16290 Why I did it Adds support for single "choice" statement in container/list How I did it Check if choice data is dictionary (instead of list). How to verify it Reconstruction details in bug's description. Tested branch (Please provide the tested image version) 202311 Description for the changelog Adds support for container in list to yang parsing Link to config_db schema for YANG module changes https://github.com/sonic-net/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md#dhcp_relay Signed-off-by: vkuk [vkuk@marvell.com]
This commit is contained in:
parent
b3845b620d
commit
0688aa38ae
@ -378,6 +378,13 @@ class SonicYangExtMixin:
|
|||||||
#choices, this is tricky, since leafs are under cases in tree.
|
#choices, this is tricky, since leafs are under cases in tree.
|
||||||
choices = model.get('choice')
|
choices = model.get('choice')
|
||||||
if choices:
|
if choices:
|
||||||
|
# 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:
|
for choice in choices:
|
||||||
cases = choice['case']
|
cases = choice['case']
|
||||||
for case in cases:
|
for case in cases:
|
||||||
@ -535,6 +542,29 @@ class SonicYangExtMixin:
|
|||||||
continue
|
continue
|
||||||
return
|
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
|
Xlate a list
|
||||||
This function will xlate from a dict in config DB to a Yang JSON 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)
|
self._xlateType1MapList(model, yang, config, table, exceptionList)
|
||||||
return
|
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.
|
#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
|
#This is done to improve performance of mapping from values of TABLEs in
|
||||||
#config DB to leaf in YANG LIST.
|
#config DB to leaf in YANG LIST.
|
||||||
@ -572,6 +605,19 @@ class SonicYangExtMixin:
|
|||||||
keyDict = self._extractKey(pkey, listKeys)
|
keyDict = self._extractKey(pkey, listKeys)
|
||||||
# fill rest of the values in keyDict
|
# fill rest of the values in keyDict
|
||||||
for vKey in config[pkey]:
|
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.elementPath.append(vKey)
|
||||||
self.sysLog(syslog.LOG_DEBUG, "xlateList vkey {}".format(vKey))
|
self.sysLog(syslog.LOG_DEBUG, "xlateList vkey {}".format(vKey))
|
||||||
try:
|
try:
|
||||||
@ -617,7 +663,7 @@ class SonicYangExtMixin:
|
|||||||
"""
|
"""
|
||||||
def _xlateContainerInContainer(self, model, yang, configC, table):
|
def _xlateContainerInContainer(self, model, yang, configC, table):
|
||||||
ccontainer = model
|
ccontainer = model
|
||||||
ccName = ccontainer['@name']
|
ccName = ccontainer.get('@name')
|
||||||
yang[ccName] = dict()
|
yang[ccName] = dict()
|
||||||
if ccName not in configC:
|
if ccName not in configC:
|
||||||
# Inner container doesn't exist in config
|
# Inner container doesn't exist in config
|
||||||
@ -876,6 +922,9 @@ class SonicYangExtMixin:
|
|||||||
self._revXlateType1MapList(model, yang, config, table)
|
self._revXlateType1MapList(model, yang, config, table)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# For handling of container(s) in list
|
||||||
|
ccontainer = model.get('container')
|
||||||
|
|
||||||
# get keys from YANG model list itself
|
# get keys from YANG model list itself
|
||||||
listKeys = model['key']['@value']
|
listKeys = model['key']['@value']
|
||||||
# create a dict to map each key under primary key with a dict yang model.
|
# 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
|
# fill rest of the entries
|
||||||
for key in entry:
|
for key in entry:
|
||||||
if key not in pkeydict:
|
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)
|
self.elementPath.append(key)
|
||||||
config[pkey][key] = self._revFindYangTypedValue(key, \
|
config[pkey][key] = self._revFindYangTypedValue(key, \
|
||||||
entry[key], leafDict)
|
entry[key], leafDict)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
@ -168,6 +168,10 @@
|
|||||||
{
|
{
|
||||||
"file" : "test-vlan.yang",
|
"file" : "test-vlan.yang",
|
||||||
"module" : "test-vlan"
|
"module" : "test-vlan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file" : "test-yang-structure.yang",
|
||||||
|
"module" : "test-yang-structure"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new_nodes" : [
|
"new_nodes" : [
|
||||||
@ -244,6 +248,10 @@
|
|||||||
{
|
{
|
||||||
"module_name" : "test-vlan",
|
"module_name" : "test-vlan",
|
||||||
"module_prefix" : "vlan"
|
"module_prefix" : "vlan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"module_name" : "test-yang-structure",
|
||||||
|
"module_prefix" : "yangstructtest"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schema_dependencies" : [
|
"schema_dependencies" : [
|
||||||
|
Loading…
Reference in New Issue
Block a user