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:
parent
e248757798
commit
a558c4cb48
5 changed files with 60 additions and 54 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue