Skip to content

Commit

Permalink
CVL database access layer changes (#100)
Browse files Browse the repository at this point in the history
* cvl database access layer changes

* cvl database access layer changes to fix test code

* cvl database access layer changes to fix benchmark test code

* cvl database access layer changes to fix CvlEditConfigData test cases

* cvl database access layer - removed the cvl_db_test.go, will be added it after integerating the changes
  • Loading branch information
mbalachandar authored Sep 12, 2023
1 parent ee3029d commit 14962fe
Show file tree
Hide file tree
Showing 5 changed files with 760 additions and 62 deletions.
57 changes: 57 additions & 0 deletions cvl/common/cvl_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2022 Broadcom. The term Broadcom refers to Broadcom Inc. and/or //
// its subsidiaries. //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and //
// limitations under the License. //
// //
////////////////////////////////////////////////////////////////////////////////

package common

import (
"github.com/antchfx/xmlquery"
)

// CVLEditConfigData Strcture for key and data in API
type CVLEditConfigData struct {
VType CVLValidateType //Validation type
VOp CVLOperation //Operation type
Key string //Key format : "PORT|Ethernet4"
Data map[string]string //Value : {"alias": "40GE0/28", "mtu" : 9100, "admin_status": down}
ReplaceOp bool
}

type CVLValidateType uint

const (
VALIDATE_NONE CVLValidateType = iota //Data is used as dependent data
VALIDATE_SYNTAX //Syntax is checked and data is used as dependent data
VALIDATE_SEMANTICS //Semantics is checked
VALIDATE_ALL //Syntax and Semantics are checked
)

type CVLOperation uint

const (
OP_NONE CVLOperation = 0 //Used to just validate the config without any operation
OP_CREATE = 1 << 0 //For Create operation
OP_UPDATE = 1 << 1 //For Update operation
OP_DELETE = 1 << 2 //For Delete operation
)

// RequestCacheType Struct for request data and YANG data
type RequestCacheType struct {
ReqData CVLEditConfigData
YangData *xmlquery.Node
}
92 changes: 92 additions & 0 deletions cvl/common/db_access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2023 Broadcom. The term Broadcom refers to Broadcom Inc. and/or //
// its subsidiaries. //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and //
// limitations under the License. //
// //
////////////////////////////////////////////////////////////////////////////////

package common

// DBAccess is used by cvl and custom validation functions to access the ConfigDB.
// This allows cvl clients to plugin additional data source, like transaction cache,
// into cvl. Most of the interface methods mimic the go-redis APIs. It also defines
// Lookup and Count methods to perform advanced search by matching hash field values.
type DBAccess interface {
Exists(key string) IntResult
Keys(pattern string) StrSliceResult
HGet(key, field string) StrResult
HMGet(key string, fields ...string) SliceResult
HGetAll(key string) StrMapResult
Pipeline() PipeResult

// Lookup entries using a Search criteria and return them in sonic db json format.
// E.g, {"INTERFACE": {"Ethernet0": {"vrf", "Vrf1"}, "Ethernet0|1.2.3.4": {"NULL": "NULL"}}}
// TODO fix the return value for not found case
Lookup(s Search) JsonResult
// Count entries using a Search criteria. Returns 0 if there are no matches.
Count(s Search) IntResult
}

type IntResult interface {
Result() (int64, error)
}

type StrResult interface {
Result() (string, error)
}

type StrSliceResult interface {
Result() ([]string, error)
}

type SliceResult interface {
Result() ([]interface{}, error)
}

type StrMapResult interface {
Result() (map[string]string, error)
}

type JsonResult interface {
Result() (string, error) //TODO have it as map instead of string
}

type PipeResult interface {
Keys(pattern string) StrSliceResult
HGet(key, field string) StrResult
HMGet(key string, fields ...string) SliceResult
HGetAll(key string) StrMapResult
Exec() error
Close()
}

// Search criteria for advanced lookup. Initial filtering is done by matching the key Pattern.
// Results are further refined by applying Predicate, WithField and Limit constraints (optional)
type Search struct {
// Pattern to match the keys from a redis table. Must contain a table name prefix.
// E.g, `INTERFACE|Ethernet0` `INTERFACE|*` "INTERFACE|*|*"
Pattern string
// Predicate is a lua condition statement to inspect an entry's key and hash attributes.
// It can use map variables 'k' and 'h' to access key & hash attributes.
// E.g, `k['type'] == 'L3' and h['enabled'] == true`
Predicate string
// KeyNames must contain the key component names in order. Required only if Predicate uses 'k'.
// E.g, if ["name","type"], a key "ACL|TEST|L3" will expand to lua map {name="TEST", type="L3"}
KeyNames []string
// WithField selects a entry only if it contains this hash field
WithField string
// Limit the results to maximum these number of entries
Limit int
}
121 changes: 64 additions & 57 deletions cvl/custom_validation/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,98 +21,106 @@ package custom_validation

import (
"reflect"
"github.com/antchfx/xmlquery"
"github.com/go-redis/redis/v7"

"github.com/Azure/sonic-mgmt-common/cvl/common"
"github.com/Azure/sonic-mgmt-common/cvl/internal/util"
"github.com/Azure/sonic-mgmt-common/cvl/internal/yparser"
)
"github.com/antchfx/xmlquery"
"github.com/go-redis/redis/v7"
)

