From 92ba23a7fb6bafe5960f11ac2ed2c45846307ac0 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Thu, 29 Oct 2026 17:03:45 -0400 Subject: [PATCH] Tighten operator-controller caching Reduce retained Boxcutter cache data while preserving objects needed for revision discovery, ownership checks, and storage migration. Co-Authored-By: GPT-6 Luna --- cmd/operator-controller/main.go | 76 +++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/cmd/operator-controller/main.go b/cmd/operator-controller/main.go index 98461c743f..319d6e7c29 100644 --- a/cmd/operator-controller/main.go +++ b/cmd/operator-controller/main.go @@ -30,10 +30,10 @@ import ( "github.com/spf13/cobra" "go.podman.io/image/v5/types" - rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" k8slabels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" k8stypes "k8s.io/apimachinery/pkg/types" apimachineryrand "k8s.io/apimachinery/pkg/util/rand" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" @@ -70,6 +70,7 @@ import ( "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render/registryv1" "github.com/operator-framework/operator-controller/internal/operator-controller/scheme" sharedcontrollers "github.com/operator-framework/operator-controller/internal/shared/controllers" + "github.com/operator-framework/operator-controller/internal/shared/labels" cacheutil "github.com/operator-framework/operator-controller/internal/shared/util/cache" fsutil "github.com/operator-framework/operator-controller/internal/shared/util/fs" httputil "github.com/operator-framework/operator-controller/internal/shared/util/http" @@ -237,27 +238,9 @@ func run() error { } setupLog.Info("set up manager") - cacheOptions := crcache.Options{ - ByObject: map[client.Object]crcache.ByObject{ - &ocv1.ClusterExtension{}: {Label: k8slabels.Everything()}, - &ocv1.ClusterCatalog{}: {Label: k8slabels.Everything()}, - &rbacv1.ClusterRole{}: {Label: k8slabels.Everything()}, - &rbacv1.ClusterRoleBinding{}: {Label: k8slabels.Everything()}, - &rbacv1.Role{}: {Namespaces: map[string]crcache.Config{}, Label: k8slabels.Everything()}, - &rbacv1.RoleBinding{}: {Namespaces: map[string]crcache.Config{}, Label: k8slabels.Everything()}, - }, - DefaultNamespaces: map[string]crcache.Config{ - cfg.systemNamespace: {LabelSelector: k8slabels.Everything()}, - }, - DefaultLabelSelector: k8slabels.Nothing(), - // Memory optimization: strip managed fields and large annotations from cached objects - DefaultTransform: cacheutil.StripAnnotations(), - } - - if features.OperatorControllerFeatureGate.Enabled(features.BoxcutterRuntime) { - cacheOptions.ByObject[&ocv1.ClusterObjectSet{}] = crcache.ByObject{ - Label: k8slabels.Everything(), - } + cacheOptions, err := newCacheOptions(cfg.systemNamespace, features.OperatorControllerFeatureGate.Enabled(features.BoxcutterRuntime)) + if err != nil { + return fmt.Errorf("configuring manager cache: %w", err) } saKey, err := sautil.GetServiceAccount() @@ -566,6 +549,55 @@ func run() error { return nil } +// newCacheOptions configures operator-controller's view of extension resources. +// The object-controller must retain full CODs and COSs regardless of OLM labels. +func newCacheOptions(systemNamespace string, boxcutterRuntime bool) (crcache.Options, error) { + options := crcache.Options{ + ByObject: map[client.Object]crcache.ByObject{ + &ocv1.ClusterExtension{}: {Label: k8slabels.Everything()}, + &ocv1.ClusterCatalog{}: {Label: k8slabels.Everything()}, + }, + DefaultNamespaces: map[string]crcache.Config{ + systemNamespace: {LabelSelector: k8slabels.Everything()}, + }, + DefaultLabelSelector: k8slabels.Nothing(), + DefaultTransform: cacheutil.StripAnnotations(), + } + if !boxcutterRuntime { + return options, nil + } + + ownerName, err := k8slabels.NewRequirement(labels.OwnerNameKey, selection.Exists, nil) + if err != nil { + return crcache.Options{}, err + } + options.ByObject[&ocv1.ClusterObjectSet{}] = crcache.ByObject{ + // Generated revisions inherit OwnerName from the COD template. Migrated + // Helm revisions also carry it. Keep their spec, status and annotations + // for group indexing, revision discovery and storage migration. + Label: k8slabels.NewSelector().Add(*ownerName), + } + options.ByObject[&ocv1.ClusterObjectDeployment{}] = crcache.ByObject{ + // Keep unlabeled deployments visible to name-based reads and ownership + // checks, without retaining their unrelated template and rollout status. + Label: k8slabels.Everything(), + Transform: transformClusterObjectDeployment, + } + return options, nil +} + +func transformClusterObjectDeployment(obj any) (any, error) { + if cod, ok := obj.(*ocv1.ClusterObjectDeployment); ok { + if _, hasOwnerName := cod.Labels[labels.OwnerNameKey]; !hasOwnerName { + cod.Spec = ocv1.ClusterObjectDeploymentSpec{} + cod.Status = ocv1.ClusterObjectDeploymentStatus{} + } + } + // A per-object transform replaces DefaultTransform rather than composing + // with it. Preserve the existing annotation stripping for all deployments. + return cacheutil.StripAnnotations()(obj) +} + func getCertificateProvider() render.CertificateProvider { if features.OperatorControllerFeatureGate.Enabled(features.WebhookProviderCertManager) { return certproviders.CertManagerCertificateProvider{}