Skip to content

Commit 82705fc

Browse files
committed
Make the revision controller report degraded on error
This makes the error handling slightly easier, keeps the retry on error logic, leaves the requeue on self-modification we rely upon. This doesn't introduce VAP to prevent writes to "immutable" configmaps and secrets, but I'm open to doing that to prevent stale caches from creating unstable and inconsistent revisions.
1 parent 5e8bc56 commit 82705fc

File tree

2 files changed

+15
-65
lines changed

2 files changed

+15
-65
lines changed

pkg/operator/revisioncontroller/revision_controller.go

Lines changed: 14 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import (
77
"strings"
88
"time"
99

10-
operatorv1 "github.com/openshift/api/operator/v1"
1110
applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
1211
"github.com/openshift/library-go/pkg/controller/factory"
13-
"github.com/openshift/library-go/pkg/operator/condition"
1412
"github.com/openshift/library-go/pkg/operator/events"
1513
"github.com/openshift/library-go/pkg/operator/management"
1614
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
@@ -90,26 +88,28 @@ func NewRevisionController(
9088
kubeInformersForTargetNamespace.Core().V1().Secrets().Informer(),
9189
).
9290
WithSync(c.sync).
91+
WithSyncDegradedOnError(operatorClient).
9392
ResyncEvery(1*time.Minute).
9493
ToController(
95-
"RevisionController", // don't change what is passed here unless you also remove the old FooDegraded condition
94+
"RevisionController",
9695
eventRecorder,
9796
)
9897
}
9998

10099
// createRevisionIfNeeded takes care of creating content for the static pods to use.
101100
// returns whether or not requeue and if an error happened when updating status. Normally it updates status itself.
102-
func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder events.Recorder, currentLastAvailableRevision int32) (wroteStatus bool, requeue bool, err error) {
101+
func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder events.Recorder, currentLastAvailableRevision int32) error {
103102
isLatestRevisionCurrent, requiredIsNotFound, reason := c.isLatestRevisionCurrent(ctx, currentLastAvailableRevision)
104103

105104
// 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
106105
if isLatestRevisionCurrent {
107106
klog.V(4).Infof("Returning early, %d triggered and up to date", currentLastAvailableRevision)
108-
return false, false, nil
107+
return nil
109108
}
110109

111110
nextRevision := currentLastAvailableRevision + 1
112111
var createdNewRevision bool
112+
var err error
113113
// check to make sure no new revision is created when a required object is missing
114114
if requiredIsNotFound {
115115
err = fmt.Errorf("%v", reason)
@@ -119,41 +119,24 @@ func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder
119119
}
120120

121121
if err != nil {
122-
status := applyoperatorv1.OperatorStatus().
123-
WithConditions(applyoperatorv1.OperatorCondition().
124-
WithType(condition.RevisionControllerDegradedConditionType).
125-
WithStatus(operatorv1.ConditionTrue).
126-
WithReason("ContentCreationError").
127-
WithMessage(err.Error()),
128-
).
129-
WithLatestAvailableRevision(currentLastAvailableRevision)
130-
updateError := c.operatorClient.ApplyOperatorStatus(ctx, c.controllerInstanceName, status)
131-
if updateError != nil {
132-
recorder.Warningf("RevisionCreateFailed", "Failed to create revision %d: %v", nextRevision, err.Error())
133-
return true, true, updateError
134-
}
135-
return true, true, nil
122+
return err
136123
}
137124

138125
if !createdNewRevision {
139126
klog.V(4).Infof("Revision %v not created", nextRevision)
140-
return false, false, nil
127+
return nil
141128
}
142129

143130
recorder.Eventf("RevisionTriggered", "new revision %d triggered by %q", nextRevision, reason)
144131

145132
status := applyoperatorv1.OperatorStatus().
146-
WithConditions(applyoperatorv1.OperatorCondition().
147-
WithType(condition.RevisionControllerDegradedConditionType).
148-
WithStatus(operatorv1.ConditionFalse),
149-
).
150133
WithLatestAvailableRevision(nextRevision)
151134
updateError := c.operatorClient.ApplyOperatorStatus(ctx, c.controllerInstanceName, status)
152135
if updateError != nil {
153-
return true, true, updateError
136+
return updateError
154137
}
155138

156-
return true, false, nil
139+
return nil
157140
}
158141

