1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

refactor: clean updaterequest generator ()

* refactor: clean updaterequest generator

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* refactor: clean updaterequest generator

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-05-23 16:39:12 +02:00 committed by GitHub
parent 005400c606
commit caa769fb1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 175 deletions
cmd/kyverno
pkg/webhooks

View file

@ -154,6 +154,7 @@ func main() {
// utils
kyvernoV1 := kyvernoInformer.Kyverno().V1()
kyvernoV1beta1 := kyvernoInformer.Kyverno().V1beta1()
kyvernoV1alpha2 := kyvernoInformer.Kyverno().V1alpha2()
// load image registry secrets
@ -264,7 +265,7 @@ func main() {
dynamicClient,
kyvernoV1.ClusterPolicies(),
kyvernoV1.Policies(),
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
kyvernoV1beta1.UpdateRequests(),
configuration,
eventGenerator,
reportReqGen,
@ -279,10 +280,7 @@ func main() {
os.Exit(1)
}
urgen := webhookgenerate.NewGenerator(kyvernoClient,
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
stopCh,
log.Log.WithName("UpdateRequestGenerator"))
urgen := webhookgenerate.NewGenerator(kyvernoClient, kyvernoV1beta1.UpdateRequests())
urc := background.NewController(
kubeClient,
@ -290,7 +288,7 @@ func main() {
dynamicClient,
kyvernoV1.ClusterPolicies(),
kyvernoV1.Policies(),
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
kyvernoV1beta1.UpdateRequests(),
kubeInformer.Core().V1().Namespaces(),
kubeInformer.Core().V1().Pods(),
eventGenerator,
@ -303,7 +301,7 @@ func main() {
dynamicClient,
kyvernoV1.ClusterPolicies(),
kyvernoV1.Policies(),
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
kyvernoV1beta1.UpdateRequests(),
kubeInformer.Core().V1().Namespaces(),
log.Log.WithName("GenerateCleanUpController"),
)
@ -413,7 +411,7 @@ func main() {
kubeInformer.Core().V1().Namespaces().Lister(),
kubeInformer.Rbac().V1().RoleBindings().Lister(),
kubeInformer.Rbac().V1().ClusterRoleBindings().Lister(),
kyvernoInformer.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
kyvernoV1beta1.UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
reportReqGen,
urgen,
eventGenerator,

View file

@ -56,7 +56,7 @@ type handlers struct {
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
prGenerator policyreport.GeneratorInterface
urGenerator webhookgenerate.Interface
urGenerator webhookgenerate.Generator
eventGen event.Interface
auditHandler AuditHandler
openAPIController *openapi.Controller
@ -73,7 +73,7 @@ func NewHandlers(
crbLister rbacv1listers.ClusterRoleBindingLister,
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
prGenerator policyreport.GeneratorInterface,
urGenerator webhookgenerate.Interface,
urGenerator webhookgenerate.Generator,
eventGen event.Interface,
auditHandler AuditHandler,
openAPIController *openapi.Controller,

View file

@ -315,7 +315,7 @@ func stripNonPolicyFields(obj, newRes map[string]interface{}, logger logr.Logger
return obj, newRes
}
func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Interface, userRequestInfo kyvernov1beta1.RequestInfo,
func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Generator, userRequestInfo kyvernov1beta1.RequestInfo,
action admissionv1.Operation, engineResponses ...*response.EngineResponse,
) (failedUpdateRequest []updateRequestResponse) {
requestBytes, err := json.Marshal(request)

View file

@ -5,10 +5,7 @@ import (
"time"
backoff "github.com/cenkalti/backoff"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernov1beta1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
@ -16,101 +13,61 @@ import (
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/retry"
)
// UpdateRequest provides interface to manage update requests
type Interface interface {
// Generator provides interface to manage update requests
type Generator interface {
Apply(gr kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error
}
// info object stores message data to create update request
type info struct {
spec kyvernov1beta1.UpdateRequestSpec
action admissionv1.Operation
}
// Generator defines the implementation to mange update request resource
type Generator struct {
// generator defines the implementation to manage update request resource
type generator struct {
// clients
client kyvernoclient.Interface
stopCh <-chan struct{}
log logr.Logger
// listers
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
}
// NewGenerator returns a new instance of UpdateRequest resource generator
func NewGenerator(client kyvernoclient.Interface, urInformer kyvernov1beta1informers.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{
func NewGenerator(client kyvernoclient.Interface, urInformer kyvernov1beta1informers.UpdateRequestInformer) Generator {
return &generator{
client: client,
stopCh: stopCh,
log: log,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace()),
}
return gen
}
// Apply creates update request resource
func (g *Generator) Apply(ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error {
logger := g.log
func (g *generator) Apply(ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error {
logger.V(4).Info("reconcile Update Request", "request", ur)
message := info{
action: action,
spec: ur,
if action == admissionv1.Delete && ur.Type == kyvernov1beta1.Generate {
return nil
}
go g.processApply(message)
_, policyName, err := cache.SplitMetaNamespaceKey(ur.Policy)
if err != nil {
return err
}
go g.applyResource(policyName, ur)
return nil
}
// Run starts the update request spec
func (g *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := g.log
defer utilruntime.HandleCrash()
logger.V(4).Info("starting")
defer func() {
logger.V(4).Info("shutting down")
}()
<-g.stopCh
}
func (g *Generator) processApply(i info) {
if err := g.generate(i); err != nil {
func (g *generator) applyResource(policyName string, urSpec kyvernov1beta1.UpdateRequestSpec) {
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()
if err := backoff.Retry(func() error { return g.tryApplyResource(policyName, urSpec) }, exbackoff); err != nil {
logger.Error(err, "failed to update request CR")
}
}
func (g *Generator) generate(i info) error {
if err := retryApplyResource(g.client, i.spec, g.log, i.action, g.urLister); err != nil {
return err
}
return nil
}
func retryApplyResource(
client kyvernoclient.Interface,
urSpec kyvernov1beta1.UpdateRequestSpec,
log logr.Logger,
action admissionv1.Operation,
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
) error {
if action == admissionv1.Delete && urSpec.Type == kyvernov1beta1.Generate {
return nil
}
var i int
var err error
_, policyName, err := cache.SplitMetaNamespaceKey(urSpec.Policy)
if err != nil {
return err
}
applyResource := func() error {
func (g *generator) tryApplyResource(policyName string, urSpec kyvernov1beta1.UpdateRequestSpec) error {
ur := kyvernov1beta1.UpdateRequest{
Spec: urSpec,
Status: kyvernov1beta1.UpdateRequestStatus{
@ -141,80 +98,59 @@ func retryApplyResource(
ur.SetNamespace(config.KyvernoNamespace())
isExist := false
log.V(4).Info("apply UpdateRequest", "ruleType", ur.Spec.Type)
logger.V(4).Info("apply UpdateRequest", "ruleType", ur.Spec.Type)
urList, err := urLister.List(labels.SelectorFromSet(queryLabels))
urList, err := g.urLister.List(labels.SelectorFromSet(queryLabels))
if err != nil {
log.Error(err, "failed to get update request for the resource", "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
logger.Error(err, "failed to get update request for the resource", "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
return err
}
for _, v := range urList {
log.V(4).Info("updating existing update request", "name", v.GetName())
logger.V(4).Info("updating existing update request", "name", v.GetName())
v.Spec.Context = ur.Spec.Context
v.Spec.Policy = ur.Spec.Policy
v.Spec.Resource = ur.Spec.Resource
v.Status.Message = ""
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
if err != nil {
log.V(4).Info("failed to update UpdateRequest, retrying", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace(), "err", err.Error())
i++
logger.V(4).Info("failed to update UpdateRequest, retrying", "name", ur.GetName(), "namespace", ur.GetNamespace(), "err", err.Error())
return err
} else {
log.V(4).Info("successfully updated UpdateRequest", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace())
logger.V(4).Info("successfully updated UpdateRequest", "name", ur.GetName(), "namespace", ur.GetNamespace())
}
err = retry.RetryOnConflict(common.DefaultRetry, func() error {
ur, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Get(context.TODO(), new.GetName(), metav1.GetOptions{})
if err != nil {
return err
}
ur.Status.State = kyvernov1beta1.Pending
_, err = client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), ur, metav1.UpdateOptions{})
return err
})
if err != nil {
log.Error(err, "failed to set UpdateRequest state to Pending")
new.Status.State = kyvernov1beta1.Pending
if _, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending")
return err
}
isExist = true
}
if !isExist {
log.V(4).Info("creating new UpdateRequest", "type", ur.Spec.Type)
logger.V(4).Info("creating new UpdateRequest", "type", ur.Spec.Type)
ur.SetGenerateName("ur-")
ur.SetLabels(queryLabels)
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), &ur, metav1.CreateOptions{})
new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), &ur, metav1.CreateOptions{})
if err != nil {
log.V(4).Info("failed to create UpdateRequest, retrying", "retryCount", i, "name", ur.GetGenerateName(), "namespace", ur.GetNamespace(), "err", err.Error())
i++
logger.V(4).Info("failed to create UpdateRequest, retrying", "name", ur.GetGenerateName(), "namespace", ur.GetNamespace(), "err", err.Error())
return err
} else {
log.V(4).Info("successfully created UpdateRequest", "retryCount", i, "name", new.GetName(), "namespace", ur.GetNamespace())
}
logger.V(4).Info("successfully created UpdateRequest", "name", new.GetName(), "namespace", ur.GetNamespace())
}
return nil
}
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()
err = backoff.Retry(applyResource, exbackoff)
if err != nil {
new.Status.State = kyvernov1beta1.Pending
if _, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending")
return err
}
}
return nil
}

View file

@ -0,0 +1,5 @@
package updaterequest
import "sigs.k8s.io/controller-runtime/pkg/log"
var logger = log.Log.WithName("updaterequest-generator")