Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions api/v2/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ type HelmReleaseSpec struct {
// +optional
StorageNamespace string `json:"storageNamespace,omitempty"`

// DependsOn may contain a meta.NamespacedObjectReference slice with
// DependsOn may contain a DependencyReference slice with
// references to HelmRelease resources that must be ready before this HelmRelease
// can be reconciled.
// +optional
DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"`
DependsOn []DependencyReference `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'.
Expand Down Expand Up @@ -1265,9 +1265,19 @@ func (in HelmRelease) UsePersistentClient() bool {
return *in.Spec.PersistentClient
}

// GetDependsOn returns the list of dependencies across-namespaces.
// GetDependsOn returns the dependencies as a list of meta.NamespacedObjectReference.
//
// This function makes the HelmRelease type conformant with the meta.ObjectWithDependencies interface
// and allows the controller-runtime to index HelmReleases by their dependencies.
func (in HelmRelease) GetDependsOn() []meta.NamespacedObjectReference {
return in.Spec.DependsOn
deps := make([]meta.NamespacedObjectReference, len(in.Spec.DependsOn))
for i := range in.Spec.DependsOn {
deps[i] = meta.NamespacedObjectReference{
Name: in.Spec.DependsOn[i].Name,
Namespace: in.Spec.DependsOn[i].Namespace,
}
}
return deps
}

// GetConditions returns the status conditions of the object.
Expand Down
20 changes: 20 additions & 0 deletions api/v2/reference_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,23 @@ type CrossNamespaceSourceReference struct {
// +optional
Namespace string `json:"namespace,omitempty"`
}

// DependencyReference defines a HelmRelease dependency on another HelmRelease resource.
type DependencyReference struct {
// Name of the referent.
// +required
Name string `json:"name"`

// Namespace of the referent, defaults to the namespace of the HelmRelease
// resource object that contains the reference.
// +optional
Namespace string `json:"namespace,omitempty"`

// ReadyExpr is a CEL expression that can be used to assess the readiness
// of a dependency. When specified, the built-in readiness check
// is replaced by the logic defined in the CEL expression.
// To make the CEL expression additive to the built-in readiness check,
// the feature gate `AdditiveCELDependencyCheck` must be set to `true`.
// +optional
ReadyExpr string `json:"readyExpr,omitempty"`
}
17 changes: 16 additions & 1 deletion api/v2/zz_generated.deepcopy.go

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

20 changes: 14 additions & 6 deletions config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,28 @@ spec:
type: object
dependsOn:
description: |-
DependsOn may contain a meta.NamespacedObjectReference slice with
DependsOn may contain a DependencyReference 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.
description: DependencyReference defines a HelmRelease dependency
on another HelmRelease resource.
properties:
name:
description: Name of the referent.
type: string
namespace:
description: Namespace of the referent, when not specified it
acts as LocalObjectReference.
description: |-
Namespace of the referent, defaults to the namespace of the HelmRelease
resource object that contains the reference.
type: string
readyExpr:
description: |-
ReadyExpr is a CEL expression that can be used to assess the readiness
of a dependency. When specified, the built-in readiness check
is replaced by the logic defined in the CEL expression.
To make the CEL expression additive to the built-in readiness check,
the feature gate `AdditiveCELDependencyCheck` must be set to `true`.
type: string
required:
- name
Expand Down
73 changes: 67 additions & 6 deletions docs/api/v2/helm.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ Defaults to the namespace of the HelmRelease.</p>
<td>
<code>dependsOn</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#NamespacedObjectReference">
[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference
<a href="#helm.toolkit.fluxcd.io/v2.DependencyReference">
[]DependencyReference
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>DependsOn may contain a meta.NamespacedObjectReference slice with
<p>DependsOn may contain a DependencyReference slice with
references to HelmRelease resources that must be ready before this HelmRelease
can be reconciled.</p>
</td>
Expand Down Expand Up @@ -615,6 +615,67 @@ resource object that contains the reference.</p>
</table>
</div>
</div>
<h3 id="helm.toolkit.fluxcd.io/v2.DependencyReference">DependencyReference
</h3>
<p>
(<em>Appears on:</em>
<a href="#helm.toolkit.fluxcd.io/v2.HelmReleaseSpec">HelmReleaseSpec</a>)
</p>
<p>DependencyReference defines a HelmRelease dependency on another HelmRelease resource.</p>
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table">
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>name</code><br>
<em>
string
</em>
</td>
<td>
<p>Name of the referent.</p>
</td>
</tr>
<tr>
<td>
<code>namespace</code><br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Namespace of the referent, defaults to the namespace of the HelmRelease
resource object that contains the reference.</p>
</td>
</tr>
<tr>
<td>
<code>readyExpr</code><br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>ReadyExpr is a CEL expression that can be used to assess the readiness
of a dependency. When specified, the built-in readiness check
is replaced by the logic defined in the CEL expression.
To make the CEL expression additive to the built-in readiness check,
the feature gate <code>AdditiveCELDependencyCheck</code> must be set to <code>true</code>.</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h3 id="helm.toolkit.fluxcd.io/v2.DriftDetection">DriftDetection
</h3>
<p>
Expand Down Expand Up @@ -1258,14 +1319,14 @@ Defaults to the namespace of the HelmRelease.</p>
<td>
<code>dependsOn</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#NamespacedObjectReference">
[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference
<a href="#helm.toolkit.fluxcd.io/v2.DependencyReference">
[]DependencyReference
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>DependsOn may contain a meta.NamespacedObjectReference slice with
<p>DependsOn may contain a DependencyReference slice with
references to HelmRelease resources that must be ready before this HelmRelease
can be reconciled.</p>
</td>
Expand Down
55 changes: 51 additions & 4 deletions docs/spec/v2/helmreleases.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,12 +396,59 @@ spec:
- name: backend
```

**Note:** This does not account for upgrade ordering. Kubernetes only allows
applying one resource (HelmRelease in this case) at a time, so there is no
way for the controller to know when a dependency HelmRelease may be updated.
Also, circular dependencies between HelmRelease resources must be avoided,
**Note:** Circular dependencies between HelmRelease resources must be avoided,
otherwise the interdependent HelmRelease resources will never be reconciled.

#### Dependency Ready Expression

`.spec.dependsOn[].readyExpr` is an optional field that can be used to define a CEL expression
to determine the readiness of a HelmRelease dependency.

This is helpful for when custom logic is needed to determine if a dependency is ready.
For example, when performing a lockstep upgrade, the `readyExpr` can be used to
verify that a dependency has a matching version in values before proceeding with the
reconciliation of the dependent HelmRelease.

```yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: backend
namespace: default
spec:
# ...omitted for brevity
values:
app:
version: v1.2.3
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: frontend
namespace: default
spec:
# ...omitted for brevity
values:
app:
version: v1.2.3
dependsOn:
- name: backend
readyExpr: >
dep.spec.values.app.version == self.spec.values.app.version &&
dep.status.conditions.filter(e, e.type == 'Ready').all(e, e.status == 'True') &&
dep.metadata.generation == dep.status.observedGeneration
```

The CEL expression contains the following variables:

- `dep`: The dependency HelmRelease object being evaluated.
- `self`: The HelmRelease object being reconciled.

**Note:** When `readyExpr` is specified, the built-in readiness check is replaced by the logic
defined in the CEL expression. You can configure the controller to run both the CEL expression
evaluation and the built-in readiness check, with the `AdditiveCELDependencyCheck`
[feature gate](https://fluxcd.io/flux/components/helm/options/#feature-gates).

### Values

The values for the Helm release can be specified in two ways:
Expand Down
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ require (
github.com/fluxcd/pkg/testserver v0.11.0
github.com/fluxcd/source-controller/api v1.6.0
github.com/go-logr/logr v1.4.3
github.com/google/cel-go v0.23.2
github.com/google/go-cmp v0.7.0
github.com/hashicorp/go-retryablehttp v0.7.8
github.com/mitchellh/copystructure v1.2.0
Expand All @@ -54,6 +55,7 @@ require (
)

require (
cel.dev/expr v0.23.0 // indirect
cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
Expand All @@ -70,6 +72,7 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect
Expand Down Expand Up @@ -172,6 +175,7 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
Expand All @@ -193,6 +197,7 @@ require (
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
Expand All @@ -201,6 +206,7 @@ require (
golang.org/x/time v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/api v0.241.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
Expand Down
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
Expand Down Expand Up @@ -42,6 +44,8 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
Expand Down Expand Up @@ -205,6 +209,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.23.2 h1:UdEe3CvQh3Nv+E/j9r1Y//WO0K0cSyD7/y0bzyLIMI4=
github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
Expand Down Expand Up @@ -378,13 +384,20 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
Expand Down Expand Up @@ -481,6 +494,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
Expand Down
Loading