diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go index f777e47259..f17813f7b3 100644 --- a/pkg/generate/generate.go +++ b/pkg/generate/generate.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/gardener/controller-manager-library/pkg/logger" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/config" @@ -344,7 +345,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou } if genClone != nil && len(genClone) != 0 { - rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, genClone, client) + rdata, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy, genClone, client) } else { rdata, mode, err = manageData(logger, genAPIVersion, genKind, genNamespace, genName, genData, client) } @@ -379,6 +380,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou label := newResource.GetLabels() label["generate.kyverno.io/policy-name"] = policy label["generate.kyverno.io/gr-name"] = gr.Name + delete(label, "generate.kyverno.io/clone-policy-name") if mode == Create { if rule.Generation.Synchronize { label["generate.kyverno.io/synchronize"] = "enable" @@ -442,7 +444,7 @@ func manageData(log logr.Logger, apiVersion, kind, namespace, name string, data return updateObj.UnstructuredContent(), Update, nil } -func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, clone map[string]interface{}, client *dclient.Client) (map[string]interface{}, ResourceMode, error) { +func manageClone(log logr.Logger, apiVersion, kind, namespace, name, policy string, clone map[string]interface{}, client *dclient.Client) (map[string]interface{}, ResourceMode, error) { rNamespace, _, err := unstructured.NestedString(clone, "namespace") if err != nil { return nil, Skip, fmt.Errorf("failed to find source namespace: %v", err) @@ -464,6 +466,38 @@ func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, clon return nil, Skip, fmt.Errorf("source resource %s %s/%s/%s not found. %v", apiVersion, kind, rNamespace, rName, err) } + updateSource := true + + // add label + label := obj.GetLabels() + if len(label) == 0 { + label = make(map[string]string) + label["generate.kyverno.io/clone-policy-name"] = policy + } else { + if label["generate.kyverno.io/clone-policy-name"] != "" { + policyNames := label["generate.kyverno.io/clone-policy-name"] + if !strings.Contains(policyNames, policy) { + policyNames = policyNames + "," + policy + label["generate.kyverno.io/clone-policy-name"] = policyNames + } else { + updateSource = false + } + } else { + label["generate.kyverno.io/clone-policy-name"] = policy + } + } + + if updateSource { + log.V(4).Info("updating existing clone source") + obj.SetLabels(label) + _, err = client.UpdateResource(apiVersion, kind, rNamespace, obj, false) + if err != nil { + logger.Error(err, "updating existing resource") + return nil, Skip, fmt.Errorf("failed to update source label: %v", err) + } + log.V(2).Info("updated source") + } + // check if resource to be generated exists newResource, err := client.GetResource(apiVersion, kind, namespace, name) if err == nil { diff --git a/pkg/webhooks/generation.go b/pkg/webhooks/generation.go index b67a91640b..94a3a20112 100644 --- a/pkg/webhooks/generation.go +++ b/pkg/webhooks/generation.go @@ -86,8 +86,8 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic return } -//HandleUpdateAndDelete handles admission-requests for update and delete -func (ws *WebhookServer) handleUpdateAndDelete(request *v1beta1.AdmissionRequest) { +//HandleUpdateAndDelete handles admission-requests for delete +func (ws *WebhookServer) handleDelete(request *v1beta1.AdmissionRequest) { resource, err := enginutils.ConvertToUnstructured(request.OldObject.Raw) if err != nil { logger.Error(err, "failed to convert object resource to unstructured format") @@ -104,6 +104,33 @@ func (ws *WebhookServer) handleUpdateAndDelete(request *v1beta1.AdmissionRequest } } +//HandleUpdateAndDelete handles admission-requests for update +func (ws *WebhookServer) handleUpdate(request *v1beta1.AdmissionRequest) { + resource, err := enginutils.ConvertToUnstructured(request.OldObject.Raw) + if err != nil { + logger.Error(err, "failed to convert object resource to unstructured format") + } + + resLabels := resource.GetLabels() + if resLabels["generate.kyverno.io/clone-policy-name"] != "" { + policyNames := strings.Split(resLabels["generate.kyverno.io/clone-policy-name"], ",") + for _, policyName := range policyNames { + selector := labels.SelectorFromSet(labels.Set(map[string]string{ + "generate.kyverno.io/policy-name": policyName, + })) + + grList, err := ws.grLister.List(selector) + if err != nil { + logger.Error(err, "failed to get generate request for the resource", "label", "generate.kyverno.io/policy-name") + + } + for _, gr := range grList { + ws.grController.EnqueueGenerateRequestFromWebhook(gr) + } + } + } +} + func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.EngineResponse) { logger.V(4).Info("querying all generate requests") selector := labels.SelectorFromSet(labels.Set(map[string]string{ diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index 6fa43fafd0..abf69254a6 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -378,7 +378,9 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1 func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse { logger := ws.log.WithName("Validate").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation) if request.Operation == v1beta1.Delete { - go ws.handleUpdateAndDelete(request) + go ws.handleDelete(request) + } else if request.Operation == v1beta1.Update { + go ws.handleUpdate(request) } if !ws.supportMutateValidate {