Files
capsule/pkg/runtime/predicates/controller_work.go
T
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

332 lines
13 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package predicates
import (
"reflect"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
capmeta "github.com/projectcapsule/capsule/pkg/api/meta"
"github.com/projectcapsule/capsule/pkg/utils"
)
func ClassChanged() predicate.Predicate {
return predicate.Or(
predicate.GenerationChangedPredicate{},
UpdatedMetadataPredicate{},
DeletionChangedPredicate{},
)
}
// TenantManagedResourceChangedPredicate admits drift in fields reconciled by
// the Tenant controller while filtering status-only updates. Several built-in
// resources do not reliably increment metadata.generation when their desired
// fields change, so GenerationChangedPredicate alone cannot detect tampering.
type TenantManagedResourceChangedPredicate struct{ predicate.Funcs }
func (TenantManagedResourceChangedPredicate) Create(event.CreateEvent) bool { return true }
func (TenantManagedResourceChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (TenantManagedResourceChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (TenantManagedResourceChangedPredicate) Update(e event.UpdateEvent) bool {
if e.ObjectOld == nil || e.ObjectNew == nil {
return false
}
if !utils.MapEqual(e.ObjectOld.GetLabels(), e.ObjectNew.GetLabels()) ||
!utils.MapEqual(e.ObjectOld.GetAnnotations(), e.ObjectNew.GetAnnotations()) ||
!reflect.DeepEqual(e.ObjectOld.GetOwnerReferences(), e.ObjectNew.GetOwnerReferences()) ||
!reflect.DeepEqual(e.ObjectOld.GetFinalizers(), e.ObjectNew.GetFinalizers()) ||
(e.ObjectOld.GetDeletionTimestamp() == nil) != (e.ObjectNew.GetDeletionTimestamp() == nil) {
return true
}
switch oldObject := e.ObjectOld.(type) {
case *corev1.LimitRange:
newObject, ok := e.ObjectNew.(*corev1.LimitRange)
return ok && !reflect.DeepEqual(oldObject.Spec, newObject.Spec)
case *corev1.ResourceQuota:
newObject, ok := e.ObjectNew.(*corev1.ResourceQuota)
return ok && !reflect.DeepEqual(oldObject.Spec, newObject.Spec)
case *networkingv1.NetworkPolicy:
newObject, ok := e.ObjectNew.(*networkingv1.NetworkPolicy)
return ok && !reflect.DeepEqual(oldObject.Spec, newObject.Spec)
case *rbacv1.RoleBinding:
newObject, ok := e.ObjectNew.(*rbacv1.RoleBinding)
return ok && (!reflect.DeepEqual(oldObject.RoleRef, newObject.RoleRef) ||
!reflect.DeepEqual(oldObject.Subjects, newObject.Subjects))
default:
return false
}
}
type NamespaceTenantStateChangedPredicate struct{ predicate.Funcs }
func (NamespaceTenantStateChangedPredicate) Create(event.CreateEvent) bool { return true }
func (NamespaceTenantStateChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (NamespaceTenantStateChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (NamespaceTenantStateChangedPredicate) Update(e event.UpdateEvent) bool {
oldNamespace, oldOK := e.ObjectOld.(*corev1.Namespace)
newNamespace, newOK := e.ObjectNew.(*corev1.Namespace)
if !oldOK || !newOK {
return false
}
return !reflect.DeepEqual(oldNamespace.Labels, newNamespace.Labels) ||
!reflect.DeepEqual(oldNamespace.Annotations, newNamespace.Annotations) ||
!reflect.DeepEqual(oldNamespace.OwnerReferences, newNamespace.OwnerReferences) ||
(oldNamespace.DeletionTimestamp == nil) != (newNamespace.DeletionTimestamp == nil)
}
type QuantityLedgerWorkChangedPredicate struct{ predicate.Funcs }
func (QuantityLedgerWorkChangedPredicate) Create(e event.CreateEvent) bool {
ledger, ok := e.Object.(*capsulev1beta2.QuantityLedger)
if !ok {
return false
}
// A ledger can be created and receive admission reservations before the
// informer observes its first Add event. In that case the Add is the only
// work notification; filtering it would strand the reservations forever.
return quantityLedgerHasWork(ledger)
}
func (QuantityLedgerWorkChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (QuantityLedgerWorkChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (QuantityLedgerWorkChangedPredicate) Update(e event.UpdateEvent) bool {
oldLedger, oldOK := e.ObjectOld.(*capsulev1beta2.QuantityLedger)
newLedger, newOK := e.ObjectNew.(*capsulev1beta2.QuantityLedger)
if !oldOK || !newOK {
return false
}
if oldLedger.Generation != newLedger.Generation {
return true
}
// Informers may coalesce an intermediate settled state. An update can
// therefore replace reservations with pending deletes (or append more
// reservations) while both observed snapshots contain work. Admit every
// newly introduced or changed work item so it cannot be stranded. Pure
// settlement/removal updates remain filtered.
return quantityLedgerIntroducesWork(oldLedger, newLedger)
}
func quantityLedgerHasWork(ledger *capsulev1beta2.QuantityLedger) bool {
return len(ledger.Status.Reservations) > 0 ||
len(ledger.Status.PendingDeletes) > 0
}
func quantityLedgerIntroducesWork(oldLedger, newLedger *capsulev1beta2.QuantityLedger) bool {
matchedReservations := make([]bool, len(oldLedger.Status.Reservations))
for _, newReservation := range newLedger.Status.Reservations {
matched := false
for i, oldReservation := range oldLedger.Status.Reservations {
if matchedReservations[i] || !reflect.DeepEqual(oldReservation, newReservation) {
continue
}
matchedReservations[i] = true
matched = true
break
}
if !matched {
return true
}
}
matchedPendingDeletes := make([]bool, len(oldLedger.Status.PendingDeletes))
for _, newPendingDelete := range newLedger.Status.PendingDeletes {
matched := false
for i, oldPendingDelete := range oldLedger.Status.PendingDeletes {
if matchedPendingDeletes[i] || !reflect.DeepEqual(oldPendingDelete, newPendingDelete) {
continue
}
matchedPendingDeletes[i] = true
matched = true
break
}
if !matched {
return true
}
}
return false
}
type ProvisionerSubjectsChangedPredicate struct{ predicate.Funcs }
func (ProvisionerSubjectsChangedPredicate) Create(event.CreateEvent) bool { return true }
func (ProvisionerSubjectsChangedPredicate) Delete(event.DeleteEvent) bool { return false }
func (ProvisionerSubjectsChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (ProvisionerSubjectsChangedPredicate) Update(e event.UpdateEvent) bool {
oldConfig, oldOK := e.ObjectOld.(*capsulev1beta2.CapsuleConfiguration)
newConfig, newOK := e.ObjectNew.(*capsulev1beta2.CapsuleConfiguration)
if !oldOK || !newOK {
return false
}
return !reflect.DeepEqual(oldConfig.Spec.Administrators, newConfig.Spec.Administrators) ||
!reflect.DeepEqual(oldConfig.Status.Users, newConfig.Status.Users) ||
oldConfig.Spec.AllowServiceAccountPromotion != newConfig.Spec.AllowServiceAccountPromotion ||
!reflect.DeepEqual(oldConfig.Spec.RBAC, newConfig.Spec.RBAC)
}
type ResourcePoolNamespacesChangedPredicate struct{ predicate.Funcs }
func (ResourcePoolNamespacesChangedPredicate) Create(event.CreateEvent) bool { return true }
func (ResourcePoolNamespacesChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (ResourcePoolNamespacesChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (ResourcePoolNamespacesChangedPredicate) Update(e event.UpdateEvent) bool {
oldPool, oldOK := e.ObjectOld.(*capsulev1beta2.ResourcePool)
newPool, newOK := e.ObjectNew.(*capsulev1beta2.ResourcePool)
if !oldOK || !newOK {
return false
}
return !reflect.DeepEqual(oldPool.Status.Namespaces, newPool.Status.Namespaces) ||
(oldPool.DeletionTimestamp == nil) != (newPool.DeletionTimestamp == nil)
}
// ResourceQuotaUsageChangedPredicate admits only usage changes from the quota
// controller. ResourcePool claim Bound conditions are derived from status.used,
// while status.hard and other status updates do not affect claim scheduling.
type ResourceQuotaUsageChangedPredicate struct{ predicate.Funcs }
func (ResourceQuotaUsageChangedPredicate) Create(event.CreateEvent) bool { return false }
func (ResourceQuotaUsageChangedPredicate) Delete(event.DeleteEvent) bool { return false }
func (ResourceQuotaUsageChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (ResourceQuotaUsageChangedPredicate) Update(e event.UpdateEvent) bool {
oldQuota, oldOK := e.ObjectOld.(*corev1.ResourceQuota)
newQuota, newOK := e.ObjectNew.(*corev1.ResourceQuota)
if !oldOK || !newOK {
return false
}
return !reflect.DeepEqual(oldQuota.Status.Used, newQuota.Status.Used)
}
type DependencyStateChangedPredicate struct{ predicate.Funcs }
func (DependencyStateChangedPredicate) Create(event.CreateEvent) bool { return true }
func (DependencyStateChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (DependencyStateChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (DependencyStateChangedPredicate) Update(e event.UpdateEvent) bool {
if e.ObjectOld == nil || e.ObjectNew == nil {
return false
}
return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() ||
(e.ObjectOld.GetDeletionTimestamp() == nil) != (e.ObjectNew.GetDeletionTimestamp() == nil) ||
!reflect.DeepEqual(resourceReadyCondition(e.ObjectOld), resourceReadyCondition(e.ObjectNew))
}
type TenantSelectionChangedPredicate struct{ predicate.Funcs }
func (TenantSelectionChangedPredicate) Create(event.CreateEvent) bool { return true }
func (TenantSelectionChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (TenantSelectionChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (TenantSelectionChangedPredicate) Update(e event.UpdateEvent) bool {
oldTenant, oldOK := e.ObjectOld.(*capsulev1beta2.Tenant)
newTenant, newOK := e.ObjectNew.(*capsulev1beta2.Tenant)
if !oldOK || !newOK {
return false
}
return !utils.MapEqual(oldTenant.Labels, newTenant.Labels) ||
!reflect.DeepEqual(oldTenant.Status.Namespaces, newTenant.Status.Namespaces) ||
(oldTenant.DeletionTimestamp == nil) != (newTenant.DeletionTimestamp == nil)
}
type TenantPodOptionsChangedPredicate struct{ predicate.Funcs }
func (TenantPodOptionsChangedPredicate) Create(event.CreateEvent) bool { return false }
func (TenantPodOptionsChangedPredicate) Delete(event.DeleteEvent) bool { return false }
func (TenantPodOptionsChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (TenantPodOptionsChangedPredicate) Update(e event.UpdateEvent) bool {
oldTenant, oldOK := e.ObjectOld.(*capsulev1beta2.Tenant)
newTenant, newOK := e.ObjectNew.(*capsulev1beta2.Tenant)
return oldOK && newOK && !reflect.DeepEqual(oldTenant.Spec.PodOptions, newTenant.Spec.PodOptions)
}
type TenantServiceOptionsChangedPredicate struct{ predicate.Funcs }
func (TenantServiceOptionsChangedPredicate) Create(event.CreateEvent) bool { return false }
func (TenantServiceOptionsChangedPredicate) Delete(event.DeleteEvent) bool { return false }
func (TenantServiceOptionsChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (TenantServiceOptionsChangedPredicate) Update(e event.UpdateEvent) bool {
oldTenant, oldOK := e.ObjectOld.(*capsulev1beta2.Tenant)
newTenant, newOK := e.ObjectNew.(*capsulev1beta2.Tenant)
return oldOK && newOK && !reflect.DeepEqual(oldTenant.Spec.ServiceOptions, newTenant.Spec.ServiceOptions)
}
type TenantNamespacesChangedPredicate struct{ predicate.Funcs }
func (TenantNamespacesChangedPredicate) Create(event.CreateEvent) bool { return true }
func (TenantNamespacesChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (TenantNamespacesChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (TenantNamespacesChangedPredicate) Update(e event.UpdateEvent) bool {
oldTenant, oldOK := e.ObjectOld.(*capsulev1beta2.Tenant)
newTenant, newOK := e.ObjectNew.(*capsulev1beta2.Tenant)
return oldOK && newOK && !reflect.DeepEqual(oldTenant.Status.Namespaces, newTenant.Status.Namespaces)
}
type NamespaceMetadataChangedPredicate struct{ predicate.Funcs }
func (NamespaceMetadataChangedPredicate) Create(event.CreateEvent) bool { return true }
func (NamespaceMetadataChangedPredicate) Delete(event.DeleteEvent) bool { return true }
func (NamespaceMetadataChangedPredicate) Generic(event.GenericEvent) bool { return false }
func (NamespaceMetadataChangedPredicate) Update(e event.UpdateEvent) bool {
oldNamespace, oldOK := e.ObjectOld.(*corev1.Namespace)
newNamespace, newOK := e.ObjectNew.(*corev1.Namespace)
return oldOK && newOK && (!reflect.DeepEqual(oldNamespace.Labels, newNamespace.Labels) ||
!reflect.DeepEqual(oldNamespace.Annotations, newNamespace.Annotations))
}
func resourceReadyCondition(obj any) any {
switch typed := obj.(type) {
case *capsulev1beta2.GlobalTenantResource:
return typed.Status.Conditions.GetConditionByType(capmeta.ReadyCondition)
case *capsulev1beta2.TenantResource:
return typed.Status.Conditions.GetConditionByType(capmeta.ReadyCondition)
default:
return nil
}
}