1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00
kyverno/pkg/breaker/resource_counter.go
Vishal Choudhary fe49e97fba
feat: add reporting to mutate and generate rules (#11265)
* feat: add reports to standard mutatation

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: add warnings for permissions

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: remove unnecessary fields

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: add reporting to generate and mutate existing

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: add reporting to generate and mutate existing

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: codegen and add generate tests

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: linter

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: e2e matrix

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: cleanup

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

---------

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>
Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2024-10-02 12:05:05 +00:00

142 lines
3.7 KiB
Go

package breaker
import (
"context"
"sync"
reportsv1 "github.com/kyverno/kyverno/api/reports/v1"
watchtools "github.com/kyverno/kyverno/cmd/kyverno/watch"
"github.com/kyverno/kyverno/pkg/client/informers/externalversions/internalinterfaces"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
metadataclient "k8s.io/client-go/metadata"
"k8s.io/client-go/tools/cache"
)
type resourceUIDGetter interface {
GetUID() types.UID
}
type Counter interface {
Count() (int, bool)
}
type counter struct {
lock sync.RWMutex
entries sets.Set[types.UID]
retryWatcher *watchtools.RetryWatcher
}
func (c *counter) Record(uid types.UID) {
c.lock.Lock()
defer c.lock.Unlock()
c.entries.Insert(uid)
}
func (c *counter) Forget(uid types.UID) {
c.lock.Lock()
defer c.lock.Unlock()
c.entries.Delete(uid)
}
func (c *counter) Count() (int, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
return c.entries.Len(), c.retryWatcher.IsRunning()
}
func StartResourceCounter(ctx context.Context, client metadataclient.Interface, gvr schema.GroupVersionResource, tweakListOptions internalinterfaces.TweakListOptionsFunc) (*counter, error) {
objs, err := client.Resource(gvr).List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
watcher := &cache.ListWatch{
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.Resource(gvr).Watch(ctx, options)
},
}
watchInterface, err := watchtools.NewRetryWatcher(objs.GetResourceVersion(), watcher)
if err != nil {
return nil, err
}
entries := sets.New[types.UID]()
for _, entry := range objs.Items {
entries.Insert(entry.GetUID())
}
w := &counter{
entries: entries,
retryWatcher: watchInterface,
}
go func() {
for event := range watchInterface.ResultChan() {
getter, ok := event.Object.(resourceUIDGetter)
if ok {
switch event.Type {
case watch.Added:
w.Record(getter.GetUID())
case watch.Modified:
w.Record(getter.GetUID())
case watch.Deleted:
w.Forget(getter.GetUID())
}
}
}
}()
return w, nil
}
func StartAdmissionReportsCounter(ctx context.Context, client metadataclient.Interface) (Counter, error) {
tweakListOptions := func(lo *metav1.ListOptions) {
lo.LabelSelector = "audit.kyverno.io/source==admission"
}
ephrs, err := StartResourceCounter(ctx, client, reportsv1.SchemeGroupVersion.WithResource("ephemeralreports"), tweakListOptions)
if err != nil {
return nil, err
}
cephrs, err := StartResourceCounter(ctx, client, reportsv1.SchemeGroupVersion.WithResource("clusterephemeralreports"), tweakListOptions)
if err != nil {
return nil, err
}
return composite{
inner: []Counter{ephrs, cephrs},
}, nil
}
func StartBackgroundReportsCounter(ctx context.Context, client metadataclient.Interface) (Counter, error) {
tweakListOptions := func(lo *metav1.ListOptions) {
lo.LabelSelector = "audit.kyverno.io/source==background-scan"
}
ephrs, err := StartResourceCounter(ctx, client, reportsv1.SchemeGroupVersion.WithResource("ephemeralreports"), tweakListOptions)
if err != nil {
return nil, err
}
cephrs, err := StartResourceCounter(ctx, client, reportsv1.SchemeGroupVersion.WithResource("clusterephemeralreports"), tweakListOptions)
if err != nil {
return nil, err
}
return composite{
inner: []Counter{ephrs, cephrs},
}, nil
}
type composite struct {
inner []Counter
}
func (c composite) Count() (int, bool) {
sum := 0
for _, counter := range c.inner {
count, isRunning := counter.Count()
if !isRunning {
return 0, false
}
sum += count
}
return sum, true
}