@@ -19,7 +19,6 @@ import (
1919 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020 "k8s.io/apimachinery/pkg/runtime"
2121 kuberecorder "k8s.io/client-go/tools/record"
22- "k8s.io/klog/v2"
2322 ctrl "sigs.k8s.io/controller-runtime"
2423 "sigs.k8s.io/controller-runtime/pkg/builder"
2524 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -84,51 +83,29 @@ func (r *ComponentVersionReconciler) Reconcile(ctx context.Context, req ctrl.Req
8483 return
8584 }
8685
87- patchHelper , err := patch .NewHelper (obj , r .Client )
88- if err != nil {
89- return ctrl.Result {}, fmt .Errorf ("failed to create patchhelper: %w" , err )
90- }
86+ patchHelper := patch .NewSerialPatcher (obj , r .Client )
9187
9288 // Always attempt to patch the object and status after each reconciliation.
9389 defer func () {
94- // Patching has not been set up, or the controller errored earlier.
95- if patchHelper == nil {
96- return
97- }
98-
99- // If still reconciling then reconciliation did not succeed, set to ProgressingWithRetry to
100- // indicate that reconciliation will be retried.
101- if conditions .IsReconciling (obj ) {
102- reconciling := conditions .Get (obj , meta .ReconcilingCondition )
103- reconciling .Reason = meta .ProgressingWithRetryReason
104- conditions .Set (obj , reconciling )
105- msg := fmt .Sprintf ("Reconciliation did not succeed, retrying in %s" , obj .GetRequeueAfter ())
106- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , msg , nil )
107- }
108-
109- // Set status observed generation option if the component is ready.
110- if conditions .IsReady (obj ) {
111- obj .Status .ObservedGeneration = obj .Generation
112- msg := fmt .Sprintf ("Reconciliation finished, next run in %s" , obj .GetRequeueAfter ())
113- vid := fmt .Sprintf ("%s:%s" , obj .Status .ComponentDescriptor .Name , obj .Status .ReconciledVersion )
114- metadata := make (map [string ]string )
115- metadata [v1alpha1 .GroupVersion .Group + "/component_version" ] = vid
116- event .New (r .EventRecorder , obj , eventv1 .EventSeverityInfo , msg , metadata )
117- }
118-
119- // Update the object.
120- if err := patchHelper .Patch (ctx , obj ); err != nil {
121- retErr = errors .Join (retErr , err )
90+ if derr := DeferredStatusUpdate (ctx , patchHelper , obj , r .EventRecorder , obj .GetRequeueAfter ()); derr != nil {
91+ retErr = errors .Join (retErr , derr )
12292 }
12393 }()
12494
125- rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "reconcilation in progress for component: %s" , obj .Spec .Component )
95+ // Starts the progression by setting ReconcilingCondition.
96+ // This will be checked in defer.
97+ // Should only be deleted on a success.
98+ rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "reconciliation in progress for component: %s" , obj .Spec .Component )
12699
127100 octx , err := r .OCMClient .CreateAuthenticatedOCMContext (ctx , obj )
128101 if err != nil {
129- msg := fmt .Sprintf ("authentication failed for repository: %s with error: %s" , obj .Spec .Repository .URL , err )
130- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .AuthenticatedContextCreationFailedReason , msg )
131- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , msg , nil )
102+ // we don't fail here, because all manifests might have been applied at once or the secret
103+ // for authentication is being reconciled.
104+ _ = r .markAsFailed (
105+ obj ,
106+ v1alpha1 .AuthenticatedContextCreationFailedReason ,
107+ fmt .Errorf ("authentication failed for repository: %s with error: %s" , obj .Spec .Repository .URL , err ),
108+ )
132109
133110 return ctrl.Result {
134111 RequeueAfter : obj .GetRequeueAfter (),
@@ -138,9 +115,12 @@ func (r *ComponentVersionReconciler) Reconcile(ctx context.Context, req ctrl.Req
138115 // reconcile the version before calling reconcile func
139116 update , version , err := r .checkVersion (ctx , octx , obj )
140117 if err != nil {
141- msg := fmt .Sprintf ("version check failed for %s %s with error: %s" , obj .Spec .Component , obj .Spec .Version .Semver , err )
142- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .CheckVersionFailedReason , msg )
143- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , msg , nil )
118+ // The component might not be there yet. We don't fail but keep polling instead.
119+ _ = r .markAsFailed (
120+ obj ,
121+ v1alpha1 .CheckVersionFailedReason ,
122+ fmt .Errorf ("version check failed for %s %s with error: %s" , obj .Spec .Component , obj .Spec .Version .Semver , err ),
123+ )
144124
145125 return ctrl.Result {
146126 RequeueAfter : obj .GetRequeueAfter (),
@@ -152,58 +132,57 @@ func (r *ComponentVersionReconciler) Reconcile(ctx context.Context, req ctrl.Req
152132 conditions .MarkTrue (obj ,
153133 meta .ReadyCondition ,
154134 meta .SucceededReason ,
155- fmt .Sprintf ("Applied version: %s" , version ))
135+ "Applied version: %s" ,
136+ version )
156137
157138 return ctrl.Result {
158139 RequeueAfter : obj .GetRequeueAfter (),
159140 }, nil
160141 }
161142
143+ rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "updating component to new version: %s: %s" , obj .Spec .Component , version )
144+
162145 ok , err := r .OCMClient .VerifyComponent (ctx , octx , obj , version )
163146 if err != nil {
164- msg := fmt .Sprintf ("failed to verify %s with constraint %s with error: %s" , obj .Spec .Component , obj .Spec .Version .Semver , err )
165- conditions .Delete (obj , meta .ReconcilingCondition )
166- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .VerificationFailedReason , msg )
167- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , fmt .Sprintf ("%s, retrying in %s" , err .Error (), obj .GetRequeueAfter ()), nil )
147+ _ = r .markAsFailed (
148+ obj ,
149+ v1alpha1 .VerificationFailedReason ,
150+ fmt .Errorf ("failed to verify %s with constraint %s with error: %s" , obj .Spec .Component , obj .Spec .Version .Semver , err ),
151+ )
168152
169153 return ctrl.Result {
170154 RequeueAfter : obj .GetRequeueAfter (),
171155 }, nil
172156 }
173157
174158 if ! ok {
175- msg := "attempted to verify component, but the digest didn't match"
176- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .VerificationFailedReason , msg )
177- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , fmt .Sprintf ("%s, retrying in %s" , msg , obj .GetRequeueAfter ()), nil )
159+ _ = r .markAsFailed (
160+ obj ,
161+ v1alpha1 .VerificationFailedReason ,
162+ errors .New ("attempted to verify component, but the digest didn't match" ),
163+ )
178164
179165 return ctrl.Result {
180166 RequeueAfter : obj .GetRequeueAfter (),
181167 }, nil
182168 }
183169
184- // update the result for the defer call to have the latest information
185- rresult , err := r .reconcile (ctx , octx , obj , version )
186- if err != nil {
187- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , fmt .Sprintf ("Reconciliation failed: %s, retrying in %s" , err .Error (), obj .GetRequeueAfter ()), nil )
188- }
189-
190- return rresult , err
170+ return r .reconcile (ctx , octx , obj , version )
191171}
192172
193173func (r * ComponentVersionReconciler ) reconcile (ctx context.Context , octx ocm.Context , obj * v1alpha1.ComponentVersion , version string ) (ctrl.Result , error ) {
194174 if obj .Generation != obj .Status .ObservedGeneration {
195- // don't have to patch here since we patch the object in the outer reconcile call.
196175 rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason ,
197176 "processing object: new generation %d -> %d" , obj .Status .ObservedGeneration , obj .Generation )
198177 }
199178
200179 cv , err := r .OCMClient .GetComponentVersion (ctx , octx , obj , obj .Spec .Component , version )
201180 if err != nil {
202- err = fmt . Errorf ( "failed to get component version: %w" , err )
203- conditions . MarkFalse ( obj , meta . ReadyCondition , v1alpha1 . ComponentVersionInvalidReason , err . Error ())
204- event . New ( r . EventRecorder , obj , eventv1 . EventSeverityError , err . Error (), nil )
205-
206- return ctrl. Result {}, err
181+ return ctrl. Result {}, r . markAsFailed (
182+ obj ,
183+ v1alpha1 . ComponentVersionInvalidReason ,
184+ fmt . Errorf ( "failed to get component version: %w" , err ),
185+ )
207186 }
208187
209188 defer cv .Close ()
@@ -212,18 +191,25 @@ func (r *ComponentVersionReconciler) reconcile(ctx context.Context, octx ocm.Con
212191 dv := & compdesc.DescriptorVersion {}
213192 cd , err := dv .ConvertFrom (cv .GetDescriptor ())
214193 if err != nil {
215- err = fmt .Errorf ("failed to convert component descriptor: %w" , err )
216- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .ConvertComponentDescriptorFailedReason , err .Error ())
217- return ctrl.Result {}, err
194+ return ctrl.Result {}, r .markAsFailed (
195+ obj ,
196+ v1alpha1 .ConvertComponentDescriptorFailedReason ,
197+ fmt .Errorf ("failed to convert component descriptor: %w" , err ),
198+ )
218199 }
219200
201+ rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "component fetched, creating descriptors" )
202+
220203 // setup the component descriptor kubernetes resource
221204 componentName , err := component .ConstructUniqueName (cd .GetName (), cd .GetVersion (), nil )
222205 if err != nil {
223- err = fmt .Errorf ("failed to generate name: %w" , err )
224- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .NameGenerationFailedReason , err .Error ())
225- return ctrl.Result {}, err
206+ return ctrl.Result {}, r .markAsFailed (
207+ obj ,
208+ v1alpha1 .NameGenerationFailedReason ,
209+ fmt .Errorf ("failed to generate name: %w" , err ),
210+ )
226211 }
212+
227213 descriptor := & v1alpha1.ComponentDescriptor {
228214 ObjectMeta : metav1.ObjectMeta {
229215 Namespace : obj .GetNamespace (),
@@ -251,10 +237,11 @@ func (r *ComponentVersionReconciler) reconcile(ctx context.Context, octx ocm.Con
251237 })
252238
253239 if err != nil {
254- err = fmt .Errorf ("failed to create or update component descriptor: %w" , err )
255- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .CreateOrUpdateComponentDescriptorFailedReason , err .Error ())
256- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , err .Error (), nil )
257- return ctrl.Result {}, err
240+ return ctrl.Result {}, r .markAsFailed (
241+ obj ,
242+ v1alpha1 .CreateOrUpdateComponentDescriptorFailedReason ,
243+ fmt .Errorf ("failed to create or update component descriptor: %w" , err ),
244+ )
258245 }
259246
260247 componentDescriptor := v1alpha1.Reference {
@@ -269,10 +256,11 @@ func (r *ComponentVersionReconciler) reconcile(ctx context.Context, octx ocm.Con
269256 if obj .Spec .References .Expand {
270257 componentDescriptor .References , err = r .parseReferences (ctx , octx , obj , cv .GetDescriptor ().References )
271258 if err != nil {
272- err = fmt .Errorf ("failed to parse references: %w" , err )
273- conditions .MarkFalse (obj , meta .ReadyCondition , v1alpha1 .ParseReferencesFailedReason , err .Error ())
274- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , err .Error (), nil )
275- return ctrl.Result {}, err
259+ return ctrl.Result {}, r .markAsFailed (
260+ obj ,
261+ v1alpha1 .ParseReferencesFailedReason ,
262+ fmt .Errorf ("failed to parse references: %w" , err ),
263+ )
276264 }
277265 }
278266
@@ -283,21 +271,22 @@ func (r *ComponentVersionReconciler) reconcile(ctx context.Context, octx ocm.Con
283271 conditions .MarkTrue (obj ,
284272 meta .ReadyCondition ,
285273 meta .SucceededReason ,
286- fmt .Sprintf ("Applied version: %s" , version ))
274+ "Applied version: %s" ,
275+ version )
287276
288277 conditions .Delete (obj , meta .ReconcilingCondition )
289278
290279 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
291280}
292281
293282func (r * ComponentVersionReconciler ) checkVersion (ctx context.Context , octx ocm.Context , obj * v1alpha1.ComponentVersion ) (bool , string , error ) {
294- log := log .FromContext (ctx ).WithName ("ocm-component-version-reconcile" )
283+ logger := log .FromContext (ctx ).WithName ("ocm-component-version-reconcile" )
295284
296285 latest , err := r .OCMClient .GetLatestValidComponentVersion (ctx , octx , obj )
297286 if err != nil {
298287 return false , "" , fmt .Errorf ("failed to get latest component version: %w" , err )
299288 }
300- log .V (4 ).Info ("got latest version of component" , "version" , latest )
289+ logger .V (4 ).Info ("got latest version of component" , "version" , latest )
301290
302291 latestSemver , err := semver .NewVersion (latest )
303292 if err != nil {
@@ -312,11 +301,11 @@ func (r *ComponentVersionReconciler) checkVersion(ctx context.Context, octx ocm.
312301 if err != nil {
313302 return false , "" , fmt .Errorf ("failed to parse reconciled version: %w" , err )
314303 }
315- log .V (4 ).Info ("current reconciled version is" , "reconciled" , current .String ())
304+ logger .V (4 ).Info ("current reconciled version is" , "reconciled" , current .String ())
316305
317306 if latestSemver .Equal (current ) || current .GreaterThan (latestSemver ) {
318- log .V (4 ).Info ("Reconciled version equal to or greater than newest available version" , "version" , latestSemver )
319- return false , "" , nil
307+ logger .V (4 ).Info ("Reconciled version equal to or greater than newest available version" , "version" , latestSemver )
308+ return false , latest , nil
320309 }
321310
322311 event .New (r .EventRecorder , obj , eventv1 .EventSeverityInfo , fmt .Sprintf ("Version check succeeded, found latest version: %s" , latest ), nil )
@@ -380,7 +369,6 @@ func (r *ComponentVersionReconciler) createComponentDescriptor(ctx context.Conte
380369 return nil , fmt .Errorf ("failed to convert component descriptor: %w" , err )
381370 }
382371
383- log := log .FromContext (ctx )
384372 // setup the component descriptor kubernetes resource
385373 componentName , err := component .ConstructUniqueName (ref .ComponentName , ref .Version , ref .GetMeta ().ExtraIdentity )
386374 if err != nil {
@@ -397,19 +385,26 @@ func (r *ComponentVersionReconciler) createComponentDescriptor(ctx context.Conte
397385 },
398386 }
399387
400- if err := controllerutil .SetOwnerReference (parent , descriptor , r .Scheme ); err != nil {
401- return nil , fmt .Errorf ("failed to set owner reference: %w" , err )
402- }
403-
404388 // create or update the component descriptor kubernetes resource
405389 // we don't need to update it
406- op , err := controllerutil .CreateOrUpdate (ctx , r .Client , descriptor , func () error {
390+ if _ , err = controllerutil .CreateOrUpdate (ctx , r .Client , descriptor , func () error {
391+ if descriptor .ObjectMeta .CreationTimestamp .IsZero () {
392+ if err := controllerutil .SetOwnerReference (parent , descriptor , r .Scheme ); err != nil {
393+ return fmt .Errorf ("failed to set owner reference: %w" , err )
394+ }
395+ }
396+
407397 return nil
408- })
409- if err != nil {
398+ }); err != nil {
410399 return nil , fmt .Errorf ("failed to create/update component descriptor: %w" , err )
411400 }
412- log .V (4 ).Info (fmt .Sprintf ("%s(ed) descriptor" , op ), "descriptor" , klog .KObj (descriptor ))
413401
414402 return descriptor , nil
415403}
404+
405+ func (r * ComponentVersionReconciler ) markAsFailed (obj * v1alpha1.ComponentVersion , reason string , err error ) error {
406+ conditions .MarkFalse (obj , meta .ReadyCondition , reason , err .Error ())
407+ event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , err .Error (), nil )
408+
409+ return err
410+ }
0 commit comments