@@ -63,32 +63,33 @@ var (
63
63
type Operator struct {
64
64
queueinformer.Operator
65
65
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
92
93
}
93
94
94
95
func NewOperator (ctx context.Context , options ... OperatorOption ) (* Operator , error ) {
@@ -121,30 +122,31 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat
121
122
}
122
123
123
124
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 ,
148
150
}
149
151
150
152
// Set up syncing for namespace-scoped resources
@@ -1299,23 +1301,40 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
1299
1301
return err
1300
1302
}
1301
1303
1302
- // Filter to unique copies
1303
- uniqueCopiedCSVs := map [string ]struct {}{}
1304
+ copiedCSVNamespaces := map [string ]map [string ]struct {}{}
1304
1305
for _ , copiedCSV := range copiedCSVs {
1305
- uniqueCopiedCSVs [copiedCSV .GetName ()] = struct {}{}
1306
+ if _ , ok := copiedCSVNamespaces [copiedCSV .GetName ()]; ! ok {
1307
+ copiedCSVNamespaces [copiedCSV .GetName ()] = map [string ]struct {}{}
1308
+ }
1309
+ copiedCSVNamespaces [copiedCSV .GetName ()][copiedCSV .GetNamespace ()] = struct {}{}
1306
1310
}
1307
1311
1308
1312
csvs , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (og .GetNamespace ()).List (labels .NewSelector ().Add (* nonCopiedCSVRequirement ))
1309
1313
if err != nil {
1310
1314
return err
1311
1315
}
1312
1316
1317
+ namespaces , err := a .lister .CoreV1 ().NamespaceLister ().List (labels .Everything ())
1318
+ if err != nil {
1319
+ return err
1320
+ }
1321
+
1322
+ var copiedCSVEvaluator func (m map [string ]struct {}) bool
1323
+ if olmConfig .CopiedCSVsAreEnabled () {
1324
+ copiedCSVEvaluator = func (m map [string ]struct {}) bool {
1325
+ return areCopiedCSVsAvailableInAllNamespaces (namespaces , m )
1326
+ }
1327
+ } else {
1328
+ copiedCSVEvaluator = func (m map [string ]struct {}) bool {
1329
+ return areCopiedCSVsAvailableOnlyInProtectedNamespaces (a .protectedCopiedCSVNamespaces , m )
1330
+ }
1331
+ }
1332
+
1313
1333
for _ , csv := range csvs {
1314
- // If the correct number of copied CSVs were found, continue
1315
- if _ , ok := uniqueCopiedCSVs [csv .GetName ()]; ok == olmConfig . CopiedCSVsAreEnabled ( ) {
1334
+ // Ignore NS where actual CSV is installed
1335
+ if copiedCSVEvaluator ( copiedCSVNamespaces [csv .GetName ()]) {
1316
1336
continue
1317
1337
}
1318
-
1319
1338
if err := a .csvQueueSet .Requeue (csv .GetNamespace (), csv .GetName ()); err != nil {
1320
1339
a .logger .WithError (err ).Warn ("unable to requeue" )
1321
1340
}
@@ -1324,7 +1343,7 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
1324
1343
}
1325
1344
1326
1345
// Update the olmConfig status if it has changed.
1327
- condition := getCopiedCSVsCondition (! olmConfig .CopiedCSVsAreEnabled (), csvIsRequeued )
1346
+ condition := getCopiedCSVsCondition (olmConfig .CopiedCSVsAreEnabled (), csvIsRequeued )
1328
1347
if ! isStatusConditionPresentAndAreTypeReasonMessageStatusEqual (olmConfig .Status .Conditions , condition ) {
1329
1348
meta .SetStatusCondition (& olmConfig .Status .Conditions , condition )
1330
1349
if _ , err := a .client .OperatorsV1 ().OLMConfigs ().UpdateStatus (context .TODO (), olmConfig , metav1.UpdateOptions {}); err != nil {
@@ -1335,6 +1354,26 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
1335
1354
return nil
1336
1355
}
1337
1356
1357
+ func areCopiedCSVsAvailableInAllNamespaces (namespaces []* corev1.Namespace , m map [string ]struct {}) bool {
1358
+ // Start at -1 to account for the namespace the original CSV is in
1359
+ expectedCopiedCSVCount := - 1
1360
+ for _ , ns := range namespaces {
1361
+ if ns .Status .Phase == corev1 .NamespaceActive {
1362
+ expectedCopiedCSVCount ++
1363
+ }
1364
+ }
1365
+ return len (m ) == expectedCopiedCSVCount
1366
+ }
1367
+
1368
+ func areCopiedCSVsAvailableOnlyInProtectedNamespaces (protectedNamespaces map [string ]struct {}, m map [string ]struct {}) bool {
1369
+ for protectedNS := range protectedNamespaces {
1370
+ if _ , ok := m [protectedNS ]; ! ok {
1371
+ return false
1372
+ }
1373
+ }
1374
+ return true
1375
+ }
1376
+
1338
1377
func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual (conditions []metav1.Condition , condition metav1.Condition ) bool {
1339
1378
foundCondition := meta .FindStatusCondition (conditions , condition .Type )
1340
1379
if foundCondition == nil {
@@ -1346,13 +1385,13 @@ func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(conditions []met
1346
1385
foundCondition .Status == condition .Status
1347
1386
}
1348
1387
1349
- func getCopiedCSVsCondition (isDisabled , csvIsRequeued bool ) metav1.Condition {
1388
+ func getCopiedCSVsCondition (enabled , csvIsRequeued bool ) metav1.Condition {
1350
1389
condition := metav1.Condition {
1351
1390
Type : operatorsv1 .DisabledCopiedCSVsConditionType ,
1352
1391
LastTransitionTime : metav1 .Now (),
1353
1392
Status : metav1 .ConditionFalse ,
1354
1393
}
1355
- if ! isDisabled {
1394
+ if enabled {
1356
1395
condition .Reason = "CopiedCSVsEnabled"
1357
1396
condition .Message = "Copied CSVs are enabled and present across the cluster"
1358
1397
if csvIsRequeued {
@@ -1361,15 +1400,14 @@ func getCopiedCSVsCondition(isDisabled, csvIsRequeued bool) metav1.Condition {
1361
1400
return condition
1362
1401
}
1363
1402
1403
+ condition .Reason = "CopiedCSVsDisabled"
1364
1404
if csvIsRequeued {
1365
- condition .Reason = "CopiedCSVsFound"
1366
- condition .Message = "Copied CSVs are disabled and at least one copied CSV was found for an operator installed in AllNamespace mode"
1405
+ condition .Message = "Copied CSVs are disabled and at least one unexpected copied CSV was found for an operator installed in AllNamespace mode"
1367
1406
return condition
1368
1407
}
1369
1408
1370
1409
condition .Status = metav1 .ConditionTrue
1371
- condition .Reason = "NoCopiedCSVsFound"
1372
- condition .Message = "Copied CSVs are disabled and none were found for operators installed in AllNamespace mode"
1410
+ condition .Message = "Copied CSVs are disabled and no unexpected copied CSVs were found for operators installed in AllNamespace mode"
1373
1411
1374
1412
return condition
1375
1413
}
@@ -1444,7 +1482,25 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
1444
1482
return err
1445
1483
}
1446
1484
1485
+ // Ensure that the Copied CSVs exist in the protected namespaces.
1486
+ protectedNamespaces := []string {}
1487
+ for ns := range a .protectedCopiedCSVNamespaces {
1488
+ if ns == clusterServiceVersion .GetNamespace () {
1489
+ continue
1490
+ }
1491
+ protectedNamespaces = append (protectedNamespaces , ns )
1492
+ }
1493
+
1494
+ if err := a .ensureCSVsInNamespaces (clusterServiceVersion , operatorGroup , NewNamespaceSet (protectedNamespaces )); err != nil {
1495
+ logger .WithError (err ).Info ("couldn't copy CSV to protected Copied CSV namespaces" )
1496
+ syncError = err
1497
+ }
1498
+
1499
+ // Delete Copied CSVs in namespaces that are not protected.
1447
1500
for _ , copiedCSV := range copiedCSVs {
1501
+ if _ , ok := a .protectedCopiedCSVNamespaces [copiedCSV .Namespace ]; ok {
1502
+ continue
1503
+ }
1448
1504
err := a .client .OperatorsV1alpha1 ().ClusterServiceVersions (copiedCSV .Namespace ).Delete (context .TODO (), copiedCSV .Name , metav1.DeleteOptions {})
1449
1505
if err != nil && ! apierrors .IsNotFound (err ) {
1450
1506
return err
0 commit comments