From 8b6d3d1f6a728f44ef4b3688999650789c5c10ec Mon Sep 17 00:00:00 2001
From: Prateek Pandey
Date: Mon, 9 May 2022 12:43:11 +0530
Subject: [PATCH] feat: trigger generate on existing matched resource (#3819)
* feat: trigger generate on existing matched resource
Signed-off-by: prateekpandey14
* refactor the triggers and fix review comments
Signed-off-by: prateekpandey14
* add trigger for other matching kinds
Signed-off-by: prateekpandey14
* implement match exclude using dynamic client
Signed-off-by: prateekpandey14
* refactor generate trigger
Signed-off-by: prateekpandey14
* increase sleep timeout
Signed-off-by: prateekpandey14
* optimize unstructured list
Signed-off-by: prateekpandey14
* fix review comments
Signed-off-by: prateekpandey14
* log refactor and clean debug comments
Signed-off-by: prateekpandey14
---
api/kyverno/v1/spec_types.go | 11 ++
charts/kyverno/templates/crds.yaml | 6 +
config/crds/kyverno.io_clusterpolicies.yaml | 6 +
config/crds/kyverno.io_policies.yaml | 6 +
config/install.yaml | 12 ++
config/install_debug.yaml | 12 ++
docs/crd/v1/index.html | 42 ++++++
pkg/background/generate/generate.go | 20 ++-
pkg/policy/policy_controller.go | 31 +++-
pkg/policy/updaterequest.go | 157 +++++++++++++-------
pkg/policy/utils.go | 58 +++++++-
11 files changed, 295 insertions(+), 66 deletions(-)
diff --git a/api/kyverno/v1/spec_types.go b/api/kyverno/v1/spec_types.go
index 171533139d..27b8526022 100644
--- a/api/kyverno/v1/spec_types.go
+++ b/api/kyverno/v1/spec_types.go
@@ -68,6 +68,12 @@ type Spec struct {
// Default value is "false".
// +optional
MutateExistingOnPolicyUpdate bool `json:"mutateExistingOnPolicyUpdate,omitempty" yaml:"mutateExistingOnPolicyUpdate,omitempty"`
+
+ // GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources
+ // If is set to "true" generate rule will be triggered and applied to existing matched resources.
+ // Defaults to "false" if not specified.
+ // +optional
+ GenerateExistingOnPolicyUpdate bool `json:"generateExistingOnPolicyUpdate,omitempty" yaml:"generateExistingOnPolicyUpdate,omitempty"`
}
func (s *Spec) SetRules(rules []Rule) {
@@ -163,6 +169,11 @@ func (s *Spec) GetMutateExistingOnPolicyUpdate() bool {
return s.MutateExistingOnPolicyUpdate
}
+// IsGenerateExistingOnPolicyUpdate return GenerateExistingOnPolicyUpdate set value
+func (s *Spec) IsGenerateExistingOnPolicyUpdate() bool {
+ return s.GenerateExistingOnPolicyUpdate
+}
+
// GetFailurePolicy returns the failure policy to be applied
func (s *Spec) GetFailurePolicy() FailurePolicyType {
if s.FailurePolicy == nil {
diff --git a/charts/kyverno/templates/crds.yaml b/charts/kyverno/templates/crds.yaml
index 71c64e1d7b..f8adef174c 100644
--- a/charts/kyverno/templates/crds.yaml
+++ b/charts/kyverno/templates/crds.yaml
@@ -64,6 +64,9 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources If is set to "true" generate rule will be triggered and applied to existing matched resources. Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting policy is applied on policy events. Default value is "false".
type: boolean
@@ -2409,6 +2412,9 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources If is set to "true" generate rule will be triggered and applied to existing matched resources. Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting policy is applied on policy events. Default value is "false".
type: boolean
diff --git a/config/crds/kyverno.io_clusterpolicies.yaml b/config/crds/kyverno.io_clusterpolicies.yaml
index a076294f7f..0c27397b1e 100644
--- a/config/crds/kyverno.io_clusterpolicies.yaml
+++ b/config/crds/kyverno.io_clusterpolicies.yaml
@@ -68,6 +68,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
diff --git a/config/crds/kyverno.io_policies.yaml b/config/crds/kyverno.io_policies.yaml
index 78b82b8663..fd5f3f06b1 100644
--- a/config/crds/kyverno.io_policies.yaml
+++ b/config/crds/kyverno.io_policies.yaml
@@ -69,6 +69,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
diff --git a/config/install.yaml b/config/install.yaml
index b8a4ff5ab4..f55b0e8ae7 100644
--- a/config/install.yaml
+++ b/config/install.yaml
@@ -85,6 +85,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
@@ -3591,6 +3597,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
diff --git a/config/install_debug.yaml b/config/install_debug.yaml
index bcbb937e63..b3b14def55 100755
--- a/config/install_debug.yaml
+++ b/config/install_debug.yaml
@@ -83,6 +83,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
@@ -3585,6 +3591,12 @@ spec:
- Ignore
- Fail
type: string
+ generateExistingOnPolicyUpdate:
+ description: GenerateExistingOnPolicyUpdate controls wether to trigger
+ generate rule in existing resources If is set to "true" generate
+ rule will be triggered and applied to existing matched resources.
+ Defaults to "false" if not specified.
+ type: boolean
mutateExistingOnPolicyUpdate:
description: MutateExistingOnPolicyUpdate controls if a mutateExisting
policy is applied on policy events. Default value is "false".
diff --git a/docs/crd/v1/index.html b/docs/crd/v1/index.html
index a0622b9f2c..51fcf08c64 100644
--- a/docs/crd/v1/index.html
+++ b/docs/crd/v1/index.html
@@ -202,6 +202,20 @@ bool
Default value is “false”.
+
+
+generateExistingOnPolicyUpdate
+
+bool
+
+ |
+
+(Optional)
+ GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources
+If is set to “true” generate rule will be triggered and applied to existing matched resources.
+Defaults to “false” if not specified.
+ |
+
@@ -395,6 +409,20 @@ bool
Default value is “false”.
+
+
+generateExistingOnPolicyUpdate
+
+bool
+
+ |
+
+(Optional)
+ GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources
+If is set to “true” generate rule will be triggered and applied to existing matched resources.
+Defaults to “false” if not specified.
+ |
+
@@ -2954,6 +2982,20 @@ bool
Default value is “false”.
+
+
+generateExistingOnPolicyUpdate
+
+bool
+
+ |
+
+(Optional)
+ GenerateExistingOnPolicyUpdate controls wether to trigger generate rule in existing resources
+If is set to “true” generate rule will be triggered and applied to existing matched resources.
+Defaults to “false” if not specified.
+ |
+
diff --git a/pkg/background/generate/generate.go b/pkg/background/generate/generate.go
index 6989aed8dc..b6f77f5b6a 100644
--- a/pkg/background/generate/generate.go
+++ b/pkg/background/generate/generate.go
@@ -349,8 +349,8 @@ func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext
return nil, processExisting, err
}
- if !processExisting {
- genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy.GetName(), ur)
+ if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() || !processExisting {
+ genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy, ur)
if err != nil {
log.Error(err, "failed to apply generate rule", "policy", policy.GetName(),
"rule", rule.Name, "resource", resource.GetName(), "suggestion", "users need to grant Kyverno's service account additional privileges")
@@ -359,6 +359,10 @@ func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext
ruleNameToProcessingTime[rule.Name] = time.Since(startTime)
genResources = append(genResources, genResource)
}
+
+ if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
+ processExisting = false
+ }
}
return genResources, processExisting, nil
@@ -384,7 +388,7 @@ func getResourceInfo(object map[string]interface{}) (kind, name, namespace, apiv
return
}
-func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, ur urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
+func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy kyverno.PolicyInterface, ur urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode
@@ -420,7 +424,7 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, res
}
if len(genClone) != 0 {
- rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy, genClone, client)
+ rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy.GetName(), genClone, client)
} else {
rdata, mode, err = manageData(logger, genAPIVersion, genKind, genNamespace, genName, genData, client)
}
@@ -455,7 +459,13 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, res
common.ManageLabels(newResource, resource)
// Add Synchronize label
label := newResource.GetLabels()
- label["policy.kyverno.io/policy-name"] = policy
+
+ // Add background gen-rule label if generate rule applied on existing resource
+ if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
+ label["kyverno.io/background-gen-rule"] = rule.Name
+ }
+
+ label["policy.kyverno.io/policy-name"] = policy.GetName()
label["policy.kyverno.io/gr-name"] = ur.Name
if mode == Create {
if rule.Generation.Synchronize {
diff --git a/pkg/policy/policy_controller.go b/pkg/policy/policy_controller.go
index 5c431e6a0d..66ea800672 100644
--- a/pkg/policy/policy_controller.go
+++ b/pkg/policy/policy_controller.go
@@ -12,7 +12,7 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
- "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
+ utilscommon "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
"github.com/kyverno/kyverno/pkg/autogen"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
@@ -30,6 +30,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
informers "k8s.io/client-go/informers/core/v1"
@@ -177,7 +178,7 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
go pc.registerPolicyChangesMetricAddPolicy(logger, p)
if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
- pol, _ := common.MutatePolicy(p, logger)
+ pol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add policy ")
@@ -203,7 +204,7 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
- pol, _ := common.MutatePolicy(curP, logger)
+ pol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update policy ")
@@ -273,7 +274,7 @@ func (pc *PolicyController) addNsPolicy(obj interface{}) {
spec := p.GetSpec()
if spec.Background == nil || spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
- nsPol, _ := common.MutatePolicy(p, logger)
+ nsPol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(p.Namespace).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add namespace policy")
@@ -297,7 +298,7 @@ func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
- nsPol, _ := common.MutatePolicy(curP, logger)
+ nsPol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(curP.GetNamespace()).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update namespace policy ")
@@ -481,7 +482,10 @@ func (pc *PolicyController) syncPolicy(key string) error {
}
return err
} else {
- pc.updateUR(key, policy)
+ err = pc.updateUR(key, policy)
+ if err != nil {
+ logger.Error(err, "failed to updateUR on Policy update")
+ }
}
pc.processExistingResources(policy)
@@ -566,6 +570,21 @@ func getTrigger(rd kyverno.ResourceDescription) []*kyverno.ResourceSpec {
return specs
}
+func generateTriggers(client client.Interface, rule kyverno.Rule, log logr.Logger) []*unstructured.Unstructured {
+ list := &unstructured.UnstructuredList{}
+
+ kinds := fetchUniqueKinds(rule)
+
+ for _, kind := range kinds {
+ mlist, err := client.ListResource("", kind, "", rule.MatchResources.Selector)
+ if err != nil {
+ log.Error(err, "failed to list matched resource")
+ }
+ list.Items = append(list.Items, mlist.Items...)
+ }
+ return convertlist(list.Items)
+}
+
func deleteUR(kyvernoClient kyvernoclient.Interface, policyKey string, grList []*urkyverno.UpdateRequest, logger logr.Logger) {
for _, v := range grList {
if policyKey == v.Spec.Policy {
diff --git a/pkg/policy/updaterequest.go b/pkg/policy/updaterequest.go
index 0a2da3738c..759262ff08 100644
--- a/pkg/policy/updaterequest.go
+++ b/pkg/policy/updaterequest.go
@@ -7,71 +7,119 @@ import (
"github.com/gardener/controller-manager-library/pkg/logger"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
+ common "github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/config"
+ "github.com/kyverno/kyverno/pkg/engine"
+ "github.com/kyverno/kyverno/pkg/engine/response"
+ engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
+
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
-func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInterface) {
+func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInterface) error {
logger := pc.log.WithName("updateUR").WithName(policyKey)
- // TODO: add check for genExisting
- if !policy.GetSpec().MutateExistingOnPolicyUpdate {
- logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate)
- return
+ if !policy.GetSpec().MutateExistingOnPolicyUpdate && !policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
+ logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate, "generateExisting", policy.GetSpec().IsGenerateExistingOnPolicyUpdate())
+ return nil
}
logger.Info("update URs on policy event")
+ var errors []error
mutateURs := pc.listMutateURs(policyKey, nil)
generateURs := pc.listGenerateURs(policyKey, nil)
updateUR(pc.kyvernoClient, policyKey, append(mutateURs, generateURs...), pc.log.WithName("updateUR"))
for _, rule := range policy.GetSpec().Rules {
var ruleType urkyverno.RequestType
+
if rule.IsMutateExisting() {
ruleType = urkyverno.Mutate
- } else {
- // TODO: assign generate ruleType
+
+ triggers := generateTriggers(pc.client, rule, pc.log)
+ for _, trigger := range triggers {
+ murs := pc.listMutateURs(policyKey, trigger)
+
+ if murs != nil {
+ logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+trigger.GetName())
+ continue
+ }
+
+ logger.Info("creating new UR")
+ ur := newUR(policy, trigger, ruleType)
+ err := pc.handleUpdateRequest(ur, trigger, rule, policy)
+ if err != nil {
+ pc.log.Error(err, "failed to create new UR policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
+ "target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
+ continue
+ } else {
+ pc.log.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
+ "target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
+ }
+ }
+ }
+ if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
+ ruleType = urkyverno.Generate
+ triggers := generateTriggers(pc.client, rule, pc.log)
+ for _, trigger := range triggers {
+ gurs := pc.listGenerateURs(policyKey, trigger)
+
+ if gurs != nil {
+ logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+"/"+trigger.GetName())
+ continue
+ }
+
+ logger.Info("creating new UR")
+ ur := newUR(policy, trigger, ruleType)
+ err := pc.handleUpdateRequest(ur, trigger, rule, policy)
+ if err != nil {
+ pc.log.Error(err, "failed to create new UR policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
+ "target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
+ errors = append(errors, err)
+ continue
+ } else {
+ pc.log.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
+ "target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
+ }
+ }
+ err := engineutils.CombineErrors(errors)
+ return err
+ }
+ }
+ return nil
+}
+
+func (pc *PolicyController) handleUpdateRequest(ur *urkyverno.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyverno.Rule, policy kyverno.PolicyInterface) error {
+ policyContext, _, err := common.NewBackgroundContext(pc.client, ur, policy, triggerResource, pc.configHandler, nil, pc.log)
+ if err != nil {
+ pc.log.WithName(rule.Name).Error(err, "failed to build policy context for existing")
+ }
+ engineResponse := engine.ApplyBackgroundChecks(policyContext)
+
+ for _, ruleResponse := range engineResponse.PolicyResponse.Rules {
+ if ruleResponse.Status != response.RuleStatusPass {
+ pc.log.Error(err, "can not create new UR for genExisting rule on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule.Status", ruleResponse.Status)
continue
}
- triggers := getTriggers(rule)
- for _, trigger := range triggers {
- var urs []*urkyverno.UpdateRequest
- if ruleType == urkyverno.Mutate {
- urs = pc.listMutateURs(policyKey, trigger)
- } else {
- urs = pc.listGenerateURs(policyKey, trigger)
- }
+ new, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), ur, metav1.CreateOptions{})
+ if err != nil {
+ return err
+ }
- logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.Namespace+trigger.Name)
-
- if urs != nil {
- continue
- }
-
- logger.Info("creating new UR")
- ur := newUR(policy, trigger, ruleType)
- new, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), ur, metav1.CreateOptions{})
- if err != nil {
- pc.log.Error(err, "failed to create new UR policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
- "target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
- continue
- } else {
- pc.log.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
- "target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
- }
-
- new.Status.State = urkyverno.Pending
- if _, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
- pc.log.Error(err, "failed to set UpdateRequest state to Pending")
- }
+ new.Status.State = urkyverno.Pending
+ if _, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
+ pc.log.Error(err, "failed to set UpdateRequest state to Pending")
+ return err
}
}
+ return err
}
-func (pc *PolicyController) listMutateURs(policyKey string, trigger *kyverno.ResourceSpec) []*urkyverno.UpdateRequest {
+func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*urkyverno.UpdateRequest {
selector := createMutateLabels(policyKey, trigger)
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
if err != nil {
@@ -81,7 +129,7 @@ func (pc *PolicyController) listMutateURs(policyKey string, trigger *kyverno.Res
return mutateURs
}
-func (pc *PolicyController) listGenerateURs(policyKey string, trigger *kyverno.ResourceSpec) []*urkyverno.UpdateRequest {
+func (pc *PolicyController) listGenerateURs(policyKey string, trigger *unstructured.Unstructured) []*urkyverno.UpdateRequest {
selector := createGenerateLabels(policyKey, trigger)
generateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
if err != nil {
@@ -91,7 +139,7 @@ func (pc *PolicyController) listGenerateURs(policyKey string, trigger *kyverno.R
return generateURs
}
-func newUR(policy kyverno.PolicyInterface, trigger *kyverno.ResourceSpec, ruleType urkyverno.RequestType) *urkyverno.UpdateRequest {
+func newUR(policy kyverno.PolicyInterface, trigger *unstructured.Unstructured, ruleType urkyverno.RequestType) *urkyverno.UpdateRequest {
var policyNameNamespaceKey string
if policy.IsNamespaced() {
@@ -117,16 +165,16 @@ func newUR(policy kyverno.PolicyInterface, trigger *kyverno.ResourceSpec, ruleTy
Type: ruleType,
Policy: policyNameNamespaceKey,
Resource: kyverno.ResourceSpec{
- Kind: trigger.Kind,
- Namespace: trigger.Namespace,
- Name: trigger.Name,
- APIVersion: trigger.APIVersion,
+ Kind: trigger.GetKind(),
+ Namespace: trigger.GetNamespace(),
+ Name: trigger.GetName(),
+ APIVersion: trigger.GetAPIVersion(),
},
},
}
}
-func createMutateLabels(policyKey string, trigger *kyverno.ResourceSpec) labels.Set {
+func createMutateLabels(policyKey string, trigger *unstructured.Unstructured) labels.Set {
var selector labels.Set
if trigger == nil {
selector = labels.Set(map[string]string{
@@ -135,20 +183,21 @@ func createMutateLabels(policyKey string, trigger *kyverno.ResourceSpec) labels.
} else {
selector = labels.Set(map[string]string{
urkyverno.URMutatePolicyLabel: policyKey,
- urkyverno.URMutateTriggerNameLabel: trigger.Name,
- urkyverno.URMutateTriggerNSLabel: trigger.Namespace,
- urkyverno.URMutatetriggerKindLabel: trigger.Kind,
+ urkyverno.URMutateTriggerNameLabel: trigger.GetName(),
+ urkyverno.URMutateTriggerNSLabel: trigger.GetNamespace(),
+ urkyverno.URMutatetriggerKindLabel: trigger.GetKind(),
})
- if trigger.APIVersion != "" {
- selector[urkyverno.URMutatetriggerAPIVersionLabel] = trigger.APIVersion
+ if trigger.GetAPIVersion() != "" {
+ selector[urkyverno.URMutatetriggerAPIVersionLabel] = trigger.GetAPIVersion()
+
}
}
return selector
}
-func createGenerateLabels(policyKey string, trigger *kyverno.ResourceSpec) labels.Set {
+func createGenerateLabels(policyKey string, trigger *unstructured.Unstructured) labels.Set {
var selector labels.Set
if trigger == nil {
selector = labels.Set(map[string]string{
@@ -157,9 +206,9 @@ func createGenerateLabels(policyKey string, trigger *kyverno.ResourceSpec) label
} else {
selector = labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: policyKey,
- "generate.kyverno.io/resource-name": trigger.Name,
- "generate.kyverno.io/resource-kind": trigger.Kind,
- "generate.kyverno.io/resource-namespace": trigger.Namespace,
+ "generate.kyverno.io/resource-name": trigger.GetName(),
+ "generate.kyverno.io/resource-kind": trigger.GetKind(),
+ "generate.kyverno.io/resource-namespace": trigger.GetNamespace(),
})
}
diff --git a/pkg/policy/utils.go b/pkg/policy/utils.go
index 58aac763bb..aa23785415 100644
--- a/pkg/policy/utils.go
+++ b/pkg/policy/utils.go
@@ -1,6 +1,9 @@
package policy
-import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+import (
+ kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
func isRunningPod(obj unstructured.Unstructured) bool {
objMap := obj.UnstructuredContent()
@@ -11,3 +14,56 @@ func isRunningPod(obj unstructured.Unstructured) bool {
return phase == "Running"
}
+
+// check if all slice elements are same
+func isMatchResourcesAllValid(rule kyverno.Rule) bool {
+ var kindlist []string
+ for _, all := range rule.MatchResources.All {
+ kindlist = append(kindlist, all.Kinds...)
+ }
+
+ if len(kindlist) == 0 {
+ return false
+ }
+
+ for i := 1; i < len(kindlist); i++ {
+ if kindlist[i] != kindlist[0] {
+ return false
+ }
+ }
+ return true
+}
+
+func fetchUniqueKinds(rule kyverno.Rule) []string {
+ var kindlist []string
+
+ kindlist = append(kindlist, rule.MatchResources.Kinds...)
+
+ for _, all := range rule.MatchResources.Any {
+ kindlist = append(kindlist, all.Kinds...)
+ }
+
+ if isMatchResourcesAllValid(rule) {
+ for _, all := range rule.MatchResources.All {
+ kindlist = append(kindlist, all.Kinds...)
+ }
+ }
+
+ inResult := make(map[string]bool)
+ var result []string
+ for _, kind := range kindlist {
+ if _, ok := inResult[kind]; !ok {
+ inResult[kind] = true
+ result = append(result, kind)
+ }
+ }
+ return result
+}
+
+func convertlist(ulists []unstructured.Unstructured) []*unstructured.Unstructured {
+ var result []*unstructured.Unstructured
+ for _, list := range ulists {
+ result = append(result, list.DeepCopy())
+ }
+ return result
+}