mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
package variables
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-logr/logr"
|
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
|
)
|
|
|
|
const (
|
|
variableRegex = `\{\{([^{}]*)\}\}`
|
|
)
|
|
|
|
//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
|
|
func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
|
|
pattern, err := subVars(log, ctx, pattern, "")
|
|
if err != nil {
|
|
return pattern, err
|
|
}
|
|
return pattern, nil
|
|
}
|
|
|
|
func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string) (interface{}, error) {
|
|
switch typedPattern := pattern.(type) {
|
|
case map[string]interface{}:
|
|
mapCopy := make(map[string]interface{})
|
|
for k, v := range typedPattern {
|
|
mapCopy[k] = v
|
|
}
|
|
|
|
return subMap(log, ctx, mapCopy, path)
|
|
case []interface{}:
|
|
sliceCopy := make([]interface{}, len(typedPattern))
|
|
copy(sliceCopy, typedPattern)
|
|
|
|
return subArray(log, ctx, sliceCopy, path)
|
|
case string:
|
|
return subValR(ctx, typedPattern, path)
|
|
default:
|
|
return pattern, nil
|
|
}
|
|
}
|
|
|
|
func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string) (map[string]interface{}, error) {
|
|
for key, patternElement := range patternMap {
|
|
curPath := path + "/" + key
|
|
value, err := subVars(log, ctx, patternElement, curPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
patternMap[key] = value
|
|
|
|
}
|
|
return patternMap, nil
|
|
}
|
|
|
|
func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string) ([]interface{}, error) {
|
|
for idx, patternElement := range patternList {
|
|
curPath := path + "/" + strconv.Itoa(idx)
|
|
value, err := subVars(log, ctx, patternElement, curPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
patternList[idx] = value
|
|
}
|
|
return patternList, nil
|
|
}
|
|
|
|
// subValR resolves the variables if defined
|
|
func subValR(ctx context.EvalInterface, valuePattern string, path string) (interface{}, error) {
|
|
originalPattern := valuePattern
|
|
|
|
regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`)
|
|
for {
|
|
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 {
|
|
return nil, fmt.Errorf("failed to resolve %v at path %s", underlyingVariable, path)
|
|
}
|
|
if val, ok := substitutedVar.(string); ok {
|
|
valuePattern = strings.Replace(valuePattern, variable, val, -1)
|
|
} else {
|
|
if substitutedVar != nil {
|
|
if originalPattern == variable {
|
|
return substitutedVar, nil
|
|
}
|
|
return nil, fmt.Errorf("failed to resolve %v at path %s", underlyingVariable, path)
|
|
}
|
|
return nil, fmt.Errorf("could not find variable %v at path %v", underlyingVariable, path)
|
|
}
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
return valuePattern, nil
|
|
}
|