@@ -7,25 +7,25 @@ import (
77 "strings"
88 "time"
99
10- "k8s.io/klog/v2"
11-
1210 operatorv1 "github.com/openshift/api/operator/v1"
13- corev1 "k8s.io/api/core/v1"
14- "k8s.io/apimachinery/pkg/api/equality"
15- apierrors "k8s.io/apimachinery/pkg/api/errors"
16- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17- "k8s.io/client-go/informers"
18- corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
19-
11+ applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
2012 "github.com/openshift/library-go/pkg/controller/factory"
2113 "github.com/openshift/library-go/pkg/operator/condition"
2214 "github.com/openshift/library-go/pkg/operator/events"
2315 "github.com/openshift/library-go/pkg/operator/management"
2416 "github.com/openshift/library-go/pkg/operator/resource/resourceapply"
2517 "github.com/openshift/library-go/pkg/operator/v1helpers"
18+ corev1 "k8s.io/api/core/v1"
19+ "k8s.io/apimachinery/pkg/api/equality"
20+ apierrors "k8s.io/apimachinery/pkg/api/errors"
21+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+ "k8s.io/client-go/informers"
23+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
24+ "k8s.io/klog/v2"
2625)
2726
2827// LatestRevisionClient is an operator client for an operator status with a latest revision field.
28+ // Deprecated
2929type LatestRevisionClient interface {
3030 v1helpers.OperatorClient
3131
@@ -39,14 +39,16 @@ type LatestRevisionClient interface {
3939// of them. If the original resources changes, the revision counter is increased, stored in LatestAvailableRevision
4040// field of the operator config and new snapshots suffixed by the revision are created.
4141type RevisionController struct {
42+ controllerInstanceName string
43+
4244 targetNamespace string
4345 // configMaps is the list of configmaps that are directly copied.A different actor/controller modifies these.
4446 // the first element should be the configmap that contains the static pod manifest
4547 configMaps []RevisionResource
4648 // secrets is a list of secrets that are directly copied for the current values. A different actor/controller modifies these.
4749 secrets []RevisionResource
4850
49- operatorClient LatestRevisionClient
51+ operatorClient v1helpers. OperatorClient
5052 configMapGetter corev1client.ConfigMapsGetter
5153 secretGetter corev1client.SecretsGetter
5254
@@ -63,11 +65,12 @@ type PreconditionFunc func(ctx context.Context) (bool, error)
6365
6466// NewRevisionController create a new revision controller.
6567func NewRevisionController (
68+ instanceName string ,
6669 targetNamespace string ,
6770 configMaps []RevisionResource ,
6871 secrets []RevisionResource ,
6972 kubeInformersForTargetNamespace informers.SharedInformerFactory ,
70- operatorClient LatestRevisionClient ,
73+ operatorClient v1helpers. OperatorClient ,
7174 configMapGetter corev1client.ConfigMapsGetter ,
7275 secretGetter corev1client.SecretsGetter ,
7376 eventRecorder events.Recorder ,
@@ -80,9 +83,10 @@ func NewRevisionController(
8083 }
8184
8285 c := & RevisionController {
83- targetNamespace : targetNamespace ,
84- configMaps : configMaps ,
85- secrets : secrets ,
86+ controllerInstanceName : factory .ControllerInstanceName (instanceName , "RevisionController" ),
87+ targetNamespace : targetNamespace ,
88+ configMaps : configMaps ,
89+ secrets : secrets ,
8690
8791 operatorClient : operatorClient ,
8892 configMapGetter : configMapGetter ,
@@ -106,18 +110,17 @@ func NewRevisionController(
106110
107111// createRevisionIfNeeded takes care of creating content for the static pods to use.
108112// returns whether or not requeue and if an error happened when updating status. Normally it updates status itself.
109- func (c RevisionController ) createRevisionIfNeeded (ctx context.Context , recorder events.Recorder , latestAvailableRevision int32 , resourceVersion string ) (bool , error ) {
110- isLatestRevisionCurrent , requiredIsNotFound , reason := c .isLatestRevisionCurrent (ctx , latestAvailableRevision )
113+ func (c RevisionController ) createRevisionIfNeeded (ctx context.Context , recorder events.Recorder , currentLastAvailableRevision int32 ) (wroteStatus bool , requeue bool , err error ) {
114+ isLatestRevisionCurrent , requiredIsNotFound , reason := c .isLatestRevisionCurrent (ctx , currentLastAvailableRevision )
111115
112116 // 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
113117 if isLatestRevisionCurrent {
114- klog .V (4 ).Infof ("Returning early, %d triggered and up to date" , latestAvailableRevision )
115- return false , nil
118+ klog .V (4 ).Infof ("Returning early, %d triggered and up to date" , currentLastAvailableRevision )
119+ return false , false , nil
116120 }
117121
118- nextRevision := latestAvailableRevision + 1
122+ nextRevision := currentLastAvailableRevision + 1
119123 var createdNewRevision bool
120- var err error
121124 // check to make sure no new revision is created when a required object is missing
122125 if requiredIsNotFound {
123126 err = fmt .Errorf ("%v" , reason )
@@ -127,36 +130,43 @@ func (c RevisionController) createRevisionIfNeeded(ctx context.Context, recorder
127130 }
128131
129132 if err != nil {
130- cond := operatorv1.OperatorCondition {
131- Type : "RevisionControllerDegraded" ,
132- Status : operatorv1 .ConditionTrue ,
133- Reason : "ContentCreationError" ,
134- Message : err .Error (),
135- }
136- if _ , _ , updateError := v1helpers .UpdateStatus (ctx , c .operatorClient , v1helpers .UpdateConditionFn (cond )); updateError != nil {
133+ status := applyoperatorv1 .OperatorStatus ().
134+ WithConditions (applyoperatorv1 .OperatorCondition ().
135+ WithType (condition .RevisionControllerDegradedConditionType ).
136+ WithStatus (operatorv1 .ConditionTrue ).
137+ WithReason ("ContentCreationError" ).
138+ WithMessage (err .Error ()),
139+ ).
140+ WithLatestAvailableRevision (currentLastAvailableRevision )
141+ // different fieldmanager is used to conflict. We could also choose to *always* set the lastavailablerevision
142+ // update this tomorrow, that's probably better.
143+ updateError := c .operatorClient .ApplyOperatorStatus (ctx , c .controllerInstanceName , status )
144+ if updateError != nil {
137145 recorder .Warningf ("RevisionCreateFailed" , "Failed to create revision %d: %v" , nextRevision , err .Error ())
138- return true , updateError
146+ return true , true , updateError
139147 }
140- return true , nil
148+ return true , true , nil
141149 }
142150
143151 if ! createdNewRevision {
144152 klog .V (4 ).Infof ("Revision %v not created" , nextRevision )
145- return false , nil
153+ return false , false , nil
146154 }
155+
147156 recorder .Eventf ("RevisionTriggered" , "new revision %d triggered by %q" , nextRevision , reason )
148157
149- cond := operatorv1.OperatorCondition {
150- Type : "RevisionControllerDegraded" ,
151- Status : operatorv1 .ConditionFalse ,
152- }
153- if _ , updated , updateError := c .operatorClient .UpdateLatestRevisionOperatorStatus (ctx , nextRevision , v1helpers .UpdateConditionFn (cond )); updateError != nil {
154- return true , updateError
155- } else if updated {
156- recorder .Eventf ("RevisionCreate" , "Revision %d created because %s" , nextRevision , reason )
158+ status := applyoperatorv1 .OperatorStatus ().
159+ WithConditions (applyoperatorv1 .OperatorCondition ().
160+ WithType (condition .RevisionControllerDegradedConditionType ).
161+ WithStatus (operatorv1 .ConditionFalse ),
162+ ).
163+ WithLatestAvailableRevision (nextRevision )
164+ updateError := c .operatorClient .ApplyOperatorStatus (ctx , c .controllerInstanceName , status )
165+ if updateError != nil {
166+ return true , true , updateError
157167 }
158168
159- return false , nil
169+ return true , false , nil
160170}
161171
162172func nameFor (name string , revision int32 ) string {
@@ -344,7 +354,8 @@ func (c RevisionController) getLatestAvailableRevision(ctx context.Context) (int
344354}
345355
346356func (c RevisionController ) sync (ctx context.Context , syncCtx factory.SyncContext ) error {
347- operatorSpec , _ , latestAvailableRevisionSeenByOperator , resourceVersion , err := c .operatorClient .GetLatestRevisionState ()
357+ //operatorSpec, _, latestAvailableRevisionSeenByOperator, resourceVersion, err := c.operatorClient.GetLatestRevisionState()
358+ operatorSpec , operatorStatus , _ , err := c .operatorClient .GetOperatorState ()
348359 if err != nil {
349360 return err
350361 }
@@ -362,33 +373,47 @@ func (c RevisionController) sync(ctx context.Context, syncCtx factory.SyncContex
362373 if err != nil {
363374 return err
364375 }
365- if latestObservedRevision != 0 && latestAvailableRevisionSeenByOperator != latestObservedRevision {
376+ if latestObservedRevision != 0 && operatorStatus . LatestAvailableRevision != latestObservedRevision {
366377 // Then make sure that revision number is what's in the operator status
367- _ , _ , err := c .operatorClient .UpdateLatestRevisionOperatorStatus (ctx , latestObservedRevision )
378+ status := applyoperatorv1 .OperatorStatus ().
379+ WithConditions (applyoperatorv1 .OperatorCondition ().
380+ WithType (condition .RevisionControllerDegradedConditionType ).
381+ WithStatus (operatorv1 .ConditionFalse ),
382+ ).
383+ WithLatestAvailableRevision (latestObservedRevision )
384+ err := c .operatorClient .ApplyOperatorStatus (ctx , c .controllerInstanceName , status )
368385 if err != nil {
369386 return err
370387 }
371388 // regardless of whether we made a change, requeue to rerun the sync with updated status
372389 return factory .SyntheticRequeueError
373390 }
374391
375- requeue , syncErr := c .createRevisionIfNeeded (ctx , syncCtx .Recorder (), latestAvailableRevisionSeenByOperator , resourceVersion )
392+ wroteStatus , requeue , syncErr := c .createRevisionIfNeeded (ctx , syncCtx .Recorder (), operatorStatus .LatestAvailableRevision )
393+ switch {
394+ case requeue && syncErr == nil :
395+ return factory .SyntheticRequeueError
396+ case syncErr != nil :
397+ // this is updated in status inside of createRevisionIfNeeded
398+ return syncErr
399+
400+ }
376401 if requeue && syncErr == nil {
377402 return factory .SyntheticRequeueError
378403 }
379- err = syncErr
404+ if wroteStatus {
405+ return syncErr
406+ }
380407
381408 // update failing condition
382- cond := operatorv1.OperatorCondition {
383- Type : condition .RevisionControllerDegradedConditionType ,
384- Status : operatorv1 .ConditionFalse ,
385- }
386- if err != nil {
387- cond .Status = operatorv1 .ConditionTrue
388- cond .Reason = "Error"
389- cond .Message = err .Error ()
390- }
391- if _ , _ , updateError := v1helpers .UpdateStatus (ctx , c .operatorClient , v1helpers .UpdateConditionFn (cond )); updateError != nil {
409+ status := applyoperatorv1 .OperatorStatus ().
410+ WithConditions (applyoperatorv1 .OperatorCondition ().
411+ WithType (condition .RevisionControllerDegradedConditionType ).
412+ WithStatus (operatorv1 .ConditionFalse ),
413+ ).
414+ WithLatestAvailableRevision (operatorStatus .LatestAvailableRevision )
415+ updateError := c .operatorClient .ApplyOperatorStatus (ctx , c .controllerInstanceName , status )
416+ if updateError != nil {
392417 if err == nil {
393418 return updateError
394419 }
0 commit comments