1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/engine/variables/vars.go

113 lines
3.1 KiB
Go
Raw Normal View History

package variables
import (
"fmt"
"regexp"
"strconv"
"strings"
2020-03-17 11:05:20 -07:00
"github.com/go-logr/logr"
"github.com/nirmata/kyverno/pkg/engine/context"
)
2020-02-26 16:41:48 -08:00
const (
2020-05-05 23:52:52 +05:30
variableRegex = `\{\{([^{}]*)\}\}`
2020-02-26 16:41:48 -08:00
)
2020-02-14 11:59:28 -08:00
//SubstituteVars replaces the variables with the values defined in the context
// - if any variable is invaid or has nil value, it is considered as a failed varable substitution
2020-03-17 11:05:20 -07:00
func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
errs := []error{}
2020-03-17 11:05:20 -07:00
pattern = subVars(log, ctx, pattern, "", &errs)
if len(errs) == 0 {
// no error while parsing the pattern
2020-02-14 11:59:28 -08:00
return pattern, nil
}
2020-02-26 16:41:48 -08:00
return pattern, fmt.Errorf("%v", errs)
}
2020-03-17 11:05:20 -07:00
func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
switch typedPattern := pattern.(type) {
case map[string]interface{}:
2020-04-09 22:00:24 +05:30
mapCopy := make(map[string]interface{})
for k, v := range typedPattern {
mapCopy[k] = v
}
return subMap(log, ctx, mapCopy, path, errs)
case []interface{}:
2020-04-09 22:00:24 +05:30
sliceCopy := make([]interface{}, len(typedPattern))
copy(sliceCopy, typedPattern)
return subArray(log, ctx, sliceCopy, path, errs)
case string:
2020-05-05 23:52:52 +05:30
return subValR(ctx, typedPattern, path, errs)
default:
return pattern
}
}
2020-03-17 11:05:20 -07:00
func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
for key, patternElement := range patternMap {
curPath := path + "/" + key
2020-03-17 11:05:20 -07:00
value := subVars(log, ctx, patternElement, curPath, errs)
patternMap[key] = value
}
return patternMap
}
2020-03-17 11:05:20 -07:00
func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
for idx, patternElement := range patternList {
curPath := path + "/" + strconv.Itoa(idx)
2020-03-17 11:05:20 -07:00
value := subVars(log, ctx, patternElement, curPath, errs)
patternList[idx] = value
}
return patternList
}
2020-02-26 16:41:48 -08:00
// subValR resolves the variables if defined
2020-05-05 23:52:52 +05:30
func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
originalPattern := valuePattern
var failedVars []interface{}
2020-02-26 16:41:48 -08:00
2020-05-05 23:52:52 +05:30
defer func() {
if len(failedVars) > 0 {
*errs = append(*errs, fmt.Errorf("failed to resolve %v at path %s", failedVars, path))
}
}()
2020-02-26 16:41:48 -08:00
2020-05-05 23:52:52 +05:30
regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`)
2020-02-26 16:41:48 -08:00
for {
2020-05-05 23:52:52 +05:30
if vars := regex.FindAllString(valuePattern, -1); len(vars) > 0 {
for _, variable := range vars {
underlyingVariable := strings.ReplaceAll(strings.ReplaceAll(variable, "}}", ""), "{{", "")
substitutedVar, err := ctx.Query(underlyingVariable)
if err != nil {
failedVars = append(failedVars, underlyingVariable)
return nil
}
if val, ok := substitutedVar.(string); ok {
if val == "" {
failedVars = append(failedVars, underlyingVariable)
return nil
}
valuePattern = strings.Replace(valuePattern, variable, val, -1)
} else {
if substitutedVar != nil {
if originalPattern == variable {
return substitutedVar
}
}
failedVars = append(failedVars, underlyingVariable)
return nil
}
2020-02-26 16:41:48 -08:00
}
2020-05-05 23:52:52 +05:30
} else {
break
2020-02-26 16:41:48 -08:00
}
}
2020-02-26 16:41:48 -08:00
return valuePattern
}