@@ -91,8 +91,8 @@ func (r *AppWrapperReconciler) Reconcile(ctx context.Context, req ctrl.Request)
9191 // handle deletion
9292 if ! appWrapper .DeletionTimestamp .IsZero () {
9393 // delete wrapped resources
94- if r . deleteResources (ctx , appWrapper ) != 0 {
95- // deletion is pending, requeue reconciliation after delay
94+ if ! r . delete (ctx , appWrapper , * appWrapper . DeletionTimestamp ) {
95+ // requeue reconciliation after delay
9696 return ctrl.Result {RequeueAfter : deletionDelay }, nil
9797 }
9898 // remove finalizer
@@ -103,7 +103,7 @@ func (r *AppWrapperReconciler) Reconcile(ctx context.Context, req ctrl.Request)
103103 }
104104 // remove AppWrapper from cache
105105 r .deleteCachedPhase (appWrapper )
106- log .FromContext (ctx ).Info ("Deleted" , "state" , "Deleted" )
106+ log .FromContext (ctx ).Info ("Deleted" )
107107 return ctrl.Result {}, nil
108108 }
109109
@@ -116,63 +116,70 @@ func (r *AppWrapperReconciler) Reconcile(ctx context.Context, req ctrl.Request)
116116 return ctrl.Result {}, err
117117 }
118118 }
119- // set queued status only after adding finalizer
120- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Queued )
119+ // set queued/idle status only after adding finalizer
120+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Queued , mcadv1beta1 . Idle )
121121
122122 case mcadv1beta1 .Queued , mcadv1beta1 .Succeeded :
123123 r .triggerDispatch ()
124124 return ctrl.Result {}, nil
125125
126- case mcadv1beta1 .Dispatching :
127- // create wrapped resources
128- err , fatal := r . createResources ( ctx , appWrapper )
129- if err != nil {
130- if fatal {
131- return r .updateStatus (ctx , appWrapper , mcadv1beta1 . Failed , err .Error ())
126+ case mcadv1beta1 .Running :
127+ switch appWrapper . Status . Step {
128+ case mcadv1beta1 . Creating :
129+ // create wrapped resources
130+ if err , fatal := r . createResources ( ctx , appWrapper ); err != nil {
131+ return r .requeueOrFail (ctx , appWrapper , fatal , err .Error ())
132132 }
133- return r .requeueOrFail (ctx , appWrapper , err .Error ())
134- }
135- // set running status only after successfully requesting the creation of all resources
136- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Running )
133+ // set running/created status only after successfully requesting the creation of all resources
134+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Running , mcadv1beta1 .Created )
137135
138- case mcadv1beta1 .Running :
139- // count AppWrapper pods
140- counts , err := r .countPods (ctx , appWrapper )
141- if err != nil {
142- return ctrl.Result {}, err
143- }
144- // check pod count if dispatched for a while
145- if isSlowDispatching (appWrapper ) && counts .Running + counts .Succeeded < int (appWrapper .Spec .Scheduling .MinAvailable ) {
136+ case mcadv1beta1 .Created :
137+ // count AppWrapper pods
138+ counts , err := r .countPods (ctx , appWrapper )
139+ if err != nil {
140+ return ctrl.Result {}, err
141+ }
142+ // check pod count if dispatched for a while
143+ if metav1 .Now ().After (appWrapper .Status .DispatchTimestamp .Add (time .Duration (appWrapper .Spec .Scheduling .Requeuing .TimeInSeconds )* time .Second )) &&
144+ counts .Running + counts .Succeeded < int (appWrapper .Spec .Scheduling .MinAvailable ) {
145+ customMessage := "expected pods " + strconv .Itoa (int (appWrapper .Spec .Scheduling .MinAvailable )) + " but found pods " + strconv .Itoa (counts .Running + counts .Succeeded )
146+ // requeue or fail if max retries exhausted with custom error message
147+ return r .requeueOrFail (ctx , appWrapper , false , customMessage )
148+ }
149+ // check for successful completion by looking at pods and wrapped resources
150+ success , err := r .isSuccessful (ctx , appWrapper , counts )
151+ if err != nil {
152+ return ctrl.Result {}, err
153+ }
154+ // set succeeded/idle status if done
155+ if success {
156+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Succeeded , mcadv1beta1 .Idle )
157+ }
158+ // AppWrapper is healthy, requeue reconciliation after delay
159+ return ctrl.Result {RequeueAfter : runDelay }, nil
146160
147- customMessage := "expected pods " + strconv .Itoa (int (appWrapper .Spec .Scheduling .MinAvailable )) + " but found pods " + strconv .Itoa (counts .Running + counts .Succeeded )
148- // requeue or fail if max retries exhausted with custom error message
149- return r .requeueOrFail (ctx , appWrapper , customMessage )
150- }
151- // check for successful completion by looking at pods and wrapped resources
152- success , err := r .isSuccessful (ctx , appWrapper , counts )
153- if err != nil {
154- return ctrl.Result {}, err
155- }
156- // set succeeded status if done
157- if success {
158- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Succeeded )
161+ case mcadv1beta1 .Deleting :
162+ // delete wrapped resources
163+ if ! r .delete (ctx , appWrapper , appWrapper .Status .RequeueTimestamp ) {
164+ // requeue reconciliation after delay
165+ return ctrl.Result {RequeueAfter : deletionDelay }, nil
166+ }
167+ // reset status to queued/idle
168+ appWrapper .Status .Restarts += 1
169+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Queued , mcadv1beta1 .Idle )
159170 }
160- // AppWrapper is healthy, requeue reconciliation after delay
161- return ctrl.Result {RequeueAfter : runDelay }, nil
162171
163- case mcadv1beta1 .Requeuing :
164- // delete wrapped resources
165- if r .deleteResources (ctx , appWrapper ) != 0 {
166- if ! isSlowRequeuing (appWrapper ) {
172+ case mcadv1beta1 .Failed :
173+ switch appWrapper .Status .Step {
174+ case mcadv1beta1 .Deleting :
175+ // delete wrapped resources
176+ if ! r .delete (ctx , appWrapper , appWrapper .Status .RequeueTimestamp ) {
167177 // requeue reconciliation after delay
168178 return ctrl.Result {RequeueAfter : deletionDelay }, nil
169179 }
170- // forcefully delete wrapped resources and pods
171- r . forceDelete (ctx , appWrapper )
180+ // set status to failed/idle
181+ return r . updateStatus (ctx , appWrapper , mcadv1beta1 . Failed , mcadv1beta1 . Idle )
172182 }
173- // reset status to queued
174- appWrapper .Status .Restarts += 1
175- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Queued )
176183 }
177184 return ctrl.Result {}, nil
178185}
@@ -208,32 +215,39 @@ func (r *AppWrapperReconciler) podMapFunc(ctx context.Context, obj client.Object
208215}
209216
210217// Update AppWrapper status
211- func (r * AppWrapperReconciler ) updateStatus (ctx context.Context , appWrapper * mcadv1beta1.AppWrapper , phase mcadv1beta1.AppWrapperPhase , reason ... string ) (ctrl.Result , error ) {
218+ func (r * AppWrapperReconciler ) updateStatus (ctx context.Context , appWrapper * mcadv1beta1.AppWrapper , phase mcadv1beta1.AppWrapperPhase , step mcadv1beta1. AppWrapperStep , reason ... string ) (ctrl.Result , error ) {
212219 // log transition
213220 now := metav1 .Now ()
214- transition := mcadv1beta1.AppWrapperTransition {Time : now , Phase : phase }
221+ transition := mcadv1beta1.AppWrapperTransition {Time : now , Phase : phase , Step : step }
215222 if len (reason ) > 0 {
216223 transition .Reason = reason [0 ]
217224 }
218225 appWrapper .Status .Transitions = append (appWrapper .Status .Transitions , transition )
219226 appWrapper .Status .Phase = phase
227+ appWrapper .Status .Step = step
220228 // update AppWrapper status in etcd, requeue reconciliation on failure
221229 if err := r .Status ().Update (ctx , appWrapper ); err != nil {
222230 return ctrl.Result {}, err
223231 }
224232 // cache AppWrapper status
225233 r .addCachedPhase (appWrapper )
226- log .FromContext (ctx ).Info (string (phase ), "state" , string ( phase ) )
234+ log .FromContext (ctx ).Info (string (phase ), "state" , phase , "step" , step )
227235 return ctrl.Result {}, nil
228236}
229237
230- // Set requeuing or failed status depending on restarts count
231- func (r * AppWrapperReconciler ) requeueOrFail (ctx context.Context , appWrapper * mcadv1beta1.AppWrapper , reason string ) (ctrl.Result , error ) {
232- if appWrapper .Status .Restarts < appWrapper .Spec .Scheduling .Requeuing .MaxNumRequeuings {
238+ // Set requeuing or failed status depending on error, configuration, and restarts count
239+ func (r * AppWrapperReconciler ) requeueOrFail (ctx context.Context , appWrapper * mcadv1beta1.AppWrapper , fatal bool , reason string ) (ctrl.Result , error ) {
240+ if appWrapper .Spec .Scheduling .MinAvailable == 0 {
241+ // set failed status and leave resources as is
242+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Failed , appWrapper .Status .Step , reason )
243+ } else if fatal || appWrapper .Spec .Scheduling .Requeuing .MaxNumRequeuings > 0 && appWrapper .Status .Restarts >= appWrapper .Spec .Scheduling .Requeuing .MaxNumRequeuings {
244+ // set failed/deleting status (request deletion of wrapped resources)
233245 appWrapper .Status .RequeueTimestamp = metav1 .Now ()
234- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Requeuing , reason )
246+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Failed , mcadv1beta1 . Deleting , reason )
235247 }
236- return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Failed , reason )
248+ // requeue AppWrapper
249+ appWrapper .Status .RequeueTimestamp = metav1 .Now ()
250+ return r .updateStatus (ctx , appWrapper , mcadv1beta1 .Running , mcadv1beta1 .Deleting , reason )
237251}
238252
239253// Trigger dispatch by means of "*/*" request
@@ -270,18 +284,22 @@ func (r *AppWrapperReconciler) dispatch(ctx context.Context) (ctrl.Result, error
270284 }
271285 // set dispatching time and status
272286 appWrapper .Status .DispatchTimestamp = metav1 .Now ()
273- if _ , err := r .updateStatus (ctx , appWrapper , mcadv1beta1 .Dispatching ); err != nil {
287+ if _ , err := r .updateStatus (ctx , appWrapper , mcadv1beta1 .Running , mcadv1beta1 . Creating ); err != nil {
274288 return ctrl.Result {}, err
275289 }
276290 }
277291}
278292
279- // Is dispatching too slow?
280- func isSlowDispatching (appWrapper * mcadv1beta1.AppWrapper ) bool {
281- return metav1 .Now ().After (appWrapper .Status .DispatchTimestamp .Add (runningTimeout ))
282- }
283-
284- // Is requeuing too slow?
285- func isSlowRequeuing (appWrapper * mcadv1beta1.AppWrapper ) bool {
286- return metav1 .Now ().After (appWrapper .Status .RequeueTimestamp .Add (requeuingTimeout ))
293+ // Delete wrapped resources, forcing deletion after a delay
294+ func (r * AppWrapperReconciler ) delete (ctx context.Context , appWrapper * mcadv1beta1.AppWrapper , time metav1.Time ) bool {
295+ if r .deleteResources (ctx , appWrapper ) != 0 {
296+ // resources still exist
297+ if ! metav1 .Now ().After (time .Add (deletionTimeout )) {
298+ // there is still time
299+ return false
300+ }
301+ // force deletion
302+ r .forceDelete (ctx , appWrapper )
303+ }
304+ return true
287305}
0 commit comments