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:
parent
4c7ca97eac
commit
88d1617390
5 changed files with 80 additions and 20 deletions
|
@ -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"`
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue