5
5
"encoding/json"
6
6
"errors"
7
7
"fmt"
8
+ "reflect"
8
9
"sync"
9
10
"time"
10
11
@@ -14,6 +15,7 @@ import (
14
15
corev1 "k8s.io/api/core/v1"
15
16
rbacv1 "k8s.io/api/rbac/v1"
16
17
v1beta1ext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
18
+ extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions"
17
19
k8serrors "k8s.io/apimachinery/pkg/api/errors"
18
20
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
21
"k8s.io/apimachinery/pkg/labels"
@@ -32,6 +34,7 @@ import (
32
34
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription"
33
35
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler"
34
36
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
37
+ index "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/index"
35
38
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
36
39
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
37
40
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
@@ -56,21 +59,22 @@ const (
56
59
type Operator struct {
57
60
queueinformer.Operator
58
61
59
- logger * logrus.Logger
60
- clock utilclock.Clock
61
- opClient operatorclient.ClientInterface
62
- client versioned.Interface
63
- lister operatorlister.OperatorLister
64
- catsrcQueueSet * queueinformer.ResourceQueueSet
65
- subQueueSet * queueinformer.ResourceQueueSet
66
- ipQueueSet * queueinformer.ResourceQueueSet
67
- nsResolveQueue workqueue.RateLimitingInterface
68
- namespace string
69
- sources map [resolver.CatalogKey ]resolver.SourceRef
70
- sourcesLock sync.RWMutex
71
- sourcesLastUpdate metav1.Time
72
- resolver resolver.Resolver
73
- reconciler reconciler.RegistryReconcilerFactory
62
+ logger * logrus.Logger
63
+ clock utilclock.Clock
64
+ opClient operatorclient.ClientInterface
65
+ client versioned.Interface
66
+ lister operatorlister.OperatorLister
67
+ catsrcQueueSet * queueinformer.ResourceQueueSet
68
+ subQueueSet * queueinformer.ResourceQueueSet
69
+ ipQueueSet * queueinformer.ResourceQueueSet
70
+ nsResolveQueue workqueue.RateLimitingInterface
71
+ namespace string
72
+ sources map [resolver.CatalogKey ]resolver.SourceRef
73
+ sourcesLock sync.RWMutex
74
+ sourcesLastUpdate metav1.Time
75
+ resolver resolver.Resolver
76
+ reconciler reconciler.RegistryReconcilerFactory
77
+ csvProvidedAPIsIndexer map [string ]cache.Indexer
74
78
}
75
79
76
80
// NewOperator creates a new Catalog Operator.
@@ -98,17 +102,18 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
98
102
99
103
// Allocate the new instance of an Operator.
100
104
op := & Operator {
101
- Operator : queueOperator ,
102
- logger : logger ,
103
- clock : clock ,
104
- opClient : opClient ,
105
- client : crClient ,
106
- lister : lister ,
107
- namespace : operatorNamespace ,
108
- sources : make (map [resolver.CatalogKey ]resolver.SourceRef ),
109
- resolver : resolver .NewOperatorsV1alpha1Resolver (lister ),
110
- catsrcQueueSet : queueinformer .NewEmptyResourceQueueSet (),
111
- subQueueSet : queueinformer .NewEmptyResourceQueueSet (),
105
+ Operator : queueOperator ,
106
+ logger : logger ,
107
+ clock : clock ,
108
+ opClient : opClient ,
109
+ client : crClient ,
110
+ lister : lister ,
111
+ namespace : operatorNamespace ,
112
+ sources : make (map [resolver.CatalogKey ]resolver.SourceRef ),
113
+ resolver : resolver .NewOperatorsV1alpha1Resolver (lister ),
114
+ catsrcQueueSet : queueinformer .NewEmptyResourceQueueSet (),
115
+ subQueueSet : queueinformer .NewEmptyResourceQueueSet (),
116
+ csvProvidedAPIsIndexer : map [string ]cache.Indexer {},
112
117
}
113
118
op .reconciler = reconciler .NewRegistryReconcilerFactory (lister , opClient , configmapRegistryImage , op .now )
114
119
@@ -122,6 +127,10 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
122
127
op .lister .OperatorsV1alpha1 ().RegisterClusterServiceVersionLister (namespace , csvInformer .Lister ())
123
128
op .RegisterInformer (csvInformer .Informer ())
124
129
130
+ csvInformer .Informer ().AddIndexers (cache.Indexers {index .ProvidedAPIsIndexFuncKey : index .ProvidedAPIsIndexFunc })
131
+ csvIndexer := csvInformer .Informer ().GetIndexer ()
132
+ op .csvProvidedAPIsIndexer [namespace ] = csvIndexer
133
+
125
134
// TODO: Add namespace resolve sync
126
135
127
136
// Wire InstallPlans
@@ -244,6 +253,20 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
244
253
245
254
}
246
255
256
+ // Register CustomResourceDefinition QueueInformer
257
+ crdInformer := extinf .NewSharedInformerFactory (op .opClient .ApiextensionsV1beta1Interface (), resyncPeriod ).Apiextensions ().V1beta1 ().CustomResourceDefinitions ()
258
+ op .lister .APIExtensionsV1beta1 ().RegisterCustomResourceDefinitionLister (crdInformer .Lister ())
259
+ crdQueueInformer , err := queueinformer .NewQueueInformer (
260
+ ctx ,
261
+ queueinformer .WithLogger (op .logger ),
262
+ queueinformer .WithInformer (crdInformer .Informer ()),
263
+ queueinformer .WithSyncer (queueinformer .LegacySyncHandler (op .syncObject ).ToSyncerWithDelete (op .handleDeletion )),
264
+ )
265
+ if err != nil {
266
+ return nil , err
267
+ }
268
+ op .RegisterQueueInformer (crdQueueInformer )
269
+
247
270
// Namespace sync for resolving subscriptions
248
271
namespaceInformer := informers .NewSharedInformerFactory (op .opClient .KubernetesInterface (), resyncPeriod ).Core ().V1 ().Namespaces ()
249
272
op .lister .CoreV1 ().RegisterNamespaceLister (namespaceInformer .Lister ())
@@ -1034,6 +1057,25 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
1034
1057
// Attempt to create the CRD.
1035
1058
_ , err = o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Create (& crd )
1036
1059
if k8serrors .IsAlreadyExists (err ) {
1060
+ currentCRD , _ := o .lister .APIExtensionsV1beta1 ().CustomResourceDefinitionLister ().Get (crd .GetName ())
1061
+ // Compare 2 CRDs to see if it needs to be updatetd
1062
+ if ! reflect .DeepEqual (crd , * currentCRD ) {
1063
+ // Verify CRD ownership, only attempt to update if
1064
+ // CRD has only one owner
1065
+ // Example: provided=database.coreos.com/v1alpha1/EtcdCluster
1066
+ matchedCSV , err := index .CRDProviderNames (o .csvProvidedAPIsIndexer , crd )
1067
+ if err != nil {
1068
+ return errorwrap .Wrapf (err , "error find matched CSV: %s" , step .Resource .Name )
1069
+ }
1070
+ if len (matchedCSV ) == 1 {
1071
+ // Attempt to update CRD
1072
+ crd .SetResourceVersion (currentCRD .GetResourceVersion ())
1073
+ _ , err = o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Update (& crd )
1074
+ if err != nil {
1075
+ return errorwrap .Wrapf (err , "error update CRD: %s" , step .Resource .Name )
1076
+ }
1077
+ }
1078
+ }
1037
1079
// If it already existed, mark the step as Present.
1038
1080
plan .Status .Plan [i ].Status = v1alpha1 .StepStatusPresent
1039
1081
continue
0 commit comments