type CustomValidation struct {}
type CustomValidation struct{}

type CVLValidateType uint

const (
VALIDATE_NONE CVLValidateType = iota //Data is used as dependent data
VALIDATE_SYNTAX //Syntax is checked and data is used as dependent data
VALIDATE_SEMANTICS //Semantics is checked
VALIDATE_ALL //Syntax and Semantics are checked
VALIDATE_NONE CVLValidateType = iota //Data is used as dependent data
VALIDATE_SYNTAX //Syntax is checked and data is used as dependent data
VALIDATE_SEMANTICS //Semantics is checked
VALIDATE_ALL //Syntax and Semantics are checked
)

type CVLOperation uint

const (
OP_NONE CVLOperation = 0 //Used to just validate the config without any operation
OP_CREATE = 1 << 0//For Create operation
OP_UPDATE = 1 << 1//For Update operation
OP_DELETE = 1 << 2//For Delete operation
OP_NONE CVLOperation = 0 //Used to just validate the config without any operation
OP_CREATE = 1 << 0 //For Create operation
OP_UPDATE = 1 << 1 //For Update operation
OP_DELETE = 1 << 2 //For Delete operation
)

//CVLRetCode CVL Error codes
// CVLRetCode CVL Error codes
type CVLRetCode int

const (
CVL_SUCCESS CVLRetCode = iota
CVL_ERROR
CVL_NOT_IMPLEMENTED
CVL_INTERNAL_UNKNOWN
CVL_FAILURE
CVL_SYNTAX_ERROR = CVLRetCode(yparser.YP_SYNTAX_ERROR)
CVL_SEMANTIC_ERROR = CVLRetCode(yparser.YP_SEMANTIC_ERROR)
CVL_SYNTAX_MISSING_FIELD = CVLRetCode(yparser.YP_SYNTAX_MISSING_FIELD)
CVL_SYNTAX_INVALID_FIELD = CVLRetCode(yparser.YP_SYNTAX_INVALID_FIELD) /* Invalid Field */
CVL_SYNTAX_INVALID_INPUT_DATA = CVLRetCode(yparser.YP_SYNTAX_INVALID_INPUT_DATA) /*Invalid Input Data */
CVL_SYNTAX_MULTIPLE_INSTANCE = CVLRetCode(yparser.YP_SYNTAX_MULTIPLE_INSTANCE) /* Multiple Field Instances */
CVL_SYNTAX_DUPLICATE = CVLRetCode(yparser.YP_SYNTAX_DUPLICATE) /* Duplicate Fields */
CVL_SYNTAX_ENUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_ENUM_INVALID) /* Invalid enum value */
CVL_SYNTAX_ENUM_INVALID_NAME = CVLRetCode(yparser.YP_SYNTAX_ENUM_INVALID_NAME) /* Invalid enum name */
CVL_SYNTAX_ENUM_WHITESPACE = CVLRetCode(yparser.YP_SYNTAX_ENUM_WHITESPACE) /* Enum name with leading/trailing whitespaces */
CVL_SYNTAX_OUT_OF_RANGE = CVLRetCode(yparser.YP_SYNTAX_OUT_OF_RANGE) /* Value out of range/length/pattern (data) */
CVL_SYNTAX_MINIMUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_MINIMUM_INVALID) /* min-elements constraint not honored */
CVL_SYNTAX_MAXIMUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_MAXIMUM_INVALID) /* max-elements constraint not honored */
CVL_SEMANTIC_DEPENDENT_DATA_MISSING = CVLRetCode(yparser.YP_SEMANTIC_DEPENDENT_DATA_MISSING) /* Dependent Data is missing */
CVL_SYNTAX_ERROR = CVLRetCode(yparser.YP_SYNTAX_ERROR)
CVL_SEMANTIC_ERROR = CVLRetCode(yparser.YP_SEMANTIC_ERROR)
CVL_SYNTAX_MISSING_FIELD = CVLRetCode(yparser.YP_SYNTAX_MISSING_FIELD)
CVL_SYNTAX_INVALID_FIELD = CVLRetCode(yparser.YP_SYNTAX_INVALID_FIELD) /* Invalid Field */
CVL_SYNTAX_INVALID_INPUT_DATA = CVLRetCode(yparser.YP_SYNTAX_INVALID_INPUT_DATA) /*Invalid Input Data */
CVL_SYNTAX_MULTIPLE_INSTANCE = CVLRetCode(yparser.YP_SYNTAX_MULTIPLE_INSTANCE) /* Multiple Field Instances */
CVL_SYNTAX_DUPLICATE = CVLRetCode(yparser.YP_SYNTAX_DUPLICATE) /* Duplicate Fields */
CVL_SYNTAX_ENUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_ENUM_INVALID) /* Invalid enum value */
CVL_SYNTAX_ENUM_INVALID_NAME = CVLRetCode(yparser.YP_SYNTAX_ENUM_INVALID_NAME) /* Invalid enum name */
CVL_SYNTAX_ENUM_WHITESPACE = CVLRetCode(yparser.YP_SYNTAX_ENUM_WHITESPACE) /* Enum name with leading/trailing whitespaces */
CVL_SYNTAX_OUT_OF_RANGE = CVLRetCode(yparser.YP_SYNTAX_OUT_OF_RANGE) /* Value out of range/length/pattern (data) */
CVL_SYNTAX_MINIMUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_MINIMUM_INVALID) /* min-elements constraint not honored */
CVL_SYNTAX_MAXIMUM_INVALID = CVLRetCode(yparser.YP_SYNTAX_MAXIMUM_INVALID) /* max-elements constraint not honored */
CVL_SEMANTIC_DEPENDENT_DATA_MISSING = CVLRetCode(yparser.YP_SEMANTIC_DEPENDENT_DATA_MISSING) /* Dependent Data is missing */
CVL_SEMANTIC_MANDATORY_DATA_MISSING = CVLRetCode(yparser.YP_SEMANTIC_MANDATORY_DATA_MISSING) /* Mandatory Data is missing */
CVL_SEMANTIC_KEY_ALREADY_EXIST = CVLRetCode(yparser.YP_SEMANTIC_KEY_ALREADY_EXIST) /* Key already existing. */
CVL_SEMANTIC_KEY_NOT_EXIST = CVLRetCode(yparser.YP_SEMANTIC_KEY_NOT_EXIST) /* Key is missing. */
CVL_SEMANTIC_KEY_DUPLICATE = CVLRetCode(yparser.YP_SEMANTIC_KEY_DUPLICATE) /* Duplicate key. */
CVL_SEMANTIC_KEY_INVALID = CVLRetCode(yparser.YP_SEMANTIC_KEY_INVALID)
CVL_SEMANTIC_KEY_ALREADY_EXIST = CVLRetCode(yparser.YP_SEMANTIC_KEY_ALREADY_EXIST) /* Key already existing. */
CVL_SEMANTIC_KEY_NOT_EXIST = CVLRetCode(yparser.YP_SEMANTIC_KEY_NOT_EXIST) /* Key is missing. */
CVL_SEMANTIC_KEY_DUPLICATE = CVLRetCode(yparser.YP_SEMANTIC_KEY_DUPLICATE) /* Duplicate key. */
CVL_SEMANTIC_KEY_INVALID = CVLRetCode(yparser.YP_SEMANTIC_KEY_INVALID)
)

