diff --git a/docs/spec/v2/helmreleases.md b/docs/spec/v2/helmreleases.md index 5104e19de..d2003d335 100644 --- a/docs/spec/v2/helmreleases.md +++ b/docs/spec/v2/helmreleases.md @@ -1685,7 +1685,6 @@ attempted to perform a Helm install or upgrade with in the The digest is used to determine if the controller should reset the [failure counters](#failure-counters) due to a change in the values. - ### Last Attempted Revision The helm-controller reports the revision of the Helm chart it last attempted diff --git a/internal/controller/helmrelease_controller.go b/internal/controller/helmrelease_controller.go index 9d0220e7c..3b210256a 100644 --- a/internal/controller/helmrelease_controller.go +++ b/internal/controller/helmrelease_controller.go @@ -353,11 +353,13 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "reconciliation in progress") } - // Attempt to adopt "legacy" v2beta1 release state on a best-effort basis. - // If this fails, the controller will fall back to performing an upgrade - // to settle on the desired state. - // TODO(hidde): remove this in a future release. + // Keep feature flagged code paths separate from the main reconciliation + // logic to ensure easy removal when the feature flag is removed. if ok, _ := features.Enabled(features.AdoptLegacyReleases); ok { + // Attempt to adopt "legacy" v2beta1 release state on a best-effort basis. + // If this fails, the controller will fall back to performing an upgrade + // to settle on the desired state. + // TODO(hidde): remove this in a future release. if err := r.adoptLegacyRelease(ctx, getter, obj); err != nil { log.Error(err, "failed to adopt v2beta1 release state") } diff --git a/internal/controller/helmrelease_controller_test.go b/internal/controller/helmrelease_controller_test.go index d998a6ef6..c2b66c3a5 100644 --- a/internal/controller/helmrelease_controller_test.go +++ b/internal/controller/helmrelease_controller_test.go @@ -1197,9 +1197,6 @@ func TestHelmReleaseReconciler_reconcileReleaseFromHelmChartSource(t *testing.T) chartMock := testutil.BuildChart() chartArtifact, err := testutil.SaveChartAsArtifact(chartMock, digest.SHA256, testServer.URL(), testServer.Root()) g.Expect(err).ToNot(HaveOccurred()) - // copy the artifact to mutate the revision - ociArtifact := chartArtifact.DeepCopy() - ociArtifact.Revision += "@" + chartArtifact.Digest ns, err := testEnv.CreateNamespace(context.TODO(), "mock") g.Expect(err).ToNot(HaveOccurred()) diff --git a/internal/postrender/build.go b/internal/postrender/build.go index 96ea800e9..66855808b 100644 --- a/internal/postrender/build.go +++ b/internal/postrender/build.go @@ -19,10 +19,10 @@ package postrender import ( "encoding/json" + "github.com/opencontainers/go-digest" helmpostrender "helm.sh/helm/v3/pkg/postrender" v2 "github.com/fluxcd/helm-controller/api/v2" - "github.com/opencontainers/go-digest" ) // BuildPostRenderers creates the post-renderer instances from a HelmRelease diff --git a/internal/reconcile/release_test.go b/internal/reconcile/release_test.go index 9c050cf1e..621f1f62e 100644 --- a/internal/reconcile/release_test.go +++ b/internal/reconcile/release_test.go @@ -25,11 +25,14 @@ import ( "helm.sh/helm/v3/pkg/chart" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/fluxcd/pkg/apis/kustomize" "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/conditions" v2 "github.com/fluxcd/helm-controller/api/v2" "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/postrender" ) const ( @@ -37,67 +40,121 @@ const ( mockReleaseNamespace = "mock-ns" ) +var ( + postRenderers = []v2.PostRenderer{ + { + Kustomize: &v2.Kustomize{ + Patches: []kustomize.Patch{ + { + Target: &kustomize.Selector{ + Kind: "Deployment", + Name: "test", + }, + Patch: `|- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: test + spec: + replicas: 2 + `, + }, + }, + }, + }, + } + + postRenderers2 = []v2.PostRenderer{ + { + Kustomize: &v2.Kustomize{ + Patches: []kustomize.Patch{ + { + Target: &kustomize.Selector{ + Kind: "Deployment", + Name: "test", + }, + Patch: `|- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: test + spec: + replicas: 3 + `, + }, + }, + }, + }, + } +) + func Test_summarize(t *testing.T) { tests := []struct { - name string - generation int64 - spec *v2.HelmReleaseSpec - conditions []metav1.Condition - expect []metav1.Condition + name string + generation int64 + spec *v2.HelmReleaseSpec + status v2.HelmReleaseStatus + expectedStatus *v2.HelmReleaseStatus }{ { name: "summarize conditions", generation: 1, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, - }, - }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, + }, + }, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, }, }, }, { name: "with tests enabled", generation: 1, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionTrue, - Reason: v2.TestSucceededReason, - Message: "test hook(s) succeeded", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hook(s) succeeded", + ObservedGeneration: 1, + }, }, }, spec: &v2.HelmReleaseSpec{ @@ -105,47 +162,51 @@ func Test_summarize(t *testing.T) { Enable: true, }, }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionTrue, - Reason: v2.TestSucceededReason, - Message: "test hook(s) succeeded", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionTrue, - Reason: v2.TestSucceededReason, - Message: "test hook(s) succeeded", - ObservedGeneration: 1, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hook(s) succeeded", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hook(s) succeeded", + ObservedGeneration: 1, + }, }, }, }, { name: "with tests enabled and failure tests", generation: 1, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, }, }, spec: &v2.HelmReleaseSpec{ @@ -153,46 +214,50 @@ func Test_summarize(t *testing.T) { Enable: true, }, }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, }, }, }, { name: "with test hooks enabled and pending tests", - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionUnknown, - Reason: "AwaitingTests", - Message: "Release is awaiting tests", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionUnknown, + Reason: "AwaitingTests", + Message: "Release is awaiting tests", + ObservedGeneration: 1, + }, }, }, spec: &v2.HelmReleaseSpec{ @@ -200,54 +265,58 @@ func Test_summarize(t *testing.T) { Enable: true, }, }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionUnknown, - Reason: "AwaitingTests", - Message: "Release is awaiting tests", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionUnknown, - Reason: "AwaitingTests", - Message: "Release is awaiting tests", - ObservedGeneration: 1, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionUnknown, + Reason: "AwaitingTests", + Message: "Release is awaiting tests", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionUnknown, + Reason: "AwaitingTests", + Message: "Release is awaiting tests", + ObservedGeneration: 1, + }, }, }, }, { name: "with remediation failure", generation: 1, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionFalse, - Reason: v2.UninstallFailedReason, - Message: "Uninstall failure", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UninstallFailedReason, + Message: "Uninstall failure", + ObservedGeneration: 1, + }, }, }, spec: &v2.HelmReleaseSpec{ @@ -255,112 +324,122 @@ func Test_summarize(t *testing.T) { Enable: true, }, }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionFalse, - Reason: v2.UninstallFailedReason, - Message: "Uninstall failure", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.InstallSucceededReason, - Message: "Install complete", - ObservedGeneration: 1, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 1, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionFalse, - Reason: v2.UninstallFailedReason, - Message: "Uninstall failure", - ObservedGeneration: 1, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionFalse, + Reason: v2.UninstallFailedReason, + Message: "Uninstall failure", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 1, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UninstallFailedReason, + Message: "Uninstall failure", + ObservedGeneration: 1, + }, }, }, }, { name: "with remediation success", generation: 1, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionFalse, - Reason: v2.UpgradeFailedReason, - Message: "Upgrade failure", - ObservedGeneration: 1, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionTrue, - Reason: v2.RollbackSucceededReason, - Message: "Uninstall complete", - ObservedGeneration: 1, - }, - }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionFalse, - Reason: v2.RollbackSucceededReason, - Message: "Uninstall complete", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionFalse, - Reason: v2.UpgradeFailedReason, - Message: "Upgrade failure", - ObservedGeneration: 1, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionTrue, - Reason: v2.RollbackSucceededReason, - Message: "Uninstall complete", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UpgradeFailedReason, + Message: "Upgrade failure", + ObservedGeneration: 1, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Uninstall complete", + ObservedGeneration: 1, + }, + }, + }, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionFalse, + Reason: v2.RollbackSucceededReason, + Message: "Uninstall complete", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UpgradeFailedReason, + Message: "Upgrade failure", + ObservedGeneration: 1, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Uninstall complete", + ObservedGeneration: 1, + }, }, }, }, { name: "with stale ready", generation: 1, - conditions: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionFalse, - Reason: "ChartNotFound", - Message: "chart not found", - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 1, - }, - }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 1, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionFalse, + Reason: "ChartNotFound", + Message: "chart not found", + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 1, + }, + }, + }, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 1, + }, }, }, }, @@ -372,61 +451,104 @@ func Test_summarize(t *testing.T) { Enable: true, }, }, - conditions: []metav1.Condition{ - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 4, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionTrue, - Reason: v2.RollbackSucceededReason, - Message: "Rollback finished", - ObservedGeneration: 3, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 2, - }, - }, - expect: []metav1.Condition{ - { - Type: meta.ReadyCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 5, - }, - { - Type: v2.ReleasedCondition, - Status: metav1.ConditionTrue, - Reason: v2.UpgradeSucceededReason, - Message: "Upgrade finished", - ObservedGeneration: 4, - }, - { - Type: v2.RemediatedCondition, - Status: metav1.ConditionTrue, - Reason: v2.RollbackSucceededReason, - Message: "Rollback finished", - ObservedGeneration: 3, - }, - { - Type: v2.TestSuccessCondition, - Status: metav1.ConditionFalse, - Reason: v2.TestFailedReason, - Message: "test hook(s) failure", - ObservedGeneration: 2, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 4, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Rollback finished", + ObservedGeneration: 3, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 2, + }, + }, + }, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 5, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 4, + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Rollback finished", + ObservedGeneration: 3, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionFalse, + Reason: v2.TestFailedReason, + Message: "test hook(s) failure", + ObservedGeneration: 2, + }, }, }, }, + { + name: "with postrender", + generation: 1, + status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + }, + ObservedPostRenderersDigest: postrender.Digest(digest.Canonical, postRenderers).String(), + }, + spec: &v2.HelmReleaseSpec{ + PostRenderers: postRenderers2, + }, + expectedStatus: &v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Install complete", + ObservedGeneration: 1, + }, + }, + ObservedPostRenderersDigest: postrender.Digest(digest.Canonical, postRenderers2).String(), + }, + }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) @@ -435,16 +557,15 @@ func Test_summarize(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Generation: tt.generation, }, - Status: v2.HelmReleaseStatus{ - Conditions: tt.conditions, - }, + Status: tt.status, } if tt.spec != nil { obj.Spec = *tt.spec.DeepCopy() } summarize(&Request{Object: obj}) - g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expect)) + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectedStatus.Conditions)) + g.Expect(obj.Status.ObservedPostRenderersDigest).To(Equal(tt.expectedStatus.ObservedPostRenderersDigest)) }) } } diff --git a/internal/reconcile/state_test.go b/internal/reconcile/state_test.go index 2a53980c2..bbd844f94 100644 --- a/internal/reconcile/state_test.go +++ b/internal/reconcile/state_test.go @@ -35,7 +35,9 @@ import ( v2 "github.com/fluxcd/helm-controller/api/v2" "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/digest" "github.com/fluxcd/helm-controller/internal/kube" + "github.com/fluxcd/helm-controller/internal/postrender" "github.com/fluxcd/helm-controller/internal/release" "github.com/fluxcd/helm-controller/internal/testutil" ) @@ -452,6 +454,34 @@ func Test_DetermineReleaseState(t *testing.T) { Status: ReleaseStatusOutOfSync, }, }, + { + name: "postRenderers changed", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.PostRenderers = postRenderers2 + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + ObservedPostRenderersDigest: postrender.Digest(digest.Canonical, postRenderers).String(), + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusOutOfSync, + }, + }, } for _, tt := range tests {