@@ -13,7 +13,10 @@ import (
13
13
errorwrap "github.com/pkg/errors"
14
14
logger "github.com/sirupsen/logrus"
15
15
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
16
- "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
16
+ apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
17
+ apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
18
+ apiextensionsv1beta1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
19
+
17
20
k8serrors "k8s.io/apimachinery/pkg/api/errors"
18
21
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
22
)
@@ -36,13 +39,16 @@ type builder struct {
36
39
opclient operatorclient.ClientInterface
37
40
dynamicClient dynamic.Interface
38
41
csvToProvidedAPIs map [string ]cache.Indexer
42
+ logger logger.FieldLogger
39
43
}
40
44
41
- func newBuilder (opclient operatorclient.ClientInterface , dynamicClient dynamic.Interface , csvToProvidedAPIs map [string ]cache.Indexer ) * builder {
45
+ func newBuilder (opclient operatorclient.ClientInterface , dynamicClient dynamic.Interface , csvToProvidedAPIs map [string ]cache.Indexer ,
46
+ logger logger.FieldLogger ) * builder {
42
47
return & builder {
43
48
opclient : opclient ,
44
49
dynamicClient : dynamicClient ,
45
50
csvToProvidedAPIs : csvToProvidedAPIs ,
51
+ logger : logger ,
46
52
}
47
53
}
48
54
@@ -57,23 +63,32 @@ func (n notSupportedStepperErr) Error() string {
57
63
// step is a factory that creates StepperFuncs based on the Kind provided and the install plan step.
58
64
func (b * builder ) create (step * v1alpha1.Step ) (Stepper , error ) {
59
65
kind := step .Resource .Kind
66
+ version , err := crdlib .Version (& step .Resource .Manifest )
67
+ if err != nil {
68
+ return nil , err
69
+ }
70
+
60
71
switch kind {
61
72
case crdKind :
62
- return b .NewCRDStep (step .Resource .Manifest , b .opclient .ApiextensionsInterface (), step .Status , step .Resource .Name ), nil
63
- default :
64
- return nil , notSupportedStepperErr {fmt .Sprintf ("stepper interface does not support %s" , kind )}
73
+ switch version {
74
+ case crdlib .V1Version :
75
+ return b .NewCRDV1Step (b .opclient .ApiextensionsInterface ().ApiextensionsV1 (), step ), nil
76
+ case crdlib .V1Beta1Version :
77
+ return b .NewCRDV1Beta1Step (b .opclient .ApiextensionsInterface ().ApiextensionsV1beta1 (), step ), nil
78
+ }
65
79
}
80
+ return nil , notSupportedStepperErr {fmt .Sprintf ("stepper interface does not support %s" , kind )}
66
81
}
67
82
68
- func (b * builder ) NewCRDStep ( manifest string , client clientset. Interface , status v1alpha1.StepStatus , name string ) StepperFunc {
83
+ func (b * builder ) NewCRDV1Step ( client apiextensionsv1client. ApiextensionsV1Interface , step * v1alpha1.Step ) StepperFunc {
69
84
return func () (v1alpha1.StepStatus , error ) {
70
- switch status {
85
+ switch step . Status {
71
86
case v1alpha1 .StepStatusPresent :
72
87
return v1alpha1 .StepStatusPresent , nil
73
88
case v1alpha1 .StepStatusCreated :
74
89
return v1alpha1 .StepStatusCreated , nil
75
90
case v1alpha1 .StepStatusWaitingForAPI :
76
- crd , err := client .ApiextensionsV1 (). CustomResourceDefinitions ().Get (context .TODO (), name , metav1.GetOptions {})
91
+ crd , err := client .CustomResourceDefinitions ().Get (context .TODO (), step . Resource . Name , metav1.GetOptions {})
77
92
if err != nil {
78
93
if k8serrors .IsNotFound (err ) {
79
94
return v1alpha1 .StepStatusNotPresent , nil
@@ -98,61 +113,161 @@ func (b *builder) NewCRDStep(manifest string, client clientset.Interface, status
98
113
return v1alpha1 .StepStatusCreated , nil
99
114
}
100
115
case v1alpha1 .StepStatusUnknown , v1alpha1 .StepStatusNotPresent :
101
- crd , err := crdlib .Serialize ( manifest )
116
+ crd , err := crdlib .UnmarshalV1 ( step . Resource . Manifest )
102
117
if err != nil {
103
118
return v1alpha1 .StepStatusUnknown , err
104
119
}
120
+ b .logger .Debugf ("creating v1 CRD %#v" , crd )
105
121
106
- _ , err = client .ApiextensionsV1 ().CustomResourceDefinitions ().Create (context .TODO (), crd , metav1.CreateOptions {})
107
- if k8serrors .IsAlreadyExists (err ) {
108
- currentCRD , _ := client .ApiextensionsV1 ().CustomResourceDefinitions ().Get (context .TODO (), crd .GetName (), metav1.GetOptions {})
109
- // Compare 2 CRDs to see if it needs to be updatetd
110
- if crdlib .NotEqual (currentCRD , crd ) {
122
+ _ , createError := client .CustomResourceDefinitions ().Create (context .TODO (), crd , metav1.CreateOptions {})
123
+ if k8serrors .IsAlreadyExists (createError ) {
124
+ currentCRD , _ := client .CustomResourceDefinitions ().Get (context .TODO (), crd .GetName (), metav1.GetOptions {})
125
+ // Compare 2 CRDs to see if it needs to be updated
126
+ logger .Debugf ("\n current crd: %#v \n new crd: %#v \n " , currentCRD , crd )
127
+ if crdlib .V1NotEqual (currentCRD , crd ) {
111
128
// Verify CRD ownership, only attempt to update if
112
129
// CRD has only one owner
113
130
// Example: provided=database.coreos.com/v1alpha1/EtcdCluster
114
- matchedCSV , err := index .CRDProviderNames (b .csvToProvidedAPIs , crd )
131
+ matchedCSV , err := index .V1CRDProviderNames (b .csvToProvidedAPIs , crd )
115
132
if err != nil {
116
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error find matched CSV: %s" , name )
133
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error find matched CSV: %s" , step . Resource . Name )
117
134
}
118
135
crd .SetResourceVersion (currentCRD .GetResourceVersion ())
119
136
if len (matchedCSV ) == 1 {
120
137
logger .Debugf ("Found one owner for CRD %v" , crd )
121
138
} else if len (matchedCSV ) > 1 {
122
139
logger .Debugf ("Found multiple owners for CRD %v" , crd )
123
140
124
- err := EnsureCRDVersions (currentCRD , crd )
141
+ err := EnsureV1CRDVersions (currentCRD , crd )
125
142
if err != nil {
126
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error missing existing CRD version(s) in new CRD: %s" , name )
143
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error missing existing CRD version(s) in new CRD: %s" , step . Resource . Name )
127
144
}
128
145
129
146
if err = validateV1CRDCompatibility (b .dynamicClient , currentCRD , crd ); err != nil {
130
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error validating existing CRs agains new CRD's schema: %s" , name )
147
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error validating existing CRs agains new CRD's schema: %s" , step . Resource . Name )
131
148
}
132
149
}
133
150
// Remove deprecated version in CRD storedVersions
134
151
storeVersions := removeDeprecatedV1StoredVersions (currentCRD , crd )
135
152
if storeVersions != nil {
136
153
currentCRD .Status .StoredVersions = storeVersions
137
- resultCRD , err := client .ApiextensionsV1 (). CustomResourceDefinitions ().UpdateStatus (context .TODO (), currentCRD , metav1.UpdateOptions {})
154
+ resultCRD , err := client .CustomResourceDefinitions ().UpdateStatus (context .TODO (), currentCRD , metav1.UpdateOptions {})
138
155
if err != nil {
139
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD's status: %s" , name )
156
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD's status: %s" , step . Resource . Name )
140
157
}
141
158
crd .SetResourceVersion (resultCRD .GetResourceVersion ())
142
159
}
143
160
// Update CRD to new version
144
- _ , err = client .ApiextensionsV1 (). CustomResourceDefinitions ().Update (context .TODO (), crd , metav1.UpdateOptions {})
161
+ _ , err = client .CustomResourceDefinitions ().Update (context .TODO (), crd , metav1.UpdateOptions {})
145
162
if err != nil {
146
- return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD: %s" , name )
163
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD: %s" , step . Resource . Name )
147
164
}
148
165
}
149
166
// If it already existed, mark the step as Present.
150
167
// they were equal - mark CRD as present
151
168
return v1alpha1 .StepStatusPresent , nil
152
- } else if err != nil {
169
+ } else if createError != nil {
153
170
// Unexpected error creating the CRD.
171
+ return v1alpha1 .StepStatusUnknown , createError
172
+ }
173
+ // If no error occured, make sure to wait for the API to become available.
174
+ return v1alpha1 .StepStatusWaitingForAPI , nil
175
+ }
176
+ return v1alpha1 .StepStatusUnknown , nil
177
+ }
178
+ }
179
+
180
+ func (b * builder ) NewCRDV1Beta1Step (client apiextensionsv1beta1client.ApiextensionsV1beta1Interface , step * v1alpha1.Step ) StepperFunc {
181
+ return func () (v1alpha1.StepStatus , error ) {
182
+ switch step .Status {
183
+ case v1alpha1 .StepStatusPresent :
184
+ return v1alpha1 .StepStatusPresent , nil
185
+ case v1alpha1 .StepStatusCreated :
186
+ return v1alpha1 .StepStatusCreated , nil
187
+ case v1alpha1 .StepStatusWaitingForAPI :
188
+ crd , err := client .CustomResourceDefinitions ().Get (context .TODO (), step .Resource .Name , metav1.GetOptions {})
189
+ if err != nil {
190
+ if k8serrors .IsNotFound (err ) {
191
+ return v1alpha1 .StepStatusNotPresent , nil
192
+ } else {
193
+ return v1alpha1 .StepStatusNotPresent , errorwrap .Wrapf (err , "error finding the %s CRD" , crd .Name )
194
+ }
195
+ }
196
+ established , namesAccepted := false , false
197
+ for _ , cdt := range crd .Status .Conditions {
198
+ switch cdt .Type {
199
+ case apiextensionsv1beta1 .Established :
200
+ if cdt .Status == apiextensionsv1beta1 .ConditionTrue {
201
+ established = true
202
+ }
203
+ case apiextensionsv1beta1 .NamesAccepted :
204
+ if cdt .Status == apiextensionsv1beta1 .ConditionTrue {
205
+ namesAccepted = true
206
+ }
207
+ }
208
+ }
209
+ if established && namesAccepted {
210
+ return v1alpha1 .StepStatusCreated , nil
211
+ }
212
+ case v1alpha1 .StepStatusUnknown , v1alpha1 .StepStatusNotPresent :
213
+ crd , err := crdlib .UnmarshalV1Beta1 (step .Resource .Manifest )
214
+ if err != nil {
154
215
return v1alpha1 .StepStatusUnknown , err
155
216
}
217
+ b .logger .Debugf ("creating v1beta1 CRD %#v" , crd )
218
+
219
+ _ , createError := client .CustomResourceDefinitions ().Create (context .TODO (), crd , metav1.CreateOptions {})
220
+ if k8serrors .IsAlreadyExists (createError ) {
221
+ currentCRD , _ := client .CustomResourceDefinitions ().Get (context .TODO (), crd .GetName (), metav1.GetOptions {})
222
+ // Compare 2 CRDs to see if it needs to be updated
223
+ logger .Debugf ("\n current crd: %#v \n new crd: %#v \n " , currentCRD , crd )
224
+ if crdlib .V1Beta1NotEqual (currentCRD , crd ) {
225
+ b .logger .Debugf ("not equal" )
226
+ // Verify CRD ownership, only attempt to update if
227
+ // CRD has only one owner
228
+ // Example: provided=database.coreos.com/v1alpha1/EtcdCluster
229
+ matchedCSV , err := index .V1Beta1CRDProviderNames (b .csvToProvidedAPIs , crd )
230
+ if err != nil {
231
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error find matched CSV: %s" , step .Resource .Name )
232
+ }
233
+ crd .SetResourceVersion (currentCRD .GetResourceVersion ())
234
+ if len (matchedCSV ) == 1 {
235
+ logger .Debugf ("Found one owner for CRD %v" , crd )
236
+ } else if len (matchedCSV ) > 1 {
237
+ logger .Debugf ("Found multiple owners for CRD %v" , crd )
238
+
239
+ err := EnsureV1Beta1CRDVersions (currentCRD , crd )
240
+ if err != nil {
241
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error missing existing CRD version(s) in new CRD: %s" , step .Resource .Name )
242
+ }
243
+
244
+ if err = validateV1Beta1CRDCompatibility (b .dynamicClient , currentCRD , crd ); err != nil {
245
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error validating existing CRs agains new CRD's schema: %s" , step .Resource .Name )
246
+ }
247
+ }
248
+ // Remove deprecated version in CRD storedVersions
249
+ storeVersions := removeDeprecatedV1Beta1StoredVersions (currentCRD , crd )
250
+ if storeVersions != nil {
251
+ currentCRD .Status .StoredVersions = storeVersions
252
+ resultCRD , err := client .CustomResourceDefinitions ().UpdateStatus (context .TODO (), currentCRD , metav1.UpdateOptions {})
253
+ if err != nil {
254
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD's status: %s" , step .Resource .Name )
255
+ }
256
+ crd .SetResourceVersion (resultCRD .GetResourceVersion ())
257
+ }
258
+ // Update CRD to new version
259
+ _ , err = client .CustomResourceDefinitions ().Update (context .TODO (), crd , metav1.UpdateOptions {})
260
+ if err != nil {
261
+ return v1alpha1 .StepStatusUnknown , errorwrap .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
262
+ }
263
+ }
264
+ // If it already existed, mark the step as Present.
265
+ // they were equal - mark CRD as present
266
+ return v1alpha1 .StepStatusPresent , nil
267
+ } else if createError != nil {
268
+ // Unexpected error creating the CRD.
269
+ return v1alpha1 .StepStatusUnknown , createError
270
+ }
156
271
// If no error occured, make sure to wait for the API to become available.
157
272
return v1alpha1 .StepStatusWaitingForAPI , nil
158
273
}
0 commit comments