Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
74 changes: 74 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,80 @@ jobs:
kubectl -n helm-system wait helmreleases/podinfo-git --for=condition=ready --timeout=4m
kubectl -n helm-system wait helmreleases/podinfo-oci --for=condition=ready --timeout=4m
kubectl -n helm-system delete -f config/testdata/podinfo
- name: Run server-side apply test
run: |
test_name=server-side-apply
kubectl -n helm-system apply -f config/testdata/$test_name/install.yaml
kubectl -n helm-system wait helmreleases/$test_name --for=condition=ready --timeout=4m

# Verify the release is deployed with SSA.
APPLY_METHOD=$(kubectl -n helm-system get secret sh.helm.release.v1.$test_name.v1 -o jsonpath='{.data.release}' | base64 -d | base64 -d | gunzip | jq -r '.apply_method')
if [ "$APPLY_METHOD" != "ssa" ]; then
echo -e "Unexpected apply method: $APPLY_METHOD (expected: ssa)"
exit 1
fi

# Upgrade with SSA.
kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml
kubectl -n helm-system wait helmreleases/$test_name --for=condition=ready --timeout=4m

# Validate release was upgraded.
REVISION_COUNT=$(helm -n helm-system history -o json $test_name | jq 'length')
if [ "$REVISION_COUNT" != 2 ]; then
echo -e "Unexpected revision count: $REVISION_COUNT"
exit 1
fi

kubectl -n helm-system delete -f config/testdata/$test_name/install.yaml
- name: Run server-side apply rollback test
run: |
test_name=server-side-apply-rollback
kubectl -n helm-system apply -f config/testdata/server-side-apply/rollback-install.yaml
kubectl -n helm-system wait helmreleases/$test_name --for=condition=ready --timeout=4m

# Verify the release is deployed with SSA.
APPLY_METHOD=$(kubectl -n helm-system get secret sh.helm.release.v1.$test_name.v1 -o jsonpath='{.data.release}' | base64 -d | base64 -d | gunzip | jq -r '.apply_method')
if [ "$APPLY_METHOD" != "ssa" ]; then
echo -e "Unexpected apply method: $APPLY_METHOD (expected: ssa)"
exit 1
fi

# Upgrade with failing config to trigger rollback.
kubectl -n helm-system apply -f config/testdata/server-side-apply/rollback-upgrade.yaml
echo -n ">>> Waiting for rollback"
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" and .Remediated=="True"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
if [[ ${count} -eq 24 ]]; then
echo ' No more retries left!'
exit 1
fi
done
echo ' done'

# Validate rollback happened with SSA (revision 3 = rollback to 1).
HISTORY=$(helm -n helm-system history -o json $test_name)
REVISION_COUNT=$(echo "$HISTORY" | jq 'length')
if [ "$REVISION_COUNT" != 3 ]; then
echo -e "Unexpected revision count: $REVISION_COUNT"
exit 1
fi
LAST_REVISION_DESCRIPTION=$(echo "$HISTORY" | jq -r 'last | .description')
if [ "$LAST_REVISION_DESCRIPTION" != "Rollback to 1" ]; then
echo -e "Unexpected last revision description: $LAST_REVISION_DESCRIPTION"
exit 1
fi

# Verify the rollback release used SSA.
APPLY_METHOD=$(kubectl -n helm-system get secret sh.helm.release.v1.$test_name.v3 -o jsonpath='{.data.release}' | base64 -d | base64 -d | gunzip | jq -r '.apply_method')
if [ "$APPLY_METHOD" != "ssa" ]; then
echo -e "Unexpected apply method after rollback: $APPLY_METHOD (expected: ssa)"
exit 1
fi

kubectl -n helm-system delete -f config/testdata/server-side-apply/rollback-install.yaml
- name: Run dependency tests
run: |
kubectl -n helm-system apply -f config/testdata/dependencies
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ COPY api/ api/
# copy modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
COPY helm/ helm/

# cache modules
RUN go mod download
Expand Down
72 changes: 68 additions & 4 deletions api/v2/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,11 @@ type Install struct {
// On uninstall, the namespace will not be garbage collected.
// +optional
CreateNamespace bool `json:"createNamespace,omitempty"`

// ServerSideApply enables server-side apply for resources during install.
// Defaults to true (or false when UseHelm3Defaults feature gate is enabled).
// +optional
ServerSideApply *bool `json:"serverSideApply,omitempty"`
}