//CVLEditConfigData Strcture for key and data in API
// CVLEditConfigData Strcture for key and data in API
type CVLEditConfigData struct {
VType CVLValidateType //Validation type
VOp CVLOperation //Operation type
Key string //Key format : "PORT|Ethernet4"
Data map[string]string //Value : {"alias": "40GE0/28", "mtu" : 9100, "admin_status": down}
VType CVLValidateType //Validation type
VOp CVLOperation //Operation type
Key string //Key format : "PORT|Ethernet4"
Data map[string]string //Value : {"alias": "40GE0/28", "mtu" : 9100, "admin_status": down}
}

//CVLErrorInfo CVL Error Structure
// CVLErrorInfo CVL Error Structure
type CVLErrorInfo struct {
TableName string /* Table having error */
ErrCode CVLRetCode /* CVL Error return Code. */
CVLErrDetails string /* CVL Error Message details. */
Keys []string /* Keys of the Table having error. */
Value string /* Field Value throwing error */
Field string /* Field Name throwing error . */
Msg string /* Detailed error message. */
ConstraintErrMsg string /* Constraint error message. */
ErrAppTag string
TableName string /* Table having error */
ErrCode CVLRetCode /* CVL Error return Code. */
CVLErrDetails string /* CVL Error Message details. */
Keys []string /* Keys of the Table having error. */
Value string /* Field Value throwing error */
Field string /* Field Name throwing error . */
Msg string /* Detailed error message. */
ConstraintErrMsg string /* Constraint error message. */
ErrAppTag string
}

