66 "net/http"
77 "os"
88 "path/filepath"
9+ "time"
910
1011 compositionMeta "github.com/krateoplatformops/composition-dynamic-controller/internal/meta"
1112
4041)
4142
4243const (
44+ reasonReconciliationGracefullyPaused event.Reason = "ReconciliationGracefullyPaused"
45+
4346 // Event reasons
4447 reasonCreated = "CompositionCreated"
4548 reasonDeleted = "CompositionDeleted"
@@ -98,6 +101,24 @@ func (h *handler) Observe(ctx context.Context, mg *unstructured.Unstructured) (c
98101 WithValues ("namespace" , mg .GetNamespace ())
99102
100103 compositionMeta .SetReleaseName (mg , mg .GetName ())
104+ if _ , p := compositionMeta .GetGracefullyPausedTime (mg ); p && compositionMeta .IsGracefullyPaused (mg ) {
105+ log .Debug ("Composition is gracefully paused, skipping observe." )
106+ h .eventRecorder .Event (mg , event .Normal (reasonReconciliationGracefullyPaused , "Observe" , "Reconciliation is paused via the gracefully paused annotation." ))
107+ return controller.ExternalObservation {
108+ ResourceExists : true ,
109+ ResourceUpToDate : true ,
110+ }, nil
111+ }
112+ // Immediately remove the gracefully paused time annotation if the composition is not gracefully paused.
113+ meta .RemoveAnnotations (mg , compositionMeta .AnnotationKeyReconciliationGracefullyPausedTime )
114+ mg , err := tools .Update (ctx , mg , tools.UpdateOptions {
115+ Pluralizer : h .pluralizer ,
116+ DynamicClient : h .dynamicClient ,
117+ })
118+ if err != nil {
119+ log .Debug ("Updating composition" , "error" , err )
120+ return controller.ExternalObservation {}, fmt .Errorf ("updating composition: %w" , err )
121+ }
101122
102123 if h .packageInfoGetter == nil {
103124 return controller.ExternalObservation {}, fmt .Errorf ("helm chart package info getter must be specified" )
@@ -220,21 +241,18 @@ func (h *handler) Observe(ctx context.Context, mg *unstructured.Unstructured) (c
220241 }, nil
221242 }
222243
223- err = setAvaibleStatus (mg , pkg , "Composition up-to-date" )
244+ err = setAvaibleStatus (mg , pkg , "Composition up-to-date" , false )
224245 if err != nil {
225246 log .Debug ("Setting available status" , "error" , err )
226247 return controller.ExternalObservation {}, err
227248 }
228- mg , err = tools .UpdateStatus (ctx , mg , tools.UpdateOptions {
229- Pluralizer : h .pluralizer ,
230- DynamicClient : h .dynamicClient ,
231- })
232249 if err != nil {
233250 log .Debug ("Updating cr status with condition" , "error" , err , "condition" , condition .Available ())
234251 return controller.ExternalObservation {}, err
235252 }
236253
237254 log .Debug ("Composition Observed - installed" , "package" , pkg .URL )
255+
238256 return controller.ExternalObservation {
239257 ResourceExists : true ,
240258 ResourceUpToDate : true ,
@@ -248,6 +266,12 @@ func (h *handler) Create(ctx context.Context, mg *unstructured.Unstructured) err
248266 WithValues ("name" , mg .GetName ()).
249267 WithValues ("namespace" , mg .GetNamespace ())
250268
269+ if _ , p := compositionMeta .GetGracefullyPausedTime (mg ); p && compositionMeta .IsGracefullyPaused (mg ) {
270+ log .Debug ("Composition is gracefully paused, skipping create." )
271+ h .eventRecorder .Event (mg , event .Normal (reasonReconciliationGracefullyPaused , "Update" , "Reconciliation is paused via the gracefully paused annotation." ))
272+ return nil
273+ }
274+
251275 compositionMeta .SetReleaseName (mg , mg .GetName ())
252276 mg , err := tools .Update (ctx , mg , tools.UpdateOptions {
253277 Pluralizer : h .pluralizer ,
@@ -343,12 +367,14 @@ func (h *handler) Create(ctx context.Context, mg *unstructured.Unstructured) err
343367 h .logger .Debug ("Composition created." , "package" , pkg .URL )
344368
345369 h .eventRecorder .Event (mg , event .Normal (reasonCreated , "Create" , fmt .Sprintf ("Composition created: %s" , mg .GetName ())))
346- err = setAvaibleStatus (mg , pkg , "Composition created" )
370+ err = setAvaibleStatus (mg , pkg , "Composition created" , true )
347371 if err != nil {
348372 log .Debug ("Setting available status" , "error" , err )
349373 return err
350374 }
351- _ , err = tools .UpdateStatus (ctx , mg , tools.UpdateOptions {
375+
376+ meta .RemoveAnnotations (mg , compositionMeta .AnnotationKeyReconciliationGracefullyPausedTime )
377+ _ , err = tools .Update (ctx , mg , tools.UpdateOptions {
352378 Pluralizer : h .pluralizer ,
353379 DynamicClient : h .dynamicClient ,
354380 })
@@ -362,6 +388,12 @@ func (h *handler) Update(ctx context.Context, mg *unstructured.Unstructured) err
362388 WithValues ("name" , mg .GetName ()).
363389 WithValues ("namespace" , mg .GetNamespace ())
364390
391+ if _ , p := compositionMeta .GetGracefullyPausedTime (mg ); p && compositionMeta .IsGracefullyPaused (mg ) {
392+ log .Debug ("Composition is gracefully paused, skipping update." )
393+ h .eventRecorder .Event (mg , event .Normal (reasonReconciliationGracefullyPaused , "Update" , "Reconciliation is paused via the gracefully paused annotation." ))
394+ return nil
395+ }
396+
365397 log .Debug ("Handling composition values update." )
366398
367399 if h .packageInfoGetter == nil {
@@ -402,16 +434,36 @@ func (h *handler) Update(ctx context.Context, mg *unstructured.Unstructured) err
402434 log .Debug ("Composition values updated." , "package" , pkg .URL )
403435
404436 h .eventRecorder .Event (mg , event .Normal (reasonUpdated , "Update" , fmt .Sprintf ("Updated composition: %s" , mg .GetName ())))
405- err = setAvaibleStatus (mg , pkg , "Composition values updated." )
406- if err != nil {
407- log .Debug ("Setting available status" , "error" , err )
408- return err
437+
438+ if compositionMeta .IsGracefullyPaused (mg ) {
439+ err = setGracefullyPausedCondition (mg , pkg )
440+ if err != nil {
441+ log .Debug ("Setting gracefully paused condition" , "error" , err )
442+ return err
443+ }
444+ compositionMeta .SetGracefullyPausedTime (mg , time .Now ())
445+ log .Debug ("Composition is gracefully paused." )
446+ h .eventRecorder .Event (mg , event .Normal (reasonReconciliationGracefullyPaused , "Update" , "Reconciliation is paused via the gracefully paused annotation." ))
447+ } else {
448+ // Normal behavior, set available status
449+ err = setAvaibleStatus (mg , pkg , "Composition values updated." , true )
450+ if err != nil {
451+ log .Debug ("Setting available status" , "error" , err )
452+ return err
453+ }
454+
455+ meta .RemoveAnnotations (mg , compositionMeta .AnnotationKeyReconciliationGracefullyPausedTime )
409456 }
410- _ , err = tools .UpdateStatus (ctx , mg , tools.UpdateOptions {
457+
458+ _ , err = tools .Update (ctx , mg , tools.UpdateOptions {
411459 Pluralizer : h .pluralizer ,
412460 DynamicClient : h .dynamicClient ,
413461 })
414- return err
462+ if err != nil {
463+ log .Debug ("Updating cr with values" , "error" , err )
464+ return err
465+ }
466+ return nil
415467}
416468
417469func (h * handler ) Delete (ctx context.Context , mg * unstructured.Unstructured ) error {
@@ -421,6 +473,12 @@ func (h *handler) Delete(ctx context.Context, mg *unstructured.Unstructured) err
421473 WithValues ("name" , mg .GetName ()).
422474 WithValues ("namespace" , mg .GetNamespace ())
423475
476+ if _ , p := compositionMeta .GetGracefullyPausedTime (mg ); p && compositionMeta .IsGracefullyPaused (mg ) {
477+ log .Debug ("Composition is gracefully paused, skipping delete." )
478+ h .eventRecorder .Event (mg , event .Normal (reasonReconciliationGracefullyPaused , "Delete" , "Reconciliation is paused via the gracefully paused annotation." ))
479+ return nil
480+ }
481+
424482 if h .packageInfoGetter == nil {
425483 return fmt .Errorf ("helm chart package info getter must be specified" )
426484 }
@@ -497,6 +555,16 @@ func (h *handler) Delete(ctx context.Context, mg *unstructured.Unstructured) err
497555
498556 h .eventRecorder .Event (mg , event .Normal (reasonDeleted , "Delete" , fmt .Sprintf ("Deleted composition: %s" , mg .GetName ())))
499557 log .Debug ("Composition package removed." , "package" , pkg .URL )
558+ meta .RemoveAnnotations (mg , compositionMeta .AnnotationKeyReconciliationGracefullyPausedTime )
559+
560+ _ , err = tools .Update (ctx , mg , tools.UpdateOptions {
561+ Pluralizer : h .pluralizer ,
562+ DynamicClient : h .dynamicClient ,
563+ })
564+ if err != nil {
565+ log .Debug ("Updating cr with values" , "error" , err )
566+ return fmt .Errorf ("updating cr with values: %w" , err )
567+ }
500568
501569 return nil
502570}
0 commit comments