Skip to content

Commit f1e2426

Browse files
committed
feat(object-controller): enable standalone reconciliation atomically
Enable the prepared deployment for BoxcutterRuntime and explicit standalone installs while removing embedded ClusterObjectSet reconciliation. Switch CRD enablement in the same change, reject disabling the new controller with BoxcutterRuntime, and include generated manifests and chart/PDB tests. Refs: OPRUN-4775 Signed-off-by: Fabricio Aguiar <fabricio.aguiar@gmail.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent b809308 commit f1e2426

8 files changed

Lines changed: 923 additions & 89 deletions

File tree

‎cmd/operator-controller/main.go‎

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,12 @@ import (
3030

3131
"github.com/spf13/cobra"
3232
"go.podman.io/image/v5/types"
33-
corev1 "k8s.io/api/core/v1"
3433
rbacv1 "k8s.io/api/rbac/v1"
3534
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3635
apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
3736
k8slabels "k8s.io/apimachinery/pkg/labels"
3837
k8stypes "k8s.io/apimachinery/pkg/types"
3938
apimachineryrand "k8s.io/apimachinery/pkg/util/rand"
40-
"k8s.io/client-go/discovery"
41-
"k8s.io/client-go/discovery/cached/memory"
4239
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
4340
_ "k8s.io/client-go/plugin/pkg/client/auth"
4441
"k8s.io/klog/v2"
@@ -61,7 +58,6 @@ import (
6158
helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client"
6259

6360
ocv1 "github.com/operator-framework/operator-controller/api/v1"
64-
clusterobjctrl "github.com/operator-framework/operator-controller/internal/object-controller/controllers"
6561
"github.com/operator-framework/operator-controller/internal/operator-controller/action"
6662
"github.com/operator-framework/operator-controller/internal/operator-controller/applier"
6763
"github.com/operator-framework/operator-controller/internal/operator-controller/catalogmetadata/cache"
@@ -119,7 +115,6 @@ type boxcutterReconcilerConfigurator struct {
119115
imageCache imageutil.Cache
120116
imagePuller imageutil.Puller
121117
finalizers crfinalizer.Finalizers
122-
trackingCache managedcache.TrackingCache
123118
}
124119

125120
type helmReconcilerConfigurator struct {
@@ -461,26 +456,22 @@ func run() error {
461456
crdupgradesafety.NewPreflight(aeClient.CustomResourceDefinitions()),
462457
}
463458

464-
trackingCache, err := managedcache.NewTrackingCache(
465-
ctrl.Log.WithName("trackingCache"),
466-
mgr.GetConfig(),
467-
crcache.Options{
468-
Scheme: mgr.GetScheme(), Mapper: mgr.GetRESTMapper(),
469-
},
470-
)
471-
if err != nil {
472-
setupLog.Error(err, "unable to create tracking cache")
473-
return err
474-
}
475-
if err := mgr.Add(trackingCache); err != nil {
476-
setupLog.Error(err, "unable to add tracking cache to manager")
477-
return err
478-
}
479-
459+
var trackingCache managedcache.TrackingCache
480460
var ctrlBuilderOpts []controllers.ControllerBuilderOption
481461
if features.OperatorControllerFeatureGate.Enabled(features.BoxcutterRuntime) {
482462
ctrlBuilderOpts = append(ctrlBuilderOpts, controllers.WithOwns(&ocv1.ClusterObjectSet{}))
483463
} else {
464+
trackingCache, err = managedcache.NewTrackingCache(
465+
ctrl.Log.WithName("trackingCache"),
466+
mgr.GetConfig(),
467+
crcache.Options{Scheme: mgr.GetScheme(), Mapper: mgr.GetRESTMapper()},
468+
)
469+
if err != nil {
470+
return fmt.Errorf("unable to create tracking cache: %w", err)
471+
}
472+
if err := mgr.Add(trackingCache); err != nil {
473+
return fmt.Errorf("unable to add tracking cache to manager: %w", err)
474+
}
484475
ctrlBuilderOpts = append(ctrlBuilderOpts, controllers.WithWatchesRawSource(
485476
trackingCache.Source(
486477
crhandler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &ocv1.ClusterExtension{}),
@@ -520,7 +511,6 @@ func run() error {
520511
imageCache: imageCache,
521512
imagePuller: imagePuller,
522513
finalizers: clusterExtensionFinalizers,
523-
trackingCache: trackingCache,
524514
}
525515
} else {
526516
cerCfg = &helmReconcilerConfigurator{
@@ -665,38 +655,6 @@ func (c *boxcutterReconcilerConfigurator) Configure(ceReconciler *controllers.Cl
665655
controllers.ApplyBundleWithBoxcutter(appl.Apply),
666656
}
667657

668-
baseDiscoveryClient, err := discovery.NewDiscoveryClientForConfig(c.mgr.GetConfig())
669-
if err != nil {
670-
return fmt.Errorf("unable to create discovery client: %w", err)
671-
}
672-
673-
// Wrap the discovery client with caching to reduce memory usage from repeated OpenAPI schema fetches
674-
discoveryClient := memory.NewMemCacheClient(baseDiscoveryClient)
675-
676-
revisionEngineFactory, err := clusterobjctrl.NewDefaultRevisionEngineFactory(
677-
c.mgr.GetScheme(),
678-
c.trackingCache,
679-
discoveryClient,
680-
c.mgr.GetRESTMapper(),
681-
fieldOwnerPrefix,
682-
c.mgr.GetConfig(),
683-
)
684-
if err != nil {
685-
return fmt.Errorf("unable to create revision engine factory: %w", err)
686-
}
687-
688-
cosClient := &secretFallbackClient{
689-
Client: c.mgr.GetClient(),
690-
apiReader: c.mgr.GetAPIReader(),
691-
systemNamespace: cfg.systemNamespace,
692-
}
693-
if err = (&clusterobjctrl.ClusterObjectSetReconciler{
694-
Client: cosClient,
695-
RevisionEngineFactory: revisionEngineFactory,
696-
TrackingCache: c.trackingCache,
697-
}).SetupWithManager(c.mgr); err != nil {
698-
return fmt.Errorf("unable to setup ClusterObjectSet controller: %w", err)
699-
}
700658
return nil
701659
}
702660

@@ -761,18 +719,3 @@ func main() {
761719
os.Exit(1)
762720
}
763721
}
764-
765-
// secretFallbackClient wraps a cached client.Client and falls back to direct
766-
// API reads for Secrets outside the system namespace, where the cache does not watch.
767-
type secretFallbackClient struct {
768-
client.Client
769-
apiReader client.Reader
770-
systemNamespace string
771-
}
772-
773-
func (c *secretFallbackClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
774-
if _, isSecret := obj.(*corev1.Secret); isSecret && key.Namespace != c.systemNamespace {
775-
return c.apiReader.Get(ctx, key, obj, opts...)
776-
}
777-
return c.Client.Get(ctx, key, obj, opts...)
778-
}

‎helm/experimental.yaml‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# experimental values for OLMv1.
22
# This is a YAML-formatted file.
33
# Declare variables to be passed into your templates.
4-
54
# List of enabled experimental features for operator-controller
65
# Use with {{- if has "FeatureGate" .Values.options.operatorController.features.enabled }}
76
# to pull in resources or additions
87
options:
8+
objectController:
9+
deployment:
10+
replicas: 2
911
operatorController:
1012
deployment:
1113
replicas: 2
@@ -18,9 +20,9 @@ options:
1820
- WebhookProviderCertManager
1921
disabled:
2022
- WebhookProviderOpenshiftServiceCA
21-
# List of enabled experimental features for catalogd
22-
# Use with {{- if has "FeatureGate" .Values.options.catalogd.features.enabled }}
23-
# to pull in resources or additions
23+
# List of enabled experimental features for catalogd
24+
# Use with {{- if has "FeatureGate" .Values.options.catalogd.features.enabled }}
25+
# to pull in resources or additions
2426
catalogd:
2527
deployment:
2628
replicas: 2
@@ -29,5 +31,5 @@ options:
2931
- APIV1MetasHandler
3032
- GraphQLCatalogQueries
3133
disabled: []
32-
# This can be one of: standard or experimental
34+
# This can be one of: standard or experimental
3335
featureSet: experimental

‎helm/olmv1/templates/_helpers.tpl‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,30 @@ olmv1
5959
{{- end -}}
6060

6161
{{/*
62-
Prepare component resources without enabling a second ClusterObjectSet reconciler.
63-
The deployment and reconciliation handover will replace this activation guard.
62+
Default to a separate object-controller whenever operator-controller uses Boxcutter.
63+
An explicit enabled value also permits installing object-controller on its own.
64+
Disabling it while Boxcutter is active would leave ClusterObjectSets without a controller.
65+
Return an empty string when disabled so the helper can be used in conditionals.
6466
*/}}
6567
{{- define "objectController.enabled" -}}
66-
{{- if hasKey .Values.options "objectController" -}}
67-
{{- if .Values.options.objectController.enabled -}}
68-
{{- fail "object-controller deployment support requires the reconciliation cutover" -}}
68+
{{- $operatorController := .Values.options.operatorController | default dict -}}
69+
{{- $features := $operatorController.features | default dict -}}
70+
{{- if and $operatorController.enabled (has "BoxcutterRuntime" $features.enabled) (has "BoxcutterRuntime" $features.disabled) -}}
71+
{{- fail "BoxcutterRuntime cannot appear in both options.operatorController.features.enabled and options.operatorController.features.disabled" -}}
6972
{{- end -}}
73+
{{- $boxcutterEnabled := and $operatorController.enabled (has "BoxcutterRuntime" $features.enabled) (not (has "BoxcutterRuntime" $features.disabled)) -}}
74+
{{- if and $boxcutterEnabled (eq (toJson .Values.options.objectController.enabled) "false") -}}
75+
{{- fail "options.objectController.enabled=false is incompatible with enabled BoxcutterRuntime" -}}
76+
{{- end -}}
77+
{{- $enabled := .Values.options.objectController.enabled -}}
78+
{{- if eq (toJson $enabled) "null" -}}
79+
{{- $enabled = $boxcutterEnabled -}}
80+
{{- end -}}
81+
{{- if $enabled -}}
82+
{{- if ne .Values.options.featureSet "experimental" -}}
83+
{{- fail "objectController requires options.featureSet=experimental" -}}
84+
{{- end -}}
85+
true
7086
{{- end -}}
7187
{{- end -}}
7288

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
{{- if .Values.options.operatorController.enabled }}
2-
{{- if (eq .Values.options.featureSet "standard") }}
3-
{{- /* Add when GA: tpl (.Files.Get "base/object-controller/crd/standard/olm.operatorframework.io_clusterobjectsetss.yaml") . */}}
4-
{{- else if (eq .Values.options.featureSet "experimental") }}
5-
{{- if has "BoxcutterRuntime" .Values.options.operatorController.features.enabled }}
1+
{{- if include "objectController.enabled" . }}
62
{{ tpl (.Files.Get "base/object-controller/crd/experimental/olm.operatorframework.io_clusterobjectsets.yaml") . }}
73
{{- end }}
8-
{{- else }}
9-
{{- fail "options.featureSet must be set to one of: {standard,experimental}" }}
10-
{{- end }}
11-
{{- end }}

‎helm/olmv1/values.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# List of components to include
55
options:
66
objectController:
7-
# Activation is reserved until the deployment and reconciliation cutover.
7+
# null follows operatorController's BoxcutterRuntime gate. Set true to deploy independently.
88
enabled: null
99
deployment:
1010
image: quay.io/operator-framework/object-controller:devel

0 commit comments

Comments
 (0)