diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 0fb3f546a..4d5e961c4 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -169,7 +169,7 @@ jobs: kubectl -n helm-system apply -f config/testdata/$test_name echo -n ">>> Waiting for expected conditions" count=0 - until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .TestSuccess=="False" and .Ready=="False"' )" ]; do + until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .TestSuccess=="False" and .Ready=="False"' )" ]; do echo -n '.' sleep 5 count=$((count + 1)) @@ -213,7 +213,7 @@ jobs: fi kubectl -n helm-system delete -f config/testdata/$test_name - - name: Run install fail with remedition test + - name: Run install fail with remediation test run: | test_name=install-fail-remediate kubectl -n helm-system apply -f config/testdata/$test_name @@ -230,21 +230,22 @@ jobs: done echo ' done' - # Ensure release does not exist (was uninstalled). - HISTORY=$(helm -n helm-system history $test_name 2>&1; exit 0) - if [ "$HISTORY" != 'Error: release: not found' ]; then - echo -e "Unexpected release history: $HISTORY" + # Ensure release was uninstalled. + RELEASE_STATUS=$(helm -n helm-system history $test_name -o json | jq -r 'if length == 1 then .[0].status else empty end') + if [ "$RELEASE_STATUS" != "uninstalled" ]; then + echo -e "Unexpected release status: $RELEASE_STATUS" exit 1 fi kubectl -n helm-system delete -f config/testdata/$test_name + helm -n helm-system delete $test_name - name: Run install fail with retry test run: | test_name=install-fail-retry kubectl -n helm-system apply -f config/testdata/$test_name echo -n ">>> Waiting for expected conditions" count=0 - until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.installFailures == 2 and ( .status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" )' )" ]; do + until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.installFailures == 2 and ( .status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" and .Stalled=="True" )' )" ]; do echo -n '.' sleep 5 count=$((count + 1)) @@ -290,7 +291,7 @@ jobs: kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml echo -n ">>> Waiting for expected conditions" count=0 - until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False"' )" ]; do + until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" and .Stalled=="True"' )" ]; do echo -n '.' sleep 5 count=$((count + 1)) @@ -336,7 +337,7 @@ jobs: kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml echo -n ">>> Waiting for expected conditions" count=0 - until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .TestSuccess=="False" and .Ready=="False"' )" ]; do + until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .TestSuccess=="False" and .Ready=="False" and .Stalled=="True"' )" ]; do echo -n '.' sleep 5 count=$((count + 1)) @@ -558,7 +559,7 @@ jobs: exit 1 fi kubectl -n helm-system delete -f config/testdata/post-renderer-kustomize - - name: Boostrap CRDs Upgrade Tests + - name: Bootstrap CRDs Upgrade Tests if: ${{ startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/') }} run: | REF=${{ github.ref }} diff --git a/Makefile b/Makefile index ee5511adc..bfb6cec90 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,17 @@ BUILD_PLATFORMS ?= linux/amd64 # Architecture to use envtest with ENVTEST_ARCH ?= amd64 +# Paths to download the CRD dependency to. +CRD_DEP_ROOT ?= $(BUILD_DIR)/config/crd/bases + +# Keep a record of the version of the downloaded source CRDs. It is used to +# detect and download new CRDs when the SOURCE_VER changes. +SOURCE_VER ?= $(shell go list -m all | grep github.com/fluxcd/source-controller/api | awk '{print $$2}') +SOURCE_CRD_VER = $(CRD_DEP_ROOT)/.src-crd-$(SOURCE_VER) + +# HelmChart source CRD. +HELMCHART_SOURCE_CRD ?= $(CRD_DEP_ROOT)/source.toolkit.fluxcd.io_helmcharts.yaml + # API (doc) generation utilities CONTROLLER_GEN_VERSION ?= v0.12.0 GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113 @@ -35,7 +46,7 @@ all: manager # Run tests KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)" -test: tidy generate fmt vet manifests api-docs install-envtest +test: tidy generate fmt vet manifests api-docs install-envtest download-crd-deps KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) go test ./... -coverprofile cover.out cd api; go test ./... -coverprofile cover.out @@ -81,7 +92,7 @@ manifests: controller-gen # Generate API reference documentation api-docs: gen-crd-api-reference-docs - $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v2beta1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v2beta1/helm.md + $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v2beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v2beta2/helm.md # Run go mod tidy tidy: @@ -113,6 +124,24 @@ docker-build: docker-push: docker push ${IMG} +# Delete previously downloaded CRDs and record the new version of the source +# CRDs. +$(SOURCE_CRD_VER): + rm -f $(CRD_DEP_ROOT)/.src-crd* + mkdir -p $(CRD_DEP_ROOT) + $(MAKE) cleanup-crd-deps + touch $(SOURCE_CRD_VER) + +$(HELMCHART_SOURCE_CRD): + curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml > $(HELMCHART_SOURCE_CRD) + +# Download the CRDs the controller depends on +download-crd-deps: $(SOURCE_CRD_VER) $(HELMCHART_SOURCE_CRD) + +# Delete the downloaded CRD dependencies. +cleanup-crd-deps: + rm -f $(HELMCHART_SOURCE_CRD) + # Find or download controller-gen CONTROLLER_GEN = $(GOBIN)/controller-gen .PHONY: controller-gen diff --git a/PROJECT b/PROJECT index 4b09ffd52..200d2d5e4 100644 --- a/PROJECT +++ b/PROJECT @@ -4,4 +4,8 @@ resources: - group: helm kind: HelmRelease version: v2beta1 +- group: helm + kind: HelmRelease + version: v2beta2 +storageVersion: v2beta2 version: "2" diff --git a/api/go.mod b/api/go.mod index 46f8471a9..8f3dd950d 100644 --- a/api/go.mod +++ b/api/go.mod @@ -8,6 +8,7 @@ require ( k8s.io/apiextensions-apiserver v0.27.4 k8s.io/apimachinery v0.27.4 sigs.k8s.io/controller-runtime v0.15.1 + sigs.k8s.io/yaml v1.3.0 ) require ( diff --git a/api/go.sum b/api/go.sum index 4a51f5632..819d8c518 100644 --- a/api/go.sum +++ b/api/go.sum @@ -103,3 +103,4 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h6 sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/api/v2beta1/helmrelease_types.go b/api/v2beta1/helmrelease_types.go index 4678a35cc..028eddee1 100644 --- a/api/v2beta1/helmrelease_types.go +++ b/api/v2beta1/helmrelease_types.go @@ -28,6 +28,8 @@ import ( "github.com/fluxcd/pkg/apis/kustomize" "github.com/fluxcd/pkg/apis/meta" + + "github.com/fluxcd/helm-controller/api/v2beta2" ) const HelmReleaseKind = "HelmRelease" @@ -905,6 +907,46 @@ type HelmReleaseStatus struct { // state. It is reset after a successful reconciliation. // +optional UpgradeFailures int64 `json:"upgradeFailures,omitempty"` + + // StorageNamespace is the namespace of the Helm release storage for the + // current release. + // + // Note: this field is provisional to the v2beta2 API, and not actively used + // by v2beta1 HelmReleases. + // +optional + StorageNamespace string `json:"storageNamespace,omitempty"` + + // History holds the history of Helm releases performed for this HelmRelease + // up to the last successfully completed release. + // + // Note: this field is provisional to the v2beta2 API, and not actively used + // by v2beta1 HelmReleases. + // +optional + History v2beta2.Snapshots `json:"history,omitempty"` + + // LastAttemptedGeneration is the last generation the controller attempted + // to reconcile. + // + // Note: this field is provisional to the v2beta2 API, and not actively used + // by v2beta1 HelmReleases. + // +optional + LastAttemptedGeneration int64 `json:"lastAttemptedGeneration,omitempty"` + + // LastAttemptedConfigDigest is the digest for the config (better known as + // "values") of the last reconciliation attempt. + // + // Note: this field is provisional to the v2beta2 API, and not actively used + // by v2beta1 HelmReleases. + // +optional + LastAttemptedConfigDigest string `json:"lastAttemptedConfigDigest,omitempty"` + + // LastAttemptedReleaseAction is the last release action performed for this + // HelmRelease. It is used to determine the active remediation strategy. + // + // Note: this field is provisional to the v2beta2 API, and not actively used + // by v2beta1 HelmReleases. + // +optional + LastAttemptedReleaseAction string `json:"lastAttemptedReleaseAction,omitempty"` } // GetHelmChart returns the namespace and name of the HelmChart. diff --git a/api/v2beta1/zz_generated.deepcopy.go b/api/v2beta1/zz_generated.deepcopy.go index a224748e3..97962b7f3 100644 --- a/api/v2beta1/zz_generated.deepcopy.go +++ b/api/v2beta1/zz_generated.deepcopy.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2021 The Flux authors +Copyright 2022 The Flux authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ limitations under the License. package v2beta1 import ( + "github.com/fluxcd/helm-controller/api/v2beta2" "github.com/fluxcd/pkg/apis/kustomize" "github.com/fluxcd/pkg/apis/meta" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -299,6 +300,17 @@ func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.History != nil { + in, out := &in.History, &out.History + *out = make(v2beta2.Snapshots, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(v2beta2.Snapshot) + (*in).DeepCopyInto(*out) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus. diff --git a/api/v2beta2/condition_types.go b/api/v2beta2/condition_types.go new file mode 100644 index 000000000..10172dfb1 --- /dev/null +++ b/api/v2beta2/condition_types.go @@ -0,0 +1,98 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +const ( + // ReleasedCondition represents the status of the last release attempt + // (install/upgrade/test) against the latest desired state. + ReleasedCondition string = "Released" + + // TestSuccessCondition represents the status of the last test attempt against + // the latest desired state. + TestSuccessCondition string = "TestSuccess" + + // RemediatedCondition represents the status of the last remediation attempt + // (uninstall/rollback) due to a failure of the last release attempt against the + // latest desired state. + RemediatedCondition string = "Remediated" +) + +const ( + // InstallSucceededReason represents the fact that the Helm install for the + // HelmRelease succeeded. + InstallSucceededReason string = "InstallSucceeded" + + // InstallFailedReason represents the fact that the Helm install for the + // HelmRelease failed. + InstallFailedReason string = "InstallFailed" + + // UpgradeSucceededReason represents the fact that the Helm upgrade for the + // HelmRelease succeeded. + UpgradeSucceededReason string = "UpgradeSucceeded" + + // UpgradeFailedReason represents the fact that the Helm upgrade for the + // HelmRelease failed. + UpgradeFailedReason string = "UpgradeFailed" + + // TestSucceededReason represents the fact that the Helm tests for the + // HelmRelease succeeded. + TestSucceededReason string = "TestSucceeded" + + // TestFailedReason represents the fact that the Helm tests for the HelmRelease + // failed. + TestFailedReason string = "TestFailed" + + // RollbackSucceededReason represents the fact that the Helm rollback for the + // HelmRelease succeeded. + RollbackSucceededReason string = "RollbackSucceeded" + + // RollbackFailedReason represents the fact that the Helm test for the + // HelmRelease failed. + RollbackFailedReason string = "RollbackFailed" + + // UninstallSucceededReason represents the fact that the Helm uninstall for the + // HelmRelease succeeded. + UninstallSucceededReason string = "UninstallSucceeded" + + // UninstallFailedReason represents the fact that the Helm uninstall for the + // HelmRelease failed. + UninstallFailedReason string = "UninstallFailed" + + // ArtifactFailedReason represents the fact that the artifact download for the + // HelmRelease failed. + ArtifactFailedReason string = "ArtifactFailed" + + // InitFailedReason represents the fact that the initialization of the Helm + // configuration failed. + InitFailedReason string = "InitFailed" + + // GetLastReleaseFailedReason represents the fact that observing the last + // release failed. + GetLastReleaseFailedReason string = "GetLastReleaseFailed" + + // DependencyNotReadyReason represents the fact that + // one of the dependencies is not ready. + DependencyNotReadyReason string = "DependencyNotReady" + + // ReconciliationSucceededReason represents the fact that + // the reconciliation succeeded. + ReconciliationSucceededReason string = "ReconciliationSucceeded" + + // ReconciliationFailedReason represents the fact that + // the reconciliation failed. + ReconciliationFailedReason string = "ReconciliationFailed" +) diff --git a/api/v2beta2/doc.go b/api/v2beta2/doc.go new file mode 100644 index 000000000..282bff813 --- /dev/null +++ b/api/v2beta2/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v2beta2 contains API Schema definitions for the helm v2beta2 API group +// +kubebuilder:object:generate=true +// +groupName=helm.toolkit.fluxcd.io +package v2beta2 diff --git a/api/v2beta2/groupversion_info.go b/api/v2beta2/groupversion_info.go new file mode 100644 index 000000000..ea03d5f67 --- /dev/null +++ b/api/v2beta2/groupversion_info.go @@ -0,0 +1,33 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "helm.toolkit.fluxcd.io", Version: "v2beta2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v2beta2/helmrelease_types.go b/api/v2beta2/helmrelease_types.go new file mode 100644 index 000000000..ac7a8524f --- /dev/null +++ b/api/v2beta2/helmrelease_types.go @@ -0,0 +1,1138 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "strings" + "time" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/yaml" + + "github.com/fluxcd/pkg/apis/kustomize" + "github.com/fluxcd/pkg/apis/meta" +) + +const ( + // HelmReleaseKind is the kind in string format. + HelmReleaseKind = "HelmRelease" + // HelmReleaseFinalizer is set on a HelmRelease when it is first handled by + // the controller, and removed when this object is deleted. + HelmReleaseFinalizer = "finalizers.fluxcd.io" +) + +// Kustomize Helm PostRenderer specification. +type Kustomize struct { + // Strategic merge and JSON patches, defined as inline YAML objects, + // capable of targeting objects based on kind, label and annotation selectors. + // +optional + Patches []kustomize.Patch `json:"patches,omitempty"` + + // Strategic merge patches, defined as inline YAML objects. + // +optional + PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"` + + // JSON 6902 patches, defined as inline YAML objects. + // +optional + PatchesJSON6902 []kustomize.JSON6902Patch `json:"patchesJson6902,omitempty"` + + // Images is a list of (image name, new name, new tag or digest) + // for changing image names, tags or digests. This can also be achieved with a + // patch, but this operator is simpler to specify. + // +optional + Images []kustomize.Image `json:"images,omitempty" yaml:"images,omitempty"` +} + +// PostRenderer contains a Helm PostRenderer specification. +type PostRenderer struct { + // Kustomization to apply as PostRenderer. + // +optional + Kustomize *Kustomize `json:"kustomize,omitempty"` +} + +// HelmReleaseSpec defines the desired state of a Helm release. +type HelmReleaseSpec struct { + // Chart defines the template of the v1beta2.HelmChart that should be created + // for this HelmRelease. + // +required + Chart HelmChartTemplate `json:"chart"` + + // Interval at which to reconcile the Helm release. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +required + Interval metav1.Duration `json:"interval"` + + // KubeConfig for reconciling the HelmRelease on a remote cluster. + // When used in combination with HelmReleaseSpec.ServiceAccountName, + // forces the controller to act on behalf of that Service Account at the + // target cluster. + // If the --default-service-account flag is set, its value will be used as + // a controller level fallback for when HelmReleaseSpec.ServiceAccountName + // is empty. + // +optional + KubeConfig *meta.KubeConfigReference `json:"kubeConfig,omitempty"` + + // Suspend tells the controller to suspend reconciliation for this HelmRelease, + // it does not apply to already started reconciliations. Defaults to false. + // +optional + Suspend bool `json:"suspend,omitempty"` + + // ReleaseName used for the Helm release. Defaults to a composition of + // '[TargetNamespace-]Name'. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=53 + // +kubebuilder:validation:Optional + // +optional + ReleaseName string `json:"releaseName,omitempty"` + + // TargetNamespace to target when performing operations for the HelmRelease. + // Defaults to the namespace of the HelmRelease. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:Optional + // +optional + TargetNamespace string `json:"targetNamespace,omitempty"` + + // StorageNamespace used for the Helm storage. + // Defaults to the namespace of the HelmRelease. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:Optional + // +optional + StorageNamespace string `json:"storageNamespace,omitempty"` + + // DependsOn may contain a meta.NamespacedObjectReference slice with + // references to HelmRelease resources that must be ready before this HelmRelease + // can be reconciled. + // +optional + DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"` + + // Timeout is the time to wait for any individual Kubernetes operation (like Jobs + // for hooks) during the performance of a Helm action. Defaults to '5m0s'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // MaxHistory is the number of revisions saved by Helm for this HelmRelease. + // Use '0' for an unlimited number of revisions; defaults to '5'. + // +optional + MaxHistory *int `json:"maxHistory,omitempty"` + + // The name of the Kubernetes service account to impersonate + // when reconciling this HelmRelease. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // PersistentClient tells the controller to use a persistent Kubernetes + // client for this release. When enabled, the client will be reused for the + // duration of the reconciliation, instead of being created and destroyed + // for each (step of a) Helm action. + // + // This can improve performance, but may cause issues with some Helm charts + // that for example do create Custom Resource Definitions during installation + // outside Helm's CRD lifecycle hooks, which are then not observed to be + // available by e.g. post-install hooks. + // + // If not set, it defaults to true. + // + // +optional + PersistentClient *bool `json:"persistentClient,omitempty"` + + // Install holds the configuration for Helm install actions for this HelmRelease. + // +optional + Install *Install `json:"install,omitempty"` + + // Upgrade holds the configuration for Helm upgrade actions for this HelmRelease. + // +optional + Upgrade *Upgrade `json:"upgrade,omitempty"` + + // Test holds the configuration for Helm test actions for this HelmRelease. + // +optional + Test *Test `json:"test,omitempty"` + + // Rollback holds the configuration for Helm rollback actions for this HelmRelease. + // +optional + Rollback *Rollback `json:"rollback,omitempty"` + + // Uninstall holds the configuration for Helm uninstall actions for this HelmRelease. + // +optional + Uninstall *Uninstall `json:"uninstall,omitempty"` + + // ValuesFrom holds references to resources containing Helm values for this HelmRelease, + // and information about how they should be merged. + ValuesFrom []ValuesReference `json:"valuesFrom,omitempty"` + + // Values holds the values for this Helm release. + // +optional + Values *apiextensionsv1.JSON `json:"values,omitempty"` + + // PostRenderers holds an array of Helm PostRenderers, which will be applied in order + // of their definition. + // +optional + PostRenderers []PostRenderer `json:"postRenderers,omitempty"` +} + +// HelmChartTemplate defines the template from which the controller will +// generate a v1beta2.HelmChart object in the same namespace as the referenced +// v1.Source. +type HelmChartTemplate struct { + // ObjectMeta holds the template for metadata like labels and annotations. + // +optional + ObjectMeta *HelmChartTemplateObjectMeta `json:"metadata,omitempty"` + + // Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease. + // +required + Spec HelmChartTemplateSpec `json:"spec"` +} + +// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a +// v1beta2.HelmChart. +type HelmChartTemplateObjectMeta struct { + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + // +optional + Annotations map[string]string `json:"annotations,omitempty"` +} + +// HelmChartTemplateSpec defines the template from which the controller will +// generate a v1beta2.HelmChartSpec object. +type HelmChartTemplateSpec struct { + // The name or path the Helm chart is available at in the SourceRef. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=2048 + // +required + Chart string `json:"chart"` + + // Version semver expression, ignored for charts from v1beta2.GitRepository and + // v1beta2.Bucket sources. Defaults to latest when omitted. + // +kubebuilder:default:=* + // +optional + Version string `json:"version,omitempty"` + + // The name and namespace of the v1.Source the chart is available at. + // +required + SourceRef CrossNamespaceObjectReference `json:"sourceRef"` + + // Interval at which to check the v1.Source for updates. Defaults to + // 'HelmReleaseSpec.Interval'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Interval *metav1.Duration `json:"interval,omitempty"` + + // Determines what enables the creation of a new artifact. Valid values are + // ('ChartVersion', 'Revision'). + // See the documentation of the values for an explanation on their behavior. + // Defaults to ChartVersion when omitted. + // +kubebuilder:validation:Enum=ChartVersion;Revision + // +kubebuilder:default:=ChartVersion + // +optional + ReconcileStrategy string `json:"reconcileStrategy,omitempty"` + + // Alternative list of values files to use as the chart values (values.yaml + // is not included by default), expected to be a relative path in the SourceRef. + // Values files are merged in the order of this list with the last file overriding + // the first. Ignored when omitted. + // +optional + ValuesFiles []string `json:"valuesFiles,omitempty"` + + // Alternative values file to use as the default chart values, expected to + // be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, + // for backwards compatibility the file defined here is merged before the + // ValuesFiles items. Ignored when omitted. + // +optional + // +deprecated + ValuesFile string `json:"valuesFile,omitempty"` + + // Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + // This field is only supported for OCI sources. + // Chart dependencies, which are not bundled in the umbrella chart artifact, + // are not verified. + // +optional + Verify *HelmChartTemplateVerification `json:"verify,omitempty"` +} + +// GetInterval returns the configured interval for the v1beta2.HelmChart, +// or the given default. +func (in HelmChartTemplate) GetInterval(defaultInterval metav1.Duration) metav1.Duration { + if in.Spec.Interval == nil { + return defaultInterval + } + return *in.Spec.Interval +} + +// GetNamespace returns the namespace targeted namespace for the +// v1beta2.HelmChart, or the given default. +func (in HelmChartTemplate) GetNamespace(defaultNamespace string) string { + if in.Spec.SourceRef.Namespace == "" { + return defaultNamespace + } + return in.Spec.SourceRef.Namespace +} + +// HelmChartTemplateVerification verifies the authenticity of an OCI Helm chart. +type HelmChartTemplateVerification struct { + // Provider specifies the technology used to sign the OCI Helm chart. + // +kubebuilder:validation:Enum=cosign + // +kubebuilder:default:=cosign + Provider string `json:"provider"` + + // SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + // +optional + SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` +} + +// Remediation defines a consistent interface for InstallRemediation and +// UpgradeRemediation. +// +kubebuilder:object:generate=false +type Remediation interface { + GetRetries() int + MustIgnoreTestFailures(bool) bool + MustRemediateLastFailure() bool + GetStrategy() RemediationStrategy + GetFailureCount(hr *HelmRelease) int64 + IncrementFailureCount(hr *HelmRelease) + RetriesExhausted(hr *HelmRelease) bool +} + +// Install holds the configuration for Helm install actions performed for this +// HelmRelease. +type Install struct { + // Timeout is the time to wait for any individual Kubernetes operation (like + // Jobs for hooks) during the performance of a Helm install action. Defaults to + // 'HelmReleaseSpec.Timeout'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Remediation holds the remediation configuration for when the Helm install + // action for the HelmRelease fails. The default is to not perform any action. + // +optional + Remediation *InstallRemediation `json:"remediation,omitempty"` + + // DisableWait disables the waiting for resources to be ready after a Helm + // install has been performed. + // +optional + DisableWait bool `json:"disableWait,omitempty"` + + // DisableWaitForJobs disables waiting for jobs to complete after a Helm + // install has been performed. + // +optional + DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"` + + // DisableHooks prevents hooks from running during the Helm install action. + // +optional + DisableHooks bool `json:"disableHooks,omitempty"` + + // DisableOpenAPIValidation prevents the Helm install action from validating + // rendered templates against the Kubernetes OpenAPI Schema. + // +optional + DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"` + + // Replace tells the Helm install action to re-use the 'ReleaseName', but only + // if that name is a deleted release which remains in the history. + // +optional + Replace bool `json:"replace,omitempty"` + + // SkipCRDs tells the Helm install action to not install any CRDs. By default, + // CRDs are installed if not already present. + // + // Deprecated use CRD policy (`crds`) attribute with value `Skip` instead. + // + // +deprecated + // +optional + SkipCRDs bool `json:"skipCRDs,omitempty"` + + // CRDs upgrade CRDs from the Helm Chart's crds directory according + // to the CRD upgrade policy provided here. Valid values are `Skip`, + // `Create` or `CreateReplace`. Default is `Create` and if omitted + // CRDs are installed but not updated. + // + // Skip: do neither install nor replace (update) any CRDs. + // + // Create: new CRDs are created, existing CRDs are neither updated nor deleted. + // + // CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + // but not deleted. + // + // By default, CRDs are applied (installed) during Helm install action. + // With this option users can opt in to CRD replace existing CRDs on Helm + // install actions, which is not (yet) natively supported by Helm. + // https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + // + // +kubebuilder:validation:Enum=Skip;Create;CreateReplace + // +optional + CRDs CRDsPolicy `json:"crds,omitempty"` + + // CreateNamespace tells the Helm install action to create the + // HelmReleaseSpec.TargetNamespace if it does not exist yet. + // On uninstall, the namespace will not be garbage collected. + // +optional + CreateNamespace bool `json:"createNamespace,omitempty"` +} + +// GetTimeout returns the configured timeout for the Helm install action, +// or the given default. +func (in Install) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration { + if in.Timeout == nil { + return defaultTimeout + } + return *in.Timeout +} + +// GetRemediation returns the configured Remediation for the Helm install action. +func (in Install) GetRemediation() Remediation { + if in.Remediation == nil { + return InstallRemediation{} + } + return *in.Remediation +} + +// InstallRemediation holds the configuration for Helm install remediation. +type InstallRemediation struct { + // Retries is the number of retries that should be attempted on failures before + // bailing. Remediation, using an uninstall, is performed between each attempt. + // Defaults to '0', a negative integer equals to unlimited retries. + // +optional + Retries int `json:"retries,omitempty"` + + // IgnoreTestFailures tells the controller to skip remediation when the Helm + // tests are run after an install action but fail. Defaults to + // 'Test.IgnoreFailures'. + // +optional + IgnoreTestFailures *bool `json:"ignoreTestFailures,omitempty"` + + // RemediateLastFailure tells the controller to remediate the last failure, when + // no retries remain. Defaults to 'false'. + // +optional + RemediateLastFailure *bool `json:"remediateLastFailure,omitempty"` +} + +// GetRetries returns the number of retries that should be attempted on +// failures. +func (in InstallRemediation) GetRetries() int { + return in.Retries +} + +// MustIgnoreTestFailures returns the configured IgnoreTestFailures or the given +// default. +func (in InstallRemediation) MustIgnoreTestFailures(def bool) bool { + if in.IgnoreTestFailures == nil { + return def + } + return *in.IgnoreTestFailures +} + +// MustRemediateLastFailure returns whether to remediate the last failure when +// no retries remain. +func (in InstallRemediation) MustRemediateLastFailure() bool { + if in.RemediateLastFailure == nil { + return false + } + return *in.RemediateLastFailure +} + +// GetStrategy returns the strategy to use for failure remediation. +func (in InstallRemediation) GetStrategy() RemediationStrategy { + return UninstallRemediationStrategy +} + +// GetFailureCount gets the failure count. +func (in InstallRemediation) GetFailureCount(hr *HelmRelease) int64 { + return hr.Status.InstallFailures +} + +// IncrementFailureCount increments the failure count. +func (in InstallRemediation) IncrementFailureCount(hr *HelmRelease) { + hr.Status.InstallFailures++ +} + +// RetriesExhausted returns true if there are no remaining retries. +func (in InstallRemediation) RetriesExhausted(hr *HelmRelease) bool { + return in.Retries >= 0 && in.GetFailureCount(hr) > int64(in.Retries) +} + +// CRDsPolicy defines the install/upgrade approach to use for CRDs when +// installing or upgrading a HelmRelease. +type CRDsPolicy string + +const ( + // Skip CRDs do neither install nor replace (update) any CRDs. + Skip CRDsPolicy = "Skip" + // Create CRDs which do not already exist, do not replace (update) already existing + // CRDs and keep (do not delete) CRDs which no longer exist in the current release. + Create CRDsPolicy = "Create" + // Create CRDs which do not already exist, Replace (update) already existing CRDs + // and keep (do not delete) CRDs which no longer exist in the current release. + CreateReplace CRDsPolicy = "CreateReplace" +) + +// Upgrade holds the configuration for Helm upgrade actions for this +// HelmRelease. +type Upgrade struct { + // Timeout is the time to wait for any individual Kubernetes operation (like + // Jobs for hooks) during the performance of a Helm upgrade action. Defaults to + // 'HelmReleaseSpec.Timeout'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Remediation holds the remediation configuration for when the Helm upgrade + // action for the HelmRelease fails. The default is to not perform any action. + // +optional + Remediation *UpgradeRemediation `json:"remediation,omitempty"` + + // DisableWait disables the waiting for resources to be ready after a Helm + // upgrade has been performed. + // +optional + DisableWait bool `json:"disableWait,omitempty"` + + // DisableWaitForJobs disables waiting for jobs to complete after a Helm + // upgrade has been performed. + // +optional + DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"` + + // DisableHooks prevents hooks from running during the Helm upgrade action. + // +optional + DisableHooks bool `json:"disableHooks,omitempty"` + + // DisableOpenAPIValidation prevents the Helm upgrade action from validating + // rendered templates against the Kubernetes OpenAPI Schema. + // +optional + DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"` + + // Force forces resource updates through a replacement strategy. + // +optional + Force bool `json:"force,omitempty"` + + // PreserveValues will make Helm reuse the last release's values and merge in + // overrides from 'Values'. Setting this flag makes the HelmRelease + // non-declarative. + // +optional + PreserveValues bool `json:"preserveValues,omitempty"` + + // CleanupOnFail allows deletion of new resources created during the Helm + // upgrade action when it fails. + // +optional + CleanupOnFail bool `json:"cleanupOnFail,omitempty"` + + // CRDs upgrade CRDs from the Helm Chart's crds directory according + // to the CRD upgrade policy provided here. Valid values are `Skip`, + // `Create` or `CreateReplace`. Default is `Skip` and if omitted + // CRDs are neither installed nor upgraded. + // + // Skip: do neither install nor replace (update) any CRDs. + // + // Create: new CRDs are created, existing CRDs are neither updated nor deleted. + // + // CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + // but not deleted. + // + // By default, CRDs are not applied during Helm upgrade action. With this + // option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. + // https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + // + // +kubebuilder:validation:Enum=Skip;Create;CreateReplace + // +optional + CRDs CRDsPolicy `json:"crds,omitempty"` +} + +// GetTimeout returns the configured timeout for the Helm upgrade action, or the +// given default. +func (in Upgrade) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration { + if in.Timeout == nil { + return defaultTimeout + } + return *in.Timeout +} + +// GetRemediation returns the configured Remediation for the Helm upgrade +// action. +func (in Upgrade) GetRemediation() Remediation { + if in.Remediation == nil { + return UpgradeRemediation{} + } + return *in.Remediation +} + +// UpgradeRemediation holds the configuration for Helm upgrade remediation. +type UpgradeRemediation struct { + // Retries is the number of retries that should be attempted on failures before + // bailing. Remediation, using 'Strategy', is performed between each attempt. + // Defaults to '0', a negative integer equals to unlimited retries. + // +optional + Retries int `json:"retries,omitempty"` + + // IgnoreTestFailures tells the controller to skip remediation when the Helm + // tests are run after an upgrade action but fail. + // Defaults to 'Test.IgnoreFailures'. + // +optional + IgnoreTestFailures *bool `json:"ignoreTestFailures,omitempty"` + + // RemediateLastFailure tells the controller to remediate the last failure, when + // no retries remain. Defaults to 'false' unless 'Retries' is greater than 0. + // +optional + RemediateLastFailure *bool `json:"remediateLastFailure,omitempty"` + + // Strategy to use for failure remediation. Defaults to 'rollback'. + // +kubebuilder:validation:Enum=rollback;uninstall + // +optional + Strategy *RemediationStrategy `json:"strategy,omitempty"` +} + +// GetRetries returns the number of retries that should be attempted on +// failures. +func (in UpgradeRemediation) GetRetries() int { + return in.Retries +} + +// MustIgnoreTestFailures returns the configured IgnoreTestFailures or the given +// default. +func (in UpgradeRemediation) MustIgnoreTestFailures(def bool) bool { + if in.IgnoreTestFailures == nil { + return def + } + return *in.IgnoreTestFailures +} + +// MustRemediateLastFailure returns whether to remediate the last failure when +// no retries remain. +func (in UpgradeRemediation) MustRemediateLastFailure() bool { + if in.RemediateLastFailure == nil { + return in.Retries > 0 + } + return *in.RemediateLastFailure +} + +// GetStrategy returns the strategy to use for failure remediation. +func (in UpgradeRemediation) GetStrategy() RemediationStrategy { + if in.Strategy == nil { + return RollbackRemediationStrategy + } + return *in.Strategy +} + +// GetFailureCount gets the failure count. +func (in UpgradeRemediation) GetFailureCount(hr *HelmRelease) int64 { + return hr.Status.UpgradeFailures +} + +// IncrementFailureCount increments the failure count. +func (in UpgradeRemediation) IncrementFailureCount(hr *HelmRelease) { + hr.Status.UpgradeFailures++ +} + +// RetriesExhausted returns true if there are no remaining retries. +func (in UpgradeRemediation) RetriesExhausted(hr *HelmRelease) bool { + return in.Retries >= 0 && in.GetFailureCount(hr) > int64(in.Retries) +} + +// RemediationStrategy returns the strategy to use to remediate a failed install +// or upgrade. +type RemediationStrategy string + +const ( + // RollbackRemediationStrategy represents a Helm remediation strategy of Helm + // rollback. + RollbackRemediationStrategy RemediationStrategy = "rollback" + + // UninstallRemediationStrategy represents a Helm remediation strategy of Helm + // uninstall. + UninstallRemediationStrategy RemediationStrategy = "uninstall" +) + +// Test holds the configuration for Helm test actions for this HelmRelease. +type Test struct { + // Enable enables Helm test actions for this HelmRelease after an Helm install + // or upgrade action has been performed. + // +optional + Enable bool `json:"enable,omitempty"` + + // Timeout is the time to wait for any individual Kubernetes operation during + // the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // IgnoreFailures tells the controller to skip remediation when the Helm tests + // are run but fail. Can be overwritten for tests run after install or upgrade + // actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'. + // +optional + IgnoreFailures bool `json:"ignoreFailures,omitempty"` + + // Filters is a list of tests to run or exclude from running. + Filters *[]Filter `json:"filters,omitempty"` +} + +// GetTimeout returns the configured timeout for the Helm test action, +// or the given default. +func (in Test) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration { + if in.Timeout == nil { + return defaultTimeout + } + return *in.Timeout +} + +// Filter holds the configuration for individual Helm test filters. +type Filter struct { + // Name is the name of the test. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +required + Name string `json:"name"` + // Exclude specifies whether the named test should be excluded. + // +optional + Exclude bool `json:"exclude,omitempty"` +} + +// GetFilters returns the configured filters for the Helm test action/ +func (in Test) GetFilters() []Filter { + if in.Filters == nil { + var filters []Filter + return filters + } + return *in.Filters +} + +// Rollback holds the configuration for Helm rollback actions for this +// HelmRelease. +type Rollback struct { + // Timeout is the time to wait for any individual Kubernetes operation (like + // Jobs for hooks) during the performance of a Helm rollback action. Defaults to + // 'HelmReleaseSpec.Timeout'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // DisableWait disables the waiting for resources to be ready after a Helm + // rollback has been performed. + // +optional + DisableWait bool `json:"disableWait,omitempty"` + + // DisableWaitForJobs disables waiting for jobs to complete after a Helm + // rollback has been performed. + // +optional + DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"` + + // DisableHooks prevents hooks from running during the Helm rollback action. + // +optional + DisableHooks bool `json:"disableHooks,omitempty"` + + // Recreate performs pod restarts for the resource if applicable. + // +optional + Recreate bool `json:"recreate,omitempty"` + + // Force forces resource updates through a replacement strategy. + // +optional + Force bool `json:"force,omitempty"` + + // CleanupOnFail allows deletion of new resources created during the Helm + // rollback action when it fails. + // +optional + CleanupOnFail bool `json:"cleanupOnFail,omitempty"` +} + +// GetTimeout returns the configured timeout for the Helm rollback action, or +// the given default. +func (in Rollback) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration { + if in.Timeout == nil { + return defaultTimeout + } + return *in.Timeout +} + +// Uninstall holds the configuration for Helm uninstall actions for this +// HelmRelease. +type Uninstall struct { + // Timeout is the time to wait for any individual Kubernetes operation (like + // Jobs for hooks) during the performance of a Helm uninstall action. Defaults + // to 'HelmReleaseSpec.Timeout'. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // DisableHooks prevents hooks from running during the Helm rollback action. + // +optional + DisableHooks bool `json:"disableHooks,omitempty"` + + // KeepHistory tells Helm to remove all associated resources and mark the + // release as deleted, but retain the release history. + // +optional + KeepHistory bool `json:"keepHistory,omitempty"` + + // DisableWait disables waiting for all the resources to be deleted after + // a Helm uninstall is performed. + // +optional + DisableWait bool `json:"disableWait,omitempty"` + + // DeletionPropagation specifies the deletion propagation policy when + // a Helm uninstall is performed. + // +kubebuilder:default=background + // +kubebuilder:validation:Enum=background;foreground;orphan + // +optional + DeletionPropagation *string `json:"deletionPropagation,omitempty"` +} + +// GetTimeout returns the configured timeout for the Helm uninstall action, or +// the given default. +func (in Uninstall) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration { + if in.Timeout == nil { + return defaultTimeout + } + return *in.Timeout +} + +// GetDeletionPropagation returns the configured deletion propagation policy +// for the Helm uninstall action, or 'background'. +func (in Uninstall) GetDeletionPropagation() string { + if in.DeletionPropagation == nil { + return "background" + } + return *in.DeletionPropagation +} + +// ReleaseAction is the action to perform a Helm release. +type ReleaseAction string + +const ( + // ReleaseActionInstall represents a Helm install action. + ReleaseActionInstall ReleaseAction = "install" + // ReleaseActionUpgrade represents a Helm upgrade action. + ReleaseActionUpgrade ReleaseAction = "upgrade" +) + +// HelmReleaseStatus defines the observed state of a HelmRelease. +type HelmReleaseStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // LastAttemptedGeneration is the last generation the controller attempted + // to reconcile. + // +optional + LastAttemptedGeneration int64 `json:"lastAttemptedGeneration,omitempty"` + + // Conditions holds the conditions for the HelmRelease. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // HelmChart is the namespaced name of the HelmChart resource created by + // the controller for the HelmRelease. + // +optional + HelmChart string `json:"helmChart,omitempty"` + + // StorageNamespace is the namespace of the Helm release storage for the + // current release. + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Optional + // +optional + StorageNamespace string `json:"storageNamespace,omitempty"` + + // History holds the history of Helm releases performed for this HelmRelease + // up to the last successfully completed release. + // +optional + History Snapshots `json:"history,omitempty"` + + // LastAttemptedReleaseAction is the last release action performed for this + // HelmRelease. It is used to determine the active remediation strategy. + // +kubebuilder:validation:Enum=install;upgrade + // +optional + LastAttemptedReleaseAction ReleaseAction `json:"lastAttemptedReleaseAction,omitempty"` + + // Failures is the reconciliation failure count against the latest desired + // state. It is reset after a successful reconciliation. + // +optional + Failures int64 `json:"failures,omitempty"` + + // InstallFailures is the install failure count against the latest desired + // state. It is reset after a successful reconciliation. + // +optional + InstallFailures int64 `json:"installFailures,omitempty"` + + // UpgradeFailures is the upgrade failure count against the latest desired + // state. It is reset after a successful reconciliation. + // +optional + UpgradeFailures int64 `json:"upgradeFailures,omitempty"` + + // LastAppliedRevision is the revision of the last successfully applied + // source. + // Deprecated: the revision can now be found in the History. + // +optional + LastAppliedRevision string `json:"lastAppliedRevision,omitempty"` + + // LastAttemptedRevision is the Source revision of the last reconciliation + // attempt. + // +optional + LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"` + + // LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last + // reconciliation attempt. + // Deprecated: Use LastAttemptedConfigDigest instead. + // +optional + LastAttemptedValuesChecksum string `json:"lastAttemptedValuesChecksum,omitempty"` + + // LastReleaseRevision is the revision of the last successful Helm release. + // Deprecated: Use History instead. + // +optional + LastReleaseRevision int `json:"lastReleaseRevision,omitempty"` + + // LastAttemptedConfigDigest is the digest for the config (better known as + // "values") of the last reconciliation attempt. + // +optional + LastAttemptedConfigDigest string `json:"lastAttemptedConfigDigest,omitempty"` + + meta.ReconcileRequestStatus `json:",inline"` +} + +// ClearHistory clears the History. +func (in *HelmReleaseStatus) ClearHistory() { + in.History = nil +} + +// ClearFailures clears the failure counters. +func (in *HelmReleaseStatus) ClearFailures() { + in.Failures = 0 + in.InstallFailures = 0 + in.UpgradeFailures = 0 +} + +// GetHelmChart returns the namespace and name of the HelmChart. +func (in HelmReleaseStatus) GetHelmChart() (string, string) { + if in.HelmChart == "" { + return "", "" + } + if split := strings.Split(in.HelmChart, string(types.Separator)); len(split) > 1 { + return split[0], split[1] + } + return "", "" +} + +const ( + // SourceIndexKey is the key used for indexing HelmReleases based on + // their sources. + SourceIndexKey string = ".metadata.source" +) + +// +genclient +// +genclient:Namespaced +// +kubebuilder:object:root=true +// +kubebuilder:resource:shortName=hr +// +kubebuilder:storageversion +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" + +// HelmRelease is the Schema for the helmreleases API +type HelmRelease struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmReleaseSpec `json:"spec,omitempty"` + // +kubebuilder:default:={"observedGeneration":-1} + Status HelmReleaseStatus `json:"status,omitempty"` +} + +// GetInstall returns the configuration for Helm install actions for the +// HelmRelease. +func (in *HelmRelease) GetInstall() Install { + if in.Spec.Install == nil { + return Install{} + } + return *in.Spec.Install +} + +// GetUpgrade returns the configuration for Helm upgrade actions for this +// HelmRelease. +func (in *HelmRelease) GetUpgrade() Upgrade { + if in.Spec.Upgrade == nil { + return Upgrade{} + } + return *in.Spec.Upgrade +} + +// GetTest returns the configuration for Helm test actions for this HelmRelease. +func (in *HelmRelease) GetTest() Test { + if in.Spec.Test == nil { + return Test{} + } + return *in.Spec.Test +} + +// GetRollback returns the configuration for Helm rollback actions for this +// HelmRelease. +func (in *HelmRelease) GetRollback() Rollback { + if in.Spec.Rollback == nil { + return Rollback{} + } + return *in.Spec.Rollback +} + +// GetUninstall returns the configuration for Helm uninstall actions for this +// HelmRelease. +func (in *HelmRelease) GetUninstall() Uninstall { + if in.Spec.Uninstall == nil { + return Uninstall{} + } + return *in.Spec.Uninstall +} + +// GetActiveRemediation returns the active Remediation configuration for the +// HelmRelease. +func (in HelmRelease) GetActiveRemediation() Remediation { + switch in.Status.LastAttemptedReleaseAction { + case ReleaseActionInstall: + return in.GetInstall().GetRemediation() + case ReleaseActionUpgrade: + return in.GetUpgrade().GetRemediation() + default: + return nil + } +} + +// GetRequeueAfter returns the duration after which the HelmRelease +// must be reconciled again. +func (in HelmRelease) GetRequeueAfter() time.Duration { + return in.Spec.Interval.Duration +} + +// GetValues unmarshals the raw values to a map[string]interface{} and returns +// the result. +func (in HelmRelease) GetValues() map[string]interface{} { + var values map[string]interface{} + if in.Spec.Values != nil { + _ = yaml.Unmarshal(in.Spec.Values.Raw, &values) + } + return values +} + +// GetReleaseName returns the configured release name, or a composition of +// '[TargetNamespace-]Name'. +func (in HelmRelease) GetReleaseName() string { + if in.Spec.ReleaseName != "" { + return in.Spec.ReleaseName + } + if in.Spec.TargetNamespace != "" { + return strings.Join([]string{in.Spec.TargetNamespace, in.Name}, "-") + } + return in.Name +} + +// GetReleaseNamespace returns the configured TargetNamespace, or the namespace +// of the HelmRelease. +func (in HelmRelease) GetReleaseNamespace() string { + if in.Spec.TargetNamespace != "" { + return in.Spec.TargetNamespace + } + return in.Namespace +} + +// GetStorageNamespace returns the configured StorageNamespace for helm, or the namespace +// of the HelmRelease. +func (in HelmRelease) GetStorageNamespace() string { + if in.Spec.StorageNamespace != "" { + return in.Spec.StorageNamespace + } + return in.Namespace +} + +// GetHelmChartName returns the name used by the controller for the HelmChart creation. +func (in HelmRelease) GetHelmChartName() string { + return strings.Join([]string{in.Namespace, in.Name}, "-") +} + +// GetTimeout returns the configured Timeout, or the default of 300s. +func (in HelmRelease) GetTimeout() metav1.Duration { + if in.Spec.Timeout == nil { + return metav1.Duration{Duration: 300 * time.Second} + } + return *in.Spec.Timeout +} + +// GetMaxHistory returns the configured MaxHistory, or the default of 5. +func (in HelmRelease) GetMaxHistory() int { + if in.Spec.MaxHistory == nil { + return 5 + } + return *in.Spec.MaxHistory +} + +// UsePersistentClient returns the configured PersistentClient, or the default +// of true. +func (in HelmRelease) UsePersistentClient() bool { + if in.Spec.PersistentClient == nil { + return true + } + return *in.Spec.PersistentClient +} + +// GetDependsOn returns the list of dependencies across-namespaces. +func (in HelmRelease) GetDependsOn() []meta.NamespacedObjectReference { + return in.Spec.DependsOn +} + +// GetConditions returns the status conditions of the object. +func (in HelmRelease) GetConditions() []metav1.Condition { + return in.Status.Conditions +} + +// SetConditions sets the status conditions on the object. +func (in *HelmRelease) SetConditions(conditions []metav1.Condition) { + in.Status.Conditions = conditions +} + +// GetStatusConditions returns a pointer to the Status.Conditions slice. +// Deprecated: use GetConditions instead. +func (in *HelmRelease) GetStatusConditions() *[]metav1.Condition { + return &in.Status.Conditions +} + +// +kubebuilder:object:root=true + +// HelmReleaseList contains a list of HelmRelease objects. +type HelmReleaseList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmRelease `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmRelease{}, &HelmReleaseList{}) +} diff --git a/api/v2beta2/reference_types.go b/api/v2beta2/reference_types.go new file mode 100644 index 000000000..4c899fe5d --- /dev/null +++ b/api/v2beta2/reference_types.go @@ -0,0 +1,88 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +// CrossNamespaceObjectReference contains enough information to let you locate +// the typed referenced object at cluster level. +type CrossNamespaceObjectReference struct { + // APIVersion of the referent. + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Kind of the referent. + // +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket + // +required + Kind string `json:"kind,omitempty"` + + // Name of the referent. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +required + Name string `json:"name"` + + // Namespace of the referent. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:Optional + // +optional + Namespace string `json:"namespace,omitempty"` +} + +// ValuesReference contains a reference to a resource containing Helm values, +// and optionally the key they can be found at. +type ValuesReference struct { + // Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + // +kubebuilder:validation:Enum=Secret;ConfigMap + // +required + Kind string `json:"kind"` + + // Name of the values referent. Should reside in the same namespace as the + // referring resource. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +required + Name string `json:"name"` + + // ValuesKey is the data key where the values.yaml or a specific value can be + // found at. Defaults to 'values.yaml'. + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^[\-._a-zA-Z0-9]+$` + // +optional + ValuesKey string `json:"valuesKey,omitempty"` + + // TargetPath is the YAML dot notation path the value should be merged at. When + // set, the ValuesKey is expected to be a single flat value. Defaults to 'None', + // which results in the values getting merged at the root. + // +kubebuilder:validation:MaxLength=250 + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$` + // +optional + TargetPath string `json:"targetPath,omitempty"` + + // Optional marks this ValuesReference as optional. When set, a not found error + // for the values reference is ignored, but any ValuesKey, TargetPath or + // transient error will still result in a reconciliation failure. + // +optional + Optional bool `json:"optional,omitempty"` +} + +// GetValuesKey returns the defined ValuesKey, or the default ('values.yaml'). +func (in ValuesReference) GetValuesKey() string { + if in.ValuesKey == "" { + return "values.yaml" + } + return in.ValuesKey +} diff --git a/api/v2beta2/snapshot_types.go b/api/v2beta2/snapshot_types.go new file mode 100644 index 000000000..2258acc58 --- /dev/null +++ b/api/v2beta2/snapshot_types.go @@ -0,0 +1,224 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "fmt" + "sort" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // snapshotStatusDeployed indicates that the release the snapshot was taken + // from is currently deployed. + snapshotStatusDeployed = "deployed" + // snapshotStatusSuperseded indicates that the release the snapshot was taken + // from has been superseded by a newer release. + snapshotStatusSuperseded = "superseded" + + // snapshotTestPhaseFailed indicates that the test of the release the snapshot + // was taken from has failed. + snapshotTestPhaseFailed = "Failed" +) + +// Snapshots is a list of Snapshot objects. +type Snapshots []*Snapshot + +// Len returns the number of Snapshots. +func (in Snapshots) Len() int { + return len(in) +} + +// SortByVersion sorts the Snapshots by version, in descending order. +func (in Snapshots) SortByVersion() { + sort.Slice(in, func(i, j int) bool { + return in[i].Version > in[j].Version + }) +} + +// Latest returns the most recent Snapshot. +func (in Snapshots) Latest() *Snapshot { + if len(in) == 0 { + return nil + } + in.SortByVersion() + return in[0] +} + +// Previous returns the most recent Snapshot before the Latest that has a +// status of "deployed" or "superseded", or nil if there is no such Snapshot. +// Unless ignoreTests is true, Snapshots with a test in the "Failed" phase are +// ignored. +func (in Snapshots) Previous(ignoreTests bool) *Snapshot { + if len(in) < 2 { + return nil + } + in.SortByVersion() + for i := range in[1:] { + s := in[i+1] + if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded { + if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) { + return s + } + } + } + return nil +} + +// Truncate removes all Snapshots up to the Previous deployed Snapshot. +// If there is no previous-deployed Snapshot, no Snapshots are removed. +func (in *Snapshots) Truncate(ignoreTests bool) { + if in.Len() < 2 { + return + } + in.SortByVersion() + for i := range (*in)[1:] { + s := (*in)[i+1] + if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded { + if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) { + *in = (*in)[:i+2] + return + } + } + } +} + +// Snapshot captures a point-in-time copy of the status information for a Helm release, +// as managed by the controller. +type Snapshot struct { + // APIVersion is the API version of the Snapshot. + // Provisional: when the calculation method of the Digest field is changed, + // this field will be used to distinguish between the old and new methods. + // +optional + APIVersion string `json:"apiVersion,omitempty"` + // Digest is the checksum of the release object in storage. + // It has the format of `:`. + // +required + Digest string `json:"digest"` + // Name is the name of the release. + // +required + Name string `json:"name"` + // Namespace is the namespace the release is deployed to. + // +required + Namespace string `json:"namespace"` + // Version is the version of the release object in storage. + // +required + Version int `json:"version"` + // Status is the current state of the release. + // +required + Status string `json:"status"` + // ChartName is the chart name of the release object in storage. + // +required + ChartName string `json:"chartName"` + // ChartVersion is the chart version of the release object in + // storage. + // +required + ChartVersion string `json:"chartVersion"` + // ConfigDigest is the checksum of the config (better known as + // "values") of the release object in storage. + // It has the format of `:`. + // +required + ConfigDigest string `json:"configDigest"` + // FirstDeployed is when the release was first deployed. + // +required + FirstDeployed metav1.Time `json:"firstDeployed"` + // LastDeployed is when the release was last deployed. + // +required + LastDeployed metav1.Time `json:"lastDeployed"` + // Deleted is when the release was deleted. + // +optional + Deleted metav1.Time `json:"deleted,omitempty"` + // TestHooks is the list of test hooks for the release as observed to be + // run by the controller. + // +optional + TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"` +} + +// FullReleaseName returns the full name of the release in the format +// of '/. +func (in *Snapshot) FullReleaseName() string { + if in == nil { + return "" + } + return fmt.Sprintf("%s/%s.v%d", in.Namespace, in.Name, in.Version) +} + +// VersionedChartName returns the full name of the chart in the format of +// '@'. +func (in *Snapshot) VersionedChartName() string { + if in == nil { + return "" + } + return fmt.Sprintf("%s@%s", in.ChartName, in.ChartVersion) +} + +// HasBeenTested returns true if TestHooks is not nil. This includes an empty +// map, which indicates the chart has no tests. +func (in *Snapshot) HasBeenTested() bool { + return in != nil && in.TestHooks != nil +} + +// GetTestHooks returns the TestHooks for the release if not nil. +func (in *Snapshot) GetTestHooks() map[string]*TestHookStatus { + if in == nil || in.TestHooks == nil { + return nil + } + return *in.TestHooks +} + +// HasTestInPhase returns true if any of the TestHooks is in the given phase. +func (in *Snapshot) HasTestInPhase(phase string) bool { + if in != nil { + for _, h := range in.GetTestHooks() { + if h.Phase == phase { + return true + } + } + } + return false +} + +// SetTestHooks sets the TestHooks for the release. +func (in *Snapshot) SetTestHooks(hooks map[string]*TestHookStatus) { + if in == nil || hooks == nil { + return + } + in.TestHooks = &hooks +} + +// Targets returns true if the Snapshot targets the given release data. +func (in *Snapshot) Targets(name, namespace string, version int) bool { + if in != nil { + return in.Name == name && in.Namespace == namespace && in.Version == version + } + return false +} + +// TestHookStatus holds the status information for a test hook as observed +// to be run by the controller. +type TestHookStatus struct { + // LastStarted is the time the test hook was last started. + // +optional + LastStarted metav1.Time `json:"lastStarted,omitempty"` + // LastCompleted is the time the test hook last completed. + // +optional + LastCompleted metav1.Time `json:"lastCompleted,omitempty"` + // Phase the test hook was observed to be in. + // +optional + Phase string `json:"phase,omitempty"` +} diff --git a/api/v2beta2/snapshot_types_test.go b/api/v2beta2/snapshot_types_test.go new file mode 100644 index 000000000..8447868b9 --- /dev/null +++ b/api/v2beta2/snapshot_types_test.go @@ -0,0 +1,280 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta2 + +import ( + "reflect" + "testing" +) + +func TestSnapshots_Sort(t *testing.T) { + tests := []struct { + name string + in Snapshots + want Snapshots + }{ + { + name: "sorts by descending version", + in: Snapshots{ + {Version: 1}, + {Version: 3}, + {Version: 2}, + }, + want: Snapshots{ + {Version: 3}, + {Version: 2}, + {Version: 1}, + }, + }, + { + name: "already sorted", + in: Snapshots{ + {Version: 3}, + {Version: 2}, + {Version: 1}, + }, + want: Snapshots{ + {Version: 3}, + {Version: 2}, + {Version: 1}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.in.SortByVersion() + + if !reflect.DeepEqual(tt.in, tt.want) { + t.Errorf("SortByVersion() got %v, want %v", tt.in, tt.want) + } + }) + } +} + +func TestSnapshots_Latest(t *testing.T) { + tests := []struct { + name string + in Snapshots + want *Snapshot + }{ + { + name: "returns most recent snapshot", + in: Snapshots{ + {Version: 1}, + {Version: 3}, + {Version: 2}, + }, + want: &Snapshot{Version: 3}, + }, + { + name: "returns nil if empty", + in: Snapshots{}, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.in.Latest(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Latest() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestSnapshots_Previous(t *testing.T) { + tests := []struct { + name string + in Snapshots + ignoreTests bool + want *Snapshot + }{ + { + name: "returns previous snapshot", + in: Snapshots{ + {Version: 2, Status: "deployed"}, + {Version: 3, Status: "failed"}, + {Version: 1, Status: "superseded"}, + }, + want: &Snapshot{Version: 2, Status: "deployed"}, + }, + { + name: "includes snapshots with failed tests", + in: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 1, Status: "superseded"}, + {Version: 2, Status: "superseded"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "test": {Phase: "Failed"}, + }}, + }, + ignoreTests: true, + want: &Snapshot{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "test": {Phase: "Failed"}, + }}, + }, + { + name: "ignores snapshots with failed tests", + in: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 1, Status: "superseded"}, + {Version: 2, Status: "superseded"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "test": {Phase: "Failed"}, + }}, + }, + ignoreTests: false, + want: &Snapshot{Version: 2, Status: "superseded"}, + }, + { + name: "returns nil without previous snapshot", + in: Snapshots{ + {Version: 1, Status: "deployed"}, + }, + want: nil, + }, + { + name: "returns nil without snapshot matching criteria", + in: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "test": {Phase: "Failed"}, + }}, + }, + ignoreTests: false, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.in.Previous(tt.ignoreTests); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Previous() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestSnapshots_Truncate(t *testing.T) { + tests := []struct { + name string + in Snapshots + ignoreTests bool + want Snapshots + }{ + { + name: "keeps previous snapshot", + in: Snapshots{ + {Version: 1, Status: "superseded"}, + {Version: 3, Status: "failed"}, + {Version: 2, Status: "superseded"}, + {Version: 4, Status: "deployed"}, + }, + want: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "failed"}, + {Version: 2, Status: "superseded"}, + }, + }, + { + name: "ignores snapshots with failed tests", + in: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"}, + "upgrade-test-fail-podinfo-grpc-test-gddcw": {}, + }}, + {Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-grpc-test-h0tc2": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-jwt-test-vzusa": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-service-test-b647e": { + Phase: "Succeeded", + }, + }}, + }, + ignoreTests: false, + want: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"}, + "upgrade-test-fail-podinfo-grpc-test-gddcw": {}, + }}, + {Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-grpc-test-h0tc2": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-jwt-test-vzusa": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-service-test-b647e": { + Phase: "Succeeded", + }, + }}, + }, + }, + { + name: "keeps previous snapshot with failed tests", + in: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"}, + "upgrade-test-fail-podinfo-grpc-test-gddcw": {}, + }}, + {Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-grpc-test-h0tc2": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-jwt-test-vzusa": { + Phase: "Succeeded", + }, + "upgrade-test-fail-podinfo-service-test-b647e": { + Phase: "Succeeded", + }, + }}, + {Version: 1, Status: "superseded"}, + }, + ignoreTests: true, + want: Snapshots{ + {Version: 4, Status: "deployed"}, + {Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{ + "upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"}, + "upgrade-test-fail-podinfo-grpc-test-gddcw": {}, + }}, + }, + }, + { + name: "without previous snapshot", + in: Snapshots{ + {Version: 1, Status: "deployed"}, + }, + want: Snapshots{ + {Version: 1, Status: "deployed"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.in.Truncate(tt.ignoreTests) + + if !reflect.DeepEqual(tt.in, tt.want) { + t.Errorf("Truncate() got %v, want %v", tt.in, tt.want) + } + }) + } +} diff --git a/api/v2beta2/zz_generated.deepcopy.go b/api/v2beta2/zz_generated.deepcopy.go new file mode 100644 index 000000000..a2f3b8f65 --- /dev/null +++ b/api/v2beta2/zz_generated.deepcopy.go @@ -0,0 +1,672 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v2beta2 + +import ( + "github.com/fluxcd/pkg/apis/kustomize" + "github.com/fluxcd/pkg/apis/meta" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CrossNamespaceObjectReference) DeepCopyInto(out *CrossNamespaceObjectReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceObjectReference. +func (in *CrossNamespaceObjectReference) DeepCopy() *CrossNamespaceObjectReference { + if in == nil { + return nil + } + out := new(CrossNamespaceObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Filter) DeepCopyInto(out *Filter) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter. +func (in *Filter) DeepCopy() *Filter { + if in == nil { + return nil + } + out := new(Filter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChartTemplate) DeepCopyInto(out *HelmChartTemplate) { + *out = *in + if in.ObjectMeta != nil { + in, out := &in.ObjectMeta, &out.ObjectMeta + *out = new(HelmChartTemplateObjectMeta) + (*in).DeepCopyInto(*out) + } + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplate. +func (in *HelmChartTemplate) DeepCopy() *HelmChartTemplate { + if in == nil { + return nil + } + out := new(HelmChartTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChartTemplateObjectMeta) DeepCopyInto(out *HelmChartTemplateObjectMeta) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateObjectMeta. +func (in *HelmChartTemplateObjectMeta) DeepCopy() *HelmChartTemplateObjectMeta { + if in == nil { + return nil + } + out := new(HelmChartTemplateObjectMeta) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChartTemplateSpec) DeepCopyInto(out *HelmChartTemplateSpec) { + *out = *in + out.SourceRef = in.SourceRef + if in.Interval != nil { + in, out := &in.Interval, &out.Interval + *out = new(metav1.Duration) + **out = **in + } + if in.ValuesFiles != nil { + in, out := &in.ValuesFiles, &out.ValuesFiles + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Verify != nil { + in, out := &in.Verify, &out.Verify + *out = new(HelmChartTemplateVerification) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateSpec. +func (in *HelmChartTemplateSpec) DeepCopy() *HelmChartTemplateSpec { + if in == nil { + return nil + } + out := new(HelmChartTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChartTemplateVerification) DeepCopyInto(out *HelmChartTemplateVerification) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateVerification. +func (in *HelmChartTemplateVerification) DeepCopy() *HelmChartTemplateVerification { + if in == nil { + return nil + } + out := new(HelmChartTemplateVerification) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRelease) DeepCopyInto(out *HelmRelease) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRelease. +func (in *HelmRelease) DeepCopy() *HelmRelease { + if in == nil { + return nil + } + out := new(HelmRelease) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRelease) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseList) DeepCopyInto(out *HelmReleaseList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmRelease, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseList. +func (in *HelmReleaseList) DeepCopy() *HelmReleaseList { + if in == nil { + return nil + } + out := new(HelmReleaseList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmReleaseList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) { + *out = *in + in.Chart.DeepCopyInto(&out.Chart) + out.Interval = in.Interval + if in.KubeConfig != nil { + in, out := &in.KubeConfig, &out.KubeConfig + *out = new(meta.KubeConfigReference) + **out = **in + } + if in.DependsOn != nil { + in, out := &in.DependsOn, &out.DependsOn + *out = make([]meta.NamespacedObjectReference, len(*in)) + copy(*out, *in) + } + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.MaxHistory != nil { + in, out := &in.MaxHistory, &out.MaxHistory + *out = new(int) + **out = **in + } + if in.PersistentClient != nil { + in, out := &in.PersistentClient, &out.PersistentClient + *out = new(bool) + **out = **in + } + if in.Install != nil { + in, out := &in.Install, &out.Install + *out = new(Install) + (*in).DeepCopyInto(*out) + } + if in.Upgrade != nil { + in, out := &in.Upgrade, &out.Upgrade + *out = new(Upgrade) + (*in).DeepCopyInto(*out) + } + if in.Test != nil { + in, out := &in.Test, &out.Test + *out = new(Test) + (*in).DeepCopyInto(*out) + } + if in.Rollback != nil { + in, out := &in.Rollback, &out.Rollback + *out = new(Rollback) + (*in).DeepCopyInto(*out) + } + if in.Uninstall != nil { + in, out := &in.Uninstall, &out.Uninstall + *out = new(Uninstall) + (*in).DeepCopyInto(*out) + } + if in.ValuesFrom != nil { + in, out := &in.ValuesFrom, &out.ValuesFrom + *out = make([]ValuesReference, len(*in)) + copy(*out, *in) + } + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } + if in.PostRenderers != nil { + in, out := &in.PostRenderers, &out.PostRenderers + *out = make([]PostRenderer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseSpec. +func (in *HelmReleaseSpec) DeepCopy() *HelmReleaseSpec { + if in == nil { + return nil + } + out := new(HelmReleaseSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.History != nil { + in, out := &in.History, &out.History + *out = make(Snapshots, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Snapshot) + (*in).DeepCopyInto(*out) + } + } + } + out.ReconcileRequestStatus = in.ReconcileRequestStatus +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus. +func (in *HelmReleaseStatus) DeepCopy() *HelmReleaseStatus { + if in == nil { + return nil + } + out := new(HelmReleaseStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Install) DeepCopyInto(out *Install) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.Remediation != nil { + in, out := &in.Remediation, &out.Remediation + *out = new(InstallRemediation) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Install. +func (in *Install) DeepCopy() *Install { + if in == nil { + return nil + } + out := new(Install) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstallRemediation) DeepCopyInto(out *InstallRemediation) { + *out = *in + if in.IgnoreTestFailures != nil { + in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures + *out = new(bool) + **out = **in + } + if in.RemediateLastFailure != nil { + in, out := &in.RemediateLastFailure, &out.RemediateLastFailure + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallRemediation. +func (in *InstallRemediation) DeepCopy() *InstallRemediation { + if in == nil { + return nil + } + out := new(InstallRemediation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Kustomize) DeepCopyInto(out *Kustomize) { + *out = *in + if in.Patches != nil { + in, out := &in.Patches, &out.Patches + *out = make([]kustomize.Patch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PatchesStrategicMerge != nil { + in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge + *out = make([]v1.JSON, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PatchesJSON6902 != nil { + in, out := &in.PatchesJSON6902, &out.PatchesJSON6902 + *out = make([]kustomize.JSON6902Patch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Images != nil { + in, out := &in.Images, &out.Images + *out = make([]kustomize.Image, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kustomize. +func (in *Kustomize) DeepCopy() *Kustomize { + if in == nil { + return nil + } + out := new(Kustomize) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PostRenderer) DeepCopyInto(out *PostRenderer) { + *out = *in + if in.Kustomize != nil { + in, out := &in.Kustomize, &out.Kustomize + *out = new(Kustomize) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostRenderer. +func (in *PostRenderer) DeepCopy() *PostRenderer { + if in == nil { + return nil + } + out := new(PostRenderer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Rollback) DeepCopyInto(out *Rollback) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rollback. +func (in *Rollback) DeepCopy() *Rollback { + if in == nil { + return nil + } + out := new(Rollback) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Snapshot) DeepCopyInto(out *Snapshot) { + *out = *in + in.FirstDeployed.DeepCopyInto(&out.FirstDeployed) + in.LastDeployed.DeepCopyInto(&out.LastDeployed) + in.Deleted.DeepCopyInto(&out.Deleted) + if in.TestHooks != nil { + in, out := &in.TestHooks, &out.TestHooks + *out = new(map[string]*TestHookStatus) + if **in != nil { + in, out := *in, *out + *out = make(map[string]*TestHookStatus, len(*in)) + for key, val := range *in { + var outVal *TestHookStatus + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(TestHookStatus) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshot. +func (in *Snapshot) DeepCopy() *Snapshot { + if in == nil { + return nil + } + out := new(Snapshot) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Snapshots) DeepCopyInto(out *Snapshots) { + { + in := &in + *out = make(Snapshots, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Snapshot) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshots. +func (in Snapshots) DeepCopy() Snapshots { + if in == nil { + return nil + } + out := new(Snapshots) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Test) DeepCopyInto(out *Test) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.Filters != nil { + in, out := &in.Filters, &out.Filters + *out = new([]Filter) + if **in != nil { + in, out := *in, *out + *out = make([]Filter, len(*in)) + copy(*out, *in) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Test. +func (in *Test) DeepCopy() *Test { + if in == nil { + return nil + } + out := new(Test) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestHookStatus) DeepCopyInto(out *TestHookStatus) { + *out = *in + in.LastStarted.DeepCopyInto(&out.LastStarted) + in.LastCompleted.DeepCopyInto(&out.LastCompleted) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestHookStatus. +func (in *TestHookStatus) DeepCopy() *TestHookStatus { + if in == nil { + return nil + } + out := new(TestHookStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Uninstall) DeepCopyInto(out *Uninstall) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.DeletionPropagation != nil { + in, out := &in.DeletionPropagation, &out.DeletionPropagation + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Uninstall. +func (in *Uninstall) DeepCopy() *Uninstall { + if in == nil { + return nil + } + out := new(Uninstall) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Upgrade) DeepCopyInto(out *Upgrade) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.Remediation != nil { + in, out := &in.Remediation, &out.Remediation + *out = new(UpgradeRemediation) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upgrade. +func (in *Upgrade) DeepCopy() *Upgrade { + if in == nil { + return nil + } + out := new(Upgrade) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpgradeRemediation) DeepCopyInto(out *UpgradeRemediation) { + *out = *in + if in.IgnoreTestFailures != nil { + in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures + *out = new(bool) + **out = **in + } + if in.RemediateLastFailure != nil { + in, out := &in.RemediateLastFailure, &out.RemediateLastFailure + *out = new(bool) + **out = **in + } + if in.Strategy != nil { + in, out := &in.Strategy, &out.Strategy + *out = new(RemediationStrategy) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeRemediation. +func (in *UpgradeRemediation) DeepCopy() *UpgradeRemediation { + if in == nil { + return nil + } + out := new(UpgradeRemediation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ValuesReference) DeepCopyInto(out *ValuesReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValuesReference. +func (in *ValuesReference) DeepCopy() *ValuesReference { + if in == nil { + return nil + } + out := new(ValuesReference) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml b/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml index d60c61267..7a17c4441 100644 --- a/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml +++ b/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml @@ -881,6 +881,99 @@ spec: description: HelmChart is the namespaced name of the HelmChart resource created by the controller for the HelmRelease. type: string + history: + description: "History holds the history of Helm releases performed + for this HelmRelease up to the last successfully completed release. + \n Note: this field is provisional to the v2beta2 API, and not actively + used by v2beta1 HelmReleases." + items: + description: Snapshot captures a point-in-time copy of the status + information for a Helm release, as managed by the controller. + properties: + apiVersion: + description: 'APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field + is changed, this field will be used to distinguish between + the old and new methods.' + type: string + chartName: + description: ChartName is the chart name of the release object + in storage. + type: string + chartVersion: + description: ChartVersion is the chart version of the release + object in storage. + type: string + configDigest: + description: ConfigDigest is the checksum of the config (better + known as "values") of the release object in storage. It has + the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: Digest is the checksum of the release object in + storage. It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed + to. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: TestHookStatus holds the status information for + a test hook as observed to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last + completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was + last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: TestHooks is the list of test hooks for the release + as observed to be run by the controller. + type: object + version: + description: Version is the version of the release object in + storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array installFailures: description: InstallFailures is the install failure count against the latest desired state. It is reset after a successful reconciliation. @@ -890,6 +983,24 @@ spec: description: LastAppliedRevision is the revision of the last successfully applied source. type: string + lastAttemptedConfigDigest: + description: "LastAttemptedConfigDigest is the digest for the config + (better known as \"values\") of the last reconciliation attempt. + \n Note: this field is provisional to the v2beta2 API, and not actively + used by v2beta1 HelmReleases." + type: string + lastAttemptedGeneration: + description: "LastAttemptedGeneration is the last generation the controller + attempted to reconcile. \n Note: this field is provisional to the + v2beta2 API, and not actively used by v2beta1 HelmReleases." + format: int64 + type: integer + lastAttemptedReleaseAction: + description: "LastAttemptedReleaseAction is the last release action + performed for this HelmRelease. It is used to determine the active + remediation strategy. \n Note: this field is provisional to the + v2beta2 API, and not actively used by v2beta1 HelmReleases." + type: string lastAttemptedRevision: description: LastAttemptedRevision is the revision of the last reconciliation attempt. @@ -911,6 +1022,1053 @@ spec: description: ObservedGeneration is the last observed generation. format: int64 type: integer + storageNamespace: + description: "StorageNamespace is the namespace of the Helm release + storage for the current release. \n Note: this field is provisional + to the v2beta2 API, and not actively used by v2beta1 HelmReleases." + type: string + upgradeFailures: + description: UpgradeFailures is the upgrade failure count against + the latest desired state. It is reset after a successful reconciliation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v2beta2 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: HelmReleaseSpec defines the desired state of a Helm release. + properties: + chart: + description: Chart defines the template of the v1beta2.HelmChart that + should be created for this HelmRelease. + properties: + metadata: + description: ObjectMeta holds the template for metadata like labels + and annotations. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map + stored with a resource that may be set by external tools + to store and retrieve arbitrary metadata. They are not queryable + and should be preserved when modifying objects. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used + to organize and categorize (scope and select) objects. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/' + type: object + type: object + spec: + description: Spec holds the template for the v1beta2.HelmChartSpec + for this HelmRelease. + properties: + chart: + description: The name or path the Helm chart is available + at in the SourceRef. + maxLength: 2048 + minLength: 1 + type: string + interval: + description: Interval at which to check the v1.Source for + updates. Defaults to 'HelmReleaseSpec.Interval'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: Determines what enables the creation of a new + artifact. Valid values are ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on + their behavior. Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: The name and namespace of the v1.Source the chart + is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent. + maxLength: 63 + minLength: 1 + type: string + required: + - name + type: object + valuesFile: + description: Alternative values file to use as the default + chart values, expected to be a relative path in the SourceRef. + Deprecated in favor of ValuesFiles, for backwards compatibility + the file defined here is merged before the ValuesFiles items. + Ignored when omitted. + type: string + valuesFiles: + description: Alternative list of values files to use as the + chart values (values.yaml is not included by default), expected + to be a relative path in the SourceRef. Values files are + merged in the order of this list with the last file overriding + the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: Verify contains the secret name containing the + trusted public keys used to verify the signature and specifies + which provider to use to check whether OCI image is authentic. + This field is only supported for OCI sources. Chart dependencies, + which are not bundled in the umbrella chart artifact, are + not verified. + properties: + provider: + default: cosign + description: Provider specifies the technology used to + sign the OCI Helm chart. + enum: + - cosign + type: string + secretRef: + description: SecretRef specifies the Kubernetes Secret + containing the trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: Version semver expression, ignored for charts + from v1beta2.GitRepository and v1beta2.Bucket sources. Defaults + to latest when omitted. + type: string + required: + - chart + - sourceRef + type: object + required: + - spec + type: object + dependsOn: + description: DependsOn may contain a meta.NamespacedObjectReference + slice with references to HelmRelease resources that must be ready + before this HelmRelease can be reconciled. + items: + description: NamespacedObjectReference contains enough information + to locate the referenced Kubernetes resource object in any namespace. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it + acts as LocalObjectReference. + type: string + required: + - name + type: object + type: array + install: + description: Install holds the configuration for Helm install actions + for this HelmRelease. + properties: + crds: + description: "CRDs upgrade CRDs from the Helm Chart's crds directory + according to the CRD upgrade policy provided here. Valid values + are `Skip`, `Create` or `CreateReplace`. Default is `Create` + and if omitted CRDs are installed but not updated. \n Skip: + do neither install nor replace (update) any CRDs. \n Create: + new CRDs are created, existing CRDs are neither updated nor + deleted. \n CreateReplace: new CRDs are created, existing CRDs + are updated (replaced) but not deleted. \n By default, CRDs + are applied (installed) during Helm install action. With this + option users can opt in to CRD replace existing CRDs on Helm + install actions, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions." + enum: + - Skip + - Create + - CreateReplace + type: string + createNamespace: + description: CreateNamespace tells the Helm install action to + create the HelmReleaseSpec.TargetNamespace if it does not exist + yet. On uninstall, the namespace will not be garbage collected. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the + Helm install action. + type: boolean + disableOpenAPIValidation: + description: DisableOpenAPIValidation prevents the Helm install + action from validating rendered templates against the Kubernetes + OpenAPI Schema. + type: boolean + disableWait: + description: DisableWait disables the waiting for resources to + be ready after a Helm install has been performed. + type: boolean + disableWaitForJobs: + description: DisableWaitForJobs disables waiting for jobs to complete + after a Helm install has been performed. + type: boolean + remediation: + description: Remediation holds the remediation configuration for + when the Helm install action for the HelmRelease fails. The + default is to not perform any action. + properties: + ignoreTestFailures: + description: IgnoreTestFailures tells the controller to skip + remediation when the Helm tests are run after an install + action but fail. Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: RemediateLastFailure tells the controller to + remediate the last failure, when no retries remain. Defaults + to 'false'. + type: boolean + retries: + description: Retries is the number of retries that should + be attempted on failures before bailing. Remediation, using + an uninstall, is performed between each attempt. Defaults + to '0', a negative integer equals to unlimited retries. + type: integer + type: object + replace: + description: Replace tells the Helm install action to re-use the + 'ReleaseName', but only if that name is a deleted release which + remains in the history. + type: boolean + skipCRDs: + description: "SkipCRDs tells the Helm install action to not install + any CRDs. By default, CRDs are installed if not already present. + \n Deprecated use CRD policy (`crds`) attribute with value `Skip` + instead." + type: boolean + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation (like Jobs for hooks) during the performance of a + Helm install action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + interval: + description: Interval at which to reconcile the Helm release. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: KubeConfig for reconciling the HelmRelease on a remote + cluster. When used in combination with HelmReleaseSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at + the target cluster. If the --default-service-account flag is set, + its value will be used as a controller level fallback for when HelmReleaseSpec.ServiceAccountName + is empty. + properties: + secretRef: + description: SecretRef holds the name of a secret that contains + a key with the kubeconfig file as the value. If no key is set, + the key will default to 'value'. It is recommended that the + kubeconfig is self-contained, and the secret is regularly updated + if credentials such as a cloud-access-token expire. Cloud specific + `cmd-path` auth helpers will not function without adding binaries + and credentials to the Pod that is responsible for reconciling + Kubernetes resources. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific + default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + required: + - secretRef + type: object + maxHistory: + description: MaxHistory is the number of revisions saved by Helm for + this HelmRelease. Use '0' for an unlimited number of revisions; + defaults to '5'. + type: integer + persistentClient: + description: "PersistentClient tells the controller to use a persistent + Kubernetes client for this release. When enabled, the client will + be reused for the duration of the reconciliation, instead of being + created and destroyed for each (step of a) Helm action. \n This + can improve performance, but may cause issues with some Helm charts + that for example do create Custom Resource Definitions during installation + outside Helm's CRD lifecycle hooks, which are then not observed + to be available by e.g. post-install hooks. \n If not set, it defaults + to true." + type: boolean + postRenderers: + description: PostRenderers holds an array of Helm PostRenderers, which + will be applied in order of their definition. + items: + description: PostRenderer contains a Helm PostRenderer specification. + properties: + kustomize: + description: Kustomization to apply as PostRenderer. + properties: + images: + description: Images is a list of (image name, new name, + new tag or digest) for changing image names, tags or digests. + This can also be achieved with a patch, but this operator + is simpler to specify. + items: + description: Image contains an image name, a new name, + a new tag or digest, which will replace the original + name and tag. + properties: + digest: + description: Digest is the value used to replace the + original image tag. If digest is present NewTag + value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace + the original name. + type: string + newTag: + description: NewTag is the value used to replace the + original tag. + type: string + required: + - name + type: object + type: array + patches: + description: Strategic merge and JSON patches, defined as + inline YAML objects, capable of targeting objects based + on kind, label and annotation selectors. + items: + description: Patch contains an inline StrategicMerge or + JSON6902 patch, and the target the patch should be applied + to. + properties: + patch: + description: Patch contains an inline StrategicMerge + patch or an inline JSON6902 patch with an array + of operation objects. + type: string + target: + description: Target points to the resources that the + patch document should be applied to. + properties: + annotationSelector: + description: AnnotationSelector is a string that + follows the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: Group is the API group to select + resources from. Together with Version and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: Kind of the API Group to select resources + from. Together with Group and Version it is + capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: LabelSelector is a string that follows + the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: Version of the API Group to select + resources from. Together with Group and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + patchesJson6902: + description: JSON 6902 patches, defined as inline YAML objects. + items: + description: JSON6902Patch contains a JSON6902 patch and + the target the patch should be applied to. + properties: + patch: + description: Patch contains the JSON6902 patch document + with an array of operation objects. + items: + description: JSON6902 is a JSON6902 operation object. + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + properties: + from: + description: From contains a JSON-pointer value + that references a location within the target + document where the operation is performed. + The meaning of the value depends on the value + of Op, and is NOT taken into account by all + operations. + type: string + op: + description: Op indicates the operation to perform. + Its value MUST be one of "add", "remove", + "replace", "move", "copy", or "test". https://datatracker.ietf.org/doc/html/rfc6902#section-4 + enum: + - test + - remove + - add + - replace + - move + - copy + type: string + path: + description: Path contains the JSON-pointer + value that references a location within the + target document where the operation is performed. + The meaning of the value depends on the value + of Op. + type: string + value: + description: Value contains a valid JSON structure. + The meaning of the value depends on the value + of Op, and is NOT taken into account by all + operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + target: + description: Target points to the resources that the + patch document should be applied to. + properties: + annotationSelector: + description: AnnotationSelector is a string that + follows the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: Group is the API group to select + resources from. Together with Version and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: Kind of the API Group to select resources + from. Together with Group and Version it is + capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: LabelSelector is a string that follows + the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: Version of the API Group to select + resources from. Together with Group and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + - target + type: object + type: array + patchesStrategicMerge: + description: Strategic merge patches, defined as inline + YAML objects. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + type: object + type: array + releaseName: + description: ReleaseName used for the Helm release. Defaults to a + composition of '[TargetNamespace-]Name'. + maxLength: 53 + minLength: 1 + type: string + rollback: + description: Rollback holds the configuration for Helm rollback actions + for this HelmRelease. + properties: + cleanupOnFail: + description: CleanupOnFail allows deletion of new resources created + during the Helm rollback action when it fails. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the + Helm rollback action. + type: boolean + disableWait: + description: DisableWait disables the waiting for resources to + be ready after a Helm rollback has been performed. + type: boolean + disableWaitForJobs: + description: DisableWaitForJobs disables waiting for jobs to complete + after a Helm rollback has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement + strategy. + type: boolean + recreate: + description: Recreate performs pod restarts for the resource if + applicable. + type: boolean + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation (like Jobs for hooks) during the performance of a + Helm rollback action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + serviceAccountName: + description: The name of the Kubernetes service account to impersonate + when reconciling this HelmRelease. + maxLength: 253 + minLength: 1 + type: string + storageNamespace: + description: StorageNamespace used for the Helm storage. Defaults + to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + suspend: + description: Suspend tells the controller to suspend reconciliation + for this HelmRelease, it does not apply to already started reconciliations. + Defaults to false. + type: boolean + targetNamespace: + description: TargetNamespace to target when performing operations + for the HelmRelease. Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + test: + description: Test holds the configuration for Helm test actions for + this HelmRelease. + properties: + enable: + description: Enable enables Helm test actions for this HelmRelease + after an Helm install or upgrade action has been performed. + type: boolean + filters: + description: Filters is a list of tests to run or exclude from + running. + items: + description: Filter holds the configuration for individual Helm + test filters. + properties: + exclude: + description: Exclude specifies whether the named test should + be excluded. + type: boolean + name: + description: Name is the name of the test. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + type: array + ignoreFailures: + description: IgnoreFailures tells the controller to skip remediation + when the Helm tests are run but fail. Can be overwritten for + tests run after install or upgrade actions in 'Install.IgnoreTestFailures' + and 'Upgrade.IgnoreTestFailures'. + type: boolean + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation during the performance of a Helm test action. Defaults + to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation (like Jobs for hooks) during the performance of a Helm + action. Defaults to '5m0s'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + uninstall: + description: Uninstall holds the configuration for Helm uninstall + actions for this HelmRelease. + properties: + deletionPropagation: + default: background + description: DeletionPropagation specifies the deletion propagation + policy when a Helm uninstall is performed. + enum: + - background + - foreground + - orphan + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the + Helm rollback action. + type: boolean + disableWait: + description: DisableWait disables waiting for all the resources + to be deleted after a Helm uninstall is performed. + type: boolean + keepHistory: + description: KeepHistory tells Helm to remove all associated resources + and mark the release as deleted, but retain the release history. + type: boolean + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation (like Jobs for hooks) during the performance of a + Helm uninstall action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + upgrade: + description: Upgrade holds the configuration for Helm upgrade actions + for this HelmRelease. + properties: + cleanupOnFail: + description: CleanupOnFail allows deletion of new resources created + during the Helm upgrade action when it fails. + type: boolean + crds: + description: "CRDs upgrade CRDs from the Helm Chart's crds directory + according to the CRD upgrade policy provided here. Valid values + are `Skip`, `Create` or `CreateReplace`. Default is `Skip` and + if omitted CRDs are neither installed nor upgraded. \n Skip: + do neither install nor replace (update) any CRDs. \n Create: + new CRDs are created, existing CRDs are neither updated nor + deleted. \n CreateReplace: new CRDs are created, existing CRDs + are updated (replaced) but not deleted. \n By default, CRDs + are not applied during Helm upgrade action. With this option + users can opt-in to CRD upgrade, which is not (yet) natively + supported by Helm. https://helm.sh/docs/chart_best_practices/custom_resource_definitions." + enum: + - Skip + - Create + - CreateReplace + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the + Helm upgrade action. + type: boolean + disableOpenAPIValidation: + description: DisableOpenAPIValidation prevents the Helm upgrade + action from validating rendered templates against the Kubernetes + OpenAPI Schema. + type: boolean + disableWait: + description: DisableWait disables the waiting for resources to + be ready after a Helm upgrade has been performed. + type: boolean + disableWaitForJobs: + description: DisableWaitForJobs disables waiting for jobs to complete + after a Helm upgrade has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement + strategy. + type: boolean + preserveValues: + description: PreserveValues will make Helm reuse the last release's + values and merge in overrides from 'Values'. Setting this flag + makes the HelmRelease non-declarative. + type: boolean + remediation: + description: Remediation holds the remediation configuration for + when the Helm upgrade action for the HelmRelease fails. The + default is to not perform any action. + properties: + ignoreTestFailures: + description: IgnoreTestFailures tells the controller to skip + remediation when the Helm tests are run after an upgrade + action but fail. Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: RemediateLastFailure tells the controller to + remediate the last failure, when no retries remain. Defaults + to 'false' unless 'Retries' is greater than 0. + type: boolean + retries: + description: Retries is the number of retries that should + be attempted on failures before bailing. Remediation, using + 'Strategy', is performed between each attempt. Defaults + to '0', a negative integer equals to unlimited retries. + type: integer + strategy: + description: Strategy to use for failure remediation. Defaults + to 'rollback'. + enum: + - rollback + - uninstall + type: string + type: object + timeout: + description: Timeout is the time to wait for any individual Kubernetes + operation (like Jobs for hooks) during the performance of a + Helm upgrade action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + values: + description: Values holds the values for this Helm release. + x-kubernetes-preserve-unknown-fields: true + valuesFrom: + description: ValuesFrom holds references to resources containing Helm + values for this HelmRelease, and information about how they should + be merged. + items: + description: ValuesReference contains a reference to a resource + containing Helm values, and optionally the key they can be found + at. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', + 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: Name of the values referent. Should reside in the + same namespace as the referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + description: Optional marks this ValuesReference as optional. + When set, a not found error for the values reference is ignored, + but any ValuesKey, TargetPath or transient error will still + result in a reconciliation failure. + type: boolean + targetPath: + description: TargetPath is the YAML dot notation path the value + should be merged at. When set, the ValuesKey is expected to + be a single flat value. Defaults to 'None', which results + in the values getting merged at the root. + maxLength: 250 + pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$ + type: string + valuesKey: + description: ValuesKey is the data key where the values.yaml + or a specific value can be found at. Defaults to 'values.yaml'. + maxLength: 253 + pattern: ^[\-._a-zA-Z0-9]+$ + type: string + required: + - kind + - name + type: object + type: array + required: + - chart + - interval + type: object + status: + default: + observedGeneration: -1 + description: HelmReleaseStatus defines the observed state of a HelmRelease. + properties: + conditions: + description: Conditions holds the conditions for the HelmRelease. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + failures: + description: Failures is the reconciliation failure count against + the latest desired state. It is reset after a successful reconciliation. + format: int64 + type: integer + helmChart: + description: HelmChart is the namespaced name of the HelmChart resource + created by the controller for the HelmRelease. + type: string + history: + description: History holds the history of Helm releases performed + for this HelmRelease up to the last successfully completed release. + items: + description: Snapshot captures a point-in-time copy of the status + information for a Helm release, as managed by the controller. + properties: + apiVersion: + description: 'APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field + is changed, this field will be used to distinguish between + the old and new methods.' + type: string + chartName: + description: ChartName is the chart name of the release object + in storage. + type: string + chartVersion: + description: ChartVersion is the chart version of the release + object in storage. + type: string + configDigest: + description: ConfigDigest is the checksum of the config (better + known as "values") of the release object in storage. It has + the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: Digest is the checksum of the release object in + storage. It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed + to. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: TestHookStatus holds the status information for + a test hook as observed to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last + completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was + last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: TestHooks is the list of test hooks for the release + as observed to be run by the controller. + type: object + version: + description: Version is the version of the release object in + storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array + installFailures: + description: InstallFailures is the install failure count against + the latest desired state. It is reset after a successful reconciliation. + format: int64 + type: integer + lastAppliedRevision: + description: 'LastAppliedRevision is the revision of the last successfully + applied source. Deprecated: the revision can now be found in the + History.' + type: string + lastAttemptedConfigDigest: + description: LastAttemptedConfigDigest is the digest for the config + (better known as "values") of the last reconciliation attempt. + type: string + lastAttemptedGeneration: + description: LastAttemptedGeneration is the last generation the controller + attempted to reconcile. + format: int64 + type: integer + lastAttemptedReleaseAction: + description: LastAttemptedReleaseAction is the last release action + performed for this HelmRelease. It is used to determine the active + remediation strategy. + enum: + - install + - upgrade + type: string + lastAttemptedRevision: + description: LastAttemptedRevision is the Source revision of the last + reconciliation attempt. + type: string + lastAttemptedValuesChecksum: + description: 'LastAttemptedValuesChecksum is the SHA1 checksum for + the values of the last reconciliation attempt. Deprecated: Use LastAttemptedConfigDigest + instead.' + type: string + lastHandledReconcileAt: + description: LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value can + be detected. + type: string + lastReleaseRevision: + description: 'LastReleaseRevision is the revision of the last successful + Helm release. Deprecated: Use History instead.' + type: integer + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + storageNamespace: + description: StorageNamespace is the namespace of the Helm release + storage for the current release. + maxLength: 63 + minLength: 1 + type: string upgradeFailures: description: UpgradeFailures is the upgrade failure count against the latest desired state. It is reset after a successful reconciliation. diff --git a/config/samples/helm_v2beta1_helmrelease_gitrepository.yaml b/config/samples/helm_v2beta2_helmrelease_gitrepository.yaml similarity index 87% rename from config/samples/helm_v2beta1_helmrelease_gitrepository.yaml rename to config/samples/helm_v2beta2_helmrelease_gitrepository.yaml index 256b8ca98..0f8d46335 100644 --- a/config/samples/helm_v2beta1_helmrelease_gitrepository.yaml +++ b/config/samples/helm_v2beta2_helmrelease_gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo-gitrepository diff --git a/config/samples/helm_v2beta1_helmrelease_helmrepository.yaml b/config/samples/helm_v2beta2_helmrelease_helmrepository.yaml similarity index 88% rename from config/samples/helm_v2beta1_helmrelease_helmrepository.yaml rename to config/samples/helm_v2beta2_helmrelease_helmrepository.yaml index 7a52c3a36..06461c1b1 100644 --- a/config/samples/helm_v2beta1_helmrelease_helmrepository.yaml +++ b/config/samples/helm_v2beta2_helmrelease_helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo-helmrepository diff --git a/config/testdata/crds-upgrade/create-replace/helmrelease.yaml b/config/testdata/crds-upgrade/create-replace/helmrelease.yaml index 5f21e5110..2df971a84 100644 --- a/config/testdata/crds-upgrade/create-replace/helmrelease.yaml +++ b/config/testdata/crds-upgrade/create-replace/helmrelease.yaml @@ -1,5 +1,5 @@ --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: crds-upgrade-test diff --git a/config/testdata/crds-upgrade/create/helmrelease.yaml b/config/testdata/crds-upgrade/create/helmrelease.yaml index de3b993e1..1e268c18e 100644 --- a/config/testdata/crds-upgrade/create/helmrelease.yaml +++ b/config/testdata/crds-upgrade/create/helmrelease.yaml @@ -1,5 +1,5 @@ --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: crds-upgrade-test diff --git a/config/testdata/crds-upgrade/init/helmrelease.yaml b/config/testdata/crds-upgrade/init/helmrelease.yaml index bfc595332..43da9323e 100644 --- a/config/testdata/crds-upgrade/init/helmrelease.yaml +++ b/config/testdata/crds-upgrade/init/helmrelease.yaml @@ -1,5 +1,5 @@ --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: crds-upgrade-test diff --git a/config/testdata/delete-ns/test.yaml b/config/testdata/delete-ns/test.yaml index f2bc4a082..71f10b596 100644 --- a/config/testdata/delete-ns/test.yaml +++ b/config/testdata/delete-ns/test.yaml @@ -51,7 +51,7 @@ spec: interval: 1m url: https://stefanprodan.github.io/podinfo --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo diff --git a/config/testdata/dependencies/helmrelease-backend.yaml b/config/testdata/dependencies/helmrelease-backend.yaml index abbad7c6c..bdf55e671 100644 --- a/config/testdata/dependencies/helmrelease-backend.yaml +++ b/config/testdata/dependencies/helmrelease-backend.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: backend diff --git a/config/testdata/dependencies/helmrelease-frontend.yaml b/config/testdata/dependencies/helmrelease-frontend.yaml index 5756725b4..91e327687 100644 --- a/config/testdata/dependencies/helmrelease-frontend.yaml +++ b/config/testdata/dependencies/helmrelease-frontend.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: frontend diff --git a/config/testdata/impersonation/test.yaml b/config/testdata/impersonation/test.yaml index e60c74a81..12edeea66 100644 --- a/config/testdata/impersonation/test.yaml +++ b/config/testdata/impersonation/test.yaml @@ -51,7 +51,7 @@ spec: interval: 1m url: https://stefanprodan.github.io/podinfo --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo @@ -67,7 +67,7 @@ spec: kind: HelmRepository name: podinfo --- -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo-fail diff --git a/config/testdata/install-create-target-ns/helmrelease.yaml b/config/testdata/install-create-target-ns/helmrelease.yaml index 69b3b8c10..92275fef8 100644 --- a/config/testdata/install-create-target-ns/helmrelease.yaml +++ b/config/testdata/install-create-target-ns/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-create-target-ns diff --git a/config/testdata/install-fail-remediate/helmrelease.yaml b/config/testdata/install-fail-remediate/helmrelease.yaml index 94733cee9..6dc456ce2 100644 --- a/config/testdata/install-fail-remediate/helmrelease.yaml +++ b/config/testdata/install-fail-remediate/helmrelease.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-fail-remediate spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,10 +11,12 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m install: remediation: remediateLastFailure: true + uninstall: + keepHistory: true values: resources: requests: diff --git a/config/testdata/install-fail-retry/helmrelease.yaml b/config/testdata/install-fail-retry/helmrelease.yaml index 72ad3adcb..0cb426996 100644 --- a/config/testdata/install-fail-retry/helmrelease.yaml +++ b/config/testdata/install-fail-retry/helmrelease.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-fail-retry spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m install: remediation: retries: 1 diff --git a/config/testdata/install-fail/helmrelease.yaml b/config/testdata/install-fail/helmrelease.yaml index 7cd37fc71..ef39c6e12 100644 --- a/config/testdata/install-fail/helmrelease.yaml +++ b/config/testdata/install-fail/helmrelease.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/install-test-fail-ignore/helmrelease.yaml b/config/testdata/install-test-fail-ignore/helmrelease.yaml index d4d050f89..7d1ec59d8 100644 --- a/config/testdata/install-test-fail-ignore/helmrelease.yaml +++ b/config/testdata/install-test-fail-ignore/helmrelease.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-test-fail-ignore spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m test: enable: true ignoreFailures: true diff --git a/config/testdata/install-test-fail/helmrelease.yaml b/config/testdata/install-test-fail/helmrelease.yaml index 39ea4d260..62e9c15e9 100644 --- a/config/testdata/install-test-fail/helmrelease.yaml +++ b/config/testdata/install-test-fail/helmrelease.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: install-test-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m test: enable: true values: diff --git a/config/testdata/podinfo/helmrelease-git.yaml b/config/testdata/podinfo/helmrelease-git.yaml index 2e8d46084..9ceffa8f6 100644 --- a/config/testdata/podinfo/helmrelease-git.yaml +++ b/config/testdata/podinfo/helmrelease-git.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo-git diff --git a/config/testdata/podinfo/helmrelease-oci.yaml b/config/testdata/podinfo/helmrelease-oci.yaml index 10e078bee..e1880d7a1 100644 --- a/config/testdata/podinfo/helmrelease-oci.yaml +++ b/config/testdata/podinfo/helmrelease-oci.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo-oci diff --git a/config/testdata/podinfo/helmrelease.yaml b/config/testdata/podinfo/helmrelease.yaml index 3c6c7b4b1..bd79661f7 100644 --- a/config/testdata/podinfo/helmrelease.yaml +++ b/config/testdata/podinfo/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: podinfo diff --git a/config/testdata/post-renderer-kustomize/helmrelease.yaml b/config/testdata/post-renderer-kustomize/helmrelease.yaml index 6f33528ba..9c5707604 100644 --- a/config/testdata/post-renderer-kustomize/helmrelease.yaml +++ b/config/testdata/post-renderer-kustomize/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: post-renderer-kustomize diff --git a/config/testdata/status-defaults/helmrelease.yaml b/config/testdata/status-defaults/helmrelease.yaml index 32d753ff7..ce7710dc6 100644 --- a/config/testdata/status-defaults/helmrelease.yaml +++ b/config/testdata/status-defaults/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: status-defaults diff --git a/config/testdata/targetnamespace/helmrelease.yaml b/config/testdata/targetnamespace/helmrelease.yaml index abe5e5747..80ac9e17a 100644 --- a/config/testdata/targetnamespace/helmrelease.yaml +++ b/config/testdata/targetnamespace/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: targetnamespace diff --git a/config/testdata/upgrade-fail-remediate-uninstall/install.yaml b/config/testdata/upgrade-fail-remediate-uninstall/install.yaml index 7871e8ac9..832c233f1 100644 --- a/config/testdata/upgrade-fail-remediate-uninstall/install.yaml +++ b/config/testdata/upgrade-fail-remediate-uninstall/install.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-remediate-uninstall spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-fail-remediate-uninstall/upgrade.yaml b/config/testdata/upgrade-fail-remediate-uninstall/upgrade.yaml index 92e372f31..4bc6d5e0d 100644 --- a/config/testdata/upgrade-fail-remediate-uninstall/upgrade.yaml +++ b/config/testdata/upgrade-fail-remediate-uninstall/upgrade.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-remediate-uninstall spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m upgrade: remediation: remediateLastFailure: true diff --git a/config/testdata/upgrade-fail-remediate/install.yaml b/config/testdata/upgrade-fail-remediate/install.yaml index a6b4e92a8..6245ab226 100644 --- a/config/testdata/upgrade-fail-remediate/install.yaml +++ b/config/testdata/upgrade-fail-remediate/install.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-remediate spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-fail-remediate/upgrade.yaml b/config/testdata/upgrade-fail-remediate/upgrade.yaml index a2def1fac..5aa9558fc 100644 --- a/config/testdata/upgrade-fail-remediate/upgrade.yaml +++ b/config/testdata/upgrade-fail-remediate/upgrade.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-remediate spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m upgrade: remediation: remediateLastFailure: true diff --git a/config/testdata/upgrade-fail-retry/install.yaml b/config/testdata/upgrade-fail-retry/install.yaml index 63cad76ee..3b9f838ac 100644 --- a/config/testdata/upgrade-fail-retry/install.yaml +++ b/config/testdata/upgrade-fail-retry/install.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-retry spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-fail-retry/upgrade.yaml b/config/testdata/upgrade-fail-retry/upgrade.yaml index 32ced3592..993eca57c 100644 --- a/config/testdata/upgrade-fail-retry/upgrade.yaml +++ b/config/testdata/upgrade-fail-retry/upgrade.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail-retry spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m upgrade: remediation: retries: 1 diff --git a/config/testdata/upgrade-fail/install.yaml b/config/testdata/upgrade-fail/install.yaml index 39a5414f2..aec23ce27 100644 --- a/config/testdata/upgrade-fail/install.yaml +++ b/config/testdata/upgrade-fail/install.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-fail/upgrade.yaml b/config/testdata/upgrade-fail/upgrade.yaml index edcc45f0e..08ef7abaf 100644 --- a/config/testdata/upgrade-fail/upgrade.yaml +++ b/config/testdata/upgrade-fail/upgrade.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-test-fail/install.yaml b/config/testdata/upgrade-test-fail/install.yaml index 78cbe3984..32216b5a9 100644 --- a/config/testdata/upgrade-test-fail/install.yaml +++ b/config/testdata/upgrade-test-fail/install.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-test-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m values: resources: requests: diff --git a/config/testdata/upgrade-test-fail/upgrade.yaml b/config/testdata/upgrade-test-fail/upgrade.yaml index defdcde49..96a3dac5c 100644 --- a/config/testdata/upgrade-test-fail/upgrade.yaml +++ b/config/testdata/upgrade-test-fail/upgrade.yaml @@ -1,9 +1,9 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: upgrade-test-fail spec: - interval: 5m + interval: 30s chart: spec: chart: podinfo @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m test: enable: true values: diff --git a/config/testdata/valuesfrom/helmrelease.yaml b/config/testdata/valuesfrom/helmrelease.yaml index 76937bfda..53e6cb4ce 100644 --- a/config/testdata/valuesfrom/helmrelease.yaml +++ b/config/testdata/valuesfrom/helmrelease.yaml @@ -1,4 +1,4 @@ -apiVersion: helm.toolkit.fluxcd.io/v2beta1 +apiVersion: helm.toolkit.fluxcd.io/v2beta2 kind: HelmRelease metadata: name: valuesfrom @@ -11,7 +11,7 @@ spec: sourceRef: kind: HelmRepository name: podinfo - interval: 1m + interval: 10m valuesFrom: - kind: ConfigMap name: valuesfrom-config diff --git a/docs/api/v2beta2/helm.md b/docs/api/v2beta2/helm.md new file mode 100644 index 000000000..bd2677ab2 --- /dev/null +++ b/docs/api/v2beta2/helm.md @@ -0,0 +1,2676 @@ +

Helm API reference v2beta2

+

Packages:

+ +

helm.toolkit.fluxcd.io/v2beta2

+

Package v2beta2 contains API Schema definitions for the helm v2beta2 API group

+Resource Types: + +

HelmRelease +

+

HelmRelease is the Schema for the helmreleases API

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+string
+helm.toolkit.fluxcd.io/v2beta2 +
+kind
+string +
+HelmRelease +
+metadata
+ + +Kubernetes meta/v1.ObjectMeta + + +
+Refer to the Kubernetes API documentation for the fields of the +metadata field. +
+spec
+ + +HelmReleaseSpec + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+chart
+ + +HelmChartTemplate + + +
+

Chart defines the template of the v1beta2.HelmChart that should be created +for this HelmRelease.

+
+interval
+ + +Kubernetes meta/v1.Duration + + +
+

Interval at which to reconcile the Helm release.

+
+kubeConfig
+ + +github.com/fluxcd/pkg/apis/meta.KubeConfigReference + + +
+(Optional) +

KubeConfig for reconciling the HelmRelease on a remote cluster. +When used in combination with HelmReleaseSpec.ServiceAccountName, +forces the controller to act on behalf of that Service Account at the +target cluster. +If the –default-service-account flag is set, its value will be used as +a controller level fallback for when HelmReleaseSpec.ServiceAccountName +is empty.

+
+suspend
+ +bool + +
+(Optional) +

Suspend tells the controller to suspend reconciliation for this HelmRelease, +it does not apply to already started reconciliations. Defaults to false.

+
+releaseName
+ +string + +
+(Optional) +

ReleaseName used for the Helm release. Defaults to a composition of +‘[TargetNamespace-]Name’.

+
+targetNamespace
+ +string + +
+(Optional) +

TargetNamespace to target when performing operations for the HelmRelease. +Defaults to the namespace of the HelmRelease.

+
+storageNamespace
+ +string + +
+(Optional) +

StorageNamespace used for the Helm storage. +Defaults to the namespace of the HelmRelease.

+
+dependsOn
+ + +[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference + + +
+(Optional) +

DependsOn may contain a meta.NamespacedObjectReference slice with +references to HelmRelease resources that must be ready before this HelmRelease +can be reconciled.

+
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like Jobs +for hooks) during the performance of a Helm action. Defaults to ‘5m0s’.

+
+maxHistory
+ +int + +
+(Optional) +

MaxHistory is the number of revisions saved by Helm for this HelmRelease. +Use ‘0’ for an unlimited number of revisions; defaults to ‘5’.

+
+serviceAccountName
+ +string + +
+(Optional) +

The name of the Kubernetes service account to impersonate +when reconciling this HelmRelease.

+
+persistentClient
+ +bool + +
+(Optional) +

PersistentClient tells the controller to use a persistent Kubernetes +client for this release. When enabled, the client will be reused for the +duration of the reconciliation, instead of being created and destroyed +for each (step of a) Helm action.

+

This can improve performance, but may cause issues with some Helm charts +that for example do create Custom Resource Definitions during installation +outside Helm’s CRD lifecycle hooks, which are then not observed to be +available by e.g. post-install hooks.

+

If not set, it defaults to true.

+
+install
+ + +Install + + +
+(Optional) +

Install holds the configuration for Helm install actions for this HelmRelease.

+
+upgrade
+ + +Upgrade + + +
+(Optional) +

Upgrade holds the configuration for Helm upgrade actions for this HelmRelease.

+
+test
+ + +Test + + +
+(Optional) +

Test holds the configuration for Helm test actions for this HelmRelease.

+
+rollback
+ + +Rollback + + +
+(Optional) +

Rollback holds the configuration for Helm rollback actions for this HelmRelease.

+
+uninstall
+ + +Uninstall + + +
+(Optional) +

Uninstall holds the configuration for Helm uninstall actions for this HelmRelease.

+
+valuesFrom
+ + +[]ValuesReference + + +
+

ValuesFrom holds references to resources containing Helm values for this HelmRelease, +and information about how they should be merged.

+
+values
+ + +Kubernetes pkg/apis/apiextensions/v1.JSON + + +
+(Optional) +

Values holds the values for this Helm release.

+
+postRenderers
+ + +[]PostRenderer + + +
+(Optional) +

PostRenderers holds an array of Helm PostRenderers, which will be applied in order +of their definition.

+
+
+status
+ + +HelmReleaseStatus + + +
+
+
+
+

CRDsPolicy +(string alias)

+

+(Appears on: +Install, +Upgrade) +

+

CRDsPolicy defines the install/upgrade approach to use for CRDs when +installing or upgrading a HelmRelease.

+

CrossNamespaceObjectReference +

+

+(Appears on: +HelmChartTemplateSpec) +

+

CrossNamespaceObjectReference contains enough information to let you locate +the typed referenced object at cluster level.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+ +string + +
+(Optional) +

APIVersion of the referent.

+
+kind
+ +string + +
+

Kind of the referent.

+
+name
+ +string + +
+

Name of the referent.

+
+namespace
+ +string + +
+(Optional) +

Namespace of the referent.

+
+
+
+

Filter +

+

+(Appears on: +Test) +

+

Filter holds the configuration for individual Helm test filters.

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+name
+ +string + +
+

Name is the name of the test.

+
+exclude
+ +bool + +
+(Optional) +

Exclude specifies whether the named test should be excluded.

+
+
+
+

HelmChartTemplate +

+

+(Appears on: +HelmReleaseSpec) +

+

HelmChartTemplate defines the template from which the controller will +generate a v1beta2.HelmChart object in the same namespace as the referenced +v1.Source.

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+metadata
+ + +HelmChartTemplateObjectMeta + + +
+(Optional) +

ObjectMeta holds the template for metadata like labels and annotations.

+
+spec
+ + +HelmChartTemplateSpec + + +
+

Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+chart
+ +string + +
+

The name or path the Helm chart is available at in the SourceRef.

+
+version
+ +string + +
+(Optional) +

Version semver expression, ignored for charts from v1beta2.GitRepository and +v1beta2.Bucket sources. Defaults to latest when omitted.

+
+sourceRef
+ + +CrossNamespaceObjectReference + + +
+

The name and namespace of the v1.Source the chart is available at.

+
+interval
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Interval at which to check the v1.Source for updates. Defaults to +‘HelmReleaseSpec.Interval’.

+
+reconcileStrategy
+ +string + +
+(Optional) +

Determines what enables the creation of a new artifact. Valid values are +(‘ChartVersion’, ‘Revision’). +See the documentation of the values for an explanation on their behavior. +Defaults to ChartVersion when omitted.

+
+valuesFiles
+ +[]string + +
+(Optional) +

Alternative list of values files to use as the chart values (values.yaml +is not included by default), expected to be a relative path in the SourceRef. +Values files are merged in the order of this list with the last file overriding +the first. Ignored when omitted.

+
+valuesFile
+ +string + +
+(Optional) +

Alternative values file to use as the default chart values, expected to +be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, +for backwards compatibility the file defined here is merged before the +ValuesFiles items. Ignored when omitted.

+
+verify
+ + +HelmChartTemplateVerification + + +
+(Optional) +

Verify contains the secret name containing the trusted public keys +used to verify the signature and specifies which provider to use to check +whether OCI image is authentic. +This field is only supported for OCI sources. +Chart dependencies, which are not bundled in the umbrella chart artifact, +are not verified.

+
+
+
+
+

HelmChartTemplateObjectMeta +

+

+(Appears on: +HelmChartTemplate) +

+

HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a +v1beta2.HelmChart.

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+labels
+ +map[string]string + +
+(Optional) +

Map of string keys and values that can be used to organize and categorize +(scope and select) objects. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/

+
+annotations
+ +map[string]string + +
+(Optional) +

Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/

+
+
+
+

HelmChartTemplateSpec +

+

+(Appears on: +HelmChartTemplate) +

+

HelmChartTemplateSpec defines the template from which the controller will +generate a v1beta2.HelmChartSpec object.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+chart
+ +string + +
+

The name or path the Helm chart is available at in the SourceRef.

+
+version
+ +string + +
+(Optional) +

Version semver expression, ignored for charts from v1beta2.GitRepository and +v1beta2.Bucket sources. Defaults to latest when omitted.

+
+sourceRef
+ + +CrossNamespaceObjectReference + + +
+

The name and namespace of the v1.Source the chart is available at.

+
+interval
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Interval at which to check the v1.Source for updates. Defaults to +‘HelmReleaseSpec.Interval’.

+
+reconcileStrategy
+ +string + +
+(Optional) +

Determines what enables the creation of a new artifact. Valid values are +(‘ChartVersion’, ‘Revision’). +See the documentation of the values for an explanation on their behavior. +Defaults to ChartVersion when omitted.

+
+valuesFiles
+ +[]string + +
+(Optional) +

Alternative list of values files to use as the chart values (values.yaml +is not included by default), expected to be a relative path in the SourceRef. +Values files are merged in the order of this list with the last file overriding +the first. Ignored when omitted.

+
+valuesFile
+ +string + +
+(Optional) +

Alternative values file to use as the default chart values, expected to +be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, +for backwards compatibility the file defined here is merged before the +ValuesFiles items. Ignored when omitted.

+
+verify
+ + +HelmChartTemplateVerification + + +
+(Optional) +

Verify contains the secret name containing the trusted public keys +used to verify the signature and specifies which provider to use to check +whether OCI image is authentic. +This field is only supported for OCI sources. +Chart dependencies, which are not bundled in the umbrella chart artifact, +are not verified.

+
+
+
+

HelmChartTemplateVerification +

+

+(Appears on: +HelmChartTemplateSpec) +

+

HelmChartTemplateVerification verifies the authenticity of an OCI Helm chart.

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+provider
+ +string + +
+

Provider specifies the technology used to sign the OCI Helm chart.

+
+secretRef
+ + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
+(Optional) +

SecretRef specifies the Kubernetes Secret containing the +trusted public keys.

+
+
+
+

HelmReleaseSpec +

+

+(Appears on: +HelmRelease) +

+

HelmReleaseSpec defines the desired state of a Helm release.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+chart
+ + +HelmChartTemplate + + +
+

Chart defines the template of the v1beta2.HelmChart that should be created +for this HelmRelease.

+
+interval
+ + +Kubernetes meta/v1.Duration + + +
+

Interval at which to reconcile the Helm release.

+
+kubeConfig
+ + +github.com/fluxcd/pkg/apis/meta.KubeConfigReference + + +
+(Optional) +

KubeConfig for reconciling the HelmRelease on a remote cluster. +When used in combination with HelmReleaseSpec.ServiceAccountName, +forces the controller to act on behalf of that Service Account at the +target cluster. +If the –default-service-account flag is set, its value will be used as +a controller level fallback for when HelmReleaseSpec.ServiceAccountName +is empty.

+
+suspend
+ +bool + +
+(Optional) +

Suspend tells the controller to suspend reconciliation for this HelmRelease, +it does not apply to already started reconciliations. Defaults to false.

+
+releaseName
+ +string + +
+(Optional) +

ReleaseName used for the Helm release. Defaults to a composition of +‘[TargetNamespace-]Name’.

+
+targetNamespace
+ +string + +
+(Optional) +

TargetNamespace to target when performing operations for the HelmRelease. +Defaults to the namespace of the HelmRelease.

+
+storageNamespace
+ +string + +
+(Optional) +

StorageNamespace used for the Helm storage. +Defaults to the namespace of the HelmRelease.

+
+dependsOn
+ + +[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference + + +
+(Optional) +

DependsOn may contain a meta.NamespacedObjectReference slice with +references to HelmRelease resources that must be ready before this HelmRelease +can be reconciled.

+
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like Jobs +for hooks) during the performance of a Helm action. Defaults to ‘5m0s’.

+
+maxHistory
+ +int + +
+(Optional) +

MaxHistory is the number of revisions saved by Helm for this HelmRelease. +Use ‘0’ for an unlimited number of revisions; defaults to ‘5’.

+
+serviceAccountName
+ +string + +
+(Optional) +

The name of the Kubernetes service account to impersonate +when reconciling this HelmRelease.

+
+persistentClient
+ +bool + +
+(Optional) +

PersistentClient tells the controller to use a persistent Kubernetes +client for this release. When enabled, the client will be reused for the +duration of the reconciliation, instead of being created and destroyed +for each (step of a) Helm action.

+

This can improve performance, but may cause issues with some Helm charts +that for example do create Custom Resource Definitions during installation +outside Helm’s CRD lifecycle hooks, which are then not observed to be +available by e.g. post-install hooks.

+

If not set, it defaults to true.

+
+install
+ + +Install + + +
+(Optional) +

Install holds the configuration for Helm install actions for this HelmRelease.

+
+upgrade
+ + +Upgrade + + +
+(Optional) +

Upgrade holds the configuration for Helm upgrade actions for this HelmRelease.

+
+test
+ + +Test + + +
+(Optional) +

Test holds the configuration for Helm test actions for this HelmRelease.

+
+rollback
+ + +Rollback + + +
+(Optional) +

Rollback holds the configuration for Helm rollback actions for this HelmRelease.

+
+uninstall
+ + +Uninstall + + +
+(Optional) +

Uninstall holds the configuration for Helm uninstall actions for this HelmRelease.

+
+valuesFrom
+ + +[]ValuesReference + + +
+

ValuesFrom holds references to resources containing Helm values for this HelmRelease, +and information about how they should be merged.

+
+values
+ + +Kubernetes pkg/apis/apiextensions/v1.JSON + + +
+(Optional) +

Values holds the values for this Helm release.

+
+postRenderers
+ + +[]PostRenderer + + +
+(Optional) +

PostRenderers holds an array of Helm PostRenderers, which will be applied in order +of their definition.

+
+
+
+

HelmReleaseStatus +

+

+(Appears on: +HelmRelease) +

+

HelmReleaseStatus defines the observed state of a HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+observedGeneration
+ +int64 + +
+(Optional) +

ObservedGeneration is the last observed generation.

+
+lastAttemptedGeneration
+ +int64 + +
+(Optional) +

LastAttemptedGeneration is the last generation the controller attempted +to reconcile.

+
+conditions
+ + +[]Kubernetes meta/v1.Condition + + +
+(Optional) +

Conditions holds the conditions for the HelmRelease.

+
+helmChart
+ +string + +
+(Optional) +

HelmChart is the namespaced name of the HelmChart resource created by +the controller for the HelmRelease.

+
+storageNamespace
+ +string + +
+(Optional) +

StorageNamespace is the namespace of the Helm release storage for the +current release.

+
+history
+ + +Snapshots + + +
+(Optional) +

History holds the history of Helm releases performed for this HelmRelease +up to the last successfully completed release.

+
+lastAttemptedReleaseAction
+ + +ReleaseAction + + +
+(Optional) +

LastAttemptedReleaseAction is the last release action performed for this +HelmRelease. It is used to determine the active remediation strategy.

+
+failures
+ +int64 + +
+(Optional) +

Failures is the reconciliation failure count against the latest desired +state. It is reset after a successful reconciliation.

+
+installFailures
+ +int64 + +
+(Optional) +

InstallFailures is the install failure count against the latest desired +state. It is reset after a successful reconciliation.

+
+upgradeFailures
+ +int64 + +
+(Optional) +

UpgradeFailures is the upgrade failure count against the latest desired +state. It is reset after a successful reconciliation.

+
+lastAppliedRevision
+ +string + +
+(Optional) +

LastAppliedRevision is the revision of the last successfully applied +source. +Deprecated: the revision can now be found in the History.

+
+lastAttemptedRevision
+ +string + +
+(Optional) +

LastAttemptedRevision is the Source revision of the last reconciliation +attempt.

+
+lastAttemptedValuesChecksum
+ +string + +
+(Optional) +

LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last +reconciliation attempt. +Deprecated: Use LastAttemptedConfigDigest instead.

+
+lastReleaseRevision
+ +int + +
+(Optional) +

LastReleaseRevision is the revision of the last successful Helm release. +Deprecated: Use History instead.

+
+lastAttemptedConfigDigest
+ +string + +
+(Optional) +

LastAttemptedConfigDigest is the digest for the config (better known as +“values”) of the last reconciliation attempt.

+
+ReconcileRequestStatus
+ + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus + + +
+

+(Members of ReconcileRequestStatus are embedded into this type.) +

+
+
+
+

Install +

+

+(Appears on: +HelmReleaseSpec) +

+

Install holds the configuration for Helm install actions performed for this +HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like +Jobs for hooks) during the performance of a Helm install action. Defaults to +‘HelmReleaseSpec.Timeout’.

+
+remediation
+ + +InstallRemediation + + +
+(Optional) +

Remediation holds the remediation configuration for when the Helm install +action for the HelmRelease fails. The default is to not perform any action.

+
+disableWait
+ +bool + +
+(Optional) +

DisableWait disables the waiting for resources to be ready after a Helm +install has been performed.

+
+disableWaitForJobs
+ +bool + +
+(Optional) +

DisableWaitForJobs disables waiting for jobs to complete after a Helm +install has been performed.

+
+disableHooks
+ +bool + +
+(Optional) +

DisableHooks prevents hooks from running during the Helm install action.

+
+disableOpenAPIValidation
+ +bool + +
+(Optional) +

DisableOpenAPIValidation prevents the Helm install action from validating +rendered templates against the Kubernetes OpenAPI Schema.

+
+replace
+ +bool + +
+(Optional) +

Replace tells the Helm install action to re-use the ‘ReleaseName’, but only +if that name is a deleted release which remains in the history.

+
+skipCRDs
+ +bool + +
+(Optional) +

SkipCRDs tells the Helm install action to not install any CRDs. By default, +CRDs are installed if not already present.

+

Deprecated use CRD policy (crds) attribute with value Skip instead.

+
+crds
+ + +CRDsPolicy + + +
+(Optional) +

CRDs upgrade CRDs from the Helm Chart’s crds directory according +to the CRD upgrade policy provided here. Valid values are Skip, +Create or CreateReplace. Default is Create and if omitted +CRDs are installed but not updated.

+

Skip: do neither install nor replace (update) any CRDs.

+

Create: new CRDs are created, existing CRDs are neither updated nor deleted.

+

CreateReplace: new CRDs are created, existing CRDs are updated (replaced) +but not deleted.

+

By default, CRDs are applied (installed) during Helm install action. +With this option users can opt in to CRD replace existing CRDs on Helm +install actions, which is not (yet) natively supported by Helm. +https://helm.sh/docs/chart_best_practices/custom_resource_definitions.

+
+createNamespace
+ +bool + +
+(Optional) +

CreateNamespace tells the Helm install action to create the +HelmReleaseSpec.TargetNamespace if it does not exist yet. +On uninstall, the namespace will not be garbage collected.

+
+
+
+

InstallRemediation +

+

+(Appears on: +Install) +

+

InstallRemediation holds the configuration for Helm install remediation.

+
+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+retries
+ +int + +
+(Optional) +

Retries is the number of retries that should be attempted on failures before +bailing. Remediation, using an uninstall, is performed between each attempt. +Defaults to ‘0’, a negative integer equals to unlimited retries.

+
+ignoreTestFailures
+ +bool + +
+(Optional) +

IgnoreTestFailures tells the controller to skip remediation when the Helm +tests are run after an install action but fail. Defaults to +‘Test.IgnoreFailures’.

+
+remediateLastFailure
+ +bool + +
+(Optional) +

RemediateLastFailure tells the controller to remediate the last failure, when +no retries remain. Defaults to ‘false’.

+
+
+
+

Kustomize +

+

+(Appears on: +PostRenderer) +

+

Kustomize Helm PostRenderer specification.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+patches
+ + +[]github.com/fluxcd/pkg/apis/kustomize.Patch + + +
+(Optional) +

Strategic merge and JSON patches, defined as inline YAML objects, +capable of targeting objects based on kind, label and annotation selectors.

+
+patchesStrategicMerge
+ + +[]Kubernetes pkg/apis/apiextensions/v1.JSON + + +
+(Optional) +

Strategic merge patches, defined as inline YAML objects.

+
+patchesJson6902
+ + +[]github.com/fluxcd/pkg/apis/kustomize.JSON6902Patch + + +
+(Optional) +

JSON 6902 patches, defined as inline YAML objects.

+
+images
+ + +[]github.com/fluxcd/pkg/apis/kustomize.Image + + +
+(Optional) +

Images is a list of (image name, new name, new tag or digest) +for changing image names, tags or digests. This can also be achieved with a +patch, but this operator is simpler to specify.

+
+
+
+

PostRenderer +

+

+(Appears on: +HelmReleaseSpec) +

+

PostRenderer contains a Helm PostRenderer specification.

+
+
+ + + + + + + + + + + + + +
FieldDescription
+kustomize
+ + +Kustomize + + +
+(Optional) +

Kustomization to apply as PostRenderer.

+
+
+
+

ReleaseAction +(string alias)

+

+(Appears on: +HelmReleaseStatus) +

+

ReleaseAction is the action to perform a Helm release.

+

Remediation +

+

Remediation defines a consistent interface for InstallRemediation and +UpgradeRemediation.

+

RemediationStrategy +(string alias)

+

+(Appears on: +UpgradeRemediation) +

+

RemediationStrategy returns the strategy to use to remediate a failed install +or upgrade.

+

Rollback +

+

+(Appears on: +HelmReleaseSpec) +

+

Rollback holds the configuration for Helm rollback actions for this +HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like +Jobs for hooks) during the performance of a Helm rollback action. Defaults to +‘HelmReleaseSpec.Timeout’.

+
+disableWait
+ +bool + +
+(Optional) +

DisableWait disables the waiting for resources to be ready after a Helm +rollback has been performed.

+
+disableWaitForJobs
+ +bool + +
+(Optional) +

DisableWaitForJobs disables waiting for jobs to complete after a Helm +rollback has been performed.

+
+disableHooks
+ +bool + +
+(Optional) +

DisableHooks prevents hooks from running during the Helm rollback action.

+
+recreate
+ +bool + +
+(Optional) +

Recreate performs pod restarts for the resource if applicable.

+
+force
+ +bool + +
+(Optional) +

Force forces resource updates through a replacement strategy.

+
+cleanupOnFail
+ +bool + +
+(Optional) +

CleanupOnFail allows deletion of new resources created during the Helm +rollback action when it fails.

+
+
+
+

Snapshot +

+

Snapshot captures a point-in-time copy of the status information for a Helm release, +as managed by the controller.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+ +string + +
+(Optional) +

APIVersion is the API version of the Snapshot. +Provisional: when the calculation method of the Digest field is changed, +this field will be used to distinguish between the old and new methods.

+
+digest
+ +string + +
+

Digest is the checksum of the release object in storage. +It has the format of <algo>:<checksum>.

+
+name
+ +string + +
+

Name is the name of the release.

+
+namespace
+ +string + +
+

Namespace is the namespace the release is deployed to.

+
+version
+ +int + +
+

Version is the version of the release object in storage.

+
+status
+ +string + +
+

Status is the current state of the release.

+
+chartName
+ +string + +
+

ChartName is the chart name of the release object in storage.

+
+chartVersion
+ +string + +
+

ChartVersion is the chart version of the release object in +storage.

+
+configDigest
+ +string + +
+

ConfigDigest is the checksum of the config (better known as +“values”) of the release object in storage. +It has the format of <algo>:<checksum>.

+
+firstDeployed
+ + +Kubernetes meta/v1.Time + + +
+

FirstDeployed is when the release was first deployed.

+
+lastDeployed
+ + +Kubernetes meta/v1.Time + + +
+

LastDeployed is when the release was last deployed.

+
+deleted
+ + +Kubernetes meta/v1.Time + + +
+(Optional) +

Deleted is when the release was deleted.

+
+testHooks
+ + +TestHookStatus + + +
+(Optional) +

TestHooks is the list of test hooks for the release as observed to be +run by the controller.

+
+
+
+

Snapshots +([]*./api/v2beta2.Snapshot alias)

+

+(Appears on: +HelmReleaseStatus) +

+

Snapshots is a list of Snapshot objects.

+

Test +

+

+(Appears on: +HelmReleaseSpec) +

+

Test holds the configuration for Helm test actions for this HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+enable
+ +bool + +
+(Optional) +

Enable enables Helm test actions for this HelmRelease after an Helm install +or upgrade action has been performed.

+
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation during +the performance of a Helm test action. Defaults to ‘HelmReleaseSpec.Timeout’.

+
+ignoreFailures
+ +bool + +
+(Optional) +

IgnoreFailures tells the controller to skip remediation when the Helm tests +are run but fail. Can be overwritten for tests run after install or upgrade +actions in ‘Install.IgnoreTestFailures’ and ‘Upgrade.IgnoreTestFailures’.

+
+filters
+ + +Filter + + +
+

Filters is a list of tests to run or exclude from running.

+
+
+
+

TestHookStatus +

+

+(Appears on: +Snapshot) +

+

TestHookStatus holds the status information for a test hook as observed +to be run by the controller.

+
+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+lastStarted
+ + +Kubernetes meta/v1.Time + + +
+(Optional) +

LastStarted is the time the test hook was last started.

+
+lastCompleted
+ + +Kubernetes meta/v1.Time + + +
+(Optional) +

LastCompleted is the time the test hook last completed.

+
+phase
+ +string + +
+(Optional) +

Phase the test hook was observed to be in.

+
+
+
+

Uninstall +

+

+(Appears on: +HelmReleaseSpec) +

+

Uninstall holds the configuration for Helm uninstall actions for this +HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like +Jobs for hooks) during the performance of a Helm uninstall action. Defaults +to ‘HelmReleaseSpec.Timeout’.

+
+disableHooks
+ +bool + +
+(Optional) +

DisableHooks prevents hooks from running during the Helm rollback action.

+
+keepHistory
+ +bool + +
+(Optional) +

KeepHistory tells Helm to remove all associated resources and mark the +release as deleted, but retain the release history.

+
+disableWait
+ +bool + +
+(Optional) +

DisableWait disables waiting for all the resources to be deleted after +a Helm uninstall is performed.

+
+deletionPropagation
+ +string + +
+(Optional) +

DeletionPropagation specifies the deletion propagation policy when +a Helm uninstall is performed.

+
+
+
+

Upgrade +

+

+(Appears on: +HelmReleaseSpec) +

+

Upgrade holds the configuration for Helm upgrade actions for this +HelmRelease.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+timeout
+ + +Kubernetes meta/v1.Duration + + +
+(Optional) +

Timeout is the time to wait for any individual Kubernetes operation (like +Jobs for hooks) during the performance of a Helm upgrade action. Defaults to +‘HelmReleaseSpec.Timeout’.

+
+remediation
+ + +UpgradeRemediation + + +
+(Optional) +

Remediation holds the remediation configuration for when the Helm upgrade +action for the HelmRelease fails. The default is to not perform any action.

+
+disableWait
+ +bool + +
+(Optional) +

DisableWait disables the waiting for resources to be ready after a Helm +upgrade has been performed.

+
+disableWaitForJobs
+ +bool + +
+(Optional) +

DisableWaitForJobs disables waiting for jobs to complete after a Helm +upgrade has been performed.

+
+disableHooks
+ +bool + +
+(Optional) +

DisableHooks prevents hooks from running during the Helm upgrade action.

+
+disableOpenAPIValidation
+ +bool + +
+(Optional) +

DisableOpenAPIValidation prevents the Helm upgrade action from validating +rendered templates against the Kubernetes OpenAPI Schema.

+
+force
+ +bool + +
+(Optional) +

Force forces resource updates through a replacement strategy.

+
+preserveValues
+ +bool + +
+(Optional) +

PreserveValues will make Helm reuse the last release’s values and merge in +overrides from ‘Values’. Setting this flag makes the HelmRelease +non-declarative.

+
+cleanupOnFail
+ +bool + +
+(Optional) +

CleanupOnFail allows deletion of new resources created during the Helm +upgrade action when it fails.

+
+crds
+ + +CRDsPolicy + + +
+(Optional) +

CRDs upgrade CRDs from the Helm Chart’s crds directory according +to the CRD upgrade policy provided here. Valid values are Skip, +Create or CreateReplace. Default is Skip and if omitted +CRDs are neither installed nor upgraded.

+

Skip: do neither install nor replace (update) any CRDs.

+

Create: new CRDs are created, existing CRDs are neither updated nor deleted.

+

CreateReplace: new CRDs are created, existing CRDs are updated (replaced) +but not deleted.

+

By default, CRDs are not applied during Helm upgrade action. With this +option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. +https://helm.sh/docs/chart_best_practices/custom_resource_definitions.

+
+
+
+

UpgradeRemediation +

+

+(Appears on: +Upgrade) +

+

UpgradeRemediation holds the configuration for Helm upgrade remediation.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+retries
+ +int + +
+(Optional) +

Retries is the number of retries that should be attempted on failures before +bailing. Remediation, using ‘Strategy’, is performed between each attempt. +Defaults to ‘0’, a negative integer equals to unlimited retries.

+
+ignoreTestFailures
+ +bool + +
+(Optional) +

IgnoreTestFailures tells the controller to skip remediation when the Helm +tests are run after an upgrade action but fail. +Defaults to ‘Test.IgnoreFailures’.

+
+remediateLastFailure
+ +bool + +
+(Optional) +

RemediateLastFailure tells the controller to remediate the last failure, when +no retries remain. Defaults to ‘false’ unless ‘Retries’ is greater than 0.

+
+strategy
+ + +RemediationStrategy + + +
+(Optional) +

Strategy to use for failure remediation. Defaults to ‘rollback’.

+
+
+
+

ValuesReference +

+

+(Appears on: +HelmReleaseSpec) +

+

ValuesReference contains a reference to a resource containing Helm values, +and optionally the key they can be found at.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+kind
+ +string + +
+

Kind of the values referent, valid values are (‘Secret’, ‘ConfigMap’).

+
+name
+ +string + +
+

Name of the values referent. Should reside in the same namespace as the +referring resource.

+
+valuesKey
+ +string + +
+(Optional) +

ValuesKey is the data key where the values.yaml or a specific value can be +found at. Defaults to ‘values.yaml’.

+
+targetPath
+ +string + +
+(Optional) +

TargetPath is the YAML dot notation path the value should be merged at. When +set, the ValuesKey is expected to be a single flat value. Defaults to ‘None’, +which results in the values getting merged at the root.

+
+optional
+ +bool + +
+(Optional) +

Optional marks this ValuesReference as optional. When set, a not found error +for the values reference is ignored, but any ValuesKey, TargetPath or +transient error will still result in a reconciliation failure.

+
+
+
+
+

This page was automatically generated with gen-crd-api-reference-docs

+
diff --git a/go.mod b/go.mod index 4502ebd31..174a31f6a 100644 --- a/go.mod +++ b/go.mod @@ -22,14 +22,17 @@ require ( github.com/fluxcd/pkg/apis/meta v1.1.2 github.com/fluxcd/pkg/runtime v0.42.0 github.com/fluxcd/pkg/ssa v0.32.0 + github.com/fluxcd/pkg/testserver v0.4.0 github.com/fluxcd/source-controller/api v1.1.2 github.com/go-logr/logr v1.2.4 github.com/google/go-cmp v0.5.9 github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/mitchellh/copystructure v1.2.0 github.com/onsi/gomega v1.27.10 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest/blake3 v0.0.0-20230815154656-802ce17c4f59 github.com/spf13/pflag v1.0.5 + golang.org/x/text v0.13.0 gopkg.in/yaml.v2 v2.4.0 helm.sh/helm/v3 v3.12.3 k8s.io/api v0.27.4 @@ -37,6 +40,7 @@ require ( k8s.io/apimachinery v0.27.4 k8s.io/cli-runtime v0.27.4 k8s.io/client-go v0.27.4 + k8s.io/kubectl v0.27.4 k8s.io/utils v0.0.0-20230505201702-9f6742963106 sigs.k8s.io/cli-utils v0.35.0 sigs.k8s.io/controller-runtime v0.15.1 @@ -113,7 +117,6 @@ require ( github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect @@ -127,6 +130,7 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect @@ -137,6 +141,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.7.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect @@ -153,7 +158,6 @@ require ( golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -166,7 +170,6 @@ require ( k8s.io/component-base v0.27.4 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - k8s.io/kubectl v0.27.3 // indirect oras.land/oras-go v1.2.4 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect diff --git a/go.sum b/go.sum index 9d9db1431..4604cc11f 100644 --- a/go.sum +++ b/go.sum @@ -178,6 +178,8 @@ github.com/fluxcd/pkg/runtime v0.42.0 h1:a5DQ/f90YjoHBmiXZUpnp4bDSLORjInbmqP7K11 github.com/fluxcd/pkg/runtime v0.42.0/go.mod h1:p6A3xWVV8cKLLQW0N90GehKgGMMmbNYv+OSJ/0qB0vg= github.com/fluxcd/pkg/ssa v0.32.0 h1:RBqs9DNrbJkFHjpfsiKilyean7gwqWFspSBTLOaBIHs= github.com/fluxcd/pkg/ssa v0.32.0/go.mod h1:+Kf5euYAbvgJX645bo+IL7V/NlH0X7kGgFTr1W++I3c= +github.com/fluxcd/pkg/testserver v0.4.0 h1:pDZ3gistqYhwlf3sAjn1Q8NzN4Qe6I1BEmHMHi46lMg= +github.com/fluxcd/pkg/testserver v0.4.0/go.mod h1:gjOKX41okmrGYOa4oOF2fiLedDAfPo1XaG/EzrUUGBI= github.com/fluxcd/source-controller/api v1.1.2 h1:FfKDKVWnopo+Q2pOAxgHEjrtr4MP41L8aapR4mqBhBk= github.com/fluxcd/source-controller/api v1.1.2/go.mod h1:ZLkaUd1KQIjtLPCvO63Ni5zpnSTVBAkeRgFBzMItbDQ= github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= @@ -607,6 +609,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -1114,8 +1117,8 @@ k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/kubectl v0.27.3 h1:HyC4o+8rCYheGDWrkcOQHGwDmyLKR5bxXFgpvF82BOw= -k8s.io/kubectl v0.27.3/go.mod h1:g9OQNCC2zxT+LT3FS09ZYqnDhlvsKAfFq76oyarBcq4= +k8s.io/kubectl v0.27.4 h1:RV1TQLIbtL34+vIM+W7HaS3KfAbqvy9lWn6pWB9els4= +k8s.io/kubectl v0.27.4/go.mod h1:qtc1s3BouB9KixJkriZMQqTsXMc+OAni6FeKAhq7q14= k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 439ccd868..44d2aa16e 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2021 The Flux authors +Copyright 2022 The Flux authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/acl/acl.go b/internal/acl/acl.go new file mode 100644 index 000000000..b27b263ec --- /dev/null +++ b/internal/acl/acl.go @@ -0,0 +1,43 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package acl + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/fluxcd/pkg/runtime/acl" +) + +var ( + // AllowCrossNamespaceRef is a global flag that can be used to allow + // cross-namespace references. + AllowCrossNamespaceRef = false +) + +// AllowsAccessTo returns an error if the object does not allow access to the +// given reference. +func AllowsAccessTo(obj client.Object, kind string, ref types.NamespacedName) error { + if !AllowCrossNamespaceRef && obj.GetNamespace() != ref.Namespace { + return acl.AccessDeniedError(fmt.Sprintf("cross-namespace references are not allowed: cannot access %s %s", + kind, ref.String(), + )) + } + return nil +} diff --git a/internal/acl/acl_test.go b/internal/acl/acl_test.go new file mode 100644 index 000000000..2ebf8c8bc --- /dev/null +++ b/internal/acl/acl_test.go @@ -0,0 +1,93 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package acl + +import ( + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "testing" +) + +func TestAllowsAccessTo(t *testing.T) { + tests := []struct { + name string + allow bool + obj client.Object + ref types.NamespacedName + wantErr bool + }{ + { + name: "allow cross-namespace reference", + allow: true, + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "some-name", + Namespace: "some-namespace", + }, + }, + ref: types.NamespacedName{ + Name: "some-name", + Namespace: "some-other-namespace", + }, + wantErr: false, + }, + { + name: "disallow cross-namespace reference", + allow: false, + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "some-name", + Namespace: "some-namespace", + }, + }, + ref: types.NamespacedName{ + Name: "some-name", + Namespace: "some-other-namespace", + }, + wantErr: true, + }, + { + name: "allow same-namespace reference", + allow: false, + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "some-name", + Namespace: "some-namespace", + }, + }, + ref: types.NamespacedName{ + Name: "some-name", + Namespace: "some-namespace", + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + curAllow := AllowCrossNamespaceRef + AllowCrossNamespaceRef = tt.allow + t.Cleanup(func() { AllowCrossNamespaceRef = curAllow }) + + if err := AllowsAccessTo(tt.obj, "mock", tt.ref); (err != nil) != tt.wantErr { + t.Errorf("AllowsAccessTo() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/action/config.go b/internal/action/config.go new file mode 100644 index 000000000..a247359e3 --- /dev/null +++ b/internal/action/config.go @@ -0,0 +1,179 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "fmt" + + helmaction "helm.sh/helm/v3/pkg/action" + helmkube "helm.sh/helm/v3/pkg/kube" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/fluxcd/helm-controller/internal/storage" +) + +const ( + // DefaultStorageDriver is the default Helm storage driver. + DefaultStorageDriver = helmdriver.SecretsDriverName +) + +// ConfigFactory is a factory for the Helm action configuration of a (series +// of) Helm action(s). It allows for sharing Kubernetes client(s) and the +// Helm storage driver between actions, where possible. +// +// To get a Helm action.Configuration for an action, use the Build method on an +// initialized factory. +type ConfigFactory struct { + // Getter is the RESTClientGetter used to get the RESTClient for the + // Kubernetes API. + Getter genericclioptions.RESTClientGetter + // KubeClient is the (Helm) Kubernetes client, it is Helm-specific and + // contains a factory used for lazy-loading. + KubeClient *helmkube.Client + // Driver to use for the Helm action. + Driver helmdriver.Driver + // StorageLog is the logger to use for the Helm storage driver. + StorageLog helmaction.DebugLog +} + +// ConfigFactoryOption is a function that configures a ConfigFactory. +type ConfigFactoryOption func(*ConfigFactory) error + +// NewConfigFactory returns a new ConfigFactory configured with the provided +// options. +func NewConfigFactory(getter genericclioptions.RESTClientGetter, opts ...ConfigFactoryOption) (*ConfigFactory, error) { + kubeClient := helmkube.New(getter) + factory := &ConfigFactory{ + Getter: getter, + KubeClient: kubeClient, + } + for _, opt := range opts { + if err := opt(factory); err != nil { + return nil, err + } + } + if err := factory.Valid(); err != nil { + return nil, err + } + return factory, nil +} + +// WithStorage configures the ConfigFactory.Driver by constructing a new Helm +// driver.Driver using the provided driver name and namespace. +// It supports driver.ConfigMapsDriverName, driver.SecretsDriverName and +// driver.MemoryDriverName. +// It returns an error when the driver name is not supported, or the client +// configuration for the storage fails. +func WithStorage(driver, namespace string) ConfigFactoryOption { + if driver == "" { + driver = DefaultStorageDriver + } + + return func(f *ConfigFactory) error { + if namespace == "" { + return fmt.Errorf("no namespace provided for '%s' storage driver", driver) + } + + switch driver { + case helmdriver.SecretsDriverName, helmdriver.ConfigMapsDriverName, "": + clientSet, err := f.KubeClient.Factory.KubernetesClientSet() + if err != nil { + return fmt.Errorf("could not get client set for '%s' storage driver: %w", driver, err) + } + if driver == helmdriver.ConfigMapsDriverName { + f.Driver = helmdriver.NewConfigMaps(clientSet.CoreV1().ConfigMaps(namespace)) + } + if driver == helmdriver.SecretsDriverName { + f.Driver = helmdriver.NewSecrets(clientSet.CoreV1().Secrets(namespace)) + } + case helmdriver.MemoryDriverName: + driver := helmdriver.NewMemory() + driver.SetNamespace(namespace) + f.Driver = driver + default: + return fmt.Errorf("unsupported Helm storage driver '%s'", driver) + } + return nil + } +} + +// WithDriver sets the ConfigFactory.Driver. +func WithDriver(driver helmdriver.Driver) ConfigFactoryOption { + return func(f *ConfigFactory) error { + f.Driver = driver + return nil + } +} + +// WithStorageLog sets the ConfigFactory.StorageLog. +func WithStorageLog(log helmaction.DebugLog) ConfigFactoryOption { + return func(f *ConfigFactory) error { + f.StorageLog = log + return nil + } +} + +// NewStorage returns a new Helm storage.Storage configured with any +// observer(s) and the Driver configured on the ConfigFactory. +func (c *ConfigFactory) NewStorage(observers ...storage.ObserveFunc) *helmstorage.Storage { + driver := c.Driver + if len(observers) > 0 { + driver = storage.NewObserver(driver, observers...) + } + s := helmstorage.Init(driver) + if c.StorageLog != nil { + s.Log = c.StorageLog + } + return s +} + +// Build returns a new Helm action.Configuration configured with the receiver +// values, and the provided logger and observer(s). +func (c *ConfigFactory) Build(log helmaction.DebugLog, observers ...storage.ObserveFunc) *helmaction.Configuration { + client := c.KubeClient + if log != nil { + // As Helm emits important information to the log of the client, we + // need to configure it with the same logger as the action.Configuration. + // This is not ideal, as we would like to re-use the client between + // actions, but otherwise this would not be thread-safe. + client = helmkube.New(c.Getter) + client.Log = log + } + + return &helmaction.Configuration{ + RESTClientGetter: c.Getter, + Releases: c.NewStorage(observers...), + KubeClient: client, + Log: log, + } +} + +// Valid returns an error if the ConfigFactory is missing configuration +// required to run a Helm action. +func (c *ConfigFactory) Valid() error { + switch { + case c == nil: + return fmt.Errorf("ConfigFactory is nil") + case c.Driver == nil: + return fmt.Errorf("no Helm storage driver configured") + case c.KubeClient == nil, c.Getter == nil: + return fmt.Errorf("no Kubernetes client and/or getter configured") + } + return nil +} diff --git a/internal/action/config_test.go b/internal/action/config_test.go new file mode 100644 index 000000000..16ef468dd --- /dev/null +++ b/internal/action/config_test.go @@ -0,0 +1,329 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "errors" + "testing" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + helmkube "helm.sh/helm/v3/pkg/kube" + helmrelease "helm.sh/helm/v3/pkg/release" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + "k8s.io/cli-runtime/pkg/genericclioptions" + cmdtest "k8s.io/kubectl/pkg/cmd/testing" + + "github.com/fluxcd/helm-controller/internal/kube" + "github.com/fluxcd/helm-controller/internal/storage" +) + +func TestNewConfigFactory(t *testing.T) { + tests := []struct { + name string + getter genericclioptions.RESTClientGetter + opts []ConfigFactoryOption + wantErr error + }{ + { + name: "constructs config factory", + getter: &kube.MemoryRESTClientGetter{}, + opts: []ConfigFactoryOption{ + WithStorage(helmdriver.MemoryDriverName, "default"), + }, + wantErr: nil, + }, + { + name: "invalid config", + getter: &kube.MemoryRESTClientGetter{}, + wantErr: errors.New("no Helm storage driver configured"), + }, + { + name: "multiple options", + getter: &kube.MemoryRESTClientGetter{}, + opts: []ConfigFactoryOption{ + WithDriver(helmdriver.NewMemory()), + WithStorageLog(func(format string, v ...interface{}) { + // noop + }), + }, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + factory, err := NewConfigFactory(tt.getter, tt.opts...) + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(factory).To(BeNil()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(factory).ToNot(BeNil()) + }) + } +} + +func TestWithStorage(t *testing.T) { + tests := []struct { + name string + factory ConfigFactory + driverName string + namespace string + wantErr error + wantDriver string + }{ + { + name: "default_" + DefaultStorageDriver, + namespace: "default", + factory: ConfigFactory{ + KubeClient: helmkube.New(cmdtest.NewTestFactory()), + }, + wantDriver: helmdriver.SecretsDriverName, + }, + { + name: helmdriver.SecretsDriverName, + driverName: helmdriver.SecretsDriverName, + namespace: "default", + factory: ConfigFactory{ + KubeClient: helmkube.New(cmdtest.NewTestFactory()), + }, + wantDriver: helmdriver.SecretsDriverName, + }, + { + name: helmdriver.ConfigMapsDriverName, + driverName: helmdriver.ConfigMapsDriverName, + namespace: "default", + factory: ConfigFactory{ + KubeClient: helmkube.New(cmdtest.NewTestFactory()), + }, + wantDriver: helmdriver.ConfigMapsDriverName, + }, + { + name: helmdriver.MemoryDriverName, + driverName: helmdriver.MemoryDriverName, + namespace: "default", + factory: ConfigFactory{}, + wantDriver: helmdriver.MemoryDriverName, + }, + { + name: "invalid namespace", + driverName: helmdriver.SecretsDriverName, + namespace: "", + factory: ConfigFactory{}, + wantErr: errors.New("no namespace provided for Helm storage driver 'secrets'"), + }, + { + name: "invalid driver", + driverName: "invalid", + namespace: "default", + factory: ConfigFactory{}, + wantErr: errors.New("unsupported Helm storage driver 'invalid'"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + factory := tt.factory + err := WithStorage(tt.driverName, tt.namespace)(&factory) + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(factory.Driver).To(BeNil()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(factory.Driver).ToNot(BeNil()) + g.Expect(factory.Driver.Name()).To(Equal(tt.wantDriver)) + }) + } +} + +func TestWithDriver(t *testing.T) { + g := NewWithT(t) + + factory := &ConfigFactory{} + driver := helmdriver.NewMemory() + g.Expect(WithDriver(driver)(factory)).NotTo(HaveOccurred()) + g.Expect(factory.Driver).To(Equal(driver)) +} + +func TestStorageLog(t *testing.T) { + g := NewWithT(t) + + factory := &ConfigFactory{} + log := helmaction.DebugLog(func(format string, v ...interface{}) { + // noop + }) + g.Expect(WithStorageLog(log)(factory)).NotTo(HaveOccurred()) + g.Expect(factory.StorageLog).ToNot(BeNil()) +} + +func TestConfigFactory_NewStorage(t *testing.T) { + t.Run("without observers", func(t *testing.T) { + g := NewWithT(t) + + factory := &ConfigFactory{ + Driver: helmdriver.NewMemory(), + } + + s := factory.NewStorage() + g.Expect(s).ToNot(BeNil()) + g.Expect(s.Driver).To(BeAssignableToTypeOf(factory.Driver)) + }) + + t.Run("with observers", func(t *testing.T) { + g := NewWithT(t) + + factory := &ConfigFactory{ + Driver: helmdriver.NewMemory(), + } + + obsFunc := func(rel *helmrelease.Release) {} + s := factory.NewStorage(obsFunc) + g.Expect(s).ToNot(BeNil()) + g.Expect(s.Driver).To(BeAssignableToTypeOf(&storage.Observer{})) + }) + + t.Run("with storage log", func(t *testing.T) { + g := NewWithT(t) + + var called bool + log := func(fmt string, v ...interface{}) { + called = true + } + + factory := &ConfigFactory{ + Driver: helmdriver.NewMemory(), + StorageLog: log, + } + + s := factory.NewStorage() + g.Expect(s).ToNot(BeNil()) + s.Log("test") + g.Expect(called).To(BeTrue()) + }) +} + +func TestConfigFactory_Build(t *testing.T) { + t.Run("build", func(t *testing.T) { + g := NewWithT(t) + + getter := &kube.MemoryRESTClientGetter{} + factory := &ConfigFactory{ + Getter: getter, + KubeClient: helmkube.New(getter), + } + + cfg := factory.Build(nil) + g.Expect(cfg).ToNot(BeNil()) + g.Expect(cfg.KubeClient).To(Equal(factory.KubeClient)) + g.Expect(cfg.RESTClientGetter).To(Equal(factory.Getter)) + }) + + t.Run("with log", func(t *testing.T) { + g := NewWithT(t) + + var called bool + log := func(fmt string, v ...interface{}) { + called = true + } + cfg := (&ConfigFactory{}).Build(log) + + g.Expect(cfg).ToNot(BeNil()) + cfg.Log("") + g.Expect(called).To(BeTrue()) + }) + + t.Run("with observe func", func(t *testing.T) { + g := NewWithT(t) + + factory := &ConfigFactory{ + Driver: helmdriver.NewMemory(), + } + + obsFunc := func(rel *helmrelease.Release) {} + cfg := factory.Build(nil, obsFunc) + + g.Expect(cfg).To(Not(BeNil())) + g.Expect(cfg.Releases).ToNot(BeNil()) + g.Expect(cfg.Releases.Driver).To(BeAssignableToTypeOf(&storage.Observer{})) + }) +} + +func TestConfigFactory_Valid(t *testing.T) { + tests := []struct { + name string + factory *ConfigFactory + wantErr error + }{ + { + name: "valid", + factory: &ConfigFactory{ + Driver: helmdriver.NewMemory(), + Getter: &kube.MemoryRESTClientGetter{}, + KubeClient: helmkube.New(&kube.MemoryRESTClientGetter{}), + }, + wantErr: nil, + }, + { + name: "no Kubernetes client", + factory: &ConfigFactory{ + Driver: helmdriver.NewMemory(), + Getter: &kube.MemoryRESTClientGetter{}, + }, + wantErr: errors.New("no Kubernetes client and/or getter configured"), + }, + { + name: "no Kubernetes getter", + factory: &ConfigFactory{ + Driver: helmdriver.NewMemory(), + KubeClient: helmkube.New(&kube.MemoryRESTClientGetter{}), + }, + wantErr: errors.New("no Kubernetes client and/or getter configured"), + }, + { + name: "no driver", + factory: &ConfigFactory{ + KubeClient: helmkube.New(&kube.MemoryRESTClientGetter{}), + Getter: &kube.MemoryRESTClientGetter{}, + }, + wantErr: errors.New("no Helm storage driver configured"), + }, + { + name: "nil factory", + factory: nil, + wantErr: errors.New("ConfigFactory is nil"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + err := tt.factory.Valid() + if tt.wantErr == nil { + g.Expect(err).To(BeNil()) + return + } + g.Expect(tt.factory.Valid()).To(Equal(tt.wantErr)) + }) + } +} diff --git a/internal/action/crds.go b/internal/action/crds.go new file mode 100644 index 000000000..9156e7603 --- /dev/null +++ b/internal/action/crds.go @@ -0,0 +1,264 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "bytes" + "context" + "fmt" + "time" + + helmaction "helm.sh/helm/v3/pkg/action" + helmchart "helm.sh/helm/v3/pkg/chart" + helmkube "helm.sh/helm/v3/pkg/kube" + apiextension "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + apierrors "k8s.io/apimachinery/pkg/api/errors" + apimeta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apiruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/cli-runtime/pkg/resource" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +const ( + // DefaultCRDPolicy is the default CRD policy. + DefaultCRDPolicy = v2.Create +) + +var accessor = apimeta.NewAccessor() + +// crdPolicy returns the CRD policy for the given CRD. +func crdPolicyOrDefault(policy v2.CRDsPolicy) (v2.CRDsPolicy, error) { + switch policy { + case "": + policy = DefaultCRDPolicy + case v2.Skip, v2.Create, v2.CreateReplace: + break + default: + return policy, fmt.Errorf("invalid CRD upgrade policy '%s', valid values are '%s', '%s' or '%s'", + policy, v2.Skip, v2.Create, v2.CreateReplace, + ) + } + return policy, nil +} + +type rootScoped struct{} + +func (*rootScoped) Name() apimeta.RESTScopeName { + return apimeta.RESTScopeNameRoot +} + +func applyCRDs(cfg *helmaction.Configuration, policy v2.CRDsPolicy, chrt *helmchart.Chart, visitorFunc ...resource.VisitorFunc) error { + if len(chrt.CRDObjects()) == 0 { + return nil + } + + if policy == v2.Skip { + cfg.Log("skipping CustomResourceDefinition apply: policy is set to %s", policy) + return nil + } + + // Collect all CRDs from all files in `crds` directory. + allCRDs := make(helmkube.ResourceList, 0) + for _, obj := range chrt.CRDObjects() { + // Read in the resources + res, err := cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false) + if err != nil { + err = fmt.Errorf("failed to parse CustomResourceDefinitions from %s: %w", obj.Name, err) + cfg.Log(err.Error()) + return err + } + allCRDs = append(allCRDs, res...) + } + + // Visit CRDs with any provided visitor functions. + for _, visitor := range visitorFunc { + if err := allCRDs.Visit(visitor); err != nil { + return err + } + } + + cfg.Log("applying CustomResourceDefinition(s) with policy %s", policy) + var totalItems []*resource.Info + switch policy { + case v2.Create: + for i := range allCRDs { + if rr, err := cfg.KubeClient.Create(allCRDs[i : i+1]); err != nil { + crdName := allCRDs[i].Name + // If the CustomResourceDefinition already exists, we skip it. + if apierrors.IsAlreadyExists(err) { + cfg.Log("CustomResourceDefinition %s is already present. Skipping.", crdName) + if rr != nil && rr.Created != nil { + totalItems = append(totalItems, rr.Created...) + } + continue + } + err = fmt.Errorf("failed to create CustomResourceDefinition %s: %w", crdName, err) + cfg.Log(err.Error()) + return err + } else { + if rr != nil && rr.Created != nil { + totalItems = append(totalItems, rr.Created...) + } + } + } + case v2.CreateReplace: + config, err := cfg.RESTClientGetter.ToRESTConfig() + if err != nil { + err = fmt.Errorf("could not create Kubernetes client REST config: %w", err) + cfg.Log(err.Error()) + return err + } + clientSet, err := apiextension.NewForConfig(config) + if err != nil { + err = fmt.Errorf("could not create Kubernetes client set for API extensions: %w", err) + cfg.Log(err.Error()) + return err + } + client := clientSet.ApiextensionsV1().CustomResourceDefinitions() + + // Note, we build the originals from the current set of Custom Resource + // Definitions, and therefore this upgrade will never delete CRDs that + // existed in the former release but no longer exist in the current + // release. + original := make(helmkube.ResourceList, 0) + for _, r := range allCRDs { + if o, err := client.Get(context.TODO(), r.Name, metav1.GetOptions{}); err == nil && o != nil { + o.GetResourceVersion() + original = append(original, &resource.Info{ + Client: clientSet.ApiextensionsV1().RESTClient(), + Mapping: &apimeta.RESTMapping{ + Resource: schema.GroupVersionResource{ + Group: "apiextensions.k8s.io", + Version: r.Mapping.GroupVersionKind.Version, + Resource: "customresourcedefinition", + }, + GroupVersionKind: schema.GroupVersionKind{ + Kind: "CustomResourceDefinition", + Group: "apiextensions.k8s.io", + Version: r.Mapping.GroupVersionKind.Version, + }, + Scope: &rootScoped{}, + }, + Namespace: o.ObjectMeta.Namespace, + Name: o.ObjectMeta.Name, + Object: o, + ResourceVersion: o.ObjectMeta.ResourceVersion, + }) + } else if !apierrors.IsNotFound(err) { + err = fmt.Errorf("failed to get CustomResourceDefinition %s: %w", r.Name, err) + cfg.Log(err.Error()) + return err + } + } + + // Send them to Kubernetes... + if rr, err := cfg.KubeClient.Update(original, allCRDs, true); err != nil { + err = fmt.Errorf("failed to update CustomResourceDefinition(s): %w", err) + return err + } else { + if rr != nil { + if rr.Created != nil { + totalItems = append(totalItems, rr.Created...) + } + if rr.Updated != nil { + totalItems = append(totalItems, rr.Updated...) + } + if rr.Deleted != nil { + totalItems = append(totalItems, rr.Deleted...) + } + } + } + default: + err := fmt.Errorf("unexpected policy %s", policy) + cfg.Log(err.Error()) + return err + } + + if len(totalItems) > 0 { + // Give time for the CRD to be recognized. + if err := cfg.KubeClient.Wait(totalItems, 60*time.Second); err != nil { + err = fmt.Errorf("failed to wait for CustomResourceDefinition(s): %w", err) + cfg.Log(err.Error()) + return err + } + cfg.Log("successfully applied %d CustomResourceDefinition(s)", len(totalItems)) + + // Clear the RESTMapper cache, since it will not have the new CRDs. + // Helm does further invalidation of the client at a later stage + // when it gathers the server capabilities. + if m, err := cfg.RESTClientGetter.ToRESTMapper(); err == nil { + if rm, ok := m.(apimeta.ResettableRESTMapper); ok { + cfg.Log("clearing REST mapper cache") + rm.Reset() + } + } + } + + return nil +} + +func setOriginVisitor(group, namespace, name string) resource.VisitorFunc { + return func(info *resource.Info, err error) error { + if err != nil { + return err + } + if err = mergeLabels(info.Object, originLabels(group, namespace, name)); err != nil { + return fmt.Errorf( + "%s origin labels could not be updated: %s", + resourceString(info), err, + ) + } + return nil + } +} + +func originLabels(group, namespace, name string) map[string]string { + return map[string]string{ + fmt.Sprintf("%s/name", group): name, + fmt.Sprintf("%s/namespace", group): namespace, + } +} + +func mergeLabels(obj apiruntime.Object, labels map[string]string) error { + current, err := accessor.Labels(obj) + if err != nil { + return err + } + return accessor.SetLabels(obj, mergeStrStrMaps(current, labels)) +} + +func resourceString(info *resource.Info) string { + _, k := info.Mapping.GroupVersionKind.ToAPIVersionAndKind() + return fmt.Sprintf( + "%s %q in namespace %q", + k, info.Name, info.Namespace, + ) +} + +func mergeStrStrMaps(current, desired map[string]string) map[string]string { + result := make(map[string]string) + for k, v := range current { + result[k] = v + } + for k, desiredVal := range desired { + result[k] = desiredVal + } + return result +} diff --git a/internal/action/install.go b/internal/action/install.go new file mode 100644 index 000000000..035cd3ab5 --- /dev/null +++ b/internal/action/install.go @@ -0,0 +1,95 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "context" + "fmt" + + helmaction "helm.sh/helm/v3/pkg/action" + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/features" + "github.com/fluxcd/helm-controller/internal/postrender" + "github.com/fluxcd/helm-controller/internal/release" +) + +// InstallOption can be used to modify Helm's action.Install after the instructions +// from the v2beta2.HelmRelease have been applied. This is for example useful to +// enable the dry-run setting as a CLI. +type InstallOption func(action *helmaction.Install) + +// Install runs the Helm install action with the provided config, using the +// v2beta2.HelmReleaseSpec of the given object to determine the target release +// and rollback configuration. +// +// It performs the installation according to the spec, which includes installing +// the CRDs according to the defined policy. +// +// It does not determine if there is a desire to perform the action, this is +// expected to be done by the caller. In addition, it does not take note of the +// action result. The caller is expected to listen to this using a +// storage.ObserveFunc, which provides superior access to Helm storage writes. +func Install(ctx context.Context, config *helmaction.Configuration, obj *v2.HelmRelease, + chrt *helmchart.Chart, vals helmchartutil.Values, opts ...InstallOption) (*helmrelease.Release, error) { + install := newInstall(config, obj, opts) + + policy, err := crdPolicyOrDefault(obj.GetInstall().CRDs) + if err != nil { + return nil, err + } + if err := applyCRDs(config, policy, chrt, setOriginVisitor(v2.GroupVersion.Group, obj.Namespace, obj.Name)); err != nil { + return nil, fmt.Errorf("failed to apply CustomResourceDefinitions: %w", err) + } + + return install.RunWithContext(ctx, chrt, vals.AsMap()) +} + +func newInstall(config *helmaction.Configuration, obj *v2.HelmRelease, opts []InstallOption) *helmaction.Install { + install := helmaction.NewInstall(config) + + install.ReleaseName = release.ShortenName(obj.GetReleaseName()) + install.Namespace = obj.GetReleaseNamespace() + install.Timeout = obj.GetInstall().GetTimeout(obj.GetTimeout()).Duration + install.Wait = !obj.GetInstall().DisableWait + install.WaitForJobs = !obj.GetInstall().DisableWaitForJobs + install.DisableHooks = obj.GetInstall().DisableHooks + install.DisableOpenAPIValidation = obj.GetInstall().DisableOpenAPIValidation + install.Replace = obj.GetInstall().Replace + install.Devel = true + install.SkipCRDs = true + + if obj.Spec.TargetNamespace != "" { + install.CreateNamespace = obj.GetInstall().CreateNamespace + } + + // If the user opted-in to allow DNS lookups, enable it. + if allowDNS, _ := features.Enabled(features.AllowDNSLookups); allowDNS { + install.EnableDNS = allowDNS + } + + install.PostRenderer = postrender.BuildPostRenderers(obj) + + for _, opt := range opts { + opt(install) + } + + return install +} diff --git a/internal/action/install_test.go b/internal/action/install_test.go new file mode 100644 index 000000000..64e516617 --- /dev/null +++ b/internal/action/install_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func Test_newInstall(t *testing.T) { + t.Run("new install", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "install", + Namespace: "install-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + Install: &v2.Install{ + Timeout: &metav1.Duration{Duration: 10 * time.Second}, + Replace: true, + }, + }, + } + + got := newInstall(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Install.Timeout.Duration)) + g.Expect(got.Replace).To(Equal(obj.Spec.Install.Replace)) + }) + + t.Run("timeout fallback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "install", + Namespace: "install-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + }, + } + + got := newInstall(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Timeout.Duration)) + }) + + t.Run("applies options", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "install", + Namespace: "install-ns", + }, + Spec: v2.HelmReleaseSpec{}, + } + + got := newInstall(&helmaction.Configuration{}, obj, []InstallOption{ + func(install *helmaction.Install) { + install.Atomic = true + }, + func(install *helmaction.Install) { + install.DryRun = true + }, + }) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Atomic).To(BeTrue()) + g.Expect(got.DryRun).To(BeTrue()) + }) +} diff --git a/internal/action/log.go b/internal/action/log.go new file mode 100644 index 000000000..5caad3bf5 --- /dev/null +++ b/internal/action/log.go @@ -0,0 +1,160 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "container/ring" + "fmt" + "strings" + "sync" + "time" + + "github.com/go-logr/logr" + helmaction "helm.sh/helm/v3/pkg/action" +) + +// DefaultLogBufferSize is the default size of the LogBuffer. +const DefaultLogBufferSize = 5 + +// nowTS can be used to stub out time.Now() in tests. +var nowTS = time.Now + +// NewDebugLog returns an action.DebugLog that logs to the given logr.Logger. +func NewDebugLog(log logr.Logger) helmaction.DebugLog { + return func(format string, v ...interface{}) { + log.Info(fmt.Sprintf(format, v...)) + } +} + +// LogBuffer is a ring buffer that logs to a Helm action.DebugLog. +type LogBuffer struct { + mu sync.RWMutex + log helmaction.DebugLog + buffer *ring.Ring +} + +// logLine is a log message with a timestamp. +type logLine struct { + ts time.Time + lastTS time.Time + msg string + count int64 +} + +// String returns the log line as a string, in the format of: +// ': '. But only if the message is not empty. +func (l *logLine) String() string { + if l == nil || l.msg == "" { + return "" + } + + msg := fmt.Sprintf("%s: %s", l.ts.Format(time.RFC3339Nano), l.msg) + if c := l.count; c > 0 { + msg += fmt.Sprintf("\n%s: %s", l.lastTS.Format(time.RFC3339Nano), l.msg) + } + if c := l.count - 1; c > 0 { + var dup = "line" + if c > 1 { + dup += "s" + } + msg += fmt.Sprintf(" (%d duplicate %s omitted)", c, dup) + } + return msg +} + +// NewLogBuffer creates a new LogBuffer with the given log function +// and a buffer of the given size. If size <= 0, it defaults to +// DefaultLogBufferSize. +func NewLogBuffer(log helmaction.DebugLog, size int) *LogBuffer { + if size <= 0 { + size = DefaultLogBufferSize + } + return &LogBuffer{ + log: log, + buffer: ring.New(size), + } +} + +// Log adds the log message to the ring buffer before calling the actual log +// function. It is safe to call this function from multiple goroutines. +func (l *LogBuffer) Log(format string, v ...interface{}) { + l.mu.Lock() + + // Filter out duplicate log lines, this happens for example when + // Helm is waiting on workloads to become ready. + msg := fmt.Sprintf(format, v...) + prev, ok := l.buffer.Prev().Value.(*logLine) + if ok && prev.msg == msg { + prev.count++ + prev.lastTS = nowTS().UTC() + l.buffer.Prev().Value = prev + } + if !ok || prev.msg != msg { + l.buffer.Value = &logLine{ + ts: nowTS().UTC(), + msg: msg, + } + l.buffer = l.buffer.Next() + } + + l.mu.Unlock() + l.log(format, v...) +} + +// Len returns the count of non-empty values in the buffer. +func (l *LogBuffer) Len() (count int) { + l.mu.RLock() + l.buffer.Do(func(s interface{}) { + if s == nil { + return + } + ll, ok := s.(*logLine) + if !ok || ll.String() == "" { + return + } + count++ + }) + l.mu.RUnlock() + return +} + +// Reset clears the buffer. +func (l *LogBuffer) Reset() { + l.mu.Lock() + l.buffer = ring.New(l.buffer.Len()) + l.mu.Unlock() +} + +// String returns the contents of the buffer as a string. +func (l *LogBuffer) String() string { + var str string + l.mu.RLock() + l.buffer.Do(func(s interface{}) { + if s == nil { + return + } + ll, ok := s.(*logLine) + if !ok { + return + } + if msg := ll.String(); msg != "" { + str += msg + "\n" + } + }) + l.mu.RUnlock() + return strings.TrimSpace(str) +} diff --git a/internal/action/log_test.go b/internal/action/log_test.go new file mode 100644 index 000000000..16aab7d5f --- /dev/null +++ b/internal/action/log_test.go @@ -0,0 +1,140 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "fmt" + "testing" + "time" + + "github.com/go-logr/logr" +) + +func TestLogBuffer_Log(t *testing.T) { + nowTS = stubNowTS + + tests := []struct { + name string + size int + fill []string + wantCount int + want string + }{ + {name: "log", size: 2, fill: []string{"a", "b", "c"}, wantCount: 3, want: fmt.Sprintf("%[1]s: b\n%[1]s: c", stubNowTS().Format(time.RFC3339Nano))}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var count int + l := NewLogBuffer(func(format string, v ...interface{}) { + count++ + }, tt.size) + for _, v := range tt.fill { + l.Log("%s", v) + } + if count != tt.wantCount { + t.Errorf("Inner Log() called %v times, want %v", count, tt.wantCount) + } + if got := l.String(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestLogBuffer_Len(t *testing.T) { + tests := []struct { + name string + size int + fill []string + want int + }{ + {name: "empty buffer", fill: []string{}, want: 0}, + {name: "filled buffer", size: 2, fill: []string{"a", "b"}, want: 2}, + {name: "half full buffer", size: 4, fill: []string{"a", "b"}, want: 2}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := NewLogBuffer(NewDebugLog(logr.Discard()), tt.size) + for _, v := range tt.fill { + l.Log("%s", v) + } + if got := l.Len(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestLogBuffer_Reset(t *testing.T) { + bufferSize := 10 + l := NewLogBuffer(NewDebugLog(logr.Discard()), bufferSize) + + if got := l.buffer.Len(); got != bufferSize { + t.Errorf("Len() = %v, want %v", got, bufferSize) + } + + for _, v := range []string{"a", "b", "c"} { + l.Log("%s", v) + } + + if got := l.String(); got == "" { + t.Errorf("String() = empty") + } + + l.Reset() + + if got := l.buffer.Len(); got != bufferSize { + t.Errorf("Len() = %v after Reset(), want %v", got, bufferSize) + } + if got := l.String(); got != "" { + t.Errorf("String() != empty after Reset()") + } +} + +func TestLogBuffer_String(t *testing.T) { + nowTS = stubNowTS + + tests := []struct { + name string + size int + fill []string + want string + }{ + {name: "empty buffer", fill: []string{}, want: ""}, + {name: "filled buffer", size: 2, fill: []string{"a", "b", "c"}, want: fmt.Sprintf("%[1]s: b\n%[1]s: c", stubNowTS().Format(time.RFC3339Nano))}, + {name: "duplicate buffer items", fill: []string{"b", "b"}, want: fmt.Sprintf("%[1]s: b\n%[1]s: b", stubNowTS().Format(time.RFC3339Nano))}, + {name: "duplicate buffer items", fill: []string{"b", "b", "b"}, want: fmt.Sprintf("%[1]s: b\n%[1]s: b (1 duplicate line omitted)", stubNowTS().Format(time.RFC3339Nano))}, + {name: "duplicate buffer items", fill: []string{"b", "b", "b", "b"}, want: fmt.Sprintf("%[1]s: b\n%[1]s: b (2 duplicate lines omitted)", stubNowTS().Format(time.RFC3339Nano))}, + {name: "duplicate buffer items", fill: []string{"a", "b", "b", "b", "c", "c"}, want: fmt.Sprintf("%[1]s: a\n%[1]s: b\n%[1]s: b (1 duplicate line omitted)\n%[1]s: c\n%[1]s: c", stubNowTS().Format(time.RFC3339Nano))}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := NewLogBuffer(NewDebugLog(logr.Discard()), tt.size) + for _, v := range tt.fill { + l.Log("%s", v) + } + if got := l.String(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }) + } +} + +// stubNowTS returns a fixed time for testing purposes. +func stubNowTS() time.Time { + return time.Date(2016, 2, 18, 12, 24, 5, 12345600, time.UTC) +} diff --git a/internal/action/reset.go b/internal/action/reset.go new file mode 100644 index 000000000..da0caf69f --- /dev/null +++ b/internal/action/reset.go @@ -0,0 +1,57 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "github.com/opencontainers/go-digest" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + intchartutil "github.com/fluxcd/helm-controller/internal/chartutil" +) + +const ( + differentGenerationReason = "generation differs from last attempt" + differentRevisionReason = "chart version differs from last attempt" + differentValuesReason = "values differ from last attempt" +) + +// MustResetFailures returns a reason and true if the HelmRelease's status +// indicates that the HelmRelease failure counters must be reset. +// This is the case if the data used to make the last (failed) attempt has +// changed in a way that indicates that a new attempt should be made. +// For example, a change in generation, chart version, or values. +// If no change is detected, an empty string is returned along with false. +func MustResetFailures(obj *v2.HelmRelease, chart *chart.Metadata, values chartutil.Values) (string, bool) { + switch { + case obj.Status.LastAttemptedGeneration != obj.Generation: + return differentGenerationReason, true + case obj.Status.LastAttemptedRevision != chart.Version: + return differentRevisionReason, true + case obj.Status.LastAttemptedConfigDigest != "" || obj.Status.LastAttemptedValuesChecksum != "": + d := obj.Status.LastAttemptedConfigDigest + if d == "" { + // TODO: remove this when the deprecated field is removed. + d = "sha1:" + obj.Status.LastAttemptedValuesChecksum + } + if ok := intchartutil.VerifyValues(digest.Digest(d), values); !ok { + return differentValuesReason, true + } + } + return "", false +} diff --git a/internal/action/reset_test.go b/internal/action/reset_test.go new file mode 100644 index 000000000..465df0e81 --- /dev/null +++ b/internal/action/reset_test.go @@ -0,0 +1,141 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + + . "github.com/onsi/gomega" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func TestMustResetFailures(t *testing.T) { + tests := []struct { + name string + obj *v2.HelmRelease + chart *chart.Metadata + values chartutil.Values + want bool + wantReason string + }{ + { + name: "on generation change", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + LastAttemptedGeneration: 2, + }, + }, + want: true, + wantReason: differentGenerationReason, + }, + { + name: "on revision change", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + LastAttemptedGeneration: 1, + LastAttemptedRevision: "1.0.0", + }, + }, + chart: &chart.Metadata{ + Version: "1.1.0", + }, + want: true, + wantReason: differentRevisionReason, + }, + { + name: "on config digest change", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + LastAttemptedGeneration: 1, + LastAttemptedRevision: "1.0.0", + LastAttemptedConfigDigest: "sha256:9933f58f8bf459eb199d59ebc8a05683f3944e1242d9f5467d99aa2cf08a5370", + }, + }, + chart: &chart.Metadata{ + Version: "1.0.0", + }, + values: chartutil.Values{ + "foo": "bar", + }, + want: true, + wantReason: differentValuesReason, + }, + { + name: "on (deprecated) values checksum change", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + LastAttemptedGeneration: 1, + LastAttemptedRevision: "1.0.0", + LastAttemptedValuesChecksum: "a856118d270c0db44a9019d51e2bba4fc3e6bac7", + }, + }, + chart: &chart.Metadata{ + Version: "1.0.0", + }, + values: chartutil.Values{ + "foo": "bar", + }, + want: true, + wantReason: differentValuesReason, + }, + { + name: "without change no reset", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + LastAttemptedGeneration: 1, + LastAttemptedRevision: "1.0.0", + LastAttemptedConfigDigest: "sha256:1dabc4e3cbbd6a0818bd460f3a6c9855bfe95d506c74726bc0f2edb0aecb1f4e", + }, + }, + chart: &chart.Metadata{ + Version: "1.0.0", + }, + values: chartutil.Values{ + "foo": "bar", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + reason, got := MustResetFailures(tt.obj, tt.chart, tt.values) + g.Expect(got).To(Equal(tt.want)) + g.Expect(reason).To(Equal(tt.wantReason)) + }) + } +} diff --git a/internal/action/rollback.go b/internal/action/rollback.go new file mode 100644 index 000000000..3985597d4 --- /dev/null +++ b/internal/action/rollback.go @@ -0,0 +1,74 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + helmaction "helm.sh/helm/v3/pkg/action" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +// RollbackOption can be used to modify Helm's action.Rollback after the +// instructions from the v2beta2.HelmRelease have been applied. This is for +// example useful to enable the dry-run setting as a CLI. +type RollbackOption func(*helmaction.Rollback) + +// RollbackToVersion returns a RollbackOption which sets the version to +// roll back to. +func RollbackToVersion(version int) RollbackOption { + return func(rollback *helmaction.Rollback) { + rollback.Version = version + } +} + +// RollbackDryRun returns a RollbackOption which enables the dry-run setting. +func RollbackDryRun() RollbackOption { + return func(rollback *helmaction.Rollback) { + rollback.DryRun = true + } +} + +// Rollback runs the Helm rollback action with the provided config. Targeting +// a specific release or enabling dry-run is possible by providing +// RollbackToVersion and/or RollbackDryRun as options. +// +// It does not determine if there is a desire to perform the action, this is +// expected to be done by the caller. In addition, it does not take note of the +// action result. The caller is expected to listen to this using a +// storage.ObserveFunc, which provides superior access to Helm storage writes. +func Rollback(config *helmaction.Configuration, obj *v2.HelmRelease, releaseName string, opts ...RollbackOption) error { + rollback := newRollback(config, obj, opts) + return rollback.Run(releaseName) +} + +func newRollback(config *helmaction.Configuration, obj *v2.HelmRelease, opts []RollbackOption) *helmaction.Rollback { + rollback := helmaction.NewRollback(config) + + rollback.Timeout = obj.GetRollback().GetTimeout(obj.GetTimeout()).Duration + rollback.Wait = !obj.GetRollback().DisableWait + rollback.WaitForJobs = !obj.GetRollback().DisableWaitForJobs + rollback.DisableHooks = obj.GetRollback().DisableHooks + rollback.Force = obj.GetRollback().Force + rollback.Recreate = obj.GetRollback().Recreate + rollback.CleanupOnFail = obj.GetRollback().CleanupOnFail + + for _, opt := range opts { + opt(rollback) + } + + return rollback +} diff --git a/internal/action/rollback_test.go b/internal/action/rollback_test.go new file mode 100644 index 000000000..adb66fd5b --- /dev/null +++ b/internal/action/rollback_test.go @@ -0,0 +1,111 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func Test_newRollback(t *testing.T) { + t.Run("new rollback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollback", + Namespace: "rollback-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + Rollback: &v2.Rollback{ + Timeout: &metav1.Duration{Duration: 10 * time.Second}, + Force: true, + }, + }, + } + + got := newRollback(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Timeout).To(Equal(obj.Spec.Rollback.Timeout.Duration)) + g.Expect(got.Force).To(Equal(obj.Spec.Rollback.Force)) + }) + + t.Run("rollback to version", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollback", + Namespace: "rollback-ns", + }, + } + + toVersion := 3 + got := newRollback(&helmaction.Configuration{}, obj, []RollbackOption{RollbackToVersion(toVersion)}) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Version).To(Equal(toVersion)) + }) + + t.Run("timeout fallback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollback", + Namespace: "rollback-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + }, + } + + got := newRollback(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Timeout).To(Equal(obj.Spec.Timeout.Duration)) + }) + + t.Run("applies options", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollback", + Namespace: "rollback-ns", + }, + Spec: v2.HelmReleaseSpec{}, + } + + got := newRollback(&helmaction.Configuration{}, obj, []RollbackOption{ + func(rollback *helmaction.Rollback) { + rollback.CleanupOnFail = true + }, + func(rollback *helmaction.Rollback) { + rollback.DryRun = true + }, + }) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.CleanupOnFail).To(BeTrue()) + g.Expect(got.DryRun).To(BeTrue()) + }) +} diff --git a/internal/action/test.go b/internal/action/test.go new file mode 100644 index 000000000..04a4e509d --- /dev/null +++ b/internal/action/test.go @@ -0,0 +1,71 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "context" + + helmaction "helm.sh/helm/v3/pkg/action" + helmrelease "helm.sh/helm/v3/pkg/release" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +// TestOption can be used to modify Helm's action.ReleaseTesting after the +// instructions from the v2beta2.HelmRelease have been applied. This is for +// example useful to enable the dry-run setting as a CLI. +type TestOption func(action *helmaction.ReleaseTesting) + +// Test runs the Helm test action with the provided config, using the +// v2beta2.HelmReleaseSpec of the given object to determine the target release +// and test configuration. +// +// It does not determine if there is a desire to perform the action, this is +// expected to be done by the caller. In addition, it does not take note of the +// action result. The caller is expected to listen to this using a +// storage.ObserveFunc, which provides superior access to Helm storage writes. +func Test(_ context.Context, config *helmaction.Configuration, obj *v2.HelmRelease, opts ...TestOption) (*helmrelease.Release, error) { + test := newTest(config, obj, opts) + return test.Run(obj.GetReleaseName()) +} + +func newTest(config *helmaction.Configuration, obj *v2.HelmRelease, opts []TestOption) *helmaction.ReleaseTesting { + test := helmaction.NewReleaseTesting(config) + + test.Namespace = obj.GetReleaseNamespace() + test.Timeout = obj.GetTest().GetTimeout(obj.GetTimeout()).Duration + + filters := make(map[string][]string) + + for _, f := range obj.GetTest().GetFilters() { + name := "name" + + if f.Exclude { + name = "!" + name + } + + filters[name] = append(filters[name], f.Name) + } + + test.Filters = filters + + for _, opt := range opts { + opt(test) + } + + return test +} diff --git a/internal/action/test_test.go b/internal/action/test_test.go new file mode 100644 index 000000000..a78dcb78f --- /dev/null +++ b/internal/action/test_test.go @@ -0,0 +1,108 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func Test_newTest(t *testing.T) { + t.Run("new test", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + Test: &v2.Test{ + Timeout: &metav1.Duration{Duration: 10 * time.Second}, + Filters: &[]v2.Filter{ + { + Name: "test", + }, + { + Name: "test2", + Exclude: true, + }, + }, + }, + }, + } + + got := newTest(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Test.Timeout.Duration)) + g.Expect(got.Filters).To(HaveLen(2)) + g.Expect(got.Filters).To(HaveKeyWithValue(Equal("name"), ContainElement("test"))) + g.Expect(got.Filters).To(HaveKeyWithValue(Equal("!name"), ContainElement("test2"))) + }) + + t.Run("timeout fallback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + }, + } + + got := newTest(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Timeout.Duration)) + }) + + t.Run("applies options", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test-ns", + }, + Spec: v2.HelmReleaseSpec{}, + } + + got := newTest(&helmaction.Configuration{}, obj, []TestOption{ + func(test *helmaction.ReleaseTesting) { + test.Filters = map[string][]string{ + "test": {"test"}, + } + }, + func(test *helmaction.ReleaseTesting) { + test.Filters["test2"] = []string{"test2"} + }, + }) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Filters).To(HaveLen(2)) + }) +} diff --git a/internal/action/uninstall.go b/internal/action/uninstall.go new file mode 100644 index 000000000..75fe6126d --- /dev/null +++ b/internal/action/uninstall.go @@ -0,0 +1,60 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "context" + + helmaction "helm.sh/helm/v3/pkg/action" + helmrelease "helm.sh/helm/v3/pkg/release" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +// UninstallOption can be used to modify Helm's action.Uninstall after the +// instructions from the v2beta2.HelmRelease have been applied. This is for +// example useful to enable the dry-run setting as a CLI. +type UninstallOption func(cfg *helmaction.Uninstall) + +// Uninstall runs the Helm uninstall action with the provided config, using the +// v2beta2.HelmReleaseSpec of the given object to determine the target release +// and uninstall configuration. +// +// It does not determine if there is a desire to perform the action, this is +// expected to be done by the caller. In addition, it does not take note of the +// action result. The caller is expected to listen to this using a +// storage.ObserveFunc, which provides superior access to Helm storage writes. +func Uninstall(_ context.Context, config *helmaction.Configuration, obj *v2.HelmRelease, releaseName string, opts ...UninstallOption) (*helmrelease.UninstallReleaseResponse, error) { + uninstall := newUninstall(config, obj, opts) + return uninstall.Run(releaseName) +} + +func newUninstall(config *helmaction.Configuration, obj *v2.HelmRelease, opts []UninstallOption) *helmaction.Uninstall { + uninstall := helmaction.NewUninstall(config) + + uninstall.Timeout = obj.GetUninstall().GetTimeout(obj.GetTimeout()).Duration + uninstall.DisableHooks = obj.GetUninstall().DisableHooks + uninstall.KeepHistory = obj.GetUninstall().KeepHistory + uninstall.Wait = !obj.GetUninstall().DisableWait + uninstall.DeletionPropagation = obj.GetUninstall().GetDeletionPropagation() + + for _, opt := range opts { + opt(uninstall) + } + + return uninstall +} diff --git a/internal/action/uninstall_test.go b/internal/action/uninstall_test.go new file mode 100644 index 000000000..dcb3efe1b --- /dev/null +++ b/internal/action/uninstall_test.go @@ -0,0 +1,95 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func Test_newUninstall(t *testing.T) { + t.Run("new uninstall", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "uninstall", + Namespace: "uninstall-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + Uninstall: &v2.Uninstall{ + Timeout: &metav1.Duration{Duration: 10 * time.Second}, + KeepHistory: true, + }, + }, + } + + got := newUninstall(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Timeout).To(Equal(obj.Spec.Uninstall.Timeout.Duration)) + g.Expect(got.KeepHistory).To(Equal(obj.Spec.Uninstall.KeepHistory)) + }) + + t.Run("timeout fallback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "uninstall", + Namespace: "uninstall-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + }, + } + + got := newUninstall(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Timeout).To(Equal(obj.Spec.Timeout.Duration)) + }) + + t.Run("applies options", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "uninstall", + Namespace: "uninstall-ns", + }, + Spec: v2.HelmReleaseSpec{}, + } + + got := newUninstall(&helmaction.Configuration{}, obj, []UninstallOption{ + func(uninstall *helmaction.Uninstall) { + uninstall.Wait = true + }, + func(uninstall *helmaction.Uninstall) { + uninstall.DisableHooks = true + }, + }) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Wait).To(BeTrue()) + g.Expect(got.DisableHooks).To(BeTrue()) + }) +} diff --git a/internal/action/upgrade.go b/internal/action/upgrade.go new file mode 100644 index 000000000..f18e50a26 --- /dev/null +++ b/internal/action/upgrade.go @@ -0,0 +1,92 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "context" + "fmt" + + helmaction "helm.sh/helm/v3/pkg/action" + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/features" + "github.com/fluxcd/helm-controller/internal/postrender" + "github.com/fluxcd/helm-controller/internal/release" +) + +// UpgradeOption can be used to modify Helm's action.Upgrade after the instructions +// from the v2beta2.HelmRelease have been applied. This is for example useful to +// enable the dry-run setting as a CLI. +type UpgradeOption func(upgrade *helmaction.Upgrade) + +// Upgrade runs the Helm upgrade action with the provided config, using the +// v2beta2.HelmReleaseSpec of the given object to determine the target release +// and upgrade configuration. +// +// It performs the upgrade according to the spec, which includes upgrading the +// CRDs according to the defined policy. +// +// It does not determine if there is a desire to perform the action, this is +// expected to be done by the caller. In addition, it does not take note of the +// action result. The caller is expected to listen to this using a +// storage.ObserveFunc, which provides superior access to Helm storage writes. +func Upgrade(ctx context.Context, config *helmaction.Configuration, obj *v2.HelmRelease, chrt *helmchart.Chart, + vals helmchartutil.Values, opts ...UpgradeOption) (*helmrelease.Release, error) { + upgrade := newUpgrade(config, obj, opts) + + policy, err := crdPolicyOrDefault(obj.GetInstall().CRDs) + if err != nil { + return nil, err + } + if err := applyCRDs(config, policy, chrt, setOriginVisitor(v2.GroupVersion.Group, obj.Namespace, obj.Name)); err != nil { + return nil, fmt.Errorf("failed to apply CustomResourceDefinitions: %w", err) + } + + return upgrade.RunWithContext(ctx, release.ShortenName(obj.GetReleaseName()), chrt, vals.AsMap()) +} + +func newUpgrade(config *helmaction.Configuration, obj *v2.HelmRelease, opts []UpgradeOption) *helmaction.Upgrade { + upgrade := helmaction.NewUpgrade(config) + upgrade.Namespace = obj.GetReleaseNamespace() + upgrade.ResetValues = !obj.GetUpgrade().PreserveValues + upgrade.ReuseValues = obj.GetUpgrade().PreserveValues + upgrade.MaxHistory = obj.GetMaxHistory() + upgrade.Timeout = obj.GetUpgrade().GetTimeout(obj.GetTimeout()).Duration + upgrade.Wait = !obj.GetUpgrade().DisableWait + upgrade.WaitForJobs = !obj.GetUpgrade().DisableWaitForJobs + upgrade.DisableHooks = obj.GetUpgrade().DisableHooks + upgrade.DisableOpenAPIValidation = obj.GetUpgrade().DisableOpenAPIValidation + upgrade.Force = obj.GetUpgrade().Force + upgrade.CleanupOnFail = obj.GetUpgrade().CleanupOnFail + upgrade.Devel = true + + // If the user opted-in to allow DNS lookups, enable it. + if allowDNS, _ := features.Enabled(features.AllowDNSLookups); allowDNS { + upgrade.EnableDNS = allowDNS + } + + upgrade.PostRenderer = postrender.BuildPostRenderers(obj) + + for _, opt := range opts { + opt(upgrade) + } + + return upgrade +} diff --git a/internal/action/upgrade_test.go b/internal/action/upgrade_test.go new file mode 100644 index 000000000..da62479b7 --- /dev/null +++ b/internal/action/upgrade_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func Test_newUpgrade(t *testing.T) { + t.Run("new upgrade", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "upgrade", + Namespace: "upgrade-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + Upgrade: &v2.Upgrade{ + Timeout: &metav1.Duration{Duration: 10 * time.Second}, + Force: true, + }, + }, + } + + got := newUpgrade(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Upgrade.Timeout.Duration)) + g.Expect(got.Force).To(Equal(obj.Spec.Upgrade.Force)) + }) + + t.Run("timeout fallback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "upgrade", + Namespace: "upgrade-ns", + }, + Spec: v2.HelmReleaseSpec{ + Timeout: &metav1.Duration{Duration: time.Minute}, + }, + } + + got := newUpgrade(&helmaction.Configuration{}, obj, nil) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Namespace).To(Equal(obj.Namespace)) + g.Expect(got.Timeout).To(Equal(obj.Spec.Timeout.Duration)) + }) + + t.Run("applies options", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "upgrade", + Namespace: "upgrade-ns", + }, + Spec: v2.HelmReleaseSpec{}, + } + + got := newUpgrade(&helmaction.Configuration{}, obj, []UpgradeOption{ + func(upgrade *helmaction.Upgrade) { + upgrade.Install = true + }, + func(upgrade *helmaction.Upgrade) { + upgrade.DryRun = true + }, + }) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Install).To(BeTrue()) + g.Expect(got.DryRun).To(BeTrue()) + }) +} diff --git a/internal/action/verify.go b/internal/action/verify.go new file mode 100644 index 000000000..db07cb545 --- /dev/null +++ b/internal/action/verify.go @@ -0,0 +1,194 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "errors" + + "github.com/opencontainers/go-digest" + helmaction "helm.sh/helm/v3/pkg/action" + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/release" +) + +var ( + ErrReleaseDisappeared = errors.New("release disappeared from storage") + ErrReleaseNotFound = errors.New("no release found") + ErrReleaseNotObserved = errors.New("release not observed to be made for object") + ErrReleaseDigest = errors.New("release digest verification error") + ErrChartChanged = errors.New("release chart changed") + ErrConfigDigest = errors.New("release config values changed") +) + +const ( + targetStorageNamespace = "storage namespace" + targetReleaseNamespace = "release namespace" + targetReleaseName = "release name" + targetChartName = "chart name" +) + +// ReleaseTargetChanged returns a reason and true if the given release and/or +// chart name have been mutated in such a way that it no longer has the same +// release target as recorded in the Status.History of the object, by comparing +// the (storage) namespace, and release and chart names. +// This can be used to e.g. trigger a garbage collection of the old release +// before installing the new one. +// If no change is detected, an empty string is returned along with false. +func ReleaseTargetChanged(obj *v2.HelmRelease, chartName string) (string, bool) { + cur := obj.Status.History.Latest() + switch { + case obj.Status.StorageNamespace == "", cur == nil: + return "", false + case obj.GetStorageNamespace() != obj.Status.StorageNamespace: + return targetStorageNamespace, true + case obj.GetReleaseNamespace() != cur.Namespace: + return targetReleaseNamespace, true + case release.ShortenName(obj.GetReleaseName()) != cur.Name: + return targetReleaseName, true + case chartName != cur.ChartName: + return targetChartName, true + default: + return "", false + } +} + +// LastRelease returns the last release object in the Helm storage with the +// given name. +// It returns an error of type ErrReleaseNotFound if there is no +// release with the given name. +// When the release name is too long, it will be shortened to the maximum +// allowed length using the release.ShortenName function. +func LastRelease(config *helmaction.Configuration, releaseName string) (*helmrelease.Release, error) { + rls, err := config.Releases.Last(release.ShortenName(releaseName)) + if err != nil { + if errors.Is(err, helmdriver.ErrReleaseNotFound) { + return nil, ErrReleaseNotFound + } + return nil, err + } + return rls, nil +} + +// IsInstalled returns true if there is any release in the Helm storage with the +// given name. It returns any error other than driver.ErrReleaseNotFound. +func IsInstalled(config *helmaction.Configuration, releaseName string) (bool, error) { + _, err := config.Releases.Last(release.ShortenName(releaseName)) + if err != nil { + if errors.Is(err, helmdriver.ErrReleaseNotFound) { + return false, nil + } + return false, err + } + return true, nil +} + +// VerifySnapshot verifies the data of the given v2beta2.Snapshot +// matches the release object in the Helm storage. It returns the verified +// release, or an error of type ErrReleaseNotFound, ErrReleaseDisappeared, +// ErrReleaseDigest or ErrReleaseNotObserved indicating the reason for the +// verification failure. +func VerifySnapshot(config *helmaction.Configuration, snapshot *v2.Snapshot) (rls *helmrelease.Release, err error) { + if snapshot == nil { + return nil, ErrReleaseNotFound + } + + rls, err = config.Releases.Get(snapshot.Name, snapshot.Version) + if err != nil { + if errors.Is(err, helmdriver.ErrReleaseNotFound) { + return nil, ErrReleaseDisappeared + } + return nil, err + } + + if err = VerifyReleaseObject(snapshot, rls); err != nil { + return nil, err + } + return rls, nil +} + +// VerifyLastStorageItem verifies the data of the given v2beta2.Snapshot +// matches the last release object in the Helm storage. It returns the release +// and any verification error of type ErrReleaseNotFound, ErrReleaseDisappeared, +// ErrReleaseDigest or ErrReleaseNotObserved indicating the reason for the +// verification failure. +func VerifyLastStorageItem(config *helmaction.Configuration, snapshot *v2.Snapshot) (rls *helmrelease.Release, err error) { + if snapshot == nil { + return nil, ErrReleaseNotFound + } + + rls, err = config.Releases.Last(snapshot.Name) + if err != nil { + if errors.Is(err, helmdriver.ErrReleaseNotFound) { + return nil, ErrReleaseDisappeared + } + return nil, err + } + + if err = VerifyReleaseObject(snapshot, rls); err != nil { + return nil, err + } + return rls, nil +} + +// VerifyReleaseObject verifies the data of the given v2beta2.Snapshot +// matches the given Helm release object. It returns an error of type +// ErrReleaseDigest or ErrReleaseNotObserved indicating the reason for the +// verification failure, or nil. +func VerifyReleaseObject(snapshot *v2.Snapshot, rls *helmrelease.Release) error { + relDig, err := digest.Parse(snapshot.Digest) + if err != nil { + return ErrReleaseDigest + } + verifier := relDig.Verifier() + + obs := release.ObserveRelease(rls) + if err = obs.Encode(verifier); err != nil { + // We are expected to be able to encode valid JSON, error out without a + // typed error assuming malfunction to signal to e.g. retry. + return err + } + if !verifier.Verified() { + return ErrReleaseNotObserved + } + return nil +} + +// VerifyRelease verifies that the data of the given release matches the given +// chart metadata, and the provided values match the Snapshot.ConfigDigest. +// It returns either an error of type ErrReleaseNotFound, ErrChartChanged or +// ErrConfigDigest, or nil. +func VerifyRelease(rls *helmrelease.Release, snapshot *v2.Snapshot, chrt *helmchart.Metadata, vals helmchartutil.Values) error { + if rls == nil { + return ErrReleaseNotFound + } + + if chrt != nil && (rls.Chart.Metadata.Name != chrt.Name || rls.Chart.Metadata.Version != chrt.Version) { + return ErrChartChanged + } + + if snapshot == nil || !chartutil.VerifyValues(digest.Digest(snapshot.ConfigDigest), vals) { + return ErrConfigDigest + } + return nil +} diff --git a/internal/action/verify_test.go b/internal/action/verify_test.go new file mode 100644 index 000000000..d1118b4f9 --- /dev/null +++ b/internal/action/verify_test.go @@ -0,0 +1,591 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "errors" + "testing" + + . "github.com/onsi/gomega" + helmaction "helm.sh/helm/v3/pkg/action" + helmchart "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + helmstorage "helm.sh/helm/v3/pkg/storage" + "helm.sh/helm/v3/pkg/storage/driver" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestReleaseTargetChanged(t *testing.T) { + const ( + defaultNamespace = "default-ns" + defaultName = "default-name" + defaultChartName = "default-chart" + defaultReleaseName = "default-release" + defaultTargetNamespace = "default-target-ns" + defaultStorageNamespace = "default-storage-ns" + ) + + tests := []struct { + name string + chartName string + spec v2.HelmReleaseSpec + status v2.HelmReleaseStatus + wantReason string + want bool + }{ + { + name: "no change", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{}, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + want: false, + }, + { + name: "no storage namespace", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + ReleaseName: defaultReleaseName, + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultReleaseName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + }, + want: false, + }, + { + name: "no current", + spec: v2.HelmReleaseSpec{}, + status: v2.HelmReleaseStatus{ + StorageNamespace: defaultNamespace, + History: nil, + }, + want: false, + }, + { + name: "different storage namespace", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + StorageNamespace: defaultStorageNamespace, + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + wantReason: targetStorageNamespace, + want: true, + }, + { + name: "different release namespace", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + TargetNamespace: defaultTargetNamespace, + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + wantReason: targetReleaseNamespace, + want: true, + }, + { + name: "different release name", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + ReleaseName: defaultReleaseName, + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + wantReason: targetReleaseName, + want: true, + }, + { + name: "different chart name", + chartName: "other-chart", + spec: v2.HelmReleaseSpec{}, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: defaultNamespace, + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + wantReason: targetChartName, + want: true, + }, + { + name: "matching shortened release name", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + TargetNamespace: "target-namespace-exceeding-max-characters", + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: "target-namespace-exceeding-max-character-eceb26601388", + Namespace: "target-namespace-exceeding-max-characters", + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + want: false, + }, + { + name: "different shortened release name", + chartName: defaultChartName, + spec: v2.HelmReleaseSpec{ + TargetNamespace: "target-namespace-exceeding-max-characters", + }, + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: defaultName, + Namespace: "target-namespace-exceeding-max-characters", + ChartName: defaultChartName, + }, + }, + StorageNamespace: defaultNamespace, + }, + wantReason: targetReleaseName, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + reason, changed := ReleaseTargetChanged(&v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: defaultNamespace, + Name: defaultName, + }, + Spec: tt.spec, + Status: tt.status, + }, tt.chartName) + g.Expect(changed).To(Equal(tt.want)) + g.Expect(reason).To(Equal(tt.wantReason)) + }) + } +} + +func TestIsInstalled(t *testing.T) { + var mockError = errors.New("query mock error") + + tests := []struct { + name string + releaseName string + releases []*helmrelease.Release + queryError error + want bool + wantErr error + }{ + { + name: "installed", + releaseName: "release", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusDeployed, + Namespace: "default", + }), + }, + want: true, + }, + { + name: "not installed", + releaseName: "release", + want: false, + }, + { + name: "release list error", + queryError: mockError, + wantErr: mockError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + s := helmstorage.Init(driver.NewMemory()) + for _, v := range tt.releases { + g.Expect(s.Create(v)).To(Succeed()) + } + + s.Driver = &storage.Failing{ + Driver: s.Driver, + QueryErr: tt.queryError, + } + + got, err := IsInstalled(&helmaction.Configuration{Releases: s}, tt.releaseName) + + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(err).To(Equal(tt.wantErr)) + g.Expect(got).To(BeFalse()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(Equal(tt.want)) + }) + } +} + +func TestVerifySnapshot(t *testing.T) { + mock := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusDeployed, + Namespace: "default", + }) + otherMock := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusSuperseded, + Namespace: "default", + }) + mockInfo := release.ObservedToSnapshot(release.ObserveRelease(mock)) + mockGetErr := errors.New("mock get error") + + tests := []struct { + name string + snapshot *v2.Snapshot + release *helmrelease.Release + getError error + want *helmrelease.Release + wantErr error + }{ + { + name: "valid release", + snapshot: mockInfo, + release: mock, + want: mock, + }, + { + name: "invalid release", + snapshot: mockInfo, + release: otherMock, + wantErr: ErrReleaseNotObserved, + }, + { + name: "release not found", + snapshot: mockInfo, + release: nil, + wantErr: ErrReleaseDisappeared, + }, + { + name: "no release snapshot", + snapshot: nil, + release: nil, + wantErr: ErrReleaseNotFound, + }, + { + name: "driver get error", + snapshot: mockInfo, + getError: mockGetErr, + wantErr: mockGetErr, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + s := helmstorage.Init(driver.NewMemory()) + if tt.release != nil { + g.Expect(s.Create(tt.release)).To(Succeed()) + } + + s.Driver = &storage.Failing{ + Driver: s.Driver, + GetErr: tt.getError, + } + + rls, err := VerifySnapshot(&helmaction.Configuration{Releases: s}, tt.snapshot) + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(err).To(Equal(tt.wantErr)) + g.Expect(rls).To(BeNil()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(rls).To(Equal(tt.want)) + }) + } +} + +func TestVerifyLastStorageItem(t *testing.T) { + mockOne := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusSuperseded, + Namespace: "default", + }) + mockTwo := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 2, + Status: helmrelease.StatusDeployed, + Namespace: "default", + }) + mockInfo := release.ObservedToSnapshot(release.ObserveRelease(mockTwo)) + mockQueryErr := errors.New("mock query error") + + tests := []struct { + name string + snapshot *v2.Snapshot + releases []*helmrelease.Release + queryError error + want *helmrelease.Release + wantErr error + }{ + { + name: "valid last release", + snapshot: mockInfo, + releases: []*helmrelease.Release{mockOne, mockTwo}, + want: mockTwo, + }, + { + name: "invalid last release", + snapshot: mockInfo, + releases: []*helmrelease.Release{mockOne}, + wantErr: ErrReleaseNotObserved, + }, + { + name: "no last release", + snapshot: mockInfo, + releases: []*helmrelease.Release{}, + wantErr: ErrReleaseDisappeared, + }, + { + name: "no release snapshot", + snapshot: nil, + releases: nil, + wantErr: ErrReleaseNotFound, + }, + { + name: "driver query error", + snapshot: mockInfo, + queryError: mockQueryErr, + wantErr: mockQueryErr, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + s := helmstorage.Init(driver.NewMemory()) + for _, v := range tt.releases { + g.Expect(s.Create(v)).To(Succeed()) + } + + s.Driver = &storage.Failing{ + Driver: s.Driver, + QueryErr: tt.queryError, + } + + rls, err := VerifyLastStorageItem(&helmaction.Configuration{Releases: s}, tt.snapshot) + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(err).To(Equal(tt.wantErr)) + g.Expect(rls).To(BeNil()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(rls).To(Equal(tt.want)) + }) + } +} + +func TestVerifyReleaseObject(t *testing.T) { + mockRls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusSuperseded, + Namespace: "default", + }) + mockSnapshot := release.ObservedToSnapshot(release.ObserveRelease(mockRls)) + mockSnapshotIllegal := mockSnapshot.DeepCopy() + mockSnapshotIllegal.Digest = "illegal" + + tests := []struct { + name string + snapshot *v2.Snapshot + rls *helmrelease.Release + wantErr error + }{ + { + name: "valid digest", + snapshot: mockSnapshot, + rls: mockRls, + }, + { + name: "illegal digest", + snapshot: mockSnapshotIllegal, + wantErr: ErrReleaseDigest, + }, + { + name: "invalid digest", + snapshot: mockSnapshot, + rls: testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusDeployed, + Namespace: "default", + }), + wantErr: ErrReleaseNotObserved, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got := VerifyReleaseObject(tt.snapshot, tt.rls) + + if tt.wantErr != nil { + g.Expect(got).To(HaveOccurred()) + g.Expect(got).To(Equal(tt.wantErr)) + return + } + + g.Expect(got).NotTo(HaveOccurred()) + }) + } +} + +func TestVerifyRelease(t *testing.T) { + mockRls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "release", + Version: 1, + Status: helmrelease.StatusSuperseded, + Namespace: "default", + }) + mockSnapshot := release.ObservedToSnapshot(release.ObserveRelease(mockRls)) + + tests := []struct { + name string + rls *helmrelease.Release + snapshot *v2.Snapshot + chrt *helmchart.Metadata + vals chartutil.Values + wantErr error + }{ + { + name: "equal", + rls: mockRls, + snapshot: mockSnapshot, + chrt: mockRls.Chart.Metadata, + vals: mockRls.Config, + }, + { + name: "no release", + rls: nil, + snapshot: mockSnapshot, + chrt: mockRls.Chart.Metadata, + vals: mockRls.Config, + wantErr: ErrReleaseNotFound, + }, + { + name: "no release snapshot", + rls: mockRls, + snapshot: nil, + chrt: mockRls.Chart.Metadata, + vals: mockRls.Config, + wantErr: ErrConfigDigest, + }, + { + name: "chart meta diff", + rls: mockRls, + snapshot: mockSnapshot, + chrt: &helmchart.Metadata{ + Name: "some-other-chart", + Version: "1.0.0", + }, + vals: mockRls.Config, + wantErr: ErrChartChanged, + }, + { + name: "chart values diff", + rls: mockRls, + snapshot: mockSnapshot, + chrt: mockRls.Chart.Metadata, + vals: chartutil.Values{ + "some": "other", + }, + wantErr: ErrConfigDigest, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got := VerifyRelease(tt.rls, tt.snapshot, tt.chrt, tt.vals) + + if tt.wantErr != nil { + g.Expect(got).To(HaveOccurred()) + g.Expect(got).To(Equal(tt.wantErr)) + return + } + + g.Expect(got).ToNot(HaveOccurred()) + }) + } +} diff --git a/internal/chartutil/digest.go b/internal/chartutil/digest.go new file mode 100644 index 000000000..5a5cf83cc --- /dev/null +++ b/internal/chartutil/digest.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chartutil + +import ( + "github.com/opencontainers/go-digest" + "helm.sh/helm/v3/pkg/chartutil" + + intyaml "github.com/fluxcd/helm-controller/internal/yaml" +) + +// DigestValues calculates the digest of the values using the provided algorithm. +// The caller is responsible for ensuring that the algorithm is supported. +func DigestValues(algo digest.Algorithm, values chartutil.Values) digest.Digest { + digester := algo.Digester() + if values = valuesOrNil(values); values != nil { + if err := intyaml.Encode(digester.Hash(), values, intyaml.SortMapSlice); err != nil { + return "" + } + } + return digester.Digest() +} + +// VerifyValues verifies the digest of the values against the provided digest. +func VerifyValues(digest digest.Digest, values chartutil.Values) bool { + if digest.Validate() != nil { + return false + } + + verifier := digest.Verifier() + if values = valuesOrNil(values); values != nil { + if err := intyaml.Encode(verifier, values, intyaml.SortMapSlice); err != nil { + return false + } + } + return verifier.Verified() +} + +// valuesOrNil returns nil if the values are empty, otherwise the values are +// returned. This is used to ensure that the digest is calculated against nil +// opposed to an empty object. +func valuesOrNil(values chartutil.Values) chartutil.Values { + if values != nil && len(values) == 0 { + return nil + } + return values +} diff --git a/internal/chartutil/digest_test.go b/internal/chartutil/digest_test.go new file mode 100644 index 000000000..54368d41a --- /dev/null +++ b/internal/chartutil/digest_test.go @@ -0,0 +1,244 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chartutil + +import ( + "testing" + + "github.com/opencontainers/go-digest" + "helm.sh/helm/v3/pkg/chartutil" +) + +func TestDigestValues(t *testing.T) { + tests := []struct { + name string + algo digest.Algorithm + values chartutil.Values + want digest.Digest + }{ + { + name: "empty", + algo: digest.SHA256, + values: chartutil.Values{}, + want: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + }, + { + name: "nil", + algo: digest.SHA256, + values: nil, + want: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + }, + { + name: "value map", + algo: digest.SHA256, + values: chartutil.Values{ + "replicas": 3, + "image": map[string]interface{}{ + "tag": "latest", + "repository": "nginx", + }, + "ports": []interface{}{ + map[string]interface{}{ + "protocol": "TCP", + "port": 8080, + }, + map[string]interface{}{ + "port": 9090, + "protocol": "UDP", + }, + }, + }, + want: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6", + }, + { + name: "value map in different order", + algo: digest.SHA256, + values: chartutil.Values{ + "image": map[string]interface{}{ + "repository": "nginx", + "tag": "latest", + }, + "ports": []interface{}{ + map[string]interface{}{ + "port": 8080, + "protocol": "TCP", + }, + map[string]interface{}{ + "port": 9090, + "protocol": "UDP", + }, + }, + "replicas": 3, + }, + want: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6", + }, + { + // Explicit test for something that does not work with sigs.k8s.io/yaml. + // See: https://go.dev/play/p/KRyfK9ZobZx + name: "values map with numeric keys", + algo: digest.SHA256, + values: chartutil.Values{ + "replicas": 3, + "test": map[string]interface{}{ + "632bd80235a05f4192aefade": "value1", + "632bd80ddf416cf32fd50679": "value2", + "632bd817c559818a52307da2": "value3", + "632bd82398e71231a98004b6": "value4", + }, + }, + want: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70", + }, + { + name: "values map with numeric keys in different order", + algo: digest.SHA256, + values: chartutil.Values{ + "test": map[string]interface{}{ + "632bd82398e71231a98004b6": "value4", + "632bd817c559818a52307da2": "value3", + "632bd80ddf416cf32fd50679": "value2", + "632bd80235a05f4192aefade": "value1", + }, + "replicas": 3, + }, + want: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70", + }, + { + name: "using different algorithm", + algo: digest.SHA512, + values: chartutil.Values{ + "foo": "bar", + "baz": map[string]interface{}{ + "cool": "stuff", + }, + }, + want: "sha512:b5f9cd4855ca3b08afd602557f373069b1732ce2e6d52341481b0d38f1938452e9d7759ab177c66699962b592f20ceded03eea3cd405d8670578c47842e2c550", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := DigestValues(tt.algo, tt.values); got != tt.want { + t.Errorf("DigestValues() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestVerifyValues(t *testing.T) { + tests := []struct { + name string + digest digest.Digest + values chartutil.Values + want bool + }{ + { + name: "empty values", + digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + values: chartutil.Values{}, + want: true, + }, + { + name: "nil values", + digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + values: nil, + want: true, + }, + { + name: "empty digest", + digest: "", + want: false, + }, + { + name: "invalid digest", + digest: "sha512:invalid", + values: nil, + want: false, + }, + { + name: "matching values", + digest: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6", + values: chartutil.Values{ + "image": map[string]interface{}{ + "repository": "nginx", + "tag": "latest", + }, + "ports": []interface{}{ + map[string]interface{}{ + "port": 8080, + "protocol": "TCP", + }, + map[string]interface{}{ + "port": 9090, + "protocol": "UDP", + }, + }, + "replicas": 3, + }, + want: true, + }, + { + name: "matching values in different order", + digest: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6", + values: chartutil.Values{ + "replicas": 3, + "image": map[string]interface{}{ + "tag": "latest", + "repository": "nginx", + }, + "ports": []interface{}{ + map[string]interface{}{ + "protocol": "TCP", + "port": 8080, + }, + map[string]interface{}{ + "port": 9090, + "protocol": "UDP", + }, + }, + }, + want: true, + }, + { + name: "matching values with numeric keys", + digest: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70", + values: chartutil.Values{ + "replicas": 3, + "test": map[string]interface{}{ + "632bd80235a05f4192aefade": "value1", + "632bd80ddf416cf32fd50679": "value2", + "632bd817c559818a52307da2": "value3", + "632bd82398e71231a98004b6": "value4", + }, + }, + want: true, + }, + { + name: "mismatching values", + digest: "sha256:3f3641788a2d4abda3534eaa90c90b54916e4c6e3a5b2e1b24758b7bfa701ecd", + values: chartutil.Values{ + "foo": "bar", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := VerifyValues(tt.digest, tt.values); got != tt.want { + t.Errorf("VerifyValues() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/chartutil/values.go b/internal/chartutil/values.go new file mode 100644 index 000000000..a5a196b5e --- /dev/null +++ b/internal/chartutil/values.go @@ -0,0 +1,272 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chartutil + +import ( + "context" + "errors" + "fmt" + "strings" + + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/strvals" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/fluxcd/pkg/runtime/transform" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +// ErrValuesRefReason is the descriptive reason for an ErrValuesReference. +type ErrValuesRefReason error + +var ( + // ErrResourceNotFound signals the referenced values resource could not be + // found. + ErrResourceNotFound = errors.New("resource not found") + // ErrKeyNotFound signals the key could not be found in the referenced + // values resource. + ErrKeyNotFound = errors.New("key not found") + // ErrUnsupportedRefKind signals the values reference kind is not + // supported. + ErrUnsupportedRefKind = errors.New("unsupported values reference kind") + // ErrValuesDataRead signals the referenced resource's values data could + // not be read. + ErrValuesDataRead = errors.New("failed to read values data") + // ErrValueMerge signals a single value could not be merged into the + // values. + ErrValueMerge = errors.New("failed to merge value") + // ErrUnknown signals the reason an error occurred is unknown. + ErrUnknown = errors.New("unknown error") +) + +// ErrValuesReference is returned by ChartValuesFromReferences +type ErrValuesReference struct { + // Reason for the values reference error. Nil equals ErrUnknown. + // Can be used with Is to reason about a returned error: + // err := &ErrValuesReference{Reason: ErrResourceNotFound, ...} + // errors.Is(err, ErrResourceNotFound) + Reason ErrValuesRefReason + // Kind of the values reference the error is being reported for. + Kind string + // Name of the values reference the error is being reported for. + Name types.NamespacedName + // Key of the values reference the error is being reported for. + Key string + // Optional indicates if the error is being reported for an optional values + // reference. + Optional bool + // Err contains the further error chain leading to this error, it can be + // nil. + Err error +} + +// Error returns an error string constructed out of the state of +// ErrValuesReference. +func (e *ErrValuesReference) Error() string { + b := strings.Builder{} + b.WriteString("could not resolve") + if e.Optional { + b.WriteString(" optional") + } + if kind := e.Kind; kind != "" { + b.WriteString(" " + kind) + } + b.WriteString(" chart values reference") + if name := e.Name.String(); name != "" { + b.WriteString(fmt.Sprintf(" '%s'", name)) + } + if key := e.Key; key != "" { + b.WriteString(fmt.Sprintf(" with key '%s'", key)) + } + reason := e.Reason.Error() + if reason == "" && e.Err == nil { + reason = ErrUnknown.Error() + } + if e.Err != nil { + reason = e.Err.Error() + } + b.WriteString(": " + reason) + return b.String() +} + +// Is returns if target == Reason, or target == Err. +// Can be used to Reason about a returned error: +// +// err := &ErrValuesReference{Reason: ErrResourceNotFound, ...} +// errors.Is(err, ErrResourceNotFound) +func (e *ErrValuesReference) Is(target error) bool { + reason := e.Reason + if reason == nil { + reason = ErrUnknown + } + if reason == target { + return true + } + return errors.Is(e.Err, target) +} + +// Unwrap returns the wrapped Err. +func (e *ErrValuesReference) Unwrap() error { + return e.Err +} + +// NewErrValuesReference returns a new ErrValuesReference constructed from the +// provided values. +func NewErrValuesReference(name types.NamespacedName, ref v2.ValuesReference, reason ErrValuesRefReason, err error) *ErrValuesReference { + return &ErrValuesReference{ + Reason: reason, + Kind: ref.Kind, + Name: name, + Key: ref.GetValuesKey(), + Optional: ref.Optional, + Err: err, + } +} + +const ( + kindConfigMap = "ConfigMap" + kindSecret = "Secret" +) + +// ChartValuesFromReferences attempts to construct new chart values by resolving +// the provided references using the client, merging them in the order given. +// If provided, the values map is merged in last. Overwriting values from +// references. It returns the merged values, or an ErrValuesReference error. +func ChartValuesFromReferences(ctx context.Context, client kubeclient.Client, namespace string, + values map[string]interface{}, refs ...v2.ValuesReference) (chartutil.Values, error) { + + log := ctrl.LoggerFrom(ctx) + + result := chartutil.Values{} + resources := make(map[string]kubeclient.Object) + + for _, ref := range refs { + namespacedName := types.NamespacedName{Namespace: namespace, Name: ref.Name} + var valuesData []byte + + switch ref.Kind { + case kindConfigMap, kindSecret: + index := ref.Kind + namespacedName.String() + + resource, ok := resources[index] + if !ok { + // The resource may not exist, but we want to act on a single version + // of the resource in case the values reference is marked as optional. + resources[index] = nil + + switch ref.Kind { + case kindSecret: + resource = &corev1.Secret{} + case kindConfigMap: + resource = &corev1.ConfigMap{} + } + + if resource != nil { + if err := client.Get(ctx, namespacedName, resource); err != nil { + if apierrors.IsNotFound(err) { + err := NewErrValuesReference(namespacedName, ref, ErrResourceNotFound, err) + if err.Optional { + log.Info(err.Error()) + continue + } + return nil, err + } + return nil, err + } + resources[index] = resource + } + } + + if resource == nil { + if ref.Optional { + continue + } + return nil, NewErrValuesReference(namespacedName, ref, ErrResourceNotFound, nil) + } + + switch typedRes := resource.(type) { + case *corev1.Secret: + data, ok := typedRes.Data[ref.GetValuesKey()] + if !ok { + err := NewErrValuesReference(namespacedName, ref, ErrKeyNotFound, nil) + if ref.Optional { + log.Info(err.Error()) + continue + } + return nil, NewErrValuesReference(namespacedName, ref, ErrKeyNotFound, nil) + } + valuesData = data + case *corev1.ConfigMap: + data, ok := typedRes.Data[ref.GetValuesKey()] + if !ok { + err := NewErrValuesReference(namespacedName, ref, ErrKeyNotFound, nil) + if ref.Optional { + log.Info(err.Error()) + continue + } + return nil, err + } + valuesData = []byte(data) + default: + return nil, NewErrValuesReference(namespacedName, ref, ErrUnsupportedRefKind, nil) + } + default: + return nil, NewErrValuesReference(namespacedName, ref, ErrUnsupportedRefKind, nil) + } + + if ref.TargetPath != "" { + // TODO(hidde): this is a bit of hack, as it mimics the way the option string is passed + // to Helm from a CLI perspective. Given the parser is however not publicly accessible + // while it contains all logic around parsing the target path, it is a fair trade-off. + if err := ReplacePathValue(result, ref.TargetPath, string(valuesData)); err != nil { + return nil, NewErrValuesReference(namespacedName, ref, ErrValueMerge, err) + } + continue + } + + values, err := chartutil.ReadValues(valuesData) + if err != nil { + return nil, NewErrValuesReference(namespacedName, ref, ErrValuesDataRead, err) + } + result = transform.MergeMaps(result, values) + } + return transform.MergeMaps(result, values), nil +} + +// ReplacePathValue replaces the value at the dot notation path with the given +// value using Helm's string value parser using strvals.ParseInto. Single or +// double-quoted values are merged using strvals.ParseIntoString. +func ReplacePathValue(values chartutil.Values, path string, value string) error { + const ( + singleQuote = "'" + doubleQuote = `"` + ) + isSingleQuoted := strings.HasPrefix(value, singleQuote) && strings.HasSuffix(value, singleQuote) + isDoubleQuoted := strings.HasPrefix(value, doubleQuote) && strings.HasSuffix(value, doubleQuote) + if isSingleQuoted || isDoubleQuoted { + value = strings.Trim(value, singleQuote+doubleQuote) + value = path + "=" + value + return strvals.ParseIntoString(value, values) + } + value = path + "=" + value + return strvals.ParseInto(value, values) +} diff --git a/internal/chartutil/values_fuzz_test.go b/internal/chartutil/values_fuzz_test.go new file mode 100644 index 000000000..bec7d58fe --- /dev/null +++ b/internal/chartutil/values_fuzz_test.go @@ -0,0 +1,186 @@ +//go:build gofuzz_libfuzzer +// +build gofuzz_libfuzzer + +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chartutil + +import ( + "context" + "testing" + + "github.com/go-logr/logr" + "helm.sh/helm/v3/pkg/chartutil" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func FuzzChartValuesFromReferences(f *testing.F) { + scheme := testScheme() + + tests := []struct { + targetPath string + valuesKey string + hrValues string + createObject bool + secretData []byte + configData string + }{ + { + targetPath: "flat", + valuesKey: "custom-values.yaml", + secretData: []byte(`flat: + nested: value +nested: value +`), + configData: `flat: value +nested: + configuration: value +`, + hrValues: ` +other: values +`, + createObject: true, + }, + { + targetPath: "'flat'", + valuesKey: "custom-values.yaml", + secretData: []byte(`flat: + nested: value +nested: value +`), + configData: `flat: value +nested: + configuration: value +`, + hrValues: ` +other: values +`, + createObject: true, + }, + { + targetPath: "flat[0]", + secretData: []byte(``), + configData: `flat: value`, + hrValues: ` +other: values +`, + createObject: true, + }, + { + secretData: []byte(`flat: + nested: value +nested: value +`), + configData: `flat: value +nested: + configuration: value +`, + hrValues: ` +other: values +`, + createObject: true, + }, + { + targetPath: "some-value", + hrValues: ` +other: values +`, + createObject: false, + }, + } + + for _, tt := range tests { + f.Add(tt.targetPath, tt.valuesKey, tt.hrValues, tt.createObject, tt.secretData, tt.configData) + } + + f.Fuzz(func(t *testing.T, + targetPath, valuesKey, hrValues string, createObject bool, secretData []byte, configData string) { + + // objectName and objectNamespace represent a name reference to a core + // Kubernetes object upstream (Secret/ConfigMap) which is validated upstream, + // and also validated by us in the OpenAPI-based validation set in + // v2.ValuesReference. Therefore, a static value here suffices, and instead + // we just play with the objects presence/absence. + objectName := "values" + objectNamespace := "default" + var resources []runtime.Object + + if createObject { + resources = append(resources, + mockConfigMap(objectName, map[string]string{valuesKey: configData}), + mockSecret(objectName, map[string][]byte{valuesKey: secretData}), + ) + } + + references := []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: objectName, + ValuesKey: valuesKey, + TargetPath: targetPath, + }, + { + Kind: kindSecret, + Name: objectName, + ValuesKey: valuesKey, + TargetPath: targetPath, + }, + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(resources...) + var values chartutil.Values + if hrValues != "" { + values, _ = chartutil.ReadValues([]byte(hrValues)) + } + + _, _ = ChartValuesFromReferences(logr.NewContext(context.TODO(), logr.Discard()), c.Build(), objectNamespace, values, references...) + }) +} + +func mockSecret(name string, data map[string][]byte) *corev1.Secret { + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: kindSecret, + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: data, + } +} + +func mockConfigMap(name string, data map[string]string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: kindConfigMap, + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: data, + } +} + +func testScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = v2.AddToScheme(scheme) + return scheme +} diff --git a/internal/chartutil/values_test.go b/internal/chartutil/values_test.go new file mode 100644 index 000000000..a0895ec22 --- /dev/null +++ b/internal/chartutil/values_test.go @@ -0,0 +1,396 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chartutil + +import ( + "context" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/gomega" + "helm.sh/helm/v3/pkg/chartutil" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +func TestChartValuesFromReferences(t *testing.T) { + scheme := testScheme() + + tests := []struct { + name string + resources []runtime.Object + namespace string + references []v2.ValuesReference + values string + want chartutil.Values + wantErr bool + }{ + { + name: "merges", + resources: []runtime.Object{ + mockConfigMap("values", map[string]string{ + "values.yaml": `flat: value +nested: + configuration: value +`, + }), + mockSecret("values", map[string][]byte{ + "values.yaml": []byte(`flat: + nested: value +nested: value +`), + }), + }, + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "values", + }, + { + Kind: kindSecret, + Name: "values", + }, + }, + values: ` +other: values +`, + want: chartutil.Values{ + "flat": map[string]interface{}{ + "nested": "value", + }, + "nested": "value", + "other": "values", + }, + }, + { + name: "with target path", + resources: []runtime.Object{ + mockSecret("values", map[string][]byte{"single": []byte("value")}), + }, + references: []v2.ValuesReference{ + { + Kind: kindSecret, + Name: "values", + ValuesKey: "single", + TargetPath: "merge.at.specific.path", + }, + }, + want: chartutil.Values{ + "merge": map[string]interface{}{ + "at": map[string]interface{}{ + "specific": map[string]interface{}{ + "path": "value", + }, + }, + }, + }, + }, + { + name: "target path for string type array item", + resources: []runtime.Object{ + mockConfigMap("values", map[string]string{ + "values.yaml": `flat: value +nested: + configuration: + - list + - item + - option +`, + }), + mockSecret("values", map[string][]byte{ + "values.yaml": []byte(`foo`), + }), + }, + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "values", + }, + { + Kind: kindSecret, + Name: "values", + TargetPath: "nested.configuration[1]", + }, + }, + values: ` +other: values +`, + want: chartutil.Values{ + "flat": "value", + "nested": map[string]interface{}{ + "configuration": []interface{}{"list", "foo", "option"}, + }, + "other": "values", + }, + }, + { + name: "values reference to non existing secret", + references: []v2.ValuesReference{ + { + Kind: kindSecret, + Name: "missing", + }, + }, + wantErr: true, + }, + { + name: "optional values reference to non existing secret", + references: []v2.ValuesReference{ + { + Kind: kindSecret, + Name: "missing", + Optional: true, + }, + }, + want: chartutil.Values{}, + wantErr: false, + }, + { + name: "values reference to non existing config map", + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "missing", + }, + }, + wantErr: true, + }, + { + name: "optional values reference to non existing config map", + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "missing", + Optional: true, + }, + }, + want: chartutil.Values{}, + wantErr: false, + }, + { + name: "missing secret key", + resources: []runtime.Object{ + mockSecret("values", nil), + }, + references: []v2.ValuesReference{ + { + Kind: kindSecret, + Name: "values", + ValuesKey: "nonexisting", + }, + }, + wantErr: true, + }, + { + name: "missing config map key", + resources: []runtime.Object{ + mockConfigMap("values", nil), + }, + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "values", + ValuesKey: "nonexisting", + }, + }, + wantErr: true, + }, + { + name: "unsupported values reference kind", + references: []v2.ValuesReference{ + { + Kind: "Unsupported", + }, + }, + wantErr: true, + }, + { + name: "invalid values", + resources: []runtime.Object{ + mockConfigMap("values", map[string]string{ + "values.yaml": ` +invalid`, + }), + }, + references: []v2.ValuesReference{ + { + Kind: kindConfigMap, + Name: "values", + }, + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(tt.resources...) + var values map[string]interface{} + if tt.values != "" { + m, err := chartutil.ReadValues([]byte(tt.values)) + g.Expect(err).ToNot(HaveOccurred()) + values = m + } + ctx := logr.NewContext(context.TODO(), logr.Discard()) + got, err := ChartValuesFromReferences(ctx, c.Build(), tt.namespace, values, tt.references...) + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + g.Expect(got).To(BeNil()) + return + } + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(Equal(tt.want)) + }) + } +} + +// This tests compatability with the formats described in: +// https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set +func TestReplacePathValue(t *testing.T) { + tests := []struct { + name string + value []byte + path string + want map[string]interface{} + wantErr bool + }{ + { + name: "outer inner", + value: []byte("value"), + path: "outer.inner", + want: map[string]interface{}{ + "outer": map[string]interface{}{ + "inner": "value", + }, + }, + }, + { + name: "inline list", + value: []byte("{a,b,c}"), + path: "name", + want: map[string]interface{}{ + // TODO(hidde): figure out why the cap is off by len+1 + "name": append(make([]interface{}, 0, 4), []interface{}{"a", "b", "c"}...), + }, + }, + { + name: "with escape", + value: []byte(`value1\,value2`), + path: "name", + want: map[string]interface{}{ + "name": "value1,value2", + }, + }, + { + name: "target path with boolean value", + value: []byte("true"), + path: "merge.at.specific.path", + want: chartutil.Values{ + "merge": map[string]interface{}{ + "at": map[string]interface{}{ + "specific": map[string]interface{}{ + "path": true, + }, + }, + }, + }, + }, + { + name: "target path with set-string behavior", + value: []byte(`"true"`), + path: "merge.at.specific.path", + want: chartutil.Values{ + "merge": map[string]interface{}{ + "at": map[string]interface{}{ + "specific": map[string]interface{}{ + "path": "true", + }, + }, + }, + }, + }, + { + name: "target path with array item", + value: []byte("value"), + path: "merge.at[2]", + want: chartutil.Values{ + "merge": map[string]interface{}{ + "at": []interface{}{nil, nil, "value"}, + }, + }, + }, + { + name: "dot sequence escaping path", + value: []byte("master"), + path: `nodeSelector.kubernetes\.io/role`, + want: map[string]interface{}{ + "nodeSelector": map[string]interface{}{ + "kubernetes.io/role": "master", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + values := map[string]interface{}{} + err := ReplacePathValue(values, tt.path, string(tt.value)) + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + g.Expect(values).To(BeNil()) + return + } + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(values).To(Equal(tt.want)) + }) + } +} + +func mockSecret(name string, data map[string][]byte) *corev1.Secret { + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: kindSecret, + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: data, + } +} + +func mockConfigMap(name string, data map[string]string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: kindConfigMap, + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: data, + } +} + +func testScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = v2.AddToScheme(scheme) + return scheme +} diff --git a/internal/controller/helmrelease_controller.go b/internal/controller/helmrelease_controller.go index 45833cd4c..7380913c7 100644 --- a/internal/controller/helmrelease_controller.go +++ b/internal/controller/helmrelease_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The Flux authors +Copyright 2023 The Flux authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,18 +23,11 @@ import ( "strings" "time" - "github.com/fluxcd/pkg/runtime/conditions" "github.com/hashicorp/go-retryablehttp" - "helm.sh/helm/v3/pkg/chart" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/storage/driver" - "helm.sh/helm/v3/pkg/strvals" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - apimeta "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + apierrutil "k8s.io/apimachinery/pkg/util/errors" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/rest" kuberecorder "k8s.io/client-go/tools/record" @@ -49,23 +42,30 @@ import ( "sigs.k8s.io/controller-runtime/pkg/ratelimiter" "sigs.k8s.io/controller-runtime/pkg/reconcile" - apiacl "github.com/fluxcd/pkg/apis/acl" + aclv1 "github.com/fluxcd/pkg/apis/acl" eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/acl" runtimeClient "github.com/fluxcd/pkg/runtime/client" + "github.com/fluxcd/pkg/runtime/conditions" helper "github.com/fluxcd/pkg/runtime/controller" "github.com/fluxcd/pkg/runtime/jitter" + "github.com/fluxcd/pkg/runtime/logger" + "github.com/fluxcd/pkg/runtime/patch" "github.com/fluxcd/pkg/runtime/predicates" - "github.com/fluxcd/pkg/runtime/transform" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" - v2 "github.com/fluxcd/helm-controller/api/v2beta1" - "github.com/fluxcd/helm-controller/internal/diff" + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + intacl "github.com/fluxcd/helm-controller/internal/acl" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" "github.com/fluxcd/helm-controller/internal/features" "github.com/fluxcd/helm-controller/internal/kube" - "github.com/fluxcd/helm-controller/internal/runner" - "github.com/fluxcd/helm-controller/internal/util" + "github.com/fluxcd/helm-controller/internal/loader" + intpredicates "github.com/fluxcd/helm-controller/internal/predicates" + intreconcile "github.com/fluxcd/helm-controller/internal/reconcile" + "github.com/fluxcd/helm-controller/internal/release" ) // +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete @@ -75,32 +75,42 @@ import ( // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmcharts/status,verbs=get // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch -// HelmReleaseReconciler reconciles a HelmRelease object +// HelmReleaseReconciler reconciles a HelmRelease object. type HelmReleaseReconciler struct { client.Client + kuberecorder.EventRecorder helper.Metrics - Config *rest.Config - Scheme *runtime.Scheme - EventRecorder kuberecorder.EventRecorder - NoCrossNamespaceRef bool - ClientOpts runtimeClient.Options - KubeConfigOpts runtimeClient.KubeConfigOptions - StatusPoller *polling.StatusPoller - PollingOpts polling.Options - ControllerName string + GetClusterConfig func() (*rest.Config, error) + ClientOpts runtimeClient.Options + KubeConfigOpts runtimeClient.KubeConfigOptions + + PollingOpts polling.Options + StatusPoller *polling.StatusPoller + + FieldManager string + DefaultServiceAccount string httpClient *retryablehttp.Client requeueDependency time.Duration } +type HelmReleaseReconcilerOptions struct { + HTTPRetry int + DependencyRequeueInterval time.Duration + RateLimiter ratelimiter.RateLimiter +} + func (r *HelmReleaseReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, opts HelmReleaseReconcilerOptions) error { // Index the HelmRelease by the HelmChart references they point at if err := mgr.GetFieldIndexer().IndexField(ctx, &v2.HelmRelease{}, v2.SourceIndexKey, func(o client.Object) []string { - hr := o.(*v2.HelmRelease) + obj := o.(*v2.HelmRelease) return []string{ - fmt.Sprintf("%s/%s", hr.Spec.Chart.GetNamespace(hr.GetNamespace()), hr.GetHelmChartName()), + types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.GetNamespace()), + Name: obj.GetHelmChartName(), + }.String(), } }, ); err != nil { @@ -125,7 +135,7 @@ func (r *HelmReleaseReconciler) SetupWithManager(ctx context.Context, mgr ctrl.M Watches( &sourcev1.HelmChart{}, handler.EnqueueRequestsFromMapFunc(r.requestsForHelmChartChange), - builder.WithPredicates(SourceRevisionChangePredicate{}), + builder.WithPredicates(intpredicates.SourceRevisionChangePredicate{}), ). WithOptions(controller.Options{ RateLimiter: opts.RateLimiter, @@ -133,621 +143,491 @@ func (r *HelmReleaseReconciler) SetupWithManager(ctx context.Context, mgr ctrl.M Complete(r) } -// ConditionError represents an error with a status condition reason attached. -type ConditionError struct { - Reason string - Err error -} - -func (c ConditionError) Error() string { - return c.Err.Error() -} - -func (r *HelmReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *HelmReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) { start := time.Now() log := ctrl.LoggerFrom(ctx) - var hr v2.HelmRelease - if err := r.Get(ctx, req.NamespacedName, &hr); err != nil { + // Fetch the HelmRelease + obj := &v2.HelmRelease{} + if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } + // Initialize the patch helper with the current version of the object. + patchHelper := patch.NewSerialPatcher(obj, r.Client) + + // Always attempt to patch the object after each reconciliation. defer func() { - // Always record metrics. - r.Metrics.RecordSuspend(ctx, &hr, hr.Spec.Suspend) - r.Metrics.RecordReadiness(ctx, &hr) - r.Metrics.RecordDuration(ctx, &hr, start) - }() + patchOpts := []patch.Option{ + patch.WithFieldOwner(r.FieldManager), + patch.WithOwnedConditions{Conditions: intreconcile.OwnedConditions}, + } - // Add our finalizer if it does not exist - if !controllerutil.ContainsFinalizer(&hr, v2.HelmReleaseFinalizer) { - patch := client.MergeFrom(hr.DeepCopy()) - controllerutil.AddFinalizer(&hr, v2.HelmReleaseFinalizer) - if err := r.Patch(ctx, &hr, patch); err != nil { - log.Error(err, "unable to register finalizer") - return ctrl.Result{}, err + if errors.Is(retErr, reconcile.TerminalError(nil)) || (retErr == nil && (result.IsZero() || !result.Requeue)) { + patchOpts = append(patchOpts, patch.WithStatusObservedGeneration{}) } - } - // Examine if the object is under deletion - if !hr.ObjectMeta.DeletionTimestamp.IsZero() { - return r.reconcileDelete(ctx, &hr) - } + if err := patchHelper.Patch(ctx, obj, patchOpts...); err != nil { + if !obj.DeletionTimestamp.IsZero() { + err = apierrutil.FilterOut(err, func(e error) bool { return apierrors.IsNotFound(e) }) + } + retErr = apierrutil.Reduce(apierrutil.NewAggregate([]error{retErr, err})) + } - // Return early if the HelmRelease is suspended. - if hr.Spec.Suspend { - log.Info("Reconciliation is suspended for this object") - return ctrl.Result{}, nil + // Always record suspend, readiness and duration metrics. + r.Metrics.RecordSuspend(ctx, obj, obj.Spec.Suspend) + r.Metrics.RecordReadiness(ctx, obj) + r.Metrics.RecordDuration(ctx, obj, start) + }() + + // Examine if the object is under deletion. + if !obj.ObjectMeta.DeletionTimestamp.IsZero() { + return r.reconcileDelete(ctx, obj) } - hr, result, err := r.reconcile(ctx, hr) + // Add finalizer first if not exist to avoid the race condition + // between init and delete. + // Note: Finalizers in general can only be added when the deletionTimestamp + // is not set. + if !controllerutil.ContainsFinalizer(obj, v2.HelmReleaseFinalizer) { + controllerutil.AddFinalizer(obj, v2.HelmReleaseFinalizer) + return ctrl.Result{Requeue: true}, nil + } - // Update status after reconciliation. - if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil { - log.Error(updateStatusErr, "unable to update status after reconciliation") - return ctrl.Result{Requeue: true}, updateStatusErr + // Return early if the object is suspended. + if obj.Spec.Suspend { + log.Info("reconciliation is suspended for this object") + return ctrl.Result{}, nil } - // Log reconciliation duration - durationMsg := fmt.Sprintf("reconciliation finished in %s", time.Since(start).String()) - if result.RequeueAfter > 0 { - durationMsg = fmt.Sprintf("%s, next run in %s", durationMsg, result.RequeueAfter.String()) + // Reconcile the HelmChart template. + if err := r.reconcileChartTemplate(ctx, obj); err != nil { + return ctrl.Result{}, err } - log.Info(durationMsg) - return result, err + return r.reconcileRelease(ctx, patchHelper, obj) } -func (r *HelmReleaseReconciler) reconcile(ctx context.Context, hr v2.HelmRelease) (v2.HelmRelease, ctrl.Result, error) { +func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelper *patch.SerialPatcher, obj *v2.HelmRelease) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) - // Record the value of the reconciliation request, if any - if v, ok := meta.ReconcileAnnotationValue(hr.GetAnnotations()); ok { - hr.Status.SetLastHandledReconcileRequest(v) - } - - // Observe HelmRelease generation. - if hr.Status.ObservedGeneration != hr.Generation { - hr.Status.ObservedGeneration = hr.Generation - hr = v2.HelmReleaseProgressing(hr) - if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil { - log.Error(updateStatusErr, "unable to update status after generation update") - return hr, ctrl.Result{Requeue: true}, updateStatusErr + + // Mark the resource as under reconciliation. + conditions.MarkReconciling(obj, meta.ProgressingReason, "Fulfilling prerequisites") + if err := patchHelper.Patch(ctx, obj); err != nil { + return ctrl.Result{}, err + } + + // Confirm dependencies are Ready before proceeding. + if c := len(obj.Spec.DependsOn); c > 0 { + log.Info(fmt.Sprintf("checking %d dependencies", c)) + + if err := r.checkDependencies(ctx, obj); err != nil { + msg := fmt.Sprintf("dependencies do not meet ready condition (%s): retrying in %s", + err.Error(), r.requeueDependency.String()) + conditions.MarkFalse(obj, meta.ReadyCondition, v2.DependencyNotReadyReason, err.Error()) + r.Eventf(obj, eventv1.EventSeverityInfo, v2.DependencyNotReadyReason, err.Error()) + log.Info(msg) + + // Exponential backoff would cause execution to be prolonged too much, + // instead we requeue on a fixed interval. + return ctrl.Result{RequeueAfter: r.requeueDependency}, nil } + + log.Info("all dependencies are ready") } - // Reconcile chart based on the HelmChartTemplate - hc, reconcileErr := r.reconcileChart(ctx, &hr) - if reconcileErr != nil { - if acl.IsAccessDenied(reconcileErr) { - log.Error(reconcileErr, "access denied to cross-namespace source") - r.event(ctx, hr, hr.Status.LastAttemptedRevision, eventv1.EventSeverityError, reconcileErr.Error()) - return v2.HelmReleaseNotReady(hr, apiacl.AccessDeniedReason, reconcileErr.Error()), - jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: hr.GetRequeueAfter()}), nil + // Get the HelmChart object for the release. + hc, err := r.getHelmChart(ctx, obj) + if err != nil { + if acl.IsAccessDenied(err) { + conditions.MarkStalled(obj, aclv1.AccessDeniedReason, err.Error()) + conditions.MarkFalse(obj, meta.ReadyCondition, aclv1.AccessDeniedReason, err.Error()) + conditions.Delete(obj, meta.ReconcilingCondition) + + // Recovering from this is not possible without a restart of the + // controller or a change of spec, both triggering a new + // reconciliation. + return ctrl.Result{}, reconcile.TerminalError(err) } - msg := fmt.Sprintf("chart reconciliation failed: %s", reconcileErr.Error()) - r.event(ctx, hr, hr.Status.LastAttemptedRevision, eventv1.EventSeverityError, msg) - return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, msg), ctrl.Result{Requeue: true}, reconcileErr + msg := fmt.Sprintf("could not get HelmChart object: %s", err.Error()) + conditions.MarkFalse(obj, meta.ReadyCondition, v2.ArtifactFailedReason, msg) + return ctrl.Result{}, err } - // Check chart readiness - if hc.Generation != hc.Status.ObservedGeneration || !apimeta.IsStatusConditionTrue(hc.Status.Conditions, meta.ReadyCondition) { + // Check chart readiness. + if hc.Generation != hc.Status.ObservedGeneration || !conditions.IsReady(hc) || hc.GetArtifact() == nil { msg := fmt.Sprintf("HelmChart '%s/%s' is not ready", hc.GetNamespace(), hc.GetName()) - r.event(ctx, hr, hr.Status.LastAttemptedRevision, eventv1.EventSeverityInfo, msg) log.Info(msg) + conditions.MarkFalse(obj, meta.ReadyCondition, "HelmChartNotReady", msg) // Do not requeue immediately, when the artifact is created // the watcher should trigger a reconciliation. - return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, msg), jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: hr.GetRequeueAfter()}), nil + return jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: obj.GetRequeueAfter()}), nil } - // Check dependencies - if len(hr.Spec.DependsOn) > 0 { - if err := r.checkDependencies(hr); err != nil { - msg := fmt.Sprintf("dependencies do not meet ready condition (%s), retrying in %s", - err.Error(), r.requeueDependency.String()) - r.event(ctx, hr, hc.GetArtifact().Revision, eventv1.EventSeverityInfo, msg) - log.Info(msg) + // Compose values based from the spec and references. + values, err := chartutil.ChartValuesFromReferences(ctx, r.Client, obj.Namespace, obj.GetValues(), obj.Spec.ValuesFrom...) + if err != nil { + conditions.MarkFalse(obj, meta.ReadyCondition, "ValuesError", err.Error()) + return ctrl.Result{}, err + } - // Exponential backoff would cause execution to be prolonged too much, - // instead we requeue on a fixed interval. - return v2.HelmReleaseNotReady(hr, - v2.DependencyNotReadyReason, err.Error()), ctrl.Result{RequeueAfter: r.requeueDependency}, nil + // Load chart from artifact. + loadedChart, err := loader.SecureLoadChartFromURL(r.httpClient, hc.GetArtifact().URL, hc.GetArtifact().Digest) + if err != nil { + if errors.Is(err, loader.ErrFileNotFound) { + msg := fmt.Sprintf("Chart not ready: artifact not found. Retrying in %s", r.requeueDependency) + conditions.MarkFalse(obj, meta.ReadyCondition, v2.ArtifactFailedReason, msg) + log.Info(msg) + return ctrl.Result{RequeueAfter: r.requeueDependency}, nil } - log.Info("all dependencies are ready, proceeding with release") + + conditions.MarkFalse(obj, meta.ReadyCondition, v2.ArtifactFailedReason, fmt.Sprintf("Could not load chart: %s", err.Error())) + return ctrl.Result{}, err } - // Compose values - values, err := r.composeValues(ctx, hr) + // Build the REST client getter. + getter, err := r.buildRESTClientGetter(ctx, obj) if err != nil { - r.event(ctx, hr, hr.Status.LastAttemptedRevision, eventv1.EventSeverityError, err.Error()) - return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, err.Error()), ctrl.Result{Requeue: true}, nil + conditions.MarkFalse(obj, meta.ReadyCondition, "RESTClientError", err.Error()) + return ctrl.Result{}, err } - // Load chart from artifact - chart, err := r.loadHelmChart(hc) - if err != nil { - r.event(ctx, hr, hr.Status.LastAttemptedRevision, eventv1.EventSeverityError, err.Error()) - return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, err.Error()), ctrl.Result{Requeue: true}, nil + // 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 ok, _ := features.Enabled(features.AdoptLegacyReleases); ok { + if err := r.adoptLegacyRelease(ctx, getter, obj); err != nil { + log.Error(err, "failed to adopt v2beta1 release state") + } } - // Reconcile Helm release - reconciledHr, reconcileErr := r.reconcileRelease(ctx, *hr.DeepCopy(), chart, values) - if reconcileErr != nil { - r.event(ctx, hr, hc.GetArtifact().Revision, eventv1.EventSeverityError, - fmt.Sprintf("reconciliation failed: %s", reconcileErr.Error())) + // If the release target configuration has changed, we need to uninstall the + // previous release target first. If we did not do this, the installation would + // fail due to resources already existing. + if reason, changed := action.ReleaseTargetChanged(obj, loadedChart.Name()); changed { + log.Info(fmt.Sprintf("release target configuration changed (%s): running uninstall for current release", reason)) + if err = r.reconcileUninstall(ctx, getter, obj); err != nil && !errors.Is(err, intreconcile.ErrNoLatest) { + return ctrl.Result{}, err + } + obj.Status.ClearHistory() + obj.Status.ClearFailures() + obj.Status.StorageNamespace = "" + return ctrl.Result{Requeue: true}, nil } - return reconciledHr, jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: hr.GetRequeueAfter()}), reconcileErr -} -type HelmReleaseReconcilerOptions struct { - HTTPRetry int - DependencyRequeueInterval time.Duration - RateLimiter ratelimiter.RateLimiter -} + // Set current storage namespace. + obj.Status.StorageNamespace = obj.GetStorageNamespace() -func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, - hr v2.HelmRelease, chart *chart.Chart, values chartutil.Values) (v2.HelmRelease, error) { - log := ctrl.LoggerFrom(ctx) + // Reset the failure count if the chart or values have changed. + if reason, ok := action.MustResetFailures(obj, loadedChart.Metadata, values); ok { + log.V(logger.DebugLevel).Info(fmt.Sprintf("resetting failure count (%s)", reason)) + obj.Status.ClearFailures() + } + + // Set last attempt values. + obj.Status.LastAttemptedGeneration = obj.Generation + obj.Status.LastAttemptedRevision = loadedChart.Metadata.Version + obj.Status.LastAttemptedConfigDigest = chartutil.DigestValues(digest.Canonical, values).String() + obj.Status.LastAttemptedValuesChecksum = "" + obj.Status.LastReleaseRevision = 0 - // Initialize Helm action runner - getter, err := r.buildRESTClientGetter(ctx, hr) + // Construct config factory for any further Helm actions. + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.Status.StorageNamespace), + action.WithStorageLog(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.TraceLevel))), + ) if err != nil { - return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, err.Error()), err + conditions.MarkFalse(obj, meta.ReadyCondition, "FactoryError", err.Error()) + return ctrl.Result{}, err } - run, err := runner.NewRunner(getter, hr.GetStorageNamespace(), log) - if err != nil { - return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, "failed to initialize Helm action runner"), err - } - - // Determine last release revision. - rel, observeLastReleaseErr := run.ObserveLastRelease(hr) - if observeLastReleaseErr != nil { - err = fmt.Errorf("failed to get last release revision: %w", observeLastReleaseErr) - return v2.HelmReleaseNotReady(hr, v2.GetLastReleaseFailedReason, "failed to get last release revision"), err - } - - // Detect divergence between release in storage and HelmRelease spec. - revision := chart.Metadata.Version - releaseRevision := util.ReleaseRevision(rel) - // TODO: deprecate "unordered" checksum. - valuesChecksum := util.OrderedValuesChecksum(values) - hasNewState := v2.HelmReleaseChanged(hr, revision, releaseRevision, util.ValuesChecksum(values), valuesChecksum) - - // Register the current release attempt. - v2.HelmReleaseRecordAttempt(&hr, revision, releaseRevision, valuesChecksum) - - // Run diff against current cluster state. - if !hasNewState && rel != nil { - if ok, _ := features.Enabled(features.DetectDrift); ok { - differ := diff.NewDiffer(runtimeClient.NewImpersonator( - r.Client, - r.StatusPoller, - r.PollingOpts, - hr.Spec.KubeConfig, - r.KubeConfigOpts, - kube.DefaultServiceAccountName, - hr.Spec.ServiceAccountName, - hr.GetNamespace(), - ), r.ControllerName) - - changeSet, drift, err := differ.Diff(ctx, rel) - if err != nil { - if changeSet == nil { - msg := "failed to diff release against cluster resources" - r.event(ctx, hr, rel.Chart.Metadata.Version, eventv1.EventSeverityError, err.Error()) - return v2.HelmReleaseNotReady(hr, "DiffFailed", fmt.Sprintf("%s: %s", msg, err.Error())), err - } - log.Error(err, "diff of release against cluster resources finished with error") - } - msg := "no diff in cluster resources compared to release" - if drift { - msg = "diff in cluster resources compared to release" - hasNewState, _ = features.Enabled(features.CorrectDrift) - } - if changeSet != nil { - msg = fmt.Sprintf("%s:\n\n%s", msg, changeSet.String()) - r.event(ctx, hr, rel.Chart.Metadata.Version, eventv1.EventSeverityInfo, msg) - } - log.Info(msg) + // Off we go! + if err = intreconcile.NewAtomicRelease(patchHelper, cfg, r.EventRecorder, r.FieldManager).Reconcile(ctx, &intreconcile.Request{ + Object: obj, + Chart: loadedChart, + Values: values, + }); err != nil { + if errors.Is(err, intreconcile.ErrMustRequeue) { + return ctrl.Result{Requeue: true}, nil } - } - - if hasNewState { - hr = v2.HelmReleaseProgressing(hr) - if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil { - log.Error(updateStatusErr, "unable to update status after state update") - return hr, updateStatusErr + if errors.Is(err, intreconcile.ErrExceededMaxRetries) { + err = reconcile.TerminalError(err) } + return ctrl.Result{}, err } + return jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: obj.GetRequeueAfter()}), nil +} - // Check status of any previous release attempt. - released := apimeta.FindStatusCondition(hr.Status.Conditions, v2.ReleasedCondition) - if released != nil { - switch released.Status { - // Succeed if the previous release attempt succeeded. - case metav1.ConditionTrue: - return v2.HelmReleaseReady(hr), nil - case metav1.ConditionFalse: - // Fail if the previous release attempt remediation failed. - remediated := apimeta.FindStatusCondition(hr.Status.Conditions, v2.RemediatedCondition) - if remediated != nil && remediated.Status == metav1.ConditionFalse { - err = fmt.Errorf("previous release attempt remediation failed") - return v2.HelmReleaseNotReady(hr, remediated.Reason, remediated.Message), err - } +// reconcileDelete deletes the v1beta2.HelmChart of the v2beta2.HelmRelease, +// and uninstalls the Helm release if the resource has not been suspended. +func (r *HelmReleaseReconciler) reconcileDelete(ctx context.Context, obj *v2.HelmRelease) (ctrl.Result, error) { + // Only uninstall the release and delete the HelmChart resource if the + // resource is not suspended. + if !obj.Spec.Suspend { + if err := r.reconcileReleaseDeletion(ctx, obj); err != nil { + return ctrl.Result{}, err } - // Fail if install retries are exhausted. - if hr.Spec.GetInstall().GetRemediation().RetriesExhausted(hr) { - err = fmt.Errorf("install retries exhausted") - return v2.HelmReleaseNotReady(hr, released.Reason, err.Error()), err + if err := r.reconcileChartTemplate(ctx, obj); err != nil { + return ctrl.Result{}, err } + } - // Fail if there is a release and upgrade retries are exhausted. - // This avoids failing after an upgrade uninstall remediation strategy. - if rel != nil && hr.Spec.GetUpgrade().GetRemediation().RetriesExhausted(hr) { - err = fmt.Errorf("upgrade retries exhausted") - return v2.HelmReleaseNotReady(hr, released.Reason, err.Error()), err - } + if !obj.DeletionTimestamp.IsZero() { + // Remove our finalizer from the list. + controllerutil.RemoveFinalizer(obj, v2.HelmReleaseFinalizer) + + // Stop reconciliation as the object is being deleted. + return ctrl.Result{}, nil } - // Deploy the release. - var deployAction v2.DeploymentAction - if rel == nil { - r.event(ctx, hr, revision, eventv1.EventSeverityInfo, "Helm install has started") - deployAction = hr.Spec.GetInstall() - rel, err = run.Install(ctx, hr, chart, values) - err = r.handleHelmActionResult(ctx, &hr, revision, err, deployAction.GetDescription(), - v2.ReleasedCondition, v2.InstallSucceededReason, v2.InstallFailedReason) - } else { - r.event(ctx, hr, revision, eventv1.EventSeverityInfo, "Helm upgrade has started") - deployAction = hr.Spec.GetUpgrade() - rel, err = run.Upgrade(ctx, hr, chart, values) - err = r.handleHelmActionResult(ctx, &hr, revision, err, deployAction.GetDescription(), - v2.ReleasedCondition, v2.UpgradeSucceededReason, v2.UpgradeFailedReason) - } - remediation := deployAction.GetRemediation() - - // If there is a new release revision... - if util.ReleaseRevision(rel) > releaseRevision { - // Ensure release is not marked remediated. - apimeta.RemoveStatusCondition(&hr.Status.Conditions, v2.RemediatedCondition) - - // If new release revision is successful and tests are enabled, run them. - if err == nil && hr.Spec.GetTest().Enable { - _, testErr := run.Test(hr) - testErr = r.handleHelmActionResult(ctx, &hr, revision, testErr, "test", - v2.TestSuccessCondition, v2.TestSucceededReason, v2.TestFailedReason) - - // Propagate any test error if not marked ignored. - if testErr != nil && !remediation.MustIgnoreTestFailures(hr.Spec.GetTest().IgnoreFailures) { - testsPassing := apimeta.FindStatusCondition(hr.Status.Conditions, v2.TestSuccessCondition) - newCondition := metav1.Condition{ - Type: v2.ReleasedCondition, - Status: metav1.ConditionFalse, - Reason: testsPassing.Reason, - Message: testsPassing.Message, - } - apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition) - err = testErr - } - } + return ctrl.Result{Requeue: true}, nil +} + +// handleReleaseDeletion handles the deletion of a HelmRelease resource. +// +// Before uninstalling the release, it will check if the current configuration +// allows for uninstallation. If this is not the case, for example because a +// Secret reference is missing, it will skip the uninstallation gracefully. +// +// If the release is uninstalled successfully, the HelmRelease resource will +// be marked as ready and the current status will be cleared. If the release +// cannot be uninstalled, the HelmRelease resource will be marked as not ready +// and the error will be recorded in the status. +// +// Any returned error signals that the release could not be uninstalled, and +// the reconciliation should be retried. +func (r *HelmReleaseReconciler) reconcileReleaseDeletion(ctx context.Context, obj *v2.HelmRelease) error { + // If the release is not marked for deletion, we should not attempt to + // uninstall it. + if obj.DeletionTimestamp.IsZero() { + return fmt.Errorf("refusing to uninstall Helm release: deletion timestamp is not set") + } + + // If the release has not been installed yet, we can skip the uninstallation. + if obj.Status.StorageNamespace == "" { + ctrl.LoggerFrom(ctx).Info("skipping Helm release uninstallation: no storage namespace configured") + return nil } + // Build client getter. + getter, err := r.buildRESTClientGetter(ctx, obj) if err != nil { - // Increment failure count for deployment action. - remediation.IncrementFailureCount(&hr) - // Remediate deployment failure if necessary. - if !remediation.RetriesExhausted(hr) || remediation.MustRemediateLastFailure() { - if util.ReleaseRevision(rel) <= releaseRevision { - log.Info("skipping remediation, no new release revision created") - } else { - var remediationErr error - switch remediation.GetStrategy() { - case v2.RollbackRemediationStrategy: - rollbackErr := run.Rollback(hr) - remediationErr = r.handleHelmActionResult(ctx, &hr, revision, rollbackErr, "rollback", - v2.RemediatedCondition, v2.RollbackSucceededReason, v2.RollbackFailedReason) - case v2.UninstallRemediationStrategy: - uninstallErr := run.Uninstall(hr) - remediationErr = r.handleHelmActionResult(ctx, &hr, revision, uninstallErr, "uninstall", - v2.RemediatedCondition, v2.UninstallSucceededReason, v2.UninstallFailedReason) - } - if remediationErr != nil { - err = remediationErr - } + if apierrors.IsNotFound(err) { + // Without a Secret reference, we cannot get a REST client + // to uninstall the release. + ctrl.LoggerFrom(ctx).Error(err, "skipping Helm release uninstallation") + return nil + } + + conditions.MarkFalse(obj, meta.ReadyCondition, v2.UninstallFailedReason, + "failed to build REST client getter to uninstall release: %s", err.Error()) + return err + } + + // Confirm any ServiceAccount used for impersonation exists before + // attempting to uninstall. + // If the ServiceAccount does not exist, for example, because the + // namespace is being terminated, we should not attempt to uninstall the + // release. + if obj.Spec.KubeConfig == nil { + cfg, err := getter.ToRESTConfig() + if err != nil { + // This should never happen. + return err + } + + if serviceAccount := cfg.Impersonate.UserName; serviceAccount != "" { + i := strings.LastIndex(serviceAccount, ":") + if i != -1 { + serviceAccount = serviceAccount[i+1:] } - // Determine release after remediation. - rel, observeLastReleaseErr = run.ObserveLastRelease(hr) - if observeLastReleaseErr != nil { - err = &ConditionError{ - Reason: v2.GetLastReleaseFailedReason, - Err: errors.New("failed to get last release revision after remediation"), + if err = r.Client.Get(ctx, types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: serviceAccount, + }, &corev1.ServiceAccount{}); err != nil { + if client.IgnoreNotFound(err) == nil { + // Without a ServiceAccount reference, we cannot confirm + // the ServiceAccount exists. + ctrl.LoggerFrom(ctx).Error(err, "skipping Helm release uninstallation") + return nil } + + conditions.MarkFalse(obj, meta.ReadyCondition, v2.UninstallFailedReason, + "failed to confirm ServiceAccount '%s' can be used to uninstall release: %s", serviceAccount, err.Error()) + return err } } } - hr.Status.LastReleaseRevision = util.ReleaseRevision(rel) - if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil { - log.Error(updateStatusErr, "unable to update status after state update") - return hr, updateStatusErr + // Attempt to uninstall the release. + if err = r.reconcileUninstall(ctx, getter, obj); err != nil && !errors.Is(err, intreconcile.ErrNoLatest) { + return err + } + if err == nil { + ctrl.LoggerFrom(ctx).Info("uninstalled Helm release for deleted resource") } + // Truncate the current release details in the status. + obj.Status.ClearHistory() + obj.Status.StorageNamespace = "" + + return nil +} + +// reconcileChartTemplate reconciles the HelmChart template from the HelmRelease. +// Effectively, this means that the HelmChart resource is created, updated or +// deleted based on the state of the HelmRelease. +func (r *HelmReleaseReconciler) reconcileChartTemplate(ctx context.Context, obj *v2.HelmRelease) error { + return intreconcile.NewHelmChartTemplate(r.Client, r.EventRecorder, r.FieldManager).Reconcile(ctx, &intreconcile.Request{ + Object: obj, + }) +} + +func (r *HelmReleaseReconciler) reconcileUninstall(ctx context.Context, getter genericclioptions.RESTClientGetter, obj *v2.HelmRelease) error { + // Construct config factory for current release. + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.Status.StorageNamespace), + action.WithStorageLog(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.TraceLevel))), + ) if err != nil { - reason := v2.ReconciliationFailedReason - if condErr := (*ConditionError)(nil); errors.As(err, &condErr) { - reason = condErr.Reason - } - return v2.HelmReleaseNotReady(hr, reason, err.Error()), err + conditions.MarkFalse(obj, meta.ReadyCondition, "ConfigFactoryErr", err.Error()) + return err } - return v2.HelmReleaseReady(hr), nil + + // Run uninstall. + return intreconcile.NewUninstall(cfg, r.EventRecorder).Reconcile(ctx, &intreconcile.Request{Object: obj}) } -func (r *HelmReleaseReconciler) checkDependencies(hr v2.HelmRelease) error { - for _, d := range hr.Spec.DependsOn { - if d.Namespace == "" { - d.Namespace = hr.GetNamespace() - } - dName := types.NamespacedName{ +// checkDependencies checks if the dependencies of the given v2beta2.HelmRelease +// are Ready. +// It returns an error if a dependency can not be retrieved or is not Ready, +// otherwise nil. +func (r *HelmReleaseReconciler) checkDependencies(ctx context.Context, obj *v2.HelmRelease) error { + for _, d := range obj.Spec.DependsOn { + ref := types.NamespacedName{ Namespace: d.Namespace, Name: d.Name, } - var dHr v2.HelmRelease - err := r.Get(context.Background(), dName, &dHr) - if err != nil { - return fmt.Errorf("unable to get '%s' dependency: %w", dName, err) + if ref.Namespace == "" { + ref.Namespace = obj.GetNamespace() } - if len(dHr.Status.Conditions) == 0 || dHr.Generation != dHr.Status.ObservedGeneration { - return fmt.Errorf("dependency '%s' is not ready", dName) + dHr := &v2.HelmRelease{} + if err := r.Get(ctx, ref, dHr); err != nil { + return fmt.Errorf("unable to get '%s' dependency: %w", ref, err) } - if !apimeta.IsStatusConditionTrue(dHr.Status.Conditions, meta.ReadyCondition) { - return fmt.Errorf("dependency '%s' is not ready", dName) + if dHr.Generation != dHr.Status.ObservedGeneration || !conditions.IsTrue(dHr, meta.ReadyCondition) { + return fmt.Errorf("dependency '%s' is not ready", ref) } } return nil } -func (r *HelmReleaseReconciler) buildRESTClientGetter(ctx context.Context, hr v2.HelmRelease) (genericclioptions.RESTClientGetter, error) { +// adoptLegacyRelease attempts to adopt a v2beta1 release into a v2beta2 +// release. +// This is done by retrieving the last successful release from the Helm storage +// and converting it to a v2beta2 release snapshot. +// If the v2beta1 release has already been adopted, this function is a no-op. +func (r *HelmReleaseReconciler) adoptLegacyRelease(ctx context.Context, getter genericclioptions.RESTClientGetter, obj *v2.HelmRelease) error { + if obj.Status.LastReleaseRevision < 1 || len(obj.Status.History) > 0 { + return nil + } + + var ( + log = ctrl.LoggerFrom(ctx).V(logger.DebugLevel) + storageNamespace = obj.GetStorageNamespace() + releaseNamespace = obj.GetReleaseNamespace() + releaseName = obj.GetReleaseName() + version = obj.Status.LastReleaseRevision + ) + + log.Info("adopting %s/%s.v%d release from v2beta1 state", releaseNamespace, releaseName, version) + + // Construct config factory for current release. + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, storageNamespace), + action.WithStorageLog(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.TraceLevel))), + ) + + // Get the last successful release based on the observation for the v2beta1 + // object. + rls, err := cfg.NewStorage().Get(releaseName, version) + if err != nil { + return err + } + + // Convert it to a v2beta2 release snapshot. + snap := release.ObservedToSnapshot(release.ObserveRelease(rls)) + + // If tests are enabled, include them as well. + if obj.GetTest().Enable { + snap.SetTestHooks(release.TestHooksFromRelease(rls)) + } + + // Adopt it as the current release in the history. + obj.Status.History = append(obj.Status.History, snap) + obj.Status.StorageNamespace = storageNamespace + + // Erase the last release revision from the status. + obj.Status.LastReleaseRevision = 0 + + return nil +} + +func (r *HelmReleaseReconciler) buildRESTClientGetter(ctx context.Context, obj *v2.HelmRelease) (genericclioptions.RESTClientGetter, error) { opts := []kube.Option{ - kube.WithNamespace(hr.GetReleaseNamespace()), + kube.WithNamespace(obj.GetReleaseNamespace()), kube.WithClientOptions(r.ClientOpts), - // When ServiceAccountName is empty, it will fall back to the configured default. - // If this is not configured either, this option will result in a no-op. - kube.WithImpersonate(hr.Spec.ServiceAccountName, hr.GetNamespace()), - kube.WithPersistent(hr.UsePersistentClient()), + // When ServiceAccountName is empty, it will fall back to the configured + // default. If this is not configured either, this option will result in + // a no-op. + kube.WithImpersonate(obj.Spec.ServiceAccountName, obj.GetNamespace()), + kube.WithPersistent(obj.UsePersistentClient()), } - if hr.Spec.KubeConfig != nil { + if obj.Spec.KubeConfig != nil { secretName := types.NamespacedName{ - Namespace: hr.GetNamespace(), - Name: hr.Spec.KubeConfig.SecretRef.Name, + Namespace: obj.GetNamespace(), + Name: obj.Spec.KubeConfig.SecretRef.Name, } var secret corev1.Secret if err := r.Get(ctx, secretName, &secret); err != nil { - return nil, fmt.Errorf("could not find KubeConfig secret '%s': %w", secretName, err) + return nil, fmt.Errorf("could not get KubeConfig secret '%s': %w", secretName, err) } - kubeConfig, err := kube.ConfigFromSecret(&secret, hr.Spec.KubeConfig.SecretRef.Key, r.KubeConfigOpts) + kubeConfig, err := kube.ConfigFromSecret(&secret, obj.Spec.KubeConfig.SecretRef.Key, r.KubeConfigOpts) if err != nil { return nil, err } return kube.NewMemoryRESTClientGetter(kubeConfig, opts...), nil } - return kube.NewInClusterMemoryRESTClientGetter(opts...) -} -// composeValues attempts to resolve all v2beta1.ValuesReference resources -// and merges them as defined. Referenced resources are only retrieved once -// to ensure a single version is taken into account during the merge. -func (r *HelmReleaseReconciler) composeValues(ctx context.Context, hr v2.HelmRelease) (chartutil.Values, error) { - result := chartutil.Values{} - - configMaps := make(map[string]*corev1.ConfigMap) - secrets := make(map[string]*corev1.Secret) - - for _, v := range hr.Spec.ValuesFrom { - namespacedName := types.NamespacedName{Namespace: hr.Namespace, Name: v.Name} - var valuesData []byte - - switch v.Kind { - case "ConfigMap": - resource, ok := configMaps[namespacedName.String()] - if !ok { - // The resource may not exist, but we want to act on a single version - // of the resource in case the values reference is marked as optional. - configMaps[namespacedName.String()] = nil - - resource = &corev1.ConfigMap{} - if err := r.Get(ctx, namespacedName, resource); err != nil { - if apierrors.IsNotFound(err) { - if v.Optional { - (ctrl.LoggerFrom(ctx)). - Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName)) - continue - } - return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName) - } - return nil, err - } - configMaps[namespacedName.String()] = resource - } - if resource == nil { - if v.Optional { - (ctrl.LoggerFrom(ctx)).Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName)) - continue - } - return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName) - } - if data, ok := resource.Data[v.GetValuesKey()]; !ok { - return nil, fmt.Errorf("missing key '%s' in %s '%s'", v.GetValuesKey(), v.Kind, namespacedName) - } else { - valuesData = []byte(data) - } - case "Secret": - resource, ok := secrets[namespacedName.String()] - if !ok { - // The resource may not exist, but we want to act on a single version - // of the resource in case the values reference is marked as optional. - secrets[namespacedName.String()] = nil - - resource = &corev1.Secret{} - if err := r.Get(ctx, namespacedName, resource); err != nil { - if apierrors.IsNotFound(err) { - if v.Optional { - (ctrl.LoggerFrom(ctx)). - Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName)) - continue - } - return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName) - } - return nil, err - } - secrets[namespacedName.String()] = resource - } - if resource == nil { - if v.Optional { - (ctrl.LoggerFrom(ctx)).Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName)) - continue - } - return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName) - } - if data, ok := resource.Data[v.GetValuesKey()]; !ok { - return nil, fmt.Errorf("missing key '%s' in %s '%s'", v.GetValuesKey(), v.Kind, namespacedName) - } else { - valuesData = data - } - default: - return nil, fmt.Errorf("unsupported ValuesReference kind '%s'", v.Kind) - } - switch v.TargetPath { - case "": - values, err := chartutil.ReadValues(valuesData) - if err != nil { - return nil, fmt.Errorf("unable to read values from key '%s' in %s '%s': %w", v.GetValuesKey(), v.Kind, namespacedName, err) - } - result = transform.MergeMaps(result, values) - default: - // TODO(hidde): this is a bit of hack, as it mimics the way the option string is passed - // to Helm from a CLI perspective. Given the parser is however not publicly accessible - // while it contains all logic around parsing the target path, it is a fair trade-off. - stringValuesData := string(valuesData) - const singleQuote = "'" - const doubleQuote = "\"" - var err error - if (strings.HasPrefix(stringValuesData, singleQuote) && strings.HasSuffix(stringValuesData, singleQuote)) || (strings.HasPrefix(stringValuesData, doubleQuote) && strings.HasSuffix(stringValuesData, doubleQuote)) { - stringValuesData = strings.Trim(stringValuesData, singleQuote+doubleQuote) - singleValue := v.TargetPath + "=" + stringValuesData - err = strvals.ParseIntoString(singleValue, result) - } else { - singleValue := v.TargetPath + "=" + stringValuesData - err = strvals.ParseInto(singleValue, result) - } - if err != nil { - return nil, fmt.Errorf("unable to merge value from key '%s' in %s '%s' into target path '%s': %w", v.GetValuesKey(), v.Kind, namespacedName, v.TargetPath, err) - } - } + cfg, err := r.GetClusterConfig() + if err != nil { + return nil, fmt.Errorf("could not get in-cluster REST config: %w", err) } - return transform.MergeMaps(result, hr.GetValues()), nil + return kube.NewMemoryRESTClientGetter(cfg, opts...), nil } -// reconcileDelete deletes the v1beta2.HelmChart of the v2beta1.HelmRelease, -// and uninstalls the Helm release if the resource has not been suspended. -// It only performs a Helm uninstall if the ServiceAccount to be impersonated -// exists. -func (r *HelmReleaseReconciler) reconcileDelete(ctx context.Context, hr *v2.HelmRelease) (ctrl.Result, error) { - log := ctrl.LoggerFrom(ctx) +// getHelmChart retrieves the v1beta2.HelmChart for the given v2beta2.HelmRelease +// using the name that is advertised in the status object. +// It returns the v1beta2.HelmChart, or an error. +func (r *HelmReleaseReconciler) getHelmChart(ctx context.Context, obj *v2.HelmRelease) (*sourcev1.HelmChart, error) { + namespace, name := obj.Status.GetHelmChart() + chartRef := types.NamespacedName{Namespace: namespace, Name: name} - // Delete the HelmChart that belongs to this resource. - if err := r.deleteHelmChart(ctx, hr); err != nil { - return ctrl.Result{}, err + if err := intacl.AllowsAccessTo(obj, sourcev1.HelmChartKind, chartRef); err != nil { + return nil, err } - // Only uninstall the Helm Release if the resource is not suspended. - if !hr.Spec.Suspend { - impersonator := runtimeClient.NewImpersonator( - r.Client, - r.StatusPoller, - r.PollingOpts, - hr.Spec.KubeConfig, - r.KubeConfigOpts, - kube.DefaultServiceAccountName, - hr.Spec.ServiceAccountName, - hr.GetNamespace(), - ) - - if impersonator.CanImpersonate(ctx) { - getter, err := r.buildRESTClientGetter(ctx, *hr) - if err != nil { - return ctrl.Result{}, err - } - run, err := runner.NewRunner(getter, hr.GetStorageNamespace(), ctrl.LoggerFrom(ctx)) - if err != nil { - return ctrl.Result{}, err - } - if err := run.Uninstall(*hr); err != nil && !errors.Is(err, driver.ErrReleaseNotFound) { - return ctrl.Result{}, err - } - log.Info("uninstalled Helm release for deleted resource") - } else { - err := fmt.Errorf("failed to find service account to impersonate") - msg := "skipping Helm uninstall" - log.Error(err, msg) - r.event(ctx, *hr, hr.Status.LastAppliedRevision, eventv1.EventSeverityError, fmt.Sprintf("%s: %s", msg, err.Error())) - } - } else { - ctrl.LoggerFrom(ctx).Info("skipping Helm uninstall for suspended resource") + hc := sourcev1.HelmChart{} + if err := r.Client.Get(ctx, chartRef, &hc); err != nil { + return nil, err } - - // Remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(hr, v2.HelmReleaseFinalizer) - if err := r.Update(ctx, hr); err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func (r *HelmReleaseReconciler) handleHelmActionResult(ctx context.Context, - hr *v2.HelmRelease, revision string, err error, action string, condition string, succeededReason string, failedReason string) error { - if err != nil { - err = fmt.Errorf("Helm %s failed: %w", action, err) - msg := err.Error() - if actionErr := (*runner.ActionError)(nil); errors.As(err, &actionErr) { - msg = strings.TrimSpace(msg) + "\n\nLast Helm logs:\n\n" + actionErr.CapturedLogs - } - newCondition := metav1.Condition{ - Type: condition, - Status: metav1.ConditionFalse, - Reason: failedReason, - Message: msg, - } - apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition) - r.event(ctx, *hr, revision, eventv1.EventSeverityError, msg) - return &ConditionError{Reason: failedReason, Err: err} - } else { - msg := fmt.Sprintf("Helm %s succeeded", action) - newCondition := metav1.Condition{ - Type: condition, - Status: metav1.ConditionTrue, - Reason: succeededReason, - Message: msg, - } - apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition) - r.event(ctx, *hr, revision, eventv1.EventSeverityInfo, msg) - return nil - } -} - -func (r *HelmReleaseReconciler) patchStatus(ctx context.Context, hr *v2.HelmRelease) error { - latest := &v2.HelmRelease{} - if err := r.Client.Get(ctx, client.ObjectKeyFromObject(hr), latest); err != nil { - return err - } - patch := client.MergeFrom(latest.DeepCopy()) - latest.Status = hr.Status - return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner(r.ControllerName)) + return &hc, nil } func (r *HelmReleaseReconciler) requestsForHelmChartChange(ctx context.Context, o client.Object) []reconcile.Request { @@ -781,24 +661,3 @@ func (r *HelmReleaseReconciler) requestsForHelmChartChange(ctx context.Context, } return reqs } - -// event emits a Kubernetes event and forwards the event to notification controller if configured. -func (r *HelmReleaseReconciler) event(_ context.Context, hr v2.HelmRelease, revision, severity, msg string) { - var eventMeta map[string]string - - if revision != "" || hr.Status.LastAttemptedValuesChecksum != "" { - eventMeta = make(map[string]string) - if revision != "" { - eventMeta[v2.GroupVersion.Group+"/"+eventv1.MetaRevisionKey] = revision - } - if hr.Status.LastAttemptedValuesChecksum != "" { - eventMeta[v2.GroupVersion.Group+"/"+eventv1.MetaTokenKey] = hr.Status.LastAttemptedValuesChecksum - } - } - - eventType := corev1.EventTypeNormal - if severity == eventv1.EventSeverityError { - eventType = corev1.EventTypeWarning - } - r.EventRecorder.AnnotatedEventf(&hr, eventMeta, eventType, severity, msg) -} diff --git a/internal/controller/helmrelease_controller_chart.go b/internal/controller/helmrelease_controller_chart.go deleted file mode 100644 index 4b3ef8111..000000000 --- a/internal/controller/helmrelease_controller_chart.go +++ /dev/null @@ -1,266 +0,0 @@ -/* -Copyright 2020 The Flux authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "context" - _ "crypto/sha256" - _ "crypto/sha512" - "fmt" - "io" - "net/http" - "net/url" - "os" - "reflect" - "strings" - - "github.com/fluxcd/pkg/runtime/acl" - "github.com/hashicorp/go-retryablehttp" - "github.com/opencontainers/go-digest" - _ "github.com/opencontainers/go-digest/blake3" - "helm.sh/helm/v3/pkg/chart" - "helm.sh/helm/v3/pkg/chart/loader" - apiequality "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - - sourcev1 "github.com/fluxcd/source-controller/api/v1" - sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2" - - v2 "github.com/fluxcd/helm-controller/api/v2beta1" -) - -func (r *HelmReleaseReconciler) reconcileChart(ctx context.Context, hr *v2.HelmRelease) (*sourcev1b2.HelmChart, error) { - chartName := types.NamespacedName{ - Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace), - Name: hr.GetHelmChartName(), - } - - if r.NoCrossNamespaceRef && chartName.Namespace != hr.Namespace { - return nil, acl.AccessDeniedError(fmt.Sprintf("can't access '%s/%s', cross-namespace references have been blocked", - hr.Spec.Chart.Spec.SourceRef.Kind, types.NamespacedName{ - Namespace: hr.Spec.Chart.Spec.SourceRef.Namespace, - Name: hr.Spec.Chart.Spec.SourceRef.Name, - })) - } - - // Garbage collect the previous HelmChart if the namespace named changed. - if hr.Status.HelmChart != "" && hr.Status.HelmChart != chartName.String() { - if err := r.deleteHelmChart(ctx, hr); err != nil { - return nil, err - } - } - - // Continue with the reconciliation of the current template. - var helmChart sourcev1b2.HelmChart - err := r.Client.Get(ctx, chartName, &helmChart) - if err != nil && !apierrors.IsNotFound(err) { - return nil, err - } - hc := buildHelmChartFromTemplate(hr) - switch { - case apierrors.IsNotFound(err): - if err = r.Client.Create(ctx, hc); err != nil { - return nil, err - } - hr.Status.HelmChart = chartName.String() - return hc, nil - case helmChartRequiresUpdate(hr, &helmChart): - ctrl.LoggerFrom(ctx).Info("chart diverged from template", strings.ToLower(sourcev1b2.HelmChartKind), chartName.String()) - helmChart.Spec = hc.Spec - helmChart.Labels = hc.Labels - helmChart.Annotations = hc.Annotations - - if err = r.Client.Update(ctx, &helmChart); err != nil { - return nil, err - } - hr.Status.HelmChart = chartName.String() - } - return &helmChart, nil -} - -// loadHelmChart attempts to download the artifact from the provided source, -// loads it into a chart.Chart, and removes the downloaded artifact. -// It returns the loaded chart.Chart on success, or an error. -func (r *HelmReleaseReconciler) loadHelmChart(source *sourcev1b2.HelmChart) (*chart.Chart, error) { - artifact := source.GetArtifact() - if artifact == nil { - return nil, fmt.Errorf("cannot load chart: HelmChart '%s/%s' has no artifact", source.GetNamespace(), source.GetName()) - } - - f, err := os.CreateTemp("", fmt.Sprintf("%s-%s-*.tgz", source.GetNamespace(), source.GetName())) - if err != nil { - return nil, err - } - defer f.Close() - defer os.Remove(f.Name()) - - artifactURL := artifact.URL - if hostname := os.Getenv("SOURCE_CONTROLLER_LOCALHOST"); hostname != "" { - u, err := url.Parse(artifactURL) - if err != nil { - return nil, err - } - u.Host = hostname - artifactURL = u.String() - } - - req, err := retryablehttp.NewRequest(http.MethodGet, artifactURL, nil) - if err != nil { - return nil, fmt.Errorf("failed to create a new request: %w", err) - } - - resp, err := r.httpClient.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to download artifact, error: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("artifact '%s' download failed (status code: %s)", source.GetArtifact().URL, resp.Status) - } - - // verify checksum matches origin - if err := r.copyAndVerifyArtifact(source.GetArtifact(), resp.Body, f); err != nil { - return nil, err - } - - return loader.Load(f.Name()) -} - -func (r *HelmReleaseReconciler) copyAndVerifyArtifact(artifact *sourcev1.Artifact, reader io.Reader, writer io.Writer) error { - dig, err := digest.Parse(artifact.Digest) - if err != nil { - return fmt.Errorf("failed to verify artifact: %w", err) - } - - // Verify the downloaded artifact against the advertised digest. - verifier := dig.Verifier() - mw := io.MultiWriter(verifier, writer) - if _, err := io.Copy(mw, reader); err != nil { - return err - } - - if !verifier.Verified() { - return fmt.Errorf("failed to verify artifact: computed digest doesn't match advertised '%s'", dig) - } - return nil -} - -// deleteHelmChart deletes the v1beta2.HelmChart of the v2beta1.HelmRelease. -func (r *HelmReleaseReconciler) deleteHelmChart(ctx context.Context, hr *v2.HelmRelease) error { - if hr.Status.HelmChart == "" { - return nil - } - var hc sourcev1b2.HelmChart - chartNS, chartName := hr.Status.GetHelmChart() - err := r.Client.Get(ctx, types.NamespacedName{Namespace: chartNS, Name: chartName}, &hc) - if err != nil { - if apierrors.IsNotFound(err) { - hr.Status.HelmChart = "" - return nil - } - err = fmt.Errorf("failed to delete HelmChart '%s': %w", hr.Status.HelmChart, err) - return err - } - if err = r.Client.Delete(ctx, &hc); err != nil { - err = fmt.Errorf("failed to delete HelmChart '%s': %w", hr.Status.HelmChart, err) - return err - } - // Truncate the chart reference in the status object. - hr.Status.HelmChart = "" - return nil -} - -// buildHelmChartFromTemplate builds a v1beta2.HelmChart from the -// v2beta1.HelmChartTemplate of the given v2beta1.HelmRelease. -func buildHelmChartFromTemplate(hr *v2.HelmRelease) *sourcev1b2.HelmChart { - template := hr.Spec.Chart - result := &sourcev1b2.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: hr.GetHelmChartName(), - Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace), - }, - Spec: sourcev1b2.HelmChartSpec{ - Chart: template.Spec.Chart, - Version: template.Spec.Version, - SourceRef: sourcev1b2.LocalHelmChartSourceReference{ - Name: template.Spec.SourceRef.Name, - Kind: template.Spec.SourceRef.Kind, - }, - Interval: template.GetInterval(hr.Spec.Interval), - ReconcileStrategy: template.Spec.ReconcileStrategy, - ValuesFiles: template.Spec.ValuesFiles, - ValuesFile: template.Spec.ValuesFile, - Verify: templateVerificationToSourceVerification(template.Spec.Verify), - }, - } - if hr.Spec.Chart.ObjectMeta != nil { - result.ObjectMeta.Labels = hr.Spec.Chart.ObjectMeta.Labels - result.ObjectMeta.Annotations = hr.Spec.Chart.ObjectMeta.Annotations - } - return result -} - -// helmChartRequiresUpdate compares the v2beta1.HelmChartTemplate of the -// v2beta1.HelmRelease to the given v1beta2.HelmChart to determine if an -// update is required. -func helmChartRequiresUpdate(hr *v2.HelmRelease, chart *sourcev1b2.HelmChart) bool { - template := hr.Spec.Chart - switch { - case template.Spec.Chart != chart.Spec.Chart: - return true - // TODO(hidde): remove emptiness checks on next MINOR version - case template.Spec.Version == "" && chart.Spec.Version != "*", - template.Spec.Version != "" && template.Spec.Version != chart.Spec.Version: - return true - case template.Spec.SourceRef.Name != chart.Spec.SourceRef.Name: - return true - case template.Spec.SourceRef.Kind != chart.Spec.SourceRef.Kind: - return true - case template.GetInterval(hr.Spec.Interval) != chart.Spec.Interval: - return true - case template.Spec.ReconcileStrategy != chart.Spec.ReconcileStrategy: - return true - case !reflect.DeepEqual(template.Spec.ValuesFiles, chart.Spec.ValuesFiles): - return true - case template.Spec.ValuesFile != chart.Spec.ValuesFile: - return true - case template.ObjectMeta != nil && !apiequality.Semantic.DeepEqual(template.ObjectMeta.Annotations, chart.Annotations): - return true - case template.ObjectMeta != nil && !apiequality.Semantic.DeepEqual(template.ObjectMeta.Labels, chart.Labels): - return true - case !reflect.DeepEqual(templateVerificationToSourceVerification(template.Spec.Verify), chart.Spec.Verify): - return true - default: - return false - } -} - -// templateVerificationToSourceVerification converts the HelmChartTemplateVerification to the OCIRepositoryVerification. -func templateVerificationToSourceVerification(template *v2.HelmChartTemplateVerification) *sourcev1b2.OCIRepositoryVerification { - if template == nil { - return nil - } - - return &sourcev1b2.OCIRepositoryVerification{ - Provider: template.Provider, - SecretRef: template.SecretRef, - } -} diff --git a/internal/controller/helmrelease_controller_chart_test.go b/internal/controller/helmrelease_controller_chart_test.go deleted file mode 100644 index 75094fce2..000000000 --- a/internal/controller/helmrelease_controller_chart_test.go +++ /dev/null @@ -1,543 +0,0 @@ -/* -Copyright 2020 The Flux authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/fluxcd/pkg/apis/meta" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" - "github.com/go-logr/logr" - . "github.com/onsi/gomega" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - v2 "github.com/fluxcd/helm-controller/api/v2beta1" -) - -func TestHelmReleaseReconciler_reconcileChart(t *testing.T) { - tests := []struct { - name string - hr *v2.HelmRelease - hc *sourcev1.HelmChart - expectHelmChartStatus string - expectGC bool - expectErr bool - noCrossNamspaceRef bool - }{ - { - name: "new HelmChart", - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - Namespace: "default", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - }, - }, - }, - }, - hc: nil, - expectHelmChartStatus: "default/default-test-release", - }, - { - name: "existing HelmChart", - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - Namespace: "default", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - }, - }, - }, - }, - hc: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "default", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - }, - }, - expectHelmChartStatus: "default/default-test-release", - }, - { - name: "modified HelmChart", - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - Namespace: "default", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - Namespace: "cross", - }, - }, - }, - }, - Status: v2.HelmReleaseStatus{ - HelmChart: "default/default-test-release", - }, - }, - hc: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "default", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - }, - }, - expectHelmChartStatus: "cross/default-test-release", - expectGC: true, - }, - { - name: "block cross namespace access when flag is set", - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - Namespace: "default", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - Namespace: "cross", - }, - }, - }, - }, - Status: v2.HelmReleaseStatus{ - HelmChart: "", - }, - }, - noCrossNamspaceRef: true, - expectErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - g.Expect(v2.AddToScheme(scheme.Scheme)).To(Succeed()) - g.Expect(sourcev1.AddToScheme(scheme.Scheme)).To(Succeed()) - - c := fake.NewClientBuilder().WithScheme(scheme.Scheme) - if tt.hc != nil { - c.WithObjects(tt.hc) - } - - r := &HelmReleaseReconciler{ - Client: c.Build(), - NoCrossNamespaceRef: tt.noCrossNamspaceRef, - } - - hc, err := r.reconcileChart(logr.NewContext(context.TODO(), logr.Discard()), tt.hr) - if tt.expectErr { - g.Expect(err).To(HaveOccurred()) - g.Expect(hc).To(BeNil()) - } else { - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(hc).NotTo(BeNil()) - } - - g.Expect(tt.hr.Status.HelmChart).To(Equal(tt.expectHelmChartStatus)) - - if tt.expectGC { - objKey := client.ObjectKeyFromObject(tt.hc) - err = r.Get(context.TODO(), objKey, tt.hc.DeepCopy()) - g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) - } - }) - } -} - -func TestHelmReleaseReconciler_deleteHelmChart(t *testing.T) { - tests := []struct { - name string - hc *sourcev1.HelmChart - hr *v2.HelmRelease - expectHelmChartStatus string - expectErr bool - }{ - { - name: "delete existing HelmChart", - hc: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-chart", - Namespace: "default", - }, - }, - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - }, - Status: v2.HelmReleaseStatus{ - HelmChart: "default/test-chart", - }, - }, - expectHelmChartStatus: "", - expectErr: false, - }, - { - name: "delete already removed HelmChart", - hc: nil, - hr: &v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - }, - Status: v2.HelmReleaseStatus{ - HelmChart: "default/test-chart", - }, - }, - expectHelmChartStatus: "", - expectErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - g.Expect(v2.AddToScheme(scheme.Scheme)).To(Succeed()) - g.Expect(sourcev1.AddToScheme(scheme.Scheme)).To(Succeed()) - - c := fake.NewClientBuilder().WithScheme(scheme.Scheme) - if tt.hc != nil { - c.WithObjects(tt.hc) - } - - r := &HelmReleaseReconciler{ - Client: c.Build(), - } - - err := r.deleteHelmChart(context.TODO(), tt.hr) - if tt.expectErr { - g.Expect(err).To(HaveOccurred()) - } else { - g.Expect(err).NotTo(HaveOccurred()) - } - g.Expect(tt.hr.Status.HelmChart).To(Equal(tt.expectHelmChartStatus)) - }) - } -} - -func Test_buildHelmChartFromTemplate(t *testing.T) { - hrWithChartTemplate := v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - Namespace: "default", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: &metav1.Duration{Duration: 2 * time.Minute}, - ValuesFiles: []string{"values.yaml"}, - }, - }, - }, - } - - tests := []struct { - name string - modify func(release *v2.HelmRelease) - want *sourcev1.HelmChart - }{ - { - name: "builds HelmChart from HelmChartTemplate", - modify: func(*v2.HelmRelease) {}, - want: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "default", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: metav1.Duration{Duration: 2 * time.Minute}, - ValuesFiles: []string{"values.yaml"}, - }, - }, - }, - { - name: "takes SourceRef namespace into account", - modify: func(hr *v2.HelmRelease) { - hr.Spec.Chart.Spec.SourceRef.Namespace = "cross" - }, - want: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "cross", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: metav1.Duration{Duration: 2 * time.Minute}, - ValuesFiles: []string{"values.yaml"}, - }, - }, - }, - { - name: "falls back to HelmRelease interval", - modify: func(hr *v2.HelmRelease) { - hr.Spec.Chart.Spec.Interval = nil - }, - want: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "default", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: metav1.Duration{Duration: time.Minute}, - ValuesFiles: []string{"values.yaml"}, - }, - }, - }, - { - name: "take cosign verification into account", - modify: func(hr *v2.HelmRelease) { - hr.Spec.Chart.Spec.Verify = &v2.HelmChartTemplateVerification{ - Provider: "cosign", - SecretRef: &meta.LocalObjectReference{ - Name: "cosign-key", - }, - } - }, - want: &sourcev1.HelmChart{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default-test-release", - Namespace: "default", - }, - Spec: sourcev1.HelmChartSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: sourcev1.LocalHelmChartSourceReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: metav1.Duration{Duration: 2 * time.Minute}, - ValuesFiles: []string{"values.yaml"}, - Verify: &sourcev1.OCIRepositoryVerification{ - Provider: "cosign", - SecretRef: &meta.LocalObjectReference{ - Name: "cosign-key", - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - hr := hrWithChartTemplate.DeepCopy() - tt.modify(hr) - g.Expect(buildHelmChartFromTemplate(hr)).To(Equal(tt.want)) - }) - } -} - -func Test_helmChartRequiresUpdate(t *testing.T) { - hrWithChartTemplate := v2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-release", - }, - Spec: v2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: time.Minute}, - Chart: v2.HelmChartTemplate{ - Spec: v2.HelmChartTemplateSpec{ - Chart: "chart", - Version: "1.0.0", - SourceRef: v2.CrossNamespaceObjectReference{ - Name: "test-repository", - Kind: "HelmRepository", - }, - Interval: &metav1.Duration{Duration: 2 * time.Minute}, - Verify: &v2.HelmChartTemplateVerification{ - Provider: "cosign", - }, - }, - }, - }, - } - - tests := []struct { - name string - modify func(*v2.HelmRelease, *sourcev1.HelmChart) - want bool - }{ - { - name: "detects no change", - modify: func(*v2.HelmRelease, *sourcev1.HelmChart) {}, - want: false, - }, - { - name: "detects chart change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.Chart = "new" - }, - want: true, - }, - { - name: "detects version change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.Version = "2.0.0" - }, - want: true, - }, - { - name: "detects chart source name change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.SourceRef.Name = "new" - }, - want: true, - }, - { - name: "detects chart source kind change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.SourceRef.Kind = "GitRepository" - }, - want: true, - }, - { - name: "detects interval change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.Interval = nil - }, - want: true, - }, - { - name: "detects reconcile strategy change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.ReconcileStrategy = "Revision" - }, - want: true, - }, - { - name: "detects values files change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.ValuesFiles = []string{"values-prod.yaml"} - }, - want: true, - }, - { - name: "detects values file change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.ValuesFile = "values-prod.yaml" - }, - want: true, - }, - { - name: "detects verify change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.Spec.Verify.Provider = "foo-bar" - }, - want: true, - }, - { - name: "detects labels change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.ObjectMeta = &v2.HelmChartTemplateObjectMeta{Labels: map[string]string{"foo": "bar"}} - }, - want: true, - }, - { - name: "detects annotations change", - modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) { - hr.Spec.Chart.ObjectMeta = &v2.HelmChartTemplateObjectMeta{Annotations: map[string]string{"foo": "bar"}} - }, - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - hr := hrWithChartTemplate.DeepCopy() - hc := buildHelmChartFromTemplate(hr) - // second copy to avoid modifying the original - hr = hrWithChartTemplate.DeepCopy() - g.Expect(helmChartRequiresUpdate(hr, hc)).To(Equal(false)) - - tt.modify(hr, hc) - fmt.Println("verify", hr.Spec.Chart.Spec.Verify.Provider, hc.Spec.Verify.Provider) - g.Expect(helmChartRequiresUpdate(hr, hc)).To(Equal(tt.want)) - }) - } -} diff --git a/internal/controller/helmrelease_controller_fuzz_test.go b/internal/controller/helmrelease_controller_fuzz_test.go index 165969689..cff926d69 100644 --- a/internal/controller/helmrelease_controller_fuzz_test.go +++ b/internal/controller/helmrelease_controller_fuzz_test.go @@ -32,148 +32,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/yaml" - v2 "github.com/fluxcd/helm-controller/api/v2beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" -) - -func FuzzHelmReleaseReconciler_composeValues(f *testing.F) { - scheme := testScheme() - tests := []struct { - targetPath string - valuesKey string - hrValues string - createObject bool - secretData []byte - configData string - }{ - { - targetPath: "flat", - valuesKey: "custom-values.yaml", - secretData: []byte(`flat: - nested: value -nested: value -`), - configData: `flat: value -nested: - configuration: value -`, - hrValues: ` -other: values -`, - createObject: true, - }, - { - targetPath: "'flat'", - valuesKey: "custom-values.yaml", - secretData: []byte(`flat: - nested: value -nested: value -`), - configData: `flat: value -nested: - configuration: value -`, - hrValues: ` -other: values -`, - createObject: true, - }, - { - targetPath: "flat[0]", - secretData: []byte(``), - configData: `flat: value`, - hrValues: ` -other: values -`, - createObject: true, - }, - { - secretData: []byte(`flat: - nested: value -nested: value -`), - configData: `flat: value -nested: - configuration: value -`, - hrValues: ` -other: values -`, - createObject: true, - }, - { - targetPath: "some-value", - hrValues: ` -other: values -`, - createObject: false, - }, - } - - for _, tt := range tests { - f.Add(tt.targetPath, tt.valuesKey, tt.hrValues, tt.createObject, tt.secretData, tt.configData) - } - - f.Fuzz(func(t *testing.T, - targetPath, valuesKey, hrValues string, createObject bool, secretData []byte, configData string) { - - // objectName represents a core Kubernetes name (Secret/ConfigMap) which is validated - // upstream, and also validated by us in the OpenAPI-based validation set in - // v2.ValuesReference. Therefore a static value here suffices, and instead we just - // play with the objects presence/absence. - objectName := "values" - var resources []client.Object - - if createObject { - resources = append(resources, - valuesConfigMap(objectName, map[string]string{valuesKey: configData}), - valuesSecret(objectName, map[string][]byte{valuesKey: secretData}), - ) - } - - references := []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: objectName, - ValuesKey: valuesKey, - TargetPath: targetPath, - }, - { - Kind: "Secret", - Name: objectName, - ValuesKey: valuesKey, - TargetPath: targetPath, - }, - } - - c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(resources...).Build() - r := &HelmReleaseReconciler{Client: c} - var values *apiextensionsv1.JSON - if hrValues != "" { - v, _ := yaml.YAMLToJSON([]byte(hrValues)) - values = &apiextensionsv1.JSON{Raw: v} - } - - hr := v2.HelmRelease{ - Spec: v2.HelmReleaseSpec{ - ValuesFrom: references, - Values: values, - }, - } - - // OpenAPI-based validation on schema is not verified here. - // Therefore some false positives may be arise, as the apiserver - // would not allow such values to make their way into the control plane. - // - // Testenv could be used so the fuzzing covers the entire E2E. - // The downsize being the resource and time cost per test would be a lot higher. - // - // Another approach could be to add validation to reject invalid inputs before - // the r.composeValues call. - _, _ = r.composeValues(logr.NewContext(context.TODO(), logr.Discard()), hr) - }) -} + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) func FuzzHelmReleaseReconciler_reconcile(f *testing.F) { scheme := testScheme() diff --git a/internal/controller/helmrelease_controller_test.go b/internal/controller/helmrelease_controller_test.go index dd3bb167b..ce5d7c782 100644 --- a/internal/controller/helmrelease_controller_test.go +++ b/internal/controller/helmrelease_controller_test.go @@ -18,264 +18,1914 @@ package controller import ( "context" - "reflect" + "errors" "strings" "testing" "time" - "github.com/go-logr/logr" - "helm.sh/helm/v3/pkg/chartutil" + "github.com/hashicorp/go-retryablehttp" + . "github.com/onsi/gomega" + "github.com/opencontainers/go-digest" + helmrelease "helm.sh/helm/v3/pkg/release" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/yaml" - v2 "github.com/fluxcd/helm-controller/api/v2beta1" + "github.com/fluxcd/pkg/apis/acl" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + feathelper "github.com/fluxcd/pkg/runtime/features" + "github.com/fluxcd/pkg/runtime/patch" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + intacl "github.com/fluxcd/helm-controller/internal/acl" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/features" + "github.com/fluxcd/helm-controller/internal/kube" + intreconcile "github.com/fluxcd/helm-controller/internal/reconcile" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/testutil" ) -func TestHelmReleaseReconciler_composeValues(t *testing.T) { - scheme := runtime.NewScheme() - _ = corev1.AddToScheme(scheme) - _ = v2.AddToScheme(scheme) +func TestHelmReleaseReconciler_reconcileRelease(t *testing.T) { + t.Run("confirms dependencies are ready", func(t *testing.T) { + g := NewWithT(t) + + dependency := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependency", + Namespace: "mock", + Generation: 1, + }, + Status: v2.HelmReleaseStatus{ + Conditions: []metav1.Condition{ + { + Type: meta.StalledCondition, + Status: metav1.ConditionTrue, + }, + }, + ObservedGeneration: 1, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency", + }, + }, + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(dependency, obj). + Build(), + EventRecorder: record.NewFakeRecorder(32), + requeueDependency: 5 * time.Second, + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.RequeueAfter).To(Equal(r.requeueDependency)) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, meta.DependencyNotReadyReason, "dependency 'mock/dependency' is not ready"), + })) + }) + + t.Run("handles HelmChart get failure", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(obj). + Build(), + } + + _, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).To(HaveOccurred()) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "Fulfilling prerequisites"), + *conditions.FalseCondition(meta.ReadyCondition, v2.ArtifactFailedReason, "could not get HelmChart object"), + })) + }) + + t.Run("handles ACL error for HelmChart", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "other/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(obj). + Build(), + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(errors.Is(err, reconcile.TerminalError(nil))).To(BeTrue()) + g.Expect(res.IsZero()).To(BeTrue()) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.StalledCondition, acl.AccessDeniedReason, "cross-namespace references are not allowed"), + *conditions.FalseCondition(meta.ReadyCondition, acl.AccessDeniedReason, "cross-namespace references are not allowed"), + })) + }) + + t.Run("waits for HelmChart to be ready", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 2, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 2, + Artifact: &sourcev1.Artifact{}, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionFalse, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Second}, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build(), + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.RequeueAfter).To(Equal(obj.Spec.Interval.Duration)) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, "HelmChartNotReady", "HelmChart 'mock/chart' is not ready"), + })) + }) + + t.Run("waits for HelmChart ObservedGeneration to equal Generation", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 2, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: &sourcev1.Artifact{}, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Second}, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build(), + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.RequeueAfter).To(Equal(obj.Spec.Interval.Duration)) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, "HelmChartNotReady", "HelmChart 'mock/chart' is not ready"), + })) + }) + + t.Run("confirms HelmChart has an Artifact", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 2, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 2, + Artifact: nil, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Second}, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build(), + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.RequeueAfter).To(Equal(obj.Spec.Interval.Duration)) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, "HelmChartNotReady", "HelmChart 'mock/chart' is not ready"), + })) + }) + + t.Run("reports values composition failure", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 2, + }, + Spec: sourcev1b2.HelmChartSpec{ + Interval: metav1.Duration{Duration: 1 * time.Second}, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 2, + Artifact: &sourcev1.Artifact{}, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + ValuesFrom: []v2.ValuesReference{ + { + Kind: "Secret", + Name: "missing", + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build(), + } + + _, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).To(HaveOccurred()) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "Fulfilling prerequisites"), + *conditions.FalseCondition(meta.ReadyCondition, "ValuesError", "could not resolve Secret chart values reference 'mock/missing' with key 'values.yaml'"), + })) + }) + + t.Run("reports Helm chart load failure", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 1, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: &sourcev1.Artifact{ + URL: testServer.URL() + "/does-not-exist", + }, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + }, + } + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build(), + httpClient: retryablehttp.NewClient(), + requeueDependency: 10 * time.Second, + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.RequeueAfter).To(Equal(r.requeueDependency)) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, v2.ArtifactFailedReason, "Chart not ready"), + })) + }) + + t.Run("attempts to adopt v2beta1 release state", func(t *testing.T) { + g := NewWithT(t) + + // Initialize feature gates. + g.Expect((&feathelper.FeatureGates{}).SupportedFeatures(features.FeatureGates())).To(Succeed()) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "adopt-release") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Create HelmChart mock. + chartMock := testutil.BuildChart() + chartArtifact, err := testutil.SaveChartAsArtifact(chartMock, digest.SHA256, testServer.URL(), testServer.Root()) + g.Expect(err).ToNot(HaveOccurred()) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "adopt-release", + Namespace: ns.Name, + Generation: 1, + }, + Spec: sourcev1b2.HelmChartSpec{ + Chart: "testdata/test-helmrepo", + Version: "0.1.0", + SourceRef: sourcev1b2.LocalHelmChartSourceReference{ + Kind: sourcev1b2.HelmRepositoryKind, + Name: "reconcile-delete", + }, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: chartArtifact, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + // Create a test Helm release storage mock. + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "adopt-release", + Namespace: ns.Name, + Version: 1, + Chart: chartMock, + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(nil)) + valChecksum := chartutil.DigestValues("sha1", rls.Config) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "adopt-release", + Namespace: ns.Name, + }, + Spec: v2.HelmReleaseSpec{ + StorageNamespace: ns.Name, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: chart.Namespace + "/" + chart.Name, + LastReleaseRevision: rls.Version, + LastAttemptedValuesChecksum: valChecksum.Hex(), + }, + } + + c := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build() + + r := &HelmReleaseReconciler{ + Client: c, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + httpClient: retryablehttp.NewClient(), + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.GetStorageNamespace())) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + g.Expect(store.Create(rls)).To(Succeed()) + + // Reconcile the Helm release. + _, err = r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, r.Client), obj) + g.Expect(err).ToNot(HaveOccurred()) + + // Assert that the Helm release has been adopted. + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + })) + g.Expect(obj.Status.StorageNamespace).To(Equal(ns.Name)) + g.Expect(obj.Status.LastAttemptedConfigDigest).ToNot(BeEmpty()) + g.Expect(obj.Status.LastReleaseRevision).To(Equal(0)) + }) + + t.Run("uninstalls HelmRelease if target has changed", func(t *testing.T) { + g := NewWithT(t) + + chartMock := testutil.BuildChart() + chartArtifact, err := testutil.SaveChartAsArtifact(chartMock, digest.SHA256, testServer.URL(), testServer.Root()) + g.Expect(err).ToNot(HaveOccurred()) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 1, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: chartArtifact, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + }, + Spec: v2.HelmReleaseSpec{ + StorageNamespace: "other", + }, + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: "mock", + Namespace: "mock", + }, + }, + HelmChart: "mock/chart", + StorageNamespace: "mock", + }, + } + + c := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build() + + r := &HelmReleaseReconciler{ + Client: c, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + httpClient: retryablehttp.NewClient(), + } + + res, err := r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, c), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, ""), + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallSucceededReason, "Release mock/mock.v0 was not found, assuming it is uninstalled"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, "Release mock/mock.v0 was not found, assuming it is uninstalled"), + })) + + // Verify history and storage namespace are cleared. + g.Expect(obj.Status.History).To(BeNil()) + g.Expect(obj.Status.StorageNamespace).To(BeEmpty()) + }) + + t.Run("resets failure counts on configuration change", func(t *testing.T) { + g := NewWithT(t) + + chartMock := testutil.BuildChart() + chartArtifact, err := testutil.SaveChartAsArtifact(chartMock, digest.SHA256, testServer.URL(), testServer.Root()) + g.Expect(err).ToNot(HaveOccurred()) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 1, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: chartArtifact, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + Generation: 2, + }, + Spec: v2.HelmReleaseSpec{ + // Trigger a failure by setting an invalid storage namespace, + // preventing the release from actually being installed. + // This allows us to just test the failure count reset, without + // having to facilitate a full install. + StorageNamespace: "not-exist", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + InstallFailures: 2, + UpgradeFailures: 3, + Failures: 5, + // Trigger actual failure reset due to change in spec. + LastAttemptedGeneration: 1, + }, + } + + c := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build() + + r := &HelmReleaseReconciler{ + Client: c, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + httpClient: retryablehttp.NewClient(), + } + + _, err = r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, c), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("namespaces \"not-exist\" not found")) + + // Verify failure counts are reset. + g.Expect(obj.Status.InstallFailures).To(Equal(int64(0))) + g.Expect(obj.Status.UpgradeFailures).To(Equal(int64(0))) + g.Expect(obj.Status.Failures).To(Equal(int64(1))) + }) + + t.Run("sets last attempted values", func(t *testing.T) { + g := NewWithT(t) + + chartMock := testutil.BuildChart() + chartArtifact, err := testutil.SaveChartAsArtifact(chartMock, digest.SHA256, testServer.URL(), testServer.Root()) + g.Expect(err).ToNot(HaveOccurred()) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "chart", + Namespace: "mock", + Generation: 1, + }, + Status: sourcev1b2.HelmChartStatus{ + ObservedGeneration: 1, + Artifact: chartArtifact, + Conditions: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "mock", + Generation: 2, + }, + Spec: v2.HelmReleaseSpec{ + // Trigger a failure by setting an invalid storage namespace, + // preventing the release from actually being installed. + // This allows us to just test the values being set, without + // having to facilitate a full install. + StorageNamespace: "not-exist", + Values: &apiextensionsv1.JSON{ + Raw: []byte(`{"foo":"bar"}`), + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "mock/chart", + ObservedGeneration: 2, + // Confirm deprecated value is cleared. + LastAttemptedValuesChecksum: "b5cbcf5c23cfd945d2cdf0ffaab387a46f2d054f", + }, + } + + c := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithStatusSubresource(&v2.HelmRelease{}). + WithObjects(chart, obj). + Build() + + r := &HelmReleaseReconciler{ + Client: c, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + httpClient: retryablehttp.NewClient(), + } + + _, err = r.reconcileRelease(context.TODO(), patch.NewSerialPatcher(obj, c), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("namespaces \"not-exist\" not found")) + + // Verify attempted values are set. + g.Expect(obj.Status.LastAttemptedGeneration).To(Equal(obj.Generation)) + g.Expect(obj.Status.LastAttemptedRevision).To(Equal(chartMock.Metadata.Version)) + g.Expect(obj.Status.LastAttemptedConfigDigest).To(Equal("sha256:1dabc4e3cbbd6a0818bd460f3a6c9855bfe95d506c74726bc0f2edb0aecb1f4e")) + g.Expect(obj.Status.LastAttemptedValuesChecksum).To(BeEmpty()) + }) +} + +func TestHelmReleaseReconciler_reconcileDelete(t *testing.T) { + t.Run("uninstalls Helm release and removes chart", func(t *testing.T) { + g := NewWithT(t) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "reconcile-delete") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Create HelmChart mock. + hc := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: ns.Name, + }, + Spec: sourcev1b2.HelmChartSpec{ + Chart: "testdata/test-helmrepo", + Version: "0.1.0", + SourceRef: sourcev1b2.LocalHelmChartSourceReference{ + Kind: sourcev1b2.HelmRepositoryKind, + Name: "reconcile-delete", + }, + }, + } + g.Expect(testEnv.Create(context.TODO(), hc)).To(Succeed()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), hc) + }) + + // Create a test Helm release storage mock. + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "reconcile-delete", + Namespace: ns.Name, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: ns.Name, + Finalizers: []string{v2.HelmReleaseFinalizer}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: ns.Name, + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + }, + HelmChart: hc.Namespace + "/" + hc.Name, + }, + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.Status.StorageNamespace)) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + g.Expect(store.Create(rls)).To(Succeed()) + + // Reconcile the actual deletion of the Helm release. + res, err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.IsZero()).To(BeTrue()) + + // Verify Helm release has been uninstalled. + _, err = store.History(rls.Name) + g.Expect(err).To(MatchError(helmdriver.ErrReleaseNotFound)) + + // Verify Helm chart has been removed. + err = testEnv.Get(context.TODO(), client.ObjectKey{ + Namespace: hc.Namespace, + Name: hc.Name, + }, &sourcev1b2.HelmChart{}) + g.Expect(err).To(HaveOccurred()) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }) + + t.Run("removes finalizer for suspended resource with DeletionTimestamp", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Finalizers: []string{v2.HelmReleaseFinalizer, "other-finalizer"}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v2.HelmReleaseSpec{ + Suspend: true, + }, + } + + res, err := (&HelmReleaseReconciler{}).reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.IsZero()).To(BeTrue()) + + g.Expect(obj.GetFinalizers()).To(ConsistOf("other-finalizer")) + }) + + t.Run("does not remove finalizer when DeletionTimestamp is not set", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Finalizers: []string{v2.HelmReleaseFinalizer}, + }, + Spec: v2.HelmReleaseSpec{ + Suspend: true, + }, + } + + res, err := (&HelmReleaseReconciler{}).reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + + g.Expect(obj.GetFinalizers()).To(ConsistOf(v2.HelmReleaseFinalizer)) + }) +} + +func TestHelmReleaseReconciler_reconileReleaseDeletion(t *testing.T) { + t.Run("uninstalls Helm release", func(t *testing.T) { + g := NewWithT(t) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "reconcile-release-deletion") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Create a test Helm release storage mock. + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "reconcile-delete", + Namespace: ns.Name, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: ns.Name, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: ns.Name, + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + }, + }, + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + EventRecorder: record.NewFakeRecorder(32), + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.Status.StorageNamespace)) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + g.Expect(store.Create(rls)).To(Succeed()) + + // Reconcile the actual deletion of the Helm release. + err = r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + // Verify status of Helm release has been updated. + g.Expect(obj.Status.StorageNamespace).To(BeEmpty()) + g.Expect(obj.Status.History).To(BeNil()) + + // Verify Helm release has been uninstalled. + _, err = store.History(rls.Name) + g.Expect(err).To(MatchError(helmdriver.ErrReleaseNotFound)) + }) + + t.Run("skip uninstalling Helm release when KubeConfig Secret is missing", func(t *testing.T) { + g := NewWithT(t) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "reconcile-release-deletion") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Create a test Helm release storage mock. + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "reconcile-delete", + Namespace: ns.Name, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: ns.Name, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: ns.Name, + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + }, + }, + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.Status.StorageNamespace)) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + g.Expect(store.Create(rls)).To(Succeed()) + + // Reconcile the actual deletion of the Helm release. + obj.Spec.KubeConfig = &meta.KubeConfigReference{ + SecretRef: meta.SecretKeyReference{ + Name: "missing-secret", + }, + } + err = r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + // Verify status of Helm release has not been updated. + g.Expect(obj.Status.StorageNamespace).ToNot(BeEmpty()) + g.Expect(obj.Status.History.Latest()).ToNot(BeNil()) + + // Verify Helm release has not been uninstalled. + _, err = store.History(rls.Name) + g.Expect(err).ToNot(HaveOccurred()) + }) + + t.Run("error when REST client getter construction fails", func(t *testing.T) { + g := NewWithT(t) + + mockErr := errors.New("mock error") + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: func() (*rest.Config, error) { + return nil, mockErr + }, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: "mock", + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: "mock", + }, + } + + // Reconcile the actual deletion of the Helm release. + err := r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(errors.Is(err, mockErr)).To(BeTrue()) + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + "failed to build REST client getter to uninstall release"), + })) + + // Verify status of Helm release has not been updated. + g.Expect(obj.Status.StorageNamespace).ToNot(BeEmpty()) + }) + + t.Run("skip uninstalling Helm release when ServiceAccount is missing", func(t *testing.T) { + g := NewWithT(t) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "reconcile-release-deletion") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Create a test Helm release storage mock. + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "reconcile-delete", + Namespace: ns.Name, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: ns.Name, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: ns.Name, + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + }, + }, + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.Status.StorageNamespace)) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + g.Expect(store.Create(rls)).To(Succeed()) + + // Reconcile the actual deletion of the Helm release. + obj.Spec.ServiceAccountName = "missing-sa" + err = r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + // Verify status of Helm release has not been updated. + g.Expect(obj.Status.StorageNamespace).ToNot(BeEmpty()) + g.Expect(obj.Status.History.Latest()).ToNot(BeNil()) + + // Verify Helm release has not been uninstalled. + _, err = store.History(rls.Name) + g.Expect(err).ToNot(HaveOccurred()) + }) + + t.Run("error when ServiceAccount existence check fails", func(t *testing.T) { + g := NewWithT(t) + + var ( + serviceAccount = "missing-sa" + namespace = "mock" + mockErr = errors.New("mock error") + ) + + c := fake.NewClientBuilder().WithInterceptorFuncs(interceptor.Funcs{ + Get: func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if key.Name == serviceAccount && key.Namespace == namespace { + return mockErr + } + return client.Get(ctx, key, obj, opts...) + }, + }) + + r := &HelmReleaseReconciler{ + Client: c.Build(), + GetClusterConfig: GetTestClusterConfig, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: namespace, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v2.HelmReleaseSpec{ + ServiceAccountName: serviceAccount, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: namespace, + }, + } + + // Reconcile the actual deletion of the Helm release. + err := r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(errors.Is(err, mockErr)).To(BeTrue()) + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + "failed to confirm ServiceAccount '%s' can be used to uninstall release", serviceAccount), + })) + + // Verify status of Helm release has not been updated. + g.Expect(obj.Status.StorageNamespace).ToNot(BeEmpty()) + }) + + t.Run("error when Helm release uninstallation fails", func(t *testing.T) { + g := NewWithT(t) + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: func() (*rest.Config, error) { + return &rest.Config{ + Host: "https://failing-mock.local", + }, nil + }, + EventRecorder: record.NewFakeRecorder(32), + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: "mock", + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: "mock", + History: v2.Snapshots{ + {}, + }, + }, + } + + err := r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, "Kubernetes cluster unreachable"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, "Kubernetes cluster unreachable"), + })) + }) + + t.Run("ignores ErrNoLatest when uninstalling Helm release", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: "mock", + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Status: v2.HelmReleaseStatus{ + StorageNamespace: "mock", + }, + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + } + + // Reconcile the actual deletion of the Helm release. + err := r.reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + // Verify status of Helm release been updated. + g.Expect(obj.Status.StorageNamespace).To(BeEmpty()) + }) + + t.Run("error when DeletionTimestamp is not set", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: "mock", + }, + } + + err := (&HelmReleaseReconciler{}).reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("deletion timestamp is not set")) + }) + + t.Run("skip uninstalling Helm release when StorageNamespace is missing", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reconcile-delete", + Namespace: "mock", + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + } + + err := (&HelmReleaseReconciler{}).reconcileReleaseDeletion(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + }) +} + +func TestHelmReleaseReconciler_reconcileChartTemplate(t *testing.T) { + t.Run("attempts to reconcile chart template", func(t *testing.T) { + g := NewWithT(t) + + r := &HelmReleaseReconciler{ + Client: fake.NewClientBuilder().WithScheme(NewTestScheme()).Build(), + EventRecorder: record.NewFakeRecorder(32), + } + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + StorageNamespace: "default", + }, + } + + // We do not care about the result of the reconcile, only that it was attempted. + err := r.reconcileChartTemplate(context.TODO(), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("failed to run server-side apply")) + }) +} + +func TestHelmReleaseReconciler_reconcileUninstall(t *testing.T) { + t.Run("attempts to uninstall release", func(t *testing.T) { + g := NewWithT(t) + + getter := kube.NewMemoryRESTClientGetter(testEnv.GetConfig()) + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + StorageNamespace: "default", + }, + } + + // We do not care about the result of the uninstall, only that it was attempted. + err := (&HelmReleaseReconciler{}).reconcileUninstall(context.TODO(), getter, obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(errors.Is(err, intreconcile.ErrNoLatest)).To(BeTrue()) + }) + + t.Run("error on empty storage namespace", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + StorageNamespace: "", + }, + } + + err := (&HelmReleaseReconciler{}).reconcileUninstall(context.TODO(), nil, obj) + g.Expect(err).To(HaveOccurred()) + + g.Expect(conditions.IsFalse(obj, meta.ReadyCondition)).To(BeTrue()) + g.Expect(conditions.GetReason(obj, meta.ReadyCondition)).To(Equal("ConfigFactoryErr")) + g.Expect(conditions.GetMessage(obj, meta.ReadyCondition)).To(ContainSubstring("no namespace provided")) + g.Expect(obj.GetConditions()).To(HaveLen(1)) + }) +} +func TestHelmReleaseReconciler_checkDependencies(t *testing.T) { tests := []struct { - name string - resources []client.Object - references []v2.ValuesReference - values string - want chartutil.Values - wantErr bool + name string + obj *v2.HelmRelease + objects []client.Object + expect func(g *WithT, err error) }{ { - name: "merges", - resources: []client.Object{ - valuesConfigMap("values", map[string]string{ - "values.yaml": `flat: value -nested: - configuration: value -`, - }), - valuesSecret("values", map[string][]byte{ - "values.yaml": []byte(`flat: - nested: value -nested: value -`), - }), - }, - references: []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: "values", + name: "all dependencies ready", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "some-namespace", }, - { - Kind: "Secret", - Name: "values", + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency-1", + }, + { + Name: "dependency-2", + Namespace: "some-other-namespace", + }, + }, }, }, - values: ` -other: values -`, - want: chartutil.Values{ - "flat": map[string]interface{}{ - "nested": "value", + objects: []client.Object{ + &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + Name: "dependency-1", + Namespace: "some-namespace", + }, + Status: v2.HelmReleaseStatus{ + ObservedGeneration: 1, + Conditions: []metav1.Condition{ + {Type: meta.ReadyCondition, Status: metav1.ConditionTrue}, + }, + }, + }, + &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 2, + Name: "dependency-2", + Namespace: "some-other-namespace", + }, + Status: v2.HelmReleaseStatus{ + ObservedGeneration: 2, + Conditions: []metav1.Condition{ + {Type: meta.ReadyCondition, Status: metav1.ConditionTrue}, + }, + }, }, - "nested": "value", - "other": "values", + }, + expect: func(g *WithT, err error) { + g.Expect(err).ToNot(HaveOccurred()) }, }, { - name: "target path", - resources: []client.Object{ - valuesSecret("values", map[string][]byte{"single": []byte("value")}), - }, - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "values", - ValuesKey: "single", - TargetPath: "merge.at.specific.path", + name: "error on dependency with ObservedGeneration < Generation", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "some-namespace", + }, + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency-1", + }, + }, }, }, - want: chartutil.Values{ - "merge": map[string]interface{}{ - "at": map[string]interface{}{ - "specific": map[string]interface{}{ - "path": "value", + objects: []client.Object{ + &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 2, + Name: "dependency-1", + Namespace: "some-namespace", + }, + Status: v2.HelmReleaseStatus{ + ObservedGeneration: 1, + Conditions: []metav1.Condition{ + {Type: meta.ReadyCondition, Status: metav1.ConditionTrue}, }, }, }, }, + expect: func(g *WithT, err error) { + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("is not ready")) + }, }, { - name: "target path with boolean value", - resources: []client.Object{ - valuesSecret("values", map[string][]byte{"single": []byte("true")}), - }, - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "values", - ValuesKey: "single", - TargetPath: "merge.at.specific.path", + name: "error on dependency with ObservedGeneration = Generation and ReadyCondition = False", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "some-namespace", + }, + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency-1", + }, + }, }, }, - want: chartutil.Values{ - "merge": map[string]interface{}{ - "at": map[string]interface{}{ - "specific": map[string]interface{}{ - "path": true, + objects: []client.Object{ + &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + Name: "dependency-1", + Namespace: "some-namespace", + }, + Status: v2.HelmReleaseStatus{ + ObservedGeneration: 1, + Conditions: []metav1.Condition{ + {Type: meta.ReadyCondition, Status: metav1.ConditionFalse}, }, }, }, }, + expect: func(g *WithT, err error) { + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("is not ready")) + }, }, { - name: "target path with set-string behavior", - resources: []client.Object{ - valuesSecret("values", map[string][]byte{"single": []byte("\"true\"")}), + name: "error on dependency without conditions", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "some-namespace", + }, + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency-1", + }, + }, + }, }, - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "values", - ValuesKey: "single", - TargetPath: "merge.at.specific.path", + objects: []client.Object{ + &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + Name: "dependency-1", + Namespace: "some-namespace", + }, + Status: v2.HelmReleaseStatus{ + ObservedGeneration: 1, + }, }, }, - want: chartutil.Values{ - "merge": map[string]interface{}{ - "at": map[string]interface{}{ - "specific": map[string]interface{}{ - "path": "true", + expect: func(g *WithT, err error) { + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("is not ready")) + }, + }, + { + name: "error on missing dependency", + obj: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dependant", + Namespace: "some-namespace", + }, + Spec: v2.HelmReleaseSpec{ + DependsOn: []meta.NamespacedObjectReference{ + { + Name: "dependency-1", }, }, }, }, + expect: func(g *WithT, err error) { + g.Expect(err).To(HaveOccurred()) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }, }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + c := fake.NewClientBuilder().WithScheme(NewTestScheme()) + if len(tt.objects) > 0 { + c.WithObjects(tt.objects...) + } + + r := &HelmReleaseReconciler{ + Client: c.Build(), + } + + err := r.checkDependencies(context.TODO(), tt.obj) + tt.expect(g, err) + }) + } +} + +func TestHelmReleaseReconciler_adoptLegacyRelease(t *testing.T) { + tests := []struct { + name string + releases func(namespace string) []*helmrelease.Release + spec func(spec *v2.HelmReleaseSpec) + status v2.HelmReleaseStatus + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + expectLastReleaseRevision int + wantErr bool + }{ { - name: "values reference to non existing secret", - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "missing", - }, + name: "adopts last release revision", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "orphaned", + Namespace: namespace, + Version: 6, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithTestHook()), + } }, - wantErr: true, + spec: func(spec *v2.HelmReleaseSpec) { + spec.ReleaseName = "orphaned" + }, + status: v2.HelmReleaseStatus{ + LastReleaseRevision: 6, + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectLastReleaseRevision: 0, }, { - name: "optional values reference to non existing secret", - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "missing", - Optional: true, - }, + name: "includes test hooks if enabled", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "orphaned-with-hooks", + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithTestHook()), + } }, - want: chartutil.Values{}, - wantErr: false, + spec: func(spec *v2.HelmReleaseSpec) { + spec.ReleaseName = "orphaned-with-hooks" + spec.Test = &v2.Test{ + Enable: true, + } + }, + status: v2.HelmReleaseStatus{ + LastReleaseRevision: 3, + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + snap := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + snap.SetTestHooks(release.TestHooksFromRelease(releases[0])) + + return v2.Snapshots{ + snap, + } + }, + expectLastReleaseRevision: 0, }, { - name: "values reference to non existing config map", - references: []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: "missing", - }, + name: "non-existing release", + spec: func(spec *v2.HelmReleaseSpec) { + spec.ReleaseName = "non-existing" }, - wantErr: true, + status: v2.HelmReleaseStatus{ + LastReleaseRevision: 2, + }, + expectLastReleaseRevision: 2, + wantErr: true, }, { - name: "optional values reference to non existing config map", - references: []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: "missing", - Optional: true, - }, + name: "without last release revision", + status: v2.HelmReleaseStatus{ + LastReleaseRevision: 0, }, - want: chartutil.Values{}, - wantErr: false, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return nil + }, + expectLastReleaseRevision: 0, }, { - name: "missing secret key", - resources: []client.Object{ - valuesSecret("values", nil), + name: "with existing history", + status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: "something", + }, + }, + LastReleaseRevision: 5, }, - references: []v2.ValuesReference{ - { - Kind: "Secret", - Name: "values", - ValuesKey: "nonexisting", + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + { + Name: "something", + }, + } + }, + expectLastReleaseRevision: 5, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + // Create a test namespace for storing the Helm release mock. + ns, err := testEnv.CreateNamespace(context.TODO(), "adopt-release") + g.Expect(err).ToNot(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), ns) + }) + + // Mock a HelmRelease object. + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + StorageNamespace: ns.Name, }, + Status: tt.status, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + + r := &HelmReleaseReconciler{ + Client: testEnv.Client, + GetClusterConfig: GetTestClusterConfig, + } + + // Store the Helm release mock in the test namespace. + getter, err := r.buildRESTClientGetter(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, action.WithStorage(helmdriver.SecretsDriverName, obj.GetStorageNamespace())) + g.Expect(err).ToNot(HaveOccurred()) + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(ns.Name) + } + store := helmstorage.Init(cfg.Driver) + for _, rls := range releases { + g.Expect(store.Create(rls)).To(Succeed()) + } + + // Adopt the Helm release mock. + err = r.adoptLegacyRelease(context.TODO(), getter, obj) + g.Expect(err != nil).To(Equal(tt.wantErr), "unexpected error: %s", err) + + // Verify the Helm release mock has been adopted. + var expectHistory v2.Snapshots + if tt.expectHistory != nil { + expectHistory = tt.expectHistory(releases) + } + g.Expect(obj.Status.History).To(Equal(expectHistory)) + g.Expect(obj.Status.LastReleaseRevision).To(Equal(tt.expectLastReleaseRevision)) + }) + } +} + +func TestHelmReleaseReconciler_buildRESTClientGetter(t *testing.T) { + const ( + namespace = "some-namespace" + kubeCfg = `apiVersion: v1 +kind: Config +clusters: +- cluster: + insecure-skip-tls-verify: true + server: https://1.2.3.4 + name: development +contexts: +- context: + cluster: development + namespace: frontend + user: developer + name: dev-frontend +current-context: dev-frontend +preferences: {} +users: +- name: developer + user: + password: some-password + username: exp` + ) + + tests := []struct { + name string + env map[string]string + getConfig func() (*rest.Config, error) + spec v2.HelmReleaseSpec + secret *corev1.Secret + want genericclioptions.RESTClientGetter + wantErr string + }{ + { + name: "builds in-cluster RESTClientGetter for HelmRelease", + getConfig: func() (*rest.Config, error) { + return clientcmd.RESTConfigFromKubeConfig([]byte(kubeCfg)) }, - wantErr: true, + spec: v2.HelmReleaseSpec{}, + want: &kube.MemoryRESTClientGetter{}, }, { - name: "missing config map key", - resources: []client.Object{ - valuesConfigMap("values", nil), + name: "returns error when in-cluster GetClusterConfig fails", + getConfig: func() (*rest.Config, error) { + return nil, errors.New("some-error") }, - references: []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: "values", - ValuesKey: "nonexisting", + wantErr: "some-error", + }, + { + name: "builds RESTClientGetter from HelmRelease with KubeConfig", + spec: v2.HelmReleaseSpec{ + KubeConfig: &meta.KubeConfigReference{ + SecretRef: meta.SecretKeyReference{ + Name: "kubeconfig", + }, }, }, - wantErr: true, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubeconfig", + Namespace: namespace, + }, + Data: map[string][]byte{ + kube.DefaultKubeConfigSecretKey: []byte(kubeCfg), + }, + }, + want: &kube.MemoryRESTClientGetter{}, }, { - name: "unsupported values reference kind", - references: []v2.ValuesReference{ - { - Kind: "Unsupported", + name: "error on missing KubeConfig secret", + spec: v2.HelmReleaseSpec{ + KubeConfig: &meta.KubeConfigReference{ + SecretRef: meta.SecretKeyReference{ + Name: "kubeconfig", + }, }, }, - wantErr: true, + wantErr: "could not get KubeConfig secret", }, { - name: "invalid values", - resources: []client.Object{ - valuesConfigMap("values", map[string]string{ - "values.yaml": ` -invalid`, - }), + name: "error on invalid KubeConfig secret", + spec: v2.HelmReleaseSpec{ + KubeConfig: &meta.KubeConfigReference{ + SecretRef: meta.SecretKeyReference{ + Name: "kubeconfig", + Key: "invalid-key", + }, + }, }, - references: []v2.ValuesReference{ - { - Kind: "ConfigMap", - Name: "values", + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubeconfig", + Namespace: namespace, }, }, - wantErr: true, + wantErr: "does not contain a 'invalid-key' key", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.resources...).Build() - r := &HelmReleaseReconciler{Client: c} - var values *apiextensionsv1.JSON - if tt.values != "" { - v, _ := yaml.YAMLToJSON([]byte(tt.values)) - values = &apiextensionsv1.JSON{Raw: v} + g := NewWithT(t) + + for k, v := range tt.env { + t.Setenv(k, v) } - hr := v2.HelmRelease{ - Spec: v2.HelmReleaseSpec{ - ValuesFrom: tt.references, - Values: values, + + c := fake.NewClientBuilder() + if tt.secret != nil { + c.WithObjects(tt.secret) + } + + r := &HelmReleaseReconciler{ + Client: c.Build(), + GetClusterConfig: tt.getConfig, + } + + getter, err := r.buildRESTClientGetter(context.Background(), &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "some-name", + Namespace: namespace, }, + Spec: tt.spec, + }) + if len(tt.wantErr) > 0 { + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring(tt.wantErr)) + } else { + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(getter).To(BeAssignableToTypeOf(tt.want)) } - got, err := r.composeValues(logr.NewContext(context.TODO(), logr.Discard()), hr) - if (err != nil) != tt.wantErr { - t.Errorf("composeValues() error = %v, wantErr %v", err, tt.wantErr) + }) + } +} + +func TestHelmReleaseReconciler_getHelmChart(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1b2.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "some-namespace", + Name: "some-chart-name", + }, + } + + tests := []struct { + name string + rel *v2.HelmRelease + chart *sourcev1b2.HelmChart + expectChart bool + wantErr bool + disallowCrossNS bool + }{ + { + name: "retrieves HelmChart object from Status", + rel: &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + HelmChart: "some-namespace/some-chart-name", + }, + }, + chart: chart, + expectChart: true, + }, + { + name: "no HelmChart found", + rel: &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + HelmChart: "some-namespace/some-chart-name", + }, + }, + chart: nil, + expectChart: false, + wantErr: true, + }, + { + name: "no HelmChart in Status", + rel: &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + HelmChart: "", + }, + }, + chart: chart, + expectChart: false, + wantErr: true, + }, + { + name: "ACL disallows cross namespace", + rel: &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "some-namespace/some-chart-name", + }, + }, + chart: chart, + expectChart: false, + wantErr: true, + disallowCrossNS: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := fake.NewClientBuilder() + c.WithScheme(NewTestScheme()) + if tt.chart != nil { + c.WithObjects(tt.chart) + } + + r := &HelmReleaseReconciler{ + Client: c.Build(), + EventRecorder: record.NewFakeRecorder(32), + } + + curAllow := intacl.AllowCrossNamespaceRef + intacl.AllowCrossNamespaceRef = !tt.disallowCrossNS + t.Cleanup(func() { intacl.AllowCrossNamespaceRef = !curAllow }) + + got, err := r.getHelmChart(context.TODO(), tt.rel) + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + g.Expect(got).To(BeNil()) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("composeValues() got = %v, want %v", got, tt.want) + g.Expect(err).ToNot(HaveOccurred()) + expect := g.Expect(got.ObjectMeta) + if tt.expectChart { + expect.To(BeEquivalentTo(tt.chart.ObjectMeta)) + } else { + expect.To(BeNil()) } }) } @@ -427,6 +2077,7 @@ func TestValuesReferenceValidation(t *testing.T) { Interval: metav1.Duration{Duration: 5 * time.Minute}, Chart: v2.HelmChartTemplate{ Spec: v2.HelmChartTemplateSpec{ + Chart: "mychart", SourceRef: v2.CrossNamespaceObjectReference{ Name: "something", }, @@ -437,7 +2088,7 @@ func TestValuesReferenceValidation(t *testing.T) { }, } - err := k8sClient.Create(context.TODO(), &hr, client.DryRunAll) + err := testEnv.Create(context.TODO(), &hr, client.DryRunAll) if (err != nil) != tt.wantErr { t.Errorf("composeValues() error = %v, wantErr %v", err, tt.wantErr) return @@ -445,17 +2096,3 @@ func TestValuesReferenceValidation(t *testing.T) { }) } } - -func valuesSecret(name string, data map[string][]byte) *corev1.Secret { - return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - Data: data, - } -} - -func valuesConfigMap(name string, data map[string]string) *corev1.ConfigMap { - return &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - Data: data, - } -} diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 764d29787..427007e3d 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -22,43 +22,78 @@ import ( "path/filepath" "testing" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" + ctrl "sigs.k8s.io/controller-runtime" - "github.com/fluxcd/helm-controller/api/v2beta1" + "github.com/fluxcd/pkg/runtime/testenv" + "github.com/fluxcd/pkg/testserver" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" // +kubebuilder:scaffold:imports ) -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment +var ( + testEnv *testenv.Environment + testServer *testserver.HTTPServer + + testCtx = ctrl.SetupSignalHandler() +) + +func NewTestScheme() *runtime.Scheme { + s := runtime.NewScheme() + utilruntime.Must(corev1.AddToScheme(s)) + utilruntime.Must(apiextensionsv1.AddToScheme(s)) + utilruntime.Must(sourcev1.AddToScheme(s)) + utilruntime.Must(v2.AddToScheme(s)) + return s +} func TestMain(m *testing.M) { - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - } + testEnv = testenv.New( + testenv.WithCRDPath( + filepath.Join("..", "..", "build", "config", "crd", "bases"), + filepath.Join("..", "..", "config", "crd", "bases"), + ), + testenv.WithScheme(NewTestScheme()), + ) var err error - cfg, err = testEnv.Start() - if err != nil { - panic(fmt.Errorf("failed to start testenv: %v", err)) + if testServer, err = testserver.NewTempHTTPServer(); err != nil { + panic(fmt.Sprintf("Failed to create a temporary storage server: %v", err)) } + fmt.Println("Starting the test storage server") + testServer.Start() - utilruntime.Must(v2beta1.AddToScheme(scheme.Scheme)) - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - if err != nil { - panic(fmt.Errorf("failed to create k8s client: %v", err)) - } + go func() { + fmt.Println("Starting the test environment") + if err := testEnv.Start(testCtx); err != nil { + panic(fmt.Sprintf("Failed to start the test environment manager: %v", err)) + } + }() + <-testEnv.Manager.Elected() code := m.Run() - err = testEnv.Stop() - if err != nil { - panic(fmt.Errorf("failed to stop testenv: %v", err)) + fmt.Println("Stopping the test environment") + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop the test environment: %v", err)) + } + + fmt.Println("Stopping the test storage server") + testServer.Stop() + if err := os.RemoveAll(testServer.Root()); err != nil { + panic(fmt.Sprintf("Failed to remove storage server dir: %v", err)) } os.Exit(code) } + +// GetTestClusterConfig returns a copy of the test cluster config. +func GetTestClusterConfig() (*rest.Config, error) { + return rest.CopyConfig(testEnv.GetConfig()), nil +} diff --git a/internal/diff/differ.go b/internal/diff/differ.go index 9359fa3f6..d97d15774 100644 --- a/internal/diff/differ.go +++ b/internal/diff/differ.go @@ -21,25 +21,22 @@ import ( "fmt" "strings" - "github.com/fluxcd/pkg/runtime/client" - "github.com/fluxcd/pkg/ssa" - "github.com/google/go-cmp/cmp" "helm.sh/helm/v3/pkg/release" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/errors" ctrl "sigs.k8s.io/controller-runtime" + "github.com/fluxcd/pkg/runtime/client" "github.com/fluxcd/pkg/runtime/logger" + "github.com/fluxcd/pkg/ssa" - helmv1 "github.com/fluxcd/helm-controller/api/v2beta1" - intcmp "github.com/fluxcd/helm-controller/internal/cmp" + v2 "github.com/fluxcd/helm-controller/api/v2beta2" "github.com/fluxcd/helm-controller/internal/util" ) var ( // MetadataKey is the label or annotation key used to disable the diffing // of an object. - MetadataKey = helmv1.GroupVersion.Group + "/driftDetection" + MetadataKey = v2.GroupVersion.Group + "/driftDetection" // MetadataDisabledValue is the value used to disable the diffing of an // object using MetadataKey. MetadataDisabledValue = "disabled" @@ -132,12 +129,8 @@ func (d *Differ) Diff(ctx context.Context, rel *release.Release) (*ssa.ChangeSet if entry.Action == ssa.ConfiguredAction { // TODO: remove this once we have a better way to log the diff // for example using a custom dyff reporter, or a flux CLI command - r := intcmp.SimpleUnstructuredReporter{} - if diff := cmp.Diff( - unstructuredWithoutStatus(releaseObject).UnstructuredContent(), - unstructuredWithoutStatus(clusterObject).UnstructuredContent(), - cmp.Reporter(&r)); diff != "" { - ctrl.LoggerFrom(ctx).V(logger.DebugLevel).Info(entry.Subject + " diff:\n" + r.String()) + if d, equal := Unstructured(releaseObject, clusterObject, WithoutStatus()); !equal { + ctrl.LoggerFrom(ctx).V(logger.DebugLevel).Info(entry.Subject + " diff:\n" + d) } } case ssa.SkippedAction: @@ -151,9 +144,3 @@ func (d *Differ) Diff(ctx context.Context, rel *release.Release) (*ssa.ChangeSet } return changeSet, diff, err } - -func unstructuredWithoutStatus(obj *unstructured.Unstructured) *unstructured.Unstructured { - obj = obj.DeepCopy() - delete(obj.Object, "status") - return obj -} diff --git a/internal/diff/unstructured.go b/internal/diff/unstructured.go new file mode 100644 index 000000000..a61ed04db --- /dev/null +++ b/internal/diff/unstructured.go @@ -0,0 +1,54 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package diff + +import ( + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + intcmp "github.com/fluxcd/helm-controller/internal/cmp" +) + +// CompareOption is a function that modifies the unstructured object before +// comparing. +type CompareOption func(u *unstructured.Unstructured) + +// WithoutStatus removes the status field from the unstructured object +// before comparing. +func WithoutStatus() CompareOption { + return func(u *unstructured.Unstructured) { + delete(u.Object, "status") + } +} + +// Unstructured compares two unstructured objects and returns a diff and +// a bool indicating whether the objects are equal. +func Unstructured(x, y *unstructured.Unstructured, opts ...CompareOption) (string, bool) { + if len(opts) > 0 { + x = x.DeepCopy() + y = y.DeepCopy() + } + + for _, opt := range opts { + opt(x) + opt(y) + } + + r := intcmp.SimpleUnstructuredReporter{} + _ = cmp.Diff(x.UnstructuredContent(), y.UnstructuredContent(), cmp.Reporter(&r)) + return r.String(), r.String() == "" +} diff --git a/internal/diff/unstructured_test.go b/internal/diff/unstructured_test.go new file mode 100644 index 000000000..8c0d42868 --- /dev/null +++ b/internal/diff/unstructured_test.go @@ -0,0 +1,162 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package diff + +import ( + "testing" + + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +func TestWithoutStatus(t *testing.T) { + g := NewWithT(t) + + u := unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": "test", + }, + } + WithoutStatus()(&u) + g.Expect(u.Object["status"]).To(BeNil()) +} + +func TestUnstructured(t *testing.T) { + tests := []struct { + name string + x *unstructured.Unstructured + y *unstructured.Unstructured + opts []CompareOption + want string + equal bool + }{ + { + name: "equal objects", + x: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(4), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(4), + }, + }}, + y: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(4), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(4), + }, + }}, + want: "", + equal: true, + }, + { + name: "added simple value", + x: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(1), + }, + "status": map[string]interface{}{}, + }}, + y: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(1), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(1), + }, + }}, + want: `.status.readyReplicas ++1`, + equal: false, + }, + { + name: "removed simple value", + x: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(1), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(4), + }, + }}, + y: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{}, + "status": map[string]interface{}{ + "readyReplicas": int64(4), + }, + }}, + want: `.spec.replicas +-1`, + equal: false, + }, + { + name: "changed simple value", + x: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(3), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(1), + }, + }}, + y: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(3), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(3), + }, + }}, + want: `.status.readyReplicas +-1 ++3`, + equal: false, + }, + { + name: "with options", + opts: []CompareOption{WithoutStatus()}, + x: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(3), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(4), + }, + }}, + y: &unstructured.Unstructured{Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": int64(3), + }, + "status": map[string]interface{}{ + "readyReplicas": int64(1), + }, + }}, + equal: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got, equal := Unstructured(tt.x, tt.y, tt.opts...) + g.Expect(got).To(Equal(tt.want)) + g.Expect(equal).To(Equal(tt.equal)) + }) + } +} diff --git a/internal/digest/digest.go b/internal/digest/digest.go new file mode 100644 index 000000000..1be1e9388 --- /dev/null +++ b/internal/digest/digest.go @@ -0,0 +1,41 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package digest + +import ( + "crypto" + _ "crypto/sha256" + _ "crypto/sha512" + + "github.com/opencontainers/go-digest" + _ "github.com/opencontainers/go-digest/blake3" +) + +const ( + SHA1 digest.Algorithm = "sha1" +) + +var ( + // Canonical is the primary digest algorithm used to calculate checksums + // for e.g. Helm release objects and config values. + Canonical = digest.SHA256 +) + +func init() { + // Register SHA-1 algorithm for support of legacy values checksums. + digest.RegisterAlgorithm(SHA1, crypto.SHA1) +} diff --git a/internal/errors/is.go b/internal/errors/is.go new file mode 100644 index 000000000..f2bfb09d0 --- /dev/null +++ b/internal/errors/is.go @@ -0,0 +1,29 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package errors + +import "errors" + +// IsOneOf returns true if err is equal to any of the errs. +func IsOneOf(err error, errs ...error) bool { + for _, e := range errs { + if errors.Is(err, e) { + return true + } + } + return false +} diff --git a/internal/errors/is_test.go b/internal/errors/is_test.go new file mode 100644 index 000000000..a3a358be7 --- /dev/null +++ b/internal/errors/is_test.go @@ -0,0 +1,40 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package errors + +import ( + "errors" + "testing" +) + +func TestIsOneOf(t *testing.T) { + err1 := errors.New("error1") + err2 := errors.New("error2") + + if !IsOneOf(err1, err1, err2) { + t.Errorf("Expected IsOneOf to return true when the error is in the list, but got false") + } + + err3 := errors.New("error3") + if IsOneOf(err3, err1, err2) { + t.Errorf("Expected IsOneOf to return false when the error is not in the list, but got true") + } + + if IsOneOf(err1) { + t.Errorf("Expected IsOneOf to return false with an empty list of errors, but got true") + } +} diff --git a/internal/features/features.go b/internal/features/features.go index 43e7a4425..4d39cad0f 100644 --- a/internal/features/features.go +++ b/internal/features/features.go @@ -47,6 +47,13 @@ const ( // OOMWatch enables the OOM watcher, which will gracefully shut down the controller // when the memory usage exceeds the configured limit. This is disabled by default. OOMWatch = "OOMWatch" + + // AdoptLegacyReleases enables the adoption of the historical Helm release + // based on the status fields from a v2beta1 HelmRelease object. + // This is enabled by default to support an upgrade path from v2beta1 to v2beta2 + // without the need to upgrade the Helm release. But it can be disabled to + // avoid potential abuse of the adoption mechanism. + AdoptLegacyReleases = "AdoptLegacyReleases" ) var features = map[string]bool{ @@ -65,6 +72,9 @@ var features = map[string]bool{ // OOMWatch // opt-in from v0.31 OOMWatch: false, + // AdoptLegacyReleases + // opt-out from v0.37 + AdoptLegacyReleases: true, } // FeatureGates contains a list of all supported feature gates and diff --git a/internal/loader/artifact_url.go b/internal/loader/artifact_url.go new file mode 100644 index 000000000..6b76416a4 --- /dev/null +++ b/internal/loader/artifact_url.go @@ -0,0 +1,96 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package loader + +import ( + "bytes" + _ "crypto/sha256" + _ "crypto/sha512" + "errors" + "fmt" + "io" + "net/http" + + "github.com/hashicorp/go-retryablehttp" + digestlib "github.com/opencontainers/go-digest" + _ "github.com/opencontainers/go-digest/blake3" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" +) + +var ( + // ErrFileNotFound is an error type used to signal 404 HTTP status code responses. + ErrFileNotFound = errors.New("file not found") + // ErrIntegrity signals a chart loader failed to verify the integrity of + // a chart, for example due to a digest mismatch. + ErrIntegrity = errors.New("integrity failure") +) + +// SecureLoadChartFromURL attempts to download a Helm chart from the given URL +// using the provided client. The retrieved data is verified against the given +// digest before loading the chart. It returns the loaded chart.Chart, or an +// error. The error may be of type ErrIntegrity if the integrity check fails. +func SecureLoadChartFromURL(client *retryablehttp.Client, URL, digest string) (*chart.Chart, error) { + req, err := retryablehttp.NewRequest(http.MethodGet, URL, nil) + if err != nil { + return nil, err + } + + resp, err := client.Do(req) + if err != nil || resp != nil && resp.StatusCode != http.StatusOK { + if err != nil { + return nil, err + } + _ = resp.Body.Close() + if resp.StatusCode == http.StatusNotFound { + return nil, fmt.Errorf("failed to download chart from '%s': %w", URL, ErrFileNotFound) + } + return nil, fmt.Errorf("failed to download chart from '%s' (status: %s)", URL, resp.Status) + } + + var c bytes.Buffer + if err := copyAndVerify(digest, resp.Body, &c); err != nil { + _ = resp.Body.Close() + return nil, err + } + + if err := resp.Body.Close(); err != nil { + return nil, err + } + return loader.LoadArchive(&c) +} + +// copyAndVerify copies the contents of reader to writer, and verifies the +// integrity of the data using the given digest. It returns an error if the +// integrity check fails. +func copyAndVerify(digest string, reader io.Reader, writer io.Writer) error { + dig, err := digestlib.Parse(digest) + if err != nil { + return fmt.Errorf("failed to parse digest '%s': %w", digest, err) + } + + verifier := dig.Verifier() + mw := io.MultiWriter(verifier, writer) + if _, err := io.Copy(mw, reader); err != nil { + return fmt.Errorf("failed to copy and verify chart artifact: %w", err) + } + + if !verifier.Verified() { + return fmt.Errorf("%w: computed digest doesn't match '%s'", ErrIntegrity, dig) + } + return nil +} diff --git a/internal/loader/artifact_url_test.go b/internal/loader/artifact_url_test.go new file mode 100644 index 000000000..20f60ac22 --- /dev/null +++ b/internal/loader/artifact_url_test.go @@ -0,0 +1,164 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package loader + +import ( + "bytes" + "errors" + "io" + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/hashicorp/go-retryablehttp" + . "github.com/onsi/gomega" + digestlib "github.com/opencontainers/go-digest" +) + +func TestSecureLoadChartFromURL(t *testing.T) { + g := NewWithT(t) + + b, err := os.ReadFile("testdata/chart-0.1.0.tgz") + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(b).ToNot(BeNil()) + digest := digestlib.SHA256.FromBytes(b) + + const chartPath = "/chart.tgz" + const notFoundPath = "/not-found.tgz" + server := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + if req.URL.Path == chartPath { + res.WriteHeader(http.StatusOK) + _, _ = res.Write(b) + return + } + if req.URL.Path == notFoundPath { + res.WriteHeader(http.StatusNotFound) + return + } + res.WriteHeader(http.StatusInternalServerError) + })) + t.Cleanup(func() { + server.Close() + }) + + chartURL := server.URL + chartPath + + client := retryablehttp.NewClient() + client.Logger = nil + client.RetryMax = 2 + + t.Run("loads Helm chart from URL", func(t *testing.T) { + g := NewWithT(t) + + got, err := SecureLoadChartFromURL(client, chartURL, digest.String()) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).ToNot(BeNil()) + g.Expect(got.Name()).To(Equal("chart")) + g.Expect(got.Metadata.Version).To(Equal("0.1.0")) + }) + + t.Run("error on chart data digest mismatch", func(t *testing.T) { + g := NewWithT(t) + + got, err := SecureLoadChartFromURL(client, chartURL, digestlib.SHA256.FromString("invalid").String()) + g.Expect(err).To(HaveOccurred()) + g.Expect(errors.Is(err, ErrIntegrity)).To(BeTrue()) + g.Expect(got).To(BeNil()) + }) + + t.Run("file not found error on 404", func(t *testing.T) { + g := NewWithT(t) + + got, err := SecureLoadChartFromURL(client, server.URL+notFoundPath, digest.String()) + g.Expect(errors.Is(err, ErrFileNotFound)).To(BeTrue()) + g.Expect(got).To(BeNil()) + }) + + t.Run("error on HTTP request failure", func(t *testing.T) { + g := NewWithT(t) + + got, err := SecureLoadChartFromURL(client, server.URL+"/invalid.tgz", digest.String()) + g.Expect(err).To(HaveOccurred()) + g.Expect(errors.Is(err, ErrFileNotFound)).To(BeFalse()) + g.Expect(got).To(BeNil()) + }) +} + +func Test_copyAndVerify(t *testing.T) { + g := NewWithT(t) + + tmpDir := t.TempDir() + closedF, err := os.CreateTemp(tmpDir, "closed.txt") + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(closedF.Close()).ToNot(HaveOccurred()) + + tests := []struct { + name string + digest string + in io.Reader + out io.Writer + wantErr bool + }{ + { + name: "digest match (SHA256)", + digest: digestlib.SHA256.FromString("foo").String(), + in: bytes.NewReader([]byte("foo")), + out: bytes.NewBuffer(nil), + }, + { + name: "digest match (SHA384)", + digest: digestlib.SHA384.FromString("foo").String(), + in: bytes.NewReader([]byte("foo")), + out: bytes.NewBuffer(nil), + }, + { + name: "digest match (SHA512)", + digest: digestlib.SHA512.FromString("foo").String(), + in: bytes.NewReader([]byte("foo")), + out: bytes.NewBuffer(nil), + }, + { + name: "digest match (BLAKE3)", + digest: digestlib.BLAKE3.FromString("foo").String(), + in: bytes.NewReader([]byte("foo")), + out: bytes.NewBuffer(nil), + }, + { + name: "digest mismatch", + digest: digestlib.SHA256.FromString("foo").String(), + in: bytes.NewReader([]byte("bar")), + out: io.Discard, + wantErr: true, + }, + { + name: "copy failure (closed file)", + digest: digestlib.SHA256.FromString("foo").String(), + in: bytes.NewReader([]byte("foo")), + out: closedF, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + err := copyAndVerify(tt.digest, tt.in, tt.out) + g.Expect(err != nil).To(Equal(tt.wantErr), err) + }) + } +} diff --git a/internal/loader/testdata/chart-0.1.0.tgz b/internal/loader/testdata/chart-0.1.0.tgz new file mode 100644 index 000000000..b5dca7618 Binary files /dev/null and b/internal/loader/testdata/chart-0.1.0.tgz differ diff --git a/internal/postrender/build.go b/internal/postrender/build.go new file mode 100644 index 000000000..5dc419af3 --- /dev/null +++ b/internal/postrender/build.go @@ -0,0 +1,47 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package postrender + +import ( + helmpostrender "helm.sh/helm/v3/pkg/postrender" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +// BuildPostRenderers creates the post-renderer instances from a HelmRelease +// and combines them into a single Combined post renderer. +func BuildPostRenderers(rel *v2.HelmRelease) helmpostrender.PostRenderer { + if rel == nil { + return nil + } + renderers := make([]helmpostrender.PostRenderer, 0) + for _, r := range rel.Spec.PostRenderers { + if r.Kustomize != nil { + renderers = append(renderers, &Kustomize{ + Patches: r.Kustomize.Patches, + PatchesStrategicMerge: r.Kustomize.PatchesStrategicMerge, + PatchesJSON6902: r.Kustomize.PatchesJSON6902, + Images: r.Kustomize.Images, + }) + } + } + renderers = append(renderers, NewOriginLabels(v2.GroupVersion.Group, rel.Namespace, rel.Name)) + if len(renderers) == 0 { + return nil + } + return NewCombined(renderers...) +} diff --git a/internal/runner/post_renderer.go b/internal/postrender/combined.go similarity index 56% rename from internal/runner/post_renderer.go rename to internal/postrender/combined.go index 45ad3c501..c25947437 100644 --- a/internal/runner/post_renderer.go +++ b/internal/postrender/combined.go @@ -14,32 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. */ -package runner +package postrender import ( "bytes" - "helm.sh/helm/v3/pkg/postrender" + helmpostrender "helm.sh/helm/v3/pkg/postrender" ) -// combinedPostRenderer, a collection of Helm PostRenders which are +// Combined is a collection of Helm PostRenders which are // invoked in the order of insertion. -type combinedPostRenderer struct { - renderers []postrender.PostRenderer +type Combined struct { + renderers []helmpostrender.PostRenderer } -func newCombinedPostRenderer() combinedPostRenderer { - return combinedPostRenderer{ - renderers: make([]postrender.PostRenderer, 0), +func NewCombined(renderer ...helmpostrender.PostRenderer) *Combined { + pr := make([]helmpostrender.PostRenderer, 0) + pr = append(pr, renderer...) + return &Combined{ + renderers: pr, } } -func (c *combinedPostRenderer) addRenderer(renderer postrender.PostRenderer) { - c.renderers = append(c.renderers, renderer) -} - -func (c *combinedPostRenderer) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { - var result *bytes.Buffer = renderedManifests +func (c *Combined) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { + var result = renderedManifests for _, renderer := range c.renderers { result, err = renderer.Run(result) if err != nil { diff --git a/internal/runner/post_renderer_kustomize.go b/internal/postrender/kustomize.go similarity index 81% rename from internal/runner/post_renderer_kustomize.go rename to internal/postrender/kustomize.go index e55d1512a..9195be811 100644 --- a/internal/runner/post_renderer_kustomize.go +++ b/internal/postrender/kustomize.go @@ -14,31 +14,92 @@ See the License for the specific language governing permissions and limitations under the License. */ -package runner +package postrender import ( "bytes" "encoding/json" "sync" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/kustomize/api/krusty" "sigs.k8s.io/kustomize/api/resmap" kustypes "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/filesys" "github.com/fluxcd/pkg/apis/kustomize" - - v2 "github.com/fluxcd/helm-controller/api/v2beta1" ) -type postRendererKustomize struct { - spec *v2.Kustomize +// Kustomize is a Helm post-render plugin that runs Kustomize. +type Kustomize struct { + // Patches is a list of patches to apply to the rendered manifests. + Patches []kustomize.Patch + // PatchesStrategicMerge is a list of strategic merge patches to apply to + // the rendered manifests. + PatchesStrategicMerge []apiextensionsv1.JSON + // PatchesJSON6902 is a list of JSON patches to apply to the rendered + // manifests. + PatchesJSON6902 []kustomize.JSON6902Patch + // Images is a list of images to replace in the rendered manifests. + Images []kustomize.Image } -func newPostRendererKustomize(spec *v2.Kustomize) *postRendererKustomize { - return &postRendererKustomize{ - spec: spec, +func (k *Kustomize) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { + fs := filesys.MakeFsInMemory() + cfg := kustypes.Kustomization{} + cfg.APIVersion = kustypes.KustomizationVersion + cfg.Kind = kustypes.KustomizationKind + cfg.Images = adaptImages(k.Images) + + // Add rendered Helm output as input resource to the Kustomization. + const input = "helm-output.yaml" + cfg.Resources = append(cfg.Resources, input) + if err := writeFile(fs, input, renderedManifests); err != nil { + return nil, err + } + + // Add patches. + for _, m := range k.Patches { + cfg.Patches = append(cfg.Patches, kustypes.Patch{ + Patch: m.Patch, + Target: adaptSelector(m.Target), + }) } + + // Add strategic merge patches. + for _, m := range k.PatchesStrategicMerge { + cfg.PatchesStrategicMerge = append(cfg.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw)) + } + + // Add JSON 6902 patches. + for i, m := range k.PatchesJSON6902 { + patch, err := json.Marshal(m.Patch) + if err != nil { + return nil, err + } + cfg.PatchesJson6902 = append(cfg.PatchesJson6902, kustypes.Patch{ + Patch: string(patch), + Target: adaptSelector(&k.PatchesJSON6902[i].Target), + }) + } + + // Write kustomization config to file. + kustomization, err := json.Marshal(cfg) + if err != nil { + return nil, err + } + if err := writeToFile(fs, "kustomization.yaml", kustomization); err != nil { + return nil, err + } + resMap, err := buildKustomization(fs, ".") + if err != nil { + return nil, err + } + yaml, err := resMap.AsYaml() + if err != nil { + return nil, err + } + return bytes.NewBuffer(yaml), nil } func writeToFile(fs filesys.FileSystem, path string, content []byte) error { @@ -95,64 +156,6 @@ func adaptSelector(selector *kustomize.Selector) (output *kustypes.Selector) { return } -func (k *postRendererKustomize) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { - fs := filesys.MakeFsInMemory() - cfg := kustypes.Kustomization{} - cfg.APIVersion = kustypes.KustomizationVersion - cfg.Kind = kustypes.KustomizationKind - cfg.Images = adaptImages(k.spec.Images) - - // Add rendered Helm output as input resource to the Kustomization. - const input = "helm-output.yaml" - cfg.Resources = append(cfg.Resources, input) - if err := writeFile(fs, input, renderedManifests); err != nil { - return nil, err - } - - // Add patches. - for _, m := range k.spec.Patches { - cfg.Patches = append(cfg.Patches, kustypes.Patch{ - Patch: m.Patch, - Target: adaptSelector(m.Target), - }) - } - - // Add strategic merge patches. - for _, m := range k.spec.PatchesStrategicMerge { - cfg.PatchesStrategicMerge = append(cfg.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw)) - } - - // Add JSON 6902 patches. - for i, m := range k.spec.PatchesJSON6902 { - patch, err := json.Marshal(m.Patch) - if err != nil { - return nil, err - } - cfg.PatchesJson6902 = append(cfg.PatchesJson6902, kustypes.Patch{ - Patch: string(patch), - Target: adaptSelector(&k.spec.PatchesJSON6902[i].Target), - }) - } - - // Write kustomization config to file. - kustomization, err := json.Marshal(cfg) - if err != nil { - return nil, err - } - if err := writeToFile(fs, "kustomization.yaml", kustomization); err != nil { - return nil, err - } - resMap, err := buildKustomization(fs, ".") - if err != nil { - return nil, err - } - yaml, err := resMap.AsYaml() - if err != nil { - return nil, err - } - return bytes.NewBuffer(yaml), nil -} - // TODO: remove mutex when kustomize fixes the concurrent map read/write panic var kustomizeRenderMutex sync.Mutex diff --git a/internal/runner/post_renderer_kustomize_test.go b/internal/postrender/kustomize_test.go similarity index 90% rename from internal/runner/post_renderer_kustomize_test.go rename to internal/postrender/kustomize_test.go index 31f322e82..c526b8795 100644 --- a/internal/runner/post_renderer_kustomize_test.go +++ b/internal/postrender/kustomize_test.go @@ -14,20 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -package runner +package postrender import ( "bytes" "encoding/json" - "reflect" "testing" + . "github.com/onsi/gomega" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/yaml" "github.com/fluxcd/pkg/apis/kustomize" - v2 "github.com/fluxcd/helm-controller/api/v2beta1" + v2 "github.com/fluxcd/helm-controller/api/v2beta2" ) const replaceImageMock = `apiVersion: v1 @@ -253,22 +253,26 @@ spec: } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + spec, err := mockKustomize(tt.patches, tt.patchesStrategicMerge, tt.patchesJson6902, tt.images) - if err != nil { - t.Errorf("Run() mockKustomize returned %v", err) - return - } - k := &postRendererKustomize{ - spec: spec, + g.Expect(err).ToNot(HaveOccurred()) + + k := &Kustomize{ + Patches: spec.Patches, + PatchesStrategicMerge: spec.PatchesStrategicMerge, + PatchesJSON6902: spec.PatchesJSON6902, + Images: spec.Images, } gotModifiedManifests, err := k.Run(bytes.NewBufferString(tt.renderedManifests)) - if (err != nil) != tt.expectErr { - t.Errorf("Run() error = %v, expectErr %v", err, tt.expectErr) + if tt.expectErr { + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(gotModifiedManifests.String()).To(BeEmpty()) return } - if !reflect.DeepEqual(gotModifiedManifests, bytes.NewBufferString(tt.expectManifests)) { - t.Errorf("Run() gotModifiedManifests = %v, want %v", gotModifiedManifests, tt.expectManifests) - } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(gotModifiedManifests).To(Equal(bytes.NewBufferString(tt.expectManifests))) }) } } diff --git a/internal/runner/post_renderer_origin_labels.go b/internal/postrender/origin_labels.go similarity index 68% rename from internal/runner/post_renderer_origin_labels.go rename to internal/postrender/origin_labels.go index 47437de05..34974a065 100644 --- a/internal/runner/post_renderer_origin_labels.go +++ b/internal/postrender/origin_labels.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package runner +package postrender import ( "bytes" @@ -24,23 +24,23 @@ import ( "sigs.k8s.io/kustomize/api/provider" "sigs.k8s.io/kustomize/api/resmap" kustypes "sigs.k8s.io/kustomize/api/types" - - v2 "github.com/fluxcd/helm-controller/api/v2beta1" ) -func newPostRendererOriginLabels(release *v2.HelmRelease) *postRendererOriginLabels { - return &postRendererOriginLabels{ - name: release.ObjectMeta.Name, - namespace: release.ObjectMeta.Namespace, +func NewOriginLabels(group, namespace, name string) *OriginLabels { + return &OriginLabels{ + group: group, + name: name, + namespace: namespace, } } -type postRendererOriginLabels struct { +type OriginLabels struct { + group string name string namespace string } -func (k *postRendererOriginLabels) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { +func (k *OriginLabels) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { resFactory := provider.NewDefaultDepProvider().GetResourceFactory() resMapFactory := resmap.NewFactory(resFactory) @@ -50,7 +50,7 @@ func (k *postRendererOriginLabels) Run(renderedManifests *bytes.Buffer) (modifie } labelTransformer := builtins.LabelTransformerPlugin{ - Labels: originLabels(k.name, k.namespace), + Labels: originLabels(k.group, k.namespace, k.name), FieldSpecs: []kustypes.FieldSpec{ {Path: "metadata/labels", CreateIfNotPresent: true}, }, @@ -67,9 +67,9 @@ func (k *postRendererOriginLabels) Run(renderedManifests *bytes.Buffer) (modifie return bytes.NewBuffer(yaml), nil } -func originLabels(name, namespace string) map[string]string { +func originLabels(group, namespace, name string) map[string]string { return map[string]string{ - fmt.Sprintf("%s/name", v2.GroupVersion.Group): name, - fmt.Sprintf("%s/namespace", v2.GroupVersion.Group): namespace, + fmt.Sprintf("%s/name", group): name, + fmt.Sprintf("%s/namespace", group): namespace, } } diff --git a/internal/runner/post_renderer_origin_labels_test.go b/internal/postrender/origin_labels_test.go similarity index 76% rename from internal/runner/post_renderer_origin_labels_test.go rename to internal/postrender/origin_labels_test.go index 14a03c23a..1d3d344af 100644 --- a/internal/runner/post_renderer_origin_labels_test.go +++ b/internal/postrender/origin_labels_test.go @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package runner +package postrender import ( "bytes" - "reflect" "testing" + + . "github.com/onsi/gomega" ) const mixedResourceMock = `apiVersion: v1 @@ -35,7 +36,7 @@ metadata: existing: label ` -func Test_postRendererOriginLabels_Run(t *testing.T) { +func Test_OriginLabels_Run(t *testing.T) { tests := []struct { name string renderedManifests string @@ -66,18 +67,17 @@ metadata: } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - k := &postRendererOriginLabels{ - name: "name", - namespace: "namespace", - } + g := NewWithT(t) + + k := NewOriginLabels("helm.toolkit.fluxcd.io", "namespace", "name") gotModifiedManifests, err := k.Run(bytes.NewBufferString(tt.renderedManifests)) - if (err != nil) != tt.expectErr { - t.Errorf("Run() error = %v, expectErr %v", err, tt.expectErr) + if tt.expectErr { + g.Expect(err).To(HaveOccurred()) + g.Expect(gotModifiedManifests.String()).To(BeEmpty()) return } - if !reflect.DeepEqual(gotModifiedManifests, bytes.NewBufferString(tt.expectManifests)) { - t.Errorf("Run() gotModifiedManifests = %v, want %v", gotModifiedManifests, tt.expectManifests) - } + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(gotModifiedManifests).To(Equal(bytes.NewBufferString(tt.expectManifests))) }) } } diff --git a/internal/controller/source_predicate.go b/internal/predicates/source_predicate.go similarity index 78% rename from internal/controller/source_predicate.go rename to internal/predicates/source_predicate.go index 8e5be1656..730abd5e2 100644 --- a/internal/controller/source_predicate.go +++ b/internal/predicates/source_predicate.go @@ -14,15 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package predicates import ( + "github.com/fluxcd/pkg/runtime/conditions" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" sourcev1 "github.com/fluxcd/source-controller/api/v1" ) +// SourceRevisionChangePredicate detects revision changes to the v1.Artifact of +// a v1.Source object. type SourceRevisionChangePredicate struct { predicate.Funcs } @@ -51,6 +54,20 @@ func (SourceRevisionChangePredicate) Update(e event.UpdateEvent) bool { return true } + oldConditions, ok := e.ObjectOld.(conditions.Getter) + if !ok { + return false + } + + newConditions, ok := e.ObjectNew.(conditions.Getter) + if !ok { + return false + } + + if !conditions.IsReady(oldConditions) && conditions.IsReady(newConditions) { + return true + } + return false } diff --git a/internal/predicates/source_predicate_test.go b/internal/predicates/source_predicate_test.go new file mode 100644 index 000000000..0accc6693 --- /dev/null +++ b/internal/predicates/source_predicate_test.go @@ -0,0 +1,138 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package predicates + +import ( + "testing" + "time" + + "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + + "github.com/fluxcd/pkg/apis/meta" + + sourcev1 "github.com/fluxcd/source-controller/api/v1" +) + +func TestSourceRevisionChangePredicate_Update(t *testing.T) { + sourceA := &sourceMock{revision: "revision-a"} + sourceB := &sourceMock{revision: "revision-b"} + emptySource := &sourceMock{} + notASource := &unstructured.Unstructured{} + + tests := []struct { + name string + old client.Object + new client.Object + want bool + }{ + {name: "same artifact revision", old: sourceA, new: sourceA, want: false}, + {name: "diff artifact revision", old: sourceA, new: sourceB, want: true}, + {name: "new with artifact", old: emptySource, new: sourceA, want: true}, + {name: "old with artifact", old: sourceA, new: emptySource, want: false}, + {name: "old not a source", old: notASource, new: sourceA, want: false}, + {name: "new not a source", old: sourceA, new: notASource, want: false}, + { + name: "old not ready and new ready", + old: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionFalse}}, + }, + new: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionTrue}}, + }, + want: true, + }, + { + name: "old ready and new not ready", + old: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionTrue}}, + }, + new: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionFalse}}, + }, + want: false, + }, + { + name: "old not ready and new not ready", + old: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionFalse}}, + }, + new: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionFalse}}, + }, + want: false, + }, + { + name: "old ready and new ready", + old: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionTrue}}, + }, + new: &sourceMock{ + revision: "revision-a", + conditions: []metav1.Condition{{Type: meta.ReadyCondition, Status: metav1.ConditionTrue}}, + }, + want: false, + }, + {name: "old nil", old: nil, new: sourceA, want: false}, + {name: "new nil", old: sourceA, new: nil, want: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := gomega.NewWithT(t) + + so := SourceRevisionChangePredicate{} + e := event.UpdateEvent{ + ObjectOld: tt.old, + ObjectNew: tt.new, + } + g.Expect(so.Update(e)).To(gomega.Equal(tt.want)) + }) + } +} + +type sourceMock struct { + unstructured.Unstructured + revision string + conditions []metav1.Condition +} + +func (m sourceMock) GetRequeueAfter() time.Duration { + return time.Second * 0 +} + +func (m *sourceMock) GetArtifact() *sourcev1.Artifact { + if m.revision != "" { + return &sourcev1.Artifact{ + Revision: m.revision, + } + } + return nil +} + +func (m *sourceMock) GetConditions() []metav1.Condition { + return m.conditions +} diff --git a/internal/reconcile/atomic_release.go b/internal/reconcile/atomic_release.go new file mode 100644 index 000000000..a00954353 --- /dev/null +++ b/internal/reconcile/atomic_release.go @@ -0,0 +1,418 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/logger" + "github.com/fluxcd/pkg/runtime/patch" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + interrors "github.com/fluxcd/helm-controller/internal/errors" +) + +// OwnedConditions is a list of Condition types owned by the HelmRelease object. +var OwnedConditions = []string{ + v2.ReleasedCondition, + v2.RemediatedCondition, + v2.TestSuccessCondition, + meta.ReconcilingCondition, + meta.ReadyCondition, + meta.StalledCondition, +} + +var ( + // ErrExceededMaxRetries is returned when there are no remaining retry + // attempts for the provided release config. + ErrExceededMaxRetries = errors.New("exceeded maximum retries") + + // ErrMustRequeue is returned when the caller must requeue the object + // to continue the reconciliation process. + ErrMustRequeue = errors.New("must requeue") + + // ErrUnknownReleaseStatus is returned when the release status is unknown + // and cannot be acted upon. + ErrUnknownReleaseStatus = errors.New("unknown release status") + + // ErrUnknownRemediationStrategy is returned when the remediation strategy + // is unknown. + ErrUnknownRemediationStrategy = errors.New("unknown remediation strategy") +) + +// AtomicRelease is an ActionReconciler which implements an atomic release +// strategy similar to Helm's `--atomic`, but with more advanced state +// determination. It determines the next action to take based on the current +// state of the Request.Object and other data, and the state of the Helm +// release. +// +// This process will continue until an action is called multiple times, no +// action remains, or a remediation action is called. In which case, the process +// will stop to be resumed at a later time or be checked upon again, by e.g. a +// requeue. +// +// Before running the ActionReconciler for the next action, the object is +// marked with Reconciling=True and the status is patched. +// This condition is removed when the ActionReconciler process is done. +// +// When it determines the object is out of remediation retries, the object +// is marked with Stalled=True. +// +// The status conditions are summarized into a Ready condition when no actions +// to be run remain, to ensure any transient error is cleared. +// +// Any returned error other than ErrExceededMaxRetries should be retried by the +// caller as soon as possible, preferably with a backoff strategy. In case of +// ErrMustRequeue, it is advised to requeue the object outside the interval +// to ensure continued progress. +// +// The caller is expected to patch the object one last time with the +// Request.Object result to persist the final observation. As there is an +// expectation they will need to patch the object anyway to e.g. update the +// ObservedGeneration. +// +// For more information on the individual ActionReconcilers, refer to their +// documentation. +type AtomicRelease struct { + patchHelper *patch.SerialPatcher + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder + strategy releaseStrategy + fieldManager string +} + +// NewAtomicRelease returns a new AtomicRelease reconciler configured with the +// provided values. +func NewAtomicRelease(patchHelper *patch.SerialPatcher, cfg *action.ConfigFactory, recorder record.EventRecorder, fieldManager string) *AtomicRelease { + return &AtomicRelease{ + patchHelper: patchHelper, + eventRecorder: recorder, + configFactory: cfg, + strategy: &cleanReleaseStrategy{}, + fieldManager: fieldManager, + } +} + +// releaseStrategy defines the continue-stop behavior of the reconcile loop. +type releaseStrategy interface { + // MustContinue should be called before running the current action, and + // returns true if the caller must proceed. + MustContinue(current ReconcilerType, previous ReconcilerTypeSet) bool + // MustStop should be called after running the current action, and returns + // true if the caller must stop. + MustStop(current ReconcilerType, previous ReconcilerTypeSet) bool +} + +// cleanReleaseStrategy is a releaseStrategy which will only execute the +// (remaining) actions for a single release. Effectively, this means it will +// only run any action once during a reconcile attempt, and stops after running +// a remediation action. +type cleanReleaseStrategy ReconcilerTypeSet + +// MustContinue returns if previous does not contain current. +func (cleanReleaseStrategy) MustContinue(current ReconcilerType, previous ReconcilerTypeSet) bool { + return !previous.Contains(current) +} + +// MustStop returns true if current equals ReconcilerTypeRemediate. +func (cleanReleaseStrategy) MustStop(current ReconcilerType, _ ReconcilerTypeSet) bool { + switch current { + case ReconcilerTypeRemediate: + return true + default: + return false + } +} + +func (r *AtomicRelease) Reconcile(ctx context.Context, req *Request) error { + log := ctrl.LoggerFrom(ctx).V(logger.InfoLevel) + + var ( + previous ReconcilerTypeSet + next ActionReconciler + ) + for { + select { + case <-ctx.Done(): + if errors.Is(ctx.Err(), context.Canceled) || errors.Is(ctx.Err(), context.DeadlineExceeded) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + // If the context is canceled, we still need to persist any + // last observation before returning. If the patch fails, we + // log the error and return the original context cancellation + // error. + if err := r.patchHelper.Patch(ctx, req.Object); err != nil { + log.Error(err, "failed to patch HelmRelease after context cancellation") + } + cancel() + } + return fmt.Errorf("atomic release canceled: %w", ctx.Err()) + default: + // Determine the next action to run based on the current state. + log.V(logger.DebugLevel).Info("determining current state of Helm release") + state, err := DetermineReleaseState(r.configFactory, req) + if err != nil { + conditions.MarkFalse(req.Object, meta.ReadyCondition, "StateError", fmt.Sprintf("Could not determine release state: %s", err.Error())) + return fmt.Errorf("cannot determine release state: %w", err) + } + + // Determine the next action to run based on the current state. + log.V(logger.DebugLevel).Info("determining next Helm action based on current state") + if next, err = r.actionForState(ctx, req, state); err != nil { + if errors.Is(err, ErrExceededMaxRetries) { + conditions.MarkStalled(req.Object, "RetriesExceeded", "Failed to %s after %d attempt(s)", + req.Object.Status.LastAttemptedReleaseAction, req.Object.GetActiveRemediation().GetFailureCount(req.Object)) + } + return err + } + + // If there is no next action, we are done. + if next == nil { + conditions.Delete(req.Object, meta.ReconcilingCondition) + + // Always summarize; this ensures we restore transient errors + // written to Ready. + summarize(req) + + return nil + } + + // If we are not allowed to run the next action, we are done for now... + if !r.strategy.MustContinue(next.Type(), previous) { + log.V(logger.DebugLevel).Info( + fmt.Sprintf("instructed to stop before running %s action reconciler %s", next.Type(), next.Name()), + ) + conditions.Delete(req.Object, meta.ReconcilingCondition) + + if remediation := req.Object.GetActiveRemediation(); remediation == nil || !remediation.RetriesExhausted(req.Object) { + return ErrMustRequeue + } + return nil + } + + // Mark the release as reconciling before we attempt to run the action. + // This to show continuous progress, as Helm actions can be long-running. + reconcilingMsg := fmt.Sprintf("Running '%s' action with timeout of %s", + next.Name(), timeoutForAction(next, req.Object).String()) + conditions.MarkTrue(req.Object, meta.ReconcilingCondition, "Progressing", reconcilingMsg) + + // If the next action is a release action, we can mark the release + // as progressing in terms of readiness as well. Doing this for any + // other action type is not useful, as it would potentially + // overwrite more important failure state from an earlier action. + if next.Type() == ReconcilerTypeRelease { + conditions.MarkUnknown(req.Object, meta.ReadyCondition, "Progressing", reconcilingMsg) + } + + // Patch the object to reflect the new condition. + if err = r.patchHelper.Patch(ctx, req.Object, patch.WithOwnedConditions{Conditions: OwnedConditions}, patch.WithFieldOwner(r.fieldManager)); err != nil { + return err + } + + // Run the action sub-reconciler. + log.Info(fmt.Sprintf("running '%s' action with timeout of %s", next.Name(), timeoutForAction(next, req.Object).String())) + if err = next.Reconcile(ctx, req); err != nil { + if conditions.IsReady(req.Object) { + conditions.MarkFalse(req.Object, meta.ReadyCondition, "ReconcileError", err.Error()) + } + return err + } + + // If we must stop after running the action, we are done for now... + if r.strategy.MustStop(next.Type(), previous) { + log.V(logger.DebugLevel).Info(fmt.Sprintf( + "instructed to stop after running %s action reconciler %s", next.Type(), next.Name()), + ) + conditions.Delete(req.Object, meta.ReconcilingCondition) + + if remediation := req.Object.GetActiveRemediation(); remediation == nil || !remediation.RetriesExhausted(req.Object) { + return ErrMustRequeue + } + return nil + } + + // Append the type to the set of action types we have performed. + previous = append(previous, next.Type()) + + // Patch the release to reflect progress. + if err = r.patchHelper.Patch(ctx, req.Object, patch.WithOwnedConditions{Conditions: OwnedConditions}, patch.WithFieldOwner(r.fieldManager)); err != nil { + return err + } + } + } +} + +// actionForState determines the next action to run based on the current state. +func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state ReleaseState) (ActionReconciler, error) { + log := ctrl.LoggerFrom(ctx) + + switch state.Status { + case ReleaseStatusInSync: + log.Info("release in-sync with desired state") + + // Remove all history up to the previous release action. + // We need to continue to hold on to the previous release result + // to ensure we can e.g. roll back when tests are enabled without + // any further changes to the release. + ignoreFailures := req.Object.GetTest().IgnoreFailures + if remediation := req.Object.GetActiveRemediation(); remediation != nil { + ignoreFailures = remediation.MustIgnoreTestFailures(req.Object.GetTest().IgnoreFailures) + } + req.Object.Status.History.Truncate(ignoreFailures) + + // TODO(hidde): this allows existing UIs to continue to display this + // field, but should be removed in a future release. + req.Object.Status.LastAppliedRevision = req.Object.Status.History.Latest().ChartVersion + + return nil, nil + case ReleaseStatusLocked: + log.Info(msgWithReason("release locked", state.Reason)) + return NewUnlock(r.configFactory, r.eventRecorder), nil + case ReleaseStatusAbsent: + log.Info(msgWithReason("release not installed", state.Reason)) + + if req.Object.GetInstall().GetRemediation().RetriesExhausted(req.Object) { + return nil, fmt.Errorf("%w: cannot install release", ErrExceededMaxRetries) + } + + return NewInstall(r.configFactory, r.eventRecorder), nil + case ReleaseStatusUnmanaged: + log.Info(msgWithReason("release not managed by object", state.Reason)) + + // Clear the history as we can no longer rely on it. + req.Object.Status.ClearHistory() + + return NewUpgrade(r.configFactory, r.eventRecorder), nil + case ReleaseStatusOutOfSync: + log.Info(msgWithReason("release out-of-sync with desired state", state.Reason)) + + if req.Object.GetUpgrade().GetRemediation().RetriesExhausted(req.Object) { + return nil, fmt.Errorf("%w: cannot upgrade release", ErrExceededMaxRetries) + } + + return NewUpgrade(r.configFactory, r.eventRecorder), nil + case ReleaseStatusUntested: + log.Info(msgWithReason("release has not been tested", state.Reason)) + return NewTest(r.configFactory, r.eventRecorder), nil + case ReleaseStatusFailed: + log.Info(msgWithReason("release is in a failed state", state.Reason)) + + remediation := req.Object.GetActiveRemediation() + + // If there is no active remediation strategy, we can only attempt to + // upgrade the release to see if that fixes the problem. + if remediation == nil { + log.V(logger.DebugLevel).Info("no active remediation strategy") + return NewUpgrade(r.configFactory, r.eventRecorder), nil + } + + // If there is no failure count, the conditions under which the failure + // occurred must have changed. + // Attempt to upgrade the release to see if the problem is resolved. + // This ensures that after a configuration change, the release is + // attempted again. + if remediation.GetFailureCount(req.Object) <= 0 { + log.Info("release conditions have changed since last failure") + return NewUpgrade(r.configFactory, r.eventRecorder), nil + } + + // We have exhausted the number of retries for the remediation + // strategy. + if remediation.RetriesExhausted(req.Object) && !remediation.MustRemediateLastFailure() { + return nil, fmt.Errorf("%w: cannot remediate failed release", ErrExceededMaxRetries) + } + + // Reset the history up to the point where the failure occurred. + // This ensures we do not accumulate a long history of failures. + req.Object.Status.History.Truncate(remediation.MustIgnoreTestFailures(req.Object.GetTest().IgnoreFailures)) + + switch remediation.GetStrategy() { + case v2.RollbackRemediationStrategy: + // Verify the previous release is still in storage and unmodified + // before instructing to roll back to it. + prev := req.Object.Status.History.Previous(remediation.MustIgnoreTestFailures(req.Object.GetTest().IgnoreFailures)) + if _, err := action.VerifySnapshot(r.configFactory.Build(nil), prev); err != nil { + if interrors.IsOneOf(err, action.ErrReleaseNotFound, action.ErrReleaseDisappeared, action.ErrReleaseNotObserved, action.ErrReleaseDigest) { + // If the rollback target is not found or is in any other + // way corrupt, the most correct remediation is to + // reattempt the upgrade. + log.Info(msgWithReason("unable to verify previous release in storage to roll back to", err.Error())) + return NewUpgrade(r.configFactory, r.eventRecorder), nil + } + + // This may be a temporary error, return it to retry. + return nil, fmt.Errorf("cannot verify previous release to roll back to: %w", err) + } + return NewRollbackRemediation(r.configFactory, r.eventRecorder), nil + case v2.UninstallRemediationStrategy: + return NewUninstallRemediation(r.configFactory, r.eventRecorder), nil + default: + return nil, fmt.Errorf("%w: %s", ErrUnknownRemediationStrategy, remediation.GetStrategy()) + } + default: + return nil, fmt.Errorf("%w: %s", ErrUnknownReleaseStatus, state.Status) + } +} + +func (r *AtomicRelease) Name() string { + return "atomic-release" +} + +func (r *AtomicRelease) Type() ReconcilerType { + return ReconcilerTypeRelease +} + +func msgWithReason(msg, reason string) string { + if reason != "" { + return fmt.Sprintf("%s: %s", msg, reason) + } + return msg +} + +func inStringSlice(ss []string, str string) (pos int, ok bool) { + for k, s := range ss { + if strings.EqualFold(s, str) { + return k, true + } + } + return -1, false +} + +func timeoutForAction(action ActionReconciler, obj *v2.HelmRelease) time.Duration { + switch action.(type) { + case *Install: + return obj.GetInstall().GetTimeout(obj.GetTimeout()).Duration + case *Upgrade: + return obj.GetUpgrade().GetTimeout(obj.GetTimeout()).Duration + case *Test: + return obj.GetTest().GetTimeout(obj.GetTimeout()).Duration + case *RollbackRemediation: + return obj.GetRollback().GetTimeout(obj.GetTimeout()).Duration + case *UninstallRemediation: + return obj.GetUninstall().GetTimeout(obj.GetTimeout()).Duration + default: + return obj.GetTimeout().Duration + } +} diff --git a/internal/reconcile/atomic_release_test.go b/internal/reconcile/atomic_release_test.go new file mode 100644 index 000000000..c7b146c45 --- /dev/null +++ b/internal/reconcile/atomic_release_test.go @@ -0,0 +1,1296 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "testing" + "time" + + . "github.com/onsi/gomega" + helmchart "helm.sh/helm/v3/pkg/chart" + helmrelease "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/patch" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/kube" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestReleaseStrategy_CleanRelease_MustContinue(t *testing.T) { + tests := []struct { + name string + current ReconcilerType + previous ReconcilerTypeSet + want bool + }{ + { + name: "continue if not in previous", + current: ReconcilerTypeRemediate, + previous: []ReconcilerType{ + ReconcilerTypeRelease, + }, + want: true, + }, + { + name: "do not continue if in previous", + current: ReconcilerTypeRemediate, + previous: []ReconcilerType{ + ReconcilerTypeRemediate, + }, + want: false, + }, + { + name: "do continue on nil", + current: ReconcilerTypeRemediate, + previous: nil, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + at := &cleanReleaseStrategy{} + if got := at.MustContinue(tt.current, tt.previous); got != tt.want { + g := NewWithT(t) + g.Expect(got).To(Equal(tt.want)) + } + }) + } +} + +func TestReleaseStrategy_CleanRelease_MustStop(t *testing.T) { + tests := []struct { + name string + current ReconcilerType + previous ReconcilerTypeSet + want bool + }{ + { + name: "stop if current is remediate", + current: ReconcilerTypeRemediate, + want: true, + }, + { + name: "do not stop if current is not remediate", + current: ReconcilerTypeRelease, + want: false, + }, + { + name: "do not stop if current is not remediate", + current: ReconcilerTypeUnlock, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + at := &cleanReleaseStrategy{} + if got := at.MustStop(tt.current, tt.previous); got != tt.want { + g := NewWithT(t) + g.Expect(got).To(Equal(tt.want)) + } + }) + } +} + +func TestAtomicRelease_Reconcile(t *testing.T) { + t.Run("runs a series of actions", func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: mockReleaseName, + Namespace: releaseNamespace, + }, + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + Test: &v2.Test{ + Enable: true, + }, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + // We use a fake client here to allow us to work with a minimal release + // object mock. As the fake client does not perform any validation. + // However, for the Helm storage driver to work, we need a real client + // which is therefore initialized separately above. + client := fake.NewClientBuilder(). + WithScheme(testEnv.Scheme()). + WithObjects(obj). + WithStatusSubresource(&v2.HelmRelease{}). + Build() + patchHelper := patch.NewSerialPatcher(obj, client) + recorder := new(record.FakeRecorder) + + req := &Request{ + Object: obj, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Values: nil, + } + g.Expect(NewAtomicRelease(patchHelper, cfg, recorder, testFieldManager).Reconcile(context.TODO(), req)).ToNot(HaveOccurred()) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hook completed successfully", + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.InstallSucceededReason, + Message: "Helm install succeeded", + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hook completed successfully", + }, + })) + g.Expect(obj.Status.History.Latest()).ToNot(BeNil(), "expected current to not be nil") + g.Expect(obj.Status.History.Previous(false)).To(BeNil(), "expected previous to be nil") + + g.Expect(obj.Status.Failures).To(BeZero()) + g.Expect(obj.Status.InstallFailures).To(BeZero()) + g.Expect(obj.Status.UpgradeFailures).To(BeZero()) + + endState, err := DetermineReleaseState(cfg, req) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(endState).To(Equal(ReleaseState{Status: ReleaseStatusInSync})) + }) +} + +func TestAtomicRelease_Reconcile_Scenarios(t *testing.T) { + tests := []struct { + name string + releases func(namespace string) []*helmrelease.Release + spec func(spec *v2.HelmReleaseSpec) + status func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus + chart *helmchart.Chart + values map[string]interface{} + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + wantErr error + }{ + { + name: "release is in-sync", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(nil)), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + values: nil, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "release is out-of-sync (chart)", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(nil)), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithVersion("0.2.0")), + values: nil, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "release is out-of-sync (values)", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "baz"}, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "release is locked (pending-install)", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingInstall, + }, testutil.ReleaseWithConfig(nil)), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: nil, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "release is locked (pending-upgrade)", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(nil)), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingUpgrade, + }, testutil.ReleaseWithConfig(nil)), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "release is locked (pending-rollback)", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithConfig(nil)), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + }, testutil.ReleaseWithConfig(nil)), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingRollback, + }, testutil.ReleaseWithConfig(nil)), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "release is not installed", + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "release exists but is not managed", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + } + }, + }, + { + name: "release was upgraded outside of the reconciler", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + previousDeployed := release.ObserveRelease(releases[1]) + previousDeployed.Info.Status = helmrelease.StatusDeployed + + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(previousDeployed), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "release was rolled back outside of the reconciler", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + modifiedRelease := release.ObserveRelease(releases[1]) + modifiedRelease.Info.Status = helmrelease.StatusFailed + + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(modifiedRelease), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "release was deleted outside of the reconciler", + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease( + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + )), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "part of the release history was deleted outside of the reconciler", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + deletedRelease := release.ObservedToSnapshot(release.ObserveRelease( + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 4, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + }), + )) + + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + deletedRelease, + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + }, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[len(releases)-1])), + } + }, + }, + { + name: "install failure", + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "install failure with remediation", + spec: func(spec *v2.HelmReleaseSpec) { + spec.Install = &v2.Install{ + Remediation: &v2.InstallRemediation{ + RemediateLastFailure: pointer.Bool(true), + }, + } + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "install test failure with remediation", + spec: func(spec *v2.HelmReleaseSpec) { + spec.Install = &v2.Install{ + Remediation: &v2.InstallRemediation{ + RemediateLastFailure: pointer.Bool(true), + }, + } + spec.Test = &v2.Test{ + Enable: true, + } + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + snap := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + snap.SetTestHooks(release.TestHooksFromRelease(releases[0])) + + return v2.Snapshots{ + snap, + } + }, + }, + { + name: "install test failure with test ignore", + spec: func(spec *v2.HelmReleaseSpec) { + spec.Test = &v2.Test{ + Enable: true, + IgnoreFailures: true, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + snap := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + snap.SetTestHooks(release.TestHooksFromRelease(releases[0])) + + return v2.Snapshots{ + snap, + } + }, + }, + { + name: "install with exhausted retries after remediation", + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease( + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusUninstalling, + }), + )), + }, + LastAttemptedReleaseAction: v2.ReleaseActionInstall, + Failures: 1, + InstallFailures: 1, + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "upgrade failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "upgrade failure with rollback remediation", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + RemediateLastFailure: pointer.Bool(true), + }, + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "upgrade failure with uninstall remediation", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + strategy := v2.UninstallRemediationStrategy + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + Strategy: &strategy, + RemediateLastFailure: pointer.Bool(true), + }, + } + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "upgrade test failure with remediation", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + RemediateLastFailure: pointer.Bool(true), + }, + } + spec.Test = &v2.Test{ + Enable: true, + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + testedSnap := release.ObservedToSnapshot(release.ObserveRelease(releases[1])) + testedSnap.SetTestHooks(release.TestHooksFromRelease(releases[1])) + + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + testedSnap, + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "upgrade test failure with test ignore", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Test = &v2.Test{ + Enable: true, + IgnoreFailures: true, + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + testedSnap := release.ObservedToSnapshot(release.ObserveRelease(releases[1])) + testedSnap.SetTestHooks(release.TestHooksFromRelease(releases[1])) + + return v2.Snapshots{ + testedSnap, + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "upgrade with exhausted retries after remediation", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 3, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(namespace string, releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + Failures: 1, + UpgradeFailures: 1, + } + }, + chart: testutil.BuildChart(), + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + wantErr: ErrExceededMaxRetries, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + releaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: mockReleaseName, + Namespace: releaseNamespace, + }, + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releaseNamespace, releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + // We use a fake client here to allow us to work with a minimal release + // object mock. As the fake client does not perform any validation. + // However, for the Helm storage driver to work, we need a real client + // which is therefore initialized separately above. + client := fake.NewClientBuilder(). + WithScheme(testEnv.Scheme()). + WithObjects(obj). + WithStatusSubresource(&v2.HelmRelease{}). + Build() + patchHelper := patch.NewSerialPatcher(obj, client) + recorder := new(record.FakeRecorder) + + req := &Request{ + Object: obj, + Chart: tt.chart, + Values: tt.values, + } + + err = NewAtomicRelease(patchHelper, cfg, recorder, testFieldManager).Reconcile(context.TODO(), req) + wantErr := BeNil() + if tt.wantErr != nil { + wantErr = MatchError(tt.wantErr) + } + g.Expect(err).To(wantErr) + + if tt.expectHistory != nil { + history, _ := store.History(mockReleaseName) + releaseutil.SortByRevision(history) + + g.Expect(req.Object.Status.History).To(testutil.Equal(tt.expectHistory(history))) + } + }) + } +} + +func TestAtomicRelease_actionForState(t *testing.T) { + tests := []struct { + name string + releases []*helmrelease.Release + spec func(spec *v2.HelmReleaseSpec) + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + state ReleaseState + want ActionReconciler + wantErr error + }{ + { + name: "in-sync release does not trigger any action", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + {Version: 1}, + }, + } + }, + state: ReleaseState{Status: ReleaseStatusInSync}, + want: nil, + }, + { + name: "locked release triggers unlock action", + state: ReleaseState{Status: ReleaseStatusLocked}, + want: &Unlock{}, + }, + { + name: "absent release triggers install action", + state: ReleaseState{Status: ReleaseStatusAbsent}, + want: &Install{}, + }, + { + name: "absent release without remaining retries returns error", + state: ReleaseState{Status: ReleaseStatusAbsent}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + InstallFailures: 1, + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "unmanaged release triggers upgrade", + state: ReleaseState{Status: ReleaseStatusUnmanaged}, + want: &Upgrade{}, + }, + { + name: "out-of-sync release triggers upgrade", + state: ReleaseState{ + Status: ReleaseStatusOutOfSync, + }, + want: &Upgrade{}, + }, + { + name: "out-of-sync release with no remaining retries returns error", + state: ReleaseState{ + Status: ReleaseStatusOutOfSync, + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + UpgradeFailures: 1, + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "untested release triggers test action", + state: ReleaseState{Status: ReleaseStatusUntested}, + want: &Test{}, + }, + { + name: "failed release without active remediation triggers upgrade", + state: ReleaseState{Status: ReleaseStatusFailed}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + LastAttemptedReleaseAction: "", + InstallFailures: 1, + } + }, + want: &Upgrade{}, + }, + { + name: "failed release without failure count triggers upgrade", + state: ReleaseState{Status: ReleaseStatusFailed}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + UpgradeFailures: 0, + } + }, + want: &Upgrade{}, + }, + { + name: "failed release with exhausted retries returns error", + state: ReleaseState{Status: ReleaseStatusFailed}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + UpgradeFailures: 1, + } + }, + wantErr: ErrExceededMaxRetries, + }, + { + name: "failed release with active install remediation triggers uninstall", + state: ReleaseState{Status: ReleaseStatusFailed}, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Install = &v2.Install{ + Remediation: &v2.InstallRemediation{ + Retries: 3, + }, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + LastAttemptedReleaseAction: v2.ReleaseActionInstall, + InstallFailures: 2, + } + }, + want: &UninstallRemediation{}, + }, + { + name: "failed release with active upgrade remediation triggers rollback", + state: ReleaseState{Status: ReleaseStatusFailed}, + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusFailed, + Chart: testutil.BuildChart(), + }), + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + Retries: 2, + }, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + UpgradeFailures: 1, + } + }, + want: &RollbackRemediation{}, + }, + { + name: "failed release with active upgrade remediation and unverified previous triggers upgrade", + state: ReleaseState{Status: ReleaseStatusFailed}, + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + Retries: 2, + }, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease( + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + )), + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + UpgradeFailures: 1, + } + }, + want: &Upgrade{}, + }, + { + name: "unknown remediation strategy returns error", + state: ReleaseState{ + Status: ReleaseStatusFailed, + }, + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + }, + spec: func(spec *v2.HelmReleaseSpec) { + strategy := v2.RemediationStrategy("invalid") + spec.Upgrade = &v2.Upgrade{ + Remediation: &v2.UpgradeRemediation{ + Strategy: &strategy, + Retries: 2, + }, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + UpgradeFailures: 1, + } + }, + wantErr: ErrUnknownRemediationStrategy, + }, + { + name: "invalid release status returns error", + state: ReleaseState{Status: "invalid"}, + wantErr: ErrUnknownReleaseStatus, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: mockReleaseNamespace, + StorageNamespace: mockReleaseNamespace, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(tt.releases) + } + + cfg, err := action.NewConfigFactory(&kube.MemoryRESTClientGetter{}, + action.WithStorage(helmdriver.MemoryDriverName, mockReleaseNamespace), + ) + g.Expect(err).ToNot(HaveOccurred()) + + if len(tt.releases) > 0 { + store := helmstorage.Init(cfg.Driver) + for _, i := range tt.releases { + g.Expect(store.Create(i)).To(Succeed()) + } + } + + r := &AtomicRelease{configFactory: cfg} + got, err := r.actionForState(context.TODO(), &Request{Object: obj}, tt.state) + + if tt.wantErr != nil { + g.Expect(got).To(BeNil()) + g.Expect(err).To(MatchError(tt.wantErr)) + return + } + g.Expect(err).ToNot(HaveOccurred()) + + want := BeAssignableToTypeOf(tt.want) + if tt.want == nil { + want = BeNil() + } + g.Expect(got).To(want) + }) + } +} diff --git a/internal/reconcile/helmchart_template.go b/internal/reconcile/helmchart_template.go new file mode 100644 index 000000000..84a835ad9 --- /dev/null +++ b/internal/reconcile/helmchart_template.go @@ -0,0 +1,233 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/ssa" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/acl" + "github.com/fluxcd/helm-controller/internal/strings" +) + +// HelmChartTemplate attempts to create, update or delete a v1beta2.HelmChart +// based on the given Request data. +// +// It does this by building a v1beta2.HelmChart from the template declared in +// the v2beta2.HelmRelease, and then reconciling that v1beta2.HelmChart using +// a server-side apply. +// +// When the server-side apply succeeds, the namespaced name of the chart is +// written to the Status.HelmChart field of the v2beta2.HelmRelease. If the +// server-side apply fails, the error is returned to the caller and indicates +// they should retry. +// +// When at the beginning of the reconciliation the deletion timestamp is set +// on the v2beta2.HelmRelease, or the Status.HelmChart differs from the +// namespaced name of the chart to be applied, the existing chart is deleted. +// The deletion is observed, and when it completes, the Status.HelmChart is +// cleared. If the deletion fails, the error is returned to the caller and +// indicates they should retry. +// +// In case the v2beta2.HelmRelease is marked for deletion, the reconciler will +// not continue to attempt to create or update the v1beta2.HelmChart. +type HelmChartTemplate struct { + client client.Client + eventRecorder record.EventRecorder + fieldManager string +} + +// NewHelmChartTemplate returns a new HelmChartTemplate reconciler configured +// with the provided values. +func NewHelmChartTemplate(client client.Client, recorder record.EventRecorder, fieldManager string) *HelmChartTemplate { + return &HelmChartTemplate{ + client: client, + eventRecorder: recorder, + fieldManager: fieldManager, + } +} + +func (r *HelmChartTemplate) Reconcile(ctx context.Context, req *Request) error { + var ( + obj = req.Object + chartRef = types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.Namespace), + Name: obj.GetHelmChartName(), + } + ) + + // The HelmChart name and/or namespace diverges or the HelmRelease is + // being deleted, delete the HelmChart. + if (obj.Status.HelmChart != "" && obj.Status.HelmChart != chartRef.String()) || !obj.DeletionTimestamp.IsZero() { + // If the HelmRelease is being deleted, we need to short-circuit to + // avoid recreating the HelmChart. + if err := r.reconcileDelete(ctx, req.Object); err != nil || !obj.DeletionTimestamp.IsZero() { + return err + } + } + + // Confirm we are allowed to fetch the HelmChart. + if err := acl.AllowsAccessTo(req.Object, sourcev1.HelmChartKind, chartRef); err != nil { + return err + } + + // Build new HelmChart based on the declared template. + newChart := buildHelmChartFromTemplate(req.Object) + + // Convert to an unstructured object to please the SSA library. + uo, err := runtime.DefaultUnstructuredConverter.ToUnstructured(newChart.DeepCopy()) + if err != nil { + return fmt.Errorf("failed to convert HelmChart to unstructured: %w", err) + } + u := &unstructured.Unstructured{Object: uo} + + // Get the GVK for the object according to the current scheme. + gvk, err := apiutil.GVKForObject(newChart, r.client.Scheme()) + if err != nil { + return fmt.Errorf("unable to get GVK for HelmChart: %w", err) + } + u.SetGroupVersionKind(gvk) + + rm := ssa.NewResourceManager(r.client, nil, ssa.Owner{ + Group: v2.GroupVersion.Group, + Field: r.fieldManager, + }) + + // Mark the object as owned by the HelmRelease. + rm.SetOwnerLabels([]*unstructured.Unstructured{u}, obj.GetName(), obj.GetNamespace()) + + // Run using server-side apply. + entry, err := rm.Apply(ctx, u, ssa.DefaultApplyOptions()) + if err != nil { + err = fmt.Errorf("failed to run server-side apply: %w", err) + r.eventRecorder.Eventf(req.Object, eventv1.EventTypeTrace, "HelmChartSyncErr", err.Error()) + return err + } + + // Consult the entry result and act accordingly. + switch entry.Action { + case ssa.CreatedAction, ssa.ConfiguredAction: + msg := strings.Normalize(fmt.Sprintf( + "%s %s with SourceRef '%s/%s/%s'", entry.Action.String(), entry.Subject, + newChart.Spec.SourceRef.Kind, newChart.GetNamespace(), newChart.Spec.SourceRef.Name, + )) + + ctrl.LoggerFrom(ctx).Info(msg) + r.eventRecorder.Eventf(req.Object, eventv1.EventTypeTrace, + fmt.Sprintf("HelmChart%s", strings.Title(entry.Action.String())), msg) + case ssa.UnchangedAction: + msg := fmt.Sprintf("%s with SourceRef '%s/%s/%s' is in-sync", entry.Subject, + newChart.Spec.SourceRef.Kind, newChart.GetNamespace(), newChart.Spec.SourceRef.Name) + + ctrl.LoggerFrom(ctx).Info(msg) + r.eventRecorder.Eventf(req.Object, eventv1.EventTypeTrace, "HelmChartInSync", msg) + default: + err = fmt.Errorf("unexpected action '%s' for %s", entry.Action.String(), entry.Subject) + return err + } + + // From this moment on, we know the HelmChart spec is up-to-date. + obj.Status.HelmChart = chartRef.String() + + return nil +} + +// reconcileDelete handles the garbage collection of the current HelmChart in +// the Status object of the given HelmRelease. +func (r *HelmChartTemplate) reconcileDelete(ctx context.Context, obj *v2.HelmRelease) error { + if !obj.Spec.Suspend && obj.Status.HelmChart != "" { + ns, name := obj.Status.GetHelmChart() + namespacedName := types.NamespacedName{Namespace: ns, Name: name} + + // Confirm we are allowed to fetch the HelmChart. + if err := acl.AllowsAccessTo(obj, sourcev1.HelmChartKind, namespacedName); err != nil { + return err + } + + // Fetch the HelmChart. + var chart sourcev1.HelmChart + err := r.client.Get(ctx, namespacedName, &chart) + if err != nil && !apierrors.IsNotFound(err) { + // Return error to retry until we succeed. + err = fmt.Errorf("failed to delete HelmChart '%s': %w", obj.Status.HelmChart, err) + return err + } + if err == nil { + // Delete the HelmChart. + if err = r.client.Delete(ctx, &chart); err != nil { + err = fmt.Errorf("failed to delete HelmChart '%s': %w", obj.Status.HelmChart, err) + return err + } + r.eventRecorder.Eventf(obj, eventv1.EventTypeTrace, "HelmChartDeleted", "deleted HelmChart '%s'", obj.Status.HelmChart) + } + + // Truncate the chart reference in the status object. + obj.Status.HelmChart = "" + } + + return nil +} + +// buildHelmChartFromTemplate builds a v1beta2.HelmChart from the +// v2beta1.HelmChartTemplate of the given v2beta1.HelmRelease. +func buildHelmChartFromTemplate(obj *v2.HelmRelease) *sourcev1.HelmChart { + template := obj.Spec.Chart.DeepCopy() + result := &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: obj.GetHelmChartName(), + Namespace: template.GetNamespace(obj.Namespace), + }, + Spec: sourcev1.HelmChartSpec{ + Chart: template.Spec.Chart, + Version: template.Spec.Version, + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: template.Spec.SourceRef.Name, + Kind: template.Spec.SourceRef.Kind, + }, + Interval: template.GetInterval(obj.Spec.Interval), + ReconcileStrategy: template.Spec.ReconcileStrategy, + ValuesFiles: template.Spec.ValuesFiles, + ValuesFile: template.Spec.ValuesFile, + }, + } + if verifyTpl := template.Spec.Verify; verifyTpl != nil { + result.Spec.Verify = &sourcev1.OCIRepositoryVerification{ + Provider: verifyTpl.Provider, + SecretRef: verifyTpl.SecretRef, + } + } + if metaTpl := template.ObjectMeta; metaTpl != nil { + result.SetAnnotations(metaTpl.Annotations) + result.SetLabels(metaTpl.Labels) + } + return result +} diff --git a/internal/reconcile/helmchart_template_test.go b/internal/reconcile/helmchart_template_test.go new file mode 100644 index 000000000..0385997ff --- /dev/null +++ b/internal/reconcile/helmchart_template_test.go @@ -0,0 +1,772 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/fluxcd/pkg/apis/meta" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/acl" +) + +func TestHelmChartTemplate_Reconcile(t *testing.T) { + g := NewWithT(t) + + namespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "helm-release-chart-reconciler-", + }, + } + g.Expect(testEnv.CreateAndWait(context.Background(), &namespace)).To(Succeed()) + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), &namespace)).To(Succeed()) + }) + + t.Run("DeletionTimestamp triggers delete", func(t *testing.T) { + g := NewWithT(t) + + releaseName := "deletion-timestamp" + existingChart := sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: fmt.Sprintf("%s-%s", namespace.GetName(), releaseName), + Labels: map[string]string{ + v2.GroupVersion.Group + "/name": releaseName, + v2.GroupVersion.Group + "/namespace": namespace.GetName(), + }, + }, + Spec: sourcev1.HelmChartSpec{ + Interval: metav1.Duration{Duration: 1 * time.Hour}, + Chart: "foo", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "foo-repository", + }, + }, + } + g.Expect(testEnv.CreateAndWait(context.Background(), &existingChart)).To(Succeed()) + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), &existingChart)).To(Succeed()) + }) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: recorder, + fieldManager: testFieldManager, + } + + ts := metav1.Now() + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: releaseName, + DeletionTimestamp: &ts, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", existingChart.GetNamespace(), existingChart.GetName()), + }, + } + + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).To(BeEmpty()) + + g.Eventually(func(g Gomega) { + g.Expect(apierrors.IsNotFound(testEnv.Get(context.TODO(), + types.NamespacedName{ + Namespace: existingChart.GetNamespace(), + Name: existingChart.GetName(), + }, + &existingChart, + ))).To(BeTrue()) + }).Should(Succeed()) + }) + + t.Run("Status.HelmChart divergence triggers delete and creates chart", func(t *testing.T) { + g := NewWithT(t) + + existingChart := sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + GenerateName: "existing-chart-", + }, + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "mock", + }, + }, + } + g.Expect(testEnv.CreateAndWait(context.TODO(), &existingChart)).To(Succeed()) + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), &existingChart)).To(Succeed()) + }) + + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: record.NewFakeRecorder(32), + fieldManager: testFieldManager, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: "release-with-existing-chart", + }, + Spec: v2.HelmReleaseSpec{ + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + Chart: "foo", + SourceRef: v2.CrossNamespaceObjectReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "foo-repository", + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", existingChart.GetNamespace(), existingChart.GetName()), + }, + } + + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).To(Equal( + fmt.Sprintf("%s/%s", namespace.GetName(), namespace.GetName()+"-"+obj.GetName()), + )) + + g.Eventually(func(g Gomega) { + g.Expect(apierrors.IsNotFound(testEnv.Get(context.TODO(), + types.NamespacedName{ + Namespace: existingChart.GetNamespace(), + Name: existingChart.GetName(), + }, + &existingChart, + ))).To(BeTrue()) + }).Should(Succeed()) + }) + + t.Run("HelmChart NotFound creates HelmChart", func(t *testing.T) { + g := NewWithT(t) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: recorder, + fieldManager: testFieldManager, + } + + releaseName := "not-found" + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: releaseName, + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Hour}, + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + SourceRef: v2.CrossNamespaceObjectReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "mock", + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", namespace.GetName(), namespace.GetName()+"-"+releaseName), + }, + } + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + expectChart := sourcev1.HelmChart{} + g.Eventually(func(g Gomega) { + g.Expect(testEnv.Get(context.TODO(), types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.Namespace), + Name: obj.GetHelmChartName()}, + &expectChart, + )).To(Succeed()) + }).Should(Succeed()) + + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), &expectChart)).To(Succeed()) + }) + }) + + t.Run("Spec divergence updates HelmChart", func(t *testing.T) { + g := NewWithT(t) + + releaseName := "divergence" + existingChart := sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: fmt.Sprintf("%s-%s", namespace.GetName(), releaseName), + Labels: map[string]string{ + v2.GroupVersion.Group + "/name": releaseName, + v2.GroupVersion.Group + "/namespace": namespace.GetName(), + }, + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "./bar", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "bar-repository", + }, + }, + } + g.Expect(testEnv.CreateAndWait(context.TODO(), &existingChart)).To(Succeed()) + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), &existingChart)).To(Succeed()) + }) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: recorder, + fieldManager: testFieldManager, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: releaseName, + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Hour}, + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + Chart: "foo", + SourceRef: v2.CrossNamespaceObjectReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "foo-repository", + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", existingChart.GetNamespace(), existingChart.GetName()), + }, + } + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + newChart := sourcev1.HelmChart{} + g.Eventually(func(g Gomega) { + g.Expect(testEnv.Get(context.TODO(), types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.Namespace), + Name: obj.GetHelmChartName()}, &newChart)).To(Succeed()) + + g.Expect(newChart.Spec.Chart).To(Equal(obj.Spec.Chart.Spec.Chart)) + g.Expect(newChart.Spec.SourceRef.Name).To(Equal(obj.Spec.Chart.Spec.SourceRef.Name)) + g.Expect(newChart.Spec.SourceRef.Kind).To(Equal(obj.Spec.Chart.Spec.SourceRef.Kind)) + }).Should(Succeed()) + }) + + t.Run("no HelmChart divergence", func(t *testing.T) { + g := NewWithT(t) + + releaseName := "no-divergence" + existingChart := &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: fmt.Sprintf("%s-%s", namespace.GetName(), releaseName), + Labels: map[string]string{ + v2.GroupVersion.Group + "/name": releaseName, + v2.GroupVersion.Group + "/namespace": namespace.GetName(), + }, + }, + Spec: sourcev1.HelmChartSpec{ + Interval: metav1.Duration{Duration: 1 * time.Hour}, + Chart: "foo", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "foo-repository", + }, + }, + } + g.Expect(testEnv.CreateAndWait(context.Background(), existingChart)).To(Succeed()) + t.Cleanup(func() { + g.Expect(testEnv.Cleanup(context.Background(), existingChart)).To(Succeed()) + }) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: recorder, + fieldManager: testFieldManager, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: releaseName, + }, + Spec: v2.HelmReleaseSpec{ + Interval: existingChart.Spec.Interval, + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + Chart: existingChart.Spec.Chart, + SourceRef: v2.CrossNamespaceObjectReference{ + Kind: existingChart.Spec.SourceRef.Kind, + Name: existingChart.Spec.SourceRef.Name, + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", existingChart.GetNamespace(), existingChart.GetName()), + }, + } + + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + newChart := sourcev1.HelmChart{} + g.Expect(testEnv.Get(context.TODO(), types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.Namespace), + Name: obj.GetHelmChartName()}, &newChart)).To(Succeed()) + g.Expect(newChart.ResourceVersion).To(Equal(existingChart.ResourceVersion), "HelmChart should not have been updated") + }) + + t.Run("sets owner labels on HelmChart", func(t *testing.T) { + g := NewWithT(t) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: testEnv, + eventRecorder: recorder, + fieldManager: testFieldManager, + } + + releaseName := "owner-labels" + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.GetName(), + Name: releaseName, + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 1 * time.Hour}, + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + SourceRef: v2.CrossNamespaceObjectReference{ + Kind: sourcev1.HelmRepositoryKind, + Name: "mock", + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: fmt.Sprintf("%s/%s", namespace.GetName(), namespace.GetName()+"-"+releaseName), + }, + } + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + expectChart := sourcev1.HelmChart{} + g.Eventually(func(g Gomega) { + g.Expect(r.client.Get(context.TODO(), types.NamespacedName{ + Namespace: obj.Spec.Chart.GetNamespace(obj.Namespace), + Name: obj.GetHelmChartName()}, + &expectChart, + )).To(Succeed()) + g.Expect(testEnv.Cleanup(context.Background(), &expectChart)).To(Succeed()) + + g.Expect(expectChart.GetLabels()).To(HaveKeyWithValue(v2.GroupVersion.Group+"/name", obj.GetName())) + g.Expect(expectChart.GetLabels()).To(HaveKeyWithValue(v2.GroupVersion.Group+"/namespace", obj.GetNamespace())) + }).Should(Succeed()) + }) + + t.Run("cross namespace disallow is respected", func(t *testing.T) { + g := NewWithT(t) + + r := &HelmChartTemplate{ + client: fake.NewClientBuilder().WithScheme(NewTestScheme()).Build(), + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "default", + }, + Spec: v2.HelmReleaseSpec{ + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + SourceRef: v2.CrossNamespaceObjectReference{ + Name: "chart", + Namespace: "other", + }, + }, + }, + }, + Status: v2.HelmReleaseStatus{}, + } + err := r.Reconcile(context.TODO(), &Request{Object: obj}) + g.Expect(err).To(HaveOccurred()) + g.Expect(obj.Status.HelmChart).To(BeEmpty()) + + err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: "other", Name: "chart"}, &sourcev1.HelmChart{}) + g.Expect(err).To(HaveOccurred()) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }) +} + +func TestHelmChartTemplate_reconcileDelete(t *testing.T) { + now := metav1.Now() + + t.Run("Status.HelmChart is deleted", func(t *testing.T) { + g := NewWithT(t) + + builder := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithObjects(&sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "chart", + }, + }) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: builder.Build(), + eventRecorder: recorder, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "default", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "default/chart", + }, + } + err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).To(BeEmpty()) + + err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "chart"}, &sourcev1.HelmChart{}) + g.Expect(err).To(HaveOccurred()) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }) + + t.Run("Status.HelmChart already deleted", func(t *testing.T) { + g := NewWithT(t) + + r := &HelmChartTemplate{ + client: fake.NewClientBuilder().WithScheme(NewTestScheme()).Build(), + } + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "default", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "default/chart", + }, + } + err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).To(BeEmpty()) + }) + + t.Run("Spec.Suspend is respected", func(t *testing.T) { + g := NewWithT(t) + + builder := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithObjects(&sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "chart", + }, + }) + + recorder := record.NewFakeRecorder(32) + r := &HelmChartTemplate{ + client: builder.Build(), + eventRecorder: recorder, + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "release", + Namespace: "default", + DeletionTimestamp: &now, + }, + Spec: v2.HelmReleaseSpec{ + Suspend: true, + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "default/chart", + }, + } + err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + g.Consistently(func(g Gomega) { + err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "chart"}, &sourcev1.HelmChart{}) + g.Expect(err).ToNot(HaveOccurred()) + }).Should(Succeed()) + }) + + t.Run("cross namespace allow is respected", func(t *testing.T) { + g := NewWithT(t) + + chart := &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "other", + Name: "chart", + }, + } + builder := fake.NewClientBuilder(). + WithScheme(NewTestScheme()). + WithObjects(chart) + + r := &HelmChartTemplate{ + client: builder.Build(), + } + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Status: v2.HelmReleaseStatus{ + HelmChart: "other/chart", + }, + } + + currentAllow := acl.AllowCrossNamespaceRef + acl.AllowCrossNamespaceRef = false + t.Cleanup(func() { acl.AllowCrossNamespaceRef = currentAllow }) + + err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).To(HaveOccurred()) + g.Expect(obj.Status.HelmChart).ToNot(BeEmpty()) + + g.Expect(r.client.Get(context.TODO(), + types.NamespacedName{Namespace: chart.Namespace, Name: chart.Name}, + &sourcev1.HelmChart{}), + ).To(Succeed()) + }) + + t.Run("empty Status.HelmChart", func(t *testing.T) { + g := NewWithT(t) + + r := &HelmChartTemplate{ + client: fake.NewClientBuilder().WithScheme(NewTestScheme()).Build(), + } + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{}, + } + err := r.reconcileDelete(context.TODO(), obj) + g.Expect(err).ToNot(HaveOccurred()) + }) +} + +func Test_buildHelmChartFromTemplate(t *testing.T) { + hrWithChartTemplate := v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-release", + Namespace: "default", + }, + Spec: v2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: time.Minute}, + Chart: v2.HelmChartTemplate{ + Spec: v2.HelmChartTemplateSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: v2.CrossNamespaceObjectReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: &metav1.Duration{Duration: 2 * time.Minute}, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + } + + tests := []struct { + name string + modify func(release *v2.HelmRelease) + want *sourcev1.HelmChart + }{ + { + name: "builds HelmChart from HelmChartTemplate", + modify: func(*v2.HelmRelease) {}, + want: &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-test-release", + Namespace: "default", + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: metav1.Duration{Duration: 2 * time.Minute}, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + { + name: "takes SourceRef namespace into account", + modify: func(hr *v2.HelmRelease) { + hr.Spec.Chart.Spec.SourceRef.Namespace = "cross" + }, + want: &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-test-release", + Namespace: "cross", + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: metav1.Duration{Duration: 2 * time.Minute}, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + { + name: "falls back to HelmRelease interval", + modify: func(hr *v2.HelmRelease) { + hr.Spec.Chart.Spec.Interval = nil + }, + want: &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-test-release", + Namespace: "default", + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: metav1.Duration{Duration: time.Minute}, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + { + name: "take cosign verification into account", + modify: func(hr *v2.HelmRelease) { + hr.Spec.Chart.Spec.Verify = &v2.HelmChartTemplateVerification{ + Provider: "cosign", + SecretRef: &meta.LocalObjectReference{ + Name: "cosign-key", + }, + } + }, + want: &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-test-release", + Namespace: "default", + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: metav1.Duration{Duration: 2 * time.Minute}, + ValuesFiles: []string{"values.yaml"}, + Verify: &sourcev1.OCIRepositoryVerification{ + Provider: "cosign", + SecretRef: &meta.LocalObjectReference{ + Name: "cosign-key", + }, + }, + }, + }, + }, + { + name: "takes object meta into account", + modify: func(hr *v2.HelmRelease) { + hr.Spec.Chart.ObjectMeta = &v2.HelmChartTemplateObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "bar": "baz", + }, + } + }, + want: &sourcev1.HelmChart{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-test-release", + Namespace: "default", + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "bar": "baz", + }, + }, + Spec: sourcev1.HelmChartSpec{ + Chart: "chart", + Version: "1.0.0", + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Name: "test-repository", + Kind: "HelmRepository", + }, + Interval: metav1.Duration{Duration: 2 * time.Minute}, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + hr := hrWithChartTemplate.DeepCopy() + tt.modify(hr) + + g.Expect(buildHelmChartFromTemplate(hr)).To(Equal(tt.want)) + }) + } +} diff --git a/internal/reconcile/install.go b/internal/reconcile/install.go new file mode 100644 index 000000000..02adae7f9 --- /dev/null +++ b/internal/reconcile/install.go @@ -0,0 +1,185 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + "strings" + + "github.com/fluxcd/pkg/runtime/logger" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" +) + +// Install is an ActionReconciler which attempts to install a Helm release +// based on the given Request data. +// +// Before the installation, the History in the Status of the Request.Object is +// cleared to mark the start of a new release lifecycle. This ensures we never +// attempt to roll back to a previous release before the install. +// +// During the installation process, the writes to the Helm storage are +// observed and recorded in the Status.History field of the Request.Object. +// +// On installation success, the object is marked with Released=True and emits +// an event. In addition, the object is marked with TestSuccess=False if tests +// are enabled to indicate we are awaiting the results. +// On failure, the object is marked with Released=False and emits a warning +// event. Only an error which resulted in a modification to the Helm storage +// counts towards a failure for the active remediation strategy. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type Install struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewInstall returns a new Install reconciler configured with the provided +// values. +func NewInstall(cfg *action.ConfigFactory, recorder record.EventRecorder) *Install { + return &Install{configFactory: cfg, eventRecorder: recorder} +} + +func (r *Install) Reconcile(ctx context.Context, req *Request) error { + var ( + logBuf = action.NewLogBuffer(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), 10) + obsReleases = make(observedReleases) + cfg = r.configFactory.Build(logBuf.Log, observeRelease(obsReleases)) + ) + + defer summarize(req) + + // Mark install attempt on object. + req.Object.Status.LastAttemptedReleaseAction = v2.ReleaseActionInstall + + // An install is always considered a reset of any previous history. + // This ensures we never attempt to roll back to a previous release + // before the install. + req.Object.Status.ClearHistory() + + // Run the Helm install action. + _, err := action.Install(ctx, cfg, req.Object, req.Chart, req.Values) + + // Record the history of releases observed during the install. + obsReleases.recordOnObject(req.Object) + + if err != nil { + r.failure(req, logBuf, err) + + // Return error if we did not store a release, as this does not + // require remediation and the caller should e.g. retry. + if len(obsReleases) == 0 { + return err + } + + // Count install failure on object, this is used to determine if + // we should retry the install and/or remediation. We only count + // attempts which did cause a modification to the storage, as + // without a new release in storage there is nothing to remediate, + // and the action can be retried immediately without causing + // storage drift. + req.Object.GetInstall().GetRemediation().IncrementFailureCount(req.Object) + return nil + } + + r.success(req) + return nil +} + +func (r *Install) Name() string { + return "install" +} + +func (r *Install) Type() ReconcilerType { + return ReconcilerTypeRelease +} + +const ( + // fmtInstallFailure is the message format for an installation failure. + fmtInstallFailure = "Helm install failed for release %s/%s with chart %s@%s: %s" + // fmtInstallSuccess is the message format for a successful installation. + fmtInstallSuccess = "Helm install succeeded for release %s with chart %s" +) + +// failure records the failure of a Helm installation action in the status of +// the given Request.Object by marking ReleasedCondition=False and increasing +// the failure counter. In addition, it emits a warning event for the +// Request.Object. +// +// Increase of the failure counter for the active remediation strategy should +// be done conditionally by the caller after verifying the failed action has +// modified the Helm storage. This to avoid counting failures which do not +// result in Helm storage drift. +func (r *Install) failure(req *Request, buffer *action.LogBuffer, err error) { + // Compose failure message. + msg := fmt.Sprintf(fmtInstallFailure, req.Object.GetReleaseNamespace(), req.Object.GetReleaseName(), req.Chart.Name(), + req.Chart.Metadata.Version, strings.TrimSpace(err.Error())) + + // Mark install failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.InstallFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String()), + corev1.EventTypeWarning, + v2.InstallFailedReason, + eventMessageWithLog(msg, buffer), + ) +} + +// success records the success of a Helm installation action in the status of +// the given Request.Object by marking ReleasedCondition=True and emitting an +// event. In addition, it marks TestSuccessCondition=False when tests are +// enabled to indicate we are awaiting test results after having made the +// release. +func (r *Install) success(req *Request) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtInstallSuccess, cur.FullReleaseName(), cur.VersionedChartName()) + + // Mark install success on object. + conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.InstallSucceededReason, msg) + if req.Object.GetTest().Enable && !cur.HasBeenTested() { + conditions.MarkUnknown(req.Object, v2.TestSuccessCondition, "AwaitingTests", fmtTestPending, + cur.FullReleaseName(), cur.VersionedChartName()) + } + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + v2.InstallSucceededReason, + msg, + ) +} diff --git a/internal/reconcile/install_test.go b/internal/reconcile/install_test.go new file mode 100644 index 000000000..e15a02e8d --- /dev/null +++ b/internal/reconcile/install_test.go @@ -0,0 +1,420 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestInstall_Reconcile(t *testing.T) { + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(driver helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before install. + releases func(namespace string) []*helmrelease.Release + // chart to install. + chart *chart.Chart + // values to use during install. + values helmchartutil.Values + // spec modifies the HelmRelease object spec before install. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease object before install. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after install. + expectConditions []metav1.Condition + // expectHistory is the expected History of the HelmRelease after + // install. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "install success", + chart: testutil.BuildChart(), + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "install failure", + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.InstallFailedReason, + "failed post-install"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.InstallFailedReason, + "failed post-install"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + expectInstallFailures: 1, + }, + { + name: "install failure without storage update", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + CreateErr: fmt.Errorf("storage create error"), + } + }, + chart: testutil.BuildChart(), + wantErr: fmt.Errorf("storage create error"), + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.InstallFailedReason, + "storage create error"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.InstallFailedReason, + "storage create error"), + }, + expectFailures: 1, + expectInstallFailures: 0, + }, + { + name: "install with current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusUninstalled, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Install = &v2.Install{ + Replace: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + } + }, + }, + { + name: "install with stale current", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: "other", + Version: 1, + Status: helmrelease.StatusUninstalled, + Chart: testutil.BuildChart(), + }))), + }, + } + }, + chart: testutil.BuildChart(), + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, + "Helm install succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + releaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := (NewInstall(cfg, recorder)).Reconcile(context.TODO(), &Request{ + Object: obj, + Chart: tt.chart, + Values: tt.values, + }) + if tt.wantErr != nil { + g.Expect(got).To(Equal(tt.wantErr)) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + releaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestInstall_failure(t *testing.T) { + var ( + obj = &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: mockReleaseNamespace, + }, + } + chrt = testutil.BuildChart() + err = errors.New("installation error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Install{ + eventRecorder: recorder, + } + + req := &Request{Object: obj.DeepCopy(), Chart: chrt, Values: map[string]interface{}{"foo": "bar"}} + r.failure(req, nil, err) + + expectMsg := fmt.Sprintf(fmtInstallFailure, mockReleaseNamespace, mockReleaseName, chrt.Name(), + chrt.Metadata.Version, err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, v2.InstallFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.InstallFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(), + }, + }, + }, + })) + }) + + t.Run("records failure with logs", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Install{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy(), Chart: chrt} + r.failure(req, mockLogBuffer(5, 10), err) + + expectSubStr := "Last Helm logs" + g.Expect(conditions.IsFalse(req.Object, v2.ReleasedCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(req.Object, v2.ReleasedCondition)).ToNot(ContainSubstring(expectSubStr)) + + events := recorder.GetEvents() + g.Expect(events).To(HaveLen(1)) + g.Expect(events[0].Message).To(ContainSubstring(expectSubStr)) + }) +} + +func TestInstall_success(t *testing.T) { + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + ) + + t.Run("records success", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Install{ + eventRecorder: recorder, + } + + req := &Request{ + Object: obj.DeepCopy(), + } + r.success(req) + + expectMsg := fmt.Sprintf(fmtInstallSuccess, + fmt.Sprintf("%s/%s.v%d", mockReleaseNamespace, mockReleaseName, obj.Status.History.Latest().Version), + fmt.Sprintf("%s@%s", obj.Status.History.Latest().ChartName, obj.Status.History.Latest().ChartVersion)) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, expectMsg), + })) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.InstallSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): obj.Status.History.Latest().ChartVersion, + eventMetaGroupKey(eventv1.MetaTokenKey): obj.Status.History.Latest().ConfigDigest, + }, + }, + }, + })) + }) + + t.Run("records success with TestSuccess=False", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Install{ + eventRecorder: recorder, + } + + obj := obj.DeepCopy() + obj.Spec.Test = &v2.Test{Enable: true} + + req := &Request{Object: obj} + r.success(req) + + g.Expect(conditions.IsTrue(req.Object, v2.ReleasedCondition)).To(BeTrue()) + + cond := conditions.Get(req.Object, v2.TestSuccessCondition) + g.Expect(cond).ToNot(BeNil()) + + expectMsg := fmt.Sprintf(fmtTestPending, + fmt.Sprintf("%s/%s.v%d", mockReleaseNamespace, mockReleaseName, obj.Status.History.Latest().Version), + fmt.Sprintf("%s@%s", obj.Status.History.Latest().ChartName, obj.Status.History.Latest().ChartVersion)) + g.Expect(cond.Message).To(Equal(expectMsg)) + }) +} diff --git a/internal/reconcile/reconcile.go b/internal/reconcile/reconcile.go new file mode 100644 index 000000000..2565e57fc --- /dev/null +++ b/internal/reconcile/reconcile.go @@ -0,0 +1,99 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +const ( + // ReconcilerTypeRelease is an ActionReconciler which produces a new + // Helm release. + ReconcilerTypeRelease ReconcilerType = "release" + // ReconcilerTypeRemediate is an ActionReconciler which remediates a + // failed Helm release. + ReconcilerTypeRemediate ReconcilerType = "remediate" + // ReconcilerTypeTest is an ActionReconciler which tests a Helm release. + ReconcilerTypeTest ReconcilerType = "test" + // ReconcilerTypeUnlock is an ActionReconciler which unlocks a Helm + // release in a stale pending state. It differs from ReconcilerTypeRemediate + // in that it does not produce a new Helm release. + ReconcilerTypeUnlock ReconcilerType = "unlock" +) + +// ReconcilerType is a string which identifies the type of ActionReconciler. +// It can be used to e.g. limiting the number of action (types) to be performed +// in a single reconciliation. +type ReconcilerType string + +// ReconcilerTypeSet is a set of ReconcilerType. +type ReconcilerTypeSet []ReconcilerType + +// Contains returns true if the set contains the given type. +func (s ReconcilerTypeSet) Contains(t ReconcilerType) bool { + for _, r := range s { + if r == t { + return true + } + } + return false +} + +// Count returns the number of elements matching the given type. +func (s ReconcilerTypeSet) Count(t ReconcilerType) int { + count := 0 + for _, r := range s { + if r == t { + count++ + } + } + return count +} + +// Request is a request to be performed by an ActionReconciler. The reconciler +// writes the result of the request to the Object's status. +type Request struct { + // Object is the Helm release to be reconciled, and describes the desired + // state to the ActionReconciler. + Object *v2.HelmRelease + // Chart is the Helm chart to be installed or upgraded. + Chart *helmchart.Chart + // Values is the Helm chart values to be used for the installation or + // upgrade. + Values helmchartutil.Values +} + +// ActionReconciler is an interface which defines the methods that a reconciler +// of a Helm action must implement. +type ActionReconciler interface { + // Reconcile performs the reconcile action for the given Request. The + // reconciler should write the result of the request to the Object's status. + // An error is returned if the reconcile action cannot be performed and did + // not result in a modification of the Helm storage. The caller should then + // either retry, or abort the operation. + Reconcile(ctx context.Context, req *Request) error + // Name returns the name of the ActionReconciler. Typically, this equals + // the name of the Helm action it performs. + Name() string + // Type returns the ReconcilerType of the ActionReconciler. + Type() ReconcilerType +} diff --git a/internal/reconcile/release.go b/internal/reconcile/release.go new file mode 100644 index 000000000..5e89aeab2 --- /dev/null +++ b/internal/reconcile/release.go @@ -0,0 +1,249 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "errors" + "sort" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + helmrelease "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" +) + +var ( + // ErrNoLatest is returned when the HelmRelease has no latest release + // but this is required by the ActionReconciler. + ErrNoLatest = errors.New("no latest release") + // ErrNoPrevious is returned when the HelmRelease has no previous release + // but this is required by the ActionReconciler. + ErrNoPrevious = errors.New("no previous release") + // ErrReleaseMismatch is returned when the resulting release after running + // an action does not match the expected latest and/or previous release. + // This can happen for actions where targeting a release by version is not + // possible, for example while running tests. + ErrReleaseMismatch = errors.New("release mismatch") +) + +// observedReleases is a map of Helm releases as observed to be written to the +// Helm storage. The key is the version of the release. +type observedReleases map[int]release.Observation + +// sortedVersions returns the versions of the observed releases in descending +// order. +func (r observedReleases) sortedVersions() (versions []int) { + for ver := range r { + versions = append(versions, ver) + } + sort.Sort(sort.Reverse(sort.IntSlice(versions))) + return +} + +// recordOnObject records the observed releases on the HelmRelease object. +func (r observedReleases) recordOnObject(obj *v2.HelmRelease) { + switch len(r) { + case 0: + return + case 1: + var obs release.Observation + for _, o := range r { + obs = o + } + obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(obs)}, obj.Status.History...) + default: + versions := r.sortedVersions() + + obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(r[versions[0]])}, obj.Status.History...) + + for _, ver := range versions[1:] { + for i := range obj.Status.History { + snap := obj.Status.History[i] + if snap.Targets(r[ver].Name, r[ver].Namespace, r[ver].Version) { + newSnap := release.ObservedToSnapshot(r[ver]) + newSnap.SetTestHooks(snap.GetTestHooks()) + obj.Status.History[i] = newSnap + return + } + } + } + } +} + +// observeRelease returns a storage.ObserveFunc that stores the observed +// releases in the given observedReleases map. +// It can be used for Helm actions that modify multiple releases in the +// Helm storage, such as install and upgrade. +func observeRelease(observed observedReleases) storage.ObserveFunc { + return func(rls *helmrelease.Release) { + obs := release.ObserveRelease(rls) + observed[obs.Version] = obs + } +} + +// summarize composes a Ready condition out of the Remediated, TestSuccess and +// Released conditions of the given Request.Object, and sets it on the object. +// +// The composition is made by sorting them by highest generation and priority +// of the summary conditions, taking the first result. +// +// Not taking the generation of the object itself into account ensures that if +// the change in generation of the resource does not result in a release, the +// Ready condition is still reflected for the current generation based on a +// release made for the previous generation. +// +// It takes the current specification of the object into account, and deals +// with the conditional handling of TestSuccess. Deleting the condition when +// tests are not enabled, and excluding it when failures must be ignored. +// +// If Ready=True, any Stalled condition is removed. +func summarize(req *Request) { + var sumConds = []string{v2.RemediatedCondition, v2.ReleasedCondition} + if req.Object.GetTest().Enable && !req.Object.GetTest().IgnoreFailures { + sumConds = []string{v2.RemediatedCondition, v2.TestSuccessCondition, v2.ReleasedCondition} + } + + // Remove any stale TestSuccess condition as soon as tests are disabled. + if !req.Object.GetTest().Enable { + conditions.Delete(req.Object, v2.TestSuccessCondition) + } + + // Remove any stale Remediation observation as soon as the release is + // Released and (optionally) has TestSuccess. + conditionallyDeleteRemediated(req) + + conds := req.Object.Status.Conditions + if len(conds) == 0 { + // Nothing to summarize if there are no conditions. + return + } + + sort.SliceStable(conds, func(i, j int) bool { + iPos, ok := inStringSlice(sumConds, conds[i].Type) + if !ok { + return false + } + + jPos, ok := inStringSlice(sumConds, conds[j].Type) + if !ok { + return true + } + + return (conds[i].ObservedGeneration >= conds[j].ObservedGeneration) && (iPos < jPos) + }) + + status := conds[0].Status + + // Any remediated state is considered an error. + if conds[0].Type == v2.RemediatedCondition { + status = metav1.ConditionFalse + } + + if status == metav1.ConditionTrue { + conditions.Delete(req.Object, meta.StalledCondition) + } + + conditions.Set(req.Object, &metav1.Condition{ + Type: meta.ReadyCondition, + Status: status, + Reason: conds[0].Reason, + Message: conds[0].Message, + ObservedGeneration: req.Object.Generation, + }) +} + +// conditionallyDeleteRemediated removes the Remediated condition if the +// release is Released and (optionally) has TestSuccess. But only if +// the observed generation of these conditions is equal or higher than +// the generation of the Remediated condition. +func conditionallyDeleteRemediated(req *Request) { + remediated := conditions.Get(req.Object, v2.RemediatedCondition) + if remediated == nil { + // If the object is not marked as Remediated, there is nothing to + // remove. + return + } + + released := conditions.Get(req.Object, v2.ReleasedCondition) + if released == nil || released.Status != metav1.ConditionTrue { + // If the release is not marked as Released, we must still be + // Remediated. + return + } + + if !req.Object.GetTest().Enable || req.Object.GetTest().IgnoreFailures { + // If tests are not enabled, or failures are ignored, and the + // generation is equal or higher than the generation of the + // Remediated condition, we are not in a Remediated state anymore. + if released.Status == metav1.ConditionTrue && released.ObservedGeneration >= remediated.ObservedGeneration { + conditions.Delete(req.Object, v2.RemediatedCondition) + } + return + } + + testSuccess := conditions.Get(req.Object, v2.TestSuccessCondition) + if testSuccess == nil || testSuccess.Status != metav1.ConditionTrue { + // If the release is not marked as TestSuccess, we must still be + // Remediated. + return + } + + if testSuccess.Status == metav1.ConditionTrue && testSuccess.ObservedGeneration >= remediated.ObservedGeneration { + // If the release is marked as TestSuccess, and the generation of + // the TestSuccess condition is equal or higher than the generation + // of the Remediated condition, we are not in a Remediated state. + conditions.Delete(req.Object, v2.RemediatedCondition) + return + } +} + +// eventMessageWithLog returns an event message composed out of the given +// message and any log messages by appending them to the message. +func eventMessageWithLog(msg string, log *action.LogBuffer) string { + if log != nil && log.Len() > 0 { + msg = msg + "\n\nLast Helm logs:\n\n" + log.String() + } + return msg +} + +// eventMeta returns the event (annotation) metadata based on the given +// parameters. +func eventMeta(revision, token string) map[string]string { + var metadata map[string]string + if revision != "" || token != "" { + metadata = make(map[string]string) + if revision != "" { + metadata[eventMetaGroupKey(eventv1.MetaRevisionKey)] = revision + } + if token != "" { + metadata[eventMetaGroupKey(eventv1.MetaTokenKey)] = token + } + } + return metadata +} + +// eventMetaGroupKey returns the event (annotation) metadata key prefixed with +// the group. +func eventMetaGroupKey(key string) string { + return v2.GroupVersion.Group + "/" + key +} diff --git a/internal/reconcile/release_test.go b/internal/reconcile/release_test.go new file mode 100644 index 000000000..038c94309 --- /dev/null +++ b/internal/reconcile/release_test.go @@ -0,0 +1,667 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "reflect" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" +) + +const ( + mockReleaseName = "mock-release" + mockReleaseNamespace = "mock-ns" +) + +func Test_observedReleases_sortedVersions(t *testing.T) { + tests := []struct { + name string + r observedReleases + wantVersions []int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotVersions := tt.r.sortedVersions(); !reflect.DeepEqual(gotVersions, tt.wantVersions) { + t.Errorf("sortedVersions() = %v, want %v", gotVersions, tt.wantVersions) + } + }) + } +} + +func Test_summarize(t *testing.T) { + tests := []struct { + name string + generation int64 + spec *v2.HelmReleaseSpec + conditions []metav1.Condition + expect []metav1.Condition + }{ + { + 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, + }, + }, + }, + { + 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, + }, + }, + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + 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, + }, + }, + }, + { + 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, + }, + }, + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + 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, + }, + }, + }, + { + 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, + }, + }, + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + 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, + }, + }, + }, + { + 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, + }, + }, + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + 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, + }, + }, + }, + { + 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, + }, + }, + }, + { + 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, + }, + }, + }, + { + name: "with stale observed generation", + generation: 5, + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + 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, + }, + }, + }, + { + name: "with stale remediation", + spec: &v2.HelmReleaseSpec{ + Test: &v2.Test{ + Enable: true, + }, + }, + conditions: []metav1.Condition{ + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Rollback finished", + ObservedGeneration: 2, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 2, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hooks succeeded", + ObservedGeneration: 2, + }, + }, + expect: []metav1.Condition{ + { + Type: meta.ReadyCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hooks succeeded", + ObservedGeneration: 2, + }, + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "Upgrade finished", + ObservedGeneration: 2, + }, + { + Type: v2.TestSuccessCondition, + Status: metav1.ConditionTrue, + Reason: v2.TestSucceededReason, + Message: "test hooks succeeded", + ObservedGeneration: 2, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Generation: tt.generation, + }, + Status: v2.HelmReleaseStatus{ + Conditions: tt.conditions, + }, + } + if tt.spec != nil { + obj.Spec = *tt.spec.DeepCopy() + } + summarize(&Request{Object: obj}) + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expect)) + }) + } +} + +func Test_conditionallyDeleteRemediated(t *testing.T) { + tests := []struct { + name string + spec v2.HelmReleaseSpec + conditions []metav1.Condition + expectDelete bool + }{ + { + name: "no Remediated condition", + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, "Install finished"), + }, + expectDelete: false, + }, + { + name: "no Released condition", + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + }, + expectDelete: false, + }, + { + name: "Released=True without tests enabled", + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + }, + expectDelete: true, + }, + { + name: "Stale Released=True with newer Remediated", + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Rollback finished", + ObservedGeneration: 2, + }, + }, + expectDelete: false, + }, + { + name: "Released=False", + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UpgradeFailedReason, "Upgrade failed"), + }, + expectDelete: false, + }, + { + name: "TestSuccess=True with tests enabled", + spec: v2.HelmReleaseSpec{ + Test: &v2.Test{ + Enable: true, + }, + }, + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + *conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, "Test hooks succeeded"), + }, + expectDelete: true, + }, + { + name: "TestSuccess=False with tests enabled", + spec: v2.HelmReleaseSpec{ + Test: &v2.Test{ + Enable: true, + }, + }, + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + *conditions.FalseCondition(v2.TestSuccessCondition, v2.TestSucceededReason, "Test hooks succeeded"), + }, + expectDelete: false, + }, + { + name: "TestSuccess=False with tests ignored", + spec: v2.HelmReleaseSpec{ + Test: &v2.Test{ + Enable: true, + IgnoreFailures: true, + }, + }, + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "Rollback finished"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + *conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason, "Test hooks failed"), + }, + expectDelete: true, + }, + { + name: "Stale TestSuccess=True with newer Remediated", + spec: v2.HelmReleaseSpec{ + Test: &v2.Test{ + Enable: true, + }, + }, + conditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Upgrade finished"), + *conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, "Test hooks succeeded"), + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "Rollback finished", + ObservedGeneration: 2, + }, + }, + expectDelete: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Spec: tt.spec, + Status: v2.HelmReleaseStatus{ + Conditions: tt.conditions, + }, + } + isRemediated := conditions.Has(obj, v2.RemediatedCondition) + + conditionallyDeleteRemediated(&Request{Object: obj}) + + if tt.expectDelete { + g.Expect(isRemediated).ToNot(Equal(conditions.Has(obj, v2.RemediatedCondition))) + return + } + + g.Expect(conditions.Has(obj, v2.RemediatedCondition)).To(Equal(isRemediated)) + }) + } +} + +func mockLogBuffer(size int, lines int) *action.LogBuffer { + log := action.NewLogBuffer(action.NewDebugLog(logr.Discard()), size) + for i := 0; i < lines; i++ { + log.Log("line %d", i+1) + } + return log +} diff --git a/internal/reconcile/rollback_remediation.go b/internal/reconcile/rollback_remediation.go new file mode 100644 index 000000000..755bf7434 --- /dev/null +++ b/internal/reconcile/rollback_remediation.go @@ -0,0 +1,195 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + "strings" + + helmrelease "helm.sh/helm/v3/pkg/release" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/logger" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" +) + +// RollbackRemediation is an ActionReconciler which attempts to roll back +// a Request.Object to a previous successful deployed release in the +// Status.History. +// +// The writes to the Helm storage during the rollback are observed, and update +// the Status.History field. +// +// After a successful rollback, the object is marked with Remediated=True and +// an event is emitted. When the rollback fails, the object is marked with +// Remediated=False and a warning event is emitted. +// +// When the Request.Object does not have a (successful) previous deployed +// release, it returns an error of type ErrNoPrevious. In addition, it +// returns ErrReleaseMismatch if the name and/or namespace of the latest and +// previous release do not match. Any other returned error indicates the caller +// should retry as it did not cause a change to the Helm storage. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type RollbackRemediation struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewRollbackRemediation returns a new RollbackRemediation reconciler +// configured with the provided values. +func NewRollbackRemediation(configFactory *action.ConfigFactory, eventRecorder record.EventRecorder) *RollbackRemediation { + return &RollbackRemediation{ + configFactory: configFactory, + eventRecorder: eventRecorder, + } +} + +func (r *RollbackRemediation) Reconcile(ctx context.Context, req *Request) error { + var ( + cur = req.Object.Status.History.Latest().DeepCopy() + logBuf = action.NewLogBuffer(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), 10) + cfg = r.configFactory.Build(logBuf.Log, observeRollback(req.Object)) + ) + + defer summarize(req) + + // Previous is required to determine what version to roll back to. + prev := req.Object.Status.History.Previous(req.Object.GetUpgrade().GetRemediation().MustIgnoreTestFailures(req.Object.GetTest().IgnoreFailures)) + if prev == nil { + return fmt.Errorf("%w: required to rollback", ErrNoPrevious) + } + + // Confirm previous and current point to the same release. + if prev.Name != cur.Name || prev.Namespace != cur.Namespace { + return fmt.Errorf("%w: previous release name or namespace %s does not match current %s", + ErrReleaseMismatch, prev.FullReleaseName(), cur.FullReleaseName()) + } + + // Run the Helm rollback action. + if err := action.Rollback(cfg, req.Object, prev.Name, action.RollbackToVersion(prev.Version)); err != nil { + r.failure(req, prev, logBuf, err) + + // Return error if we did not store a release, as this does not + // affect state and the caller should e.g. retry. + if newCur := req.Object.Status.History.Latest(); newCur == nil || (cur != nil && newCur.Digest == cur.Digest) { + return err + } + + return nil + } + + r.success(req, prev) + return nil +} + +func (r *RollbackRemediation) Name() string { + return "rollback" +} + +func (r *RollbackRemediation) Type() ReconcilerType { + return ReconcilerTypeRemediate +} + +const ( + // fmtRollbackRemediationFailure is the message format for a rollback + // remediation failure. + fmtRollbackRemediationFailure = "Helm rollback to previous release %s with chart %s failed: %s" + // fmtRollbackRemediationSuccess is the message format for a successful + // rollback remediation. + fmtRollbackRemediationSuccess = "Helm rollback to previous release %s with chart %s succeeded" +) + +// failure records the failure of a Helm rollback action in the status of the +// given Request.Object by marking Remediated=False and emitting a warning +// event. +func (r *RollbackRemediation) failure(req *Request, prev *v2.Snapshot, buffer *action.LogBuffer, err error) { + // Compose failure message. + msg := fmt.Sprintf(fmtRollbackRemediationFailure, prev.FullReleaseName(), prev.VersionedChartName(), strings.TrimSpace(err.Error())) + + // Mark remediation failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.RemediatedCondition, v2.RollbackFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String()), + corev1.EventTypeWarning, + v2.RollbackFailedReason, + eventMessageWithLog(msg, buffer), + ) +} + +// success records the success of a Helm rollback action in the status of the +// given Request.Object by marking Remediated=True and emitting an event. +func (r *RollbackRemediation) success(req *Request, prev *v2.Snapshot) { + // Compose success message. + msg := fmt.Sprintf(fmtRollbackRemediationSuccess, prev.FullReleaseName(), prev.VersionedChartName()) + + // Mark remediation success on object. + conditions.MarkTrue(req.Object, v2.RemediatedCondition, v2.RollbackSucceededReason, msg) + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String()), + corev1.EventTypeNormal, + v2.RollbackSucceededReason, + msg, + ) +} + +// observeRollback returns a storage.ObserveFunc to track the rollback history +// of a HelmRelease. +// It observes the rollback action of a Helm release by comparing the release +// history with the recorded snapshots. +// If the rolled-back release matches a snapshot, it updates the snapshot with +// the observed release data. +// If no matching snapshot is found, it creates a new snapshot and prepends it +// to the release history. +func observeRollback(obj *v2.HelmRelease) storage.ObserveFunc { + return func(rls *helmrelease.Release) { + for i := range obj.Status.History { + snap := obj.Status.History[i] + if snap.Targets(rls.Name, rls.Namespace, rls.Version) { + newSnap := release.ObservedToSnapshot(release.ObserveRelease(rls)) + newSnap.SetTestHooks(snap.GetTestHooks()) + obj.Status.History[i] = newSnap + return + } + } + + obs := release.ObserveRelease(rls) + obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(obs)}, obj.Status.History...) + } +} diff --git a/internal/reconcile/rollback_remediation_test.go b/internal/reconcile/rollback_remediation_test.go new file mode 100644 index 000000000..cf8e23906 --- /dev/null +++ b/internal/reconcile/rollback_remediation_test.go @@ -0,0 +1,616 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" + "time" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + helmreleaseutil "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestRollbackRemediation_Reconcile(t *testing.T) { + var ( + mockCreateErr = fmt.Errorf("storage create error") + mockUpdateErr = fmt.Errorf("storage update error") + ) + + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(driver helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before rollback. + releases func(namespace string) []*helmrelease.Release + // spec modifies the HelmRelease object's spec before rollback. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease before rollback. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after rolling back. + expectConditions []metav1.Condition + // expectHistory is the expected History on the HelmRelease after + // rolling back. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count on the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count on the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count on the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "rollback", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + Namespace: namespace, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + Namespace: namespace, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.RollbackSucceededReason, "succeeded"), + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, "succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "rollback without previous", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + Namespace: namespace, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + Namespace: namespace, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + }, + } + }, + wantErr: ErrNoPrevious, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + } + }, + }, + { + name: "rollback failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + Status: helmrelease.StatusSuperseded, + Namespace: namespace, + }, testutil.ReleaseWithFailingHook()), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + Namespace: namespace, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.RollbackFailedReason, + "timed out waiting for the condition"), + *conditions.FalseCondition(v2.RemediatedCondition, v2.RollbackFailedReason, + "timed out waiting for the condition"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "rollback with storage create error", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + CreateErr: mockCreateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + Namespace: namespace, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + Namespace: namespace, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + wantErr: mockCreateErr, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.RollbackFailedReason, + mockCreateErr.Error()), + *conditions.FalseCondition(v2.RemediatedCondition, v2.RollbackFailedReason, + mockCreateErr.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "rollback with storage update error", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + UpdateErr: mockUpdateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusSuperseded, + Namespace: namespace, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + Namespace: namespace, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.RollbackFailedReason, + "storage update error"), + *conditions.FalseCondition(v2.RemediatedCondition, v2.RollbackFailedReason, + "storage update error"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + helmreleaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := (NewRollbackRemediation(cfg, recorder)).Reconcile(context.TODO(), &Request{ + Object: obj, + }) + if tt.wantErr != nil { + g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue()) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + helmreleaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestRollbackRemediation_failure(t *testing.T) { + var ( + prev = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(prev)), + }, + }, + } + err = errors.New("rollback error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &RollbackRemediation{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy()} + r.failure(req, release.ObservedToSnapshot(release.ObserveRelease(prev)), nil, err) + + expectMsg := fmt.Sprintf(fmtRollbackRemediationFailure, + fmt.Sprintf("%s/%s.v%d", prev.Namespace, prev.Name, prev.Version), + fmt.Sprintf("%s@%s", prev.Chart.Name(), prev.Chart.Metadata.Version), + strings.TrimSpace(err.Error())) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.RollbackFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.RollbackFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): prev.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(), + }, + }, + }, + })) + }) + + t.Run("records failure with logs", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &RollbackRemediation{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy()} + r.failure(req, release.ObservedToSnapshot(release.ObserveRelease(prev)), mockLogBuffer(5, 10), err) + + expectSubStr := "Last Helm logs" + g.Expect(conditions.IsFalse(req.Object, v2.RemediatedCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(req.Object, v2.RemediatedCondition)).ToNot(ContainSubstring(expectSubStr)) + + events := recorder.GetEvents() + g.Expect(events).To(HaveLen(1)) + g.Expect(events[0].Message).To(ContainSubstring(expectSubStr)) + }) +} + +func TestRollbackRemediation_success(t *testing.T) { + g := NewWithT(t) + + var prev = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Chart: testutil.BuildChart(), + Version: 4, + }) + + recorder := testutil.NewFakeRecorder(10, false) + r := &RollbackRemediation{ + eventRecorder: recorder, + } + req := &Request{Object: &v2.HelmRelease{}, Values: map[string]interface{}{"foo": "bar"}} + r.success(req, release.ObservedToSnapshot(release.ObserveRelease(prev))) + + expectMsg := fmt.Sprintf(fmtRollbackRemediationSuccess, + fmt.Sprintf("%s/%s.v%d", prev.Namespace, prev.Name, prev.Version), + fmt.Sprintf("%s@%s", prev.Chart.Name(), prev.Chart.Metadata.Version)) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.RollbackSucceededReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(0))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.RollbackSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): prev.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(), + }, + }, + }, + })) +} + +func Test_observeRollback(t *testing.T) { + t.Run("rollback", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{} + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusPendingRollback, + }) + observeRollback(obj)(rls) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + expect, + })) + }) + + t.Run("rollback with latest", func(t *testing.T) { + g := NewWithT(t) + + latest := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusFailed.String(), + } + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + latest, + }, + }, + } + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: latest.Name, + Namespace: latest.Namespace, + Version: latest.Version + 1, + Status: helmrelease.StatusPendingRollback, + }) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + + observeRollback(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + expect, + latest, + })) + }) + + t.Run("rollback with update to previous deployed", func(t *testing.T) { + g := NewWithT(t) + + previous := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusFailed.String(), + } + latest := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 3, + Status: helmrelease.StatusDeployed.String(), + } + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + latest, + previous, + }, + }, + } + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: previous.Name, + Namespace: previous.Namespace, + Version: previous.Version, + Status: helmrelease.StatusSuperseded, + }) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + + observeRollback(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + latest, + expect, + })) + }) + + t.Run("rollback with update to previous deployed copies existing test hooks", func(t *testing.T) { + g := NewWithT(t) + + previous := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusFailed.String(), + TestHooks: &map[string]*v2.TestHookStatus{ + "test-hook": { + Phase: helmrelease.HookPhaseSucceeded.String(), + }, + }, + } + latest := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 3, + Status: helmrelease.StatusDeployed.String(), + } + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + latest, + previous, + }, + }, + } + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: previous.Name, + Namespace: previous.Namespace, + Version: previous.Version, + Status: helmrelease.StatusSuperseded, + }) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + expect.SetTestHooks(previous.GetTestHooks()) + + observeRollback(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + latest, + expect, + })) + }) +} diff --git a/internal/reconcile/state.go b/internal/reconcile/state.go new file mode 100644 index 000000000..ca9b04331 --- /dev/null +++ b/internal/reconcile/state.go @@ -0,0 +1,153 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "errors" + "fmt" + + helmrelease "helm.sh/helm/v3/pkg/release" + + "github.com/fluxcd/helm-controller/internal/action" + interrors "github.com/fluxcd/helm-controller/internal/errors" +) + +// ReleaseStatus represents the status of a Helm release as determined by +// comparing the Helm storage with the v2beta2.HelmRelease object. +type ReleaseStatus string + +// String returns the string representation of the release status. +func (s ReleaseStatus) String() string { + return string(s) +} + +const ( + // ReleaseStatusUnknown indicates that the status of the release could not + // be determined. + ReleaseStatusUnknown ReleaseStatus = "Unknown" + // ReleaseStatusAbsent indicates that the release is not present in the + // Helm storage. + ReleaseStatusAbsent ReleaseStatus = "Absent" + // ReleaseStatusUnmanaged indicates that the release is present in the Helm + // storage, but is not managed by the v2beta2.HelmRelease object. + ReleaseStatusUnmanaged ReleaseStatus = "Unmanaged" + // ReleaseStatusOutOfSync indicates that the release is present in the Helm + // storage, but is not in sync with the v2beta2.HelmRelease object. + ReleaseStatusOutOfSync ReleaseStatus = "OutOfSync" + // ReleaseStatusLocked indicates that the release is present in the Helm + // storage, but is locked. + ReleaseStatusLocked ReleaseStatus = "Locked" + // ReleaseStatusUntested indicates that the release is present in the Helm + // storage, but has not been tested. + ReleaseStatusUntested ReleaseStatus = "Untested" + // ReleaseStatusInSync indicates that the release is present in the Helm + // storage, and is in sync with the v2beta2.HelmRelease object. + ReleaseStatusInSync ReleaseStatus = "InSync" + // ReleaseStatusFailed indicates that the release is present in the Helm + // storage, but has failed. + ReleaseStatusFailed ReleaseStatus = "Failed" +) + +// ReleaseState represents the state of a Helm release as determined by +// comparing the Helm storage with the v2beta2.HelmRelease object. +type ReleaseState struct { + // Status is the status of the release. + Status ReleaseStatus + // Reason for the Status. + Reason string +} + +// DetermineReleaseState determines the state of the Helm release as compared +// to the v2beta2.HelmRelease object. It returns a ReleaseState that indicates +// the status of the release, and an error if the state could not be determined. +func DetermineReleaseState(cfg *action.ConfigFactory, req *Request) (ReleaseState, error) { + rls, err := action.LastRelease(cfg.Build(nil), req.Object.GetReleaseName()) + if err != nil { + if errors.Is(err, action.ErrReleaseNotFound) { + return ReleaseState{Status: ReleaseStatusAbsent, Reason: "no release in storage for object"}, nil + } + return ReleaseState{Status: ReleaseStatusUnknown}, fmt.Errorf("failed to retrieve last release from storage: %w", err) + } + + // If the release is in a pending state, it must be unlocked before any + // further action can be taken. + if rls.Info.Status.IsPending() { + return ReleaseState{Status: ReleaseStatusLocked, Reason: fmt.Sprintf("release with status '%s'", rls.Info.Status)}, err + } + + // Confirm we have a release object to compare against. + if req.Object.Status.History.Len() == 0 { + if rls.Info.Status == helmrelease.StatusUninstalled { + return ReleaseState{Status: ReleaseStatusAbsent, Reason: "found uninstalled release in storage"}, nil + } + return ReleaseState{Status: ReleaseStatusUnmanaged, Reason: "found existing release in storage"}, err + } + + // Verify the release object against the state we observed during our + // last reconciliation. + cur := req.Object.Status.History.Latest() + if err := action.VerifyReleaseObject(cur, rls); err != nil { + if interrors.IsOneOf(err, action.ErrReleaseDigest, action.ErrReleaseNotObserved) { + // The release object has been mutated in such a way that we are + // unable to determine the state of the release. + // Effectively, this means that the object no longer manages the + // release, and we should e.g. perform an upgrade to bring + // the release back in-sync and under management. + return ReleaseState{Status: ReleaseStatusUnmanaged, Reason: err.Error()}, nil + } + return ReleaseState{Status: ReleaseStatusUnknown}, fmt.Errorf("failed to verify release object: %w", err) + } + + // Further determine the state of the release based on the Helm release + // status, which can now be considered reliable. + switch rls.Info.Status { + case helmrelease.StatusFailed: + return ReleaseState{Status: ReleaseStatusFailed}, nil + case helmrelease.StatusUninstalled: + return ReleaseState{Status: ReleaseStatusAbsent, Reason: fmt.Sprintf("found uninstalled release in storage")}, nil + case helmrelease.StatusDeployed: + // Verify the release is in sync with the desired configuration. + if err = action.VerifyRelease(rls, cur, req.Chart.Metadata, req.Values); err != nil { + switch err { + case action.ErrChartChanged, action.ErrConfigDigest: + return ReleaseState{Status: ReleaseStatusOutOfSync, Reason: err.Error()}, nil + default: + return ReleaseState{Status: ReleaseStatusUnknown}, err + } + } + + // For the further determination of test results, we look at the + // observed state of the object. As tests can be run manually by + // users running e.g. `helm test`. + if testSpec := req.Object.GetTest(); testSpec.Enable { + // Confirm the release has been tested if enabled. + if !cur.HasBeenTested() { + return ReleaseState{Status: ReleaseStatusUntested}, nil + } + + // Act on any observed test failure. + remediation := req.Object.GetActiveRemediation() + if remediation != nil && !remediation.MustIgnoreTestFailures(testSpec.IgnoreFailures) && cur.HasTestInPhase(helmrelease.HookPhaseFailed.String()) { + return ReleaseState{Status: ReleaseStatusFailed, Reason: "release has test in failed phase"}, nil + } + } + + return ReleaseState{Status: ReleaseStatusInSync}, nil + default: + return ReleaseState{Status: ReleaseStatusUnknown}, fmt.Errorf("unable to determine state for release with status '%s'", rls.Info.Status) + } +} diff --git a/internal/reconcile/state_test.go b/internal/reconcile/state_test.go new file mode 100644 index 000000000..a4a3b9c64 --- /dev/null +++ b/internal/reconcile/state_test.go @@ -0,0 +1,496 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "testing" + + . "github.com/onsi/gomega" + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/kube" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func Test_DetermineReleaseState(t *testing.T) { + tests := []struct { + name string + releases []*helmrelease.Release + spec func(spec *v2.HelmReleaseSpec) + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + chart *helmchart.Chart + values helmchartutil.Values + want ReleaseState + wantErr bool + }{ + { + name: "in-sync release", + 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"})), + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusInSync, + }, + }, + { + name: "no release in storage", + releases: nil, + want: ReleaseState{ + Status: ReleaseStatusAbsent, + }, + }, + { + name: "release disappeared from storage", + status: func(_ []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }))), + }, + } + }, + want: ReleaseState{ + Status: ReleaseStatusAbsent, + }, + }, + { + name: "existing release without current", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }), + }, + want: ReleaseState{ + Status: ReleaseStatusUnmanaged, + }, + }, + { + name: "release digest parse error", + 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"})), + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + cur := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + cur.Digest = "sha256:invalid" + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + cur, + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusUnmanaged, + }, + }, + { + name: "release digest mismatch", + 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"})), + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + cur := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + // Digest for empty string is always mismatch + cur.Digest = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + cur, + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusUnmanaged, + }, + }, + { + name: "release in pending state", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusPendingInstall, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusLocked, + }, + }, + { + name: "untested release", + 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.Test = &v2.Test{ + Enable: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusUntested, + }, + }, + { + name: "failed test", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + testutil.BuildRelease( + &helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }, + testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"}), + testutil.ReleaseWithHookExecution("failure-tests", []helmrelease.HookEvent{helmrelease.HookTest}, + helmrelease.HookPhaseFailed), + ), + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Test = &v2.Test{ + Enable: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + cur := release.ObservedToSnapshot(release.ObserveRelease(releases[1])) + cur.SetTestHooks(release.TestHooksFromRelease(releases[1])) + + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + cur, + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusFailed, + }, + }, + { + name: "failed test with ignore failures set", + releases: []*helmrelease.Release{ + testutil.BuildRelease( + &helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }, + testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"}), + testutil.ReleaseWithHookExecution("failure-tests", []helmrelease.HookEvent{helmrelease.HookTest}, + helmrelease.HookPhaseFailed), + ), + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Test = &v2.Test{ + Enable: true, + IgnoreFailures: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + cur := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + cur.SetTestHooks(release.TestHooksFromRelease(releases[0])) + + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + cur, + }, + LastAttemptedReleaseAction: v2.ReleaseActionInstall, + } + }, + want: ReleaseState{ + Status: ReleaseStatusInSync, + }, + }, + { + name: "failed test is ignored when not made by controller", + releases: []*helmrelease.Release{ + testutil.BuildRelease( + &helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }, + testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"}), + testutil.ReleaseWithHookExecution("failure-tests", []helmrelease.HookEvent{helmrelease.HookTest}, + helmrelease.HookPhaseFailed), + ), + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"foo": "bar"}, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Test = &v2.Test{ + Enable: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + want: ReleaseState{ + Status: ReleaseStatusUntested, + }, + }, + { + name: "failed release", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusSuperseded, + Chart: testutil.BuildChart(), + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + Status: helmrelease.StatusFailed, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + want: ReleaseState{ + Status: ReleaseStatusFailed, + }, + }, + { + name: "uninstalled release", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusUninstalled, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{}, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + want: ReleaseState{ + Status: ReleaseStatusAbsent, + }, + }, + { + name: "uninstalled release without current", + releases: []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusUninstalled, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"})), + }, + want: ReleaseState{ + Status: ReleaseStatusAbsent, + }, + }, + { + name: "chart 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"})), + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(testutil.ChartWithName("other-name")), + values: map[string]interface{}{"foo": "bar"}, + want: ReleaseState{ + Status: ReleaseStatusOutOfSync, + }, + }, + { + name: "values 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"})), + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + chart: testutil.BuildChart(), + values: map[string]interface{}{"bar": "foo"}, + want: ReleaseState{ + Status: ReleaseStatusOutOfSync, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: mockReleaseNamespace, + StorageNamespace: mockReleaseNamespace, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(tt.releases) + } + + cfg, err := action.NewConfigFactory(&kube.MemoryRESTClientGetter{}, + action.WithStorage(helmdriver.MemoryDriverName, mockReleaseNamespace), + ) + g.Expect(err).ToNot(HaveOccurred()) + + if len(tt.releases) > 0 { + store := helmstorage.Init(cfg.Driver) + for _, i := range tt.releases { + g.Expect(store.Create(i)).To(Succeed()) + } + } + + got, err := DetermineReleaseState(cfg, &Request{ + Object: obj, + Chart: tt.chart, + Values: tt.values, + }) + if tt.wantErr { + g.Expect(got).To(BeNil()) + g.Expect(err).To(HaveOccurred()) + return + } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got.Status).To(Equal(tt.want.Status)) + g.Expect(got.Reason).To(ContainSubstring(tt.want.Reason)) + }) + } +} diff --git a/internal/reconcile/suite_test.go b/internal/reconcile/suite_test.go new file mode 100644 index 000000000..ab059265c --- /dev/null +++ b/internal/reconcile/suite_test.go @@ -0,0 +1,151 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "helm.sh/helm/v3/pkg/kube" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/fluxcd/pkg/runtime/testenv" + + sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" +) + +const testFieldManager = "helm-controller" + +var ( + ctx = ctrl.SetupSignalHandler() + testEnv *testenv.Environment +) + +func NewTestScheme() *runtime.Scheme { + s := runtime.NewScheme() + utilruntime.Must(corev1.AddToScheme(s)) + utilruntime.Must(apiextensionsv1.AddToScheme(s)) + utilruntime.Must(sourcev1.AddToScheme(s)) + utilruntime.Must(v2.AddToScheme(s)) + return s +} + +func TestMain(m *testing.M) { + testEnv = testenv.New( + testenv.WithCRDPath( + filepath.Join("..", "..", "build", "config", "crd", "bases"), + filepath.Join("..", "..", "config", "crd", "bases"), + ), + testenv.WithScheme(NewTestScheme()), + ) + + go func() { + fmt.Println("Starting the test environment") + if err := testEnv.Start(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the test environment manager: %v", err)) + } + }() + <-testEnv.Manager.Elected() + + // Globally configure field manager for all tests. + kube.ManagedFieldsManager = "reconciler-tests" + + code := m.Run() + + fmt.Println("Stopping the test environment") + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop the test environment: %v", err)) + } + os.Exit(code) +} + +type managerRESTClientGetter struct { + restConfig *rest.Config + discoveryClient discovery.CachedDiscoveryInterface + restMapper meta.RESTMapper + namespaceConfig clientcmd.ClientConfig +} + +func RESTClientGetterFromManager(mgr manager.Manager, ns string) (genericclioptions.RESTClientGetter, error) { + cfg := mgr.GetConfig() + dc, err := discovery.NewDiscoveryClientForConfig(cfg) + if err != nil { + return nil, err + } + cdc := memory.NewMemCacheClient(dc) + rm := mgr.GetRESTMapper() + return &managerRESTClientGetter{ + restConfig: cfg, + discoveryClient: cdc, + restMapper: rm, + namespaceConfig: &namespaceClientConfig{ns}, + }, nil +} + +func (c *managerRESTClientGetter) ToRESTConfig() (*rest.Config, error) { + return c.restConfig, nil +} + +func (c *managerRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + return c.discoveryClient, nil +} + +func (c *managerRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + return c.restMapper, nil +} + +func (c *managerRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { + return c.namespaceConfig +} + +var _ clientcmd.ClientConfig = &namespaceClientConfig{} + +type namespaceClientConfig struct { + namespace string +} + +func (c namespaceClientConfig) RawConfig() (clientcmdapi.Config, error) { + return clientcmdapi.Config{}, nil +} + +func (c namespaceClientConfig) ClientConfig() (*rest.Config, error) { + return nil, nil +} + +func (c namespaceClientConfig) Namespace() (string, bool, error) { + return c.namespace, false, nil +} + +func (c namespaceClientConfig) ConfigAccess() clientcmd.ConfigAccess { + return nil +} diff --git a/internal/reconcile/test.go b/internal/reconcile/test.go new file mode 100644 index 000000000..f40a3d4cf --- /dev/null +++ b/internal/reconcile/test.go @@ -0,0 +1,207 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + "strings" + + "github.com/fluxcd/pkg/runtime/logger" + helmrelease "helm.sh/helm/v3/pkg/release" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" +) + +// Test is an ActionReconciler which attempts to perform a Helm test for +// the latest release of the Request.Object. +// +// The writes to the Helm storage during testing are observed, which causes the +// TestHooks field of the latest Snapshot in the Status.History to be updated +// if it matches the target of the test. +// +// When all test hooks for the release succeed, the object is marked with +// TestSuccess=True and an event is emitted. When one of the test hooks fails, +// Helm stops running the remaining tests, and the object is marked with +// TestSuccess=False and a warning event is emitted. If test failures are not +// ignored, the failure count for the active remediation strategy is +// incremented. +// +// When the Request.Object does not have a latest release, it returns an +// error of type ErrNoLatest. In addition, it returns ErrReleaseMismatch +// if the test ran for a different release target than the latest release. +// Any other returned error indicates the caller should retry as it did not cause +// a change to the Helm storage. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type Test struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewTest returns a new Test reconciler configured with the provided values. +func NewTest(cfg *action.ConfigFactory, recorder record.EventRecorder) *Test { + return &Test{configFactory: cfg, eventRecorder: recorder} +} + +func (r *Test) Reconcile(ctx context.Context, req *Request) error { + var ( + cur = req.Object.Status.History.Latest().DeepCopy() + cfg = r.configFactory.Build(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), observeTest(req.Object)) + ) + + defer summarize(req) + + // We only accept test results for the current release. + if cur == nil { + return fmt.Errorf("%w: required for test", ErrNoLatest) + } + + // Run the Helm test action. + rls, err := action.Test(ctx, cfg, req.Object) + + // The Helm test action does always target the latest release. Before + // accepting results, we need to confirm this is actually the release we + // have recorded as latest. + if rls != nil && !release.ObserveRelease(rls).Targets(cur.Name, cur.Namespace, cur.Version) { + err = fmt.Errorf("%w: tested release %s/%s.v%d != current release %s/%s.v%d", + ErrReleaseMismatch, rls.Namespace, rls.Name, rls.Version, cur.Namespace, cur.Name, cur.Version) + } + + // Something went wrong. + if err != nil { + r.failure(req, err) + + // If we failed to observe anything happened at all, we want to retry + // and return the error to indicate this. + if !req.Object.Status.History.Latest().HasBeenTested() { + return err + } + return nil + } + + r.success(req) + return nil +} + +func (r *Test) Name() string { + return "test" +} + +func (r *Test) Type() ReconcilerType { + return ReconcilerTypeTest +} + +const ( + // fmtTestPending is the message format used when awaiting tests to be run. + fmtTestPending = "Helm release %s with chart %s is awaiting tests" + // fmtTestFailure is the message format for a test failure. + fmtTestFailure = "Helm test failed for release %s with chart %s: %s" + // fmtTestSuccess is the message format for a successful test. + fmtTestSuccess = "Helm test succeeded for release %s with chart %s: %s" +) + +// failure records the failure of a Helm test action in the status of the given +// Request.Object by marking TestSuccess=False and increasing the failure +// counter. In addition, it emits a warning event for the Request.Object. +// The active remediation failure count is only incremented if test failures +// are not ignored. +func (r *Test) failure(req *Request, err error) { + // Compose failure message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtTestFailure, cur.FullReleaseName(), cur.VersionedChartName(), strings.TrimSpace(err.Error())) + + // Mark test failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.TestSuccessCondition, v2.TestFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeWarning, + v2.TestFailedReason, + msg, + ) + + if req.Object.Status.History.Latest().HasBeenTested() { + // Count the failure of the test for the active remediation strategy if enabled. + remediation := req.Object.GetActiveRemediation() + if remediation != nil && !remediation.MustIgnoreTestFailures(req.Object.GetTest().IgnoreFailures) { + remediation.IncrementFailureCount(req.Object) + } + } +} + +// success records the failure of a Helm test action in the status of the given +// Request.Object by marking TestSuccess=True and emitting an event. +func (r *Test) success(req *Request) { + // Compose success message. + cur := req.Object.Status.History.Latest() + var hookMsg = "no test hooks" + if l := len(cur.GetTestHooks()); l > 0 { + h := "hook" + if l > 1 { + h += "s" + } + hookMsg = fmt.Sprintf("%d test %s completed successfully", l, h) + } + msg := fmt.Sprintf(fmtTestSuccess, cur.FullReleaseName(), cur.VersionedChartName(), hookMsg) + + // Mark test success on object. + conditions.MarkTrue(req.Object, v2.TestSuccessCondition, v2.TestSucceededReason, msg) + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + v2.TestSucceededReason, + msg, + ) +} + +// observeTest returns a storage.ObserveFunc to track test results of a +// HelmRelease. +// It only accepts test results for the latest release and updates the +// latest snapshot with the observed test results. +func observeTest(obj *v2.HelmRelease) storage.ObserveFunc { + return func(rls *helmrelease.Release) { + // Only accept test results for the latest release. + if !obj.Status.History.Latest().Targets(rls.Name, rls.Namespace, rls.Version) { + return + } + + // Update the latest snapshot with the test result. + tested := release.ObservedToSnapshot(release.ObserveRelease(rls)) + tested.SetTestHooks(release.TestHooksFromRelease(rls)) + obj.Status.History[0] = tested + } +} diff --git a/internal/reconcile/test_test.go b/internal/reconcile/test_test.go new file mode 100644 index 000000000..d97dbe0c9 --- /dev/null +++ b/internal/reconcile/test_test.go @@ -0,0 +1,593 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + helmreleaseutil "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +// testHookFixtures is a list of release.Hook in every possible LastRun state. +var testHookFixtures = []*helmrelease.Hook{ + { + Name: "never-run-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + }, + { + Name: "passing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + StartedAt: testutil.MustParseHelmTime("2006-01-02T15:04:05Z"), + CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:04:07Z"), + Phase: helmrelease.HookPhaseSucceeded, + }, + }, + { + Name: "failing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + StartedAt: testutil.MustParseHelmTime("2006-01-02T15:10:05Z"), + CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:10:07Z"), + Phase: helmrelease.HookPhaseFailed, + }, + }, + { + Name: "passing-pre-install", + Events: []helmrelease.HookEvent{helmrelease.HookPreInstall}, + LastRun: helmrelease.HookExecution{ + StartedAt: testutil.MustParseHelmTime("2006-01-02T15:00:05Z"), + CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:00:07Z"), + Phase: helmrelease.HookPhaseSucceeded, + }, + }, +} + +func TestTest_Reconcile(t *testing.T) { + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(driver helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before test. + releases func(namespace string) []*helmrelease.Release + // spec modifies the HelmRelease Object spec before test. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease Object before test. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after running test. + expectConditions []metav1.Condition + // expectHistory is the expected History on the HelmRelease after + // running test. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "test success", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithTestHook()), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.TestSucceededReason, + "1 test hook completed successfully"), + *conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, + "1 test hook completed successfully"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + withTests.SetTestHooks(release.TestHooksFromRelease(releases[0])) + return v2.Snapshots{withTests} + }, + }, + { + name: "test without hooks", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.TestSucceededReason, + "no test hooks"), + *conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, + "no test hooks"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + withTests.SetTestHooks(release.TestHooksFromRelease(releases[0])) + return v2.Snapshots{withTests} + }, + }, + { + name: "test install failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()), + }, testutil.ReleaseWithFailingTestHook()), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + LastAttemptedReleaseAction: v2.ReleaseActionInstall, + InstallFailures: 0, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.TestFailedReason, + "timed out waiting for the condition"), + *conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason, + "timed out waiting for the condition"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0])) + withTests.SetTestHooks(release.TestHooksFromRelease(releases[0])) + return v2.Snapshots{withTests} + }, + expectFailures: 1, + expectInstallFailures: 1, + }, + { + name: "test without current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }, testutil.ReleaseWithTestHook()), + } + }, + expectConditions: []metav1.Condition{}, + wantErr: ErrNoLatest, + }, + { + name: "test with stale current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusSuperseded, + }, testutil.ReleaseWithTestHook()), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.TestFailedReason, + ErrReleaseMismatch.Error()), + *conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason, + ErrReleaseMismatch.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + wantErr: ErrReleaseMismatch, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + helmreleaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + Test: &v2.Test{ + Enable: true, + }, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := (NewTest(cfg, recorder)).Reconcile(context.TODO(), &Request{ + Object: obj, + }) + if tt.wantErr != nil { + g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue()) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + helmreleaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func Test_observeTest(t *testing.T) { + t.Run("test with current", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + }, + }, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + }, testutil.ReleaseWithHooks(testHookFixtures)) + + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + expect.SetTestHooks(release.TestHooksFromRelease(rls)) + + observeTest(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + expect, + })) + }) + + t.Run("test targeting different version than latest", func(t *testing.T) { + g := NewWithT(t) + + current := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + } + previous := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + } + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + current, + previous, + }, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: previous.Version, + }, testutil.ReleaseWithHooks(testHookFixtures)) + + observeTest(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + current, + previous, + })) + }) + + t.Run("test without current", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{} + + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 2, + }, testutil.ReleaseWithHooks(testHookFixtures)) + + observeTest(obj)(rls) + g.Expect(obj.Status.History).To(BeEmpty()) + }) +} + +func TestTest_failure(t *testing.T) { + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + err = errors.New("test error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Test{ + eventRecorder: recorder, + } + + req := &Request{Object: obj.DeepCopy()} + r.failure(req, err) + + expectMsg := fmt.Sprintf(fmtTestFailure, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(req.Object.Status.InstallFailures).To(BeZero()) + g.Expect(req.Object.Status.UpgradeFailures).To(BeZero()) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.TestFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) + }) + + t.Run("increases remediation failure count", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Test{ + eventRecorder: recorder, + } + + obj := obj.DeepCopy() + obj.Status.LastAttemptedReleaseAction = v2.ReleaseActionInstall + obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{}) + req := &Request{Object: obj} + r.failure(req, err) + + g.Expect(req.Object.Status.InstallFailures).To(Equal(int64(1))) + }) + + t.Run("follows ignore failure instructions", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Test{ + eventRecorder: recorder, + } + + obj := obj.DeepCopy() + obj.Spec.Test = &v2.Test{IgnoreFailures: true} + obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{}) + req := &Request{Object: obj} + r.failure(req, err) + + g.Expect(req.Object.Status.InstallFailures).To(BeZero()) + }) +} + +func TestTest_success(t *testing.T) { + g := NewWithT(t) + + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + ) + + t.Run("records success", func(t *testing.T) { + recorder := testutil.NewFakeRecorder(10, false) + r := &Test{ + eventRecorder: recorder, + } + + obj := obj.DeepCopy() + obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{ + "test": { + Phase: helmrelease.HookPhaseSucceeded.String(), + }, + "test-2": { + Phase: helmrelease.HookPhaseSucceeded.String(), + }, + }) + req := &Request{Object: obj} + r.success(req) + + expectMsg := fmt.Sprintf(fmtTestSuccess, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + "2 test hooks completed successfully") + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(0))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.TestSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) + }) + + t.Run("records success without hooks", func(t *testing.T) { + r := &Test{ + eventRecorder: new(testutil.FakeRecorder), + } + + obj := obj.DeepCopy() + obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{}) + req := &Request{Object: obj} + r.success(req) + + g.Expect(conditions.IsTrue(req.Object, v2.TestSuccessCondition)).To(BeTrue()) + g.Expect(req.Object.Status.Conditions[0].Message).To(ContainSubstring("no test hooks")) + }) +} diff --git a/internal/reconcile/uninstall.go b/internal/reconcile/uninstall.go new file mode 100644 index 000000000..8c8158745 --- /dev/null +++ b/internal/reconcile/uninstall.go @@ -0,0 +1,234 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "strings" + + helmrelease "helm.sh/helm/v3/pkg/release" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/logger" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" +) + +// Uninstall is an ActionReconciler which attempts to uninstall a Helm release +// based on the given Request data. +// +// The writes to the Helm storage during the uninstallation are observed, and +// update the Status.History field. +// +// After a successful uninstall, the object is marked with Released=False and +// an event is emitted. When the uninstallation fails, the object is marked +// with Released=False and a warning event is emitted. +// +// When the Request.Object does not have a latest release, it returns an +// error of type ErrNoLatest. If the uninstallation targeted a different +// release (version) than the latest release, it returns an error of type +// ErrReleaseMismatch. In addition, it returns ErrNoStorageUpdate if the +// uninstallation completed without updating the Helm storage. In which case +// the resources for the release will be removed from the cluster, but the +// storage object remains in the cluster. Any other returned error indicates +// the caller should retry as it did not cause a change to the Helm storage or +// the cluster resources. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// This reconciler is different from UninstallRemediation, in that it makes +// observations to the Released condition type instead of Remediated. Use this +// reconciler to uninstall a release, and UninstallRemediation to remediate a +// release. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type Uninstall struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewUninstall returns a new Uninstall reconciler configured with the provided +// values. +func NewUninstall(cfg *action.ConfigFactory, recorder record.EventRecorder) *Uninstall { + return &Uninstall{configFactory: cfg, eventRecorder: recorder} +} + +func (r *Uninstall) Reconcile(ctx context.Context, req *Request) error { + var ( + cur = req.Object.Status.History.Latest().DeepCopy() + logBuf = action.NewLogBuffer(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), 10) + cfg = r.configFactory.Build(logBuf.Log, observeUninstall(req.Object)) + ) + + defer summarize(req) + + // Require current to run uninstall. + if cur == nil { + return fmt.Errorf("%w: required to uninstall", ErrNoLatest) + } + + // Run the Helm uninstall action. + res, err := action.Uninstall(ctx, cfg, req.Object, cur.Name) + + // When the release is not found, something else has already uninstalled + // the release. As such, we can assume the release is uninstalled while + // taking note that we did not do it. + if errors.Is(err, helmdriver.ErrReleaseNotFound) { + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.UninstallSucceededReason, + "Release %s was not found, assuming it is uninstalled", cur.FullReleaseName()) + return nil + } + + // When the release is already uninstalled and the user requested to keep + // the history, we can assume the release is uninstalled while taking note + // that we did not do it. + // This can happen when the release was uninstalled as part of a + // remediation, with a subsequent uninstall request due to the object + // being deleted. + if err != nil && req.Object.GetUninstall().KeepHistory && strings.Contains(err.Error(), "is already deleted") { + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.UninstallSucceededReason, + "Release %s was already uninstalled", cur.FullReleaseName()) + return nil + } + + // The Helm uninstall action does always target the latest release. Before + // accepting results, we need to confirm this is actually the release we + // have recorded as latest. + if res != nil && !release.ObserveRelease(res.Release).Targets(cur.Name, cur.Namespace, cur.Version) { + err = fmt.Errorf("%w: uninstalled release %s/%s.v%d != current release %s", + ErrReleaseMismatch, res.Release.Namespace, res.Release.Name, res.Release.Version, cur.FullReleaseName()) + } + + // The Helm uninstall action may return without an error while the update + // to the storage failed. Detect this and return an error. + if err == nil && cur.Digest == req.Object.Status.History.Latest().Digest { + // An exception is made for the case where the release was already marked + // as uninstalled, which would only result in the release object getting + // removed from the storage. + if s := helmrelease.Status(cur.Status); s != helmrelease.StatusUninstalled { + err = fmt.Errorf("uninstall completed with error: %w", ErrNoStorageUpdate) + } + } + + // Handle any error. + if err != nil { + r.failure(req, logBuf, err) + if req.Object.Status.History.Latest().Digest == cur.Digest { + return err + } + return nil + } + + // Mark success. + r.success(req) + return nil +} + +func (r *Uninstall) Name() string { + return "uninstall" +} + +func (r *Uninstall) Type() ReconcilerType { + return ReconcilerTypeRelease +} + +const ( + // fmtUninstallFailed is the message format for an uninstall failure. + fmtUninstallFailure = "Helm uninstall failed for release %s with chart %s: %s" + // fmtUninstallSuccess is the message format for a successful uninstall. + fmtUninstallSuccess = "Helm uninstall succeeded for release %s with chart %s" +) + +// failure records the failure of a Helm uninstall action in the status of the +// given Request.Object by marking Released=False and emitting a warning +// event. +func (r *Uninstall) failure(req *Request, buffer *action.LogBuffer, err error) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtUninstallFailure, cur.FullReleaseName(), cur.VersionedChartName(), strings.TrimSpace(err.Error())) + + // Mark remediation failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.UninstallFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeWarning, v2.UninstallFailedReason, + eventMessageWithLog(msg, buffer), + ) +} + +// success records the success of a Helm uninstall action in the status of +// the given Request.Object by marking Released=False and emitting an +// event. +func (r *Uninstall) success(req *Request) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtUninstallSuccess, cur.FullReleaseName(), cur.VersionedChartName()) + + // Mark remediation success on object. + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.UninstallSucceededReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + v2.UninstallSucceededReason, + msg, + ) +} + +// observeUninstall returns a storage.ObserveFunc to track uninstallations of a +// HelmRelease. +// It compares the release history snapshots with the uninstalled release +// information. +// If a matching snapshot for the uninstalled release is found, it updates the +// snapshot with the observed release data. +func observeUninstall(obj *v2.HelmRelease) storage.ObserveFunc { + // NB: One could argue that we should only update the latest release in + // the history. + // But like during rollback, Helm may supersede any previous releases. + // As such, we need to update all releases we have in our history. + // xref: https://github.com/helm/helm/pull/12564 + return func(rls *helmrelease.Release) { + for i := range obj.Status.History { + snap := obj.Status.History[i] + if snap.Targets(rls.Name, rls.Namespace, rls.Version) { + newSnap := release.ObservedToSnapshot(release.ObserveRelease(rls)) + newSnap.SetTestHooks(snap.GetTestHooks()) + obj.Status.History[i] = newSnap + return + } + } + } +} diff --git a/internal/reconcile/uninstall_remediation.go b/internal/reconcile/uninstall_remediation.go new file mode 100644 index 000000000..4e244cdc0 --- /dev/null +++ b/internal/reconcile/uninstall_remediation.go @@ -0,0 +1,183 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/logger" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/release" +) + +var ( + ErrNoStorageUpdate = errors.New("release not updated in Helm storage") +) + +// UninstallRemediation is an ActionReconciler which attempts to remediate a +// failed Helm release for the given Request data by uninstalling it. +// +// The writes to the Helm storage during the rollback are observed, and update +// the Status.History field. +// +// After a successful uninstall, the object is marked with Remediated=True and +// an event is emitted. When the uninstallation fails, the object is marked +// with Remediated=False and a warning event is emitted. +// +// When the Request.Object does not have a latest release, it returns an +// error of type ErrNoLatest. If the uninstallation targeted a different +// release (version) than the latest release, it returns an error of type +// ErrReleaseMismatch. In addition, it returns ErrNoStorageUpdate if the +// uninstallation completed without updating the Helm storage. In which case +// the resources for the release will be removed from the cluster, but the +// storage object remains in the cluster. Any other returned error indicates +// the caller should retry as it did not cause a change to the Helm storage or +// the cluster resources. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// This reconciler is different from Uninstall, in that it makes observations +// to the Remediated condition type instead of Released. Use this reconciler +// to remediate a failed release, and Uninstall to uninstall a release. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type UninstallRemediation struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewUninstallRemediation returns a new UninstallRemediation reconciler +// configured with the provided values. +func NewUninstallRemediation(cfg *action.ConfigFactory, recorder record.EventRecorder) *UninstallRemediation { + return &UninstallRemediation{configFactory: cfg, eventRecorder: recorder} +} + +func (r *UninstallRemediation) Reconcile(ctx context.Context, req *Request) error { + var ( + cur = req.Object.Status.History.Latest().DeepCopy() + logBuf = action.NewLogBuffer(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), 10) + cfg = r.configFactory.Build(logBuf.Log, observeUninstall(req.Object)) + ) + + // Require current to run uninstall. + if cur == nil { + return fmt.Errorf("%w: required to uninstall", ErrNoLatest) + } + + // Run the Helm uninstall action. + res, err := action.Uninstall(ctx, cfg, req.Object, cur.Name) + + // The Helm uninstall action does always target the latest release. Before + // accepting results, we need to confirm this is actually the release we + // have recorded as latest. + if res != nil && !release.ObserveRelease(res.Release).Targets(cur.Name, cur.Namespace, cur.Version) { + err = fmt.Errorf("%w: uninstalled release %s/%s.v%d != current release %s", + ErrReleaseMismatch, res.Release.Namespace, res.Release.Name, res.Release.Version, cur.FullReleaseName()) + } + + // The Helm uninstall action may return without an error while the update + // to the storage failed. Detect this and return an error. + if err == nil && cur.Digest == req.Object.Status.History.Latest().Digest { + err = fmt.Errorf("uninstall completed with error: %w", ErrNoStorageUpdate) + } + + // Handle any error. + if err != nil { + r.failure(req, logBuf, err) + if cur.Digest == req.Object.Status.History.Latest().Digest { + return err + } + return nil + } + + // Mark success. + r.success(req) + return nil +} + +func (r *UninstallRemediation) Name() string { + return "uninstall" +} + +func (r *UninstallRemediation) Type() ReconcilerType { + return ReconcilerTypeRemediate +} + +const ( + // fmtUninstallRemediationFailure is the message format for an uninstall + // remediation failure. + fmtUninstallRemediationFailure = "Helm uninstall remediation for release %s with chart %s failed: %s" + // fmtUninstallRemediationSuccess is the message format for a successful + // uninstall remediation. + fmtUninstallRemediationSuccess = "Helm uninstall remediation for release %s with chart %s succeeded" +) + +// success records the success of a Helm uninstall remediation action in the +// status of the given Request.Object by marking Remediated=False and emitting +// a warning event. +func (r *UninstallRemediation) failure(req *Request, buffer *action.LogBuffer, err error) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtUninstallRemediationFailure, cur.FullReleaseName(), cur.VersionedChartName(), strings.TrimSpace(err.Error())) + + // Mark uninstall failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.RemediatedCondition, v2.UninstallFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeWarning, + v2.UninstallFailedReason, + eventMessageWithLog(msg, buffer), + ) +} + +// success records the success of a Helm uninstall remediation action in the +// status of the given Request.Object by marking Remediated=True and emitting +// an event. +func (r *UninstallRemediation) success(req *Request) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtUninstallRemediationSuccess, cur.FullReleaseName(), cur.VersionedChartName()) + + // Mark remediation success on object. + conditions.MarkTrue(req.Object, v2.RemediatedCondition, v2.UninstallSucceededReason, msg) + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + v2.UninstallSucceededReason, + msg, + ) +} diff --git a/internal/reconcile/uninstall_remediation_test.go b/internal/reconcile/uninstall_remediation_test.go new file mode 100644 index 000000000..f6abe2745 --- /dev/null +++ b/internal/reconcile/uninstall_remediation_test.go @@ -0,0 +1,498 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestUninstallRemediation_Reconcile(t *testing.T) { + var ( + mockUpdateErr = fmt.Errorf("storage update error") + mockDeleteErr = fmt.Errorf("storage delete error") + ) + + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before uninstall. + releases func(namespace string) []*helmrelease.Release + // spec modifies the HelmRelease Object spec before uninstall. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease Object before uninstall. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after running rollback. + expectConditions []metav1.Condition + // expectHistory is the expected History of the HelmRelease after + // uninstall. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "uninstall success", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.UninstallSucceededReason, + "succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "uninstall failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + }, testutil.ReleaseWithFailingHook()), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.UninstallFailedReason, + "uninstallation completed with 1 error(s): 1 error occurred:\n\t* timed out waiting for the condition"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "uninstall failure without storage update", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + // Explicitly inherit the driver, as we want to rely on the + // Secret storage, as the memory storage does not detach + // objects from the release action. Causing writes post-persist + // to leak to the stored release object. + // xref: https://github.com/helm/helm/issues/11304 + Driver: driver, + UpdateErr: mockUpdateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.UninstallFailedReason, + ErrNoStorageUpdate.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + wantErr: ErrNoStorageUpdate, + }, + { + name: "uninstall failure without storage delete", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + // Explicitly inherit the driver, as we want to rely on the + // Secret storage, as the memory storage does not detach + // objects from the release action. Causing writes post-persist + // to leak to the stored release object. + // xref: https://github.com/helm/helm/issues/11304 + Driver: driver, + DeleteErr: mockDeleteErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.UninstallFailedReason, mockDeleteErr.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "uninstall without current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + expectConditions: []metav1.Condition{}, + wantErr: ErrNoLatest, + }, + { + name: "uninstall with stale current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusSuperseded, + }, testutil.ReleaseWithTestHook()), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.UninstallFailedReason, + ErrReleaseMismatch.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + wantErr: ErrReleaseMismatch, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + releaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := NewUninstallRemediation(cfg, recorder).Reconcile(context.TODO(), &Request{ + Object: obj, + }) + if tt.wantErr != nil { + g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue()) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + releaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestUninstallRemediation_failure(t *testing.T) { + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + err = errors.New("uninstall error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &UninstallRemediation{ + eventRecorder: recorder, + } + + req := &Request{Object: obj.DeepCopy()} + r.failure(req, nil, err) + + expectMsg := fmt.Sprintf(fmtUninstallRemediationFailure, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.RemediatedCondition, v2.UninstallFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.UninstallFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) + }) + + t.Run("records failure with logs", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &UninstallRemediation{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy()} + r.failure(req, mockLogBuffer(5, 10), err) + + expectSubStr := "Last Helm logs" + g.Expect(conditions.IsFalse(req.Object, v2.RemediatedCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(req.Object, v2.RemediatedCondition)).ToNot(ContainSubstring(expectSubStr)) + + events := recorder.GetEvents() + g.Expect(events).To(HaveLen(1)) + g.Expect(events[0].Message).To(ContainSubstring(expectSubStr)) + }) +} + +func TestUninstallRemediation_success(t *testing.T) { + g := NewWithT(t) + + var cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + + recorder := testutil.NewFakeRecorder(10, false) + r := &UninstallRemediation{ + eventRecorder: recorder, + } + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + + req := &Request{Object: obj} + r.success(req) + + expectMsg := fmt.Sprintf(fmtUninstallRemediationSuccess, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version)) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(v2.RemediatedCondition, v2.UninstallSucceededReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(0))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.UninstallSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) +} diff --git a/internal/reconcile/uninstall_test.go b/internal/reconcile/uninstall_test.go new file mode 100644 index 000000000..ec0a9e23a --- /dev/null +++ b/internal/reconcile/uninstall_test.go @@ -0,0 +1,705 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestUninstall_Reconcile(t *testing.T) { + mockUpdateErr := errors.New("mock update error") + + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before uninstall. + releases func(namespace string) []*helmrelease.Release + // spec modifies the HelmRelease Object spec before uninstall. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease Object before uninstall. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after running rollback. + expectConditions []metav1.Condition + // expectHistory is the expected History of the HelmRelease after + // uninstall. + expectHistory func(namespace string, releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "uninstall success", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallSucceededReason, + "succeeded"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, + "succeeded"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "uninstall failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + }, testutil.ReleaseWithFailingHook()), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + "uninstallation completed with 1 error(s): 1 error occurred:\n\t* timed out waiting for the condition"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, + "uninstallation completed with 1 error(s): 1 error occurred:\n\t* timed out waiting for the condition"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "uninstall failure without storage update", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + // Explicitly inherit the driver, as we want to rely on the + // Secret storage, as the memory storage does not detach + // objects from the release action. Causing writes post-persist + // to leak to the stored release object. + // xref: https://github.com/helm/helm/issues/11304 + Driver: driver, + UpdateErr: mockUpdateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + ErrNoStorageUpdate.Error()), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, + ErrNoStorageUpdate.Error()), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + wantErr: ErrNoStorageUpdate, + }, + { + name: "uninstall failure without storage delete", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + // Explicitly inherit the driver, as we want to rely on the + // Secret storage, as the memory storage does not detach + // objects from the release action. Causing writes post-persist + // to leak to the stored release object. + // xref: https://github.com/helm/helm/issues/11304 + Driver: driver, + DeleteErr: fmt.Errorf("delete error"), + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Status: helmrelease.StatusDeployed, + Chart: testutil.BuildChart(), + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + "delete error"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, + "delete error"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "uninstall without current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + expectConditions: []metav1.Condition{}, + wantErr: ErrNoLatest, + }, + { + name: "uninstall with stale current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusSuperseded, + }, testutil.ReleaseWithTestHook()), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallFailedReason, + ErrReleaseMismatch.Error()), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, + ErrReleaseMismatch.Error()), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + wantErr: ErrReleaseMismatch, + }, + { + name: "uninstall already deleted release", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + // Explicitly inherit the driver, as we want to rely on the + // Secret storage, as the memory storage does not detach + // objects from the release action. Causing writes post-persist + // to leak to the stored release object. + // xref: https://github.com/helm/helm/issues/11304 + Driver: driver, + QueryErr: helmdriver.ErrReleaseNotFound, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallSucceededReason, + "assuming it is uninstalled"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, + "assuming it is uninstalled"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "already uninstalled without keep history", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusUninstalled, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallSucceededReason, + "succeeded"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, + "succeeded"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusUninstalled, + }) + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(rls)), + } + }, + }, + { + name: "already uninstalled with keep history", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Status: helmrelease.StatusUninstalled, + }), + } + }, + spec: func(spec *v2.HelmReleaseSpec) { + spec.Uninstall = &v2.Uninstall{ + KeepHistory: true, + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UninstallSucceededReason, + "was already uninstalled"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, + "was already uninstalled"), + }, + expectHistory: func(namespace string, releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + releaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := NewUninstall(cfg, recorder).Reconcile(context.TODO(), &Request{ + Object: obj, + }) + if tt.wantErr != nil { + g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue()) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + releaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releaseNamespace, releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestUninstall_failure(t *testing.T) { + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + err = errors.New("uninstall error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Uninstall{ + eventRecorder: recorder, + } + + req := &Request{Object: obj.DeepCopy()} + r.failure(req, nil, err) + + expectMsg := fmt.Sprintf(fmtUninstallFailure, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.UninstallFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) + }) + + t.Run("records failure with logs", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Uninstall{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy()} + r.failure(req, mockLogBuffer(5, 10), err) + + expectSubStr := "Last Helm logs" + g.Expect(conditions.IsFalse(req.Object, v2.ReleasedCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(req.Object, v2.ReleasedCondition)).ToNot(ContainSubstring(expectSubStr)) + + events := recorder.GetEvents() + g.Expect(events).To(HaveLen(1)) + g.Expect(events[0].Message).To(ContainSubstring(expectSubStr)) + }) +} + +func TestUninstall_success(t *testing.T) { + g := NewWithT(t) + + var cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Uninstall{ + eventRecorder: recorder, + } + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + req := &Request{Object: obj} + r.success(req) + + expectMsg := fmt.Sprintf(fmtUninstallSuccess, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version)) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, v2.UninstallSucceededReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(0))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.UninstallSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) +} + +func Test_observeUninstall(t *testing.T) { + t.Run("uninstall of current", func(t *testing.T) { + g := NewWithT(t) + + current := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusDeployed.String(), + } + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + current, + }, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: current.Name, + Namespace: current.Namespace, + Version: current.Version, + Status: helmrelease.StatusUninstalled, + }) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + + observeUninstall(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + expect, + })) + }) + + t.Run("uninstall without current", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: nil, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusUninstalling, + }) + + observeUninstall(obj)(rls) + g.Expect(obj.Status.History).To(BeNil()) + }) + + t.Run("uninstall of different version than current", func(t *testing.T) { + g := NewWithT(t) + + current := &v2.Snapshot{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusDeployed.String(), + } + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + current, + }, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: current.Name, + Namespace: current.Namespace, + Version: current.Version + 1, + Status: helmrelease.StatusUninstalled, + }) + + observeUninstall(obj)(rls) + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + current, + })) + }) +} diff --git a/internal/reconcile/unlock.go b/internal/reconcile/unlock.go new file mode 100644 index 000000000..7d045856c --- /dev/null +++ b/internal/reconcile/unlock.go @@ -0,0 +1,162 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "strings" + + helmrelease "helm.sh/helm/v3/pkg/release" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" +) + +// Unlock is an ActionReconciler which attempts to unlock the latest release +// for a Request.Object in the Helm storage if stuck in a pending state, by +// setting the status to release.StatusFailed and persisting it. +// +// This write to the Helm storage is observed, and updates the Status.History +// field if the persisted object targets the same release version. +// +// Any pending state marks the v2beta2.HelmRelease object with +// ReleasedCondition=False, even if persisting the object to the Helm storage +// fails. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +type Unlock struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewUnlock returns a new Unlock reconciler configured with the provided +// values. +func NewUnlock(cfg *action.ConfigFactory, recorder record.EventRecorder) *Unlock { + return &Unlock{configFactory: cfg, eventRecorder: recorder} +} + +func (r *Unlock) Reconcile(_ context.Context, req *Request) error { + defer summarize(req) + + // Build action configuration to gain access to Helm storage. + cfg := r.configFactory.Build(nil, observeUnlock(req.Object)) + + // Retrieve last release object. + rls, err := action.LastRelease(cfg, req.Object.GetReleaseName()) + if err != nil { + // Ignore not found error. Assume caller will decide what to do + // when it re-assess state to determine the next action. + if errors.Is(err, action.ErrReleaseNotFound) { + return nil + } + // Return any other error to retry. + return err + } + + // Ensure the release is in a pending state. + cur := release.ObservedToSnapshot(release.ObserveRelease(rls)) + if status := rls.Info.Status; status.IsPending() { + // Update pending status to failed and persist. + rls.SetStatus(helmrelease.StatusFailed, fmt.Sprintf("Release unlocked from stale '%s' state", status.String())) + if err = cfg.Releases.Update(rls); err != nil { + r.failure(req, cur, status, err) + return err + } + r.success(req, cur, status) + } + return nil +} + +func (r *Unlock) Name() string { + return "unlock" +} + +func (r *Unlock) Type() ReconcilerType { + return ReconcilerTypeUnlock +} + +const ( + // fmtUnlockFailure is the message format for an unlock failure. + fmtUnlockFailure = "Unlock of Helm release %s with chart %s in %s state failed: %s" + // fmtUnlockSuccess is the message format for a successful unlock. + fmtUnlockSuccess = "Unlocked Helm release %s with chart %s in %s state" +) + +// failure records the failure of an unlock action in the status of the given +// Request.Object by marking ReleasedCondition=False and increasing the failure +// counter. In addition, it emits a warning event for the Request.Object. +func (r *Unlock) failure(req *Request, cur *v2.Snapshot, status helmrelease.Status, err error) { + // Compose failure message. + msg := fmt.Sprintf(fmtUnlockFailure, cur.FullReleaseName(), cur.VersionedChartName(), status.String(), strings.TrimSpace(err.Error())) + + // Mark unlock failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.ReleasedCondition, "PendingRelease", msg) + + // Record warning event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeWarning, + "PendingRelease", + msg, + ) +} + +// success records the success of an unlock action in the status of the given +// Request.Object by marking ReleasedCondition=False and emitting an event. +func (r *Unlock) success(req *Request, cur *v2.Snapshot, status helmrelease.Status) { + // Compose success message. + msg := fmt.Sprintf(fmtUnlockSuccess, cur.FullReleaseName(), cur.VersionedChartName(), status.String()) + + // Mark unlock success on object. + conditions.MarkFalse(req.Object, v2.ReleasedCondition, "PendingRelease", msg) + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + "PendingRelease", + msg, + ) +} + +// observeUnlock returns a storage.ObserveFunc to track unlocking actions on +// a HelmRelease. +// It updates the snapshot of a release when an unlock action is observed for +// that release. +func observeUnlock(obj *v2.HelmRelease) storage.ObserveFunc { + return func(rls *helmrelease.Release) { + for i := range obj.Status.History { + snap := obj.Status.History[i] + if snap.Targets(rls.Name, rls.Namespace, rls.Version) { + obj.Status.History[i] = release.ObservedToSnapshot(release.ObserveRelease(rls)) + return + } + } + } +} diff --git a/internal/reconcile/unlock_test.go b/internal/reconcile/unlock_test.go new file mode 100644 index 000000000..6799fe198 --- /dev/null +++ b/internal/reconcile/unlock_test.go @@ -0,0 +1,504 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + helmreleaseutil "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestUnlock_Reconcile(t *testing.T) { + var ( + mockQueryErr = errors.New("storage query error") + mockUpdateErr = errors.New("storage update error") + ) + + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before unlock. + releases func(namespace string) []*helmrelease.Release + // spec modifies the HelmRelease Object spec before unlock. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease object before unlock. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after running rollback. + expectConditions []metav1.Condition + // expectHistory is the expected History of the HelmRelease after + // unlock. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "unlock success", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingInstall, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, "PendingRelease", "Unlocked Helm release"), + *conditions.FalseCondition(v2.ReleasedCondition, "PendingRelease", "Unlocked Helm release"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "unlock failure", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + UpdateErr: mockUpdateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingRollback, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + wantErr: mockUpdateErr, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, "PendingRelease", "in pending-rollback state failed: storage update error"), + *conditions.FalseCondition(v2.ReleasedCondition, "PendingRelease", "in pending-rollback state failed: storage update error"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + }, + { + name: "unlock without pending status", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusFailed, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + }, + } + }, + expectConditions: []metav1.Condition{}, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + } + }, + }, + { + name: "unlock with stale current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 2, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusDeployed, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: releases[0].Version - 1, + Status: helmrelease.StatusPendingInstall.String(), + }, + }, + } + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: releases[0].Version - 1, + Status: helmrelease.StatusPendingInstall.String(), + }, + } + }, + }, + { + name: "unlock without latest", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + }, + } + }, + expectConditions: []metav1.Condition{}, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + } + }, + }, + { + name: "unlock with storage query error", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + QueryErr: mockQueryErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Version: 1, + Chart: testutil.BuildChart(), + Status: helmrelease.StatusPendingInstall, + }), + } + }, + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + }, + } + }, + wantErr: mockQueryErr, + expectConditions: []metav1.Condition{}, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + &v2.Snapshot{ + Name: mockReleaseName, + Version: 1, + Status: helmrelease.StatusFailed.String(), + }, + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + helmreleaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := NewUnlock(cfg, recorder).Reconcile(context.TODO(), &Request{ + Object: obj, + }) + if tt.wantErr != nil { + g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue()) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + helmreleaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestUnlock_failure(t *testing.T) { + g := NewWithT(t) + + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{} + status = helmrelease.StatusPendingInstall + err = fmt.Errorf("unlock error") + ) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Unlock{ + eventRecorder: recorder, + } + + req := &Request{Object: obj} + r.failure(req, release.ObservedToSnapshot(release.ObserveRelease(cur)), status, err) + + expectMsg := fmt.Sprintf(fmtUnlockFailure, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + status, err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, "PendingRelease", expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: "PendingRelease", + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) +} + +func TestUnlock_success(t *testing.T) { + g := NewWithT(t) + + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + Version: 4, + }) + obj = &v2.HelmRelease{} + status = helmrelease.StatusPendingInstall + ) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Unlock{ + eventRecorder: recorder, + } + + req := &Request{Object: obj} + r.success(req, release.ObservedToSnapshot(release.ObserveRelease(cur)), status) + + expectMsg := fmt.Sprintf(fmtUnlockSuccess, + fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version), + fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version), + status) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, "PendingRelease", expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(0))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: "PendingRelease", + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(), + }, + }, + }, + })) +} + +func Test_observeUnlock(t *testing.T) { + t.Run("unlock", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusPendingRollback.String(), + }, + }, + }, + } + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusFailed, + }) + expect := release.ObservedToSnapshot(release.ObserveRelease(rls)) + observeUnlock(obj)(rls) + + g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{ + expect, + })) + }) + + t.Run("unlock without current", func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{} + rls := helmrelease.Mock(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Version: 1, + Status: helmrelease.StatusFailed, + }) + observeUnlock(obj)(rls) + + g.Expect(obj.Status.History).To(BeEmpty()) + }) +} diff --git a/internal/reconcile/upgrade.go b/internal/reconcile/upgrade.go new file mode 100644 index 000000000..06e617491 --- /dev/null +++ b/internal/reconcile/upgrade.go @@ -0,0 +1,175 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/logger" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" +) + +// Upgrade is an ActionReconciler which attempts to upgrade a Helm release +// based on the given Request data. +// +// The writes to the Helm storage during the upgrade process are observed, +// and update the Status.History field. +// +// On upgrade success, the object is marked with Released=True and emits an +// event. In addition, the object is marked with TestSuccess=False if tests +// are enabled to indicate we are awaiting the results. +// On failure, the object is marked with Released=False and emits a warning +// event. Only an error which resulted in a modification to the Helm storage +// counts towards a failure for the active remediation strategy. +// +// At the end of the reconciliation, the Status.Conditions are summarized and +// propagated to the Ready condition on the Request.Object. +// +// The caller is assumed to have verified the integrity of Request.Object using +// e.g. action.VerifySnapshot before calling Reconcile. +type Upgrade struct { + configFactory *action.ConfigFactory + eventRecorder record.EventRecorder +} + +// NewUpgrade returns a new Upgrade reconciler configured with the provided +// values. +func NewUpgrade(cfg *action.ConfigFactory, recorder record.EventRecorder) *Upgrade { + return &Upgrade{configFactory: cfg, eventRecorder: recorder} +} + +func (r *Upgrade) Reconcile(ctx context.Context, req *Request) error { + var ( + logBuf = action.NewLogBuffer(action.NewDebugLog(ctrl.LoggerFrom(ctx).V(logger.DebugLevel)), 10) + obsReleases = make(observedReleases) + cfg = r.configFactory.Build(logBuf.Log, observeRelease(obsReleases)) + ) + + defer summarize(req) + + // Mark upgrade attempt on object. + req.Object.Status.LastAttemptedReleaseAction = v2.ReleaseActionUpgrade + + // Run the Helm upgrade action. + _, err := action.Upgrade(ctx, cfg, req.Object, req.Chart, req.Values) + + // Record the history of releases observed during the upgrade. + obsReleases.recordOnObject(req.Object) + + if err != nil { + r.failure(req, logBuf, err) + + // Return error if we did not store a release, as this does not + // affect state and the caller should e.g. retry. + if len(obsReleases) == 0 { + return err + } + + // Count upgrade failure on object, this is used to determine if + // we should retry the upgrade and/or remediation. We only count + // attempts which did cause a modification to the storage, as + // without a new release in storage there is nothing to remediate, + // and the action can be retried immediately without causing + // storage drift. + req.Object.GetUpgrade().GetRemediation().IncrementFailureCount(req.Object) + return nil + } + + r.success(req) + return nil +} + +func (r *Upgrade) Name() string { + return "upgrade" +} + +func (r *Upgrade) Type() ReconcilerType { + return ReconcilerTypeRelease +} + +const ( + // fmtUpgradeFailure is the message format for an upgrade failure. + fmtUpgradeFailure = "Helm upgrade failed for release %s/%s with chart %s@%s: %s" + // fmtUpgradeSuccess is the message format for a successful upgrade. + fmtUpgradeSuccess = "Helm upgrade succeeded for release %s with chart %s" +) + +// failure records the failure of a Helm upgrade action in the status of the +// given Request.Object by marking ReleasedCondition=False and increasing the +// failure counter. In addition, it emits a warning event for the +// Request.Object. +// +// Increase of the failure counter for the active remediation strategy should +// be done conditionally by the caller after verifying the failed action has +// modified the Helm storage. This to avoid counting failures which do not +// result in Helm storage drift. +func (r *Upgrade) failure(req *Request, buffer *action.LogBuffer, err error) { + // Compose failure message. + msg := fmt.Sprintf(fmtUpgradeFailure, req.Object.GetReleaseNamespace(), req.Object.GetReleaseName(), req.Chart.Name(), req.Chart.Metadata.Version, strings.TrimSpace(err.Error())) + + // Mark upgrade failure on object. + req.Object.Status.Failures++ + conditions.MarkFalse(req.Object, v2.ReleasedCondition, v2.UpgradeFailedReason, msg) + + // Record warning event, this message contains more data than the + // Condition summary. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String()), + corev1.EventTypeWarning, + v2.UpgradeFailedReason, + eventMessageWithLog(msg, buffer), + ) +} + +// success records the success of a Helm upgrade action in the status of the +// given Request.Object by marking ReleasedCondition=True and emitting an +// event. In addition, it marks TestSuccessCondition=False when tests are +// enabled to indicate we are awaiting test results after having made the +// release. +func (r *Upgrade) success(req *Request) { + // Compose success message. + cur := req.Object.Status.History.Latest() + msg := fmt.Sprintf(fmtUpgradeSuccess, cur.FullReleaseName(), cur.VersionedChartName()) + + // Mark upgrade success on object. + conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg) + if req.Object.GetTest().Enable && !cur.HasBeenTested() { + conditions.MarkUnknown(req.Object, v2.TestSuccessCondition, "AwaitingTests", fmtTestPending, + cur.FullReleaseName(), cur.VersionedChartName()) + } + + // Record event. + r.eventRecorder.AnnotatedEventf( + req.Object, + eventMeta(cur.ChartVersion, cur.ConfigDigest), + corev1.EventTypeNormal, + v2.UpgradeSucceededReason, + msg, + ) +} diff --git a/internal/reconcile/upgrade_test.go b/internal/reconcile/upgrade_test.go new file mode 100644 index 000000000..32ac87c8e --- /dev/null +++ b/internal/reconcile/upgrade_test.go @@ -0,0 +1,540 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + helmchart "helm.sh/helm/v3/pkg/chart" + helmchartutil "helm.sh/helm/v3/pkg/chartutil" + helmrelease "helm.sh/helm/v3/pkg/release" + helmreleaseutil "helm.sh/helm/v3/pkg/releaseutil" + helmstorage "helm.sh/helm/v3/pkg/storage" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/conditions" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/action" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" + "github.com/fluxcd/helm-controller/internal/release" + "github.com/fluxcd/helm-controller/internal/storage" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestUpgrade_Reconcile(t *testing.T) { + var ( + mockCreateErr = fmt.Errorf("storage create error") + mockUpdateErr = fmt.Errorf("storage update error") + ) + + tests := []struct { + name string + // driver allows for modifying the Helm storage driver. + driver func(driver helmdriver.Driver) helmdriver.Driver + // releases is the list of releases that are stored in the driver + // before upgrade. + releases func(namespace string) []*helmrelease.Release + // chart to upgrade. + chart *helmchart.Chart + // values to use during upgrade. + values helmchartutil.Values + // spec modifies the HelmRelease object spec before upgrade. + spec func(spec *v2.HelmReleaseSpec) + // status to configure on the HelmRelease Object before upgrade. + status func(releases []*helmrelease.Release) v2.HelmReleaseStatus + // wantErr is the error that is expected to be returned. + wantErr error + // expectedConditions are the conditions that are expected to be set on + // the HelmRelease after upgrade. + expectConditions []metav1.Condition + // expectHistory returns the expected History of the HelmRelease after + // upgrade. + expectHistory func(releases []*helmrelease.Release) v2.Snapshots + // expectFailures is the expected Failures count of the HelmRelease. + expectFailures int64 + // expectInstallFailures is the expected InstallFailures count of the + // HelmRelease. + expectInstallFailures int64 + // expectUpgradeFailures is the expected UpgradeFailures count of the + // HelmRelease. + expectUpgradeFailures int64 + }{ + { + name: "upgrade success", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(testutil.ChartWithTestHook()), + Version: 1, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + }, + { + name: "upgrade failure", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(testutil.ChartWithFailingHook()), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UpgradeFailedReason, + "post-upgrade hooks failed: 1 error occurred:\n\t* timed out waiting for the condition"), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UpgradeFailedReason, + "post-upgrade hooks failed: 1 error occurred:\n\t* timed out waiting for the condition"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + expectUpgradeFailures: 1, + }, + { + name: "upgrade failure without storage create", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + CreateErr: mockCreateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UpgradeFailedReason, + mockCreateErr.Error()), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UpgradeFailedReason, + mockCreateErr.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + expectUpgradeFailures: 0, + wantErr: mockCreateErr, + }, + { + name: "upgrade failure without storage update", + driver: func(driver helmdriver.Driver) helmdriver.Driver { + return &storage.Failing{ + Driver: driver, + UpdateErr: mockUpdateErr, + } + }, + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.FalseCondition(meta.ReadyCondition, v2.UpgradeFailedReason, + mockUpdateErr.Error()), + *conditions.FalseCondition(v2.ReleasedCondition, v2.UpgradeFailedReason, + mockUpdateErr.Error()), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + release.ObservedToSnapshot(release.ObserveRelease(releases[0])), + } + }, + expectFailures: 1, + expectUpgradeFailures: 1, + }, + { + name: "upgrade without current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: nil, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[1])), + } + }, + }, + { + name: "upgrade with stale current", + releases: func(namespace string) []*helmrelease.Release { + return []*helmrelease.Release{ + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 1, + Status: helmrelease.StatusSuperseded, + }), + testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: namespace, + Chart: testutil.BuildChart(), + Version: 2, + Status: helmrelease.StatusDeployed, + }), + } + }, + chart: testutil.BuildChart(), + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + { + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: 1, + Status: helmrelease.StatusDeployed.String(), + }, + }, + } + }, + expectConditions: []metav1.Condition{ + *conditions.TrueCondition(meta.ReadyCondition, v2.UpgradeSucceededReason, + "Helm upgrade succeeded"), + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, + "Helm upgrade succeeded"), + }, + expectHistory: func(releases []*helmrelease.Release) v2.Snapshots { + return v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(releases[2])), + { + Name: mockReleaseName, + Namespace: releases[0].Namespace, + Version: 1, + Status: helmrelease.StatusDeployed.String(), + }, + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace) + g.Expect(err).NotTo(HaveOccurred()) + t.Cleanup(func() { + _ = testEnv.Delete(context.TODO(), namedNS) + }) + releaseNamespace := namedNS.Name + + var releases []*helmrelease.Release + if tt.releases != nil { + releases = tt.releases(releaseNamespace) + helmreleaseutil.SortByRevision(releases) + } + + obj := &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: releaseNamespace, + StorageNamespace: releaseNamespace, + Timeout: &metav1.Duration{Duration: 100 * time.Millisecond}, + }, + } + if tt.spec != nil { + tt.spec(&obj.Spec) + } + if tt.status != nil { + obj.Status = tt.status(releases) + } + + getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace()) + g.Expect(err).ToNot(HaveOccurred()) + + cfg, err := action.NewConfigFactory(getter, + action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()), + ) + g.Expect(err).ToNot(HaveOccurred()) + + store := helmstorage.Init(cfg.Driver) + for _, r := range releases { + g.Expect(store.Create(r)).To(Succeed()) + } + + if tt.driver != nil { + cfg.Driver = tt.driver(cfg.Driver) + } + + recorder := new(record.FakeRecorder) + got := NewUpgrade(cfg, recorder).Reconcile(context.TODO(), &Request{ + Object: obj, + Chart: tt.chart, + Values: tt.values, + }) + if tt.wantErr != nil { + g.Expect(got).To(Equal(tt.wantErr)) + } else { + g.Expect(got).ToNot(HaveOccurred()) + } + + g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions)) + + releases, _ = store.History(mockReleaseName) + helmreleaseutil.SortByRevision(releases) + + if tt.expectHistory != nil { + g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases))) + } else { + g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty") + } + + g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures)) + g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures)) + g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures)) + }) + } +} + +func TestUpgrade_failure(t *testing.T) { + var ( + obj = &v2.HelmRelease{ + Spec: v2.HelmReleaseSpec{ + ReleaseName: mockReleaseName, + TargetNamespace: mockReleaseNamespace, + }, + } + chrt = testutil.BuildChart() + err = errors.New("upgrade error") + ) + + t.Run("records failure", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Upgrade{ + eventRecorder: recorder, + } + + req := &Request{Object: obj.DeepCopy(), Chart: chrt, Values: map[string]interface{}{"foo": "bar"}} + r.failure(req, nil, err) + + expectMsg := fmt.Sprintf(fmtUpgradeFailure, mockReleaseNamespace, mockReleaseName, chrt.Name(), + chrt.Metadata.Version, err.Error()) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.FalseCondition(v2.ReleasedCondition, v2.UpgradeFailedReason, expectMsg), + })) + g.Expect(req.Object.Status.Failures).To(Equal(int64(1))) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeWarning, + Reason: v2.UpgradeFailedReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version, + eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(), + }, + }, + }, + })) + }) + + t.Run("records failure with logs", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Upgrade{ + eventRecorder: recorder, + } + req := &Request{Object: obj.DeepCopy(), Chart: chrt} + r.failure(req, mockLogBuffer(5, 10), err) + + expectSubStr := "Last Helm logs" + g.Expect(conditions.IsFalse(req.Object, v2.ReleasedCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(req.Object, v2.ReleasedCondition)).ToNot(ContainSubstring(expectSubStr)) + + events := recorder.GetEvents() + g.Expect(events).To(HaveLen(1)) + g.Expect(events[0].Message).To(ContainSubstring(expectSubStr)) + }) +} + +func TestUpgrade_success(t *testing.T) { + var ( + cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: mockReleaseName, + Namespace: mockReleaseNamespace, + Chart: testutil.BuildChart(), + }) + obj = &v2.HelmRelease{ + Status: v2.HelmReleaseStatus{ + History: v2.Snapshots{ + release.ObservedToSnapshot(release.ObserveRelease(cur)), + }, + }, + } + ) + + t.Run("records success", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Upgrade{ + eventRecorder: recorder, + } + + req := &Request{ + Object: obj.DeepCopy(), + } + r.success(req) + + expectMsg := fmt.Sprintf(fmtUpgradeSuccess, + fmt.Sprintf("%s/%s.v%d", mockReleaseNamespace, mockReleaseName, obj.Status.History.Latest().Version), + fmt.Sprintf("%s@%s", obj.Status.History.Latest().ChartName, obj.Status.History.Latest().ChartVersion)) + + g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, expectMsg), + })) + g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{ + { + Type: corev1.EventTypeNormal, + Reason: v2.UpgradeSucceededReason, + Message: expectMsg, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventMetaGroupKey(eventv1.MetaRevisionKey): obj.Status.History.Latest().ChartVersion, + eventMetaGroupKey(eventv1.MetaTokenKey): obj.Status.History.Latest().ConfigDigest, + }, + }, + }, + })) + }) + + t.Run("records success with TestSuccess=False", func(t *testing.T) { + g := NewWithT(t) + + recorder := testutil.NewFakeRecorder(10, false) + r := &Upgrade{ + eventRecorder: recorder, + } + + obj := obj.DeepCopy() + obj.Spec.Test = &v2.Test{Enable: true} + + req := &Request{Object: obj} + r.success(req) + + g.Expect(conditions.IsTrue(req.Object, v2.ReleasedCondition)).To(BeTrue()) + + cond := conditions.Get(req.Object, v2.TestSuccessCondition) + g.Expect(cond).ToNot(BeNil()) + + expectMsg := fmt.Sprintf(fmtTestPending, + fmt.Sprintf("%s/%s.v%d", mockReleaseNamespace, mockReleaseName, obj.Status.History.Latest().Version), + fmt.Sprintf("%s@%s", obj.Status.History.Latest().ChartName, obj.Status.History.Latest().ChartVersion)) + g.Expect(cond.Message).To(Equal(expectMsg)) + }) +} diff --git a/internal/release/decode_test.go b/internal/release/decode_test.go new file mode 100644 index 000000000..1ea41c237 --- /dev/null +++ b/internal/release/decode_test.go @@ -0,0 +1,70 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "io" + + rspb "helm.sh/helm/v3/pkg/release" +) + +var ( + b64 = base64.StdEncoding + magicGzip = []byte{0x1f, 0x8b, 0x08} +) + +// decodeRelease decodes the bytes of data into a release +// type. Data must contain a base64 encoded gzipped string of a +// valid release, otherwise an error is returned. +// +// It is copied over from the Helm project to be able to deal +// with encoded releases. +// Ref: https://github.com/helm/helm/blob/v3.9.0/pkg/storage/driver/util.go#L56 +func decodeRelease(data string) (*rspb.Release, error) { + // base64 decode string + b, err := b64.DecodeString(data) + if err != nil { + return nil, err + } + + // For backwards compatibility with releases that were stored before + // compression was introduced we skip decompression if the + // gzip magic header is not found + if bytes.Equal(b[0:3], magicGzip) { + r, err := gzip.NewReader(bytes.NewReader(b)) + if err != nil { + return nil, err + } + defer r.Close() + b2, err := io.ReadAll(r) + if err != nil { + return nil, err + } + b = b2 + } + + var rls rspb.Release + // unmarshal release object bytes + if err := json.Unmarshal(b, &rls); err != nil { + return nil, err + } + return &rls, nil +} diff --git a/internal/release/digest.go b/internal/release/digest.go new file mode 100644 index 000000000..90ae9966f --- /dev/null +++ b/internal/release/digest.go @@ -0,0 +1,36 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "encoding/json" + + "github.com/opencontainers/go-digest" +) + +// Digest calculates the digest of the given Observation by JSON encoding +// it into a hash.Hash of the given digest.Algorithm. The algorithm is expected +// to have been confirmed to be available by the caller, not doing this may +// result in panics. +func Digest(algo digest.Algorithm, rel Observation) digest.Digest { + digester := algo.Digester() + enc := json.NewEncoder(digester.Hash()) + if err := enc.Encode(rel); err != nil { + return "" + } + return digester.Digest() +} diff --git a/internal/release/digest_test.go b/internal/release/digest_test.go new file mode 100644 index 000000000..609d64bf5 --- /dev/null +++ b/internal/release/digest_test.go @@ -0,0 +1,51 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "testing" + + . "github.com/onsi/gomega" + + "github.com/opencontainers/go-digest" +) + +func TestDigest(t *testing.T) { + tests := []struct { + name string + algo digest.Algorithm + rel Observation + exp digest.Digest + }{ + { + name: "SHA256", + algo: digest.SHA256, + rel: Observation{ + Name: "foo", + }, + exp: "sha256:d0bc0774bd4b6d4aaa3c19e6a951352fe10a1a1a4e280ee06e85e972c572a74e", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got := Digest(tt.algo, tt.rel) + g.Expect(got).To(Equal(tt.exp)) + }) + } +} diff --git a/internal/release/name.go b/internal/release/name.go new file mode 100644 index 000000000..c01b68dfb --- /dev/null +++ b/internal/release/name.go @@ -0,0 +1,46 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "crypto/sha256" + "fmt" +) + +// ShortenName returns a short release name in the format of +// '-' for the given name +// if it exceeds 53 characters in length. +// +// The shortening is done by hashing the given release name with +// SHA256 and taking the first 12 characters of the resulting hash. +// The hash is then appended to the release name shortened to 40 +// characters divided by a hyphen separator. +// +// For example: 'some-front-appended-namespace-release-wi-1234567890ab' +// where '1234567890ab' are the first 12 characters of the SHA hash. +func ShortenName(name string) string { + if len(name) <= 53 { + return name + } + + const maxLength = 53 + const shortHashLength = 12 + + sum := fmt.Sprintf("%x", sha256.Sum256([]byte(name))) + shortName := name[:maxLength-(shortHashLength+1)] + "-" + return shortName + sum[:shortHashLength] +} diff --git a/internal/release/name_test.go b/internal/release/name_test.go new file mode 100644 index 000000000..416629d12 --- /dev/null +++ b/internal/release/name_test.go @@ -0,0 +1,55 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "testing" + + . "github.com/onsi/gomega" +) + +func TestShortName(t *testing.T) { + g := NewWithT(t) + + tests := []struct { + name string + expected string + }{ + { + name: "release-name", + expected: "release-name", + }, + { + name: "release-name-with-very-long-name-which-is-longer-than-53-characters", + expected: "release-name-with-very-long-name-which-i-788ca0d0d7b0", + }, + { + name: "another-release-name-with-very-long-name-which-is-longer-than-53-characters", + expected: "another-release-name-with-very-long-name-7e72150d5a36", + }, + { + name: "", + expected: "", + }, + } + + for _, tt := range tests { + got := ShortenName(tt.name) + g.Expect(got).To(Equal(tt.expected), got) + g.Expect(got).To(Satisfy(func(s string) bool { return len(s) <= 53 })) + } +} diff --git a/internal/release/observation.go b/internal/release/observation.go new file mode 100644 index 000000000..f2056ce42 --- /dev/null +++ b/internal/release/observation.go @@ -0,0 +1,198 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "encoding/json" + "io" + + "github.com/mitchellh/copystructure" + "helm.sh/helm/v3/pkg/chart" + helmrelease "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/chartutil" + "github.com/fluxcd/helm-controller/internal/digest" +) + +var ( + DefaultDataFilters = []DataFilter{ + IgnoreHookTestEvents, + } +) + +// DataFilter allows for filtering data from the returned Observation while +// making an observation. +type DataFilter func(rel *Observation) + +// IgnoreHookTestEvents ignores test event hooks. For example, to exclude it +// while generating a digest for the object. To prevent manual test triggers +// from a user to interfere with the checksum. +func IgnoreHookTestEvents(rel *Observation) { + if len(rel.Hooks) > 0 { + var hooks []helmrelease.Hook + for i := range rel.Hooks { + h := rel.Hooks[i] + if !IsHookForEvent(&h, helmrelease.HookTest) { + hooks = append(hooks, h) + } + } + rel.Hooks = hooks + } +} + +// Observation is a copy of a Helm release object, as observed to be written +// to the storage by a storage.Observer. The object is detached from the Helm +// storage object, and mutations to it do not change the underlying release +// object. +type Observation struct { + // Name of the release. + Name string `json:"name"` + // Version of the release, at times also called revision. + Version int `json:"version"` + // Info provides information about the release. + Info helmrelease.Info `json:"info"` + // ChartMetadata contains the current Chartfile data of the release. + ChartMetadata chart.Metadata `json:"chartMetadata"` + // Config is the set of extra Values added to the chart. + // These values override the default values inside the chart. + Config map[string]interface{} `json:"config"` + // Manifest is the string representation of the rendered template. + Manifest string `json:"manifest"` + // Hooks are all the hooks declared for this release, and the current + // state they are in. + Hooks []helmrelease.Hook `json:"hooks"` + // Namespace is the Kubernetes namespace of the release. + Namespace string `json:"namespace"` + // Labels of the release. + Labels map[string]string `json:"labels"` +} + +// Targets returns if the release matches the given name, namespace and +// version. If the version is 0, it matches any version. +func (o Observation) Targets(name, namespace string, version int) bool { + return o.Name == name && o.Namespace == namespace && (version == 0 || o.Version == version) +} + +// Encode JSON encodes the Observation and writes it into the given writer. +func (o Observation) Encode(w io.Writer) error { + enc := json.NewEncoder(w) + if err := enc.Encode(o); err != nil { + return err + } + return nil +} + +// ObserveRelease deep copies the values from the provided release.Release +// into a new Observation while omitting all chart data except metadata. +// If no filters are provided, it defaults to DefaultDataFilters. To not use +// any filters, pass an explicit empty slice. +func ObserveRelease(rel *helmrelease.Release, filter ...DataFilter) Observation { + if rel == nil { + return Observation{} + } + + if filter == nil { + filter = DefaultDataFilters + } + + obsRel := Observation{ + Name: rel.Name, + Version: rel.Version, + Config: nil, + Manifest: rel.Manifest, + Hooks: nil, + Namespace: rel.Namespace, + Labels: nil, + } + + if rel.Info != nil { + obsRel.Info = *rel.Info + } + + if rel.Chart != nil && rel.Chart.Metadata != nil { + if v, err := copystructure.Copy(rel.Chart.Metadata); err == nil { + obsRel.ChartMetadata = *v.(*chart.Metadata) + } + } + + if len(rel.Config) > 0 { + if v, err := copystructure.Copy(rel.Config); err == nil { + obsRel.Config = v.(map[string]interface{}) + } + } + + if len(rel.Hooks) > 0 { + obsRel.Hooks = make([]helmrelease.Hook, len(rel.Hooks)) + if v, err := copystructure.Copy(rel.Hooks); err == nil { + for i, h := range v.([]*helmrelease.Hook) { + obsRel.Hooks[i] = *h + } + } + } + + if len(rel.Labels) > 0 { + obsRel.Labels = make(map[string]string, len(rel.Labels)) + for i, v := range rel.Labels { + obsRel.Labels[i] = v + } + } + + for _, f := range filter { + f(&obsRel) + } + + return obsRel +} + +// ObservedToSnapshot returns a v2beta2.Snapshot constructed from the +// Observation data. Calculating the (config) digest using the +// digest.Canonical algorithm. +func ObservedToSnapshot(rls Observation) *v2.Snapshot { + return &v2.Snapshot{ + Digest: Digest(digest.Canonical, rls).String(), + Name: rls.Name, + Namespace: rls.Namespace, + Version: rls.Version, + ChartName: rls.ChartMetadata.Name, + ChartVersion: rls.ChartMetadata.Version, + ConfigDigest: chartutil.DigestValues(digest.Canonical, rls.Config).String(), + FirstDeployed: metav1.NewTime(rls.Info.FirstDeployed.Time), + LastDeployed: metav1.NewTime(rls.Info.LastDeployed.Time), + Deleted: metav1.NewTime(rls.Info.Deleted.Time), + Status: rls.Info.Status.String(), + } +} + +// TestHooksFromRelease returns the list of v2beta2.TestHookStatus for the +// given release, indexed by name. +func TestHooksFromRelease(rls *helmrelease.Release) map[string]*v2.TestHookStatus { + hooks := make(map[string]*v2.TestHookStatus) + for k, v := range GetTestHooks(rls) { + var h *v2.TestHookStatus + if v != nil { + h = &v2.TestHookStatus{ + LastStarted: metav1.NewTime(v.LastRun.StartedAt.Time), + LastCompleted: metav1.NewTime(v.LastRun.CompletedAt.Time), + Phase: v.LastRun.Phase.String(), + } + } + hooks[k] = h + } + return hooks +} diff --git a/internal/release/observation_test.go b/internal/release/observation_test.go new file mode 100644 index 000000000..d92742f85 --- /dev/null +++ b/internal/release/observation_test.go @@ -0,0 +1,376 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "bytes" + "testing" + + . "github.com/onsi/gomega" + "github.com/opencontainers/go-digest" + helmrelease "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v2 "github.com/fluxcd/helm-controller/api/v2beta2" + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestIgnoreHookTestEvents(t *testing.T) { + // testHookFixtures is a list of release.Hook in every possible LastRun state. + var testHookFixtures = []helmrelease.Hook{ + { + Name: "never-run-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + }, + { + Name: "passing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseSucceeded, + }, + }, + { + Name: "failing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseFailed, + }, + }, + { + Name: "passing-pre-install", + Events: []helmrelease.HookEvent{helmrelease.HookPreInstall}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseSucceeded, + }, + }, + } + + tests := []struct { + name string + hooks []helmrelease.Hook + want []helmrelease.Hook + }{ + { + name: "ignores test hooks", + hooks: testHookFixtures, + want: []helmrelease.Hook{ + testHookFixtures[3], + }, + }, + { + name: "no hooks", + hooks: []helmrelease.Hook{}, + want: []helmrelease.Hook{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obs := Observation{ + Hooks: tt.hooks, + } + IgnoreHookTestEvents(&obs) + g.Expect(obs.Hooks).To(Equal(tt.want)) + + }) + } +} + +func TestObservation_Targets(t *testing.T) { + tests := []struct { + name string + obs Observation + targetName string + targetNamespace string + targetVersion int + want bool + }{ + { + name: "matching name, namespace and version", + obs: Observation{ + Name: "foo", + Namespace: "bar", + Version: 2, + }, + targetName: "foo", + targetNamespace: "bar", + targetVersion: 2, + want: true, + }, + { + name: "matching name and namespace with version set to 0", + obs: Observation{ + Name: "foo", + Namespace: "bar", + Version: 2, + }, + targetName: "foo", + targetNamespace: "bar", + targetVersion: 0, + want: true, + }, + { + name: "name mismatch", + obs: Observation{ + Name: "baz", + Namespace: "bar", + Version: 2, + }, + targetName: "foo", + targetNamespace: "bar", + targetVersion: 2, + }, + { + name: "namespace mismatch", + obs: Observation{ + Name: "foo", + Namespace: "baz", + Version: 2, + }, + targetName: "foo", + targetNamespace: "bar", + targetVersion: 2, + }, + { + name: "matching name, namespace and version", + obs: Observation{ + Name: "foo", + Namespace: "bar", + Version: 2, + }, + targetName: "foo", + targetNamespace: "bar", + targetVersion: 3, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + g.Expect(tt.obs.Targets(tt.targetName, tt.targetNamespace, tt.targetVersion)).To(Equal(tt.want)) + }) + } +} + +func TestObservation_Encode(t *testing.T) { + g := NewWithT(t) + + o := Observation{ + Name: "foo", + Namespace: "bar", + Version: 2, + } + w := &bytes.Buffer{} + g.Expect(o.Encode(w)).ToNot(HaveOccurred()) + g.Expect(w.String()).ToNot(BeEmpty()) +} + +func TestObserveRelease(t *testing.T) { + var ( + testReleaseWithConfig = testutil.BuildRelease( + &helmrelease.MockReleaseOptions{ + Name: "foo", + Namespace: "namespace", + Version: 1, + Chart: testutil.BuildChart(), + }, + testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"}), + ) + testReleaseWithLabels = testutil.BuildRelease( + &helmrelease.MockReleaseOptions{ + Name: "foo", + Namespace: "namespace", + Version: 1, + Chart: testutil.BuildChart(), + }, + testutil.ReleaseWithLabels(map[string]string{"foo": "bar"}), + ) + ) + + tests := []struct { + name string + release *helmrelease.Release + filters []DataFilter + want Observation + }{ + { + name: "observes release", + release: smallRelease, + want: Observation{ + Name: smallRelease.Name, + Namespace: smallRelease.Namespace, + Version: smallRelease.Version, + Info: *smallRelease.Info, + ChartMetadata: *smallRelease.Chart.Metadata, + Manifest: smallRelease.Manifest, + Hooks: nil, + Labels: smallRelease.Labels, + Config: smallRelease.Config, + }, + }, + { + name: "observes with filters overwrite", + release: midRelease, + filters: []DataFilter{}, + want: Observation{ + Name: midRelease.Name, + Namespace: midRelease.Namespace, + Version: midRelease.Version, + Info: *midRelease.Info, + ChartMetadata: *midRelease.Chart.Metadata, + Manifest: midRelease.Manifest, + Hooks: func() []helmrelease.Hook { + var hooks []helmrelease.Hook + for _, h := range midRelease.Hooks { + hooks = append(hooks, *h) + } + return hooks + }(), + Labels: midRelease.Labels, + Config: midRelease.Config, + }, + }, + { + name: "observes config", + release: testReleaseWithConfig, + want: Observation{ + Name: testReleaseWithConfig.Name, + Namespace: testReleaseWithConfig.Namespace, + Version: testReleaseWithConfig.Version, + Info: *testReleaseWithConfig.Info, + ChartMetadata: *testReleaseWithConfig.Chart.Metadata, + Config: testReleaseWithConfig.Config, + Manifest: testReleaseWithConfig.Manifest, + Hooks: []helmrelease.Hook{ + *testReleaseWithConfig.Hooks[0], + }, + }, + }, + { + name: "observes labels", + release: testReleaseWithLabels, + want: Observation{ + Name: testReleaseWithLabels.Name, + Namespace: testReleaseWithLabels.Namespace, + Version: testReleaseWithLabels.Version, + Info: *testReleaseWithLabels.Info, + ChartMetadata: *testReleaseWithLabels.Chart.Metadata, + Config: testReleaseWithLabels.Config, + Labels: testReleaseWithLabels.Labels, + Manifest: testReleaseWithLabels.Manifest, + Hooks: []helmrelease.Hook{ + *testReleaseWithLabels.Hooks[0], + }, + }, + }, + { + name: "empty release", + release: &helmrelease.Release{}, + want: Observation{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + g.Expect(ObserveRelease(tt.release, tt.filters...)).To(testutil.Equal(tt.want)) + }) + } +} + +func TestObservedToSnapshot(t *testing.T) { + g := NewWithT(t) + + obs := ObserveRelease(testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "foo", + Namespace: "namespace", + Version: 1, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithConfig(map[string]interface{}{"foo": "bar"}))) + + got := ObservedToSnapshot(obs) + + g.Expect(got.Name).To(Equal(obs.Name)) + g.Expect(got.Namespace).To(Equal(obs.Namespace)) + g.Expect(got.Version).To(Equal(obs.Version)) + g.Expect(got.ChartName).To(Equal(obs.ChartMetadata.Name)) + g.Expect(got.ChartVersion).To(Equal(obs.ChartMetadata.Version)) + g.Expect(got.Status).To(BeEquivalentTo(obs.Info.Status)) + + g.Expect(obs.Info.FirstDeployed.Time.Equal(got.FirstDeployed.Time)).To(BeTrue()) + g.Expect(obs.Info.LastDeployed.Time.Equal(got.LastDeployed.Time)).To(BeTrue()) + g.Expect(obs.Info.Deleted.Time.Equal(got.Deleted.Time)).To(BeTrue()) + + g.Expect(got.Digest).ToNot(BeEmpty()) + g.Expect(digest.Digest(got.Digest).Validate()).To(Succeed()) + + g.Expect(got.ConfigDigest).ToNot(BeEmpty()) + g.Expect(digest.Digest(got.ConfigDigest).Validate()).To(Succeed()) +} + +func TestTestHooksFromRelease(t *testing.T) { + g := NewWithT(t) + + hooks := []*helmrelease.Hook{ + { + Name: "never-run-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + }, + { + Name: "passing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseSucceeded, + }, + }, + { + Name: "failing-test", + Events: []helmrelease.HookEvent{helmrelease.HookTest}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseFailed, + }, + }, + { + Name: "passing-pre-install", + Events: []helmrelease.HookEvent{helmrelease.HookPreInstall}, + LastRun: helmrelease.HookExecution{ + Phase: helmrelease.HookPhaseSucceeded, + }, + }, + } + rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{ + Name: "foo", + Namespace: "namespace", + Version: 1, + Chart: testutil.BuildChart(), + }, testutil.ReleaseWithHooks(hooks)) + + g.Expect(TestHooksFromRelease(rls)).To(testutil.Equal(map[string]*v2.TestHookStatus{ + hooks[0].Name: {}, + hooks[1].Name: { + LastStarted: metav1.Time{Time: hooks[1].LastRun.StartedAt.Time}, + LastCompleted: metav1.Time{Time: hooks[1].LastRun.CompletedAt.Time}, + Phase: hooks[1].LastRun.Phase.String(), + }, + hooks[2].Name: { + LastStarted: metav1.Time{Time: hooks[2].LastRun.StartedAt.Time}, + LastCompleted: metav1.Time{Time: hooks[2].LastRun.CompletedAt.Time}, + Phase: hooks[2].LastRun.Phase.String(), + }, + })) +} diff --git a/internal/release/observed_bench_test.go b/internal/release/observed_bench_test.go new file mode 100644 index 000000000..77ef9fd5e --- /dev/null +++ b/internal/release/observed_bench_test.go @@ -0,0 +1,49 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "testing" + + "github.com/opencontainers/go-digest" + "helm.sh/helm/v3/pkg/release" + + intdigest "github.com/fluxcd/helm-controller/internal/digest" +) + +func init() { + intdigest.Canonical = digest.SHA256 +} + +func benchmarkNewObservedRelease(rel release.Release, b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + ObservedToSnapshot(ObserveRelease(&rel)) + } +} + +func BenchmarkNewObservedReleaseSmall(b *testing.B) { + benchmarkNewObservedRelease(*smallRelease, b) +} + +func BenchmarkNewObservedReleaseMid(b *testing.B) { + benchmarkNewObservedRelease(*midRelease, b) +} + +func BenchmarkNewObservedReleaseBigger(b *testing.B) { + benchmarkNewObservedRelease(*biggerRelease, b) +} diff --git a/internal/release/suite_test.go b/internal/release/suite_test.go new file mode 100644 index 000000000..659b03f9e --- /dev/null +++ b/internal/release/suite_test.go @@ -0,0 +1,62 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "fmt" + "log" + "os" + "testing" + + "helm.sh/helm/v3/pkg/release" +) + +var ( + // smallRelease is 125K while encoded. + smallRelease *release.Release + // midRelease is 17K while encoded, but heavier in metadata than smallRelease. + midRelease *release.Release + // biggerRelease is 862K while encoded. + biggerRelease *release.Release +) + +func TestMain(m *testing.M) { + var err error + if smallRelease, err = decodeReleaseFromFile("testdata/istio-base-1"); err != nil { + log.Fatal(err) + } + if midRelease, err = decodeReleaseFromFile("testdata/podinfo-helm-1"); err != nil { + log.Fatal(err) + } + if biggerRelease, err = decodeReleaseFromFile("testdata/prom-stack-1"); err != nil { + log.Fatal(err) + } + r := m.Run() + os.Exit(r) +} + +func decodeReleaseFromFile(path string) (*release.Release, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to load encoded release data: %w", err) + } + rel, err := decodeRelease(string(b)) + if err != nil { + return nil, fmt.Errorf("failed to decode release data: %w", err) + } + return rel, nil +} diff --git a/internal/release/testdata/istio-base-1 b/internal/release/testdata/istio-base-1 new file mode 100644 index 000000000..a99ff1f77 --- /dev/null +++ b/internal/release/testdata/istio-base-1 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/internal/release/testdata/podinfo-helm-1 b/internal/release/testdata/podinfo-helm-1 new file mode 100644 index 000000000..e1e387187 --- /dev/null +++ b/internal/release/testdata/podinfo-helm-1 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/internal/release/testdata/prom-stack-1 b/internal/release/testdata/prom-stack-1 new file mode 100644 index 000000000..ea3a7899a --- /dev/null +++ b/internal/release/testdata/prom-stack-1 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/internal/release/util.go b/internal/release/util.go new file mode 100644 index 000000000..5ef10718a --- /dev/null +++ b/internal/release/util.go @@ -0,0 +1,45 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + helmrelease "helm.sh/helm/v3/pkg/release" +) + +// GetTestHooks returns the list of test hooks for the given release, indexed +// by hook name. +func GetTestHooks(rls *helmrelease.Release) map[string]*helmrelease.Hook { + th := make(map[string]*helmrelease.Hook) + for _, h := range rls.Hooks { + if IsHookForEvent(h, helmrelease.HookTest) { + th[h.Name] = h + } + } + return th +} + +// IsHookForEvent returns if the given hook fires on the provided event. +func IsHookForEvent(hook *helmrelease.Hook, event helmrelease.HookEvent) bool { + if hook != nil { + for _, e := range hook.Events { + if e == event { + return true + } + } + } + return false +} diff --git a/internal/release/util_test.go b/internal/release/util_test.go new file mode 100644 index 000000000..c4555379d --- /dev/null +++ b/internal/release/util_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "testing" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + + "github.com/fluxcd/helm-controller/internal/testutil" +) + +func TestGetTestHooks(t *testing.T) { + g := NewWithT(t) + + hooks := []*helmrelease.Hook{ + { + Name: "pre-install", + Events: []helmrelease.HookEvent{ + helmrelease.HookPreInstall, + }, + }, + { + Name: "test", + Events: []helmrelease.HookEvent{ + helmrelease.HookTest, + }, + }, + { + Name: "post-install", + Events: []helmrelease.HookEvent{ + helmrelease.HookPostInstall, + }, + }, + { + Name: "combined-test-hook", + Events: []helmrelease.HookEvent{ + helmrelease.HookPostRollback, + helmrelease.HookTest, + }, + }, + } + + g.Expect(GetTestHooks(&helmrelease.Release{ + Hooks: hooks, + })).To(testutil.Equal(map[string]*helmrelease.Hook{ + hooks[1].Name: hooks[1], + hooks[3].Name: hooks[3], + })) +} + +func TestIsHookForEvent(t *testing.T) { + g := NewWithT(t) + + hook := &helmrelease.Hook{ + Events: []helmrelease.HookEvent{ + helmrelease.HookPreInstall, + helmrelease.HookPostInstall, + }, + } + g.Expect(IsHookForEvent(hook, helmrelease.HookPreInstall)).To(BeTrue()) + g.Expect(IsHookForEvent(hook, helmrelease.HookPostInstall)).To(BeTrue()) + g.Expect(IsHookForEvent(hook, helmrelease.HookTest)).To(BeFalse()) +} diff --git a/internal/runner/runner.go b/internal/runner/runner.go index afdce270e..c6f9234b9 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -46,6 +46,7 @@ import ( v2 "github.com/fluxcd/helm-controller/api/v2beta1" "github.com/fluxcd/helm-controller/internal/features" + intpostrender "github.com/fluxcd/helm-controller/internal/postrender" ) var accessor = meta.NewAccessor() @@ -100,17 +101,22 @@ func NewRunner(getter genericclioptions.RESTClientGetter, storageNamespace strin // Create post renderer instances from HelmRelease and combine them into // a single combined post renderer. func postRenderers(hr v2.HelmRelease) (postrender.PostRenderer, error) { - var combinedRenderer = newCombinedPostRenderer() + renderers := make([]postrender.PostRenderer, 0) for _, r := range hr.Spec.PostRenderers { if r.Kustomize != nil { - combinedRenderer.addRenderer(newPostRendererKustomize(r.Kustomize)) + renderers = append(renderers, &intpostrender.Kustomize{ + Patches: r.Kustomize.Patches, + PatchesStrategicMerge: r.Kustomize.PatchesStrategicMerge, + PatchesJSON6902: r.Kustomize.PatchesJSON6902, + Images: r.Kustomize.Images, + }) } } - combinedRenderer.addRenderer(newPostRendererOriginLabels(&hr)) - if len(combinedRenderer.renderers) == 0 { + renderers = append(renderers, intpostrender.NewOriginLabels(v2.GroupVersion.Group, hr.Namespace, hr.Name)) + if len(renderers) == 0 { return nil, nil } - return &combinedRenderer, nil + return intpostrender.NewCombined(renderers...), nil } // Install runs a Helm install action for the given v2beta1.HelmRelease. @@ -459,6 +465,13 @@ func mergeLabels(obj runtime.Object, labels map[string]string) error { return accessor.SetLabels(obj, mergeStrStrMaps(current, labels)) } +func originLabels(name, namespace string) map[string]string { + return map[string]string{ + fmt.Sprintf("%s/name", v2.GroupVersion.Group): name, + fmt.Sprintf("%s/namespace", v2.GroupVersion.Group): namespace, + } +} + func resourceString(info *resource.Info) string { _, k := info.Mapping.GroupVersionKind.ToAPIVersionAndKind() return fmt.Sprintf( diff --git a/internal/storage/failing.go b/internal/storage/failing.go new file mode 100644 index 000000000..3669fcece --- /dev/null +++ b/internal/storage/failing.go @@ -0,0 +1,104 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/storage/driver" +) + +const ( + // FailingDriverName is the name of the failing driver. + FailingDriverName = "failing" +) + +// Failing is a failing Helm storage driver that returns the configured errors. +type Failing struct { + driver.Driver + + // GetErr is returned by Get if configured. If not set, the embedded driver + // result is returned. + GetErr error + // ListErr is returned by List if configured. If not set, the embedded + // driver result is returned. + ListErr error + // QueryErr is returned by Query if configured. If not set, the embedded + // driver result is returned. + QueryErr error + // CreateErr is returned by Create if configured. If not set, the embedded + // driver result is returned. + CreateErr error + // UpdateErr is returned by Update if configured. If not set, the embedded + // driver result is returned. + UpdateErr error + // DeleteErr is returned by Delete if configured. If not set, the embedded + // driver result is returned. + DeleteErr error +} + +// Name returns the name of the driver. +func (o *Failing) Name() string { + return FailingDriverName +} + +// Get returns GetErr, or the embedded driver result. +func (o *Failing) Get(key string) (*release.Release, error) { + if o.GetErr != nil { + return nil, o.GetErr + } + return o.Driver.Get(key) +} + +// List returns ListErr, or the embedded driver result. +func (o *Failing) List(filter func(*release.Release) bool) ([]*release.Release, error) { + if o.ListErr != nil { + return nil, o.ListErr + } + return o.Driver.List(filter) +} + +// Query returns QueryErr, or the embedded driver result. +func (o *Failing) Query(keyvals map[string]string) ([]*release.Release, error) { + if o.QueryErr != nil { + return nil, o.QueryErr + } + return o.Driver.Query(keyvals) +} + +// Create returns CreateErr, or the embedded driver result. +func (o *Failing) Create(key string, rls *release.Release) error { + if o.CreateErr != nil { + return o.CreateErr + } + return o.Driver.Create(key, rls) +} + +// Update returns UpdateErr, or the embedded driver result. +func (o *Failing) Update(key string, rls *release.Release) error { + if o.UpdateErr != nil { + return o.UpdateErr + } + return o.Driver.Update(key, rls) +} + +// Delete returns DeleteErr, or the embedded driver result. +func (o *Failing) Delete(key string) (*release.Release, error) { + if o.DeleteErr != nil { + return nil, o.DeleteErr + } + return o.Driver.Delete(key) +} diff --git a/internal/storage/observer.go b/internal/storage/observer.go new file mode 100644 index 000000000..a0885ad76 --- /dev/null +++ b/internal/storage/observer.go @@ -0,0 +1,115 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + helmrelease "helm.sh/helm/v3/pkg/release" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" +) + +// ObserverDriverName contains the string representation of Observer. +const ObserverDriverName = "observer" + +// Observer is an observing Helm storage driver. +// +// It can be configured with a list of ObserveFunc functions that are called +// after a successful persistence operation to the underlying driver. +// +// This allows for observations on persisted state as performed by the driver, +// and works around the inconsistent behavior of some Helm actions that may +// return an object that was not actually persisted to the Helm storage +// (e.g. because a validation error occurred during a Helm upgrade). +type Observer struct { + // driver holds the underlying driver.Driver implementation which is used + // to persist data to, and retrieve from. + driver helmdriver.Driver + // observers holds a slice of ObserveFunc which are called after a + // successful persistence of a release to storage driver. + observers []ObserveFunc +} + +// ObserveFunc observes a release which has been successfully persisted to +// storage. +// NOTE: while it takes a pointer, the caller is expected to perform a +// read-only operation. +type ObserveFunc func(rel *helmrelease.Release) + +// NewObserver creates a new Observer for the given Helm storage driver. +func NewObserver(driver helmdriver.Driver, observers ...ObserveFunc) *Observer { + return &Observer{ + driver: driver, + observers: observers, + } +} + +// Name returns the name of the driver. +func (o *Observer) Name() string { + return ObserverDriverName +} + +// Get returns the release named by key or returns ErrReleaseNotFound. +func (o *Observer) Get(key string) (*helmrelease.Release, error) { + return o.driver.Get(key) +} + +// List returns the list of all releases such that filter(release) == true. +func (o *Observer) List(filter func(*helmrelease.Release) bool) ([]*helmrelease.Release, error) { + return o.driver.List(filter) +} + +// Query returns the set of releases that match the provided set of labels. +func (o *Observer) Query(keyvals map[string]string) ([]*helmrelease.Release, error) { + return o.driver.Query(keyvals) +} + +// Create creates a new release or returns driver.ErrReleaseExists. +// It observes the release as provided after a successful creation. +func (o *Observer) Create(key string, rls *helmrelease.Release) error { + if err := o.driver.Create(key, rls); err != nil { + return err + } + for _, obs := range o.observers { + obs(rls) + } + return nil +} + +// Update updates a release or returns driver.ErrReleaseNotFound. +// After a successful update, it observes the release as provided. +func (o *Observer) Update(key string, rls *helmrelease.Release) error { + if err := o.driver.Update(key, rls); err != nil { + return err + } + for _, obs := range o.observers { + obs(rls) + } + return nil +} + +// Delete deletes a release or returns driver.ErrReleaseNotFound. +// After a successful deletion, it observes the release as returned by the +// embedded driver.Deletor. +func (o *Observer) Delete(key string) (*helmrelease.Release, error) { + rls, err := o.driver.Delete(key) + if err != nil { + return nil, err + } + for _, obs := range o.observers { + obs(rls) + } + return rls, nil +} diff --git a/internal/storage/observer_test.go b/internal/storage/observer_test.go new file mode 100644 index 000000000..b8e055e27 --- /dev/null +++ b/internal/storage/observer_test.go @@ -0,0 +1,222 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "fmt" + "testing" + + . "github.com/onsi/gomega" + helmrelease "helm.sh/helm/v3/pkg/release" + helmdriver "helm.sh/helm/v3/pkg/storage/driver" +) + +func TestObserver_Name(t *testing.T) { + g := NewWithT(t) + + o := NewObserver(helmdriver.NewMemory()) + g.Expect(o.Name()).To(Equal(ObserverDriverName)) +} + +func TestObserver_Get(t *testing.T) { + t.Run("ignores get", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + got, err := o.Get(key) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(Equal(rel)) + g.Expect(called).To(BeFalse()) + }) +} + +func TestObserver_List(t *testing.T) { + t.Run("ignores list", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + got, err := o.List(func(r *helmrelease.Release) bool { + // Include everything + return true + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(HaveLen(1)) + g.Expect(got[0]).To(Equal(rel)) + g.Expect(called).To(BeFalse()) + }) +} + +func TestObserver_Query(t *testing.T) { + t.Run("ignores query", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + rls, err := o.Query(map[string]string{"status": "deployed"}) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(rls).To(HaveLen(1)) + g.Expect(rls[0]).To(Equal(rel)) + g.Expect(called).To(BeFalse()) + }) +} + +func TestObserver_Create(t *testing.T) { + t.Run("observes create success", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + g.Expect(o.Create(key, rel)).To(Succeed()) + g.Expect(called).To(BeTrue()) + }) + + t.Run("ignores create error", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + + rel := releaseStub("error", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + rel2 := releaseStub("error", 1, "ns1", helmrelease.StatusFailed) + g.Expect(o.Create(key, rel2)).To(HaveOccurred()) + g.Expect(called).To(BeFalse()) + }) +} + +func TestObserver_Update(t *testing.T) { + t.Run("observes update success", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + g.Expect(o.Update(key, rel)).To(Succeed()) + g.Expect(called).To(BeTrue()) + }) + + t.Run("ignores update error", func(t *testing.T) { + g := NewWithT(t) + + var called bool + o := NewObserver(helmdriver.NewMemory(), func(rls *helmrelease.Release) { + called = true + }) + + rel := releaseStub("error", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(o.Update(key, rel)).To(HaveOccurred()) + g.Expect(called).To(BeFalse()) + }) +} + +func TestObserver_Delete(t *testing.T) { + t.Run("observes delete success", func(t *testing.T) { + g := NewWithT(t) + + ms := helmdriver.NewMemory() + rel := releaseStub("success", 1, "ns1", helmrelease.StatusDeployed) + key := testKey(rel.Name, rel.Version) + g.Expect(ms.Create(key, rel)).To(Succeed()) + + var called bool + o := NewObserver(ms, func(rls *helmrelease.Release) { + called = true + }) + + got, err := o.Delete(key) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).ToNot(BeNil()) + g.Expect(called).To(BeTrue()) + + _, err = ms.Get(key) + g.Expect(err).To(Equal(helmdriver.ErrReleaseNotFound)) + }) + + t.Run("delete release not found", func(t *testing.T) { + g := NewWithT(t) + + var called bool + o := NewObserver(helmdriver.NewMemory(), func(rls *helmrelease.Release) { + called = true + }) + + key := testKey("error", 1) + got, err := o.Delete(key) + g.Expect(err).To(Equal(helmdriver.ErrReleaseNotFound)) + g.Expect(got).To(BeNil()) + g.Expect(called).To(BeFalse()) + }) +} + +func releaseStub(name string, version int, namespace string, status helmrelease.Status) *helmrelease.Release { + return &helmrelease.Release{ + Name: name, + Version: version, + Namespace: namespace, + Info: &helmrelease.Info{Status: status}, + } +} + +func testKey(name string, vers int) string { + return fmt.Sprintf("%s.v%d", name, vers) +} diff --git a/internal/strings/title.go b/internal/strings/title.go new file mode 100644 index 000000000..78bb4a591 --- /dev/null +++ b/internal/strings/title.go @@ -0,0 +1,40 @@ +package strings + +import ( + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +// Title returns a copy of the string s with all Unicode letters that begin +// words mapped to their title case. It uses language.Und for word boundaries. +// For a more general solution, see TitleWithLanguage. +func Title(s string) string { + return TitleWithLanguage(s, language.Und) +} + +// TitleWithLanguage returns a copy of the string s with all Unicode letters +// that begin words mapped to their title case. +func TitleWithLanguage(s string, lang language.Tag) string { + return cases.Title(lang, cases.NoLower).String(s) +} + +// Normalize returns a copy of the string s with the first word mapped to its +// title case. It uses language.Und for word boundaries. +// For a more general solution, see NormalizeWithLanguage. +func Normalize(s string) string { + return NormalizeWithLanguage(s, language.Und) +} + +// NormalizeWithLanguage returns a copy of the string s with the first word +// mapped to its title case. If lang is not nil, it is used to determine the +// language for which the case transformation should be performed. If lang is +// nil, language.Und is used. +func NormalizeWithLanguage(s string, lang language.Tag) string { + words := strings.Fields(s) + if len(words) > 0 { + words[0] = TitleWithLanguage(words[0], lang) + } + return strings.Join(words, " ") +} diff --git a/internal/strings/title_test.go b/internal/strings/title_test.go new file mode 100644 index 000000000..88af9c38e --- /dev/null +++ b/internal/strings/title_test.go @@ -0,0 +1,153 @@ +package strings + +import ( + "testing" + + "golang.org/x/text/language" +) + +func TestTitle(t *testing.T) { + tests := []struct { + name string + s string + want string + }{ + { + name: "sentence", + s: "the quick brown fox jumps over the lazy dog", + want: "The Quick Brown Fox Jumps Over The Lazy Dog", + }, + { + name: "sentence with uppercase word", + s: "the quick brown fox jumps over the LAZY dog", + want: "The Quick Brown Fox Jumps Over The LAZY Dog", + }, + { + name: "empty string", + s: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Title(tt.s); got != tt.want { + t.Errorf("Title() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTitleWithLanguage(t *testing.T) { + tests := []struct { + name string + s string + lang language.Tag + want string + }{ + { + name: "Dutch sentence", + s: "de snelle bruine vos springt over de luie hond in ijburg", + lang: language.Dutch, + want: "De Snelle Bruine Vos Springt Over De Luie Hond In IJburg", + }, + { + name: "English sentence", + s: "the quick brown fox jumps over the lazy dog", + lang: language.English, + want: "The Quick Brown Fox Jumps Over The Lazy Dog", + }, + { + name: "English sentence with uppercase word", + s: "the quick brown fox jumps over the LAZY dog", + lang: language.English, + want: "The Quick Brown Fox Jumps Over The LAZY Dog", + }, + { + name: "empty", + s: "", + lang: language.English, + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := TitleWithLanguage(tt.s, tt.lang); got != tt.want { + t.Errorf("TitleWithLanguage() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNormalize(t *testing.T) { + tests := []struct { + name string + s string + want string + }{ + { + name: "sentence", + s: "the quick brown fox jumps over the lazy dog", + want: "The quick brown fox jumps over the lazy dog", + }, + { + name: "sentence with uppercase word", + s: "MacDonald had a farm", + want: "MacDonald had a farm", + }, + { + name: "empty string", + s: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Normalize(tt.s); got != tt.want { + t.Errorf("Normalize() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNormalizeWithLanguage(t *testing.T) { + tests := []struct { + name string + s string + lang language.Tag + want string + }{ + { + name: "Dutch sentence", + s: "ijburg is een wijk in Amsterdam", + lang: language.Dutch, + want: "IJburg is een wijk in Amsterdam", + }, + { + name: "English sentence", + s: "the quick brown fox jumps over the lazy dog", + lang: language.English, + want: "The quick brown fox jumps over the lazy dog", + }, + { + name: "English sentence with uppercase word", + s: "MacDonald had a farm", + lang: language.English, + want: "MacDonald had a farm", + }, + { + name: "empty", + s: "", + lang: language.Und, + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := NormalizeWithLanguage(tt.s, tt.lang); got != tt.want { + t.Errorf("NormalizeWithLanguage() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/testutil/equal_cmp.go b/internal/testutil/equal_cmp.go new file mode 100644 index 000000000..a8ca1960c --- /dev/null +++ b/internal/testutil/equal_cmp.go @@ -0,0 +1,67 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "github.com/google/go-cmp/cmp" + "github.com/onsi/gomega/types" +) + +// This file was adapted from https://github.com/KamikazeZirou/equal-cmp +// Original license follows: +// +// MIT License +// +// Copyright (c) 2021 KamikazeZirou +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// Equal uses go-cmp to compare actual with expected. Equal is strict about +// types when performing comparisons. +func Equal(expected interface{}, options ...cmp.Option) types.GomegaMatcher { + return &equalCmpMatcher{ + expected: expected, + options: options, + } +} + +type equalCmpMatcher struct { + expected interface{} + options cmp.Options +} + +func (matcher *equalCmpMatcher) Match(actual interface{}) (success bool, err error) { + return cmp.Equal(actual, matcher.expected, matcher.options), nil +} + +func (matcher *equalCmpMatcher) FailureMessage(actual interface{}) (message string) { + diff := cmp.Diff(matcher.expected, actual, matcher.options) + return "Mismatch (-want, +got):\n" + diff +} + +func (matcher *equalCmpMatcher) NegatedFailureMessage(actual interface{}) (message string) { + diff := cmp.Diff(matcher.expected, actual, matcher.options) + return "Mismatch (-want, +got):\n" + diff +} diff --git a/internal/testutil/fake_recorder.go b/internal/testutil/fake_recorder.go new file mode 100644 index 000000000..24d877fb3 --- /dev/null +++ b/internal/testutil/fake_recorder.go @@ -0,0 +1,116 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "fmt" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + + _ "k8s.io/client-go/tools/record" +) + +// FakeRecorder is used as a fake during tests. +// +// It was invented to be used in tests which require more precise control over +// e.g. assertions of specific event fields like Reason. For which string +// comparisons on the concentrated event message using record.FakeRecorder is +// not sufficient. +// +// To empty the Events channel into a slice of the recorded events, use +// GetEvents(). Not initializing Events will cause the recorder to not record +// any messages. +type FakeRecorder struct { + Events chan corev1.Event + IncludeObject bool +} + +// NewFakeRecorder creates new fake event recorder with an Events channel with +// the given size. Setting includeObject to true will cause the recorder to +// include the object reference in the events. +// +// To initialize a recorder which does not record any events, simply use: +// +// recorder := new(FakeRecorder) +func NewFakeRecorder(bufferSize int, includeObject bool) *FakeRecorder { + return &FakeRecorder{ + Events: make(chan corev1.Event, bufferSize), + IncludeObject: includeObject, + } +} + +// Event emits an event with the given message. +func (f *FakeRecorder) Event(obj runtime.Object, eventType, reason, message string) { + f.Eventf(obj, eventType, reason, message) +} + +// Eventf emits an event with the given message. +func (f *FakeRecorder) Eventf(obj runtime.Object, eventType, reason, message string, args ...any) { + if f.Events != nil { + f.Events <- f.generateEvent(obj, nil, eventType, reason, message, args...) + } +} + +// AnnotatedEventf emits an event with annotations. +func (f *FakeRecorder) AnnotatedEventf(obj runtime.Object, annotations map[string]string, eventType, reason, message string, args ...any) { + if f.Events != nil { + f.Events <- f.generateEvent(obj, annotations, eventType, reason, message, args...) + } +} + +// GetEvents empties the Events channel and returns a slice of recorded events. +// If the Events channel is nil, it returns nil. +func (f *FakeRecorder) GetEvents() (events []corev1.Event) { + if f.Events != nil { + for { + select { + case e := <-f.Events: + events = append(events, e) + default: + return events + } + } + } + return nil +} + +// generateEvent generates a new mocked event with the given parameters. +func (f *FakeRecorder) generateEvent(obj runtime.Object, annotations map[string]string, eventType, reason, message string, args ...any) corev1.Event { + event := corev1.Event{ + InvolvedObject: objectReference(obj, f.IncludeObject), + Type: eventType, + Reason: reason, + Message: fmt.Sprintf(message, args...), + } + if annotations != nil { + event.ObjectMeta.Annotations = annotations + } + return event +} + +// objectReference returns an object reference for the given object with the +// kind and (group) API version set. +func objectReference(obj runtime.Object, includeObject bool) corev1.ObjectReference { + if !includeObject { + return corev1.ObjectReference{} + } + + return corev1.ObjectReference{ + Kind: obj.GetObjectKind().GroupVersionKind().Kind, + APIVersion: obj.GetObjectKind().GroupVersionKind().GroupVersion().String(), + } +} diff --git a/internal/testutil/helm_time.go b/internal/testutil/helm_time.go new file mode 100644 index 000000000..5c4b81639 --- /dev/null +++ b/internal/testutil/helm_time.go @@ -0,0 +1,33 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "time" + + helmtime "helm.sh/helm/v3/pkg/time" +) + +// MustParseHelmTime parses a string into a Helm time.Time, panicking if it +// fails. +func MustParseHelmTime(t string) helmtime.Time { + res, err := helmtime.Parse(time.RFC3339, t) + if err != nil { + panic(err) + } + return res +} diff --git a/internal/testutil/mock_chart.go b/internal/testutil/mock_chart.go new file mode 100644 index 000000000..72c458806 --- /dev/null +++ b/internal/testutil/mock_chart.go @@ -0,0 +1,167 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "fmt" + + helmchart "helm.sh/helm/v3/pkg/chart" +) + +var manifestTmpl = `apiVersion: v1 +kind: ConfigMap +metadata: + name: cm + namespace: %[1]s +data: + foo: bar +` + +var manifestWithHookTmpl = `apiVersion: v1 +kind: ConfigMap +metadata: + name: hook + namespace: %[1]s + annotations: + "helm.sh/hook": post-install,pre-delete,post-upgrade +data: + name: value +` + +var manifestWithFailingHookTmpl = `apiVersion: v1 +kind: Pod +metadata: + name: failing-hook + namespace: %[1]s + annotations: + "helm.sh/hook": post-install,pre-delete,post-upgrade +spec: + containers: + - name: test + image: alpine + command: ["/bin/sh", "-c", "exit 1"] +` + +var manifestWithTestHookTmpl = `apiVersion: v1 +kind: ConfigMap +metadata: + name: test-hook + namespace: %[1]s + annotations: + "helm.sh/hook": test +data: + test: data +` + +var manifestWithFailingTestHookTmpl = `apiVersion: v1 +kind: Pod +metadata: + name: failing-test-hook + namespace: %[1]s + annotations: + "helm.sh/hook": test +spec: + containers: + - name: test + image: alpine + command: ["/bin/sh", "-c", "exit 1"] + restartPolicy: Never +` + +// ChartOptions is a helper to build a Helm chart object. +type ChartOptions struct { + *helmchart.Chart +} + +// ChartOption is a function that can be used to modify a chart. +type ChartOption func(*ChartOptions) + +// BuildChart returns a Helm chart object built with basic data +// and any provided chart options. +func BuildChart(opts ...ChartOption) *helmchart.Chart { + c := &ChartOptions{ + Chart: &helmchart.Chart{ + // TODO: This should be more complete. + Metadata: &helmchart.Metadata{ + APIVersion: "v1", + Name: "hello", + Version: "0.1.0", + }, + // This adds a basic template and hooks. + Templates: []*helmchart.File{ + { + Name: "templates/manifest", + Data: []byte(fmt.Sprintf(manifestTmpl, "{{ default .Release.Namespace }}")), + }, + { + Name: "templates/hooks", + Data: []byte(fmt.Sprintf(manifestWithHookTmpl, "{{ default .Release.Namespace }}")), + }, + }, + }, + } + + for _, opt := range opts { + opt(c) + } + + return c.Chart +} + +// ChartWithName sets the name of the chart. +func ChartWithName(name string) ChartOption { + return func(opts *ChartOptions) { + opts.Metadata.Name = name + } +} + +// ChartWithVersion sets the version of the chart. +func ChartWithVersion(version string) ChartOption { + return func(opts *ChartOptions) { + opts.Metadata.Version = version + } +} + +// ChartWithFailingHook appends a failing hook to the chart. +func ChartWithFailingHook() ChartOption { + return func(opts *ChartOptions) { + opts.Templates = append(opts.Templates, &helmchart.File{ + Name: "templates/failing-hook", + Data: []byte(fmt.Sprintf(manifestWithFailingHookTmpl, "{{ default .Release.Namespace }}")), + }) + } +} + +// ChartWithTestHook appends a test hook to the chart. +func ChartWithTestHook() ChartOption { + return func(opts *ChartOptions) { + opts.Templates = append(opts.Templates, &helmchart.File{ + Name: "templates/test-hooks", + Data: []byte(fmt.Sprintf(manifestWithTestHookTmpl, "{{ default .Release.Namespace }}")), + }) + } +} + +// ChartWithFailingTestHook appends a failing test hook to the chart. +func ChartWithFailingTestHook() ChartOption { + return func(options *ChartOptions) { + options.Templates = append(options.Templates, &helmchart.File{ + Name: "templates/test-hooks", + Data: []byte(fmt.Sprintf(manifestWithFailingTestHookTmpl, "{{ default .Release.Namespace }}")), + }) + } +} diff --git a/internal/testutil/mock_release.go b/internal/testutil/mock_release.go new file mode 100644 index 000000000..e37b3e762 --- /dev/null +++ b/internal/testutil/mock_release.go @@ -0,0 +1,126 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "fmt" + + helmrelease "helm.sh/helm/v3/pkg/release" +) + +// ReleaseOptions is a helper to build a Helm release mock. +type ReleaseOptions struct { + *helmrelease.Release +} + +// ReleaseOption is a function that can be used to modify a release. +type ReleaseOption func(*ReleaseOptions) + +// BuildRelease builds a release with release.Mock using the given options, +// and applies any provided options to the release before returning it. +func BuildRelease(mockOpts *helmrelease.MockReleaseOptions, opts ...ReleaseOption) *helmrelease.Release { + mock := helmrelease.Mock(mockOpts) + r := &ReleaseOptions{Release: mock} + + for _, opt := range opts { + opt(r) + } + + return r.Release +} + +// ReleaseWithConfig sets the config on the release. +func ReleaseWithConfig(config map[string]interface{}) ReleaseOption { + return func(options *ReleaseOptions) { + options.Config = config + } +} + +// ReleaseWithLabels sets the labels on the release. +func ReleaseWithLabels(labels map[string]string) ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Labels = labels + } +} + +// ReleaseWithFailingHook appends a failing hook to the release. +func ReleaseWithFailingHook() ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Hooks = append(options.Release.Hooks, &helmrelease.Hook{ + Name: "failing-hook", + Kind: "Pod", + Manifest: fmt.Sprintf(manifestWithFailingTestHookTmpl, options.Release.Namespace), + Events: []helmrelease.HookEvent{ + helmrelease.HookPostInstall, + helmrelease.HookPostUpgrade, + helmrelease.HookPostRollback, + helmrelease.HookPostDelete, + }, + }) + } +} + +// ReleaseWithHookExecution appends a hook with a last run with the given +// execution phase on the release. +func ReleaseWithHookExecution(name string, events []helmrelease.HookEvent, phase helmrelease.HookPhase) ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Hooks = append(options.Release.Hooks, &helmrelease.Hook{ + Name: name, + Events: events, + LastRun: helmrelease.HookExecution{ + StartedAt: MustParseHelmTime("2006-01-02T15:10:05Z"), + CompletedAt: MustParseHelmTime("2006-01-02T15:10:07Z"), + Phase: phase, + }, + }) + } +} + +// ReleaseWithTestHook appends a test hook to the release. +func ReleaseWithTestHook() ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Hooks = append(options.Release.Hooks, &helmrelease.Hook{ + Name: "test-hook", + Kind: "ConfigMap", + Manifest: fmt.Sprintf(manifestWithTestHookTmpl, options.Release.Namespace), + Events: []helmrelease.HookEvent{ + helmrelease.HookTest, + }, + }) + } +} + +// ReleaseWithFailingTestHook appends a failing test hook to the release. +func ReleaseWithFailingTestHook() ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Hooks = append(options.Release.Hooks, &helmrelease.Hook{ + Name: "failing-test-hook", + Kind: "Pod", + Manifest: fmt.Sprintf(manifestWithFailingTestHookTmpl, options.Release.Namespace), + Events: []helmrelease.HookEvent{ + helmrelease.HookTest, + }, + }) + } +} + +// ReleaseWithHooks sets the hooks on the release. +func ReleaseWithHooks(hooks []*helmrelease.Hook) ReleaseOption { + return func(options *ReleaseOptions) { + options.Release.Hooks = append(options.Release.Hooks, hooks...) + } +} diff --git a/internal/testutil/save_chart.go b/internal/testutil/save_chart.go new file mode 100644 index 000000000..6b071299c --- /dev/null +++ b/internal/testutil/save_chart.go @@ -0,0 +1,107 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutil + +import ( + "io" + "os" + "path/filepath" + "strings" + + sourcev1 "github.com/fluxcd/source-controller/api/v1" + "github.com/opencontainers/go-digest" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/rand" +) + +// SaveChart saves the given chart to the given directory, and returns the +// path to the saved chart. The chart is saved with a random suffix to avoid +// name collisions. +func SaveChart(c *chart.Chart, outDir string) (string, error) { + tmpDir, err := os.MkdirTemp("", "chart-") + if err != nil { + return "", err + } + defer os.RemoveAll(tmpDir) + + tmpChart, err := chartutil.Save(c, tmpDir) + if err != nil { + return "", err + } + + var ( + tmpChartFileName = filepath.Base(tmpChart) + tmpChartExt = filepath.Ext(tmpChartFileName) + newChartFileName = strings.TrimSuffix(tmpChartFileName, tmpChartExt) + "-" + rand.String(5) + tmpChartExt + targetPath = filepath.Join(outDir, newChartFileName) + ) + + if err = os.Rename(tmpChart, targetPath); err != nil { + return "", err + } + return targetPath, nil +} + +// SaveChartAsArtifact saves the given chart to the given directory, and +// returns an artifact with the chart's metadata. The chart is saved with a +// random suffix to avoid name collisions. +func SaveChartAsArtifact(c *chart.Chart, algo digest.Algorithm, baseURL, outDir string) (*sourcev1.Artifact, error) { + abs, err := SaveChart(c, outDir) + if err != nil { + return nil, err + } + + f, err := os.Open(abs) + if err != nil { + return nil, err + } + defer f.Close() + + bc := &byteCountReader{Reader: f} + dig, err := algo.FromReader(bc) + if err != nil { + return nil, err + } + + rel, err := filepath.Rel(outDir, abs) + if err != nil { + return nil, err + } + fileURL := strings.TrimSuffix(baseURL, "/") + "/" + rel + + return &sourcev1.Artifact{ + Path: abs, + URL: fileURL, + Revision: c.Metadata.Version, + Digest: dig.String(), + LastUpdateTime: v1.Now(), + Size: &bc.Count, + }, nil +} + +type byteCountReader struct { + Reader io.Reader + Count int64 +} + +func (b *byteCountReader) Read(p []byte) (n int, err error) { + n, err = b.Reader.Read(p) + b.Count += int64(n) + return n, err +} diff --git a/internal/util/util.go b/internal/util/util.go deleted file mode 100644 index 8c43d53b0..000000000 --- a/internal/util/util.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright 2020 The Flux authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "crypto/sha1" - "fmt" - "sort" - - goyaml "gopkg.in/yaml.v2" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/release" - "sigs.k8s.io/yaml" -) - -// ValuesChecksum calculates and returns the SHA1 checksum for the -// given chartutil.Values. -func ValuesChecksum(values chartutil.Values) string { - var s string - if len(values) != 0 { - s, _ = values.YAML() - } - return fmt.Sprintf("%x", sha1.Sum([]byte(s))) -} - -// OrderedValuesChecksum sort the chartutil.Values then calculates -// and returns the SHA1 checksum for the sorted values. -func OrderedValuesChecksum(values chartutil.Values) string { - var s []byte - if len(values) != 0 { - msValues := yaml.JSONObjectToYAMLObject(copyValues(values)) - SortMapSlice(msValues) - s, _ = goyaml.Marshal(msValues) - } - return fmt.Sprintf("%x", sha1.Sum(s)) -} - -// SortMapSlice recursively sorts the given goyaml.MapSlice by key. -// This is used to ensure that the values checksum is the same regardless -// of the order of the keys in the values file. -func SortMapSlice(ms goyaml.MapSlice) { - sort.Slice(ms, func(i, j int) bool { - return fmt.Sprint(ms[i].Key) < fmt.Sprint(ms[j].Key) - }) - for _, item := range ms { - if nestedMS, ok := item.Value.(goyaml.MapSlice); ok { - SortMapSlice(nestedMS) - } else if _, ok := item.Value.([]interface{}); ok { - for _, vItem := range item.Value.([]interface{}) { - if itemMS, ok := vItem.(goyaml.MapSlice); ok { - SortMapSlice(itemMS) - } - } - } - } -} - -// cleanUpMapValue changes all instances of -// map[interface{}]interface{} to map[string]interface{}. -// This is for handling the mismatch when unmarshaling -// reference to the issue: https://github.com/go-yaml/yaml/issues/139 -func cleanUpMapValue(v interface{}) interface{} { - switch v := v.(type) { - case []interface{}: - return cleanUpInterfaceArray(v) - case map[interface{}]interface{}: - return cleanUpInterfaceMap(v) - default: - return v - } -} - -func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} { - result := make(map[string]interface{}) - for k, v := range in { - result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v) - } - return result -} - -func cleanUpInterfaceArray(in []interface{}) []interface{} { - result := make([]interface{}, len(in)) - for i, v := range in { - result[i] = cleanUpMapValue(v) - } - return result -} - -func copyValues(in map[string]interface{}) map[string]interface{} { - copiedValues, _ := goyaml.Marshal(in) - newValues := make(map[string]interface{}) - - _ = goyaml.Unmarshal(copiedValues, newValues) - for i, value := range newValues { - newValues[i] = cleanUpMapValue(value) - } - - return newValues -} - -// ReleaseRevision returns the revision of the given release.Release. -func ReleaseRevision(rel *release.Release) int { - if rel == nil { - return 0 - } - return rel.Version -} diff --git a/internal/util/util_test.go b/internal/util/util_test.go deleted file mode 100644 index 04826f642..000000000 --- a/internal/util/util_test.go +++ /dev/null @@ -1,230 +0,0 @@ -/* -Copyright 2020 The Flux authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "reflect" - "testing" - - goyaml "gopkg.in/yaml.v2" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/release" -) - -func TestValuesChecksum(t *testing.T) { - tests := []struct { - name string - values chartutil.Values - want string - }{ - { - name: "empty", - values: chartutil.Values{}, - want: "da39a3ee5e6b4b0d3255bfef95601890afd80709", - }, - { - name: "value map", - values: chartutil.Values{ - "foo": "bar", - "baz": map[string]string{ - "cool": "stuff", - }, - }, - want: "7d487b668ca37fe68c42adfc06fa4d0e74443afd", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ValuesChecksum(tt.values); got != tt.want { - t.Errorf("ValuesChecksum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestOrderedValuesChecksum(t *testing.T) { - tests := []struct { - name string - values chartutil.Values - want string - }{ - { - name: "empty", - values: chartutil.Values{}, - want: "da39a3ee5e6b4b0d3255bfef95601890afd80709", - }, - { - name: "value map", - values: chartutil.Values{ - "foo": "bar", - "baz": map[string]string{ - "fruit": "apple", - "cool": "stuff", - }, - }, - want: "dfd6589332e4d2da5df7bcbf5885f406f08b58ee", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := OrderedValuesChecksum(tt.values); got != tt.want { - t.Errorf("OrderedValuesChecksum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestReleaseRevision(t *testing.T) { - var rel *release.Release - if rev := ReleaseRevision(rel); rev != 0 { - t.Fatalf("ReleaseRevision() = %v, want %v", rev, 0) - } - rel = &release.Release{Version: 1} - if rev := ReleaseRevision(rel); rev != 1 { - t.Fatalf("ReleaseRevision() = %v, want %v", rev, 1) - } -} - -func TestSortMapSlice(t *testing.T) { - tests := []struct { - name string - input goyaml.MapSlice - expected goyaml.MapSlice - }{ - { - name: "Simple case", - input: goyaml.MapSlice{ - {Key: "b", Value: 2}, - {Key: "a", Value: 1}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: 1}, - {Key: "b", Value: 2}, - }, - }, - { - name: "Nested MapSlice", - input: goyaml.MapSlice{ - {Key: "b", Value: 2}, - {Key: "a", Value: 1}, - {Key: "c", Value: goyaml.MapSlice{ - {Key: "d", Value: 4}, - {Key: "e", Value: 5}, - }}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: 1}, - {Key: "b", Value: 2}, - {Key: "c", Value: goyaml.MapSlice{ - {Key: "d", Value: 4}, - {Key: "e", Value: 5}, - }}, - }, - }, - { - name: "Empty MapSlice", - input: goyaml.MapSlice{}, - expected: goyaml.MapSlice{}, - }, - { - name: "Single element", - input: goyaml.MapSlice{ - {Key: "a", Value: 1}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: 1}, - }, - }, - { - name: "Already sorted", - input: goyaml.MapSlice{ - {Key: "a", Value: 1}, - {Key: "b", Value: 2}, - {Key: "c", Value: 3}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: 1}, - {Key: "b", Value: 2}, - {Key: "c", Value: 3}, - }, - }, - - { - name: "Complex Case", - input: goyaml.MapSlice{ - {Key: "b", Value: 2}, - {Key: "a", Value: map[interface{}]interface{}{ - "d": []interface{}{4, 5}, - "c": 3, - }}, - {Key: "c", Value: goyaml.MapSlice{ - {Key: "f", Value: 6}, - {Key: "e", Value: goyaml.MapSlice{ - {Key: "h", Value: 8}, - {Key: "g", Value: 7}, - }}, - }}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: map[interface{}]interface{}{ - "c": 3, - "d": []interface{}{4, 5}, - }}, - {Key: "b", Value: 2}, - {Key: "c", Value: goyaml.MapSlice{ - {Key: "e", Value: goyaml.MapSlice{ - {Key: "g", Value: 7}, - {Key: "h", Value: 8}, - }}, - {Key: "f", Value: 6}, - }}, - }, - }, - { - name: "Map slice in slice", - input: goyaml.MapSlice{ - {Key: "b", Value: 2}, - {Key: "a", Value: []interface{}{ - map[interface{}]interface{}{ - "d": 4, - "c": 3, - }, - 1, - }}, - }, - expected: goyaml.MapSlice{ - {Key: "a", Value: []interface{}{ - map[interface{}]interface{}{ - "c": 3, - "d": 4, - }, - 1, - }}, - {Key: "b", Value: 2}, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - SortMapSlice(test.input) - if !reflect.DeepEqual(test.input, test.expected) { - t.Errorf("Expected %v, got %v", test.expected, test.input) - } - }) - } -} diff --git a/internal/yaml/encode.go b/internal/yaml/encode.go new file mode 100644 index 000000000..1bda1fb3d --- /dev/null +++ b/internal/yaml/encode.go @@ -0,0 +1,43 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml + +import ( + "io" + + goyaml "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" +) + +// PreEncoder allows for pre-processing of the YAML data before encoding. +type PreEncoder func(goyaml.MapSlice) + +// Encode encodes the given data to YAML format and writes it to the provided +// io.Write, without going through a byte representation (unlike +// sigs.k8s.io/yaml#Unmarshal). +// +// It optionally takes one or more PreEncoder functions that allow +// for pre-processing of the data before encoding, such as sorting the data. +// +// It returns an error if the data cannot be encoded. +func Encode(w io.Writer, data map[string]interface{}, pe ...PreEncoder) error { + ms := yaml.JSONObjectToYAMLObject(data) + for _, m := range pe { + m(ms) + } + return goyaml.NewEncoder(w).Encode(ms) +} diff --git a/internal/yaml/encode_test.go b/internal/yaml/encode_test.go new file mode 100644 index 000000000..048c2210f --- /dev/null +++ b/internal/yaml/encode_test.go @@ -0,0 +1,106 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml + +import ( + "bytes" + "os" + "testing" + + "sigs.k8s.io/yaml" +) + +func TestEncode(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + preEncoders []PreEncoder + want []byte + }{ + { + name: "empty map", + input: map[string]interface{}{}, + want: []byte(`{} +`), + }, + { + name: "simple values", + input: map[string]interface{}{ + "replicaCount": 3, + }, + want: []byte(`replicaCount: 3 +`), + }, + { + name: "with pre-encoder", + input: map[string]interface{}{ + "replicaCount": 3, + "image": map[string]interface{}{ + "repository": "nginx", + "tag": "latest", + }, + "port": 8080, + }, + preEncoders: []PreEncoder{SortMapSlice}, + want: []byte(`image: + repository: nginx + tag: latest +port: 8080 +replicaCount: 3 +`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var actual bytes.Buffer + err := Encode(&actual, tt.input, tt.preEncoders...) + if err != nil { + t.Fatalf("error encoding: %v", err) + } + + if !bytes.Equal(actual.Bytes(), tt.want) { + t.Errorf("Encode() = %v, want: %s", actual.String(), tt.want) + } + }) + } +} + +func BenchmarkEncode(b *testing.B) { + // Test against the values.yaml from the kube-prometheus-stack chart, which + // is a fairly large file. + v, err := os.ReadFile("testdata/values.yaml") + if err != nil { + b.Fatalf("error reading testdata: %v", err) + } + + var data map[string]interface{} + if err = yaml.Unmarshal(v, &data); err != nil { + b.Fatalf("error unmarshalling testdata: %v", err) + } + + b.Run("EncodeWithSort", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Encode(bytes.NewBuffer(nil), data, SortMapSlice) + } + }) + + b.Run("SigYAMLMarshal", func(b *testing.B) { + for i := 0; i < b.N; i++ { + yaml.Marshal(data) + } + }) +} diff --git a/internal/yaml/sort.go b/internal/yaml/sort.go new file mode 100644 index 000000000..2d0e8a93e --- /dev/null +++ b/internal/yaml/sort.go @@ -0,0 +1,44 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml + +import ( + "sort" + + goyaml "gopkg.in/yaml.v2" +) + +// SortMapSlice recursively sorts the given goyaml.MapSlice by key. +// It can be used in combination with Encode to sort YAML by key +// before encoding it. +func SortMapSlice(ms goyaml.MapSlice) { + sort.Slice(ms, func(i, j int) bool { + return ms[i].Key.(string) < ms[j].Key.(string) + }) + + for _, item := range ms { + if nestedMS, ok := item.Value.(goyaml.MapSlice); ok { + SortMapSlice(nestedMS) + } else if nestedSlice, ok := item.Value.([]interface{}); ok { + for _, vItem := range nestedSlice { + if nestedMS, ok := vItem.(goyaml.MapSlice); ok { + SortMapSlice(nestedMS) + } + } + } + } +} diff --git a/internal/yaml/sort_test.go b/internal/yaml/sort_test.go new file mode 100644 index 000000000..832c81621 --- /dev/null +++ b/internal/yaml/sort_test.go @@ -0,0 +1,183 @@ +/* +Copyright 2023 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml + +import ( + "bytes" + "testing" + + goyaml "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" +) + +func TestSortMapSlice(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + want map[string]interface{} + }{ + { + name: "empty map", + input: map[string]interface{}{}, + want: map[string]interface{}{}, + }, + { + name: "flat map", + input: map[string]interface{}{ + "b": "value-b", + "a": "value-a", + "c": "value-c", + }, + want: map[string]interface{}{ + "a": "value-a", + "b": "value-b", + "c": "value-c", + }, + }, + { + name: "nested map", + input: map[string]interface{}{ + "b": "value-b", + "a": "value-a", + "c": map[string]interface{}{ + "z": "value-z", + "y": "value-y", + }, + }, + want: map[string]interface{}{ + "a": "value-a", + "b": "value-b", + "c": map[string]interface{}{ + "y": "value-y", + "z": "value-z", + }, + }, + }, + { + name: "map with slices", + input: map[string]interface{}{ + "b": []interface{}{"apple", "banana", "cherry"}, + "a": []interface{}{"orange", "grape"}, + "c": []interface{}{"strawberry"}, + }, + want: map[string]interface{}{ + "a": []interface{}{"orange", "grape"}, + "b": []interface{}{"apple", "banana", "cherry"}, + "c": []interface{}{"strawberry"}, + }, + }, + { + name: "map with mixed data types", + input: map[string]interface{}{ + "b": 50, + "a": "value-a", + "c": []interface{}{"strawberry", "banana"}, + "d": map[string]interface{}{ + "x": true, + "y": 123, + }, + }, + want: map[string]interface{}{ + "a": "value-a", + "b": 50, + "c": []interface{}{"strawberry", "banana"}, + "d": map[string]interface{}{ + "x": true, + "y": 123, + }, + }, + }, + { + name: "map with complex structure", + input: map[string]interface{}{ + "a": map[string]interface{}{ + "c": "value-c", + "b": "value-b", + "a": "value-a", + }, + "b": "value-b", + "c": map[string]interface{}{ + "z": map[string]interface{}{ + "a": "value-a", + "b": "value-b", + "c": "value-c", + }, + "y": "value-y", + }, + "d": map[string]interface{}{ + "q": "value-q", + "p": "value-p", + "r": "value-r", + }, + "e": []interface{}{"strawberry", "banana"}, + }, + want: map[string]interface{}{ + "a": map[string]interface{}{ + "a": "value-a", + "b": "value-b", + "c": "value-c", + }, + "b": "value-b", + "c": map[string]interface{}{ + "y": "value-y", + "z": map[string]interface{}{ + "a": "value-a", + "b": "value-b", + "c": "value-c", + }, + }, + "d": map[string]interface{}{ + "p": "value-p", + "q": "value-q", + "r": "value-r", + }, + "e": []interface{}{"strawberry", "banana"}, + }, + }, + { + name: "map with empty slices and maps", + input: map[string]interface{}{ + "b": []interface{}{}, + "a": map[string]interface{}{}, + }, + want: map[string]interface{}{ + "a": map[string]interface{}{}, + "b": []interface{}{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + input := yaml.JSONObjectToYAMLObject(tt.input) + SortMapSlice(input) + + expect, err := goyaml.Marshal(input) + if err != nil { + t.Fatalf("error marshalling output: %v", err) + } + actual, err := goyaml.Marshal(tt.want) + if err != nil { + t.Fatalf("error marshalling want: %v", err) + } + + if !bytes.Equal(expect, actual) { + t.Errorf("SortMapSlice() = %s, want %s", expect, actual) + } + }) + } +} diff --git a/internal/yaml/testdata/values.yaml b/internal/yaml/testdata/values.yaml new file mode 100644 index 000000000..51d7c5288 --- /dev/null +++ b/internal/yaml/testdata/values.yaml @@ -0,0 +1,4043 @@ +# Snapshot taken from: https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-48.1.1/charts/kube-prometheus-stack/values.yaml + +# Default values for kube-prometheus-stack. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +## Provide a name in place of kube-prometheus-stack for `app:` labels +## +nameOverride: "" + +## Override the deployment namespace +## +namespaceOverride: "" + +## Provide a k8s version to auto dashboard import script example: kubeTargetVersionOverride: 1.16.6 +## +kubeTargetVersionOverride: "" + +## Allow kubeVersion to be overridden while creating the ingress +## +kubeVersionOverride: "" + +## Provide a name to substitute for the full names of resources +## +fullnameOverride: "" + +## Labels to apply to all resources +## +commonLabels: {} +# scmhash: abc123 +# myLabel: aakkmd + +## Install Prometheus Operator CRDs +## +crds: + enabled: true + +## Create default rules for monitoring the cluster +## +defaultRules: + create: true + rules: + alertmanager: true + etcd: true + configReloaders: true + general: true + k8s: true + kubeApiserverAvailability: true + kubeApiserverBurnrate: true + kubeApiserverHistogram: true + kubeApiserverSlos: true + kubeControllerManager: true + kubelet: true + kubeProxy: true + kubePrometheusGeneral: true + kubePrometheusNodeRecording: true + kubernetesApps: true + kubernetesResources: true + kubernetesStorage: true + kubernetesSystem: true + kubeSchedulerAlerting: true + kubeSchedulerRecording: true + kubeStateMetrics: true + network: true + node: true + nodeExporterAlerting: true + nodeExporterRecording: true + prometheus: true + prometheusOperator: true + windows: true + + ## Reduce app namespace alert scope + appNamespacesTarget: ".*" + + ## Labels for default rules + labels: {} + ## Annotations for default rules + annotations: {} + + ## Additional labels for PrometheusRule alerts + additionalRuleLabels: {} + + ## Additional annotations for PrometheusRule alerts + additionalRuleAnnotations: {} + + ## Additional labels for specific PrometheusRule alert groups + additionalRuleGroupLabels: + alertmanager: {} + etcd: {} + configReloaders: {} + general: {} + k8s: {} + kubeApiserverAvailability: {} + kubeApiserverBurnrate: {} + kubeApiserverHistogram: {} + kubeApiserverSlos: {} + kubeControllerManager: {} + kubelet: {} + kubeProxy: {} + kubePrometheusGeneral: {} + kubePrometheusNodeRecording: {} + kubernetesApps: {} + kubernetesResources: {} + kubernetesStorage: {} + kubernetesSystem: {} + kubeSchedulerAlerting: {} + kubeSchedulerRecording: {} + kubeStateMetrics: {} + network: {} + node: {} + nodeExporterAlerting: {} + nodeExporterRecording: {} + prometheus: {} + prometheusOperator: {} + + ## Additional annotations for specific PrometheusRule alerts groups + additionalRuleGroupAnnotations: + alertmanager: {} + etcd: {} + configReloaders: {} + general: {} + k8s: {} + kubeApiserverAvailability: {} + kubeApiserverBurnrate: {} + kubeApiserverHistogram: {} + kubeApiserverSlos: {} + kubeControllerManager: {} + kubelet: {} + kubeProxy: {} + kubePrometheusGeneral: {} + kubePrometheusNodeRecording: {} + kubernetesApps: {} + kubernetesResources: {} + kubernetesStorage: {} + kubernetesSystem: {} + kubeSchedulerAlerting: {} + kubeSchedulerRecording: {} + kubeStateMetrics: {} + network: {} + node: {} + nodeExporterAlerting: {} + nodeExporterRecording: {} + prometheus: {} + prometheusOperator: {} + + ## Prefix for runbook URLs. Use this to override the first part of the runbookURLs that is common to all rules. + runbookUrl: "https://runbooks.prometheus-operator.dev/runbooks" + + ## Disabled PrometheusRule alerts + disabled: {} + # KubeAPIDown: true + # NodeRAIDDegraded: true + +## Deprecated way to provide custom recording or alerting rules to be deployed into the cluster. +## +# additionalPrometheusRules: [] +# - name: my-rule-file +# groups: +# - name: my_group +# rules: +# - record: my_record +# expr: 100 * my_record + +## Provide custom recording or alerting rules to be deployed into the cluster. +## +additionalPrometheusRulesMap: {} +# rule-name: +# groups: +# - name: my_group +# rules: +# - record: my_record +# expr: 100 * my_record + +## +global: + rbac: + create: true + + ## Create ClusterRoles that extend the existing view, edit and admin ClusterRoles to interact with prometheus-operator CRDs + ## Ref: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles + createAggregateClusterRoles: false + pspEnabled: false + pspAnnotations: {} + ## Specify pod annotations + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl + ## + # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' + # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default' + # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' + + ## Global image registry to use if it needs to be overriden for some specific use cases (e.g local registries, custom images, ...) + ## + imageRegistry: "" + + ## Reference to one or more secrets to be used when pulling images + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + imagePullSecrets: [] + # - name: "image-pull-secret" + # or + # - "image-pull-secret" + +windowsMonitoring: + ## Deploys the windows-exporter and Windows-specific dashboards and rules + enabled: false + ## Job must match jobLabel in the PodMonitor/ServiceMonitor and is used for the rules + job: prometheus-windows-exporter + +## Configuration for alertmanager +## ref: https://prometheus.io/docs/alerting/alertmanager/ +## +alertmanager: + + ## Deploy alertmanager + ## + enabled: true + + ## Annotations for Alertmanager + ## + annotations: {} + + ## Api that prometheus will use to communicate with alertmanager. Possible values are v1, v2 + ## + apiVersion: v2 + + ## Service account for Alertmanager to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + annotations: {} + automountServiceAccountToken: true + + ## Configure pod disruption budgets for Alertmanager + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget + ## This configuration is immutable once created and will require the PDB to be deleted to be changed + ## https://github.com/kubernetes/kubernetes/issues/45398 + ## + podDisruptionBudget: + enabled: false + minAvailable: 1 + maxUnavailable: "" + + ## Alertmanager configuration directives + ## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file + ## https://prometheus.io/webtools/alerting/routing-tree-editor/ + ## + config: + global: + resolve_timeout: 5m + inhibit_rules: + - source_matchers: + - 'severity = critical' + target_matchers: + - 'severity =~ warning|info' + equal: + - 'namespace' + - 'alertname' + - source_matchers: + - 'severity = warning' + target_matchers: + - 'severity = info' + equal: + - 'namespace' + - 'alertname' + - source_matchers: + - 'alertname = InfoInhibitor' + target_matchers: + - 'severity = info' + equal: + - 'namespace' + route: + group_by: ['namespace'] + group_wait: 30s + group_interval: 5m + repeat_interval: 12h + receiver: 'null' + routes: + - receiver: 'null' + matchers: + - alertname =~ "InfoInhibitor|Watchdog" + receivers: + - name: 'null' + templates: + - '/etc/alertmanager/config/*.tmpl' + + ## Alertmanager configuration directives (as string type, preferred over the config hash map) + ## stringConfig will be used only, if tplConfig is true + ## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file + ## https://prometheus.io/webtools/alerting/routing-tree-editor/ + ## + stringConfig: "" + + ## Pass the Alertmanager configuration directives through Helm's templating + ## engine. If the Alertmanager configuration contains Alertmanager templates, + ## they'll need to be properly escaped so that they are not interpreted by + ## Helm + ## ref: https://helm.sh/docs/developing_charts/#using-the-tpl-function + ## https://prometheus.io/docs/alerting/configuration/#tmpl_string + ## https://prometheus.io/docs/alerting/notifications/ + ## https://prometheus.io/docs/alerting/notification_examples/ + tplConfig: false + + ## Alertmanager template files to format alerts + ## By default, templateFiles are placed in /etc/alertmanager/config/ and if + ## they have a .tmpl file suffix will be loaded. See config.templates above + ## to change, add other suffixes. If adding other suffixes, be sure to update + ## config.templates above to include those suffixes. + ## ref: https://prometheus.io/docs/alerting/notifications/ + ## https://prometheus.io/docs/alerting/notification_examples/ + ## + templateFiles: {} + # + ## An example template: + # template_1.tmpl: |- + # {{ define "cluster" }}{{ .ExternalURL | reReplaceAll ".*alertmanager\\.(.*)" "$1" }}{{ end }} + # + # {{ define "slack.myorg.text" }} + # {{- $root := . -}} + # {{ range .Alerts }} + # *Alert:* {{ .Annotations.summary }} - `{{ .Labels.severity }}` + # *Cluster:* {{ template "cluster" $root }} + # *Description:* {{ .Annotations.description }} + # *Graph:* <{{ .GeneratorURL }}|:chart_with_upwards_trend:> + # *Runbook:* <{{ .Annotations.runbook }}|:spiral_note_pad:> + # *Details:* + # {{ range .Labels.SortedPairs }} - *{{ .Name }}:* `{{ .Value }}` + # {{ end }} + # {{ end }} + # {{ end }} + + ingress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + + labels: {} + + ## Override ingress to a different defined port on the service + # servicePort: 8081 + ## Override ingress to a different service then the default, this is useful if you need to + ## point to a specific instance of the alertmanager (eg kube-prometheus-stack-alertmanager-0) + # serviceName: kube-prometheus-stack-alertmanager-0 + + ## Hosts must be provided if Ingress is enabled. + ## + hosts: [] + # - alertmanager.domain.com + + ## Paths to use for ingress rules - one path should match the alertmanagerSpec.routePrefix + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Alertmanager Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: alertmanager-general-tls + # hosts: + # - alertmanager.example.com + + ## Configuration for Alertmanager secret + ## + secret: + annotations: {} + + ## Configuration for creating an Ingress that will map to each Alertmanager replica service + ## alertmanager.servicePerReplica must be enabled + ## + ingressPerReplica: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Final form of the hostname for each per replica ingress is + ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }} + ## + ## Prefix for the per replica ingress that will have `-$replicaNumber` + ## appended to the end + hostPrefix: "" + ## Domain that will be used for the per replica ingress + hostDomain: "" + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## Secret name containing the TLS certificate for alertmanager per replica ingress + ## Secret must be manually created in the namespace + tlsSecretName: "" + + ## Separated secret for each per replica Ingress. Can be used together with cert-manager + ## + tlsSecretPerReplica: + enabled: false + ## Final form of the secret for each per replica ingress is + ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }} + ## + prefix: "alertmanager" + + ## Configuration for Alertmanager service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + + ## Port for Alertmanager Service to listen on + ## + port: 9093 + ## To be used with a proxy extraContainer port + ## + targetPort: 9093 + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30903 + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + + ## Additional ports to open for Alertmanager service + additionalPorts: [] + # additionalPorts: + # - name: authenticated + # port: 8081 + # targetPort: 8081 + + externalIPs: [] + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## If you want to make sure that connections from a particular client are passed to the same Pod each time + ## Accepts 'ClientIP' or '' + ## + sessionAffinity: "" + + ## Service type + ## + type: ClusterIP + + ## Configuration for creating a separate Service for each statefulset Alertmanager replica + ## + servicePerReplica: + enabled: false + annotations: {} + + ## Port for Alertmanager Service per replica to listen on + ## + port: 9093 + + ## To be used with a proxy extraContainer port + targetPort: 9093 + + ## Port to expose on each node + ## Only used if servicePerReplica.type is 'NodePort' + ## + nodePort: 30904 + + ## Loadbalancer source IP ranges + ## Only used if servicePerReplica.type is "LoadBalancer" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## If true, create a serviceMonitor for alertmanager + ## + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + selfMonitor: true + + ## Additional labels + ## + additionalLabels: {} + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## enableHttp2: Whether to enable HTTP2. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#endpoint + enableHttp2: true + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Settings affecting alertmanagerSpec + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerspec + ## + alertmanagerSpec: + ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata + ## Metadata Labels and Annotations gets propagated to the Alertmanager pods. + ## + podMetadata: {} + + ## Image of Alertmanager + ## + image: + registry: quay.io + repository: prometheus/alertmanager + tag: v0.25.0 + sha: "" + + ## If true then the user will be responsible to provide a secret with alertmanager configuration + ## So when true the config part will be ignored (including templateFiles) and the one in the secret will be used + ## + useExistingSecret: false + + ## Secrets is a list of Secrets in the same namespace as the Alertmanager object, which shall be mounted into the + ## Alertmanager Pods. The Secrets are mounted into /etc/alertmanager/secrets/. + ## + secrets: [] + + ## ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager object, which shall be mounted into the Alertmanager Pods. + ## The ConfigMaps are mounted into /etc/alertmanager/configmaps/. + ## + configMaps: [] + + ## ConfigSecret is the name of a Kubernetes Secret in the same namespace as the Alertmanager object, which contains configuration for + ## this Alertmanager instance. Defaults to 'alertmanager-' The secret is mounted into /etc/alertmanager/config. + ## + # configSecret: + + ## WebTLSConfig defines the TLS parameters for HTTPS + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerwebspec + web: {} + + ## AlertmanagerConfigs to be selected to merge and configure Alertmanager with. + ## + alertmanagerConfigSelector: {} + ## Example which selects all alertmanagerConfig resources + ## with label "alertconfig" with values any of "example-config" or "example-config-2" + # alertmanagerConfigSelector: + # matchExpressions: + # - key: alertconfig + # operator: In + # values: + # - example-config + # - example-config-2 + # + ## Example which selects all alertmanagerConfig resources with label "role" set to "example-config" + # alertmanagerConfigSelector: + # matchLabels: + # role: example-config + + ## Namespaces to be selected for AlertmanagerConfig discovery. If nil, only check own namespace. + ## + alertmanagerConfigNamespaceSelector: {} + ## Example which selects all namespaces + ## with label "alertmanagerconfig" with values any of "example-namespace" or "example-namespace-2" + # alertmanagerConfigNamespaceSelector: + # matchExpressions: + # - key: alertmanagerconfig + # operator: In + # values: + # - example-namespace + # - example-namespace-2 + + ## Example which selects all namespaces with label "alertmanagerconfig" set to "enabled" + # alertmanagerConfigNamespaceSelector: + # matchLabels: + # alertmanagerconfig: enabled + + ## AlermanagerConfig to be used as top level configuration + ## + alertmanagerConfiguration: {} + ## Example with select a global alertmanagerconfig + # alertmanagerConfiguration: + # name: global-alertmanager-Configuration + + ## Defines the strategy used by AlertmanagerConfig objects to match alerts. eg: + ## + alertmanagerConfigMatcherStrategy: {} + ## Example with use OnNamespace strategy + # alertmanagerConfigMatcherStrategy: + # type: OnNamespace + + ## Define Log Format + # Use logfmt (default) or json logging + logFormat: logfmt + + ## Log level for Alertmanager to be configured with. + ## + logLevel: info + + ## Size is the expected size of the alertmanager cluster. The controller will eventually make the size of the + ## running cluster equal to the expected size. + replicas: 1 + + ## Time duration Alertmanager shall retain data for. Default is '120h', and must match the regular expression + ## [0-9]+(ms|s|m|h) (milliseconds seconds minutes hours). + ## + retention: 120h + + ## Storage is the definition of how storage will be used by the Alertmanager instances. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md + ## + storage: {} + # volumeClaimTemplate: + # spec: + # storageClassName: gluster + # accessModes: ["ReadWriteOnce"] + # resources: + # requests: + # storage: 50Gi + # selector: {} + + + ## The external URL the Alertmanager instances will be available under. This is necessary to generate correct URLs. This is necessary if Alertmanager is not served from root of a DNS name. string false + ## + externalUrl: + + ## The route prefix Alertmanager registers HTTP handlers for. This is useful, if using ExternalURL and a proxy is rewriting HTTP routes of a request, and the actual ExternalURL is still true, + ## but the server serves requests under a different route prefix. For example for use with kubectl proxy. + ## + routePrefix: / + + ## scheme: HTTP scheme to use. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when connect to the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + ## If set to true all actions on the underlying managed objects are not going to be performed, except for delete actions. + ## + paused: false + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Define resources requests and limits for single Pods. + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: {} + # requests: + # memory: 400Mi + + ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node. + ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided. + ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node. + ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured. + ## + podAntiAffinity: "" + + ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity. + ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone + ## + podAntiAffinityTopologyKey: kubernetes.io/hostname + + ## Assign custom affinity rules to the alertmanager instance + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + + ## If specified, the pod's tolerations. + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## If specified, the pod's topology spread constraints. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app: alertmanager + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 2000 + seccompProfile: + type: RuntimeDefault + + ## ListenLocal makes the Alertmanager server listen on loopback, so that it does not bind against the Pod IP. + ## Note this is only for the Alertmanager UI, not the gossip communication. + ## + listenLocal: false + + ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to an Alertmanager pod. + ## + containers: [] + # containers: + # - name: oauth-proxy + # image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0 + # args: + # - --upstream=http://127.0.0.1:9093 + # - --http-address=0.0.0.0:8081 + # - ... + # ports: + # - containerPort: 8081 + # name: oauth-proxy + # protocol: TCP + # resources: {} + + # Additional volumes on the output StatefulSet definition. + volumes: [] + + # Additional VolumeMounts on the output StatefulSet definition. + volumeMounts: [] + + ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes + ## (permissions, dir tree) on mounted volumes before starting prometheus + initContainers: [] + + ## Priority class assigned to the Pods + ## + priorityClassName: "" + + ## AdditionalPeers allows injecting a set of additional Alertmanagers to peer with to form a highly available cluster. + ## + additionalPeers: [] + + ## PortName to use for Alert Manager. + ## + portName: "http-web" + + ## ClusterAdvertiseAddress is the explicit address to advertise in cluster. Needs to be provided for non RFC1918 [1] (public) addresses. [1] RFC1918: https://tools.ietf.org/html/rfc1918 + ## + clusterAdvertiseAddress: false + + ## clusterGossipInterval determines interval between gossip attempts. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterGossipInterval: "" + + ## clusterPeerTimeout determines timeout for cluster peering. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterPeerTimeout: "" + + ## clusterPushpullInterval determines interval between pushpull attempts. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterPushpullInterval: "" + + ## ForceEnableClusterMode ensures Alertmanager does not deactivate the cluster mode when running with a single replica. + ## Use case is e.g. spanning an Alertmanager cluster across Kubernetes clusters with a single replica in each. + forceEnableClusterMode: false + + ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to + ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready). + minReadySeconds: 0 + + ## ExtraSecret can be used to store various data in an extra secret + ## (use it for example to store hashed basic auth credentials) + extraSecret: + ## if not set, name will be auto generated + # name: "" + annotations: {} + data: {} + # auth: | + # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0 + # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c. + +## Using default values from https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml +## +grafana: + enabled: true + namespaceOverride: "" + + ## ForceDeployDatasources Create datasource configmap even if grafana deployment has been disabled + ## + forceDeployDatasources: false + + ## ForceDeployDashboard Create dashboard configmap even if grafana deployment has been disabled + ## + forceDeployDashboards: false + + ## Deploy default dashboards + ## + defaultDashboardsEnabled: true + + ## Timezone for the default dashboards + ## Other options are: browser or a specific timezone, i.e. Europe/Luxembourg + ## + defaultDashboardsTimezone: utc + + adminPassword: prom-operator + + rbac: + ## If true, Grafana PSPs will be created + ## + pspEnabled: false + + ingress: + ## If true, Grafana Ingress will be created + ## + enabled: false + + ## IngressClassName for Grafana Ingress. + ## Should be provided if Ingress is enable. + ## + # ingressClassName: nginx + + ## Annotations for Grafana Ingress + ## + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + ## Labels to be added to the Ingress + ## + labels: {} + + ## Hostnames. + ## Must be provided if Ingress is enable. + ## + # hosts: + # - grafana.domain.com + hosts: [] + + ## Path for grafana ingress + path: / + + ## TLS configuration for grafana Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: grafana-general-tls + # hosts: + # - grafana.example.com + + sidecar: + dashboards: + enabled: true + label: grafana_dashboard + labelValue: "1" + # Allow discovery in all namespaces for dashboards + searchNamespace: ALL + + ## Annotations for Grafana dashboard configmaps + ## + annotations: {} + multicluster: + global: + enabled: false + etcd: + enabled: false + provider: + allowUiUpdates: false + datasources: + enabled: true + defaultDatasourceEnabled: true + isDefaultDatasource: true + + uid: prometheus + + ## URL of prometheus datasource + ## + # url: http://prometheus-stack-prometheus:9090/ + + ## Prometheus request timeout in seconds + # timeout: 30 + + # If not defined, will use prometheus.prometheusSpec.scrapeInterval or its default + # defaultDatasourceScrapeInterval: 15s + + ## Annotations for Grafana datasource configmaps + ## + annotations: {} + + ## Set method for HTTP to send query to datasource + httpMethod: POST + + ## Create datasource for each Pod of Prometheus StatefulSet; + ## this uses headless service `prometheus-operated` which is + ## created by Prometheus Operator + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/0fee93e12dc7c2ea1218f19ae25ec6b893460590/pkg/prometheus/statefulset.go#L255-L286 + createPrometheusReplicasDatasources: false + label: grafana_datasource + labelValue: "1" + + ## Field with internal link pointing to existing data source in Grafana. + ## Can be provisioned via additionalDataSources + exemplarTraceIdDestinations: {} + # datasourceUid: Jaeger + # traceIdLabelName: trace_id + alertmanager: + enabled: true + uid: alertmanager + handleGrafanaManagedAlerts: false + implementation: prometheus + + extraConfigmapMounts: [] + # - name: certs-configmap + # mountPath: /etc/grafana/ssl/ + # configMap: certs-configmap + # readOnly: true + + deleteDatasources: [] + # - name: example-datasource + # orgId: 1 + + ## Configure additional grafana datasources (passed through tpl) + ## ref: http://docs.grafana.org/administration/provisioning/#datasources + additionalDataSources: [] + # - name: prometheus-sample + # access: proxy + # basicAuth: true + # basicAuthPassword: pass + # basicAuthUser: daco + # editable: false + # jsonData: + # tlsSkipVerify: true + # orgId: 1 + # type: prometheus + # url: https://{{ printf "%s-prometheus.svc" .Release.Name }}:9090 + # version: 1 + + ## Passed to grafana subchart and used by servicemonitor below + ## + service: + portName: http-web + + serviceMonitor: + # If true, a ServiceMonitor CRD is created for a prometheus operator + # https://github.com/coreos/prometheus-operator + # + enabled: true + + # Path to use for scraping metrics. Might be different if server.root_url is set + # in grafana.ini + path: "/metrics" + + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + + # labels for the ServiceMonitor + labels: {} + + # Scrape interval. If not set, the Prometheus default scrape interval is used. + # + interval: "" + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + +## Flag to disable all the kubernetes component scrapers +## +kubernetesServiceMonitors: + enabled: true + +## Component scraping the kube api server +## +kubeApiServer: + enabled: true + tlsConfig: + serverName: kubernetes + insecureSkipVerify: false + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + jobLabel: component + selector: + matchLabels: + component: apiserver + provider: kubernetes + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: + # Drop excessively noisy apiserver buckets. + - action: drop + regex: apiserver_request_duration_seconds_bucket;(0.15|0.2|0.3|0.35|0.4|0.45|0.6|0.7|0.8|0.9|1.25|1.5|1.75|2|3|3.5|4|4.5|6|7|8|9|15|25|40|50) + sourceLabels: + - __name__ + - le + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: + # - __meta_kubernetes_namespace + # - __meta_kubernetes_service_name + # - __meta_kubernetes_endpoint_port_name + # action: keep + # regex: default;kubernetes;https + # - targetLabel: __address__ + # replacement: kubernetes.default.svc:443 + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping the kubelet and kubelet-hosted cAdvisor +## +kubelet: + enabled: true + namespace: kube-system + + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Enable scraping the kubelet over https. For requirements to enable this see + ## https://github.com/prometheus-operator/prometheus-operator/issues/926 + ## + https: true + + ## Enable scraping /metrics/cadvisor from kubelet's service + ## + cAdvisor: true + + ## Enable scraping /metrics/probes from kubelet's service + ## + probes: true + + ## Enable scraping /metrics/resource from kubelet's service + ## This is disabled by default because container metrics are already exposed by cAdvisor + ## + resource: false + # From kubernetes 1.18, /metrics/resource/v1alpha1 renamed to /metrics/resource + resourcePath: "/metrics/resource/v1alpha1" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + cAdvisorMetricRelabelings: + # Drop less useful container CPU metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total)' + # Drop less useful container / always zero filesystem metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total)' + # Drop less useful / always zero container memory metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_memory_(mapped_file|swap)' + # Drop less useful container process metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_(file_descriptors|tasks_state|threads_max)' + # Drop container spec metrics that overlap with kube-state-metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_spec.*' + # Drop cgroup metrics with no pod. + - sourceLabels: [id, pod] + action: drop + regex: '.+;' + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + probesMetricRelabelings: [] + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + ## metrics_path is required to match upstream rules and charts + cAdvisorRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + probesRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + resourceRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + ## metrics_path is required to match upstream rules and charts + relabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping the kube controller manager +## +kubeControllerManager: + enabled: true + + ## If your kube controller manager is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## If using kubeControllerManager.endpoints only the port and targetPort are used + ## + service: + enabled: true + ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change + ## of default port in Kubernetes 1.22. + ## + port: null + targetPort: null + # selector: + # component: kube-controller-manager + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Enable scraping kube-controller-manager over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks. + ## If null or unset, the value is determined dynamically based on target Kubernetes version. + ## + https: null + + # Skip TLS certificate validation when scraping + insecureSkipVerify: null + + # Name of the server to use when validating TLS certificate + serverName: null + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping coreDns. Use either this or kubeDns +## +coreDns: + enabled: true + service: + port: 9153 + targetPort: 9153 + # selector: + # k8s-app: kube-dns + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kubeDns. Use either this or coreDns +## +kubeDns: + enabled: false + service: + dnsmasq: + port: 10054 + targetPort: 10054 + skydns: + port: 10055 + targetPort: 10055 + # selector: + # k8s-app: kube-dns + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + dnsmasqMetricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + dnsmasqRelabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping etcd +## +kubeEtcd: + enabled: true + + ## If your etcd is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## Etcd service. If using kubeEtcd.endpoints only the port and targetPort are used + ## + service: + enabled: true + port: 2381 + targetPort: 2381 + # selector: + # component: etcd + + ## Configure secure access to the etcd cluster by loading a secret into prometheus and + ## specifying security configuration below. For example, with a secret named etcd-client-cert + ## + ## serviceMonitor: + ## scheme: https + ## insecureSkipVerify: false + ## serverName: localhost + ## caFile: /etc/prometheus/secrets/etcd-client-cert/etcd-ca + ## certFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client + ## keyFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key + ## + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + scheme: http + insecureSkipVerify: false + serverName: "" + caFile: "" + certFile: "" + keyFile: "" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube scheduler +## +kubeScheduler: + enabled: true + + ## If your kube scheduler is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## If using kubeScheduler.endpoints only the port and targetPort are used + ## + service: + enabled: true + ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change + ## of default port in Kubernetes 1.23. + ## + port: null + targetPort: null + # selector: + # component: kube-scheduler + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + ## Enable scraping kube-scheduler over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks. + ## If null or unset, the value is determined dynamically based on target Kubernetes version. + ## + https: null + + ## Skip TLS certificate validation when scraping + insecureSkipVerify: null + + ## Name of the server to use when validating TLS certificate + serverName: null + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube proxy +## +kubeProxy: + enabled: true + + ## If your kube proxy is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + service: + enabled: true + port: 10249 + targetPort: 10249 + # selector: + # k8s-app: kube-proxy + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Enable scraping kube-proxy over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks + ## + https: false + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube state metrics +## +kubeStateMetrics: + enabled: true + +## Configuration for kube-state-metrics subchart +## +kube-state-metrics: + namespaceOverride: "" + rbac: + create: true + releaseLabel: true + prometheus: + monitor: + enabled: true + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## Scrape Timeout. If not set, the Prometheus default scrape timeout is used. + ## + scrapeTimeout: "" + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + # Keep labels from scraped data, overriding server-side labels + ## + honorLabels: true + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + selfMonitor: + enabled: false + +## Deploy node exporter as a daemonset to all nodes +## +nodeExporter: + enabled: true + +## Configuration for prometheus-node-exporter subchart +## +prometheus-node-exporter: + namespaceOverride: "" + podLabels: + ## Add the 'node-exporter' label to be used by serviceMonitor to match standard common usage in rules and grafana dashboards + ## + jobLabel: node-exporter + releaseLabel: true + extraArgs: + - --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($|/) + - --collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$ + service: + portName: http-metrics + prometheus: + monitor: + enabled: true + + jobLabel: jobLabel + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## How long until a scrape request times out. If not set, the Prometheus default scape timeout is used. + ## + scrapeTimeout: "" + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - sourceLabels: [__name__] + # separator: ; + # regex: ^node_mountstats_nfs_(event|operations|transport)_.+ + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + rbac: + ## If true, create PSPs for node-exporter + ## + pspEnabled: false + +## Manages Prometheus and Alertmanager components +## +prometheusOperator: + enabled: true + + ## Prometheus-Operator v0.39.0 and later support TLS natively. + ## + tls: + enabled: true + # Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants + tlsMinVersion: VersionTLS13 + # The default webhook port is 10250 in order to work out-of-the-box in GKE private clusters and avoid adding firewall rules. + internalPort: 10250 + + ## Admission webhook support for PrometheusRules resources added in Prometheus Operator 0.30 can be enabled to prevent incorrectly formatted + ## rules from making their way into prometheus and potentially preventing the container from starting + admissionWebhooks: + ## Valid values: Fail, Ignore, IgnoreOnInstallOnly + ## IgnoreOnInstallOnly - If Release.IsInstall returns "true", set "Ignore" otherwise "Fail" + failurePolicy: "" + ## The default timeoutSeconds is 10 and the maximum value is 30. + timeoutSeconds: 10 + enabled: true + ## A PEM encoded CA bundle which will be used to validate the webhook's server certificate. + ## If unspecified, system trust roots on the apiserver are used. + caBundle: "" + ## If enabled, generate a self-signed certificate, then patch the webhook configurations with the generated data. + ## On chart upgrades (or if the secret exists) the cert will not be re-generated. You can use this to provide your own + ## certs ahead of time if you wish. + ## + annotations: {} + # argocd.argoproj.io/hook: PreSync + # argocd.argoproj.io/hook-delete-policy: HookSucceeded + patch: + enabled: true + image: + registry: registry.k8s.io + repository: ingress-nginx/kube-webhook-certgen + tag: v20221220-controller-v1.5.1-58-g787ea74b6 + sha: "" + pullPolicy: IfNotPresent + resources: {} + ## Provide a priority class name to the webhook patching job + ## + priorityClassName: "" + annotations: {} + # argocd.argoproj.io/hook: PreSync + # argocd.argoproj.io/hook-delete-policy: HookSucceeded + podAnnotations: {} + nodeSelector: {} + affinity: {} + tolerations: [] + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 2000 and gid 2000. *v1.PodSecurityContext false + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + seccompProfile: + type: RuntimeDefault + + # Security context for create job container + createSecretJob: + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Security context for patch job container + patchWebhookJob: + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Use certmanager to generate webhook certs + certManager: + enabled: false + # self-signed root certificate + rootCert: + duration: "" # default to be 5y + admissionCert: + duration: "" # default to be 1y + # issuerRef: + # name: "issuer" + # kind: "ClusterIssuer" + + ## Namespaces to scope the interaction of the Prometheus Operator and the apiserver (allow list). + ## This is mutually exclusive with denyNamespaces. Setting this to an empty object will disable the configuration + ## + namespaces: {} + # releaseNamespace: true + # additional: + # - kube-system + + ## Namespaces not to scope the interaction of the Prometheus Operator (deny list). + ## + denyNamespaces: [] + + ## Filter namespaces to look for prometheus-operator custom resources + ## + alertmanagerInstanceNamespaces: [] + alertmanagerConfigNamespaces: [] + prometheusInstanceNamespaces: [] + thanosRulerInstanceNamespaces: [] + + ## The clusterDomain value will be added to the cluster.peer option of the alertmanager. + ## Without this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated:9094 (default value) + ## With this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated.namespace.svc.cluster-domain:9094 + ## + # clusterDomain: "cluster.local" + + networkPolicy: + ## Enable creation of NetworkPolicy resources. + ## + enabled: false + + ## Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + # cilium: + # egress: + + ## Service account for Alertmanager to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + + ## Configuration for Prometheus operator service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30080 + + nodePortTls: 30443 + + ## Additional ports to open for Prometheus service + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services + ## + additionalPorts: [] + + ## Loadbalancer IP + ## Only use if service.type is "LoadBalancer" + ## + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## NodePort, ClusterIP, LoadBalancer + ## + type: ClusterIP + + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + # ## Labels to add to the operator deployment + # ## + labels: {} + + ## Annotations to add to the operator deployment + ## + annotations: {} + + ## Labels to add to the operator pod + ## + podLabels: {} + + ## Annotations to add to the operator pod + ## + podAnnotations: {} + + ## Assign a PriorityClassName to pods if set + # priorityClassName: "" + + ## Define Log Format + # Use logfmt (default) or json logging + # logFormat: logfmt + + ## Decrease log verbosity to errors only + # logLevel: error + + ## If true, the operator will create and maintain a service for scraping kubelets + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/helm/prometheus-operator/README.md + ## + kubeletService: + enabled: true + namespace: kube-system + ## Use '{{ template "kube-prometheus-stack.fullname" . }}-kubelet' by default + name: "" + + ## Create a servicemonitor for the operator + ## + serviceMonitor: + ## Labels for ServiceMonitor + additionalLabels: {} + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## Scrape timeout. If not set, the Prometheus default scrape timeout is used. + scrapeTimeout: "" + selfMonitor: true + + ## Metric relabel configs to apply to samples before ingestion. + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Resource limits & requests + ## + resources: {} + # limits: + # cpu: 200m + # memory: 200Mi + # requests: + # cpu: 100m + # memory: 100Mi + + # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico), + # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working + ## + hostNetwork: false + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for use with node taints + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## Assign custom affinity rules to the prometheus operator + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + dnsConfig: {} + # nameservers: + # - 1.2.3.4 + # searches: + # - ns1.svc.cluster-domain.example + # - my.dns.search.suffix + # options: + # - name: ndots + # value: "2" + # - name: edns0 + securityContext: + fsGroup: 65534 + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault + + ## Container-specific security context configuration + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + containerSecurityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Enable vertical pod autoscaler support for prometheus-operator + verticalPodAutoscaler: + enabled: false + + # Recommender responsible for generating recommendation for the object. + # List should be empty (then the default recommender will generate the recommendation) + # or contain exactly one recommender. + # recommenders: + # - name: custom-recommender-performance + + # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + controlledResources: [] + # Specifies which resource values should be controlled: RequestsOnly or RequestsAndLimits. + # controlledValues: RequestsAndLimits + + # Define the max allowed resources for the pod + maxAllowed: {} + # cpu: 200m + # memory: 100Mi + # Define the min allowed resources for the pod + minAllowed: {} + # cpu: 200m + # memory: 100Mi + + updatePolicy: + # Specifies minimal number of replicas which need to be alive for VPA Updater to attempt pod eviction + # minReplicas: 1 + # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates + # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto". + updateMode: Auto + + ## Prometheus-operator image + ## + image: + registry: quay.io + repository: prometheus-operator/prometheus-operator + # if not set appVersion field from Chart.yaml is used + tag: "" + sha: "" + pullPolicy: IfNotPresent + + ## Prometheus image to use for prometheuses managed by the operator + ## + # prometheusDefaultBaseImage: prometheus/prometheus + + ## Prometheus image registry to use for prometheuses managed by the operator + ## + # prometheusDefaultBaseImageRegistry: quay.io + + ## Alertmanager image to use for alertmanagers managed by the operator + ## + # alertmanagerDefaultBaseImage: prometheus/alertmanager + + ## Alertmanager image registry to use for alertmanagers managed by the operator + ## + # alertmanagerDefaultBaseImageRegistry: quay.io + + ## Prometheus-config-reloader + ## + prometheusConfigReloader: + image: + registry: quay.io + repository: prometheus-operator/prometheus-config-reloader + # if not set appVersion field from Chart.yaml is used + tag: "" + sha: "" + + # add prometheus config reloader liveness and readiness probe. Default: false + enableProbe: false + + # resource config for prometheusConfigReloader + resources: + requests: + cpu: 200m + memory: 50Mi + limits: + cpu: 200m + memory: 50Mi + + ## Thanos side-car image when configured + ## + thanosImage: + registry: quay.io + repository: thanos/thanos + tag: v0.31.0 + sha: "" + + ## Set a Label Selector to filter watched prometheus and prometheusAgent + ## + prometheusInstanceSelector: "" + + ## Set a Label Selector to filter watched alertmanager + ## + alertmanagerInstanceSelector: "" + + ## Set a Label Selector to filter watched thanosRuler + thanosRulerInstanceSelector: "" + + ## Set a Field Selector to filter watched secrets + ## + secretFieldSelector: "type!=kubernetes.io/dockercfg,type!=kubernetes.io/service-account-token,type!=helm.sh/release.v1" + +## Deploy a Prometheus instance +## +prometheus: + enabled: true + + ## Toggle prometheus into agent mode + ## Note many of features described below (e.g. rules, query, alerting, remote read, thanos) will not work in agent mode. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/designs/prometheus-agent.md + ## + agentMode: false + + ## Annotations for Prometheus + ## + annotations: {} + + ## Configure network policy for the prometheus + networkPolicy: + enabled: false + + ## Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + # cilium: + # endpointSelector: + # egress: + # ingress: + + # egress: + # - {} + # ingress: + # - {} + # podSelector: + # matchLabels: + # app: prometheus + + ## Service account for Prometheuses to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + annotations: {} + + # Service for thanos service discovery on sidecar + # Enable this can make Thanos Query can use + # `--store=dnssrv+_grpc._tcp.${kube-prometheus-stack.fullname}-thanos-discovery.${namespace}.svc.cluster.local` to discovery + # Thanos sidecar on prometheus nodes + # (Please remember to change ${kube-prometheus-stack.fullname} and ${namespace}. Not just copy and paste!) + thanosService: + enabled: false + annotations: {} + labels: {} + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## gRPC port config + portName: grpc + port: 10901 + targetPort: "grpc" + + ## HTTP port config (for metrics) + httpPortName: http + httpPort: 10902 + targetHttpPort: "http" + + ## ClusterIP to assign + # Default is to make this a headless service ("None") + clusterIP: "None" + + ## Port to expose on each node, if service type is NodePort + ## + nodePort: 30901 + httpNodePort: 30902 + + # ServiceMonitor to scrape Sidecar metrics + # Needs thanosService to be enabled as well + thanosServiceMonitor: + enabled: false + interval: "" + + ## Additional labels + ## + additionalLabels: {} + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## Metric relabel configs to apply to samples before ingestion. + metricRelabelings: [] + + ## relabel configs to apply to samples before ingestion. + relabelings: [] + + # Service for external access to sidecar + # Enabling this creates a service to expose thanos-sidecar outside the cluster. + thanosServiceExternal: + enabled: false + annotations: {} + labels: {} + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## gRPC port config + portName: grpc + port: 10901 + targetPort: "grpc" + + ## HTTP port config (for metrics) + httpPortName: http + httpPort: 10902 + targetHttpPort: "http" + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: LoadBalancer + + ## Port to expose on each node + ## + nodePort: 30901 + httpNodePort: 30902 + + ## Configuration for Prometheus service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + + ## Port for Prometheus Service to listen on + ## + port: 9090 + + ## To be used with a proxy extraContainer port + targetPort: 9090 + + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30090 + + ## Loadbalancer IP + ## Only use if service.type is "LoadBalancer" + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Additional port to define in the Service + additionalPorts: [] + # additionalPorts: + # - name: authenticated + # port: 8081 + # targetPort: 8081 + + ## Consider that all endpoints are considered "ready" even if the Pods themselves are not + ## Ref: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec + publishNotReadyAddresses: false + + sessionAffinity: "" + + ## Configuration for creating a separate Service for each statefulset Prometheus replica + ## + servicePerReplica: + enabled: false + annotations: {} + + ## Port for Prometheus Service per replica to listen on + ## + port: 9090 + + ## To be used with a proxy extraContainer port + targetPort: 9090 + + ## Port to expose on each node + ## Only used if servicePerReplica.type is 'NodePort' + ## + nodePort: 30091 + + ## Loadbalancer source IP ranges + ## Only used if servicePerReplica.type is "LoadBalancer" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Configure pod disruption budgets for Prometheus + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget + ## This configuration is immutable once created and will require the PDB to be deleted to be changed + ## https://github.com/kubernetes/kubernetes/issues/45398 + ## + podDisruptionBudget: + enabled: false + minAvailable: 1 + maxUnavailable: "" + + # Ingress exposes thanos sidecar outside the cluster + thanosIngress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + servicePort: 10901 + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30901 + + ## Hosts must be provided if Ingress is enabled. + ## + hosts: [] + # - thanos-gateway.domain.com + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Thanos Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: thanos-gateway-tls + # hosts: + # - thanos-gateway.domain.com + # + + ## ExtraSecret can be used to store various data in an extra secret + ## (use it for example to store hashed basic auth credentials) + extraSecret: + ## if not set, name will be auto generated + # name: "" + annotations: {} + data: {} + # auth: | + # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0 + # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c. + + ingress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Redirect ingress to an additional defined port on the service + # servicePort: 8081 + + ## Hostnames. + ## Must be provided if Ingress is enabled. + ## + # hosts: + # - prometheus.domain.com + hosts: [] + + ## Paths to use for ingress rules - one path should match the prometheusSpec.routePrefix + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Prometheus Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: prometheus-general-tls + # hosts: + # - prometheus.example.com + + ## Configuration for creating an Ingress that will map to each Prometheus replica service + ## prometheus.servicePerReplica must be enabled + ## + ingressPerReplica: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Final form of the hostname for each per replica ingress is + ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }} + ## + ## Prefix for the per replica ingress that will have `-$replicaNumber` + ## appended to the end + hostPrefix: "" + ## Domain that will be used for the per replica ingress + hostDomain: "" + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## Secret name containing the TLS certificate for Prometheus per replica ingress + ## Secret must be manually created in the namespace + tlsSecretName: "" + + ## Separated secret for each per replica Ingress. Can be used together with cert-manager + ## + tlsSecretPerReplica: + enabled: false + ## Final form of the secret for each per replica ingress is + ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }} + ## + prefix: "prometheus" + + ## Configure additional options for default pod security policy for Prometheus + ## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ + podSecurityPolicy: + allowedCapabilities: [] + allowedHostPaths: [] + volumes: [] + + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + selfMonitor: true + + ## Additional labels + ## + additionalLabels: {} + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## Metric relabel configs to apply to samples before ingestion. + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Settings affecting prometheusSpec + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#prometheusspec + ## + prometheusSpec: + ## If true, pass --storage.tsdb.max-block-duration=2h to prometheus. This is already done if using Thanos + ## + disableCompaction: false + ## APIServerConfig + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#apiserverconfig + ## + apiserverConfig: {} + + ## Allows setting additional arguments for the Prometheus container + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.Prometheus + additionalArgs: [] + + ## Interval between consecutive scrapes. + ## Defaults to 30s. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/release-0.44/pkg/prometheus/promcfg.go#L180-L183 + ## + scrapeInterval: "" + + ## Number of seconds to wait for target to respond before erroring + ## + scrapeTimeout: "" + + ## Interval between consecutive evaluations. + ## + evaluationInterval: "" + + ## ListenLocal makes the Prometheus server listen on loopback, so that it does not bind against the Pod IP. + ## + listenLocal: false + + ## EnableAdminAPI enables Prometheus the administrative HTTP API which includes functionality such as deleting time series. + ## This is disabled by default. + ## ref: https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-admin-apis + ## + enableAdminAPI: false + + ## Sets version of Prometheus overriding the Prometheus version as derived + ## from the image tag. Useful in cases where the tag does not follow semver v2. + version: "" + + ## WebTLSConfig defines the TLS parameters for HTTPS + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#webtlsconfig + web: {} + + ## Exemplars related settings that are runtime reloadable. + ## It requires to enable the exemplar storage feature to be effective. + exemplars: "" + ## Maximum number of exemplars stored in memory for all series. + ## If not set, Prometheus uses its default value. + ## A value of zero or less than zero disables the storage. + # maxSize: 100000 + + # EnableFeatures API enables access to Prometheus disabled features. + # ref: https://prometheus.io/docs/prometheus/latest/disabled_features/ + enableFeatures: [] + # - exemplar-storage + + ## Image of Prometheus. + ## + image: + registry: quay.io + repository: prometheus/prometheus + tag: v2.45.0 + sha: "" + + ## Tolerations for use with node taints + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## If specified, the pod's topology spread constraints. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app: prometheus + + ## Alertmanagers to which alerts will be sent + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerendpoints + ## + ## Default configuration will connect to the alertmanager deployed as part of this release + ## + alertingEndpoints: [] + # - name: "" + # namespace: "" + # port: http + # scheme: http + # pathPrefix: "" + # tlsConfig: {} + # bearerTokenFile: "" + # apiVersion: v2 + + ## External labels to add to any time series or alerts when communicating with external systems + ## + externalLabels: {} + + ## enable --web.enable-remote-write-receiver flag on prometheus-server + ## + enableRemoteWriteReceiver: false + + ## Name of the external label used to denote replica name + ## + replicaExternalLabelName: "" + + ## If true, the Operator won't add the external label used to denote replica name + ## + replicaExternalLabelNameClear: false + + ## Name of the external label used to denote Prometheus instance name + ## + prometheusExternalLabelName: "" + + ## If true, the Operator won't add the external label used to denote Prometheus instance name + ## + prometheusExternalLabelNameClear: false + + ## External URL at which Prometheus will be reachable. + ## + externalUrl: "" + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Secrets is a list of Secrets in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods. + ## The Secrets are mounted into /etc/prometheus/secrets/. Secrets changes after initial creation of a Prometheus object are not + ## reflected in the running Pods. To change the secrets mounted into the Prometheus Pods, the object must be deleted and recreated + ## with the new list of secrets. + ## + secrets: [] + + ## ConfigMaps is a list of ConfigMaps in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods. + ## The ConfigMaps are mounted into /etc/prometheus/configmaps/. + ## + configMaps: [] + + ## QuerySpec defines the query command line flags when starting Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#queryspec + ## + query: {} + + ## If nil, select own namespace. Namespaces to be selected for PrometheusRules discovery. + ruleNamespaceSelector: {} + ## Example which selects PrometheusRules in namespaces with label "prometheus" set to "somelabel" + # ruleNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.ruleSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the PrometheusRule resources created + ## + ruleSelectorNilUsesHelmValues: true + + ## PrometheusRules to be selected for target discovery. + ## If {}, select all PrometheusRules + ## + ruleSelector: {} + ## Example which select all PrometheusRules resources + ## with label "prometheus" with values any of "example-rules" or "example-rules-2" + # ruleSelector: + # matchExpressions: + # - key: prometheus + # operator: In + # values: + # - example-rules + # - example-rules-2 + # + ## Example which select all PrometheusRules resources with label "role" set to "example-rules" + # ruleSelector: + # matchLabels: + # role: example-rules + + ## If true, a nil or {} value for prometheus.prometheusSpec.serviceMonitorSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the servicemonitors created + ## + serviceMonitorSelectorNilUsesHelmValues: true + + ## ServiceMonitors to be selected for target discovery. + ## If {}, select all ServiceMonitors + ## + serviceMonitorSelector: {} + ## Example which selects ServiceMonitors with label "prometheus" set to "somelabel" + # serviceMonitorSelector: + # matchLabels: + # prometheus: somelabel + + ## Namespaces to be selected for ServiceMonitor discovery. + ## + serviceMonitorNamespaceSelector: {} + ## Example which selects ServiceMonitors in namespaces with label "prometheus" set to "somelabel" + # serviceMonitorNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.podMonitorSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the podmonitors created + ## + podMonitorSelectorNilUsesHelmValues: true + + ## PodMonitors to be selected for target discovery. + ## If {}, select all PodMonitors + ## + podMonitorSelector: {} + ## Example which selects PodMonitors with label "prometheus" set to "somelabel" + # podMonitorSelector: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for PodMonitor discovery. + podMonitorNamespaceSelector: {} + ## Example which selects PodMonitor in namespaces with label "prometheus" set to "somelabel" + # podMonitorNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.probeSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the probes created + ## + probeSelectorNilUsesHelmValues: true + + ## Probes to be selected for target discovery. + ## If {}, select all Probes + ## + probeSelector: {} + ## Example which selects Probes with label "prometheus" set to "somelabel" + # probeSelector: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for Probe discovery. + probeNamespaceSelector: {} + ## Example which selects Probe in namespaces with label "prometheus" set to "somelabel" + # probeNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.scrapeConfigSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the scrapeConfigs created + ## + scrapeConfigSelectorNilUsesHelmValues: true + + ## scrapeConfigs to be selected for target discovery. + ## If {}, select all scrapeConfigs + ## + scrapeConfigSelector: {} + ## Example which selects scrapeConfigs with label "prometheus" set to "somelabel" + # scrapeConfig: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for scrapeConfig discovery. + scrapeConfigNamespaceSelector: {} + ## Example which selects scrapeConfig in namespaces with label "prometheus" set to "somelabel" + # scrapeConfigsNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## How long to retain metrics + ## + retention: 10d + + ## Maximum size of metrics + ## + retentionSize: "" + + ## Allow out-of-order/out-of-bounds samples ingested into Prometheus for a specified duration + ## See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#tsdb + tsdb: + outOfOrderTimeWindow: 0s + + ## Enable compression of the write-ahead log using Snappy. + ## + walCompression: true + + ## If true, the Operator won't process any Prometheus configuration changes + ## + paused: false + + ## Number of replicas of each shard to deploy for a Prometheus deployment. + ## Number of replicas multiplied by shards is the total number of Pods created. + ## + replicas: 1 + + ## EXPERIMENTAL: Number of shards to distribute targets onto. + ## Number of replicas multiplied by shards is the total number of Pods created. + ## Note that scaling down shards will not reshard data onto remaining instances, it must be manually moved. + ## Increasing shards will not reshard data either but it will continue to be available from the same instances. + ## To query globally use Thanos sidecar and Thanos querier or remote write data to a central location. + ## Sharding is done on the content of the `__address__` target meta-label. + ## + shards: 1 + + ## Log level for Prometheus be configured in + ## + logLevel: info + + ## Log format for Prometheus be configured in + ## + logFormat: logfmt + + ## Prefix used to register routes, overriding externalUrl route. + ## Useful for proxies that rewrite URLs. + ## + routePrefix: / + + ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata + ## Metadata Labels and Annotations gets propagated to the prometheus pods. + ## + podMetadata: {} + # labels: + # app: prometheus + # k8s-app: prometheus + + ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node. + ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided. + ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node. + ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured. + podAntiAffinity: "" + + ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity. + ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone + ## + podAntiAffinityTopologyKey: kubernetes.io/hostname + + ## Assign custom affinity rules to the prometheus instance + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + + ## The remote_read spec configuration for Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotereadspec + remoteRead: [] + # - url: http://remote1/read + ## additionalRemoteRead is appended to remoteRead + additionalRemoteRead: [] + + ## The remote_write spec configuration for Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotewritespec + remoteWrite: [] + # - url: http://remote1/push + ## additionalRemoteWrite is appended to remoteWrite + additionalRemoteWrite: [] + + ## Enable/Disable Grafana dashboards provisioning for prometheus remote write feature + remoteWriteDashboards: false + + ## Resource limits & requests + ## + resources: {} + # requests: + # memory: 400Mi + + ## Prometheus StorageSpec for persistent data + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md + ## + storageSpec: {} + ## Using PersistentVolumeClaim + ## + # volumeClaimTemplate: + # spec: + # storageClassName: gluster + # accessModes: ["ReadWriteOnce"] + # resources: + # requests: + # storage: 50Gi + # selector: {} + + ## Using tmpfs volume + ## + # emptyDir: + # medium: Memory + + # Additional volumes on the output StatefulSet definition. + volumes: [] + + # Additional VolumeMounts on the output StatefulSet definition. + volumeMounts: [] + + ## AdditionalScrapeConfigs allows specifying additional Prometheus scrape configurations. Scrape configurations + ## are appended to the configurations generated by the Prometheus Operator. Job configurations must have the form + ## as specified in the official Prometheus documentation: + ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config. As scrape configs are + ## appended, the user is responsible to make sure it is valid. Note that using this feature may expose the possibility + ## to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible + ## scrape configs are going to break Prometheus after the upgrade. + ## AdditionalScrapeConfigs can be defined as a list or as a templated string. + ## + ## The scrape configuration example below will find master nodes, provided they have the name .*mst.*, relabel the + ## port to 2379 and allow etcd scraping provided it is running on all Kubernetes master nodes + ## + additionalScrapeConfigs: [] + # - job_name: kube-etcd + # kubernetes_sd_configs: + # - role: node + # scheme: https + # tls_config: + # ca_file: /etc/prometheus/secrets/etcd-client-cert/etcd-ca + # cert_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client + # key_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key + # relabel_configs: + # - action: labelmap + # regex: __meta_kubernetes_node_label_(.+) + # - source_labels: [__address__] + # action: replace + # targetLabel: __address__ + # regex: ([^:;]+):(\d+) + # replacement: ${1}:2379 + # - source_labels: [__meta_kubernetes_node_name] + # action: keep + # regex: .*mst.* + # - source_labels: [__meta_kubernetes_node_name] + # action: replace + # targetLabel: node + # regex: (.*) + # replacement: ${1} + # metric_relabel_configs: + # - regex: (kubernetes_io_hostname|failure_domain_beta_kubernetes_io_region|beta_kubernetes_io_os|beta_kubernetes_io_arch|beta_kubernetes_io_instance_type|failure_domain_beta_kubernetes_io_zone) + # action: labeldrop + # + ## If scrape config contains a repetitive section, you may want to use a template. + ## In the following example, you can see how to define `gce_sd_configs` for multiple zones + # additionalScrapeConfigs: | + # - job_name: "node-exporter" + # gce_sd_configs: + # {{range $zone := .Values.gcp_zones}} + # - project: "project1" + # zone: "{{$zone}}" + # port: 9100 + # {{end}} + # relabel_configs: + # ... + + + ## If additional scrape configurations are already deployed in a single secret file you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalScrapeConfigs + additionalScrapeConfigsSecret: {} + # enabled: false + # name: + # key: + + ## additionalPrometheusSecretsAnnotations allows to add annotations to the kubernetes secret. This can be useful + ## when deploying via spinnaker to disable versioning on the secret, strategy.spinnaker.io/versioned: 'false' + additionalPrometheusSecretsAnnotations: {} + + ## AdditionalAlertManagerConfigs allows for manual configuration of alertmanager jobs in the form as specified + ## in the official Prometheus documentation https://prometheus.io/docs/prometheus/latest/configuration/configuration/#. + ## AlertManager configurations specified are appended to the configurations generated by the Prometheus Operator. + ## As AlertManager configs are appended, the user is responsible to make sure it is valid. Note that using this + ## feature may expose the possibility to break upgrades of Prometheus. It is advised to review Prometheus release + ## notes to ensure that no incompatible AlertManager configs are going to break Prometheus after the upgrade. + ## + additionalAlertManagerConfigs: [] + # - consul_sd_configs: + # - server: consul.dev.test:8500 + # scheme: http + # datacenter: dev + # tag_separator: ',' + # services: + # - metrics-prometheus-alertmanager + + ## If additional alertmanager configurations are already deployed in a single secret, or you want to manage + ## them separately from the helm deployment, you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalAlertManagerConfigs + additionalAlertManagerConfigsSecret: {} + # name: + # key: + # optional: false + + ## AdditionalAlertRelabelConfigs allows specifying Prometheus alert relabel configurations. Alert relabel configurations specified are appended + ## to the configurations generated by the Prometheus Operator. Alert relabel configurations specified must have the form as specified in the + ## official Prometheus documentation: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alert_relabel_configs. + ## As alert relabel configs are appended, the user is responsible to make sure it is valid. Note that using this feature may expose the + ## possibility to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible alert relabel + ## configs are going to break Prometheus after the upgrade. + ## + additionalAlertRelabelConfigs: [] + # - separator: ; + # regex: prometheus_replica + # replacement: $1 + # action: labeldrop + + ## If additional alert relabel configurations are already deployed in a single secret, or you want to manage + ## them separately from the helm deployment, you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalAlertRelabelConfigs + additionalAlertRelabelConfigsSecret: {} + # name: + # key: + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 1000 and gid 2000. + ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 2000 + seccompProfile: + type: RuntimeDefault + + ## Priority class assigned to the Pods + ## + priorityClassName: "" + + ## Thanos configuration allows configuring various aspects of a Prometheus server in a Thanos environment. + ## This section is experimental, it may change significantly without deprecation notice in any release. + ## This is experimental and may change significantly without backward compatibility in any release. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#thanosspec + ## + thanos: {} + # secretProviderClass: + # provider: gcp + # parameters: + # secrets: | + # - resourceName: "projects/$PROJECT_ID/secrets/testsecret/versions/latest" + # fileName: "objstore.yaml" + # objectStorageConfigFile: /var/secrets/object-store.yaml + + ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to a Prometheus pod. + ## if using proxy extraContainer update targetPort with proxy container port + containers: [] + # containers: + # - name: oauth-proxy + # image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0 + # args: + # - --upstream=http://127.0.0.1:9093 + # - --http-address=0.0.0.0:8081 + # - ... + # ports: + # - containerPort: 8081 + # name: oauth-proxy + # protocol: TCP + # resources: {} + + ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes + ## (permissions, dir tree) on mounted volumes before starting prometheus + initContainers: [] + + ## PortName to use for Prometheus. + ## + portName: "http-web" + + ## ArbitraryFSAccessThroughSMs configures whether configuration based on a service monitor can access arbitrary files + ## on the file system of the Prometheus container e.g. bearer token files. + arbitraryFSAccessThroughSMs: false + + ## OverrideHonorLabels if set to true overrides all user configured honor_labels. If HonorLabels is set in ServiceMonitor + ## or PodMonitor to true, this overrides honor_labels to false. + overrideHonorLabels: false + + ## OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs. + overrideHonorTimestamps: false + + ## IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from the podmonitor and servicemonitor + ## configs, and they will only discover endpoints within their current namespace. Defaults to false. + ignoreNamespaceSelectors: false + + ## EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert and metric that is user created. + ## The label value will always be the namespace of the object that is being created. + ## Disabled by default + enforcedNamespaceLabel: "" + + ## PrometheusRulesExcludedFromEnforce - list of prometheus rules to be excluded from enforcing of adding namespace labels. + ## Works only if enforcedNamespaceLabel set to true. Make sure both ruleNamespace and ruleName are set for each pair + ## Deprecated, use `excludedFromEnforcement` instead + prometheusRulesExcludedFromEnforce: [] + + ## ExcludedFromEnforcement - list of object references to PodMonitor, ServiceMonitor, Probe and PrometheusRule objects + ## to be excluded from enforcing a namespace label of origin. + ## Works only if enforcedNamespaceLabel set to true. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#objectreference + excludedFromEnforcement: [] + + ## QueryLogFile specifies the file to which PromQL queries are logged. Note that this location must be writable, + ## and can be persisted using an attached volume. Alternatively, the location can be set to a stdout location such + ## as /dev/stdout to log querie information to the default Prometheus log stream. This is only available in versions + ## of Prometheus >= 2.16.0. For more details, see the Prometheus docs (https://prometheus.io/docs/guides/query-log/) + queryLogFile: false + + ## EnforcedSampleLimit defines global limit on number of scraped samples that will be accepted. This overrides any SampleLimit + ## set per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the SampleLimit to keep overall + ## number of samples/series under the desired limit. Note that if SampleLimit is lower that value will be taken instead. + enforcedSampleLimit: false + + ## EnforcedTargetLimit defines a global limit on the number of scraped targets. This overrides any TargetLimit set + ## per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the TargetLimit to keep the overall + ## number of targets under the desired limit. Note that if TargetLimit is lower, that value will be taken instead, except + ## if either value is zero, in which case the non-zero value will be used. If both values are zero, no limit is enforced. + enforcedTargetLimit: false + + + ## Per-scrape limit on number of labels that will be accepted for a sample. If more than this number of labels are present + ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions + ## 2.27.0 and newer. + enforcedLabelLimit: false + + ## Per-scrape limit on length of labels name that will be accepted for a sample. If a label name is longer than this number + ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions + ## 2.27.0 and newer. + enforcedLabelNameLengthLimit: false + + ## Per-scrape limit on length of labels value that will be accepted for a sample. If a label value is longer than this + ## number post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus + ## versions 2.27.0 and newer. + enforcedLabelValueLengthLimit: false + + ## AllowOverlappingBlocks enables vertical compaction and vertical query merge in Prometheus. This is still experimental + ## in Prometheus so it may change in any upcoming release. + allowOverlappingBlocks: false + + ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to + ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready). + minReadySeconds: 0 + + # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico), + # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working + # Use the host's network namespace if true. Make sure to understand the security implications if you want to enable it. + # When hostNetwork is enabled, this will set dnsPolicy to ClusterFirstWithHostNet automatically. + hostNetwork: false + + # HostAlias holds the mapping between IP and hostnames that will be injected + # as an entry in the pod’s hosts file. + hostAliases: [] + # - ip: 10.10.0.100 + # hostnames: + # - a1.app.local + # - b1.app.local + + ## TracingConfig configures tracing in Prometheus. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#prometheustracingconfig + tracingConfig: {} + + additionalRulesForClusterRole: [] + # - apiGroups: [ "" ] + # resources: + # - nodes/proxy + # verbs: [ "get", "list", "watch" ] + + additionalServiceMonitors: [] + ## Name of the ServiceMonitor to create + ## + # - name: "" + + ## Additional labels to set used for the ServiceMonitorSelector. Together with standard labels from + ## the chart + ## + # additionalLabels: {} + + ## Service label for use in assembling a job name of the form