1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-15 08:46:36 +00:00

fix: extend retry function to mutate rules (#8100)

Uses the UpdateRetryAnnotation mechanism already implemented in generate rules for mutate rules.

This fixes the issue that UpdateRequests keep existing indefinitely when the original trigger resource was deleted.

Signed-off-by: Ströger Florian <stroeger@youniqx.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Florian Ströger 2023-08-30 14:24:57 +02:00 committed by GitHub
parent e248757798
commit a558c4cb48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 54 deletions

View file

@ -2,6 +2,8 @@ package common
import (
"context"
"fmt"
"strconv"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
@ -51,3 +53,49 @@ func ResourceSpecFromUnstructured(obj unstructured.Unstructured) kyvernov1.Resou
Name: obj.GetName(),
}
}
func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]string, error) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = map[string]string{
kyvernov1beta1.URGenerateRetryCountAnnotation: "1",
}
}
retry := 1
val, ok := urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]
if !ok {
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = "1"
} else {
retryUint, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return retry, urAnnotations, fmt.Errorf("unable to convert retry-count %v: %w", val, err)
}
retry = int(retryUint)
retry += 1
incrementedRetryString := strconv.Itoa(retry)
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = incrementedRetryString
}
return retry, urAnnotations, nil
}
func UpdateRetryAnnotation(kyvernoClient versioned.Interface, ur *kyvernov1beta1.UpdateRequest) error {
retry, urAnnotations, err := increaseRetryAnnotation(ur)
if err != nil {
return err
}
if retry > 3 {
err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), ur.GetName(), metav1.DeleteOptions{})
if err != nil {
return errors.Wrapf(err, "exceeds retry limit, failed to delete the UR: %s, retry: %v, resourceVersion: %s", ur.Name, retry, ur.GetResourceVersion())
}
} else {
ur.SetAnnotations(urAnnotations)
_, err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Update(context.TODO(), ur, metav1.UpdateOptions{})
if err != nil {
return errors.Wrapf(err, "failed to update annotation in update request: %s for the resource, retry: %v, resourceVersion %s, annotations: %v", ur.Name, retry, ur.GetResourceVersion(), urAnnotations)
}
}
return nil
}

View file

@ -99,7 +99,7 @@ func (c *GenerateController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error {
trigger, err := c.getTrigger(ur.Spec)
if err != nil {
logger.V(3).Info("the trigger resource does not exist or is pending creation, re-queueing", "details", err.Error())
if err := updateRetryAnnotation(c.kyvernoClient, ur); err != nil {
if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil {
return err
}
}

View file

@ -2,16 +2,10 @@ package generate
import (
"context"
"fmt"
"strconv"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -26,52 +20,6 @@ func newResourceSpec(genAPIVersion, genKind, genNamespace, genName string) kyver
}
}
func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]string, error) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = map[string]string{
kyvernov1beta1.URGenerateRetryCountAnnotation: "1",
}
}
retry := 1
val, ok := urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]
if !ok {
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = "1"
} else {
retryUint, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return retry, urAnnotations, fmt.Errorf("unable to convert retry-count %v: %w", val, err)
}
retry = int(retryUint)
retry += 1
incrementedRetryString := strconv.Itoa(retry)
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = incrementedRetryString
}
return retry, urAnnotations, nil
}
func updateRetryAnnotation(kyvernoClient versioned.Interface, ur *kyvernov1beta1.UpdateRequest) error {
retry, urAnnotations, err := increaseRetryAnnotation(ur)
if err != nil {
return err
}
if retry > 3 {
err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), ur.GetName(), metav1.DeleteOptions{})
if err != nil {
return errors.Wrapf(err, "exceeds retry limit, failed to delete the UR: %s, retry: %v, resourceVersion: %s", ur.Name, retry, ur.GetResourceVersion())
}
} else {
ur.SetAnnotations(urAnnotations)
_, err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Update(context.TODO(), ur, metav1.UpdateOptions{})
if err != nil {
return errors.Wrapf(err, "failed to update annotation in update request: %s for the resource, retry: %v, resourceVersion %s, annotations: %v", ur.Name, retry, ur.GetResourceVersion(), urAnnotations)
}
}
return nil
}
func TriggerFromLabels(labels map[string]string) kyvernov1.ResourceSpec {
group := labels[common.GenerateTriggerGroupLabel]
version := labels[common.GenerateTriggerVersionLabel]

View file

@ -8,6 +8,7 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
@ -29,6 +30,7 @@ var ErrEmptyPatch error = fmt.Errorf("empty resource to patch")
type mutateExistingController struct {
// clients
client dclient.Interface
kyvernoClient versioned.Interface
statusControl common.StatusControlInterface
engine engineapi.Engine
@ -47,6 +49,7 @@ type mutateExistingController struct {
// NewMutateExistingController returns an instance of the MutateExistingController
func NewMutateExistingController(
client dclient.Interface,
kyvernoClient versioned.Interface,
statusControl common.StatusControlInterface,
engine engineapi.Engine,
policyLister kyvernov1listers.ClusterPolicyLister,
@ -59,6 +62,7 @@ func NewMutateExistingController(
) *mutateExistingController {
c := mutateExistingController{
client: client,
kyvernoClient: kyvernoClient,
statusControl: statusControl,
engine: engine,
policyLister: policyLister,
@ -94,6 +98,9 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
if err != nil || trigger == nil {
logger.WithName(rule.Name).Error(err, "failed to get trigger resource")
errs = append(errs, err)
if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil {
errs = append(errs, err)
}
continue
}
} else {
@ -103,6 +110,9 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
if admissionRequest.SubResource == "" {
logger.WithName(rule.Name).Error(err, "failed to get trigger resource")
errs = append(errs, err)
if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil {
errs = append(errs, err)
}
continue
} else {
logger.WithName(rule.Name).Info("trigger resource not found for subresource, reverting to resource in AdmissionReviewRequest", "subresource", admissionRequest.SubResource)

View file

@ -220,7 +220,7 @@ func (c *controller) processUR(ur *kyvernov1beta1.UpdateRequest) error {
statusControl := common.NewStatusControl(c.kyvernoClient, c.urLister)
switch ur.Spec.GetRequestType() {
case kyvernov1beta1.Mutate:
ctrl := mutate.NewMutateExistingController(c.client, statusControl, c.engine, c.cpolLister, c.polLister, c.nsLister, c.configuration, c.eventGen, logger, c.jp)
ctrl := mutate.NewMutateExistingController(c.client, c.kyvernoClient, statusControl, c.engine, c.cpolLister, c.polLister, c.nsLister, c.configuration, c.eventGen, logger, c.jp)
return ctrl.ProcessUR(ur)
case kyvernov1beta1.Generate:
ctrl := generate.NewGenerateController(c.client, c.kyvernoClient, statusControl, c.engine, c.cpolLister, c.polLister, c.urLister, c.nsLister, c.configuration, c.eventGen, logger, c.jp)