1
0
Fork 0
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:
shravan 2020-05-05 23:52:52 +05:30
parent ab8664d6ca
commit 717e8e7245
3 changed files with 50 additions and 104 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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)
}