@@ -89,12 +89,14 @@ func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder
89
89
90
90
// check to make sure that the latestRevision has the exact content we expect. No mutation here, so we start creating the next Revision only when it is required
91
91
if isLatestRevisionCurrent {
92
+ klog .V (4 ).Infof ("Returning early, %d triggered and up to date" , latestAvailableRevision )
92
93
return false , nil
93
94
}
94
95
95
96
nextRevision := latestAvailableRevision + 1
96
- recorder .Eventf ("RevisionTriggered" , "new revision %d triggered by %q" , nextRevision , reason )
97
- if err := c .createNewRevision (ctx , recorder , nextRevision , reason ); err != nil {
97
+ recorder .Eventf ("StartingNewRevision" , "new revision %d triggered by %q" , nextRevision , reason )
98
+ createdNewRevision , err := c .createNewRevision (ctx , recorder , nextRevision , reason )
99
+ if err != nil {
98
100
cond := operatorv1.OperatorCondition {
99
101
Type : "RevisionControllerDegraded" ,
100
102
Status : operatorv1 .ConditionTrue ,
@@ -108,6 +110,12 @@ func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder
108
110
return true , nil
109
111
}
110
112
113
+ if ! createdNewRevision {
114
+ klog .V (4 ).Infof ("Revision %v not created" , nextRevision )
115
+ return false , nil
116
+ }
117
+ recorder .Eventf ("RevisionTriggered" , "new revision %d triggered by %q" , nextRevision , reason )
118
+
111
119
cond := operatorv1.OperatorCondition {
112
120
Type : "RevisionControllerDegraded" ,
113
121
Status : operatorv1 .ConditionFalse ,
@@ -208,55 +216,80 @@ func (c RevisionController) isLatestRevisionCurrent(ctx context.Context, revisio
208
216
return true , ""
209
217
}
210
218
211
- func (c RevisionController ) createNewRevision (ctx context.Context , recorder events.Recorder , revision int32 , reason string ) error {
219
+ // returns true if we created a revision
220
+ func (c RevisionController ) createNewRevision (ctx context.Context , recorder events.Recorder , revision int32 , reason string ) (bool , error ) {
212
221
// Create a new InProgress status configmap
213
- statusConfigMap := & corev1.ConfigMap {
222
+ desiredStatusConfigMap := & corev1.ConfigMap {
214
223
ObjectMeta : metav1.ObjectMeta {
215
224
Namespace : c .targetNamespace ,
216
225
Name : nameFor ("revision-status" , revision ),
226
+ Annotations : map [string ]string {
227
+ "operator.openshift.io/revision-ready" : "false" ,
228
+ },
217
229
},
218
230
Data : map [string ]string {
219
231
"revision" : fmt .Sprintf ("%d" , revision ),
220
232
"reason" : reason ,
221
233
},
222
234
}
223
- statusConfigMap , _ , err := resourceapply .ApplyConfigMap (ctx , c .configMapGetter , recorder , statusConfigMap )
224
- if err != nil {
225
- return err
235
+ createdStatus , err := c .configMapGetter .ConfigMaps (desiredStatusConfigMap .Namespace ).Create (ctx , desiredStatusConfigMap , metav1.CreateOptions {})
236
+ switch {
237
+ case apierrors .IsAlreadyExists (err ):
238
+ if createdStatus == nil || len (createdStatus .UID ) == 0 {
239
+ createdStatus , err = c .configMapGetter .ConfigMaps (desiredStatusConfigMap .Namespace ).Get (ctx , desiredStatusConfigMap .Name , metav1.GetOptions {})
240
+ if err != nil {
241
+ return false , err
242
+ }
243
+ }
244
+ // take a live GET here to get current status to check the annotation
245
+ if createdStatus .Annotations ["operator.openshift.io/revision-ready" ] == "true" {
246
+ // no work to do because our cache is out of date and when we're updated, we will be able to see the result
247
+ klog .Infof ("down the branch indicating that our cache was out of date and we're trying to recreate a revision." )
248
+ return false , nil
249
+ }
250
+ // update the sync and continue
251
+ case err != nil :
252
+ return false , err
226
253
}
227
254
228
255
ownerRefs := []metav1.OwnerReference {{
229
256
APIVersion : "v1" ,
230
257
Kind : "ConfigMap" ,
231
- Name : statusConfigMap .Name ,
232
- UID : statusConfigMap .UID ,
258
+ Name : createdStatus .Name ,
259
+ UID : createdStatus .UID ,
233
260
}}
234
261
235
262
for _ , cm := range c .configMaps {
236
263
obj , _ , err := resourceapply .SyncConfigMap (ctx , c .configMapGetter , recorder , c .targetNamespace , cm .Name , c .targetNamespace , nameFor (cm .Name , revision ), ownerRefs )
237
264
if err != nil {
238
- return err
265
+ return false , err
239
266
}
240
267
if obj == nil && ! cm .Optional {
241
- return apierrors .NewNotFound (corev1 .Resource ("configmaps" ), cm .Name )
268
+ return false , apierrors .NewNotFound (corev1 .Resource ("configmaps" ), cm .Name )
242
269
}
243
270
}
244
271
for _ , s := range c .secrets {
245
272
obj , _ , err := resourceapply .SyncSecret (ctx , c .secretGetter , recorder , c .targetNamespace , s .Name , c .targetNamespace , nameFor (s .Name , revision ), ownerRefs )
246
273
if err != nil {
247
- return err
274
+ return false , err
248
275
}
249
276
if obj == nil && ! s .Optional {
250
- return apierrors .NewNotFound (corev1 .Resource ("secrets" ), s .Name )
277
+ return false , apierrors .NewNotFound (corev1 .Resource ("secrets" ), s .Name )
251
278
}
252
279
}
253
280
254
- return nil
281
+ createdStatus .Annotations ["operator.openshift.io/revision-ready" ] = "true"
282
+ if _ , err := c .configMapGetter .ConfigMaps (createdStatus .Namespace ).Update (ctx , createdStatus , metav1.UpdateOptions {}); err != nil {
283
+ return false , err
284
+ }
285
+
286
+ return true , nil
255
287
}
256
288
257
289
// getLatestAvailableRevision returns the latest known revision to the operator
258
290
// This is determined by checking revision status configmaps.
259
291
func (c RevisionController ) getLatestAvailableRevision (ctx context.Context ) (int32 , error ) {
292
+ // this appears to use a cached getter. I conceded that past-David should have explicitly used Listers
260
293
configMaps , err := c .configMapGetter .ConfigMaps (c .targetNamespace ).List (ctx , metav1.ListOptions {})
261
294
if err != nil {
262
295
return 0 , err
@@ -281,7 +314,7 @@ func (c RevisionController) getLatestAvailableRevision(ctx context.Context) (int
281
314
}
282
315
283
316
func (c RevisionController ) sync (ctx context.Context , syncCtx factory.SyncContext ) error {
284
- operatorSpec , _ , latestAvailableRevision , resourceVersion , err := c .operatorClient .GetLatestRevisionState ()
317
+ operatorSpec , _ , latestAvailableRevisionSeenByOperator , resourceVersion , err := c .operatorClient .GetLatestRevisionState ()
285
318
if err != nil {
286
319
return err
287
320
}
@@ -290,26 +323,22 @@ func (c RevisionController) sync(ctx context.Context, syncCtx factory.SyncContex
290
323
return nil
291
324
}
292
325
293
- // If the operator status has 0 as its latest available revision, this is either the first revision
294
- // or possibly the operator resource was deleted and reset back to 0, which is not what we want so check configmaps
295
- if latestAvailableRevision == 0 {
296
- // Check to see if current revision is accurate and if not, search through configmaps for latest revision
297
- latestRevision , err := c .getLatestAvailableRevision (ctx )
326
+ // If the operator status's latest available revision is not the same as the observed latest revision, update the operator.
327
+ latestObservedRevision , err := c .getLatestAvailableRevision (ctx )
328
+ if err != nil {
329
+ return err
330
+ }
331
+ if latestObservedRevision != 0 && latestAvailableRevisionSeenByOperator != latestObservedRevision {
332
+ // Then make sure that revision number is what's in the operator status
333
+ _ , _ , err := c .operatorClient .UpdateLatestRevisionOperatorStatus (ctx , latestObservedRevision )
298
334
if err != nil {
299
335
return err
300
336
}
301
- if latestRevision != 0 {
302
- // Then make sure that revision number is what's in the operator status
303
- _ , _ , err := c .operatorClient .UpdateLatestRevisionOperatorStatus (ctx , latestRevision )
304
- if err != nil {
305
- return err
306
- }
307
- // regardless of whether we made a change, requeue to rerun the sync with updated status
308
- return factory .SyntheticRequeueError
309
- }
337
+ // regardless of whether we made a change, requeue to rerun the sync with updated status
338
+ return factory .SyntheticRequeueError
310
339
}
311
340
312
- requeue , syncErr := c .createRevisionIfNeeded (ctx , syncCtx .Recorder (), latestAvailableRevision , resourceVersion )
341
+ requeue , syncErr := c .createRevisionIfNeeded (ctx , syncCtx .Recorder (), latestAvailableRevisionSeenByOperator , resourceVersion )
313
342
if requeue && syncErr == nil {
314
343
return factory .SyntheticRequeueError
315
344
}
0 commit comments