2019-06-13 17:20:00 +03:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
2019-06-25 18:16:02 -07:00
|
|
|
"fmt"
|
2019-06-13 17:20:00 +03:00
|
|
|
"strconv"
|
2019-09-05 12:44:38 -07:00
|
|
|
|
|
|
|
"github.com/golang/glog"
|
2019-06-13 17:20:00 +03:00
|
|
|
)
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//ValidationHandler for element processes
|
2019-09-25 15:12:33 -07:00
|
|
|
type ValidationHandler interface {
|
2019-09-25 21:01:45 -07:00
|
|
|
Handle(resourceMap map[string]interface{}, originPattenr interface{}) (string, error)
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//CreateElementHandler factory to process elements
|
2019-09-25 15:12:33 -07:00
|
|
|
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
switch {
|
|
|
|
case isConditionAnchor(element):
|
|
|
|
return NewConditionAnchorHandler(element, pattern, path)
|
|
|
|
case isExistanceAnchor(element):
|
|
|
|
return NewExistanceHandler(element, pattern, path)
|
2019-10-01 12:35:14 -07:00
|
|
|
case isEqualityAnchor(element):
|
|
|
|
return NewEqualityHandler(element, pattern, path)
|
2019-10-10 16:59:08 -07:00
|
|
|
case isNegationAnchor(element):
|
|
|
|
return NewNegationHandler(element, pattern, path)
|
2019-09-25 15:12:33 -07:00
|
|
|
default:
|
|
|
|
return NewDefaultHandler(element, pattern, path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 16:59:08 -07:00
|
|
|
func NewNegationHandler(anchor string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
return NegationHandler{
|
|
|
|
anchor: anchor,
|
|
|
|
pattern: pattern,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//NegationHandler provides handler for check if the tag in anchor is not defined
|
|
|
|
type NegationHandler struct {
|
|
|
|
anchor string
|
|
|
|
pattern interface{}
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
|
|
|
//Handle process negation handler
|
|
|
|
func (nh NegationHandler) Handle(resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
|
|
|
anchorKey := removeAnchor(nh.anchor)
|
|
|
|
currentPath := nh.path + anchorKey + "/"
|
|
|
|
// if anchor is present in the resource then fail
|
|
|
|
if _, ok := resourceMap[anchorKey]; ok {
|
|
|
|
// no need to process elements in value as key cannot be present in resource
|
2019-10-10 17:34:20 -07:00
|
|
|
return currentPath, fmt.Errorf("Validation rule failed at %s, field %s is disallowed", currentPath, anchorKey)
|
2019-10-10 16:59:08 -07:00
|
|
|
}
|
|
|
|
// key is not defined in the resource
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2019-10-01 12:35:14 -07:00
|
|
|
func NewEqualityHandler(anchor string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
return EqualityHandler{
|
|
|
|
anchor: anchor,
|
|
|
|
pattern: pattern,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//EqualityHandler provides handler for non anchor element
|
|
|
|
type EqualityHandler struct {
|
|
|
|
anchor string
|
|
|
|
pattern interface{}
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
|
|
|
//Handle processed condition anchor
|
|
|
|
func (eh EqualityHandler) Handle(resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
|
|
|
anchorKey := removeAnchor(eh.anchor)
|
|
|
|
currentPath := eh.path + anchorKey + "/"
|
|
|
|
// check if anchor is present in resource
|
|
|
|
if value, ok := resourceMap[anchorKey]; ok {
|
|
|
|
// validate the values of the pattern
|
|
|
|
returnPath, err := validateResourceElement(value, eh.pattern, originPattern, currentPath)
|
|
|
|
if err != nil {
|
|
|
|
return returnPath, err
|
|
|
|
}
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//NewDefaultHandler returns handler for non anchor elements
|
2019-09-25 15:12:33 -07:00
|
|
|
func NewDefaultHandler(element string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
return DefaultHandler{
|
|
|
|
element: element,
|
|
|
|
pattern: pattern,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//DefaultHandler provides handler for non anchor element
|
2019-09-25 15:12:33 -07:00
|
|
|
type DefaultHandler struct {
|
|
|
|
element string
|
|
|
|
pattern interface{}
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//Handle process non anchor element
|
2019-09-25 21:01:45 -07:00
|
|
|
func (dh DefaultHandler) Handle(resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
2019-09-25 15:12:33 -07:00
|
|
|
currentPath := dh.path + dh.element + "/"
|
|
|
|
if dh.pattern == "*" && resourceMap[dh.element] != nil {
|
2019-09-25 21:01:45 -07:00
|
|
|
return "", nil
|
2019-09-25 15:12:33 -07:00
|
|
|
} else if dh.pattern == "*" && resourceMap[dh.element] == nil {
|
2019-09-25 21:01:45 -07:00
|
|
|
return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element)
|
2019-09-25 15:12:33 -07:00
|
|
|
} else {
|
|
|
|
path, err := validateResourceElement(resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
|
|
|
if err != nil {
|
2019-09-25 21:01:45 -07:00
|
|
|
return path, err
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
}
|
2019-09-25 21:01:45 -07:00
|
|
|
return "", nil
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//NewConditionAnchorHandler returns an instance of condition acnhor handler
|
2019-09-25 15:12:33 -07:00
|
|
|
func NewConditionAnchorHandler(anchor string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
return ConditionAnchorHandler{
|
|
|
|
anchor: anchor,
|
|
|
|
pattern: pattern,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//ConditionAnchorHandler provides handler for condition anchor
|
2019-09-25 15:12:33 -07:00
|
|
|
type ConditionAnchorHandler struct {
|
|
|
|
anchor string
|
|
|
|
pattern interface{}
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//Handle processed condition anchor
|
2019-09-25 21:01:45 -07:00
|
|
|
func (ch ConditionAnchorHandler) Handle(resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
|
|
|
anchorKey := removeAnchor(ch.anchor)
|
|
|
|
currentPath := ch.path + anchorKey + "/"
|
|
|
|
// check if anchor is present in resource
|
|
|
|
if value, ok := resourceMap[anchorKey]; ok {
|
|
|
|
// validate the values of the pattern
|
|
|
|
returnPath, err := validateResourceElement(value, ch.pattern, originPattern, currentPath)
|
|
|
|
if err != nil {
|
|
|
|
return returnPath, err
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
2019-09-25 21:01:45 -07:00
|
|
|
return "", nil
|
2019-09-25 15:12:33 -07:00
|
|
|
|
|
|
|
}
|
2019-09-25 21:01:45 -07:00
|
|
|
return "", nil
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//NewExistanceHandler returns existence handler
|
2019-09-25 15:12:33 -07:00
|
|
|
func NewExistanceHandler(anchor string, pattern interface{}, path string) ValidationHandler {
|
|
|
|
return ExistanceHandler{
|
|
|
|
anchor: anchor,
|
|
|
|
pattern: pattern,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//ExistanceHandler provides handlers to process exitence anchor handler
|
2019-09-25 15:12:33 -07:00
|
|
|
type ExistanceHandler struct {
|
|
|
|
anchor string
|
|
|
|
pattern interface{}
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
//Handle processes the existence anchor handler
|
2019-09-25 21:01:45 -07:00
|
|
|
func (eh ExistanceHandler) Handle(resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
2019-09-25 15:12:33 -07:00
|
|
|
// skip is used by existance anchor to not process further if condition is not satisfied
|
2019-09-25 21:01:45 -07:00
|
|
|
anchorKey := removeAnchor(eh.anchor)
|
|
|
|
currentPath := eh.path + anchorKey + "/"
|
|
|
|
// check if anchor is present in resource
|
|
|
|
if value, ok := resourceMap[anchorKey]; ok {
|
|
|
|
// Existance anchor can only exist on resource value type of list
|
|
|
|
switch typedResource := value.(type) {
|
|
|
|
case []interface{}:
|
|
|
|
typedPattern, ok := eh.pattern.([]interface{})
|
|
|
|
if !ok {
|
2019-10-10 16:59:08 -07:00
|
|
|
return currentPath, fmt.Errorf("Invalid pattern type %T: Pattern has to be of list to compare against resource", eh.pattern)
|
2019-09-25 21:01:45 -07:00
|
|
|
}
|
|
|
|
// get the first item in the pattern array
|
|
|
|
patternMap := typedPattern[0]
|
|
|
|
typedPatternMap, ok := patternMap.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
return currentPath, fmt.Errorf("Invalid pattern type %T: Pattern has to be of type map to compare against items in resource", eh.pattern)
|
2019-09-25 16:06:37 -07:00
|
|
|
}
|
2019-09-25 21:01:45 -07:00
|
|
|
return validateExistenceListResource(typedResource, typedPatternMap, originPattern, currentPath)
|
|
|
|
default:
|
|
|
|
glog.Error("Invalid type: Existance ^ () anchor can be used only on list/array type resource")
|
|
|
|
return currentPath, fmt.Errorf("Invalid resource type %T: Existance ^ () anchor can be used only on list/array type resource", value)
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
}
|
2019-09-25 21:01:45 -07:00
|
|
|
return "", nil
|
2019-09-25 15:12:33 -07:00
|
|
|
}
|
|
|
|
|
2019-09-25 21:01:45 -07:00
|
|
|
func validateExistenceListResource(resourceList []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
|
|
|
// the idea is atleast on the elements in the array should satisfy the pattern
|
|
|
|
// if non satisfy then throw an error
|
|
|
|
for i, resourceElement := range resourceList {
|
|
|
|
currentPath := path + strconv.Itoa(i) + "/"
|
|
|
|
_, err := validateResourceElement(resourceElement, patternMap, originPattern, currentPath)
|
|
|
|
if err == nil {
|
|
|
|
// condition is satisfied, dont check further
|
|
|
|
glog.V(4).Infof("Existence check satisfied at path %s, for pattern %v", currentPath, patternMap)
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// none of the existance checks worked, so thats a failure sceanario
|
|
|
|
return path, fmt.Errorf("Existence anchor validation failed at path %s", path)
|
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
func getAnchorsResourcesFromMap(patternMap map[string]interface{}) (map[string]interface{}, map[string]interface{}) {
|
|
|
|
anchors := map[string]interface{}{}
|
|
|
|
resources := map[string]interface{}{}
|
|
|
|
for key, value := range patternMap {
|
2019-10-10 16:59:08 -07:00
|
|
|
if isConditionAnchor(key) || isExistanceAnchor(key) || isEqualityAnchor(key) || isNegationAnchor(key) {
|
2019-09-28 14:20:39 -07:00
|
|
|
anchors[key] = value
|
2019-06-13 17:20:00 +03:00
|
|
|
continue
|
|
|
|
}
|
2019-09-28 14:20:39 -07:00
|
|
|
resources[key] = value
|
2019-06-13 17:20:00 +03:00
|
|
|
}
|
|
|
|
|
2019-09-28 14:20:39 -07:00
|
|
|
return anchors, resources
|
2019-06-13 17:20:00 +03:00
|
|
|
}
|