Skip to content

Commit a847888

Browse files
committed
pkg/reconciler: handle deletion as soon as possible, improve condition reasons
1 parent 5d7ed5d commit a847888

File tree

2 files changed

+64
-60
lines changed

2 files changed

+64
-60
lines changed

pkg/reconciler/internal/conditions/conditions.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ const (
3232
ReasonUpgradeSuccessful = status.ConditionReason("UpgradeSuccessful")
3333
ReasonUninstallSuccessful = status.ConditionReason("UninstallSuccessful")
3434

35-
ReasonErrorGatheringState = status.ConditionReason("ErrorGatheringState")
36-
ReasonInstallError = status.ConditionReason("InstallError")
37-
ReasonUpgradeError = status.ConditionReason("UpgradeError")
38-
ReasonReconcileError = status.ConditionReason("ReconcileError")
39-
ReasonUninstallError = status.ConditionReason("UninstallError")
35+
ReasonErrorGettingClient = status.ConditionReason("ErrorGettingClient")
36+
ReasonErrorMappingValues = status.ConditionReason("ErrorMappingValues")
37+
ReasonErrorGettingReleaseState = status.ConditionReason("ErrorGettingReleaseState")
38+
ReasonInstallError = status.ConditionReason("InstallError")
39+
ReasonUpgradeError = status.ConditionReason("UpgradeError")
40+
ReasonReconcileError = status.ConditionReason("ReconcileError")
41+
ReasonUninstallError = status.ConditionReason("UninstallError")
4042
)
4143

4244
func Initialized(stat corev1.ConditionStatus, reason status.ConditionReason, message interface{}) status.Condition {

pkg/reconciler/reconciler.go

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -410,13 +410,18 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res ctrl.Result, err error) {
410410

411411
actionClient, err := r.actionClientGetter.ActionClientFor(obj)
412412
if err != nil {
413-
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorGatheringState, err)))
413+
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorGettingClient, err)))
414+
return ctrl.Result{}, err
415+
}
416+
417+
if obj.GetDeletionTimestamp() != nil {
418+
err := r.handleDeletion(ctx, actionClient, obj, log)
414419
return ctrl.Result{}, err
415420
}
416421

417422
vals, err := r.getValues(obj)
418423
if err != nil {
419-
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorGatheringState, err)))
424+
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorMappingValues, err)))
420425
return ctrl.Result{}, err
421426
}
422427

@@ -428,50 +433,14 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res ctrl.Result, err error) {
428433

429434
rel, state, err := r.getReleaseState(actionClient, obj, vals.AsMap())
430435
if err != nil {
431-
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorGatheringState, err)))
436+
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonErrorGettingReleaseState, err)))
432437
return ctrl.Result{}, err
433438
}
434-
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionFalse, "", "")))
435-
436-
switch state {
437-
case stateAlreadyUninstalled:
438-
log.Info("Resource is terminated, skipping reconciliation")
439-
return ctrl.Result{}, nil
440-
case stateNeedsUninstall:
441-
// Use defer in a closure so that it executes before we wait for
442-
// the deletion of the CR. This might seem unnecessary since we're
443-
// applying changes to the CR after is has a deletion timestamp.
444-
// However, if uninstall fails, the finalizer will not be removed
445-
// and we need to be able to update the conditions on the CR to
446-
// indicate that the uninstall failed.
447-
if err := func() (err error) {
448-
uninstallUpdater := updater.New(r.client)
449-
defer func() {
450-
applyErr := uninstallUpdater.Apply(ctx, obj)
451-
if err == nil {
452-
err = applyErr
453-
}
454-
}()
455-
return r.doUninstall(actionClient, &uninstallUpdater, obj, log)
456-
}(); err != nil {
457-
return ctrl.Result{}, err
458-
}
459-
460-
// Since the client is hitting a cache, waiting for the
461-
// deletion here will guarantee that the next reconciliation
462-
// will see that the CR has been deleted and that there's
463-
// nothing left to do.
464-
if err := controllerutil.WaitForDeletion(ctx, r.client, obj); err != nil {
465-
return ctrl.Result{}, err
466-
}
467-
468-
return ctrl.Result{}, nil
469-
}
470-
471-
u.UpdateStatus(updater.EnsureCondition(conditions.Initialized(corev1.ConditionTrue, "", "")))
472439
if rel != nil {
473440
ensureDeployedRelease(&u, rel)
474441
}
442+
u.UpdateStatus(updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionFalse, "", "")))
443+
u.UpdateStatus(updater.EnsureCondition(conditions.Initialized(corev1.ConditionTrue, "", "")))
475444

