1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-09 17:37:12 +00:00
kyverno/pkg/globalcontext/k8sresource/entry.go
Khaled Emara 2b2587469d
feat: enhance global context (#9710)
* feat(globalcontext): add event handling

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* feat(globalcontext): handle cache sync error

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* feat(globalcontext): ensure api is called during init

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* design(events): decouple events from policies a bit

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* feat(globalcontext): use status

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): make status optional

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): status update

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): codegen

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* chore(globalcontext): delete yaml annotations

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): fix status in tests

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcotext): update enqueue func

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): error

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* chore(globalcontext): rbac

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* chore(globalcontext): retry logic

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): unknown api call in test

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* bump

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix: set unique name for each testing resource

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix: update readme

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix: log msg

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix: add delays

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix: delay gctce creation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* debug: check Kyverno status

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* debug: update chainsaw config

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* debug: revert chainsaw config

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* test(globalcontext): print actual status

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): add necessary delays and check status before applying

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* test(globalcontext): long refreshInterval

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* debug: log success

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* debug: print informer data

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): use client instead of informer

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* debug: print status after update

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* debug: print ResourceVersion

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* debug: remove gcecontroller from other controllers

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): update status only once

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* chore: remove excess logs

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

* fix(globalcontext): add store to cleanup controller

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>

---------

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>
Co-authored-by: shuting <shuting@nirmata.com>
Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2024-02-23 10:34:04 +00:00

124 lines
3.5 KiB
Go

package k8sresource
import (
"context"
"fmt"
"github.com/go-logr/logr"
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/event"
entryevent "github.com/kyverno/kyverno/pkg/globalcontext/event"
"github.com/kyverno/kyverno/pkg/globalcontext/invalid"
"github.com/kyverno/kyverno/pkg/globalcontext/store"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/dynamic/dynamicinformer"
"k8s.io/client-go/tools/cache"
)
type entry struct {
lister cache.GenericLister
stop func()
gce *kyvernov2alpha1.GlobalContextEntry
eventGen event.Interface
}
// TODO: Handle Kyverno Pod Ready State
func New(
ctx context.Context,
gce *kyvernov2alpha1.GlobalContextEntry,
eventGen event.Interface,
client dynamic.Interface,
kyvernoClient versioned.Interface,
logger logr.Logger,
gvr schema.GroupVersionResource,
namespace string,
shouldUpdateStatus bool,
) (store.Entry, error) {
indexers := cache.Indexers{
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
}
if namespace == "" {
namespace = metav1.NamespaceAll
}
informer := dynamicinformer.NewFilteredDynamicInformer(client, gvr, namespace, 0, indexers, nil)
var group wait.Group
ctx, cancel := context.WithCancel(ctx)
stop := func() {
// Send stop signal to informer's goroutine
cancel()
// Wait for the group to terminate
group.Wait()
}
group.StartWithContext(ctx, func(ctx context.Context) {
informer.Informer().Run(ctx.Done())
})
if !cache.WaitForCacheSync(ctx.Done(), informer.Informer().HasSynced) {
stop()
if shouldUpdateStatus {
if err := updateStatus(ctx, gce, kyvernoClient, false, "CacheSyncFailure"); err != nil {
logger.Error(err, "failed to update status")
}
}
err := fmt.Errorf("failed to sync cache for %s", gvr)
eventGen.Add(entryevent.NewErrorEvent(corev1.ObjectReference{
APIVersion: gce.APIVersion,
Kind: gce.Kind,
Name: gce.Name,
Namespace: gce.Namespace,
UID: gce.UID,
}, entryevent.ReasonCacheSyncFailure, err))
return invalid.New(err), nil
}
if shouldUpdateStatus {
if err := updateStatus(ctx, gce, kyvernoClient, true, "CacheSyncSuccess"); err != nil {
logger.Error(err, "failed to update status")
}
}
return &entry{
lister: informer.Lister(),
stop: stop,
eventGen: eventGen,
}, nil
}
func (e *entry) Get() (any, error) {
obj, err := e.lister.List(labels.Everything())
if err != nil {
e.eventGen.Add(entryevent.NewErrorEvent(corev1.ObjectReference{
APIVersion: e.gce.APIVersion,
Kind: e.gce.Kind,
Name: e.gce.Name,
Namespace: e.gce.Namespace,
UID: e.gce.UID,
}, entryevent.ReasonResourceListFailure, err))
return nil, err
}
return obj, nil
}
func (e *entry) Stop() {
e.stop()
}
func updateStatus(ctx context.Context, gce *kyvernov2alpha1.GlobalContextEntry, kyvernoClient versioned.Interface, ready bool, reason string) error {
_, err := controllerutils.UpdateStatus(ctx, gce, kyvernoClient.KyvernoV2alpha1().GlobalContextEntries(), func(latest *kyvernov2alpha1.GlobalContextEntry) error {
if latest == nil {
return fmt.Errorf("failed to update status: %s", gce.Name)
}
latest.Status.SetReady(ready, reason)
return nil
})
return err
}