@@ -4,21 +4,22 @@ import (
4
4
"context"
5
5
"fmt"
6
6
7
- "k8s.io/client-go/dynamic "
8
- "k8s.io/client-go/tools/cache "
7
+ "github.com/pkg/errors "
8
+ "github.com/sirupsen/logrus "
9
9
10
- "github.com/operator-framework/api/pkg/operators/v1alpha1"
11
- crdlib "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/crd"
12
- "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
13
- errorwrap "github.com/pkg/errors"
14
- logger "github.com/sirupsen/logrus"
15
10
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
16
11
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
17
12
apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
18
13
apiextensionsv1beta1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
19
-
20
14
k8serrors "k8s.io/apimachinery/pkg/api/errors"
21
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16
+ "k8s.io/client-go/dynamic"
17
+
18
+ "github.com/operator-framework/api/pkg/operators/v1alpha1"
19
+ listersv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
20
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside"
21
+ crdlib "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/crd"
22
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
22
23
)
23
24
24
25
// Stepper manages cluster interactions based on the step.
@@ -36,21 +37,24 @@ func (s StepperFunc) Status() (v1alpha1.StepStatus, error) {
36
37
// Builder holds clients and data structures required for the StepBuilder to work
37
38
// Builder attributes are not to meant to be accessed outside the StepBuilder method
38
39
type builder struct {
39
- opclient operatorclient.ClientInterface
40
- dynamicClient dynamic.Interface
41
- manifestResolver ManifestResolver
42
- csvToProvidedAPIs map [string ]cache.Indexer
43
- logger logger.FieldLogger
40
+ plan * v1alpha1.InstallPlan
41
+ csvLister listersv1alpha1.ClusterServiceVersionLister
42
+ opclient operatorclient.ClientInterface
43
+ dynamicClient dynamic.Interface
44
+ manifestResolver ManifestResolver
45
+ logger logrus.FieldLogger
46
+
47
+ annotator alongside.Annotator
44
48
}
45
49
46
- func newBuilder (opclient operatorclient.ClientInterface , dynamicClient dynamic.Interface , csvToProvidedAPIs map [string ]cache.Indexer ,
47
- manifestResolver ManifestResolver , logger logger.FieldLogger ) * builder {
50
+ func newBuilder (plan * v1alpha1.InstallPlan , csvLister listersv1alpha1.ClusterServiceVersionLister , opclient operatorclient.ClientInterface , dynamicClient dynamic.Interface , manifestResolver ManifestResolver , logger logrus.FieldLogger ) * builder {
48
51
return & builder {
49
- opclient : opclient ,
50
- dynamicClient : dynamicClient ,
51
- manifestResolver : manifestResolver ,
52
- csvToProvidedAPIs : csvToProvidedAPIs ,
53
- logger : logger ,
52
+ plan : plan ,
53
+ csvLister : csvLister ,
54
+ opclient : opclient ,
55
+ dynamicClient : dynamicClient ,
56
+ manifestResolver : manifestResolver ,
57
+ logger : logger ,
54
58
}
55
59
}
56
60
@@ -75,6 +79,7 @@ func (b *builder) create(step v1alpha1.Step) (Stepper, error) {
75
79
if err != nil {
76
80
return nil , err
77
81
}
82
+
78
83
switch version {
79
84
case crdlib .V1Version :
80
85
return b .NewCRDV1Step (b .opclient .ApiextensionsInterface ().ApiextensionsV1 (), & step , manifest ), nil
@@ -98,7 +103,7 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter
98
103
if k8serrors .IsNotFound (err ) {
99
104
return v1alpha1 .StepStatusNotPresent , nil
100
105
} else {
101
- return v1alpha1 .StepStatusNotPresent , errorwrap .Wrapf (err , "error finding the %s CRD" , crd .Name )
106
+ return v1alpha1 .StepStatusNotPresent , errors .Wrapf (err , "error finding the %s CRD" , crd .Name )
102
107
}
103
108
}
104
109
established , namesAccepted := false , false
@@ -123,28 +128,31 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter
123
128
return v1alpha1 .StepStatusUnknown , err
124
129
}
125
130
131
+ setInstalledAlongsideAnnotation (b .annotator , crd , b .plan .GetNamespace (), step .Resolving , b .csvLister , crd )
132
+
126
133
_ , createError := client .CustomResourceDefinitions ().Create (context .TODO (), crd , metav1.CreateOptions {})
127
134
if k8serrors .IsAlreadyExists (createError ) {
128
135
currentCRD , _ := client .CustomResourceDefinitions ().Get (context .TODO (), crd .GetName (), metav1.GetOptions {})
129
136
crd .SetResourceVersion (currentCRD .GetResourceVersion ())
130
137
if err = validateV1CRDCompatibility (b .dynamicClient , currentCRD , crd ); err != nil {
131
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error validating existing CRs against new CRD's schema: %s" , step .Resource .Name )
138
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "error validating existing CRs against new CRD's schema: %s" , step .Resource .Name )
132
139
}
133
140
134
141
// check to see if stored versions changed and whether the upgrade could cause potential data loss
135
142
safe , err := crdlib .SafeStorageVersionUpgrade (currentCRD , crd )
136
143
if ! safe {
137
144
b .logger .Errorf ("risk of data loss updating %s: %s" , step .Resource .Name , err )
138
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "risk of data loss updating %s" , step .Resource .Name )
145
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "risk of data loss updating %s" , step .Resource .Name )
139
146
}
140
147
if err != nil {
141
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "checking CRD for potential data loss updating %s" , step .Resource .Name )
148
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "checking CRD for potential data loss updating %s" , step .Resource .Name )
142
149
}
143
150
144
151
// Update CRD to new version
152
+ setInstalledAlongsideAnnotation (b .annotator , crd , b .plan .GetNamespace (), step .Resolving , b .csvLister , crd , currentCRD )
145
153
_ , err = client .CustomResourceDefinitions ().Update (context .TODO (), crd , metav1.UpdateOptions {})
146
154
if err != nil {
147
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
155
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
148
156
}
149
157
// If it already existed, mark the step as Present.
150
158
// they were equal - mark CRD as present
@@ -173,7 +181,7 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi
173
181
if k8serrors .IsNotFound (err ) {
174
182
return v1alpha1 .StepStatusNotPresent , nil
175
183
} else {
176
- return v1alpha1 .StepStatusNotPresent , errorwrap .Wrapf (err , "error finding the %s CRD" , crd .Name )
184
+ return v1alpha1 .StepStatusNotPresent , errors .Wrapf (err , "error finding the %s CRD" , crd .Name )
177
185
}
178
186
}
179
187
established , namesAccepted := false , false
@@ -198,29 +206,32 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi
198
206
return v1alpha1 .StepStatusUnknown , err
199
207
}
200
208
209
+ setInstalledAlongsideAnnotation (b .annotator , crd , b .plan .GetNamespace (), step .Resolving , b .csvLister , crd )
210
+
201
211
_ , createError := client .CustomResourceDefinitions ().Create (context .TODO (), crd , metav1.CreateOptions {})
202
212
if k8serrors .IsAlreadyExists (createError ) {
203
213
currentCRD , _ := client .CustomResourceDefinitions ().Get (context .TODO (), crd .GetName (), metav1.GetOptions {})
204
214
crd .SetResourceVersion (currentCRD .GetResourceVersion ())
205
215
206
216
if err = validateV1Beta1CRDCompatibility (b .dynamicClient , currentCRD , crd ); err != nil {
207
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error validating existing CRs against new CRD's schema: %s" , step .Resource .Name )
217
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "error validating existing CRs against new CRD's schema: %s" , step .Resource .Name )
208
218
}
209
219
210
220
// check to see if stored versions changed and whether the upgrade could cause potential data loss
211
221
safe , err := crdlib .SafeStorageVersionUpgrade (currentCRD , crd )
212
222
if ! safe {
213
223
b .logger .Errorf ("risk of data loss updating %s: %s" , step .Resource .Name , err )
214
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "risk of data loss updating %s" , step .Resource .Name )
224
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "risk of data loss updating %s" , step .Resource .Name )
215
225
}
216
226
if err != nil {
217
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "checking CRD for potential data loss updating %s" , step .Resource .Name )
227
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "checking CRD for potential data loss updating %s" , step .Resource .Name )
218
228
}
219
229
220
230
// Update CRD to new version
231
+ setInstalledAlongsideAnnotation (b .annotator , crd , b .plan .GetNamespace (), step .Resolving , b .csvLister , crd , currentCRD )
221
232
_ , err = client .CustomResourceDefinitions ().Update (context .TODO (), crd , metav1.UpdateOptions {})
222
233
if err != nil {
223
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
234
+ return v1alpha1 .StepStatusUnknown , errors .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
224
235
}
225
236
// If it already existed, mark the step as Present.
226
237
// they were equal - mark CRD as present
@@ -235,3 +246,35 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi
235
246
return v1alpha1 .StepStatusUnknown , nil
236
247
}
237
248
}
249
+
250
+ func setInstalledAlongsideAnnotation (a alongside.Annotator , dst metav1.Object , namespace string , name string , lister listersv1alpha1.ClusterServiceVersionLister , srcs ... metav1.Object ) {
251
+ var (
252
+ nns []alongside.NamespacedName
253
+ )
254
+
255
+ // Only keep references to existing and non-copied CSVs to
256
+ // avoid unbounded growth.
257
+ for _ , src := range srcs {
258
+ for _ , nn := range a .FromObject (src ) {
259
+ if nn .Namespace == namespace && nn .Name == name {
260
+ continue
261
+ }
262
+
263
+ if csv , err := lister .ClusterServiceVersions (nn .Namespace ).Get (nn .Name ); k8serrors .IsNotFound (err ) {
264
+ continue
265
+ } else if err == nil && csv .IsCopied () {
266
+ continue
267
+ }
268
+ // CSV exists and is not copied OR err is non-nil, but
269
+ // not 404. Safer to assume it exists in unhandled
270
+ // error cases and try again next time.
271
+ nns = append (nns , nn )
272
+ }
273
+ }
274
+
275
+ if namespace != "" && name != "" {
276
+ nns = append (nns , alongside.NamespacedName {Namespace : namespace , Name : name })
277
+ }
278
+
279
+ a .ToObject (dst , nns )
280
+ }
0 commit comments