Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions src/sonic-yang-mgmt/sonic_yang_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,17 @@ def _createLeafDict(self, model, table):
#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']
Copy link
Copy Markdown
Collaborator

@qiluo-msft qiluo-msft Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case

Is it possible that 'case' is not in choices dict? will it throw? #Closed

Copy link
Copy Markdown
Contributor Author

@VladimirKuk VladimirKuk Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding that this should be validated by libyang. Since the choice is already checked, at least one case must be present otherwise yang file won't be valid.

for case in cases:
self._fillLeafDict(case.get('leaf'), leafDict)
Copy link
Copy Markdown
Collaborator

@qiluo-msft qiluo-msft Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2 lines are duplicated, you may consider reusing. #Closed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, but throughout the code every time, there are separation between single element (dict) and multiple (list), they are handled separately.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no easy way to reuse.

# 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)
Expand Down Expand Up @@ -535,6 +542,29 @@ def _xlateType1MapList(self, model, yang, config, table, exceptionList):
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['@name']
if ccName not in configC:
# Inner container doesn't exist in config
return

if len(configC[ccName]) == 0:
# 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
Expand All @@ -553,6 +583,9 @@ def _xlateList(self, model, yang, config, table, exceptionList):
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.
Expand All @@ -572,6 +605,19 @@ 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]:
if ccontainer and vKey == ccontainer['@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:
Expand Down Expand Up @@ -876,6 +922,9 @@ def _revXlateList(self, model, yang, config, table):
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.
Expand All @@ -894,6 +943,17 @@ def _revXlateList(self, model, yang, config, table):
# 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)
Expand Down
34 changes: 34 additions & 0 deletions src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -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 */
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@
{
"file" : "test-vlan.yang",
"module" : "test-vlan"
},
{
"file" : "test-yang-structure.yang",
"module" : "test-yang-structure"
}
],
"new_nodes" : [
Expand Down Expand Up @@ -244,6 +248,10 @@
{
"module_name" : "test-vlan",
"module_prefix" : "vlan"
},
{
"module_name" : "test-yang-structure",
"module_prefix" : "yangstructtest"
}
],
"schema_dependencies" : [
Expand Down