Skip to content

Commit

Permalink
CVL Changes sonic-net#5: YParser enhancement (sonic-net#23)
Browse files Browse the repository at this point in the history
Adding following YParser enhancement :

Add multiple nodes to the tree from array instead of using "#" delimiter
Read YIN file schema
Read leafref, must, when expression details
API IsLeafrefMatchedInUnion() to check if data instance type in union is of leafref type.
  • Loading branch information
dutta-partha committed Sep 30, 2020
1 parent 904ce18 commit 80f369e
Show file tree
Hide file tree
Showing 4 changed files with 522 additions and 60 deletions.
6 changes: 3 additions & 3 deletions cvl/cvl.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ type CVL struct {
yp *yparser.YParser
tmpDbCache map[string]interface{} //map of table storing map of key-value pair
requestCache map[string]map[string][]*requestCacheType//Cache of validated data,
//per table, per key. Can be used as dependent data in next request
batchLeaf string
//per table, per key. Can be used as dependent data in next request
batchLeaf []*yparser.YParserLeafValue //field name and value
chkLeafRefWithOthCache bool
yv *YValidator //Custom YANG validator for validating external dependencies
}
Expand Down Expand Up @@ -1159,7 +1159,7 @@ func (c *CVL) validate (data *yparser.YParserNode) CVLRetCode {
return CVL_SUCCESS
}

func CreateCVLErrObj(errObj yparser.YParserError) CVLErrorInfo {
func createCVLErrObj(errObj yparser.YParserError) CVLErrorInfo {

cvlErrObj := CVLErrorInfo {
TableName : errObj.TableName,
Expand Down
66 changes: 41 additions & 25 deletions cvl/cvl_syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

package cvl
import (
"fmt"
"github.com/antchfx/jsonquery"
"github.com/Azure/sonic-mgmt-common/cvl/internal/yparser"
//lint:ignore ST1001 This is safe to dot import for util package
Expand All @@ -33,15 +32,16 @@ func(c *CVL) addChildNode(tableName string, parent *yparser.YParserNode, name st
return c.yp.AddChildNode(modelInfo.tableInfo[tableName].module, parent, name)
}

func (c *CVL) addChildLeaf(config bool, tableName string, parent *yparser.YParserNode, name string, value string) {
func (c *CVL) addChildLeaf(config bool, tableName string, parent *yparser.YParserNode, name string, value string, multileaf *[]*yparser.YParserLeafValue) {

/* If there is no value then assign default space string. */
if len(value) == 0 {
value = " "
}

//Batch leaf creation
c.batchLeaf = c.batchLeaf + name + "#" + value + "#"
*multileaf = append(*multileaf, &yparser.YParserLeafValue{Name: name, Value: value})

//Check if this leaf has leafref,
//If so add the add redis key to its table so that those
// details can be fetched for dependency validation
Expand All @@ -50,7 +50,8 @@ func (c *CVL) addChildLeaf(config bool, tableName string, parent *yparser.YParse
}

func (c *CVL) generateTableFieldsData(config bool, tableName string, jsonNode *jsonquery.Node,
parent *yparser.YParserNode) CVLRetCode {
parent *yparser.YParserNode, multileaf *[]*yparser.YParserLeafValue) CVLErrorInfo {
var cvlErrObj CVLErrorInfo

//Traverse fields
for jsonFieldNode := jsonNode.FirstChild; jsonFieldNode!= nil;
Expand All @@ -61,32 +62,35 @@ parent *yparser.YParserNode) CVLRetCode {
jsonFieldNode.FirstChild.Type == jsonquery.TextNode) {

if (len(modelInfo.tableInfo[tableName].mapLeaf) == 2) {//mapping should have two leaf always
batchInnerListLeaf := make([]*yparser.YParserLeafValue, 0)
//Values should be stored inside another list as map table
listNode := c.addChildNode(tableName, parent, tableName) //Add the list to the top node
c.addChildLeaf(config, tableName,
listNode, modelInfo.tableInfo[tableName].mapLeaf[0],
jsonFieldNode.Data)
jsonFieldNode.Data, &batchInnerListLeaf)

c.addChildLeaf(config, tableName,
listNode, modelInfo.tableInfo[tableName].mapLeaf[1],
jsonFieldNode.FirstChild.Data)
jsonFieldNode.FirstChild.Data, &batchInnerListLeaf)

if errObj := c.yp.AddMultiLeafNodes(modelInfo.tableInfo[tableName].module, listNode, batchInnerListLeaf); errObj.ErrCode != yparser.YP_SUCCESS {
cvlErrObj = createCVLErrObj(errObj)
CVL_LOG(ERROR, "Failed to create innner list leaf nodes, data = %v", batchInnerListLeaf)
return cvlErrObj
}
} else {
//check if it is hash-ref, then need to add only key from "TABLE|k1"
hashRefMatch := reHashRef.FindStringSubmatch(jsonFieldNode.FirstChild.Data)

if (hashRefMatch != nil && len(hashRefMatch) == 3) {
/*if (strings.HasPrefix(jsonFieldNode.FirstChild.Data, "[")) &&
(strings.HasSuffix(jsonFieldNode.FirstChild.Data, "]")) &&
(strings.Index(jsonFieldNode.FirstChild.Data, "|") > 0) {*/
if len(hashRefMatch) == 3 {

c.addChildLeaf(config, tableName,
parent, jsonFieldNode.Data,
hashRefMatch[2]) //take hashref key value
hashRefMatch[2], multileaf) //take hashref key value
} else {
c.addChildLeaf(config, tableName,
parent, jsonFieldNode.Data,
jsonFieldNode.FirstChild.Data)
jsonFieldNode.FirstChild.Data, multileaf)
}
}

Expand All @@ -99,28 +103,34 @@ parent *yparser.YParserNode) CVLRetCode {
arrayNode = arrayNode.NextSibling {
c.addChildLeaf(config, tableName,
parent, jsonFieldNode.Data,
arrayNode.FirstChild.Data)
arrayNode.FirstChild.Data, multileaf)
}
}
}

return CVL_SUCCESS
cvlErrObj.ErrCode = CVL_SUCCESS
return cvlErrObj
}