type CustValidationCache struct {
Data interface{}
}

//CustValidationCtxt Custom validation context passed to custom validation function
// CustValidationCtxt Custom validation context passed to custom validation function
type CustValidationCtxt struct {
ReqData []CVLEditConfigData //All request data
CurCfg *CVLEditConfigData //Current request data for which validation should be done
YNodeName string //YANG node name
YNodeVal string //YANG node value, leaf-list will have "," separated value
YCur *xmlquery.Node //YANG data tree
ReqData []CVLEditConfigData //All request data
CurCfg *CVLEditConfigData //Current request data for which validation should be done
YNodeName string //YANG node name
YNodeVal string //YANG node value, leaf-list will have "," separated value
YCur *xmlquery.Node //YANG data tree
SessCache *CustValidationCache //Session cache, can be used for storing data, persistent in session
RClient *redis.Client //Redis client
RClient *redis.Client //Redis client
}

//InvokeCustomValidation Common function to invoke custom validation
//TBD should we do this using GO plugin feature ?
func InvokeCustomValidation(cv *CustomValidation, name string, args... interface{}) CVLErrorInfo {
// Search criteria for advanced lookup through DBAccess APIs
type Search = common.Search

// InvokeCustomValidation Common function to invoke custom validation
// TBD should we do this using GO plugin feature ?
func InvokeCustomValidation(cv *CustomValidation, name string, args ...interface{}) CVLErrorInfo {
inputs := make([]reflect.Value, len(args))
for i := range args {
inputs[i] = reflect.ValueOf(args[i])
Expand All @@ -129,4 +137,3 @@ func InvokeCustomValidation(cv *CustomValidation, name string, args... interface

return CVLErrorInfo{ErrCode: CVL_SUCCESS}
}

Loading

0 comments on commit 14962fe

Please sign in to comment.