476445
switch state {
477446
case stateNeedsInstall:
@@ -495,7 +464,6 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res ctrl.Result, err error) {
495464
}
496465

497466
ensureDeployedRelease(&u, rel)
498-
499467
u.Update(updater.EnsureFinalizer(uninstallFinalizer))
500468
u.UpdateStatus(
501469
updater.EnsureCondition(conditions.ReleaseFailed(corev1.ConditionFalse, "", "")),
@@ -530,34 +498,68 @@ func (r *Reconciler) getValues(obj *unstructured.Unstructured) (chartutil.Values
530498
type helmReleaseState string
531499

532500
const (
533-
stateNeedsInstall helmReleaseState = "needs install"
534-
stateNeedsUpgrade helmReleaseState = "needs upgrade"
535-
stateNeedsUninstall helmReleaseState = "needs uninstall"
536-
stateUnchanged helmReleaseState = "unchanged"
537-
stateAlreadyUninstalled helmReleaseState = "already uninstalled"
538-
stateError helmReleaseState = "error"
501+
stateNeedsInstall helmReleaseState = "needs install"
502+
stateNeedsUpgrade helmReleaseState = "needs upgrade"
503+
stateUnchanged helmReleaseState = "unchanged"
504+
stateError helmReleaseState = "error"
539505
)
540506

507+
func (r *Reconciler) handleDeletion(ctx context.Context, actionClient helmclient.ActionInterface, obj *unstructured.Unstructured, log logr.Logger) error {
508+
if !controllerutil.ContainsFinalizer(obj, uninstallFinalizer) {
509+
log.Info("Resource is terminated, skipping reconciliation")
510+
return nil
511+
}
512+
513+
// Use defer in a closure so that it executes before we wait for
514+
// the deletion of the CR. This might seem unnecessary since we're
515+
// applying changes to the CR after is has a deletion timestamp.
516+
// However, if uninstall fails, the finalizer will not be removed
517+
// and we need to be able to update the conditions on the CR to
518+
// indicate that the uninstall failed.
519+
if err := func() (err error) {
520+
uninstallUpdater := updater.New(r.client)
521+
defer func() {
522+
applyErr := uninstallUpdater.Apply(ctx, obj)
523+
if err == nil {
524+
err = applyErr
525+
}
526+
}()
527+
return r.doUninstall(actionClient, &uninstallUpdater, obj, log)
528+
}(); err != nil {
529+
return err
530+
}
531+
532+
// Since the client is hitting a cache, waiting for the
533+
// deletion here will guarantee that the next reconciliation
534+
// will see that the CR has been deleted and that there's
535+
// nothing left to do.
536+
if err := controllerutil.WaitForDeletion(ctx, r.client, obj); err != nil {
537+
return err
538+
}
539+
return nil
540+
}
541+
541542
func (r *Reconciler) getReleaseState(client helmclient.ActionInterface, obj metav1.Object, vals map[string]interface{}) (*release.Release, helmReleaseState, error) {
542543
deployedRelease, err := client.Get(obj.GetName())
543544
if err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
544545
return nil, stateError, err
545546
}
546547

547-
if obj.GetDeletionTimestamp() != nil {
548-
if controllerutil.ContainsFinalizer(obj, uninstallFinalizer) {
549-
return deployedRelease, stateNeedsUninstall, nil
550-
}
551-
return deployedRelease, stateAlreadyUninstalled, nil
552-
}
553548
if errors.Is(err, driver.ErrReleaseNotFound) {
554549
return nil, stateNeedsInstall, nil
555550
}
556551

557-
specRelease, err := client.Upgrade(obj.GetName(), obj.GetNamespace(), r.chrt, vals, func(u *action.Upgrade) error {
552+
var opts []helmclient.UpgradeOption
553+
for name, annot := range r.upgradeAnnotations {
554+
if v, ok := obj.GetAnnotations()[name]; ok {
555+
opts = append(opts, annot.UpgradeOption(v))
556+
}
557+
}
558+
opts = append(opts, func(u *action.Upgrade) error {
558559
u.DryRun = true
559560
return nil
560561
})
562+
specRelease, err := client.Upgrade(obj.GetName(), obj.GetNamespace(), r.chrt, vals, opts...)
561563
if err != nil {
562564
return deployedRelease, stateError, err
563565
}

0 commit comments

Comments
 (0)