Skip to content

Commit

Permalink
Allow adding reconciliation extensions (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
misberner authored and ludydoo committed Jun 27, 2023
1 parent df2bae4 commit a8cc213
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 2 deletions.
12 changes: 12 additions & 0 deletions pkg/extensions/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package extensions

import (
"context"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// ReconcileExtension is an arbitrary extension that can be implemented to run either before
// or after the main Helm reconciliation action.
// An error returned by a ReconcileExtension will cause the Reconcile to fail, unlike a hook error.
type ReconcileExtension func(context.Context, *unstructured.Unstructured, logr.Logger) error
69 changes: 67 additions & 2 deletions pkg/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
"github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/updater"
internalvalues "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/values"
"github.com/operator-framework/helm-operator-plugins/pkg/values"
"github.com/joelanford/helm-operator/pkg/extensions"
)

const uninstallFinalizer = "uninstall-helm-release"
Expand All @@ -70,6 +71,9 @@ type Reconciler struct {
preHooks []hook.PreHook
postHooks []hook.PostHook

preExtensions []extensions.ReconcileExtension
postExtensions []extensions.ReconcileExtension

log logr.Logger
gvk *schema.GroupVersionKind
chrt *chart.Chart
Expand Down Expand Up @@ -423,6 +427,20 @@ func WithPreHook(h hook.PreHook) Option {
}
}

// WithPreExtension is an Option that configures the reconciler to run the given
// extension before performing any reconciliation steps (including values translation).
// An error returned from the extension will cause the reconciliation to fail.
// This should be preferred to WithPreHook in most cases, except for when the logic
// depends on the translated Helm values.
// The extension will be invoked with the raw object state; meaning it needs to be careful
// to check for existence of the deletionTimestamp field.
func WithPreExtension(e extensions.ReconcileExtension) Option {
return func(r *Reconciler) error {
r.preExtensions = append(r.preExtensions, e)
return nil
}
}

// WithPostHook is an Option that configures the reconciler to run the given
// PostHook just after performing any non-uninstall release actions.
func WithPostHook(h hook.PostHook) Option {
Expand All @@ -432,6 +450,22 @@ func WithPostHook(h hook.PostHook) Option {
}
}

// WithPostExtension is an Option that configures the reconciler to run the given
// extension after performing any reconciliation steps (including uninstall of the release,
// but not removal of the finalizer).
// An error returned from the extension will cause the reconciliation to fail, which might
// prevent the finalizer from getting removed.
// This should be preferred to WithPostHook in most cases, except for when the logic
// depends on the translated Helm values.
// The extension will be invoked with the raw object state; meaning it needs to be careful
// to check for existence of the deletionTimestamp field.
func WithPostExtension(e extensions.ReconcileExtension) Option {
return func(r *Reconciler) error {
r.postExtensions = append(r.postExtensions, e)
return nil
}
}

// WithValueTranslator is an Option that configures a function that translates a
// custom resource to the values passed to Helm.
// Use this if you need to customize the logic that translates your custom resource to Helm values.
Expand Down Expand Up @@ -566,6 +600,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.
}
u.UpdateStatus(updater.EnsureCondition(conditions.Initialized(corev1.ConditionTrue, "", "")))

for _, ext := range r.preExtensions {
if err := ext(ctx, obj, r.log); err != nil {
u.UpdateStatus(
updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonReconcileError, err)),
updater.EnsureConditionUnknown(conditions.TypeReleaseFailed),
)
return ctrl.Result{}, err
}
}

if obj.GetDeletionTimestamp() != nil {
err := r.handleDeletion(ctx, actionClient, obj, log)
return ctrl.Result{}, err
Expand Down Expand Up @@ -625,6 +669,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.
}
}

for _, ext := range r.postExtensions {
if err := ext(ctx, obj, r.log); err != nil {
u.UpdateStatus(
updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonReconcileError, err)),
updater.EnsureConditionUnknown(conditions.TypeReleaseFailed),
)
return ctrl.Result{}, err
}
}

ensureDeployedRelease(&u, rel)
u.UpdateStatus(
updater.EnsureCondition(conditions.ReleaseFailed(corev1.ConditionFalse, "", "")),
Expand Down Expand Up @@ -679,7 +733,7 @@ func (r *Reconciler) handleDeletion(ctx context.Context, actionClient helmclient
err = applyErr
}
}()
return r.doUninstall(actionClient, &uninstallUpdater, obj, log)
return r.doUninstall(ctx, actionClient, &uninstallUpdater, obj, log)
}(); err != nil {
return err
}
Expand Down Expand Up @@ -825,7 +879,7 @@ func (r *Reconciler) doReconcile(actionClient helmclient.ActionInterface, u *upd
return nil
}

func (r *Reconciler) doUninstall(actionClient helmclient.ActionInterface, u *updater.Updater, obj *unstructured.Unstructured, log logr.Logger) error {
func (r *Reconciler) doUninstall(ctx context.Context, actionClient helmclient.ActionInterface, u *updater.Updater, obj *unstructured.Unstructured, log logr.Logger) error {
var opts []helmclient.UninstallOption
for name, annot := range r.uninstallAnnotations {
if v, ok := obj.GetAnnotations()[name]; ok {
Expand All @@ -850,6 +904,17 @@ func (r *Reconciler) doUninstall(actionClient helmclient.ActionInterface, u *upd
fmt.Println(diff.Generate(resp.Release.Manifest, ""))
}
}

for _, ext := range r.postExtensions {
if err := ext(ctx, obj, r.log); err != nil {
u.UpdateStatus(
updater.EnsureCondition(conditions.Irreconcilable(corev1.ConditionTrue, conditions.ReasonReconcileError, err)),
updater.EnsureConditionUnknown(conditions.TypeReleaseFailed),
)
return err
}
}

u.Update(updater.RemoveFinalizer(uninstallFinalizer))
u.UpdateStatus(
updater.EnsureCondition(conditions.ReleaseFailed(corev1.ConditionFalse, "", "")),
Expand Down

0 comments on commit a8cc213

Please sign in to comment.