Files
Oliver BählerandGitHub 2252c530f4 feat(performance): removed duplicate client calls from all admission paths (#2054)
* chore

* perfromance improvements

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* perfromance improvements

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat(performance): removed duplicate client calls from all admission paths

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

---------

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
2026-07-28 14:32:42 +02:00

203 lines
4.3 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package events
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
eventsv1 "k8s.io/api/events/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
k8sevents "k8s.io/client-go/tools/events"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/projectcapsule/capsule/pkg/runtime/configuration"
)
const (
ReportingController = "controller.projectcapsule.dev"
ReportingInstance = "capsule-admission"
eventQueueSize = 1024
eventCreateTimeout = 10 * time.Second
)
type EventRecorder interface {
k8sevents.EventRecorder
LabeledEvent(regarding runtime.Object, eventType string, reason string, action string, note string) LabeledEvent
}
type eventEmitter interface {
Emit(ctx context.Context, e LabeledEvent)
}
type eventRecorder struct {
k8sevents.EventRecorder
client client.Client
configuration configuration.Configuration
log logr.Logger
queue chan *eventsv1.Event
}
func NewEventRecorder(
c client.Client,
log logr.Logger,
recorder k8sevents.EventRecorder,
configuration configuration.Configuration,
) EventRecorder {
r := &eventRecorder{
EventRecorder: recorder,
client: c,
log: log.WithName("event-recorder"),
configuration: configuration,
}
if c != nil {
r.queue = make(chan *eventsv1.Event, eventQueueSize)
go r.run()
}
return r
}
func (r *eventRecorder) Emit(ctx context.Context, e LabeledEvent) {
if r == nil {
return
}
if r.client == nil {
r.log.Error(nil, "cannot emit labeled event: client is nil")
return
}
if e == nil {
r.log.Error(nil, "cannot emit labeled event: event is nil")
return
}
if e.Reason() == "" {
r.log.Error(nil, "cannot emit labeled event: reason is empty")
return
}
if e.Action() == "" {
r.log.Error(nil, "cannot emit labeled event: action is empty")
return
}
regardingRef, metaObj, err := objectReference(e.Regarding())
if err != nil {
r.log.Error(err, "cannot emit labeled event: build regarding reference")
return
}
namespace := metaObj.GetNamespace()
if namespace == "" {
namespace = r.configuration.Events().ClusterEventNamespace
}
if namespace == "" {
r.log.Error(nil, "cannot emit labeled event: namespace is empty")
return
}
event := &eventsv1.Event{
ObjectMeta: metav1.ObjectMeta{
GenerateName: metaObj.GetName(),
Namespace: namespace,
Labels: e.Labels(),
Annotations: e.Annotations(),
},
EventTime: metav1.MicroTime{Time: time.Now()},
ReportingController: ReportingController,
ReportingInstance: ReportingInstance,
Action: e.Action(),
Reason: e.Reason(),
Regarding: regardingRef,
Note: e.Note(),
Type: e.EventType(),
}
if e.Related() != nil {
relatedRef, _, err := objectReference(e.Related())
if err != nil {
r.log.Error(err, "cannot emit labeled event: build related reference")
return
}
event.Related = &relatedRef
}
select {
case r.queue <- event:
default:
r.log.Error(
nil,
"cannot enqueue labeled event: queue is full",
"reason", e.Reason(),
"action", e.Action(),
"type", e.EventType(),
"regarding", regardingRef.Name,
"namespace", namespace,
)
}
}
func (r *eventRecorder) run() {
for event := range r.queue {
ctx, cancel := context.WithTimeout(context.Background(), eventCreateTimeout)
err := r.client.Create(ctx, event)
cancel()
if err == nil {
continue
}
r.log.Error(
err,
"cannot emit labeled event",
"reason", event.Reason,
"action", event.Action,
"type", event.Type,
"regarding", event.Regarding.Name,
"namespace", event.Namespace,
)
}
}
func objectReference(obj runtime.Object) (corev1.ObjectReference, metav1.Object, error) {
if obj == nil {
return corev1.ObjectReference{}, nil, fmt.Errorf("object is nil")
}
metaObj, ok := obj.(metav1.Object)
if !ok {
return corev1.ObjectReference{}, nil, fmt.Errorf("%T does not implement metav1.Object", obj)
}
gvk := obj.GetObjectKind().GroupVersionKind()
return corev1.ObjectReference{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
Namespace: metaObj.GetNamespace(),
Name: metaObj.GetName(),
UID: metaObj.GetUID(),
}, metaObj, nil
}