func (c *CVL) generateTableData(config bool, jsonNode *jsonquery.Node)(*yparser.YParserNode, CVLErrorInfo) {
var cvlErrObj CVLErrorInfo

tableName := fmt.Sprintf("%s",jsonNode.Data)
c.batchLeaf = ""
tableName := jsonNode.Data
c.batchLeaf = nil
c.batchLeaf = make([]*yparser.YParserLeafValue, 0)

//Every Redis table is mapped as list within a container,
//E.g. ACL_RULE is mapped as
// container ACL_RULE { list ACL_RULE_LIST {} }
var topNode *yparser.YParserNode

// Add top most conatiner e.g. 'container sonic-acl {...}'
if _, exists := modelInfo.tableInfo[tableName]; exists == false {
return nil, cvlErrObj
if _, exists := modelInfo.tableInfo[tableName]; !exists {
CVL_LOG(ERROR, "Schema details not found for %s", tableName)
cvlErrObj.ErrCode = CVL_SYNTAX_ERROR
cvlErrObj.TableName = tableName
cvlErrObj.Msg ="Schema details not found"
return nil, cvlErrObj
}
topNode = c.yp.AddChildNode(modelInfo.tableInfo[tableName].module,
nil, modelInfo.tableInfo[tableName].modelName)
Expand All @@ -147,7 +157,7 @@ func (c *CVL) generateTableData(config bool, jsonNode *jsonquery.Node)(*yparser.
//Find number of all key combinations
//Each key can have one or more key values, which results in nk1 * nk2 * nk2 combinations
idx := 0
for i,_ := range keyValuePair {
for i := range keyValuePair {
totalKeyComb = totalKeyComb * len(keyValuePair[i].values)
keyIndices = append(keyIndices, 0)
}
Expand All @@ -165,11 +175,13 @@ func (c *CVL) generateTableData(config bool, jsonNode *jsonquery.Node)(*yparser.
for idx = 0; idx < keyCompCount; idx++ {
c.addChildLeaf(config, tableName,
listNode, keyValuePair[idx].key,
keyValuePair[idx].values[keyIndices[idx]])
keyValuePair[idx].values[keyIndices[idx]], &c.batchLeaf)
}

//Get all fields under the key field and add them as children of the list
c.generateTableFieldsData(config, tableName, jsonNode, listNode)
if fldDataErrObj := c.generateTableFieldsData(config, tableName, jsonNode, listNode, &c.batchLeaf); fldDataErrObj.ErrCode != CVL_SUCCESS {
return nil, fldDataErrObj
}

//Check which key elements left after current key element
var next int = keyCompCount - 1
Expand All @@ -188,13 +200,17 @@ func (c *CVL) generateTableData(config bool, jsonNode *jsonquery.Node)(*yparser.
keyIndices[idx] = 0
}

TRACE_LOG(INFO_API, TRACE_CACHE, "Starting batch leaf creation - %s\n", c.batchLeaf)
TRACE_LOG(INFO_API, TRACE_CACHE, "Starting batch leaf creation - %v\n", c.batchLeaf)
//process batch leaf creation
if errObj := c.yp.AddMultiLeafNodes(modelInfo.tableInfo[tableName].module, listNode, c.batchLeaf); errObj.ErrCode != yparser.YP_SUCCESS {
cvlErrObj = CreateCVLErrObj(errObj)
return nil, cvlErrObj
cvlErrObj = createCVLErrObj(errObj)
CVL_LOG(ERROR, "Failed to create leaf nodes, data = %v",
c.batchLeaf)
return nil, cvlErrObj
}
c.batchLeaf = ""

c.batchLeaf = nil
c.batchLeaf = make([]*yparser.YParserLeafValue, 0)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cvl/cvl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ func TestValidateEditConfig_Create_Syntax_CableLength(t *testing.T) {
map[string]string{
"Ethernet8": "5m",
"Ethernet12": "5m",
"Ethernet16": "5m",
"PortChannel16": "5m",
},
},
}
Expand Down
Loading

0 comments on commit 80f369e

Please sign in to comment.