Skip to content

Commit c606a18

Browse files
committed
upgrade: Add support for retrying automatically without remediations
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
1 parent 8555152 commit c606a18

7 files changed

Lines changed: 260 additions & 11 deletions

File tree

api/v2/helmrelease_types.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,11 @@ type Upgrade struct {
631631
// +optional
632632
Timeout *metav1.Duration `json:"timeout,omitempty"`
633633

634+
// Strategy defines the upgrade strategy to use for this HelmRelease.
635+
// Defaults to 'RemediateOnFailure'.
636+
// +optional
637+
Strategy *UpgradeStrategy `json:"strategy,omitempty"`
638+
634639
// Remediation holds the remediation configuration for when the Helm upgrade
635640
// action for the HelmRelease fails. The default is to not perform any action.
636641
// +optional
@@ -719,6 +724,35 @@ func (in Upgrade) GetRemediation() Remediation {
719724
return *in.Remediation
720725
}
721726

727+
// GetRetry returns the configured retry interval for the Helm upgrade
728+
// action, or the given default.
729+
func (in Upgrade) GetRetry() *metav1.Duration {
730+
if in.Strategy == nil || in.Strategy.Name != string(ActionStrategyRetryOnFailure) {
731+
return nil
732+
}
733+
if in.Strategy.RetryInterval == nil {
734+
return &metav1.Duration{Duration: 5 * time.Minute}
735+
}
736+
return in.Strategy.RetryInterval
737+
}
738+
739+
// UpgradeStrategy holds the configuration for Helm upgrade strategy.
740+
// +kubebuilder:validation:XValidation:rule="!has(self.retryInterval) || self.name == 'RetryOnFailure'", message=".retryInterval can only be set when name is 'RetryOnFailure'"
741+
type UpgradeStrategy struct {
742+
// Name of the upgrade strategy.
743+
// +kubebuilder:validation:Enum=RemediateOnFailure;RetryOnFailure
744+
// +required
745+
Name string `json:"name"`
746+
747+
// RetryInterval is the interval at which to retry a failed upgrade.
748+
// Can be used only when Name is set to RetryOnFailure.
749+
// Defaults to '5m'.
750+
// +kubebuilder:validation:Type=string
751+
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
752+
// +optional
753+
RetryInterval *metav1.Duration `json:"retryInterval,omitempty"`
754+
}
755+
722756
// UpgradeRemediation holds the configuration for Helm upgrade remediation.
723757
type UpgradeRemediation struct {
724758
// Retries is the number of retries that should be attempted on failures before
@@ -791,6 +825,19 @@ func (in UpgradeRemediation) RetriesExhausted(hr *HelmRelease) bool {
791825
return in.Retries >= 0 && in.GetFailureCount(hr) > int64(in.Retries)
792826
}
793827

828+
// ActionStrategyName is a valid name for an action strategy.
829+
type ActionStrategyName string
830+
831+
const (
832+
// ActionStrategyRemediateOnFailure is the action strategy name for
833+
// remediate on failure.
834+
ActionStrategyRemediateOnFailure ActionStrategyName = "RemediateOnFailure"
835+
836+
// ActionStrategyRetryOnFailure is the action strategy name for retry on
837+
// failure.
838+
ActionStrategyRetryOnFailure ActionStrategyName = "RetryOnFailure"
839+
)
840+
794841
// RemediationStrategy returns the strategy to use to remediate a failed install
795842
// or upgrade.
796843
type RemediationStrategy string
@@ -1012,7 +1059,8 @@ type HelmReleaseStatus struct {
10121059
History Snapshots `json:"history,omitempty"`
10131060

10141061
// LastAttemptedReleaseAction is the last release action performed for this
1015-
// HelmRelease. It is used to determine the active remediation strategy.
1062+
// HelmRelease. It is used to determine the active retry or remediation
1063+
// strategy.
10161064
// +kubebuilder:validation:Enum=install;upgrade
10171065
// +optional
10181066
LastAttemptedReleaseAction ReleaseAction `json:"lastAttemptedReleaseAction,omitempty"`
@@ -1189,6 +1237,17 @@ func (in HelmRelease) GetActiveRemediation() Remediation {
11891237
}
11901238
}
11911239

1240+
// GetActiveRetry returns the active retry configuration for the
1241+
// HelmRelease.
1242+
func (in HelmRelease) GetActiveRetry() *metav1.Duration {
1243+
switch in.Status.LastAttemptedReleaseAction {
1244+
case ReleaseActionUpgrade:
1245+
return in.GetUpgrade().GetRetry()
1246+
default:
1247+
return nil
1248+
}
1249+
}
1250+
11921251
// GetRequeueAfter returns the duration after which the HelmRelease
11931252
// must be reconciled again.
11941253
func (in HelmRelease) GetRequeueAfter() time.Duration {

api/v2/zz_generated.deepcopy.go

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,30 @@ spec:
912912
- uninstall
913913
type: string
914914
type: object
915+
strategy:
916+
description: |-
917+
Strategy defines the upgrade strategy to use for this HelmRelease.
918+
Defaults to 'RemediateOnFailure'.
919+
properties:
920+
name:
921+
description: Name of the upgrade strategy.
922+
enum:
923+
- RemediateOnFailure
924+
- RetryOnFailure
925+
type: string
926+
retryInterval:
927+
description: |-
928+
RetryInterval is the interval at which to retry a failed upgrade.
929+
Can be used only when Name is set to RetryOnFailure.
930+
Defaults to '5m'.
931+
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
932+
type: string
933+
required:
934+
- name
935+
type: object
936+
x-kubernetes-validations:
937+
- message: .retryInterval can only be set when name is 'RetryOnFailure'
938+
rule: '!has(self.retryInterval) || self.name == ''RetryOnFailure'''
915939
timeout:
916940
description: |-
917941
Timeout is the time to wait for any individual Kubernetes operation (like
@@ -1178,7 +1202,8 @@ spec:
11781202
lastAttemptedReleaseAction:
11791203
description: |-
11801204
LastAttemptedReleaseAction is the last release action performed for this
1181-
HelmRelease. It is used to determine the active remediation strategy.
1205+
HelmRelease. It is used to determine the active retry or remediation
1206+
strategy.
11821207
enum:
11831208
- install
11841209
- upgrade

docs/api/v2/helm.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ HelmReleaseStatus
424424
</table>
425425
</div>
426426
</div>
427+
<h3 id="helm.toolkit.fluxcd.io/v2.ActionStrategyName">ActionStrategyName
428+
(<code>string</code> alias)</h3>
429+
<p>ActionStrategyName is a valid name for an action strategy.</p>
427430
<h3 id="helm.toolkit.fluxcd.io/v2.CRDsPolicy">CRDsPolicy
428431
(<code>string</code> alias)</h3>
429432
<p>
@@ -1676,7 +1679,8 @@ ReleaseAction
16761679
<td>
16771680
<em>(Optional)</em>
16781681
<p>LastAttemptedReleaseAction is the last release action performed for this
1679-
HelmRelease. It is used to determine the active remediation strategy.</p>
1682+
HelmRelease. It is used to determine the active retry or remediation
1683+
strategy.</p>
16801684
</td>
16811685
</tr>
16821686
<tr>
@@ -2833,6 +2837,21 @@ Jobs for hooks) during the performance of a Helm upgrade action. Defaults to
28332837
</tr>
28342838
<tr>
28352839
<td>
2840+
<code>strategy</code><br>
2841+
<em>
2842+
<a href="#helm.toolkit.fluxcd.io/v2.UpgradeStrategy">
2843+
UpgradeStrategy
2844+
</a>
2845+
</em>
2846+
</td>
2847+
<td>
2848+
<em>(Optional)</em>
2849+
<p>Strategy defines the upgrade strategy to use for this HelmRelease.
2850+
Defaults to &lsquo;RemediateOnFailure&rsquo;.</p>
2851+
</td>
2852+
</tr>
2853+
<tr>
2854+
<td>
28362855
<code>remediation</code><br>
28372856
<em>
28382857
<a href="#helm.toolkit.fluxcd.io/v2.UpgradeRemediation">
@@ -3066,6 +3085,54 @@ RemediationStrategy
30663085
</table>
30673086
</div>
30683087
</div>
3088+
<h3 id="helm.toolkit.fluxcd.io/v2.UpgradeStrategy">UpgradeStrategy
3089+
</h3>
3090+
<p>
3091+
(<em>Appears on:</em>
3092+
<a href="#helm.toolkit.fluxcd.io/v2.Upgrade">Upgrade</a>)
3093+
</p>
3094+
<p>UpgradeStrategy holds the configuration for Helm upgrade strategy.</p>
3095+
<div class="md-typeset__scrollwrap">
3096+
<div class="md-typeset__table">
3097+
<table>
3098+
<thead>
3099+
<tr>
3100+
<th>Field</th>
3101+
<th>Description</th>
3102+
</tr>
3103+
</thead>
3104+
<tbody>
3105+
<tr>
3106+
<td>
3107+
<code>name</code><br>
3108+
<em>
3109+
string
3110+
</em>
3111+
</td>
3112+
<td>
3113+
<p>Name of the upgrade strategy.</p>
3114+
</td>
3115+
</tr>
3116+
<tr>
3117+
<td>
3118+
<code>retryInterval</code><br>
3119+
<em>
3120+
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
3121+
Kubernetes meta/v1.Duration
3122+
</a>
3123+
</em>
3124+
</td>
3125+
<td>
3126+
<em>(Optional)</em>
3127+
<p>RetryInterval is the interval at which to retry a failed upgrade.
3128+
Can be used only when Name is set to RetryOnFailure.
3129+
Defaults to &lsquo;5m&rsquo;.</p>
3130+
</td>
3131+
</tr>
3132+
</tbody>
3133+
</table>
3134+
</div>
3135+
</div>
30693136
<div class="admonition note">
30703137
<p class="last">This page was automatically generated with <code>gen-crd-api-reference-docs</code></p>
30713138
</div>

docs/spec/v2/helmreleases.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,30 @@ The field offers the following subfields:
606606
last release while merging in overrides from [values](#values). Setting
607607
this flag makes the HelmRelease non-declarative. Defaults to `false`.
608608

609+
#### Upgrade strategy
610+
611+
`.spec.upgrade.strategy` is an optional field to specify the strategy
612+
to use when running a Helm upgrade action.
613+
614+
The field offers the following subfields:
615+
616+
- `.name` (Required): The name of the upgrade strategy to use. One of
617+
`RemediateOnFailure` or `RetryOnFailure`. If the `.spec.upgrade.strategy`
618+
field is not specified, the HelmRelease reconciliation behaves as if
619+
`.spec.upgrade.strategy.name` was set to `RemediateOnFailure`.
620+
- `.retryInterval` (Optional): The time to wait between retries of failed
621+
releases wwhen the upgrade strategy is set to `RetryOnFailure`. Defaults
622+
to `5m`. Cannot be used with `RemediateOnFailure`.
623+
624+
The default `RemediateOnFailure` strategy applies the rules defined by the
625+
`.spec.upgrade.remediation` field to the upgrade action, i.e. the same
626+
behavior of the controller prior to the introduction of the `RetryOnFailure`
627+
strategy.
628+
629+
The `RetryOnFailure` strategy will retry failed releases in a regular
630+
interval defined by `.spec.upgrade.strategy.retryInterval` field, without
631+
applying any remediation.
632+
609633
#### Upgrade remediation
610634

611635
`.spec.upgrade.remediation` is an optional field to configure the remediation

internal/controller/helmrelease_controller.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,12 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
392392
Chart: loadedChart,
393393
Values: values,
394394
}); err != nil {
395-
if errors.Is(err, intreconcile.ErrMustRequeue) {
395+
switch {
396+
case errors.Is(err, intreconcile.ErrRetryAfterInterval):
397+
return ctrl.Result{RequeueAfter: obj.GetActiveRetry().Duration}, nil
398+
case errors.Is(err, intreconcile.ErrMustRequeue):
396399
return ctrl.Result{Requeue: true}, nil
397-
}
398-
if interrors.IsOneOf(err, intreconcile.ErrExceededMaxRetries, intreconcile.ErrMissingRollbackTarget) {
400+
case interrors.IsOneOf(err, intreconcile.ErrExceededMaxRetries, intreconcile.ErrMissingRollbackTarget):
399401
err = reconcile.TerminalError(err)
400402
}
401403
return ctrl.Result{}, err

0 commit comments

Comments
 (0)