1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 07:57:07 +00:00
kyverno/pkg/controllers/webhook/controller.go

183 lines
5.7 KiB
Go
Raw Normal View History

package background
import (
"context"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/controllers"
"github.com/kyverno/kyverno/pkg/tls"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
admissionregistrationv1informers "k8s.io/client-go/informers/admissionregistration/v1"
corev1informers "k8s.io/client-go/informers/core/v1"
admissionregistrationv1listers "k8s.io/client-go/listers/admissionregistration/v1"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/util/workqueue"
)
const (
// Workers is the number of workers for this controller
Workers = 2
maxRetries = 10
)
type controller struct {
// clients
secretClient controllerutils.GetClient[*corev1.Secret]
mwcClient controllerutils.UpdateClient[*admissionregistrationv1.MutatingWebhookConfiguration]
vwcClient controllerutils.UpdateClient[*admissionregistrationv1.ValidatingWebhookConfiguration]
// listers
secretLister corev1listers.SecretLister
mwcLister admissionregistrationv1listers.MutatingWebhookConfigurationLister
vwcLister admissionregistrationv1listers.ValidatingWebhookConfigurationLister
// queue
queue workqueue.RateLimitingInterface
mwcEnqueue controllerutils.EnqueueFunc
vwcEnqueue controllerutils.EnqueueFunc
}
func NewController(
secretClient controllerutils.GetClient[*corev1.Secret],
mwcClient controllerutils.UpdateClient[*admissionregistrationv1.MutatingWebhookConfiguration],
vwcClient controllerutils.UpdateClient[*admissionregistrationv1.ValidatingWebhookConfiguration],
secretInformer corev1informers.SecretInformer,
mwcInformer admissionregistrationv1informers.MutatingWebhookConfigurationInformer,
vwcInformer admissionregistrationv1informers.ValidatingWebhookConfigurationInformer,
) controllers.Controller {
queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), controllerName)
c := controller{
secretClient: secretClient,
mwcClient: mwcClient,
vwcClient: vwcClient,
secretLister: secretInformer.Lister(),
mwcLister: mwcInformer.Lister(),
vwcLister: vwcInformer.Lister(),
queue: queue,
mwcEnqueue: controllerutils.AddDefaultEventHandlers(logger.V(3), mwcInformer.Informer(), queue),
vwcEnqueue: controllerutils.AddDefaultEventHandlers(logger.V(3), vwcInformer.Informer(), queue),
}
controllerutils.AddEventHandlers(
secretInformer.Informer(),
func(obj interface{}) {
if err := c.enqueue(obj.(*corev1.Secret)); err != nil {
logger.Error(err, "failed to enqueue")
}
},
func(_, obj interface{}) {
if err := c.enqueue(obj.(*corev1.Secret)); err != nil {
logger.Error(err, "failed to enqueue")
}
},
func(obj interface{}) {
if err := c.enqueue(obj.(*corev1.Secret)); err != nil {
logger.Error(err, "failed to enqueue")
}
},
)
return &c
}
func (c *controller) Run(ctx context.Context, workers int) {
controllerutils.Run(ctx, controllerName, logger.V(3), c.queue, workers, maxRetries, c.reconcile)
}
func (c *controller) enqueue(obj *corev1.Secret) error {
if obj.GetName() == tls.GenerateRootCASecretName() && obj.GetNamespace() == config.KyvernoNamespace() {
requirement, err := labels.NewRequirement("webhook.kyverno.io/managed-by", selection.Equals, []string{kyvernov1.ValueKyvernoApp})
if err != nil {
// TODO: log error
return err
}
selector := labels.Everything().Add(*requirement)
mwcs, err := c.mwcLister.List(selector)
if err != nil {
return err
}
for _, mwc := range mwcs {
err = c.mwcEnqueue(mwc)
if err != nil {
return err
}
}
vwcs, err := c.vwcLister.List(selector)
if err != nil {
return err
}
for _, vwc := range vwcs {
err = c.vwcEnqueue(vwc)
if err != nil {
return err
}
}
}
return nil
}
func (c *controller) reconcileMutatingWebhookConfiguration(ctx context.Context, logger logr.Logger, name string) error {
w, err := c.mwcLister.Get(name)
if err != nil {
if apierrors.IsNotFound(err) {
return nil
}
return err
}
labels := w.GetLabels()
if labels == nil || labels["webhook.kyverno.io/managed-by"] != kyvernov1.ValueKyvernoApp {
return nil
}
_, err = controllerutils.Update(ctx, w, c.mwcClient, func(w *admissionregistrationv1.MutatingWebhookConfiguration) error {
caData, err := tls.ReadRootCASecret(c.secretClient)
if err != nil {
return err
}
for i := range w.Webhooks {
w.Webhooks[i].ClientConfig.CABundle = caData
}
return nil
})
return err
}
func (c *controller) reconcileValidatingWebhookConfiguration(ctx context.Context, logger logr.Logger, name string) error {
w, err := c.vwcLister.Get(name)
if err != nil {
if apierrors.IsNotFound(err) {
return nil
}
return err
}
labels := w.GetLabels()
if labels == nil || labels["webhook.kyverno.io/managed-by"] != kyvernov1.ValueKyvernoApp {
return nil
}
_, err = controllerutils.Update(ctx, w, c.vwcClient, func(w *admissionregistrationv1.ValidatingWebhookConfiguration) error {
caData, err := tls.ReadRootCASecret(c.secretClient)
if err != nil {
return err
}
for i := range w.Webhooks {
w.Webhooks[i].ClientConfig.CABundle = caData
}
return nil
})
return err
}
func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, namespace, name string) error {
if err := c.reconcileMutatingWebhookConfiguration(ctx, logger, name); err != nil {
return err
}
if err := c.reconcileValidatingWebhookConfiguration(ctx, logger, name); err != nil {
return err
}
return nil
}