2022-04-25 20:20:40 +08:00
|
|
|
package updaterequest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
backoff "github.com/cenkalti/backoff"
|
2024-06-20 11:44:43 +02:00
|
|
|
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
2022-05-24 09:41:12 +02:00
|
|
|
"github.com/kyverno/kyverno/pkg/background/common"
|
2022-09-07 06:01:43 +02:00
|
|
|
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
2024-06-20 11:44:43 +02:00
|
|
|
kyvernov2informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v2"
|
|
|
|
kyvernov2listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v2"
|
2022-04-25 20:20:40 +08:00
|
|
|
"github.com/kyverno/kyverno/pkg/config"
|
2024-06-11 16:54:51 +08:00
|
|
|
generatorutils "github.com/kyverno/kyverno/pkg/utils/generator"
|
2022-04-25 20:20:40 +08:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
)
|
|
|
|
|
2022-05-23 16:39:12 +02:00
|
|
|
// Generator provides interface to manage update requests
|
|
|
|
type Generator interface {
|
2024-06-20 11:44:43 +02:00
|
|
|
Apply(context.Context, kyvernov2.UpdateRequestSpec) error
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
|
|
|
|
2022-05-23 16:39:12 +02:00
|
|
|
// generator defines the implementation to manage update request resource
|
|
|
|
type generator struct {
|
|
|
|
// clients
|
2022-09-07 06:01:43 +02:00
|
|
|
client versioned.Interface
|
2022-04-25 20:20:40 +08:00
|
|
|
|
2022-05-23 16:39:12 +02:00
|
|
|
// listers
|
2024-06-20 11:44:43 +02:00
|
|
|
urLister kyvernov2listers.UpdateRequestNamespaceLister
|
2024-06-11 16:54:51 +08:00
|
|
|
|
|
|
|
urGenerator generatorutils.UpdateRequestGenerator
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewGenerator returns a new instance of UpdateRequest resource generator
|
2024-06-20 11:44:43 +02:00
|
|
|
func NewGenerator(client versioned.Interface, urInformer kyvernov2informers.UpdateRequestInformer, urGenerator generatorutils.UpdateRequestGenerator) Generator {
|
2022-05-23 16:39:12 +02:00
|
|
|
return &generator{
|
2024-06-11 16:54:51 +08:00
|
|
|
client: client,
|
|
|
|
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace()),
|
|
|
|
urGenerator: urGenerator,
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply creates update request resource
|
2024-06-20 11:44:43 +02:00
|
|
|
func (g *generator) Apply(ctx context.Context, ur kyvernov2.UpdateRequestSpec) error {
|
2024-09-10 17:42:16 +08:00
|
|
|
if ur.Type == kyvernov2.Generate && len(ur.RuleContext) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2023-02-22 18:49:09 +08:00
|
|
|
logger.V(4).Info("apply Update Request", "request", ur)
|
2022-12-09 14:45:11 +01:00
|
|
|
go g.applyResource(context.TODO(), ur)
|
2022-04-25 20:20:40 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-06-20 11:44:43 +02:00
|
|
|
func (g *generator) applyResource(ctx context.Context, urSpec kyvernov2.UpdateRequestSpec) {
|
2022-05-23 16:39:12 +02:00
|
|
|
exbackoff := &backoff.ExponentialBackOff{
|
|
|
|
InitialInterval: 500 * time.Millisecond,
|
|
|
|
RandomizationFactor: 0.5,
|
|
|
|
Multiplier: 1.5,
|
|
|
|
MaxInterval: time.Second,
|
|
|
|
MaxElapsedTime: 3 * time.Second,
|
|
|
|
Clock: backoff.SystemClock,
|
|
|
|
}
|
|
|
|
exbackoff.Reset()
|
2022-12-09 14:45:11 +01:00
|
|
|
if err := backoff.Retry(func() error { return g.tryApplyResource(ctx, urSpec) }, exbackoff); err != nil {
|
2022-04-25 20:20:40 +08:00
|
|
|
logger.Error(err, "failed to update request CR")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-20 11:44:43 +02:00
|
|
|
func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov2.UpdateRequestSpec) error {
|
2023-02-10 22:56:17 +08:00
|
|
|
l := logger.WithValues("ruleType", urSpec.GetRequestType(), "resource", urSpec.GetResource().String())
|
2022-05-24 09:41:12 +02:00
|
|
|
var queryLabels labels.Set
|
2022-06-16 16:53:37 +05:30
|
|
|
|
2024-06-20 11:44:43 +02:00
|
|
|
if urSpec.GetRequestType() == kyvernov2.Mutate {
|
2023-02-10 22:56:17 +08:00
|
|
|
queryLabels = common.MutateLabelsSet(urSpec.Policy, urSpec.GetResource())
|
2024-06-20 11:44:43 +02:00
|
|
|
} else if urSpec.GetRequestType() == kyvernov2.Generate {
|
2024-08-14 01:14:06 +08:00
|
|
|
queryLabels = common.GenerateLabelsSet(urSpec.Policy)
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
2023-02-22 18:49:09 +08:00
|
|
|
|
2023-03-17 16:36:06 +08:00
|
|
|
l.V(4).Info("creating new UpdateRequest")
|
2024-06-20 11:44:43 +02:00
|
|
|
ur := kyvernov2.UpdateRequest{
|
2023-03-17 16:36:06 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Namespace: config.KyvernoNamespace(),
|
|
|
|
GenerateName: "ur-",
|
|
|
|
Labels: queryLabels,
|
|
|
|
},
|
|
|
|
Spec: urSpec,
|
|
|
|
}
|
2024-06-11 16:54:51 +08:00
|
|
|
created, err := g.urGenerator.Generate(ctx, g.client, &ur, l)
|
2022-04-25 20:20:40 +08:00
|
|
|
if err != nil {
|
2023-03-17 16:36:06 +08:00
|
|
|
l.V(4).Error(err, "failed to create UpdateRequest, retrying", "name", ur.GetGenerateName(), "namespace", ur.GetNamespace())
|
2022-04-25 20:20:40 +08:00
|
|
|
return err
|
2024-06-11 16:54:51 +08:00
|
|
|
} else if created == nil {
|
|
|
|
return nil
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
2023-03-17 16:36:06 +08:00
|
|
|
updated := created.DeepCopy()
|
2024-06-20 11:44:43 +02:00
|
|
|
updated.Status.State = kyvernov2.Pending
|
|
|
|
_, err = g.client.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
2023-03-17 16:36:06 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-04-25 20:20:40 +08:00
|
|
|
}
|
2023-03-17 16:36:06 +08:00
|
|
|
l.V(4).Info("successfully created UpdateRequest", "name", updated.GetName(), "namespace", ur.GetNamespace())
|
2022-04-25 20:20:40 +08:00
|
|
|
return nil
|
|
|
|
}
|