// GetTimeout returns the configured timeout for the Helm install action,
Expand Down Expand Up @@ -569,6 +574,11 @@ func (in Install) GetRetry() Retry {
return in.Strategy
}

// GetDisableWait returns whether waiting is disabled for the Helm install action.
func (in Install) GetDisableWait() bool {
return in.DisableWait
}

// InstallStrategy holds the configuration for Helm install strategy.
// +kubebuilder:validation:XValidation:rule="!has(self.retryInterval) || self.name != 'RemediateOnFailure'", message=".retryInterval cannot be set when .name is 'RemediateOnFailure'"
type InstallStrategy struct {
Expand Down Expand Up @@ -674,6 +684,21 @@ const (
CreateReplace CRDsPolicy = "CreateReplace"
)

// ServerSideApplyMode defines the server-side apply mode for Helm upgrade and
// rollback actions.
type ServerSideApplyMode string

var (
// ServerSideApplyEnabled enables server-side apply for resources.
ServerSideApplyEnabled ServerSideApplyMode = "enabled"

// ServerSideApplyDisabled disables server-side apply for resources.
ServerSideApplyDisabled ServerSideApplyMode = "disabled"

// ServerSideApplyAuto uses the release's previous apply method.
ServerSideApplyAuto ServerSideApplyMode = "auto"
)

// Upgrade holds the configuration for Helm upgrade actions for this
// HelmRelease.
type Upgrade struct {
Expand Down Expand Up @@ -758,6 +783,14 @@ type Upgrade struct {
// +kubebuilder:validation:Enum=Skip;Create;CreateReplace
// +optional
CRDs CRDsPolicy `json:"crds,omitempty"`

// ServerSideApply enables server-side apply for resources during upgrade.
// Can be "enabled", "disabled", or "auto".
// When "auto", server-side apply usage will be based on the release's previous usage.
// Defaults to "auto".
// +kubebuilder:validation:Enum=enabled;disabled;auto
// +optional
ServerSideApply ServerSideApplyMode `json:"serverSideApply,omitempty"`
}

// GetTimeout returns the configured timeout for the Helm upgrade action, or the
Expand Down Expand Up @@ -787,6 +820,11 @@ func (in Upgrade) GetRetry() Retry {
return in.Strategy
}

// GetDisableWait returns whether waiting is disabled for the Helm upgrade action.
func (in Upgrade) GetDisableWait() bool {
return in.DisableWait
}

// UpgradeStrategy holds the configuration for Helm upgrade strategy.
// +kubebuilder:validation:XValidation:rule="!has(self.retryInterval) || self.name == 'RetryOnFailure'", message=".retryInterval can only be set when .name is 'RetryOnFailure'"
type UpgradeStrategy struct {
Expand Down Expand Up @@ -991,7 +1029,15 @@ type Rollback struct {
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`

// Recreate performs pod restarts for the resource if applicable.
// Recreate performs pod restarts for any managed workloads.
//
// Deprecated: This behavior was deprecated in Helm 3:
// - Deprecation: https://github.com/helm/helm/pull/6463
// - Removal: https://github.com/helm/helm/pull/31023
// After helm-controller was upgraded to the Helm 4 SDK,
// this field is no longer functional and will print a
// warning if set to true. It will also be removed in a
// future release.
// +optional
Recreate bool `json:"recreate,omitempty"`

Expand All @@ -1003,6 +1049,14 @@ type Rollback struct {
// rollback action when it fails.
// +optional
CleanupOnFail bool `json:"cleanupOnFail,omitempty"`

// ServerSideApply enables server-side apply for resources during rollback.
// Can be "enabled", "disabled", or "auto".
// When "auto", server-side apply usage will be based on the release's previous usage.
// Defaults to "auto".
// +kubebuilder:validation:Enum=enabled;disabled;auto
// +optional
ServerSideApply ServerSideApplyMode `json:"serverSideApply,omitempty"`
}

// GetTimeout returns the configured timeout for the Helm rollback action, or
Expand All @@ -1014,6 +1068,11 @@ func (in Rollback) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
return *in.Timeout
}

// GetDisableWait returns whether waiting is disabled for the Helm rollback action.
func (in Rollback) GetDisableWait() bool {
return in.DisableWait
}

// Uninstall holds the configuration for Helm uninstall actions for this
// HelmRelease.
type Uninstall struct {
Expand Down Expand Up @@ -1065,6 +1124,11 @@ func (in Uninstall) GetDeletionPropagation() string {
return *in.DeletionPropagation
}

// GetDisableWait returns whether waiting is disabled for the Helm uninstall action.
func (in Uninstall) GetDisableWait() bool {
return in.DisableWait
}

// ReleaseAction is the action to perform a Helm release.
type ReleaseAction string

Expand Down Expand Up @@ -1322,10 +1386,10 @@ func (in HelmRelease) GetRequeueAfter() time.Duration {
return in.Spec.Interval.Duration
}

// GetValues unmarshals the raw values to a map[string]interface{} and returns
// GetValues unmarshals the raw values to a map[string]any and returns
// the result.
func (in HelmRelease) GetValues() map[string]interface{} {
var values map[string]interface{}
func (in HelmRelease) GetValues() map[string]any {
var values map[string]any
if in.Spec.Values != nil {
_ = yaml.Unmarshal(in.Spec.Values.Raw, &values)
}
Expand Down
5 changes: 5 additions & 0 deletions api/v2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions api/v2beta1/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1115,10 +1115,10 @@ func (in HelmRelease) GetRequeueAfter() time.Duration {
return in.Spec.Interval.Duration
}

// GetValues unmarshals the raw values to a map[string]interface{} and returns
// GetValues unmarshals the raw values to a map[string]any and returns
// the result.
func (in HelmRelease) GetValues() map[string]interface{} {
var values map[string]interface{}
func (in HelmRelease) GetValues() map[string]any {
var values map[string]any
if in.Spec.Values != nil {
_ = json.Unmarshal(in.Spec.Values.Raw, &values)
}
Expand Down
6 changes: 3 additions & 3 deletions api/v2beta2/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1185,10 +1185,10 @@ func (in HelmRelease) GetRequeueAfter() time.Duration {
return in.Spec.Interval.Duration
}

// GetValues unmarshals the raw values to a map[string]interface{} and returns
// GetValues unmarshals the raw values to a map[string]any and returns
// the result.
func (in HelmRelease) GetValues() map[string]interface{} {
var values map[string]interface{}
func (in HelmRelease) GetValues() map[string]any {
var values map[string]any
if in.Spec.Values != nil {
_ = yaml.Unmarshal(in.Spec.Values.Raw, &values)
}
Expand Down
39 changes: 37 additions & 2 deletions config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,11 @@ spec:
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
serverSideApply:
description: |-
ServerSideApply enables server-side apply for resources during install.
Defaults to true (or false when UseHelm3Defaults feature gate is enabled).
type: boolean
skipCRDs:
description: |-
SkipCRDs tells the Helm install action to not install any CRDs. By default,
Expand Down Expand Up @@ -716,9 +721,28 @@ spec:
strategy.
type: boolean
recreate:
description: Recreate performs pod restarts for the resource if
applicable.
description: |-
Recreate performs pod restarts for any managed workloads.

Deprecated: This behavior was deprecated in Helm 3:
- Deprecation: https://github.com/helm/helm/pull/6463
- Removal: https://github.com/helm/helm/pull/31023
After helm-controller was upgraded to the Helm 4 SDK,
this field is no longer functional and will print a
warning if set to true. It will also be removed in a
future release.
type: boolean
serverSideApply:
description: |-
ServerSideApply enables server-side apply for resources during rollback.
Can be "enabled", "disabled", or "auto".
When "auto", server-side apply usage will be based on the release's previous usage.
Defaults to "auto".
enum:
- enabled
- disabled
- auto
type: string
timeout:
description: |-
Timeout is the time to wait for any individual Kubernetes operation (like
Expand Down Expand Up @@ -937,6 +961,17 @@ spec:
- uninstall
type: string
type: object
serverSideApply:
description: |-
ServerSideApply enables server-side apply for resources during upgrade.
Can be "enabled", "disabled", or "auto".
When "auto", server-side apply usage will be based on the release's previous usage.
Defaults to "auto".
enum:
- enabled
- disabled
- auto
type: string
strategy:
description: |-
Strategy defines the upgrade strategy to use for this HelmRelease.
Expand Down
21 changes: 21 additions & 0 deletions config/testdata/server-side-apply/install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: server-side-apply
spec:
interval: 5m
install:
serverSideApply: true
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 1m
values:
resources:
requests:
cpu: 100m
memory: 64Mi
21 changes: 21 additions & 0 deletions config/testdata/server-side-apply/rollback-install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: server-side-apply-rollback
spec:
interval: 30s
install:
serverSideApply: true
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
values:
resources:
requests:
cpu: 100m
memory: 64Mi
Loading
Loading