@@ -208,11 +208,18 @@ func (r *AppWrapperReconciler) Reconcile(ctx context.Context, req ctrl.Request)
208
208
209
209
// Handle Success
210
210
if podStatus .succeeded >= podStatus .expected && (podStatus .pending + podStatus .running + podStatus .failed == 0 ) {
211
+ msg := fmt .Sprintf ("%v pods succeeded and no running, pending, or failed pods" , podStatus .succeeded )
211
212
meta .SetStatusCondition (& aw .Status .Conditions , metav1.Condition {
212
213
Type : string (workloadv1beta2 .QuotaReserved ),
213
214
Status : metav1 .ConditionFalse ,
214
215
Reason : string (workloadv1beta2 .AppWrapperSucceeded ),
215
- Message : fmt .Sprintf ("%v pods succeeded and no running, pending, or failed pods" , podStatus .succeeded ),
216
+ Message : msg ,
217
+ })
218
+ meta .SetStatusCondition (& aw .Status .Conditions , metav1.Condition {
219
+ Type : string (workloadv1beta2 .ResourcesDeployed ),
220
+ Status : metav1 .ConditionTrue ,
221
+ Reason : string (workloadv1beta2 .AppWrapperSucceeded ),
222
+ Message : msg ,
216
223
})
217
224
return r .updateStatus (ctx , aw , workloadv1beta2 .AppWrapperSucceeded )
218
225
}
@@ -370,6 +377,29 @@ func (r *AppWrapperReconciler) Reconcile(ctx context.Context, req ctrl.Request)
370
377
Message : "No resources deployed" ,
371
378
})
372
379
return ctrl.Result {}, r .Status ().Update (ctx , aw )
380
+
381
+ case workloadv1beta2 .AppWrapperSucceeded :
382
+ if meta .IsStatusConditionTrue (aw .Status .Conditions , string (workloadv1beta2 .ResourcesDeployed )) {
383
+ deletionDelay := r .timeToLiveAfterSucceededDuration (ctx , aw )
384
+ whenSucceeded := meta .FindStatusCondition (aw .Status .Conditions , string (workloadv1beta2 .ResourcesDeployed )).LastTransitionTime
385
+ now := time .Now ()
386
+ deadline := whenSucceeded .Add (deletionDelay )
387
+ if now .Before (deadline ) {
388
+ return ctrl.Result {RequeueAfter : deadline .Sub (now )}, r .Status ().Update (ctx , aw )
389
+ }
390
+
391
+ if ! r .deleteComponents (ctx , aw ) {
392
+ return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
393
+ }
394
+ meta .SetStatusCondition (& aw .Status .Conditions , metav1.Condition {
395
+ Type : string (workloadv1beta2 .ResourcesDeployed ),
396
+ Status : metav1 .ConditionFalse ,
397
+ Reason : string (workloadv1beta2 .AppWrapperSucceeded ),
398
+ Message : fmt .Sprintf ("Time to live after success of %v expired" , deletionDelay ),
399
+ })
400
+ return ctrl.Result {}, r .Status ().Update (ctx , aw )
401
+ }
402
+ return ctrl.Result {}, nil
373
403
}
374
404
375
405
return ctrl.Result {}, nil
@@ -495,6 +525,19 @@ func (r *AppWrapperReconciler) debuggingFailureDeletionDelay(ctx context.Context
495
525
return 0 * time .Second
496
526
}
497
527
528
+ func (r * AppWrapperReconciler ) timeToLiveAfterSucceededDuration (ctx context.Context , aw * workloadv1beta2.AppWrapper ) time.Duration {
529
+ if userPeriod , ok := aw .Annotations [workloadv1beta2 .SuccessTTLDurationAnnotation ]; ok {
530
+ if duration , err := time .ParseDuration (userPeriod ); err == nil {
531
+ if duration > 0 && duration < r .Config .FaultTolerance .SuccessTTLCeiling {
532
+ return duration
533
+ }
534
+ } else {
535
+ log .FromContext (ctx ).Info ("Malformed successTTL annotation" , "annotation" , userPeriod , "error" , err )
536
+ }
537
+ }
538
+ return r .Config .FaultTolerance .SuccessTTLCeiling
539
+ }
540
+
498
541
func clearCondition (aw * workloadv1beta2.AppWrapper , condition workloadv1beta2.AppWrapperCondition , reason string , message string ) {
499
542
if meta .IsStatusConditionTrue (aw .Status .Conditions , string (condition )) {
500
543
meta .SetStatusCondition (& aw .Status .Conditions , metav1.Condition {
0 commit comments