Skip to content

Commit d023277

Browse files
committed
controller: start w/ adding tests for HelmRelease
This adds base coverage for some of the simpler methods which do not require extensive mocking. Signed-off-by: Hidde Beydals <hidde@hhh.computer>
1 parent 18eb679 commit d023277

File tree

3 files changed

+469
-73
lines changed

3 files changed

+469
-73
lines changed

internal/controller/helmrelease_controller.go

+49-53
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
intacl "github.com/fluxcd/helm-controller/internal/acl"
2423
"time"
2524

2625
"github.com/hashicorp/go-retryablehttp"
2726
corev1 "k8s.io/api/core/v1"
28-
"k8s.io/apimachinery/pkg/runtime"
2927
"k8s.io/apimachinery/pkg/types"
3028
apierrors "k8s.io/apimachinery/pkg/util/errors"
3129
"k8s.io/cli-runtime/pkg/genericclioptions"
@@ -53,6 +51,7 @@ import (
5351
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
5452

5553
v2 "github.com/fluxcd/helm-controller/api/v2beta2"
54+
intacl "github.com/fluxcd/helm-controller/internal/acl"
5655
"github.com/fluxcd/helm-controller/internal/action"
5756
"github.com/fluxcd/helm-controller/internal/chartutil"
5857
"github.com/fluxcd/helm-controller/internal/digest"
@@ -67,11 +66,9 @@ type HelmReleaseReconciler struct {
6766
kuberecorder.EventRecorder
6867
helper.Metrics
6968

70-
Config *rest.Config
71-
Scheme *runtime.Scheme
72-
73-
ClientOpts runtimeClient.Options
74-
KubeConfigOpts runtimeClient.KubeConfigOptions
69+
GetClusterConfig func() (*rest.Config, error)
70+
ClientOpts runtimeClient.Options
71+
KubeConfigOpts runtimeClient.KubeConfigOptions
7572

7673
PollingOpts polling.Options
7774
StatusPoller *polling.StatusPoller
@@ -209,7 +206,7 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
209206
if c := len(obj.Spec.DependsOn); c > 0 {
210207
log.Info(fmt.Sprintf("checking %d dependencies", c))
211208

212-
if err := r.checkDependencies(obj); err != nil {
209+
if err := r.checkDependencies(ctx, obj); err != nil {
213210
msg := fmt.Sprintf("dependencies do not meet ready condition (%s): retrying in %s",
214211
err.Error(), r.requeueDependency.String())
215212
r.Eventf(obj, obj.Status.Current.ChartVersion, corev1.EventTypeWarning, err.Error())
@@ -317,46 +314,40 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
317314
// reconcileDelete deletes the v1beta2.HelmChart of the v2beta2.HelmRelease,
318315
// and uninstalls the Helm release if the resource has not been suspended.
319316
func (r *HelmReleaseReconciler) reconcileDelete(ctx context.Context, obj *v2.HelmRelease) (ctrl.Result, error) {
320-
if obj.Status.Current != nil {
321-
// Only uninstall the Helm Release if the resource is not suspended.
322-
if !obj.Spec.Suspend {
323-
// Build client getter.
324-
getter, err := r.buildRESTClientGetter(ctx, obj)
325-
if err != nil {
326-
conditions.MarkFalse(obj, meta.ReadyCondition, "GetterError", err.Error())
327-
return ctrl.Result{}, err
328-
}
329-
330-
// Attempt to uninstall the release.
331-
err = r.reconcileUninstall(ctx, getter, obj)
332-
if err != nil && !errors.Is(err, intreconcile.ErrNoCurrent) {
333-
return ctrl.Result{}, err
334-
}
335-
if err == nil {
336-
ctrl.LoggerFrom(ctx).Info("uninstalled Helm release for deleted resource")
337-
}
317+
// Only uninstall the Helm Release if the resource is not suspended.
318+
if !obj.Spec.Suspend {
319+
// Build client getter.
320+
getter, err := r.buildRESTClientGetter(ctx, obj)
321+
if err != nil {
322+
conditions.MarkFalse(obj, meta.ReadyCondition, "GetterError", err.Error())
323+
return ctrl.Result{}, err
324+
}
338325

339-
// Truncate the current release details in the status.
340-
obj.Status.Current = nil
341-
obj.Status.StorageNamespace = ""
342-
} else {
343-
ctrl.LoggerFrom(ctx).Info("skipping Helm uninstall for suspended resource")
326+
// Attempt to uninstall the release.
327+
if err = r.reconcileUninstall(ctx, getter, obj); err != nil && !errors.Is(err, intreconcile.ErrNoCurrent) {
328+
return ctrl.Result{}, err
329+
}
330+
if err == nil {
331+
ctrl.LoggerFrom(ctx).Info("uninstalled Helm release for deleted resource")
344332
}
345-
}
346333

347-
// Delete the HelmChart resource.
348-
if err := r.reconcileChartTemplate(ctx, obj); err != nil {
349-
return ctrl.Result{}, err
334+
// Truncate the current release details in the status.
335+
obj.Status.Current = nil
336+
obj.Status.StorageNamespace = ""
337+
338+
// Delete the HelmChart resource.
339+
if err := r.reconcileChartTemplate(ctx, obj); err != nil {
340+
return ctrl.Result{}, err
341+
}
342+
} else {
343+
ctrl.LoggerFrom(ctx).Info("skipping Helm uninstall and chart removal for suspended resource")
350344
}
351345

352-
if !obj.DeletionTimestamp.IsZero() {
353-
// Remove our finalizer from the list.
354-
controllerutil.RemoveFinalizer(obj, v2.HelmReleaseFinalizer)
346+
// Remove our finalizer from the list.
347+
controllerutil.RemoveFinalizer(obj, v2.HelmReleaseFinalizer)
355348

356-
// Stop reconciliation as the object is being deleted.
357-
return ctrl.Result{}, nil
358-
}
359-
return ctrl.Result{Requeue: true}, nil
349+
// Stop reconciliation as the object is being deleted.
350+
return ctrl.Result{}, nil
360351
}
361352

362353
// reconcileChartTemplate reconciles the HelmChart template from the HelmRelease.
@@ -384,23 +375,23 @@ func (r *HelmReleaseReconciler) reconcileUninstall(ctx context.Context, getter g
384375
// are Ready.
385376
// It returns an error if a dependency can not be retrieved or is not Ready,
386377
// otherwise nil.
387-
func (r *HelmReleaseReconciler) checkDependencies(obj *v2.HelmRelease) error {
378+
func (r *HelmReleaseReconciler) checkDependencies(ctx context.Context, obj *v2.HelmRelease) error {
388379
for _, d := range obj.Spec.DependsOn {
389-
if d.Namespace == "" {
390-
d.Namespace = obj.GetNamespace()
391-
}
392-
dName := types.NamespacedName{
380+
ref := types.NamespacedName{
393381
Namespace: d.Namespace,
394382
Name: d.Name,
395383
}
384+
if ref.Namespace == "" {
385+
ref.Namespace = obj.GetNamespace()
386+
}
387+
396388
dHr := &v2.HelmRelease{}
397-
err := r.Get(context.Background(), dName, dHr)
398-
if err != nil {
399-
return fmt.Errorf("unable to get '%s' dependency: %w", dName, err)
389+
if err := r.Get(ctx, ref, dHr); err != nil {
390+
return fmt.Errorf("unable to get '%s' dependency: %w", ref, err)
400391
}
401392

402-
if dHr.Generation != dHr.Status.ObservedGeneration || len(dHr.Status.Conditions) == 0 || !conditions.IsTrue(dHr, meta.ReadyCondition) {
403-
return fmt.Errorf("dependency '%s' is not ready", dName)
393+
if dHr.Generation != dHr.Status.ObservedGeneration || !conditions.IsTrue(dHr, meta.ReadyCondition) {
394+
return fmt.Errorf("dependency '%s' is not ready", ref)
404395
}
405396
}
406397
return nil
@@ -431,7 +422,12 @@ func (r *HelmReleaseReconciler) buildRESTClientGetter(ctx context.Context, obj *
431422
}
432423
return kube.NewMemoryRESTClientGetter(kubeConfig, opts...), nil
433424
}
434-
return kube.NewInClusterMemoryRESTClientGetter(opts...)
425+
426+
cfg, err := r.GetClusterConfig()
427+
if err != nil {
428+
return nil, fmt.Errorf("could not get in-cluster REST config: %w", err)
429+
}
430+
return kube.NewMemoryRESTClientGetter(cfg, opts...), nil
435431
}
436432

437433
// getHelmChart retrieves the v1beta2.HelmChart for the given v2beta2.HelmRelease

0 commit comments

Comments
 (0)