1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Resolving variables from the resource passed | CLI (#2180)

* added logic for adding resources in context

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* small fix

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* returning error if request.object is passed from cmd

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* reterning error if request.object is passed from value file

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* removing comments

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* small fix

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* handling context for delete operation

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

* small fix for test command

Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>
This commit is contained in:
Pooja Singh 2021-07-24 00:02:48 +05:30 committed by GitHub
parent 4c7ca97eac
commit 88d1617390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 20 deletions

View file

@ -143,6 +143,34 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
return ctx.AddJSON(objRaw)
}
//AddResourceInOldObject data at path: request.oldObject
func (ctx *Context) AddResourceInOldObject(dataRaw []byte) error {
// unmarshal the resource struct
var data interface{}
if err := json.Unmarshal(dataRaw, &data); err != nil {
ctx.log.Error(err, "failed to unmarshal the resource")
return err
}
modifiedResource := struct {
Request interface{} `json:"request"`
}{
Request: struct {
OldObject interface{} `json:"oldObject"`
}{
OldObject: data,
},
}
objRaw, err := json.Marshal(modifiedResource)
if err != nil {
ctx.log.Error(err, "failed to marshal the resource")
return err
}
return ctx.AddJSON(objRaw)
}
func (ctx *Context) AddResourceAsObject(data interface{}) error {
modifiedResource := struct {
Request interface{} `json:"request"`

View file

@ -157,7 +157,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
}
variables, valuesMap, namespaceSelectorMap, err := common.GetVariable(variablesString, valuesFile, fs, false, "")
variables, valuesMap, namespaceSelectorMap, operationIsDelete, err := common.GetVariable(variablesString, valuesFile, fs, false, "")
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to decode yaml", err)
@ -263,9 +263,9 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
}
matches := common.PolicyHasVariables(*policy)
variable := common.RemoveDuplicateVariables(matches)
variable := common.RemoveDuplicateAndObjectVariables(matches)
if len(matches) > 0 && variablesString == "" && valuesFile == "" {
if len(variable) > 0 && variablesString == "" && valuesFile == "" {
rc.skip++
skipPolicy := SkippedPolicy{
Name: policy.GetName(),
@ -288,11 +288,11 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
thisPolicyResourceValues[k] = v
}
if len(common.PolicyHasVariables(*policy)) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
}
ers, validateErs, responseError, rcErs, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin)
ers, validateErs, responseError, rcErs, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin, operationIsDelete)
if err != nil {
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
}

View file

