Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVL Changes #5: YParser enhancement #23

Merged
merged 10 commits into from
Sep 30, 2020
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 @@ -764,7 +764,7 @@ func TestValidateEditConfig_Create_Syntax_CableLength(t *testing.T) {
map[string]string{
"Ethernet8": "5m",
"Ethernet12": "5m",
"Ethernet16": "5m",
"PortChannel16": "5m",
},
},
}
Expand Down
Loading