diff --git a/pkg/background/generate/generate.go b/pkg/background/generate/generate.go index 6e2f65926f..42c586f7dc 100644 --- a/pkg/background/generate/generate.go +++ b/pkg/background/generate/generate.go @@ -101,7 +101,7 @@ func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error { var resource *unstructured.Unstructured var genResources []kyverno.ResourceSpec var precreatedResource bool - logger.Info("start processing UR", "resourceVersion", ur.GetResourceVersion()) + logger.Info("start processing UR", "ur", ur.Name, "resourceVersion", ur.GetResourceVersion()) // 1 - Check if the resource exists resource, err = common.GetResource(c.client, ur.Spec, c.log) diff --git a/pkg/background/request_process.go b/pkg/background/request_process.go index 5d18797dd8..cb87af3194 100644 --- a/pkg/background/request_process.go +++ b/pkg/background/request_process.go @@ -2,11 +2,15 @@ package background import ( "context" + "strconv" + "github.com/go-logr/logr" urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1" "github.com/kyverno/kyverno/pkg/background/generate" "github.com/kyverno/kyverno/pkg/background/mutate" "github.com/kyverno/kyverno/pkg/config" + dclient "github.com/kyverno/kyverno/pkg/dclient" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -55,3 +59,64 @@ func (c *Controller) UnmarkUR(ur *urkyverno.UpdateRequest) error { _, err = c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), newUR, metav1.UpdateOptions{}) return err } + +func (c *Controller) HandleDeleteUR(ur urkyverno.UpdateRequest) error { + logger := c.log.WithValues("kind", ur.Kind, "namespace", ur.Namespace, "name", ur.Name) + // 1- Corresponding policy has been deleted + // then we don't delete the generated resources + + // 2- The trigger resource is deleted, then delete the generated resources + if !ownerResourceExists(logger, c.client, ur) { + deleteUR := false + // check retry count in annotaion + urAnnotations := ur.Annotations + if val, ok := urAnnotations["generate.kyverno.io/retry-count"]; ok { + retryCount, err := strconv.ParseUint(val, 10, 32) + if err != nil { + logger.Error(err, "unable to convert retry-count") + return err + } + + if retryCount >= 5 { + deleteUR = true + } + } + + if deleteUR { + if err := deleteGeneratedResources(logger, c.client, ur); err != nil { + return err + } + // - trigger-resource is deleted + // - generated-resources are deleted + // - > Now delete the UpdateRequest CR + return c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), ur.Name, metav1.DeleteOptions{}) + } + } + return nil +} + +func ownerResourceExists(log logr.Logger, client dclient.Interface, ur urkyverno.UpdateRequest) bool { + _, err := client.GetResource("", ur.Spec.Resource.Kind, ur.Spec.Resource.Namespace, ur.Spec.Resource.Name) + // trigger resources has been deleted + if apierrors.IsNotFound(err) { + return false + } + if err != nil { + log.Error(err, "failed to get resource", "genKind", ur.Spec.Resource.Kind, "genNamespace", ur.Spec.Resource.Namespace, "genName", ur.Spec.Resource.Name) + } + // if there was an error while querying the resources we don't delete the generated resources + // but expect the deletion in next reconciliation loop + return true +} + +func deleteGeneratedResources(log logr.Logger, client dclient.Interface, ur urkyverno.UpdateRequest) error { + for _, genResource := range ur.Status.GeneratedResources { + err := client.DeleteResource("", genResource.Kind, genResource.Namespace, genResource.Name, false) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + log.V(3).Info("generated resource deleted", "genKind", ur.Spec.Resource.Kind, "genNamespace", ur.Spec.Resource.Namespace, "genName", ur.Spec.Resource.Name) + } + return nil +} diff --git a/pkg/background/update_request_controller.go b/pkg/background/update_request_controller.go index e012909f21..642f404cd3 100644 --- a/pkg/background/update_request_controller.go +++ b/pkg/background/update_request_controller.go @@ -204,7 +204,9 @@ func (c *Controller) syncUpdateRequest(key string) error { logger.V(3).Info("UR is marked successfully", "ur", ur.GetName(), "resourceVersion", ur.GetResourceVersion()) if err := c.ProcessUR(ur); err != nil { - return fmt.Errorf("failed to process UR %s: %v", key, err) + logger.Info("failed to process the UR, triggering handle delete operation", "handler", ur.Status.Handler, "ur", ur.GetName(), "err", err) + err = c.HandleDeleteUR(*ur) + return fmt.Errorf("failed to process delete UR %s: %v", key, err) } if err = c.UnmarkUR(ur); err != nil {