159142
func nameFor(name string, revision int32) string {
@@ -394,47 +377,23 @@ func (c RevisionController) sync(ctx context.Context, syncCtx factory.SyncContex
394377
if latestObservedRevision != 0 && operatorStatus.LatestAvailableRevision != latestObservedRevision {
395378
// Then make sure that revision number is what's in the operator status
396379
status := applyoperatorv1.OperatorStatus().
397-
WithConditions(applyoperatorv1.OperatorCondition().
398-
WithType(condition.RevisionControllerDegradedConditionType).
399-
WithStatus(operatorv1.ConditionFalse),
400-
).
401380
WithLatestAvailableRevision(latestObservedRevision)
402381
err := c.operatorClient.ApplyOperatorStatus(ctx, c.controllerInstanceName, status)
403382
if err != nil {
404383
return err
405384
}
406-
// regardless of whether we made a change, requeue to rerun the sync with updated status
407-
return factory.SyntheticRequeueError
385+
// we will be called again because the update will self-feed the informer
386+
return nil
408387
}
409388

410389
if shouldCreateNewRevision, err := c.revisionPrecondition(ctx); err != nil || !shouldCreateNewRevision {
411390
return err
412391
}
413392

414-
wroteStatus, requeue, syncErr := c.createRevisionIfNeeded(ctx, syncCtx.Recorder(), operatorStatus.LatestAvailableRevision)
415-
switch {
416-
case requeue && syncErr == nil:
417-
return factory.SyntheticRequeueError
418-
case syncErr != nil:
419-
// this is updated in status inside of createRevisionIfNeeded
393+
syncErr := c.createRevisionIfNeeded(ctx, syncCtx.Recorder(), operatorStatus.LatestAvailableRevision)
394+
if syncErr != nil {
420395
return syncErr
421-
case wroteStatus:
422-
return syncErr
423-
}
424-
425-
// update failing condition
426-
status := applyoperatorv1.OperatorStatus().
427-
WithConditions(applyoperatorv1.OperatorCondition().
428-
WithType(condition.RevisionControllerDegradedConditionType).
429-
WithStatus(operatorv1.ConditionFalse),
430-
).
431-
WithLatestAvailableRevision(operatorStatus.LatestAvailableRevision)
432-
updateError := c.operatorClient.ApplyOperatorStatus(ctx, c.controllerInstanceName, status)
433-
if updateError != nil {
434-
if err == nil {
435-
return updateError
436-
}
437396
}
438397

439-
return err
398+
return nil
440399
}

pkg/operator/revisioncontroller/revision_controller_test.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,17 +220,8 @@ func TestRevisionController(t *testing.T) {
220220
),
221221
testConfigs: []RevisionResource{{Name: "test-config"}},
222222
testSecrets: []RevisionResource{{Name: "test-secret"}},
223-
expectSyncError: "synthetic requeue request",
223+
expectSyncError: `configmaps "test-config" not found`,
224224
validateStatus: func(t *testing.T, status *operatorv1.StaticPodOperatorStatus) {
225-
if status.Conditions[0].Type != "RevisionControllerDegraded" {
226-
t.Errorf("expected status condition to be 'RevisionControllerFailing', got %v", status.Conditions[0].Type)
227-
}
228-
if status.Conditions[0].Reason != "ContentCreationError" {
229-
t.Errorf("expected status condition reason to be 'ContentCreationError', got %v", status.Conditions[0].Reason)
230-
}
231-
if !strings.Contains(status.Conditions[0].Message, `configmaps "test-config" not found`) {
232-
t.Errorf("expected status to be 'configmaps test-config not found', got: %s", status.Conditions[0].Message)
233-
}
234225
},
235226
validateActions: func(t *testing.T, actions []clienttesting.Action, kclient *fake.Clientset) {
236227
createdObjects := filterCreateActions(actions)

0 commit comments

Comments
 (0)