@@ -16,6 +16,7 @@ import (
1616 "github.com/fluxcd/pkg/runtime/patch"
1717 rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
1818 sourcev1 "github.com/fluxcd/source-controller/api/v1"
19+ "github.com/open-component-model/ocm-controller/pkg/event"
1920 "golang.org/x/exp/slices"
2021 apierrors "k8s.io/apimachinery/pkg/api/errors"
2122 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -36,7 +37,6 @@ import (
3637
3738 "github.com/open-component-model/ocm-controller/api/v1alpha1"
3839 "github.com/open-component-model/ocm-controller/pkg/cache"
39- "github.com/open-component-model/ocm-controller/pkg/event"
4040 "github.com/open-component-model/ocm-controller/pkg/ocm"
4141 "github.com/open-component-model/ocm-controller/pkg/snapshot"
4242)
@@ -170,131 +170,58 @@ func (r *ConfigurationReconciler) Reconcile(
170170 return result , nil
171171 }
172172
173- var patchHelper * patch.Helper
174- patchHelper , err = patch .NewHelper (obj , r .Client )
175- if err != nil {
176- return ctrl.Result {}, fmt .Errorf ("failed to create patch helper: %w" , err )
177- }
173+ patchHelper := patch .NewSerialPatcher (obj , r .Client )
178174
179175 // Always attempt to patch the object and status after each reconciliation.
180176 defer func () {
181- // Patching has not been set up, or the controller errored earlier.
182- if patchHelper == nil {
183- return
184- }
185-
186- if condition := conditions .Get (obj , meta .StalledCondition ); condition != nil &&
187- condition .Status == metav1 .ConditionTrue {
188- conditions .Delete (obj , meta .ReconcilingCondition )
189- }
190-
191- // Check if it's a successful reconciliation.
192- // We don't set Requeue in case of error, so we can safely check for Requeue.
193- if result .RequeueAfter == obj .GetRequeueAfter () && ! result .Requeue && err == nil {
194- // Remove the reconciling condition if it's set.
195- conditions .Delete (obj , meta .ReconcilingCondition )
196-
197- // Set the return err as the ready failure message is the resource is not ready, but also not reconciling or stalled.
198- if ready := conditions .Get (obj , meta .ReadyCondition ); ready != nil &&
199- ready .Status == metav1 .ConditionFalse &&
200- ! conditions .IsStalled (obj ) {
201- err = errors .New (conditions .GetMessage (obj , meta .ReadyCondition ))
202- event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , err .Error (), nil )
203- }
204- }
205-
206- // If still reconciling then reconciliation did not succeed, set to ProgressingWithRetry to
207- // indicate that reconciliation will be retried.
208- if conditions .IsReconciling (obj ) {
209- reconciling := conditions .Get (obj , meta .ReconcilingCondition )
210- reconciling .Reason = meta .ProgressingWithRetryReason
211- conditions .Set (obj , reconciling )
212- }
213-
214- // If not reconciling or stalled than mark Ready=True
215- if ! conditions .IsReconciling (obj ) && ! conditions .IsStalled (obj ) &&
216- err == nil && result .RequeueAfter == obj .GetRequeueAfter () {
217- conditions .MarkTrue (
218- obj ,
219- meta .ReadyCondition ,
220- meta .SucceededReason ,
221- "Reconciliation success" ,
222- )
223- event .New (
224- r .EventRecorder ,
225- obj ,
226- eventv1 .EventSeverityInfo ,
227- "Reconciliation succeeded" ,
228- nil ,
229- )
230- }
231-
232- // Set status observed generation option if the object is stalled or ready.
233- if conditions .IsStalled (obj ) || conditions .IsReady (obj ) {
234- obj .Status .ObservedGeneration = obj .Generation
235- event .New (
236- r .EventRecorder ,
237- obj ,
238- eventv1 .EventSeverityInfo ,
239- fmt .Sprintf ("Reconciliation finished, next run in %s" , obj .GetRequeueAfter ()),
240- map [string ]string {
241- v1alpha1 .GroupVersion .Group + "/configuration_digest" : obj .Status .LatestSnapshotDigest ,
242- },
243- )
244- }
245-
246- if perr := patchHelper .Patch (ctx , obj ); perr != nil {
247- err = errors .Join (err , perr )
177+ if derr := DeferredStatusUpdate (ctx , patchHelper , obj , r .EventRecorder , obj .GetRequeueAfter ()); derr != nil {
178+ err = errors .Join (err , derr )
248179 }
249180 }()
250181
251- logger .Info ("reconciling configuration" )
182+ // Starts the progression by setting ReconcilingCondition.
183+ // This will be checked in defer.
184+ // Should only be deleted on a success.
185+ rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "reconciliation in progress for configuration: %s" , obj .Name )
252186
253187 // check dependencies are ready
254188 ready , err := r .checkReadiness (ctx , obj .GetNamespace (), & obj .Spec .SourceRef )
255189 if err != nil {
256- logger .Info ("source ref object is not ready with error" , "error" , err )
190+ r .markAsFailed (obj , "SourceRefNotReadyWithError" , err .Error (), "source ref not yet ready with error: %s" , obj .Spec .SourceRef .Name )
191+
257192 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
258193 }
259194 if ! ready {
260- logger .Info (
261- "source ref object is not ready" ,
262- "source" ,
263- obj .Spec .SourceRef .GetNamespacedName (),
264- )
195+ r .markAsFailed (obj , "SourceRefNotReady" , "source not ready yet" , "source ref not yet ready: %s" , obj .Spec .SourceRef .Name )
196+
265197 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
266198 }
267199
268200 if obj .Spec .ConfigRef != nil {
269201 ready , err := r .checkReadiness (ctx , obj .GetNamespace (), obj .Spec .ConfigRef )
270202 if err != nil {
271- logger .Info ("config ref object is not ready with error" , "error" , err )
203+ r .markAsFailed (obj , "ConfigRefNotReadyWithError" , err .Error (), "config ref not yet ready with error: %s" , obj .Spec .ConfigRef .Name )
204+
272205 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
273206 }
274207 if ! ready {
275- logger .Info (
276- "config ref object is not ready" ,
277- "source" ,
278- obj .Spec .SourceRef .GetNamespacedName (),
279- )
208+ r .markAsFailed (obj , "ConfigRefNotReady" , "config ref not ready" , "config ref not yet ready: %s" , obj .Spec .ConfigRef .Name )
209+
280210 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
281211 }
282212 }
283213
284214 if obj .Spec .PatchStrategicMerge != nil {
285215 ready , err := r .checkFluxSourceReadiness (ctx , obj .Spec .PatchStrategicMerge .Source .SourceRef )
286216 if err != nil {
287- logger .Info ("source object is not ready with error" , "error" , err )
217+ r .markAsFailed (obj , "PatchStrategicMergeSourceRefNotReadyWithError" , err .Error (), "patch strategic merge source ref not yet ready with error: %s" , obj .Spec .PatchStrategicMerge .Source .SourceRef .Name )
218+
288219 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
289220 }
290221
291222 if ! ready {
292- ref := obj .Spec .PatchStrategicMerge .Source .SourceRef
293- logger .Info (
294- "patch git repository object is not ready" ,
295- "gitrepository" ,
296- (types.NamespacedName {Namespace : ref .Namespace , Name : ref .Name }).String (),
297- )
223+ r .markAsFailed (obj , "PatchStrategicMergeSourceRefNotReady" , "patch strategic merge source not ready yet" , "patch strategic merge source ref not yet ready: %s" , obj .Spec .PatchStrategicMerge .Source .SourceRef .Name )
224+
298225 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
299226 }
300227 }
@@ -304,9 +231,13 @@ func (r *ConfigurationReconciler) Reconcile(
304231 if obj .GetSnapshotName () == "" {
305232 name , err := snapshot .GenerateSnapshotName (obj .GetName ())
306233 if err != nil {
234+ r .markAsFailed (obj , "GenerateSnapshotNameError" , err .Error (), "failed to generate snapshot name for: %s" , obj .GetName ())
235+
307236 return ctrl.Result {}, err
308237 }
238+
309239 obj .Status .SnapshotName = name
240+
310241 return ctrl.Result {Requeue : true }, nil
311242 }
312243
@@ -338,31 +269,25 @@ func (r *ConfigurationReconciler) reconcile(
338269
339270 if errors .Is (err , errTar ) {
340271 err = fmt .Errorf ("source resource is not a tar archive: %w" , err )
341- conditions .MarkFalse (
342- obj ,
343- meta .ReadyCondition ,
344- v1alpha1 .SourceReasonNotATarArchiveReason ,
345- err .Error (),
346- )
272+ r .markAsFailed (obj , v1alpha1 .SourceReasonNotATarArchiveReason , err .Error (), "source is not a tar archive" )
273+
347274 return ctrl.Result {}, err
348275 }
349276
350277 err = fmt .Errorf ("failed to reconcile mutation object: %w" , err )
351- conditions .MarkFalse (
352- obj ,
353- meta .ReadyCondition ,
354- v1alpha1 .ReconcileMutationObjectFailedReason ,
355- err .Error (),
356- )
278+ r .markAsFailed (obj , v1alpha1 .ReconcileMutationObjectFailedReason , err .Error (), "failed to reconcile mutation object" )
279+
357280 return ctrl.Result {}, err
358281 }
359282
360283 obj .Status .ObservedGeneration = obj .GetGeneration ()
361284
362- // Remove any stale Ready condition, most likely False, set above. Its value
363- // is derived from the overall result of the reconciliation in the deferred
364- // bcfgk at the very end.
365- conditions .Delete (obj , meta .ReadyCondition )
285+ conditions .MarkTrue (obj ,
286+ meta .ReadyCondition ,
287+ meta .SucceededReason ,
288+ "Reconciliation success" )
289+
290+ conditions .Delete (obj , meta .ReconcilingCondition )
366291
367292 return ctrl.Result {RequeueAfter : obj .GetRequeueAfter ()}, nil
368293}
@@ -527,3 +452,9 @@ func makeRequestsForConfigurations(ll ...v1alpha1.Configuration) []reconcile.Req
527452
528453 return requests
529454}
455+
456+ func (r * ConfigurationReconciler ) markAsFailed (obj * v1alpha1.Configuration , reason , msg , format string , messageArgs ... any ) {
457+ rreconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , format , messageArgs ... )
458+ conditions .MarkFalse (obj , meta .ReadyCondition , reason , msg )
459+ event .New (r .EventRecorder , obj , eventv1 .EventSeverityError , msg , nil )
460+ }
0 commit comments