mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
744 fixed error messages
This commit is contained in:
parent
ab8664d6ca
commit
717e8e7245
3 changed files with 50 additions and 104 deletions
|
@ -31,16 +31,25 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
if reflect.DeepEqual(resp, response.EngineResponse{}) {
|
||||
return
|
||||
}
|
||||
startResultResponse(&resp, policy, newR)
|
||||
endResultResponse(logger, &resp, startTime)
|
||||
var resource unstructured.Unstructured
|
||||
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
|
||||
// for delete requests patched resource will be oldR since newR is empty
|
||||
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
|
||||
resp.PatchedResource = oldR
|
||||
resource = oldR
|
||||
} else {
|
||||
resp.PatchedResource = newR
|
||||
resource = newR
|
||||
}
|
||||
}
|
||||
for i := range resp.PolicyResponse.Rules {
|
||||
messageInterface, err := variables.SubstituteVars(logger, ctx, resp.PolicyResponse.Rules[i].Message)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resp.PolicyResponse.Rules[i].Message, _ = messageInterface.(string)
|
||||
}
|
||||
resp.PatchedResource = resource
|
||||
startResultResponse(&resp, policy, resource)
|
||||
endResultResponse(logger, &resp, startTime)
|
||||
}()
|
||||
|
||||
// If request is delete, newR will be empty
|
||||
|
|
|
@ -11,8 +11,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
variableRegex = `\{\{([^{}]*)\}\}`
|
||||
singleVarRegex = `^\{\{([^{}]*)\}\}$`
|
||||
variableRegex = `\{\{([^{}]*)\}\}`
|
||||
)
|
||||
|
||||
//SubstituteVars replaces the variables with the values defined in the context
|
||||
|
@ -42,7 +41,7 @@ func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, pa
|
|||
|
||||
return subArray(log, ctx, sliceCopy, path, errs)
|
||||
case string:
|
||||
return subValR(log, ctx, typedPattern, path, errs)
|
||||
return subValR(ctx, typedPattern, path, errs)
|
||||
default:
|
||||
return pattern
|
||||
}
|
||||
|
@ -68,108 +67,46 @@ func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interfac
|
|||
}
|
||||
|
||||
// subValR resolves the variables if defined
|
||||
func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
|
||||
func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
|
||||
originalPattern := valuePattern
|
||||
var failedVars []interface{}
|
||||
|
||||
// variable values can be scalar values(string,int, float) or they can be obects(map,slice)
|
||||
// - {{variable}}
|
||||
// there is a single variable resolution so the value can be scalar or object
|
||||
// - {{variable1--{{variable2}}}}}
|
||||
// variable2 is evaluted first as an individual variable and can be have scalar or object values
|
||||
// but resolving the outer variable, {{variable--<value>}}
|
||||
// if <value> is scalar then it can replaced, but for object types its tricky
|
||||
// as object cannot be directy replaced, if the object is stringyfied then it loses it structure.
|
||||
// since this might be a potential place for error, required better error reporting and handling
|
||||
defer func() {
|
||||
if len(failedVars) > 0 {
|
||||
*errs = append(*errs, fmt.Errorf("failed to resolve %v at path %s", failedVars, path))
|
||||
}
|
||||
}()
|
||||
|
||||
// object values are only suported for single variable substitution
|
||||
if ok, retVal := processIfSingleVariable(log, ctx, valuePattern, path, errs); ok {
|
||||
return retVal
|
||||
}
|
||||
// var emptyInterface interface{}
|
||||
var failedVars []string
|
||||
// process type string
|
||||
regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`)
|
||||
for {
|
||||
valueStr := valuePattern
|
||||
if len(failedVars) != 0 {
|
||||
log.Info("failed to resolve variablesl short-circuiting")
|
||||
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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
// get variables at this level
|
||||
validRegex := regexp.MustCompile(variableRegex)
|
||||
groups := validRegex.FindAllStringSubmatch(valueStr, -1)
|
||||
if len(groups) == 0 {
|
||||
// there was no match
|
||||
// not variable defined
|
||||
break
|
||||
}
|
||||
subs := map[string]interface{}{}
|
||||
for _, group := range groups {
|
||||
if _, ok := subs[group[0]]; ok {
|
||||
// value has already been substituted
|
||||
continue
|
||||
}
|
||||
// here we do the querying of the variables from the context
|
||||
variable, err := ctx.Query(group[1])
|
||||
if err != nil {
|
||||
// error while evaluating
|
||||
failedVars = append(failedVars, group[1])
|
||||
continue
|
||||
}
|
||||
// path not found in context and value stored in null/nill
|
||||
if variable == nil {
|
||||
failedVars = append(failedVars, group[1])
|
||||
continue
|
||||
}
|
||||
// get values for each and replace
|
||||
subs[group[0]] = variable
|
||||
}
|
||||
// perform substitutions
|
||||
newVal := valueStr
|
||||
for k, v := range subs {
|
||||
// if value is of type string then cast else consider it as direct replacement
|
||||
if val, ok := v.(string); ok {
|
||||
newVal = strings.Replace(newVal, k, val, -1)
|
||||
continue
|
||||
}
|
||||
// if type is not scalar then consider this as a failed variable
|
||||
log.Info("variable resolves to non-scalar value. Non-Scalar values are not supported for nested variables", "variable", k, "value", v)
|
||||
failedVars = append(failedVars, k)
|
||||
}
|
||||
valuePattern = newVal
|
||||
}
|
||||
// update errors if any
|
||||
if len(failedVars) > 0 {
|
||||
*errs = append(*errs, fmt.Errorf("failed to resolve %v at path %s", failedVars, path))
|
||||
}
|
||||
|
||||
return valuePattern
|
||||
}
|
||||
|
||||
// processIfSingleVariable will process the evaluation of single variables
|
||||
// {{variable-{{variable}}}} -> compound/nested variables
|
||||
// {{variable}}{{variable}} -> multiple variables
|
||||
// {{variable}} -> single variable
|
||||
// if the value can be evaluted return the value
|
||||
// -> return value can be scalar or object type
|
||||
// -> if the variable is not present in the context then add an error and dont process further
|
||||
func processIfSingleVariable(log logr.Logger, ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
|
||||
valueStr, ok := valuePattern.(string)
|
||||
if !ok {
|
||||
log.Info("failed to convert to string", "pattern", valuePattern)
|
||||
return false, nil
|
||||
}
|
||||
// get variables at this level
|
||||
validRegex := regexp.MustCompile(singleVarRegex)
|
||||
groups := validRegex.FindAllStringSubmatch(valueStr, -1)
|
||||
if len(groups) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
// as there will be exactly one variable based on the above regex
|
||||
group := groups[0]
|
||||
variable, err := ctx.Query(group[1])
|
||||
if err != nil || variable == nil {
|
||||
*errs = append(*errs, fmt.Errorf("failed to resolve %v at path %s", group[1], path))
|
||||
// return the same value pattern, and add un-resolvable variable error
|
||||
return true, valuePattern
|
||||
}
|
||||
return true, variable
|
||||
}
|
||||
|
|
|
@ -153,5 +153,5 @@ func Test_SubvarRecursive(t *testing.T) {
|
|||
ctx := context.NewContext()
|
||||
assert.Assert(t, ctx.AddResource(resourceRaw))
|
||||
errs := []error{}
|
||||
subValR(log.Log, ctx, string(patternRaw), "/", &errs)
|
||||
subValR(ctx, string(patternRaw), "/", &errs)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue