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
6 changes: 5 additions & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ go 1.26.0
require (
github.com/fluxcd/pkg/apis/kustomize v1.21.0
github.com/fluxcd/pkg/apis/meta v1.32.0
github.com/fluxcd/source-controller/api v1.9.6
k8s.io/apiextensions-apiserver v0.37.0
k8s.io/apimachinery v0.37.0
sigs.k8s.io/yaml v1.6.0
)

require (
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
github.com/fluxcd/pkg/apis/acl v0.11.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -28,3 +30,5 @@ require (
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect
)

replace github.com/fluxcd/source-controller/api => github.com/fluxcd/source-controller/api v1.9.1-0.20261005091731-e47a59ad5d01
8 changes: 6 additions & 2 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fluxcd/pkg/apis/acl v0.11.0 h1:BxThatpA6qd5Qzwim6/hRu0gdAX0JxNm3PledDuJqXo=
github.com/fluxcd/pkg/apis/acl v0.11.0/go.mod h1:a87i2A7AlFO5N2J8CxtzaUCCDmuLLWOHwkKu3eJF5fY=
github.com/fluxcd/pkg/apis/kustomize v1.21.0 h1:dNR/mcuEdziBQKH2bG/B1X6MmASFv9ijXU7PdY8s2JU=
github.com/fluxcd/pkg/apis/kustomize v1.21.0/go.mod h1:cN3wx9ZwzYkjYJ2ugTA7yjiW19IirZxiEwZhu4SFxyc=
github.com/fluxcd/pkg/apis/meta v1.32.0 h1:jWuNuIziUM8NOrhZB7vovdFQ4wBYRNJoAn+XUoYlj1I=
github.com/fluxcd/pkg/apis/meta v1.32.0/go.mod h1:bZmU0RbSwFzsCg9sgjhbSWxgSbUy+3Oh/s7qUCZjwPk=
github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fluxcd/source-controller/api v1.9.1-0.20261005091731-e47a59ad5d01 h1:QKNUNGjIV94G0JvE++lXtSzoEzyRlsEHMAuvo6I/VaM=
github.com/fluxcd/source-controller/api v1.9.1-0.20261005091731-e47a59ad5d01/go.mod h1:EOuCFZQd2k3bBI+lte0x771y/QE9fR6JeGWxmxTuNNU=
github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
Expand Down
194 changes: 131 additions & 63 deletions api/v2/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)

const (
Expand All @@ -45,8 +46,9 @@ const (
// HelmReleaseSpec defines the desired state of a Helm release.
// +kubebuilder:validation:XValidation:rule="(has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef))", message="either chart or chartRef must be set"
type HelmReleaseSpec struct {
// Chart defines the template of the v1.HelmChart that should be created
// for this HelmRelease.
// Chart defines the template of the source object that should be
// created for this HelmRelease. The Kind field determines whether a
// sourcev1.HelmChart or sourcev1.OCIRepository is created.
// +optional
Chart *HelmChartTemplate `json:"chart,omitempty"`

Expand Down Expand Up @@ -208,6 +210,24 @@ type HelmReleaseSpec struct {
HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
}

func (in *HelmRelease) GetHelmChartReference() *HelmChartReference {
if in == nil || in.Spec.ChartRef == nil {
return nil
}
ref := &HelmChartReference{
Kind: in.Spec.ChartRef.Kind,
Name: in.Spec.ChartRef.Name,
Namespace: in.Spec.ChartRef.Namespace,
}
if ref.Kind == "" {
ref.Kind = sourcev1.HelmChartKind
}
if ref.Namespace == "" {
ref.Namespace = in.GetNamespace()
}
return ref
}

// +kubebuilder:object:generate=false

type ValuesReference = meta.ValuesReference
Expand Down Expand Up @@ -347,20 +367,45 @@ func (d DriftDetection) MustDetectChanges() bool {
}

// HelmChartTemplate defines the template from which the controller will
// generate a v1.HelmChart object in the same namespace as the referenced
// v1.Source.
// generate a sourcev1.HelmChart or sourcev1.OCIRepository object. The
// Kind field determines which object is generated.
//
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || (has(self.spec.url) && size(self.spec.url) > 0)", message="chart.spec.url must be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.spec.url) || (has(self.kind) && self.kind == 'OCIRepository')",message="chart.spec.url requires chart.kind: 'OCIRepository'; for a HelmChart template set spec.chart and spec.sourceRef instead"
// +kubebuilder:validation:XValidation:rule="(has(self.kind) && self.kind == 'OCIRepository') || (has(self.spec.chart) && has(self.spec.sourceRef))", message="chart.spec.chart and chart.spec.sourceRef must be set when chart.kind is not 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.chart)", message="chart.spec.chart cannot be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.version) || self.spec.version == '*'", message="chart.spec.version cannot be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.sourceRef)", message="chart.spec.sourceRef cannot be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.reconcileStrategy) || self.spec.reconcileStrategy == 'ChartVersion'", message="chart.spec.reconcileStrategy cannot be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.valuesFiles)", message="chart.spec.valuesFiles cannot be set when chart.kind is 'OCIRepository'"
// +kubebuilder:validation:XValidation:rule="!has(self.kind) || self.kind != 'OCIRepository' || !has(self.spec.ignoreMissingValuesFiles)", message="chart.spec.ignoreMissingValuesFiles cannot be set when chart.kind is 'OCIRepository'"
type HelmChartTemplate struct {
// Kind is the kind of the source object generated from this template. Valid values:
// - HelmChart (default): generates a source.toolkit.fluxcd.io/v1 HelmChart from
// the HelmChartSpec-compatible fields under .spec.chart.spec. In particular,
// .spec.chart.spec.chart and .spec.chart.spec.sourceRef are required.
// - OCIRepository: generates a source.toolkit.fluxcd.io/v1 OCIRepository from
// the OCIRepositorySpec fields under .spec.chart.spec. In particular,
// .spec.chart.spec.url is required, and .spec.chart.spec.interval defaults
// to .spec.interval (interval is required in a plain OCIRepository).
// Use OCIRepository for charts hosted in OCI registries; use HelmChart for
// HelmRepository, GitRepository or Bucket sources.
//
// +kubebuilder:validation:Enum=HelmChart;OCIRepository
// +optional
Kind string `json:"kind,omitempty"`

// ObjectMeta holds the template for metadata like labels and annotations.
// +optional
ObjectMeta *HelmChartTemplateObjectMeta `json:"metadata,omitempty"`

// Spec holds the template for the v1.HelmChartSpec for this HelmRelease.
// Spec holds the spec of the object generated for this HelmRelease.
// +required
Spec HelmChartTemplateSpec `json:"spec"`
}

// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a
// v1.HelmChart.
// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of the
// generated object.
type HelmChartTemplateObjectMeta struct {
// Map of string keys and values that can be used to organize and categorize
// (scope and select) objects.
Expand All @@ -377,37 +422,30 @@ type HelmChartTemplateObjectMeta struct {
}

// HelmChartTemplateSpec defines the template from which the controller will
// generate a v1.HelmChartSpec object.
// generate a sourcev1.HelmChartSpec or sourcev1.OCIRepositorySpec object.
type HelmChartTemplateSpec struct {
sourcev1.OCIRepositorySpec `json:",inline"`

// 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"`
// +optional
Chart string `json:"chart,omitempty"`

// Version semver expression, ignored for charts from v1.GitRepository and
// v1beta2.Bucket sources. Defaults to latest when omitted.
// +kubebuilder:default:=*
// v1beta2.Bucket sources. Defaults to latest when omitted i.e. to '*'.
// +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"`
SourceRef *CrossNamespaceObjectReference `json:"sourceRef,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"`

Expand All @@ -421,46 +459,33 @@ type HelmChartTemplateSpec struct {
// IgnoreMissingValuesFiles controls whether to silently ignore missing values files rather than failing.
// +optional
IgnoreMissingValuesFiles bool `json:"ignoreMissingValuesFiles,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 v1.HelmChart,
// or the given default.
func (in HelmChartTemplate) GetInterval(defaultInterval metav1.Duration) metav1.Duration {
if in.Spec.Interval == nil {
return defaultInterval
// GetTemplateInterval returns the configured interval for the generated
// object, or the HelmRelease interval if not set on the chart template.
func (in *HelmRelease) GetTemplateInterval() metav1.Duration {
if in.Spec.Chart == nil || in.Spec.Chart.Spec.Interval == nil {
return in.Spec.Interval
}
return *in.Spec.Interval
return *in.Spec.Chart.Spec.Interval
}

// GetNamespace returns the namespace targeted namespace for the
// v1.HelmChart, or the given default.
func (in HelmChartTemplate) GetNamespace(defaultNamespace string) string {
if in.Spec.SourceRef.Namespace == "" {
return defaultNamespace
// GetVersion returns the configured version for the generated object,
// or the default '*'.
func (in HelmChartTemplateSpec) GetVersion() string {
if in.Version == "" {
return "*"
}
return in.Spec.SourceRef.Namespace
return in.Version
}

// 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;notation
// +kubebuilder:default:=cosign
Provider string `json:"provider"`

// SecretRef specifies the Kubernetes Secret containing the
// trusted public keys.
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
// GetReconcileStrategy returns the configured reconcile strategy for the generated object,
// or the default 'ChartVersion'.
func (in HelmChartTemplateSpec) GetReconcileStrategy() string {
if in.ReconcileStrategy == "" {
return sourcev1.ReconcileStrategyChartVersion
}
return in.ReconcileStrategy
}

// WaitStrategyName is a strategy for waiting for resources to be ready.
Expand Down Expand Up @@ -1308,7 +1333,9 @@ type HelmReleaseStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty"`

// HelmChart is the namespaced name of the HelmChart resource created by
// the controller for the HelmRelease.
// the controller for the HelmRelease, in the format '<namespace>/<name>',
// or the typed and namespaced name of the OCIRepository resource, in the
// format '<kind>/<namespace>/<name>'.
// +optional
HelmChart string `json:"helmChart,omitempty"`

Expand Down Expand Up @@ -1408,15 +1435,42 @@ func (in *HelmReleaseStatus) ClearFailures() {
in.UpgradeFailures = 0
}

// GetHelmChart returns the namespace and name of the HelmChart.
func (in HelmReleaseStatus) GetHelmChart() (string, string) {
// HasChart returns true if the status has a HelmChart.
func (in *HelmReleaseStatus) HasChart() bool {
return in.HelmChart != ""
}

// SetChart sets the namespaced name of the chart created by the controller
// for the HelmRelease. A HelmChart is stored as '<namespace>/<name>' for
// backwards compatibility, while any other kind is stored as
// '<kind>/<namespace>/<name>'.
func (in *HelmReleaseStatus) SetChart(ref *HelmChartReference) {
in.HelmChart = strings.TrimPrefix(ref.String(), sourcev1.HelmChartKind+"/")
}

// GetHelmChartReference parses the typed and namespaced reference of the chart
// from the status. A '<namespace>/<name>' value is interpreted as a HelmChart
// for backwards compatibility.
func (in HelmReleaseStatus) GetHelmChartReference() *HelmChartReference {
if in.HelmChart == "" {
return "", ""
return nil
}
if split := strings.Split(in.HelmChart, string(types.Separator)); len(split) > 1 {
return split[0], split[1]
switch s := strings.Split(in.HelmChart, string(types.Separator)); len(s) {
case 2:
return &HelmChartReference{
Kind: sourcev1.HelmChartKind,
Namespace: s[0],
Name: s[1],
}
case 3:
return &HelmChartReference{
Kind: s[0],
Namespace: s[1],
Name: s[2],
}
default:
return nil
}
return "", ""
}

func (in *HelmReleaseStatus) GetLastAttemptedRevision() string {
Expand Down Expand Up @@ -1576,9 +1630,23 @@ func (in HelmRelease) GetStorageNamespace() string {
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}, "-")
// GetHelmChartTemplateReference returns the typed and namespaced reference of the HelmChartTemplate.
func (in *HelmRelease) GetHelmChartTemplateReference() *HelmChartReference {
if in == nil || in.Spec.Chart == nil {
return nil
}
ref := &HelmChartReference{
Kind: in.Spec.Chart.Kind,
Name: strings.Join([]string{in.Namespace, in.Name}, "-"),
Namespace: in.GetNamespace(),
}
if ref.Kind == "" {
ref.Kind = sourcev1.HelmChartKind
}
if ref.Kind == sourcev1.HelmChartKind && in.Spec.Chart.Spec.SourceRef != nil && in.Spec.Chart.Spec.SourceRef.Namespace != "" {
ref.Namespace = in.Spec.Chart.Spec.SourceRef.Namespace
}
return ref
}

// GetTimeout returns the configured Timeout, or the default of 300s.
Expand Down
Loading
Loading