Skip to content

Commit e1dcc94

Browse files
committed
Introduce protectedCopiedCSVNamespaces flag
Problem: Users rely on Copied CSVs in order to understand which operators are available in a given namespace. When installing All Namespace operators, a Copied CSV is created in every namespace which can place a huge performance strain on clusters with many namespaces. OLM introduced the ability to disable Copied CSVs for All Namespace mode operators in an effort to resolve the performance issues on large clusters, unfortunately removing the ability for users to identify which operators are available in a given namepsace. Solution: The protectedCopiedCSVNamespaces runtime flag can be used to prevent Copied CSVs from being deleted even when Copied CSVs are disabled. An admin can then provide users with the proper RBAC to view which operators are running in All Namespace mode. Signed-off-by: Alexander Greene <[email protected]>
1 parent 0b7970c commit e1dcc94

File tree

3 files changed

+92
-62
lines changed

3 files changed

+92
-62
lines changed

Diff for: cmd/olm/main.go

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ var (
6060
tlsKeyPath = pflag.String(
6161
"tls-key", "", "Path to use for private key (requires tls-cert)")
6262

63+
protectedCopiedCSVNamespaces = pflag.String("protectedCopiedCSVNamespaces",
64+
"", "A set of namespaces where global Copied CSVs will always appear, even if disabled")
65+
6366
tlsCertPath = pflag.String(
6467
"tls-cert", "", "Path to use for certificate key (requires tls-key)")
6568

Diff for: pkg/controller/operators/olm/config.go

+27-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package olm
22

33
import (
4+
"strings"
45
"time"
56

67
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
@@ -21,18 +22,19 @@ import (
2122
type OperatorOption func(*operatorConfig)
2223

2324
type operatorConfig struct {
24-
resyncPeriod func() time.Duration
25-
operatorNamespace string
26-
watchedNamespaces []string
27-
clock utilclock.Clock
28-
logger *logrus.Logger
29-
operatorClient operatorclient.ClientInterface
30-
externalClient versioned.Interface
31-
strategyResolver install.StrategyResolverInterface
32-
apiReconciler APIIntersectionReconciler
33-
apiLabeler labeler.Labeler
34-
restConfig *rest.Config
35-
configClient configv1client.Interface
25+
protectedCopiedCSVNamespaces map[string]struct{}
26+
resyncPeriod func() time.Duration
27+
operatorNamespace string
28+
watchedNamespaces []string
29+
clock utilclock.Clock
30+
logger *logrus.Logger
31+
operatorClient operatorclient.ClientInterface
32+
externalClient versioned.Interface
33+
strategyResolver install.StrategyResolverInterface
34+
apiReconciler APIIntersectionReconciler
35+
apiLabeler labeler.Labeler
36+
restConfig *rest.Config
37+
configClient configv1client.Interface
3638
}
3739

3840
func (o *operatorConfig) apply(options []OperatorOption) {
@@ -112,6 +114,19 @@ func WithLogger(logger *logrus.Logger) OperatorOption {
112114
}
113115
}
114116

117+
func WithProtectedCopiedCSVNamespaces(namespaces *string) OperatorOption {
118+
return func(config *operatorConfig) {
119+
config.protectedCopiedCSVNamespaces = map[string]struct{}{}
120+
if namespaces == nil {
121+
return
122+
}
123+
124+
for _, ns := range strings.Split(*namespaces, ",") {
125+
config.protectedCopiedCSVNamespaces[ns] = struct{}{}
126+
}
127+
}
128+
}
129+
115130
func WithClock(clock utilclock.Clock) OperatorOption {
116131
return func(config *operatorConfig) {
117132
config.clock = clock

Diff for: pkg/controller/operators/olm/operator.go

+62-50
Original file line numberDiff line numberDiff line change
@@ -63,32 +63,33 @@ var (
6363
type Operator struct {
6464
queueinformer.Operator
6565

66-
clock utilclock.Clock
67-
logger *logrus.Logger
68-
opClient operatorclient.ClientInterface
69-
client versioned.Interface
70-
lister operatorlister.OperatorLister
71-
copiedCSVLister operatorsv1alpha1listers.ClusterServiceVersionLister
72-
ogQueueSet *queueinformer.ResourceQueueSet
73-
csvQueueSet *queueinformer.ResourceQueueSet
74-
olmConfigQueue workqueue.RateLimitingInterface
75-
csvCopyQueueSet *queueinformer.ResourceQueueSet
76-
copiedCSVGCQueueSet *queueinformer.ResourceQueueSet
77-
objGCQueueSet *queueinformer.ResourceQueueSet
78-
nsQueueSet workqueue.RateLimitingInterface
79-
apiServiceQueue workqueue.RateLimitingInterface
80-
csvIndexers map[string]cache.Indexer
81-
recorder record.EventRecorder
82-
resolver install.StrategyResolverInterface
83-
apiReconciler APIIntersectionReconciler
84-
apiLabeler labeler.Labeler
85-
csvSetGenerator csvutility.SetGenerator
86-
csvReplaceFinder csvutility.ReplaceFinder
87-
csvNotification csvutility.WatchNotification
88-
serviceAccountSyncer *scoped.UserDefinedServiceAccountSyncer
89-
clientAttenuator *scoped.ClientAttenuator
90-
serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier
91-
clientFactory clients.Factory
66+
clock utilclock.Clock
67+
logger *logrus.Logger
68+
opClient operatorclient.ClientInterface
69+
client versioned.Interface
70+
lister operatorlister.OperatorLister
71+
protectedCopiedCSVNamespaces map[string]struct{}
72+
copiedCSVLister operatorsv1alpha1listers.ClusterServiceVersionLister
73+
ogQueueSet *queueinformer.ResourceQueueSet
74+
csvQueueSet *queueinformer.ResourceQueueSet
75+
olmConfigQueue workqueue.RateLimitingInterface
76+
csvCopyQueueSet *queueinformer.ResourceQueueSet
77+
copiedCSVGCQueueSet *queueinformer.ResourceQueueSet
78+
objGCQueueSet *queueinformer.ResourceQueueSet
79+
nsQueueSet workqueue.RateLimitingInterface
80+
apiServiceQueue workqueue.RateLimitingInterface
81+
csvIndexers map[string]cache.Indexer
82+
recorder record.EventRecorder
83+
resolver install.StrategyResolverInterface
84+
apiReconciler APIIntersectionReconciler
85+
apiLabeler labeler.Labeler
86+
csvSetGenerator csvutility.SetGenerator
87+
csvReplaceFinder csvutility.ReplaceFinder
88+
csvNotification csvutility.WatchNotification
89+
serviceAccountSyncer *scoped.UserDefinedServiceAccountSyncer
90+
clientAttenuator *scoped.ClientAttenuator
91+
serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier
92+
clientFactory clients.Factory
9293
}
9394

9495
func NewOperator(ctx context.Context, options ...OperatorOption) (*Operator, error) {
@@ -121,30 +122,31 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat
121122
}
122123

123124
op := &Operator{
124-
Operator: queueOperator,
125-
clock: config.clock,
126-
logger: config.logger,
127-
opClient: config.operatorClient,
128-
client: config.externalClient,
129-
ogQueueSet: queueinformer.NewEmptyResourceQueueSet(),
130-
csvQueueSet: queueinformer.NewEmptyResourceQueueSet(),
131-
olmConfigQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "olmConfig"),
132-
csvCopyQueueSet: queueinformer.NewEmptyResourceQueueSet(),
133-
copiedCSVGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
134-
objGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
135-
apiServiceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "apiservice"),
136-
resolver: config.strategyResolver,
137-
apiReconciler: config.apiReconciler,
138-
lister: lister,
139-
recorder: eventRecorder,
140-
apiLabeler: config.apiLabeler,
141-
csvIndexers: map[string]cache.Indexer{},
142-
csvSetGenerator: csvutility.NewSetGenerator(config.logger, lister),
143-
csvReplaceFinder: csvutility.NewReplaceFinder(config.logger, config.externalClient),
144-
serviceAccountSyncer: scoped.NewUserDefinedServiceAccountSyncer(config.logger, scheme, config.operatorClient, config.externalClient),
145-
clientAttenuator: scoped.NewClientAttenuator(config.logger, config.restConfig, config.operatorClient),
146-
serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(config.logger, config.externalClient),
147-
clientFactory: clients.NewFactory(config.restConfig),
125+
Operator: queueOperator,
126+
clock: config.clock,
127+
logger: config.logger,
128+
opClient: config.operatorClient,
129+
client: config.externalClient,
130+
ogQueueSet: queueinformer.NewEmptyResourceQueueSet(),
131+
csvQueueSet: queueinformer.NewEmptyResourceQueueSet(),
132+
olmConfigQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "olmConfig"),
133+
csvCopyQueueSet: queueinformer.NewEmptyResourceQueueSet(),
134+
copiedCSVGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
135+
objGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
136+
apiServiceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "apiservice"),
137+
resolver: config.strategyResolver,
138+
apiReconciler: config.apiReconciler,
139+
lister: lister,
140+
recorder: eventRecorder,
141+
apiLabeler: config.apiLabeler,
142+
csvIndexers: map[string]cache.Indexer{},
143+
csvSetGenerator: csvutility.NewSetGenerator(config.logger, lister),
144+
csvReplaceFinder: csvutility.NewReplaceFinder(config.logger, config.externalClient),
145+
serviceAccountSyncer: scoped.NewUserDefinedServiceAccountSyncer(config.logger, scheme, config.operatorClient, config.externalClient),
146+
clientAttenuator: scoped.NewClientAttenuator(config.logger, config.restConfig, config.operatorClient),
147+
serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(config.logger, config.externalClient),
148+
clientFactory: clients.NewFactory(config.restConfig),
149+
protectedCopiedCSVNamespaces: config.protectedCopiedCSVNamespaces,
148150
}
149151

150152
// Set up syncing for namespace-scoped resources
@@ -1389,6 +1391,13 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
13891391
"targetNamespaces": strings.Join(operatorGroup.Status.Namespaces, ","),
13901392
}).Debug("copying csv to targets")
13911393

1394+
for ns := range a.protectedCopiedCSVNamespaces {
1395+
if err := a.ensureCSVsInNamespaces(clusterServiceVersion, operatorGroup, NewNamespaceSet([]string{ns})); err != nil {
1396+
logger.WithError(err).Info("couldn't copy CSV to default global operator namespaces")
1397+
syncError = err
1398+
}
1399+
}
1400+
13921401
copiedCSVsAreEnabled, err := a.copiedCSVsAreEnabled()
13931402
if err != nil {
13941403
return err
@@ -1423,6 +1432,9 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
14231432
}
14241433

14251434
for _, copiedCSV := range copiedCSVs {
1435+
if _, ok := a.protectedCopiedCSVNamespaces[copiedCSV.Namespace]; ok {
1436+
continue
1437+
}
14261438
err := a.client.OperatorsV1alpha1().ClusterServiceVersions(copiedCSV.Namespace).Delete(context.TODO(), copiedCSV.Name, metav1.DeleteOptions{})
14271439
if err != nil && !apierrors.IsNotFound(err) {
14281440
return err

0 commit comments

Comments
 (0)