@ -366,34 +366,44 @@ func IsInputFromPipe() bool {
return fileInfo.Mode()&os.ModeCharDevice == 0
}
// RemoveDuplicateVariables - remove duplicate variables
func RemoveDuplicateVariables(matches [][]string) string {
// RemoveDuplicateAndObjectVariables - remove duplicate variables
func RemoveDuplicateAndObjectVariables(matches [][]string) string {
var variableStr string
for _, m := range matches {
for _, v := range m {
foundVariable := strings.Contains(variableStr, v)
if !foundVariable {
variableStr = variableStr + " " + v
if !strings.Contains(v, "request.object") {
variableStr = variableStr + " " + v
}
}
}
}
return variableStr
}
func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit bool, policyResourcePath string) (map[string]string, map[string]map[string]Resource, map[string]map[string]string, error) {
func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit bool, policyResourcePath string) (map[string]string, map[string]map[string]Resource, map[string]map[string]string, bool, error) {
valuesMapResource := make(map[string]map[string]Resource)
valuesMapRule := make(map[string]map[string]Rule)
namespaceSelectorMap := make(map[string]map[string]string)
variables := make(map[string]string)
operationIsDelete := false
var yamlFile []byte
var err error
if variablesString != "" {
kvpairs := strings.Split(strings.Trim(variablesString, " "), ",")
for _, kvpair := range kvpairs {
kvs := strings.Split(strings.Trim(kvpair, " "), "=")
if strings.Contains(kvs[0], "request.object") {
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, sanitizederror.NewWithError("variable request.object.* is handled by kyverno. please do not pass value for request.object variables ", err)
}
if strings.Contains(kvs[0], "request.operation") && strings.Contains(kvs[1], "DELETE") {
operationIsDelete = true
}
variables[strings.Trim(kvs[0], " ")] = strings.Trim(kvs[1], " ")
}
}
if valuesFile != "" {
if isGit {
filep, err := fs.Open(filepath.Join(policyResourcePath, valuesFile))
@ -406,22 +416,30 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
}
if err != nil {
return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("unable to read yaml", err)
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, sanitizederror.NewWithError("unable to read yaml", err)
}
valuesBytes, err := yaml.ToJSON(yamlFile)
if err != nil {
return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("failed to convert json", err)
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, sanitizederror.NewWithError("failed to convert json", err)
}
values := &Values{}
if err := json.Unmarshal(valuesBytes, values); err != nil {
return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("failed to decode yaml", err)
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, sanitizederror.NewWithError("failed to decode yaml", err)
}
for _, p := range values.Policies {
resourceMap := make(map[string]Resource)
for _, r := range p.Resources {
for variableInFile, valueInFile := range r.Values {
if strings.Contains(variableInFile, "request.object") {
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, sanitizederror.NewWithError("variable request.object.* is handled by kyverno. please do not pass value for request.object variables ", err)
}
if strings.Contains(variableInFile, "request.operation") && strings.Contains(valueInFile, "DELETE") {
operationIsDelete = true
}
}
resourceMap[r.Name] = r
}
valuesMapResource[p.Name] = resourceMap
@ -459,7 +477,7 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
Policies: storePolices,
})
return variables, valuesMapResource, namespaceSelectorMap, nil
return variables, valuesMapResource, namespaceSelectorMap, operationIsDelete, nil
}
// MutatePolices - function to apply mutation on policies
@ -482,7 +500,7 @@ func MutatePolices(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) {
// ApplyPolicyOnResource - function to apply policy on resource
func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool) ([]*response.EngineResponse, *response.EngineResponse, bool, bool, error) {
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool, operationIsDelete bool) ([]*response.EngineResponse, *response.EngineResponse, bool, bool, error) {
responseError := false
rcError := false
@ -510,6 +528,20 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
log.Log.V(3).Info("applying policy on resource", "policy", policy.Name, "resource", resPath)
ctx := context.NewContext()
resourceRaw, err := resource.MarshalJSON()
if err != nil {
log.Log.Error(err, "failed to marshal resource")
}
if operationIsDelete {
err = ctx.AddResourceInOldObject(resourceRaw)
} else {
err = ctx.AddResource(resourceRaw)
}
if err != nil {
log.Log.Error(err, "failed to load resource in context")
}
for key, value := range variables {
jsonData := pkgcommon.VariableToJSON(key, value)
ctx.AddJSON(jsonData)

View file

@ -85,7 +85,7 @@ func Test_NamespaceSelector(t *testing.T) {
for _, tc := range testcases {
policyArray, _ := ut.GetPolicy(tc.policy)
resourceArray, _ := GetResource(tc.resource)
_, validateErs, _, _, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false)
_, validateErs, _, _, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, false)
assert.Assert(t, tc.success == validateErs.IsSuccessful())
}
}

View file

@ -305,7 +305,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s
fmt.Printf("\nExecuting %s...", values.Name)
_, valuesMap, namespaceSelectorMap, err := common.GetVariable(variablesString, values.Variables, fs, isGit, policyResourcePath)
_, valuesMap, namespaceSelectorMap, operationIsDelete, err := common.GetVariable(variablesString, values.Variables, fs, isGit, policyResourcePath)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return sanitizederror.NewWithError("failed to decode yaml", err)
@ -357,8 +357,8 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s
}
matches := common.PolicyHasVariables(*policy)
variable := common.RemoveDuplicateVariables(matches)
if len(matches) > 0 && variablesString == "" && values.Variables == "" {
variable := common.RemoveDuplicateAndObjectVariables(matches)
if len(variable) > 0 && variablesString == "" && values.Variables == "" {
skipPolicy := SkippedPolicy{
Name: policy.GetName(),
Rules: policy.Spec.Rules,
@ -385,11 +385,11 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s
if len(valuesMap[policy.GetName()]) != 0 && !reflect.DeepEqual(valuesMap[policy.GetName()][resource.GetName()], Resource{}) {
thisPolicyResourceValues = valuesMap[policy.GetName()][resource.GetName()].Values
}
if len(common.PolicyHasVariables(*policy)) > 0 && len(thisPolicyResourceValues) == 0 {
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 {
return sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
}
ers, validateErs, _, _, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false)
ers, validateErs, _, _, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false, operationIsDelete)
if err != nil {
return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
}