From f85bc174e63c65938ffe8e1e7d16fa3372a02498 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Apr 2024 17:20:06 +0300 Subject: [PATCH 1/7] Promote Helm APIs to v1 (GA) Signed-off-by: Stefan Prodan --- PROJECT | 6 + api/v1/helmchart_types.go | 237 +++ api/v1/helmrepository_types.go | 228 +++ api/v1/ociverification_types.go | 56 + api/v1/zz_generated.deepcopy.go | 300 ++- api/v1beta1/zz_generated.deepcopy.go | 2 +- api/v1beta2/helmchart_types.go | 5 +- api/v1beta2/helmrepository_types.go | 2 +- api/v1beta2/ocirepository_types.go | 38 +- api/v1beta2/zz_generated.deepcopy.go | 46 +- .../source.toolkit.fluxcd.io_helmcharts.yaml | 397 +++- ...ce.toolkit.fluxcd.io_helmrepositories.yaml | 322 +++- .../testdata/helmchart-from-oci/notation.yaml | 4 +- docs/api/v1/source.md | 1602 +++++++++++++++-- docs/api/v1beta2/source.md | 129 +- hack/boilerplate.go.txt | 2 +- internal/controller/helmchart_controller.go | 100 +- .../controller/helmchart_controller_test.go | 470 ++--- .../controller/helmrepository_controller.go | 47 +- .../helmrepository_controller_test.go | 189 +- .../ocirepository_controller_test.go | 14 +- internal/helm/getter/client_opts.go | 9 +- internal/helm/getter/client_opts_test.go | 2 +- .../helmrepository_type_predicate.go | 2 +- .../helmrepository_type_predicate_test.go | 5 +- main.go | 22 +- 26 files changed, 3393 insertions(+), 843 deletions(-) create mode 100644 api/v1/helmchart_types.go create mode 100644 api/v1/helmrepository_types.go create mode 100644 api/v1/ociverification_types.go diff --git a/PROJECT b/PROJECT index 7e43c7b24..8af858a45 100644 --- a/PROJECT +++ b/PROJECT @@ -7,9 +7,15 @@ resources: - group: source kind: GitRepository version: v1beta2 +- group: source + kind: HelmRepository + version: v1 - group: source kind: HelmRepository version: v1beta2 +- group: source + kind: HelmChart + version: v1 - group: source kind: HelmChart version: v1beta2 diff --git a/api/v1/helmchart_types.go b/api/v1/helmchart_types.go new file mode 100644 index 000000000..c01700c29 --- /dev/null +++ b/api/v1/helmchart_types.go @@ -0,0 +1,237 @@ +/* +Copyright 2024 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 v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/acl" + "github.com/fluxcd/pkg/apis/meta" +) + +// HelmChartKind is the string representation of a HelmChart. +const HelmChartKind = "HelmChart" + +// HelmChartSpec specifies the desired state of a Helm chart. +type HelmChartSpec struct { + // Chart is the name or path the Helm chart is available at in the + // SourceRef. + // +required + Chart string `json:"chart"` + + // Version is the chart version semver expression, ignored for charts from + // GitRepository and Bucket sources. Defaults to latest when omitted. + // +kubebuilder:default:=* + // +optional + Version string `json:"version,omitempty"` + + // SourceRef is the reference to the Source the chart is available at. + // +required + SourceRef LocalHelmChartSourceReference `json:"sourceRef"` + + // Interval at which the HelmChart SourceRef is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +required + Interval metav1.Duration `json:"interval"` + + // ReconcileStrategy 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"` + + // ValuesFiles is an 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"` + + // ValuesFile is an 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 specified here + // is merged before the ValuesFiles items. Ignored when omitted. + // +optional + // +deprecated + ValuesFile string `json:"valuesFile,omitempty"` + + // Suspend tells the controller to suspend the reconciliation of this + // source. + // +optional + Suspend bool `json:"suspend,omitempty"` + + // AccessFrom specifies an Access Control List for allowing cross-namespace + // references to this object. + // NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + // +optional + AccessFrom *acl.AccessFrom `json:"accessFrom,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 when using HelmRepository source with spec.type 'oci'. + // Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + // +optional + Verify *OCIRepositoryVerification `json:"verify,omitempty"` +} + +const ( + // ReconcileStrategyChartVersion reconciles when the version of the Helm chart is different. + ReconcileStrategyChartVersion string = "ChartVersion" + + // ReconcileStrategyRevision reconciles when the Revision of the source is different. + ReconcileStrategyRevision string = "Revision" +) + +// LocalHelmChartSourceReference contains enough information to let you locate +// the typed referenced object at namespace level. +type LocalHelmChartSourceReference struct { + // APIVersion of the referent. + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + // 'Bucket'). + // +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket + // +required + Kind string `json:"kind"` + + // Name of the referent. + // +required + Name string `json:"name"` +} + +// HelmChartStatus records the observed state of the HelmChart. +type HelmChartStatus struct { + // ObservedGeneration is the last observed generation of the HelmChart + // object. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ObservedSourceArtifactRevision is the last observed Artifact.Revision + // of the HelmChartSpec.SourceRef. + // +optional + ObservedSourceArtifactRevision string `json:"observedSourceArtifactRevision,omitempty"` + + // ObservedChartName is the last observed chart name as specified by the + // resolved chart reference. + // +optional + ObservedChartName string `json:"observedChartName,omitempty"` + + // Conditions holds the conditions for the HelmChart. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // URL is the dynamic fetch link for the latest Artifact. + // It is provided on a "best effort" basis, and using the precise + // BucketStatus.Artifact data is recommended. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful reconciliation. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` + + meta.ReconcileRequestStatus `json:",inline"` +} + +const ( + // ChartPullSucceededReason signals that the pull of the Helm chart + // succeeded. + ChartPullSucceededReason string = "ChartPullSucceeded" + + // ChartPackageSucceededReason signals that the package of the Helm + // chart succeeded. + ChartPackageSucceededReason string = "ChartPackageSucceeded" +) + +// GetConditions returns the status conditions of the object. +func (in HelmChart) GetConditions() []metav1.Condition { + return in.Status.Conditions +} + +// SetConditions sets the status conditions on the object. +func (in *HelmChart) SetConditions(conditions []metav1.Condition) { + in.Status.Conditions = conditions +} + +// GetRequeueAfter returns the duration after which the source must be +// reconciled again. +func (in HelmChart) GetRequeueAfter() time.Duration { + return in.Spec.Interval.Duration +} + +// GetArtifact returns the latest artifact from the source if present in the +// status sub-resource. +func (in *HelmChart) GetArtifact() *Artifact { + return in.Status.Artifact +} + +// GetValuesFiles returns a merged list of HelmChartSpec.ValuesFiles. +func (in *HelmChart) GetValuesFiles() []string { + valuesFiles := in.Spec.ValuesFiles + + // Prepend the deprecated ValuesFile to the list + if in.Spec.ValuesFile != "" { + valuesFiles = append([]string{in.Spec.ValuesFile}, valuesFiles...) + } + return valuesFiles +} + +// +genclient +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:resource:shortName=hc +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Chart",type=string,JSONPath=`.spec.chart` +// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.version` +// +kubebuilder:printcolumn:name="Source Kind",type=string,JSONPath=`.spec.sourceRef.kind` +// +kubebuilder:printcolumn:name="Source Name",type=string,JSONPath=`.spec.sourceRef.name` +// +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="" + +// HelmChart is the Schema for the helmcharts API. +type HelmChart struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmChartSpec `json:"spec,omitempty"` + // +kubebuilder:default={"observedGeneration":-1} + Status HelmChartStatus `json:"status,omitempty"` +} + +// HelmChartList contains a list of HelmChart objects. +// +kubebuilder:object:root=true +type HelmChartList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmChart `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmChart{}, &HelmChartList{}) +} diff --git a/api/v1/helmrepository_types.go b/api/v1/helmrepository_types.go new file mode 100644 index 000000000..2a21f2c52 --- /dev/null +++ b/api/v1/helmrepository_types.go @@ -0,0 +1,228 @@ +/* +Copyright 2024 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 v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/acl" + "github.com/fluxcd/pkg/apis/meta" +) + +const ( + // HelmRepositoryKind is the string representation of a HelmRepository. + HelmRepositoryKind = "HelmRepository" + // HelmRepositoryURLIndexKey is the key used for indexing HelmRepository + // objects by their HelmRepositorySpec.URL. + HelmRepositoryURLIndexKey = ".metadata.helmRepositoryURL" + // HelmRepositoryTypeDefault is the default HelmRepository type. + // It is used when no type is specified and corresponds to a Helm repository. + HelmRepositoryTypeDefault = "default" + // HelmRepositoryTypeOCI is the type for an OCI repository. + HelmRepositoryTypeOCI = "oci" +) + +// HelmRepositorySpec specifies the required configuration to produce an +// Artifact for a Helm repository index YAML. +type HelmRepositorySpec struct { + // URL of the Helm repository, a valid URL contains at least a protocol and + // host. + // +kubebuilder:validation:Pattern="^(http|https|oci)://.*$" + // +required + URL string `json:"url"` + + // SecretRef specifies the Secret containing authentication credentials + // for the HelmRepository. + // For HTTP/S basic auth the secret must contain 'username' and 'password' + // fields. + // Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + // keys is deprecated. Please use `.spec.certSecretRef` instead. + // +optional + SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` + + // CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // It takes precedence over the values specified in the Secret referred + // to by `.spec.secretRef`. + // +optional + CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"` + + // PassCredentials allows the credentials from the SecretRef to be passed + // on to a host that does not match the host as defined in URL. + // This may be required if the host of the advertised chart URLs in the + // index differ from the defined URL. + // Enabling this should be done with caution, as it can potentially result + // in credentials getting stolen in a MITM-attack. + // +optional + PassCredentials bool `json:"passCredentials,omitempty"` + + // Interval at which the HelmRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Interval metav1.Duration `json:"interval,omitempty"` + + // Insecure allows connecting to a non-TLS HTTP container registry. + // This field is only taken into account if the .spec.type field is set to 'oci'. + // +optional + Insecure bool `json:"insecure,omitempty"` + + // Timeout is used for the index fetch operation for an HTTPS helm repository, + // and for remote OCI Repository operations like pulling for an OCI helm + // chart by the associated HelmChart. + // Its default value is 60s. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Suspend tells the controller to suspend the reconciliation of this + // HelmRepository. + // +optional + Suspend bool `json:"suspend,omitempty"` + + // AccessFrom specifies an Access Control List for allowing cross-namespace + // references to this object. + // NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + // +optional + AccessFrom *acl.AccessFrom `json:"accessFrom,omitempty"` + + // Type of the HelmRepository. + // When this field is set to "oci", the URL field value must be prefixed with "oci://". + // +kubebuilder:validation:Enum=default;oci + // +optional + Type string `json:"type,omitempty"` + + // Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + // When not specified, defaults to 'generic'. + // +kubebuilder:validation:Enum=generic;aws;azure;gcp + // +kubebuilder:default:=generic + // +optional + Provider string `json:"provider,omitempty"` +} + +// HelmRepositoryStatus records the observed state of the HelmRepository. +type HelmRepositoryStatus struct { + // ObservedGeneration is the last observed generation of the HelmRepository + // object. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions holds the conditions for the HelmRepository. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // URL is the dynamic fetch link for the latest Artifact. + // It is provided on a "best effort" basis, and using the precise + // HelmRepositoryStatus.Artifact data is recommended. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the last successful HelmRepository reconciliation. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` + + meta.ReconcileRequestStatus `json:",inline"` +} + +const ( + // IndexationFailedReason signals that the HelmRepository index fetch + // failed. + IndexationFailedReason string = "IndexationFailed" +) + +// GetConditions returns the status conditions of the object. +func (in HelmRepository) GetConditions() []metav1.Condition { + return in.Status.Conditions +} + +// SetConditions sets the status conditions on the object. +func (in *HelmRepository) SetConditions(conditions []metav1.Condition) { + in.Status.Conditions = conditions +} + +// GetRequeueAfter returns the duration after which the source must be +// reconciled again. +func (in HelmRepository) GetRequeueAfter() time.Duration { + if in.Spec.Interval.Duration != 0 { + return in.Spec.Interval.Duration + } + return time.Minute +} + +// GetTimeout returns the timeout duration used for various operations related +// to this HelmRepository. +func (in HelmRepository) GetTimeout() time.Duration { + if in.Spec.Timeout != nil { + return in.Spec.Timeout.Duration + } + return time.Minute +} + +// GetArtifact returns the latest artifact from the source if present in the +// status sub-resource. +func (in *HelmRepository) GetArtifact() *Artifact { + return in.Status.Artifact +} + +// +genclient +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:resource:shortName=helmrepo +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url` +// +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="" + +// HelmRepository is the Schema for the helmrepositories API. +type HelmRepository struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmRepositorySpec `json:"spec,omitempty"` + // +kubebuilder:default={"observedGeneration":-1} + Status HelmRepositoryStatus `json:"status,omitempty"` +} + +// HelmRepositoryList contains a list of HelmRepository objects. +// +kubebuilder:object:root=true +type HelmRepositoryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmRepository `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmRepository{}, &HelmRepositoryList{}) +} diff --git a/api/v1/ociverification_types.go b/api/v1/ociverification_types.go new file mode 100644 index 000000000..de74be343 --- /dev/null +++ b/api/v1/ociverification_types.go @@ -0,0 +1,56 @@ +/* +Copyright 2024 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 v1 + +import ( + "github.com/fluxcd/pkg/apis/meta" +) + +// OCIRepositoryVerification verifies the authenticity of an OCI Artifact +type OCIRepositoryVerification struct { + // Provider specifies the technology used to sign the OCI Artifact. + // +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"` + + // MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + // +optional + MatchOIDCIdentity []OIDCIdentityMatch `json:"matchOIDCIdentity,omitempty"` +} + +// OIDCIdentityMatch specifies options for verifying the certificate identity, +// i.e. the issuer and the subject of the certificate. +type OIDCIdentityMatch struct { + // Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + // +required + Issuer string `json:"issuer"` + // Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + // +required + Subject string `json:"subject"` +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 8df302930..6ef308061 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2023 The Flux authors +Copyright 2024 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. @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + "github.com/fluxcd/pkg/apis/acl" "github.com/fluxcd/pkg/apis/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -264,3 +265,300 @@ func (in *GitRepositoryVerification) DeepCopy() *GitRepositoryVerification { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChart) DeepCopyInto(out *HelmChart) { + *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 HelmChart. +func (in *HelmChart) DeepCopy() *HelmChart { + if in == nil { + return nil + } + out := new(HelmChart) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmChart) 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 *HelmChartList) DeepCopyInto(out *HelmChartList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmChart, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartList. +func (in *HelmChartList) DeepCopy() *HelmChartList { + if in == nil { + return nil + } + out := new(HelmChartList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmChartList) 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 *HelmChartSpec) DeepCopyInto(out *HelmChartSpec) { + *out = *in + out.SourceRef = in.SourceRef + out.Interval = in.Interval + if in.ValuesFiles != nil { + in, out := &in.ValuesFiles, &out.ValuesFiles + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AccessFrom != nil { + in, out := &in.AccessFrom, &out.AccessFrom + *out = new(acl.AccessFrom) + (*in).DeepCopyInto(*out) + } + if in.Verify != nil { + in, out := &in.Verify, &out.Verify + *out = new(OCIRepositoryVerification) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartSpec. +func (in *HelmChartSpec) DeepCopy() *HelmChartSpec { + if in == nil { + return nil + } + out := new(HelmChartSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmChartStatus) DeepCopyInto(out *HelmChartStatus) { + *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.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(Artifact) + (*in).DeepCopyInto(*out) + } + out.ReconcileRequestStatus = in.ReconcileRequestStatus +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartStatus. +func (in *HelmChartStatus) DeepCopy() *HelmChartStatus { + if in == nil { + return nil + } + out := new(HelmChartStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepository) DeepCopyInto(out *HelmRepository) { + *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 HelmRepository. +func (in *HelmRepository) DeepCopy() *HelmRepository { + if in == nil { + return nil + } + out := new(HelmRepository) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRepository) 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 *HelmRepositoryList) DeepCopyInto(out *HelmRepositoryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmRepository, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepositoryList. +func (in *HelmRepositoryList) DeepCopy() *HelmRepositoryList { + if in == nil { + return nil + } + out := new(HelmRepositoryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRepositoryList) 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 *HelmRepositorySpec) DeepCopyInto(out *HelmRepositorySpec) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + if in.CertSecretRef != nil { + in, out := &in.CertSecretRef, &out.CertSecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + out.Interval = in.Interval + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.AccessFrom != nil { + in, out := &in.AccessFrom, &out.AccessFrom + *out = new(acl.AccessFrom) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepositorySpec. +func (in *HelmRepositorySpec) DeepCopy() *HelmRepositorySpec { + if in == nil { + return nil + } + out := new(HelmRepositorySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepositoryStatus) DeepCopyInto(out *HelmRepositoryStatus) { + *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.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(Artifact) + (*in).DeepCopyInto(*out) + } + out.ReconcileRequestStatus = in.ReconcileRequestStatus +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepositoryStatus. +func (in *HelmRepositoryStatus) DeepCopy() *HelmRepositoryStatus { + if in == nil { + return nil + } + out := new(HelmRepositoryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalHelmChartSourceReference) DeepCopyInto(out *LocalHelmChartSourceReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalHelmChartSourceReference. +func (in *LocalHelmChartSourceReference) DeepCopy() *LocalHelmChartSourceReference { + if in == nil { + return nil + } + out := new(LocalHelmChartSourceReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepositoryVerification) DeepCopyInto(out *OCIRepositoryVerification) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + if in.MatchOIDCIdentity != nil { + in, out := &in.MatchOIDCIdentity, &out.MatchOIDCIdentity + *out = make([]OIDCIdentityMatch, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryVerification. +func (in *OCIRepositoryVerification) DeepCopy() *OCIRepositoryVerification { + if in == nil { + return nil + } + out := new(OCIRepositoryVerification) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OIDCIdentityMatch) DeepCopyInto(out *OIDCIdentityMatch) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCIdentityMatch. +func (in *OIDCIdentityMatch) DeepCopy() *OIDCIdentityMatch { + if in == nil { + return nil + } + out := new(OIDCIdentityMatch) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index d0481535a..a600106ea 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2023 The Flux authors +Copyright 2024 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/api/v1beta2/helmchart_types.go b/api/v1beta2/helmchart_types.go index 417a5a506..6bc7875a8 100644 --- a/api/v1beta2/helmchart_types.go +++ b/api/v1beta2/helmchart_types.go @@ -23,6 +23,7 @@ import ( "github.com/fluxcd/pkg/apis/acl" "github.com/fluxcd/pkg/apis/meta" + apiv1 "github.com/fluxcd/source-controller/api/v1" ) @@ -101,7 +102,7 @@ type HelmChartSpec struct { // This field is only supported when using HelmRepository source with spec.type 'oci'. // Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. // +optional - Verify *OCIRepositoryVerification `json:"verify,omitempty"` + Verify *apiv1.OCIRepositoryVerification `json:"verify,omitempty"` } const ( @@ -214,10 +215,10 @@ func (in *HelmChart) GetValuesFiles() []string { } // +genclient -// +kubebuilder:storageversion // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=hc // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta2 HelmChart is deprecated, upgrade to v1" // +kubebuilder:printcolumn:name="Chart",type=string,JSONPath=`.spec.chart` // +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.version` // +kubebuilder:printcolumn:name="Source Kind",type=string,JSONPath=`.spec.sourceRef.kind` diff --git a/api/v1beta2/helmrepository_types.go b/api/v1beta2/helmrepository_types.go index db965a727..0a618b88b 100644 --- a/api/v1beta2/helmrepository_types.go +++ b/api/v1beta2/helmrepository_types.go @@ -198,10 +198,10 @@ func (in *HelmRepository) GetArtifact() *apiv1.Artifact { } // +genclient -// +kubebuilder:storageversion // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=helmrepo // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta2 HelmRepository is deprecated, upgrade to v1" // +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url` // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" diff --git a/api/v1beta2/ocirepository_types.go b/api/v1beta2/ocirepository_types.go index 5c4df35ce..1e8338393 100644 --- a/api/v1beta2/ocirepository_types.go +++ b/api/v1beta2/ocirepository_types.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/fluxcd/pkg/apis/meta" + apiv1 "github.com/fluxcd/source-controller/api/v1" ) @@ -89,7 +90,7 @@ type OCIRepositorySpec struct { // used to verify the signature and specifies which provider to use to check // whether OCI image is authentic. // +optional - Verify *OCIRepositoryVerification `json:"verify,omitempty"` + Verify *apiv1.OCIRepositoryVerification `json:"verify,omitempty"` // ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate // the image pull if the service account has attached pull secrets. For more information: @@ -183,41 +184,6 @@ type OCILayerSelector struct { Operation string `json:"operation,omitempty"` } -// OCIRepositoryVerification verifies the authenticity of an OCI Artifact -type OCIRepositoryVerification struct { - // Provider specifies the technology used to sign the OCI Artifact. - // +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"` - - // MatchOIDCIdentity specifies the identity matching criteria to use - // while verifying an OCI artifact which was signed using Cosign keyless - // signing. The artifact's identity is deemed to be verified if any of the - // specified matchers match against the identity. - // +optional - MatchOIDCIdentity []OIDCIdentityMatch `json:"matchOIDCIdentity,omitempty"` -} - -// OIDCIdentityMatch specifies options for verifying the certificate identity, -// i.e. the issuer and the subject of the certificate. -type OIDCIdentityMatch struct { - // Issuer specifies the regex pattern to match against to verify - // the OIDC issuer in the Fulcio certificate. The pattern must be a - // valid Go regular expression. - // +required - Issuer string `json:"issuer"` - // Subject specifies the regex pattern to match against to verify - // the identity subject in the Fulcio certificate. The pattern must - // be a valid Go regular expression. - // +required - Subject string `json:"subject"` -} - // OCIRepositoryStatus defines the observed state of OCIRepository type OCIRepositoryStatus struct { // ObservedGeneration is the last observed generation. diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index aafc2fd1b..12cda6cb0 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2023 The Flux authors +Copyright 2024 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. @@ -466,7 +466,7 @@ func (in *HelmChartSpec) DeepCopyInto(out *HelmChartSpec) { } if in.Verify != nil { in, out := &in.Verify, &out.Verify - *out = new(OCIRepositoryVerification) + *out = new(apiv1.OCIRepositoryVerification) (*in).DeepCopyInto(*out) } } @@ -761,7 +761,7 @@ func (in *OCIRepositorySpec) DeepCopyInto(out *OCIRepositorySpec) { } if in.Verify != nil { in, out := &in.Verify, &out.Verify - *out = new(OCIRepositoryVerification) + *out = new(apiv1.OCIRepositoryVerification) (*in).DeepCopyInto(*out) } if in.CertSecretRef != nil { @@ -829,43 +829,3 @@ func (in *OCIRepositoryStatus) DeepCopy() *OCIRepositoryStatus { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OCIRepositoryVerification) DeepCopyInto(out *OCIRepositoryVerification) { - *out = *in - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(meta.LocalObjectReference) - **out = **in - } - if in.MatchOIDCIdentity != nil { - in, out := &in.MatchOIDCIdentity, &out.MatchOIDCIdentity - *out = make([]OIDCIdentityMatch, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryVerification. -func (in *OCIRepositoryVerification) DeepCopy() *OCIRepositoryVerification { - if in == nil { - return nil - } - out := new(OCIRepositoryVerification) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCIdentityMatch) DeepCopyInto(out *OIDCIdentityMatch) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCIdentityMatch. -func (in *OIDCIdentityMatch) DeepCopy() *OIDCIdentityMatch { - if in == nil { - return nil - } - out := new(OIDCIdentityMatch) - in.DeepCopyInto(out) - return out -} diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 0a0a9a2a6..7f69d4347 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -16,6 +16,386 @@ spec: singular: helmchart scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .spec.chart + name: Chart + type: string + - jsonPath: .spec.version + name: Version + type: string + - jsonPath: .spec.sourceRef.kind + name: Source Kind + type: string + - jsonPath: .spec.sourceRef.name + name: Source Name + type: string + - 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: v1 + schema: + openAPIV3Schema: + description: HelmChart is the Schema for the helmcharts 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: HelmChartSpec specifies the desired state of a Helm chart. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + chart: + description: |- + Chart is the name or path the Helm chart is available at in the + SourceRef. + type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean + interval: + description: |- + Interval at which the HelmChart SourceRef is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + ReconcileStrategy 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: SourceRef is the reference to the Source the chart is + available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: |- + Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + 'Bucket'). + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + source. + type: boolean + valuesFile: + description: |- + ValuesFile is an 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 specified here + is merged before the ValuesFiles items. Ignored when omitted. + type: string + valuesFiles: + description: |- + ValuesFiles is an 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 when using HelmRepository source with spec.type 'oci'. + Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the + OCI Artifact. + enum: + - cosign + - notation + 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 is the chart version semver expression, ignored for charts from + GitRepository and Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: HelmChartStatus records the observed state of the HelmChart. + properties: + artifact: + description: Artifact represents the output of the last successful + reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmChart. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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 + 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 + observedChartName: + description: |- + ObservedChartName is the last observed chart name as specified by the + resolved chart reference. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmChart + object. + format: int64 + type: integer + observedSourceArtifactRevision: + description: |- + ObservedSourceArtifactRevision is the last observed Artifact.Revision + of the HelmChartSpec.SourceRef. + type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .spec.chart name: Chart @@ -305,6 +685,8 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].message name: Status type: string + deprecated: true + deprecationWarning: v1beta2 HelmChart is deprecated, upgrade to v1 name: v1beta2 schema: openAPIV3Schema: @@ -363,11 +745,6 @@ spec: Chart is the name or path the Helm chart is available at in the SourceRef. type: string - ignoreMissingValuesFiles: - description: |- - IgnoreMissingValuesFiles controls whether to silently ignore missing values - files rather than failing. - type: boolean interval: description: |- Interval at which the HelmChart SourceRef is checked for updates. @@ -643,14 +1020,6 @@ spec: ObservedSourceArtifactRevision is the last observed Artifact.Revision of the HelmChartSpec.SourceRef. type: string - observedValuesFiles: - description: |- - ObservedValuesFiles are the observed value files of the last successful - reconciliation. - It matches the chart in the last successfully reconciled artifact. - items: - type: string - type: array url: description: |- URL is the dynamic fetch link for the latest Artifact. @@ -660,6 +1029,6 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml index 2e9252ad0..dc081faa2 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml @@ -16,6 +16,324 @@ spec: singular: helmrepository scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - 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: v1 + schema: + openAPIV3Schema: + description: HelmRepository is the Schema for the helmrepositories 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: |- + HelmRepositorySpec specifies the required configuration to produce an + Artifact for a Helm repository index YAML. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + + It takes precedence over the values specified in the Secret referred + to by `.spec.secretRef`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + insecure: + description: |- + Insecure allows connecting to a non-TLS HTTP container registry. + This field is only taken into account if the .spec.type field is set to 'oci'. + type: boolean + interval: + description: |- + Interval at which the HelmRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + passCredentials: + description: |- + PassCredentials allows the credentials from the SecretRef to be passed + on to a host that does not match the host as defined in URL. + This may be required if the host of the advertised chart URLs in the + index differ from the defined URL. + Enabling this should be done with caution, as it can potentially result + in credentials getting stolen in a MITM-attack. + type: boolean + provider: + default: generic + description: |- + Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the HelmRepository. + For HTTP/S basic auth the secret must contain 'username' and 'password' + fields. + Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + keys is deprecated. Please use `.spec.certSecretRef` instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + HelmRepository. + type: boolean + timeout: + description: |- + Timeout is used for the index fetch operation for an HTTPS helm repository, + and for remote OCI Repository operations like pulling for an OCI helm + chart by the associated HelmChart. + Its default value is 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: |- + Type of the HelmRepository. + When this field is set to "oci", the URL field value must be prefixed with "oci://". + enum: + - default + - oci + type: string + url: + description: |- + URL of the Helm repository, a valid URL contains at least a protocol and + host. + pattern: ^(http|https|oci)://.*$ + type: string + required: + - url + type: object + status: + default: + observedGeneration: -1 + description: HelmRepositoryStatus records the observed state of the HelmRepository. + properties: + artifact: + description: Artifact represents the last successful HelmRepository + reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmRepository. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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 + 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 + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmRepository + object. + format: int64 + type: integer + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + HelmRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .spec.url name: URL @@ -259,6 +577,8 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].message name: Status type: string + deprecated: true + deprecationWarning: v1beta2 HelmRepository is deprecated, upgrade to v1 name: v1beta2 schema: openAPIV3Schema: @@ -561,6 +881,6 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/config/testdata/helmchart-from-oci/notation.yaml b/config/testdata/helmchart-from-oci/notation.yaml index 713af91c9..6434479ea 100644 --- a/config/testdata/helmchart-from-oci/notation.yaml +++ b/config/testdata/helmchart-from-oci/notation.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: podinfo-notation @@ -8,7 +8,7 @@ spec: type: "oci" interval: 1m --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: podinfo-notation diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index ff34c7e60..547572b5e 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -10,6 +10,10 @@ Resource Types:

GitRepository

@@ -246,124 +250,1077 @@ GitRepositoryStatus +

HelmChart +

+

HelmChart is the Schema for the helmcharts API.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+string
+source.toolkit.fluxcd.io/v1 +
+kind
+string +
+HelmChart +
+metadata
+ + +Kubernetes meta/v1.ObjectMeta + + +
+Refer to the Kubernetes API documentation for the fields of the +metadata field. +
+spec
+ + +HelmChartSpec + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+chart
+ +string + +
+

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

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

Version is the chart version semver expression, ignored for charts from +GitRepository and Bucket sources. Defaults to latest when omitted.

+
+sourceRef
+ + +LocalHelmChartSourceReference + + +
+

SourceRef is the reference to the Source the chart is available at.

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

Interval at which the HelmChart SourceRef is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

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

ReconcileStrategy 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) +

ValuesFiles is an 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) +

ValuesFile is an 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 specified here +is merged before the ValuesFiles items. Ignored when omitted.

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

Suspend tells the controller to suspend the reconciliation of this +source.

+
+accessFrom
+ + +github.com/fluxcd/pkg/apis/acl.AccessFrom + + +
+(Optional) +

AccessFrom specifies an Access Control List for allowing cross-namespace +references to this object. +NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

+
+verify
+ + +OCIRepositoryVerification + + +
+(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 when using HelmRepository source with spec.type ‘oci’. +Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified.

+
+
+status
+ + +HelmChartStatus + + +
+
+
+
+

HelmRepository +

+

HelmRepository is the Schema for the helmrepositories API.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+string
+source.toolkit.fluxcd.io/v1 +
+kind
+string +
+HelmRepository +
+metadata
+ + +Kubernetes meta/v1.ObjectMeta + + +
+Refer to the Kubernetes API documentation for the fields of the +metadata field. +
+spec
+ + +HelmRepositorySpec + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+url
+ +string + +
+

URL of the Helm repository, a valid URL contains at least a protocol and +host.

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

SecretRef specifies the Secret containing authentication credentials +for the HelmRepository. +For HTTP/S basic auth the secret must contain ‘username’ and ‘password’ +fields. +Support for TLS auth using the ‘certFile’ and ‘keyFile’, and/or ‘caFile’ +keys is deprecated. Please use .spec.certSecretRef instead.

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

CertSecretRef can be given the name of a Secret containing +either or both of

+
    +
  • a PEM-encoded client certificate (tls.crt) and private +key (tls.key);
  • +
  • a PEM-encoded CA certificate (ca.crt)
  • +
+

and whichever are supplied, will be used for connecting to the +registry. The client cert and key are useful if you are +authenticating with a certificate; the CA cert is useful if +you are using a self-signed server certificate. The Secret must +be of type Opaque or kubernetes.io/tls.

+

It takes precedence over the values specified in the Secret referred +to by .spec.secretRef.

+
+passCredentials
+ +bool + +
+(Optional) +

PassCredentials allows the credentials from the SecretRef to be passed +on to a host that does not match the host as defined in URL. +This may be required if the host of the advertised chart URLs in the +index differ from the defined URL. +Enabling this should be done with caution, as it can potentially result +in credentials getting stolen in a MITM-attack.

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

Interval at which the HelmRepository URL is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

+
+insecure
+ +bool + +
+(Optional) +

Insecure allows connecting to a non-TLS HTTP container registry. +This field is only taken into account if the .spec.type field is set to ‘oci’.

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

Timeout is used for the index fetch operation for an HTTPS helm repository, +and for remote OCI Repository operations like pulling for an OCI helm +chart by the associated HelmChart. +Its default value is 60s.

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

Suspend tells the controller to suspend the reconciliation of this +HelmRepository.

+
+accessFrom
+ + +github.com/fluxcd/pkg/apis/acl.AccessFrom + + +
+(Optional) +

AccessFrom specifies an Access Control List for allowing cross-namespace +references to this object. +NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

+
+type
+ +string + +
+(Optional) +

Type of the HelmRepository. +When this field is set to “oci”, the URL field value must be prefixed with “oci://”.

+
+provider
+ +string + +
+(Optional) +

Provider used for authentication, can be ‘aws’, ‘azure’, ‘gcp’ or ‘generic’. +This field is optional, and only taken into account if the .spec.type field is set to ‘oci’. +When not specified, defaults to ‘generic’.

+
+
+status
+ + +HelmRepositoryStatus + + +
+
+
+

Artifact

(Appears on: -GitRepositoryStatus) +GitRepositoryStatus, +HelmChartStatus, +HelmRepositoryStatus) +

+

Artifact represents the output of a Source reconciliation.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+path
+ +string + +
+

Path is the relative file path of the Artifact. It can be used to locate +the file in the root of the Artifact storage on the local file system of +the controller managing the Source.

+
+url
+ +string + +
+

URL is the HTTP address of the Artifact as exposed by the controller +managing the Source. It can be used to retrieve the Artifact for +consumption, e.g. by another controller applying the Artifact contents.

+
+revision
+ +string + +
+

Revision is a human-readable identifier traceable in the origin source +system. It can be a Git commit SHA, Git tag, a Helm chart version, etc.

+
+digest
+ +string + +
+(Optional) +

Digest is the digest of the file in the form of ‘:’.

+
+lastUpdateTime
+ + +Kubernetes meta/v1.Time + + +
+

LastUpdateTime is the timestamp corresponding to the last update of the +Artifact.

+
+size
+ +int64 + +
+(Optional) +

Size is the number of bytes in the file.

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

Metadata holds upstream information such as OCI annotations.

+
+
+
+

GitRepositoryInclude +

+

+(Appears on: +GitRepositorySpec, +GitRepositoryStatus) +

+

GitRepositoryInclude specifies a local reference to a GitRepository which +Artifact (sub-)contents must be included, and where they should be placed.

+
+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+repository
+ + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
+

GitRepositoryRef specifies the GitRepository which Artifact contents +must be included.

+
+fromPath
+ +string + +
+(Optional) +

FromPath specifies the path to copy contents from, defaults to the root +of the Artifact.

+
+toPath
+ +string + +
+(Optional) +

ToPath specifies the path to copy contents to, defaults to the name of +the GitRepositoryRef.

+
+
+
+

GitRepositoryRef +

+

+(Appears on: +GitRepositorySpec) +

+

GitRepositoryRef specifies the Git reference to resolve and checkout.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+branch
+ +string + +
+(Optional) +

Branch to check out, defaults to ‘master’ if no other field is defined.

+
+tag
+ +string + +
+(Optional) +

Tag to check out, takes precedence over Branch.

+
+semver
+ +string + +
+(Optional) +

SemVer tag expression to check out, takes precedence over Tag.

+
+name
+ +string + +
+(Optional) +

Name of the reference to check out; takes precedence over Branch, Tag and SemVer.

+

It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description +Examples: “refs/heads/main”, “refs/tags/v0.1.0”, “refs/pull/420/head”, “refs/merge-requests/1/head”

+
+commit
+ +string + +
+(Optional) +

Commit SHA to check out, takes precedence over all reference fields.

+

This can be combined with Branch to shallow clone the branch, in which +the commit is expected to exist.

+
+
+
+

GitRepositorySpec +

+

+(Appears on: +GitRepository)

-

Artifact represents the output of a Source reconciliation.

+

GitRepositorySpec specifies the required configuration to produce an +Artifact for a Git repository.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+url
+ +string + +
+

URL specifies the Git repository URL, it can be an HTTP/S or SSH address.

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

SecretRef specifies the Secret containing authentication credentials for +the GitRepository. +For HTTPS repositories the Secret must contain ‘username’ and ‘password’ +fields for basic auth or ‘bearerToken’ field for token auth. +For SSH repositories the Secret must contain ‘identity’ +and ‘known_hosts’ fields.

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

Interval at which the GitRepository URL is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

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

Timeout for Git operations like cloning, defaults to 60s.

+
+ref
+ + +GitRepositoryRef + + +
+(Optional) +

Reference specifies the Git reference to resolve and monitor for +changes, defaults to the ‘master’ branch.

+
+verify
+ + +GitRepositoryVerification + + +
+(Optional) +

Verification specifies the configuration to verify the Git commit +signature(s).

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

ProxySecretRef specifies the Secret containing the proxy configuration +to use while communicating with the Git server.

+
+ignore
+ +string + +
+(Optional) +

Ignore overrides the set of excluded patterns in the .sourceignore format +(which is the same as .gitignore). If not provided, a default will be used, +consult the documentation for your version to find out what those are.

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

Suspend tells the controller to suspend the reconciliation of this +GitRepository.

+
+recurseSubmodules
+ +bool + +
+(Optional) +

RecurseSubmodules enables the initialization of all submodules within +the GitRepository as cloned from the URL, using their default settings.

+
+include
+ + +[]GitRepositoryInclude + + +
+(Optional) +

Include specifies a list of GitRepository resources which Artifacts +should be included in the Artifact produced for this GitRepository.

+
+
+
+

GitRepositoryStatus +

+

+(Appears on: +GitRepository) +

+

GitRepositoryStatus records the observed state of a Git repository.

- - + + + + + + + + + + + + - -
FieldDescriptionFieldDescription
+observedGeneration
+ +int64 + +
+(Optional) +

ObservedGeneration is the last observed generation of the GitRepository +object.

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

Conditions holds the conditions for the GitRepository.

+
-path
+artifact
-string + +Artifact +
-

Path is the relative file path of the Artifact. It can be used to locate -the file in the root of the Artifact storage on the local file system of -the controller managing the Source.

+(Optional) +

Artifact represents the last successful GitRepository reconciliation.

-url
+includedArtifacts
-string + +[]Artifact +
-

URL is the HTTP address of the Artifact as exposed by the controller -managing the Source. It can be used to retrieve the Artifact for -consumption, e.g. by another controller applying the Artifact contents.

+(Optional) +

IncludedArtifacts contains a list of the last successfully included +Artifacts as instructed by GitRepositorySpec.Include.

-revision
+observedIgnore
string
-

Revision is a human-readable identifier traceable in the origin source -system. It can be a Git commit SHA, Git tag, a Helm chart version, etc.

+(Optional) +

ObservedIgnore is the observed exclusion patterns used for constructing +the source artifact.

-digest
+observedRecurseSubmodules
-string +bool
(Optional) -

Digest is the digest of the file in the form of ‘:’.

+

ObservedRecurseSubmodules is the observed resource submodules +configuration used to produce the current Artifact.

-lastUpdateTime
+observedInclude
- -Kubernetes meta/v1.Time + +[]GitRepositoryInclude
-

LastUpdateTime is the timestamp corresponding to the last update of the -Artifact.

+(Optional) +

ObservedInclude is the observed list of GitRepository resources used to +produce the current Artifact.

-size
+sourceVerificationMode
-int64 + +GitVerificationMode +
(Optional) -

Size is the number of bytes in the file.

+

SourceVerificationMode is the last used verification mode indicating +which Git object(s) have been verified.

-metadata
+ReconcileRequestStatus
-map[string]string + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus +
-(Optional) -

Metadata holds upstream information such as OCI annotations.

+

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

-

GitRepositoryInclude +

GitRepositoryVerification

(Appears on: -GitRepositorySpec, -GitRepositoryStatus) +GitRepositorySpec)

-

GitRepositoryInclude specifies a local reference to a GitRepository which -Artifact (sub-)contents must be included, and where they should be placed.

+

GitRepositoryVerification specifies the Git commit signature verification +strategy.

@@ -376,7 +1333,24 @@ Artifact (sub-)contents must be included, and where they should be placed.

+ + + + + + +
-repository
+mode
+ + +GitVerificationMode + + +
+(Optional) +

Mode specifies which Git object(s) should be verified.

+

The variants “head” and “HEAD” both imply the same thing, i.e. verify +the commit that the HEAD of the Git repository points to. The variant +“head” solely exists to ensure backwards compatibility.

+
+secretRef
github.com/fluxcd/pkg/apis/meta.LocalObjectReference @@ -384,47 +1358,196 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
-

GitRepositoryRef specifies the GitRepository which Artifact contents -must be included.

+

SecretRef specifies the Secret containing the public keys of trusted Git +authors.

+
+
+
+

GitVerificationMode +(string alias)

+

+(Appears on: +GitRepositoryStatus, +GitRepositoryVerification) +

+

GitVerificationMode specifies the verification mode for a Git repository.

+

HelmChartSpec +

+

+(Appears on: +HelmChart) +

+

HelmChartSpec specifies the desired state of a Helm chart.

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

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

-fromPath
+version
string
(Optional) -

FromPath specifies the path to copy contents from, defaults to the root -of the Artifact.

+

Version is the chart version semver expression, ignored for charts from +GitRepository and Bucket sources. Defaults to latest when omitted.

-toPath
+sourceRef
+ + +LocalHelmChartSourceReference + + +
+

SourceRef is the reference to the Source the chart is available at.

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

Interval at which the HelmChart SourceRef is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

+
+reconcileStrategy
string
(Optional) -

ToPath specifies the path to copy contents to, defaults to the name of -the GitRepositoryRef.

+

ReconcileStrategy 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) +

ValuesFiles is an 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) +

ValuesFile is an 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 specified here +is merged before the ValuesFiles items. Ignored when omitted.

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

Suspend tells the controller to suspend the reconciliation of this +source.

+
+accessFrom
+ + +github.com/fluxcd/pkg/apis/acl.AccessFrom + + +
+(Optional) +

AccessFrom specifies an Access Control List for allowing cross-namespace +references to this object. +NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

+
+verify
+ + +OCIRepositoryVerification + + +
+(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 when using HelmRepository source with spec.type ‘oci’. +Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified.

-

GitRepositoryRef +

HelmChartStatus

(Appears on: -GitRepositorySpec) +HelmChart)

-

GitRepositoryRef specifies the Git reference to resolve and checkout.

+

HelmChartStatus records the observed state of the HelmChart.

@@ -437,80 +1560,112 @@ the GitRepositoryRef.

+ + + + + + + +
-branch
+observedGeneration
+ +int64 + +
+(Optional) +

ObservedGeneration is the last observed generation of the HelmChart +object.

+
+observedSourceArtifactRevision
string
(Optional) -

Branch to check out, defaults to ‘master’ if no other field is defined.

+

ObservedSourceArtifactRevision is the last observed Artifact.Revision +of the HelmChartSpec.SourceRef.

-tag
+observedChartName
string
(Optional) -

Tag to check out, takes precedence over Branch.

+

ObservedChartName is the last observed chart name as specified by the +resolved chart reference.

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

SemVer tag expression to check out, takes precedence over Tag.

+

Conditions holds the conditions for the HelmChart.

-name
+url
string
(Optional) -

Name of the reference to check out; takes precedence over Branch, Tag and SemVer.

-

It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description -Examples: “refs/heads/main”, “refs/tags/v0.1.0”, “refs/pull/420/head”, “refs/merge-requests/1/head”

+

URL is the dynamic fetch link for the latest Artifact. +It is provided on a “best effort” basis, and using the precise +BucketStatus.Artifact data is recommended.

-commit
+artifact
-string + +Artifact +
(Optional) -

Commit SHA to check out, takes precedence over all reference fields.

-

This can be combined with Branch to shallow clone the branch, in which -the commit is expected to exist.

+

Artifact represents the output of the last successful reconciliation.

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

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

-

GitRepositorySpec +

HelmRepositorySpec

(Appears on: -GitRepository) +HelmRepository)

-

GitRepositorySpec specifies the required configuration to produce an -Artifact for a Git repository.

+

HelmRepositorySpec specifies the required configuration to produce an +Artifact for a Helm repository index YAML.

@@ -529,7 +1684,8 @@ string @@ -543,154 +1699,171 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
-

URL specifies the Git repository URL, it can be an HTTP/S or SSH address.

+

URL of the Helm repository, a valid URL contains at least a protocol and +host.

(Optional) -

SecretRef specifies the Secret containing authentication credentials for -the GitRepository. -For HTTPS repositories the Secret must contain ‘username’ and ‘password’ -fields for basic auth or ‘bearerToken’ field for token auth. -For SSH repositories the Secret must contain ‘identity’ -and ‘known_hosts’ fields.

+

SecretRef specifies the Secret containing authentication credentials +for the HelmRepository. +For HTTP/S basic auth the secret must contain ‘username’ and ‘password’ +fields. +Support for TLS auth using the ‘certFile’ and ‘keyFile’, and/or ‘caFile’ +keys is deprecated. Please use .spec.certSecretRef instead.

-interval
+certSecretRef
- -Kubernetes meta/v1.Duration + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference
-

Interval at which the GitRepository URL is checked for updates. -This interval is approximate and may be subject to jitter to ensure -efficient use of resources.

+(Optional) +

CertSecretRef can be given the name of a Secret containing +either or both of

+
    +
  • a PEM-encoded client certificate (tls.crt) and private +key (tls.key);
  • +
  • a PEM-encoded CA certificate (ca.crt)
  • +
+

and whichever are supplied, will be used for connecting to the +registry. The client cert and key are useful if you are +authenticating with a certificate; the CA cert is useful if +you are using a self-signed server certificate. The Secret must +be of type Opaque or kubernetes.io/tls.

+

It takes precedence over the values specified in the Secret referred +to by .spec.secretRef.

-timeout
+passCredentials
- -Kubernetes meta/v1.Duration - +bool
(Optional) -

Timeout for Git operations like cloning, defaults to 60s.

+

PassCredentials allows the credentials from the SecretRef to be passed +on to a host that does not match the host as defined in URL. +This may be required if the host of the advertised chart URLs in the +index differ from the defined URL. +Enabling this should be done with caution, as it can potentially result +in credentials getting stolen in a MITM-attack.

-ref
+interval
- -GitRepositoryRef + +Kubernetes meta/v1.Duration
(Optional) -

Reference specifies the Git reference to resolve and monitor for -changes, defaults to the ‘master’ branch.

+

Interval at which the HelmRepository URL is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

-verify
+insecure
- -GitRepositoryVerification - +bool
(Optional) -

Verification specifies the configuration to verify the Git commit -signature(s).

+

Insecure allows connecting to a non-TLS HTTP container registry. +This field is only taken into account if the .spec.type field is set to ‘oci’.

-proxySecretRef
+timeout
- -github.com/fluxcd/pkg/apis/meta.LocalObjectReference + +Kubernetes meta/v1.Duration
(Optional) -

ProxySecretRef specifies the Secret containing the proxy configuration -to use while communicating with the Git server.

+

Timeout is used for the index fetch operation for an HTTPS helm repository, +and for remote OCI Repository operations like pulling for an OCI helm +chart by the associated HelmChart. +Its default value is 60s.

-ignore
+suspend
-string +bool
(Optional) -

Ignore overrides the set of excluded patterns in the .sourceignore format -(which is the same as .gitignore). If not provided, a default will be used, -consult the documentation for your version to find out what those are.

+

Suspend tells the controller to suspend the reconciliation of this +HelmRepository.

-suspend
+accessFrom
-bool + +github.com/fluxcd/pkg/apis/acl.AccessFrom +
(Optional) -

Suspend tells the controller to suspend the reconciliation of this -GitRepository.

+

AccessFrom specifies an Access Control List for allowing cross-namespace +references to this object. +NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

-recurseSubmodules
+type
-bool +string
(Optional) -

RecurseSubmodules enables the initialization of all submodules within -the GitRepository as cloned from the URL, using their default settings.

+

Type of the HelmRepository. +When this field is set to “oci”, the URL field value must be prefixed with “oci://”.

-include
+provider
- -[]GitRepositoryInclude - +string
(Optional) -

Include specifies a list of GitRepository resources which Artifacts -should be included in the Artifact produced for this GitRepository.

+

Provider used for authentication, can be ‘aws’, ‘azure’, ‘gcp’ or ‘generic’. +This field is optional, and only taken into account if the .spec.type field is set to ‘oci’. +When not specified, defaults to ‘generic’.

-

GitRepositoryStatus +

HelmRepositoryStatus

(Appears on: -GitRepository) +HelmRepository)

-

GitRepositoryStatus records the observed state of a Git repository.

+

HelmRepositoryStatus records the observed state of the HelmRepository.

@@ -710,7 +1883,7 @@ int64 @@ -725,7 +1898,21 @@ object.

+ + + + @@ -739,107 +1926,157 @@ Artifact + +
(Optional) -

ObservedGeneration is the last observed generation of the GitRepository +

ObservedGeneration is the last observed generation of the HelmRepository object.

(Optional) -

Conditions holds the conditions for the GitRepository.

+

Conditions holds the conditions for the HelmRepository.

+
+url
+ +string + +
+(Optional) +

URL is the dynamic fetch link for the latest Artifact. +It is provided on a “best effort” basis, and using the precise +HelmRepositoryStatus.Artifact data is recommended.

(Optional) -

Artifact represents the last successful GitRepository reconciliation.

+

Artifact represents the last successful HelmRepository reconciliation.

-includedArtifacts
+ReconcileRequestStatus
- -[]Artifact + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
-(Optional) -

IncludedArtifacts contains a list of the last successfully included -Artifacts as instructed by GitRepositorySpec.Include.

+

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

+
+
+

LocalHelmChartSourceReference +

+

+(Appears on: +HelmChartSpec) +

+

LocalHelmChartSourceReference contains enough information to let you locate +the typed referenced object at namespace level.

+
+
+ + + + + + + + + + +
FieldDescription
-observedIgnore
+apiVersion
string
(Optional) -

ObservedIgnore is the observed exclusion patterns used for constructing -the source artifact.

+

APIVersion of the referent.

-observedRecurseSubmodules
+kind
-bool +string
-(Optional) -

ObservedRecurseSubmodules is the observed resource submodules -configuration used to produce the current Artifact.

+

Kind of the referent, valid values are (‘HelmRepository’, ‘GitRepository’, +‘Bucket’).

-observedInclude
+name
- -[]GitRepositoryInclude - +string
-(Optional) -

ObservedInclude is the observed list of GitRepository resources used to -produce the current Artifact.

+

Name of the referent.

+
+
+
+

OCIRepositoryVerification +

+

+(Appears on: +HelmChartSpec) +

+

OCIRepositoryVerification verifies the authenticity of an OCI Artifact

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

Provider specifies the technology used to sign the OCI Artifact.

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

SourceVerificationMode is the last used verification mode indicating -which Git object(s) have been verified.

+

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

-ReconcileRequestStatus
+matchOIDCIdentity
- -github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus + +[]OIDCIdentityMatch
-

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

+(Optional) +

MatchOIDCIdentity specifies the identity matching criteria to use +while verifying an OCI artifact which was signed using Cosign keyless +signing. The artifact’s identity is deemed to be verified if any of the +specified matchers match against the identity.

-

GitRepositoryVerification +

OIDCIdentityMatch

(Appears on: -GitRepositorySpec) +OCIRepositoryVerification)

-

GitRepositoryVerification specifies the Git commit signature verification -strategy.

+

OIDCIdentityMatch specifies options for verifying the certificate identity, +i.e. the issuer and the subject of the certificate.

@@ -852,47 +2089,34 @@ strategy.

-mode
+issuer
- -GitVerificationMode - +string
-(Optional) -

Mode specifies which Git object(s) should be verified.

-

The variants “head” and “HEAD” both imply the same thing, i.e. verify -the commit that the HEAD of the Git repository points to. The variant -“head” solely exists to ensure backwards compatibility.

+

Issuer specifies the regex pattern to match against to verify +the OIDC issuer in the Fulcio certificate. The pattern must be a +valid Go regular expression.

-secretRef
+subject
- -github.com/fluxcd/pkg/apis/meta.LocalObjectReference - +string
-

SecretRef specifies the Secret containing the public keys of trusted Git -authors.

+

Subject specifies the regex pattern to match against to verify +the identity subject in the Fulcio certificate. The pattern must +be a valid Go regular expression.

-

GitVerificationMode -(string alias)

-

-(Appears on: -GitRepositoryStatus, -GitRepositoryVerification) -

-

GitVerificationMode specifies the verification mode for a Git repository.

Source

Source interface must be supported by all API types. diff --git a/docs/api/v1beta2/source.md b/docs/api/v1beta2/source.md index 7144c8566..439c81afd 100644 --- a/docs/api/v1beta2/source.md +++ b/docs/api/v1beta2/source.md @@ -704,8 +704,8 @@ NOTE: Not implemented, provisional as of -OCIRepositoryVerification + +github.com/fluxcd/source-controller/api/v1.OCIRepositoryVerification @@ -1122,8 +1122,8 @@ The secret must be of type kubernetes.io/dockerconfigjson.

verify
- -OCIRepositoryVerification + +github.com/fluxcd/source-controller/api/v1.OCIRepositoryVerification @@ -2386,8 +2386,8 @@ NOTE: Not implemented, provisional as of -OCIRepositoryVerification + +github.com/fluxcd/source-controller/api/v1.OCIRepositoryVerification @@ -3096,8 +3096,8 @@ The secret must be of type kubernetes.io/dockerconfigjson.

verify
- -OCIRepositoryVerification + +github.com/fluxcd/source-controller/api/v1.OCIRepositoryVerification @@ -3357,119 +3357,6 @@ github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus -

OCIRepositoryVerification -

-

-(Appears on: -HelmChartSpec, -OCIRepositorySpec) -

-

OCIRepositoryVerification verifies the authenticity of an OCI Artifact

-
-
- - - - - - - - - - - - - - - - - - - - - -
FieldDescription
-provider
- -string - -
-

Provider specifies the technology used to sign the OCI Artifact.

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

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

-
-matchOIDCIdentity
- - -[]OIDCIdentityMatch - - -
-(Optional) -

MatchOIDCIdentity specifies the identity matching criteria to use -while verifying an OCI artifact which was signed using Cosign keyless -signing. The artifact’s identity is deemed to be verified if any of the -specified matchers match against the identity.

-
-
-
-

OIDCIdentityMatch -

-

-(Appears on: -OCIRepositoryVerification) -

-

OIDCIdentityMatch specifies options for verifying the certificate identity, -i.e. the issuer and the subject of the certificate.

-
-
- - - - - - - - - - - - - - - - - -
FieldDescription
-issuer
- -string - -
-

Issuer specifies the regex pattern to match against to verify -the OIDC issuer in the Fulcio certificate. The pattern must be a -valid Go regular expression.

-
-subject
- -string - -
-

Subject specifies the regex pattern to match against to verify -the identity subject in the Fulcio certificate. The pattern must -be a valid Go regular expression.

-
-
-

Source

Source interface must be supported by all API types. diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index e4b53a5f0..79a769a8c 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2023 The Flux authors +Copyright 2024 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/controller/helmchart_controller.go b/internal/controller/helmchart_controller.go index 608b8382d..b8d2aa88f 100644 --- a/internal/controller/helmchart_controller.go +++ b/internal/controller/helmchart_controller.go @@ -65,7 +65,7 @@ import ( "github.com/fluxcd/pkg/tar" sourcev1 "github.com/fluxcd/source-controller/api/v1" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/cache" serror "github.com/fluxcd/source-controller/internal/error" "github.com/fluxcd/source-controller/internal/helm/chart" @@ -162,26 +162,26 @@ type HelmChartReconcilerOptions struct { // helmChartReconcileFunc is the function type for all the v1beta2.HelmChart // (sub)reconcile functions. The type implementations are grouped and // executed serially to perform the complete reconcile of the object. -type helmChartReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmChart, build *chart.Build) (sreconcile.Result, error) +type helmChartReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) func (r *HelmChartReconciler) SetupWithManagerAndOptions(ctx context.Context, mgr ctrl.Manager, opts HelmChartReconcilerOptions) error { r.patchOptions = getPatchOptions(helmChartReadyCondition.Owned, r.ControllerName) - if err := mgr.GetCache().IndexField(ctx, &helmv1.HelmRepository{}, helmv1.HelmRepositoryURLIndexKey, + if err := mgr.GetCache().IndexField(ctx, &sourcev1.HelmRepository{}, sourcev1.HelmRepositoryURLIndexKey, r.indexHelmRepositoryByURL); err != nil { return fmt.Errorf("failed setting index fields: %w", err) } - if err := mgr.GetCache().IndexField(ctx, &helmv1.HelmChart{}, sourcev1.SourceIndexKey, + if err := mgr.GetCache().IndexField(ctx, &sourcev1.HelmChart{}, sourcev1.SourceIndexKey, r.indexHelmChartBySource); err != nil { return fmt.Errorf("failed setting index fields: %w", err) } return ctrl.NewControllerManagedBy(mgr). - For(&helmv1.HelmChart{}, builder.WithPredicates( + For(&sourcev1.HelmChart{}, builder.WithPredicates( predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}), )). Watches( - &helmv1.HelmRepository{}, + &sourcev1.HelmRepository{}, handler.EnqueueRequestsFromMapFunc(r.requestsForHelmRepositoryChange), builder.WithPredicates(SourceRevisionChangePredicate{}), ). @@ -191,7 +191,7 @@ func (r *HelmChartReconciler) SetupWithManagerAndOptions(ctx context.Context, mg builder.WithPredicates(SourceRevisionChangePredicate{}), ). Watches( - &helmv1.Bucket{}, + &sourcev1beta2.Bucket{}, handler.EnqueueRequestsFromMapFunc(r.requestsForBucketChange), builder.WithPredicates(SourceRevisionChangePredicate{}), ). @@ -206,7 +206,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( log := ctrl.LoggerFrom(ctx) // Fetch the HelmChart - obj := &helmv1.HelmChart{} + obj := &sourcev1.HelmChart{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -280,7 +280,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // reconcile iterates through the helmChartReconcileFunc tasks for the // object. It returns early on the first call that returns // reconcile.ResultRequeue, or produces an error. -func (r *HelmChartReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmChart, reconcilers []helmChartReconcileFunc) (sreconcile.Result, error) { +func (r *HelmChartReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, reconcilers []helmChartReconcileFunc) (sreconcile.Result, error) { oldObj := obj.DeepCopy() rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress") @@ -333,7 +333,7 @@ func (r *HelmChartReconciler) reconcile(ctx context.Context, sp *patch.SerialPat } // notify emits notification related to the reconciliation. -func (r *HelmChartReconciler) notify(ctx context.Context, oldObj, newObj *helmv1.HelmChart, build *chart.Build, res sreconcile.Result, resErr error) { +func (r *HelmChartReconciler) notify(ctx context.Context, oldObj, newObj *sourcev1.HelmChart, build *chart.Build, res sreconcile.Result, resErr error) { // Notify successful reconciliation for new artifact and recovery from any // failure. if resErr == nil && res == sreconcile.ResultSuccess && newObj.Status.Artifact != nil { @@ -369,7 +369,7 @@ func (r *HelmChartReconciler) notify(ctx context.Context, oldObj, newObj *helmv1 // condition is added. // The hostname of any URL in the Status of the object are updated, to ensure // they match the Storage server hostname of current runtime. -func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { +func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -423,7 +423,7 @@ func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, sp *patch.Se return sreconcile.ResultSuccess, nil } -func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmChart, build *chart.Build) (_ sreconcile.Result, retErr error) { +func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (_ sreconcile.Result, retErr error) { // Remove any failed verification condition. // The reason is that a failing verification should be recalculated. if conditions.IsFalse(obj, sourcev1.SourceVerifiedCondition) { @@ -453,7 +453,7 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.Ser // Assert source has an artifact if s.GetArtifact() == nil || !r.Storage.ArtifactExist(*s.GetArtifact()) { // Set the condition to indicate that the source has no artifact for all types except OCI HelmRepository - if helmRepo, ok := s.(*helmv1.HelmRepository); !ok || helmRepo.Spec.Type != helmv1.HelmRepositoryTypeOCI { + if helmRepo, ok := s.(*sourcev1.HelmRepository); !ok || helmRepo.Spec.Type != sourcev1.HelmRepositoryTypeOCI { conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, "NoSourceArtifact", "no artifact available for %s source '%s'", obj.Spec.SourceRef.Kind, obj.Spec.SourceRef.Name) r.eventLogf(ctx, obj, eventv1.EventTypeTrace, "NoSourceArtifact", @@ -500,9 +500,9 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.Ser // Perform the build for the chart source type switch typedSource := s.(type) { - case *helmv1.HelmRepository: + case *sourcev1.HelmRepository: return r.buildFromHelmRepository(ctx, obj, typedSource, build) - case *sourcev1.GitRepository, *helmv1.Bucket: + case *sourcev1.GitRepository, *sourcev1beta2.Bucket: return r.buildFromTarballArtifact(ctx, obj, *typedSource.GetArtifact(), build) default: // Ending up here should generally not be possible @@ -516,8 +516,8 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.Ser // objects. // In case of a failure it records v1beta2.FetchFailedCondition on the chart // object, and returns early. -func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *helmv1.HelmChart, - repo *helmv1.HelmRepository, b *chart.Build) (sreconcile.Result, error) { +func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *sourcev1.HelmChart, + repo *sourcev1.HelmRepository, b *chart.Build) (sreconcile.Result, error) { // Used to login with the repository declared provider ctxTimeout, cancel := context.WithTimeout(ctx, repo.GetTimeout()) defer cancel() @@ -550,7 +550,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj * // Initialize the chart repository var chartRepo repository.Downloader switch repo.Spec.Type { - case helmv1.HelmRepositoryTypeOCI: + case sourcev1.HelmRepositoryTypeOCI: if !helmreg.IsOCI(normalizedURL) { err := fmt.Errorf("invalid OCI registry URL: %s", normalizedURL) return chartRepoConfigErrorReturn(err, obj) @@ -700,7 +700,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj * // v1beta2.Artifact. // In case of a failure it records v1beta2.FetchFailedCondition on the chart // object, and returns early. -func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj *helmv1.HelmChart, source sourcev1.Artifact, b *chart.Build) (sreconcile.Result, error) { +func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj *sourcev1.HelmChart, source sourcev1.Artifact, b *chart.Build) (sreconcile.Result, error) { // Create temporary working directory tmpDir, err := util.TempDirForObj("", obj) if err != nil { @@ -772,17 +772,17 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj } // Configure revision metadata for chart build if we should react to revision changes - if obj.Spec.ReconcileStrategy == helmv1.ReconcileStrategyRevision { + if obj.Spec.ReconcileStrategy == sourcev1.ReconcileStrategyRevision { rev := source.Revision if obj.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind { rev = git.ExtractHashFromRevision(rev).String() } - if obj.Spec.SourceRef.Kind == helmv1.BucketKind { + if obj.Spec.SourceRef.Kind == sourcev1beta2.BucketKind { if dig := digest.Digest(rev); dig.Validate() == nil { rev = dig.Encoded() } } - if kind := obj.Spec.SourceRef.Kind; kind == sourcev1.GitRepositoryKind || kind == helmv1.BucketKind { + if kind := obj.Spec.SourceRef.Kind; kind == sourcev1.GitRepositoryKind || kind == sourcev1beta2.BucketKind { // The SemVer from the metadata is at times used in e.g. the label metadata for a resource // in a chart, which has a limited length of 63 characters. // To not fill most of this space with a full length SHA hex (40 characters for SHA-1, and @@ -829,7 +829,7 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj // early. // On a successful archive, the Artifact in the Status of the object is set, // and the symlink in the Storage is updated to its path. -func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, _ *patch.SerialPatcher, obj *helmv1.HelmChart, b *chart.Build) (sreconcile.Result, error) { +func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, _ *patch.SerialPatcher, obj *sourcev1.HelmChart, b *chart.Build) (sreconcile.Result, error) { // Without a complete chart build, there is little to reconcile if !b.Complete() { return sreconcile.ResultRequeue, nil @@ -909,15 +909,15 @@ func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, _ *patch.Se // getSource returns the v1beta1.Source for the given object, or an error describing why the source could not be // returned. -func (r *HelmChartReconciler) getSource(ctx context.Context, obj *helmv1.HelmChart) (sourcev1.Source, error) { +func (r *HelmChartReconciler) getSource(ctx context.Context, obj *sourcev1.HelmChart) (sourcev1.Source, error) { namespacedName := types.NamespacedName{ Namespace: obj.GetNamespace(), Name: obj.Spec.SourceRef.Name, } var s sourcev1.Source switch obj.Spec.SourceRef.Kind { - case helmv1.HelmRepositoryKind: - var repo helmv1.HelmRepository + case sourcev1.HelmRepositoryKind: + var repo sourcev1.HelmRepository if err := r.Client.Get(ctx, namespacedName, &repo); err != nil { return nil, err } @@ -928,15 +928,15 @@ func (r *HelmChartReconciler) getSource(ctx context.Context, obj *helmv1.HelmCha return nil, err } s = &repo - case helmv1.BucketKind: - var bucket helmv1.Bucket + case sourcev1beta2.BucketKind: + var bucket sourcev1beta2.Bucket if err := r.Client.Get(ctx, namespacedName, &bucket); err != nil { return nil, err } s = &bucket default: return nil, fmt.Errorf("unsupported source kind '%s', must be one of: %v", obj.Spec.SourceRef.Kind, []string{ - helmv1.HelmRepositoryKind, sourcev1.GitRepositoryKind, helmv1.BucketKind}) + sourcev1.HelmRepositoryKind, sourcev1.GitRepositoryKind, sourcev1beta2.BucketKind}) } return s, nil } @@ -944,7 +944,7 @@ func (r *HelmChartReconciler) getSource(ctx context.Context, obj *helmv1.HelmCha // reconcileDelete handles the deletion of the object. // It first garbage collects all Artifacts for the object from the Storage. // Removing the finalizer from the object if successful. -func (r *HelmChartReconciler) reconcileDelete(ctx context.Context, obj *helmv1.HelmChart) (sreconcile.Result, error) { +func (r *HelmChartReconciler) reconcileDelete(ctx context.Context, obj *sourcev1.HelmChart) (sreconcile.Result, error) { // Garbage collect the resource's artifacts if err := r.garbageCollect(ctx, obj); err != nil { // Return the error so we retry the failed garbage collection @@ -963,7 +963,7 @@ func (r *HelmChartReconciler) reconcileDelete(ctx context.Context, obj *helmv1.H // It removes all but the current Artifact from the Storage, unless the // deletion timestamp on the object is set. Which will result in the // removal of all Artifacts for the objects. -func (r *HelmChartReconciler) garbageCollect(ctx context.Context, obj *helmv1.HelmChart) error { +func (r *HelmChartReconciler) garbageCollect(ctx context.Context, obj *sourcev1.HelmChart) error { if !obj.DeletionTimestamp.IsZero() { if deleted, err := r.Storage.RemoveAll(r.Storage.NewArtifactFor(obj.Kind, obj.GetObjectMeta(), "", "*")); err != nil { return serror.NewGeneric( @@ -1010,8 +1010,8 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont if apierrs.ReasonForError(err) != metav1.StatusReasonUnknown { return nil, err } - obj = &helmv1.HelmRepository{ - Spec: helmv1.HelmRepositorySpec{ + obj = &sourcev1.HelmRepository{ + Spec: sourcev1.HelmRepositorySpec{ URL: url, Timeout: &metav1.Duration{Duration: 60 * time.Second}, }, @@ -1099,13 +1099,13 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont } } -func (r *HelmChartReconciler) resolveDependencyRepository(ctx context.Context, url string, namespace string) (*helmv1.HelmRepository, error) { +func (r *HelmChartReconciler) resolveDependencyRepository(ctx context.Context, url string, namespace string) (*sourcev1.HelmRepository, error) { listOpts := []client.ListOption{ client.InNamespace(namespace), - client.MatchingFields{helmv1.HelmRepositoryURLIndexKey: url}, + client.MatchingFields{sourcev1.HelmRepositoryURLIndexKey: url}, client.Limit(1), } - var list helmv1.HelmRepositoryList + var list sourcev1.HelmRepositoryList err := r.Client.List(ctx, &list, listOpts...) if err != nil { return nil, fmt.Errorf("unable to retrieve HelmRepositoryList: %w", err) @@ -1117,7 +1117,7 @@ func (r *HelmChartReconciler) resolveDependencyRepository(ctx context.Context, u } func (r *HelmChartReconciler) indexHelmRepositoryByURL(o client.Object) []string { - repo, ok := o.(*helmv1.HelmRepository) + repo, ok := o.(*sourcev1.HelmRepository) if !ok { panic(fmt.Sprintf("Expected a HelmRepository, got %T", o)) } @@ -1129,7 +1129,7 @@ func (r *HelmChartReconciler) indexHelmRepositoryByURL(o client.Object) []string } func (r *HelmChartReconciler) indexHelmChartBySource(o client.Object) []string { - hc, ok := o.(*helmv1.HelmChart) + hc, ok := o.(*sourcev1.HelmChart) if !ok { panic(fmt.Sprintf("Expected a HelmChart, got %T", o)) } @@ -1137,7 +1137,7 @@ func (r *HelmChartReconciler) indexHelmChartBySource(o client.Object) []string { } func (r *HelmChartReconciler) requestsForHelmRepositoryChange(ctx context.Context, o client.Object) []reconcile.Request { - repo, ok := o.(*helmv1.HelmRepository) + repo, ok := o.(*sourcev1.HelmRepository) if !ok { ctrl.LoggerFrom(ctx).Error(fmt.Errorf("expected a HelmRepository, got %T", o), "failed to get requests for HelmRepository change") return nil @@ -1148,9 +1148,9 @@ func (r *HelmChartReconciler) requestsForHelmRepositoryChange(ctx context.Contex return nil } - var list helmv1.HelmChartList + var list sourcev1.HelmChartList if err := r.List(ctx, &list, client.MatchingFields{ - sourcev1.SourceIndexKey: fmt.Sprintf("%s/%s", helmv1.HelmRepositoryKind, repo.Name), + sourcev1.SourceIndexKey: fmt.Sprintf("%s/%s", sourcev1.HelmRepositoryKind, repo.Name), }); err != nil { ctrl.LoggerFrom(ctx).Error(err, "failed to list HelmCharts for HelmRepository change") return nil @@ -1178,7 +1178,7 @@ func (r *HelmChartReconciler) requestsForGitRepositoryChange(ctx context.Context return nil } - var list helmv1.HelmChartList + var list sourcev1.HelmChartList if err := r.List(ctx, &list, client.MatchingFields{ sourcev1.SourceIndexKey: fmt.Sprintf("%s/%s", sourcev1.GitRepositoryKind, repo.Name), }); err != nil { @@ -1196,7 +1196,7 @@ func (r *HelmChartReconciler) requestsForGitRepositoryChange(ctx context.Context } func (r *HelmChartReconciler) requestsForBucketChange(ctx context.Context, o client.Object) []reconcile.Request { - bucket, ok := o.(*helmv1.Bucket) + bucket, ok := o.(*sourcev1beta2.Bucket) if !ok { ctrl.LoggerFrom(ctx).Error(fmt.Errorf("expected a Bucket, got %T", o), "failed to get reconcile requests for Bucket change") @@ -1208,9 +1208,9 @@ func (r *HelmChartReconciler) requestsForBucketChange(ctx context.Context, o cli return nil } - var list helmv1.HelmChartList + var list sourcev1.HelmChartList if err := r.List(ctx, &list, client.MatchingFields{ - sourcev1.SourceIndexKey: fmt.Sprintf("%s/%s", helmv1.BucketKind, bucket.Name), + sourcev1.SourceIndexKey: fmt.Sprintf("%s/%s", sourcev1beta2.BucketKind, bucket.Name), }); err != nil { ctrl.LoggerFrom(ctx).Error(err, "failed to list HelmCharts for Bucket change") return nil @@ -1242,7 +1242,7 @@ func (r *HelmChartReconciler) eventLogf(ctx context.Context, obj runtime.Object, } // observeChartBuild records the observation on the given given build and error on the object. -func observeChartBuild(ctx context.Context, sp *patch.SerialPatcher, pOpts []patch.Option, obj *helmv1.HelmChart, build *chart.Build, err error) { +func observeChartBuild(ctx context.Context, sp *patch.SerialPatcher, pOpts []patch.Option, obj *sourcev1.HelmChart, build *chart.Build, err error) { if build.HasMetadata() { if build.Name != obj.Status.ObservedChartName || !obj.GetArtifact().HasRevision(build.Version) { if obj.GetArtifact() != nil { @@ -1297,12 +1297,12 @@ func reasonForBuild(build *chart.Build) string { return "" } if build.Packaged { - return helmv1.ChartPackageSucceededReason + return sourcev1.ChartPackageSucceededReason } - return helmv1.ChartPullSucceededReason + return sourcev1.ChartPullSucceededReason } -func chartRepoConfigErrorReturn(err error, obj *helmv1.HelmChart) (sreconcile.Result, error) { +func chartRepoConfigErrorReturn(err error, obj *sourcev1.HelmChart) (sreconcile.Result, error) { switch err.(type) { case *url.Error: e := serror.NewStalling( @@ -1322,7 +1322,7 @@ func chartRepoConfigErrorReturn(err error, obj *helmv1.HelmChart) (sreconcile.Re } // makeVerifiers returns a list of verifiers for the given chart. -func (r *HelmChartReconciler) makeVerifiers(ctx context.Context, obj *helmv1.HelmChart, clientOpts getter.ClientOpts) ([]soci.Verifier, error) { +func (r *HelmChartReconciler) makeVerifiers(ctx context.Context, obj *sourcev1.HelmChart, clientOpts getter.ClientOpts) ([]soci.Verifier, error) { var verifiers []soci.Verifier verifyOpts := []remote.Option{} diff --git a/internal/controller/helmchart_controller_test.go b/internal/controller/helmchart_controller_test.go index b15fcf6d5..06426068a 100644 --- a/internal/controller/helmchart_controller_test.go +++ b/internal/controller/helmchart_controller_test.go @@ -67,7 +67,7 @@ import ( "github.com/fluxcd/pkg/testserver" sourcev1 "github.com/fluxcd/source-controller/api/v1" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" serror "github.com/fluxcd/source-controller/internal/error" "github.com/fluxcd/source-controller/internal/helm/chart" "github.com/fluxcd/source-controller/internal/helm/chart/secureloader" @@ -90,13 +90,13 @@ func TestHelmChartReconciler_deleteBeforeFinalizer(t *testing.T) { g.Expect(k8sClient.Delete(ctx, namespace)).NotTo(HaveOccurred()) }) - helmchart := &helmv1.HelmChart{} + helmchart := &sourcev1.HelmChart{} helmchart.Name = "test-helmchart" helmchart.Namespace = namespaceName - helmchart.Spec = helmv1.HelmChartSpec{ + helmchart.Spec = sourcev1.HelmChartSpec{ Interval: metav1.Duration{Duration: interval}, Chart: "foo", - SourceRef: helmv1.LocalHelmChartSourceReference{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Kind: "HelmRepository", Name: "bar", }, @@ -135,12 +135,12 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { tests := []struct { name string - beforeFunc func(repository *helmv1.HelmRepository) - assertFunc func(g *WithT, obj *helmv1.HelmChart, repository *helmv1.HelmRepository) + beforeFunc func(repository *sourcev1.HelmRepository) + assertFunc func(g *WithT, obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) }{ { name: "Reconciles chart build", - assertFunc: func(g *WithT, obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { origObj := obj.DeepCopy() key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} @@ -206,10 +206,10 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { }, { name: "Stalling on invalid repository URL", - beforeFunc: func(repository *helmv1.HelmRepository) { + beforeFunc: func(repository *sourcev1.HelmRepository) { repository.Spec.URL = "https://unsupported/foo://" // Invalid URL }, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, _ *helmv1.HelmRepository) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, _ *sourcev1.HelmRepository) { key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} // Wait for HelmChart to be FetchFailed == true g.Eventually(func() bool { @@ -241,10 +241,10 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { }, { name: "Stalling on invalid oci repository URL", - beforeFunc: func(repository *helmv1.HelmRepository) { + beforeFunc: func(repository *sourcev1.HelmRepository) { repository.Spec.URL = strings.Replace(repository.Spec.URL, "http", "oci", 1) }, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, _ *helmv1.HelmRepository) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, _ *sourcev1.HelmRepository) { key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} // Wait for HelmChart to be Ready g.Eventually(func() bool { @@ -288,12 +288,12 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - repository := helmv1.HelmRepository{ + repository := sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", Namespace: ns.Name, }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: server.URL(), }, } @@ -305,16 +305,16 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { g.Expect(testEnv.CreateAndWait(ctx, &repository)).To(Succeed()) defer func() { g.Expect(testEnv.Delete(ctx, &repository)).To(Succeed()) }() - obj := helmv1.HelmChart{ + obj := sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-reconcile-", Namespace: ns.Name, }, - Spec: helmv1.HelmChartSpec{ + Spec: sourcev1.HelmChartSpec{ Chart: chartName, Version: chartVersion, - SourceRef: helmv1.LocalHelmChartSourceReference{ - Kind: helmv1.HelmRepositoryKind, + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, Name: repository.Name, }, }, @@ -331,7 +331,7 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { func TestHelmChartReconciler_reconcileStorage(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *helmv1.HelmChart, storage *Storage) error + beforeFunc func(obj *sourcev1.HelmChart, storage *Storage) error want sreconcile.Result wantErr bool assertArtifact *sourcev1.Artifact @@ -340,7 +340,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { }{ { name: "garbage collects", - beforeFunc: func(obj *helmv1.HelmChart, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmChart, storage *Storage) error { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] @@ -390,7 +390,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { }, { name: "notices missing artifact in storage", - beforeFunc: func(obj *helmv1.HelmChart, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmChart, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "d", @@ -409,7 +409,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { }, { name: "notices empty artifact digest", - beforeFunc: func(obj *helmv1.HelmChart, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmChart, storage *Storage) error { f := "empty-digest.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -440,7 +440,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { }, { name: "notices artifact digest mismatch", - beforeFunc: func(obj *helmv1.HelmChart, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmChart, storage *Storage) error { f := "digest-mismatch.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -471,7 +471,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { }, { name: "updates hostname on diff from current", - beforeFunc: func(obj *helmv1.HelmChart, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmChart, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", @@ -514,14 +514,14 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { r := &HelmChartReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmChart{}). + WithStatusSubresource(&sourcev1.HelmChart{}). Build(), EventRecorder: record.NewFakeRecorder(32), Storage: testStorage, patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Generation: 1, @@ -581,10 +581,10 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { tests := []struct { name string source sourcev1.Source - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr error - assertFunc func(g *WithT, build chart.Build, obj helmv1.HelmChart) + assertFunc func(g *WithT, build chart.Build, obj sourcev1.HelmChart) cleanFunc func(g *WithT, build *chart.Build) }{ { @@ -598,15 +598,15 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { Artifact: gitArtifact, }, }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "gitrepository", Kind: sourcev1.GitRepositoryKind, } }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeTrue()) g.Expect(build.Name).To(Equal("helmchart")) g.Expect(build.Version).To(Equal("0.1.0")) @@ -633,9 +633,9 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { Artifact: gitArtifact, }, }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "gitrepository", Kind: sourcev1.GitRepositoryKind, } @@ -645,7 +645,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { } }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeTrue()) g.Expect(build.Name).To(Equal("helmchart")) g.Expect(build.Version).To(Equal("0.1.0")) @@ -661,8 +661,8 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, { name: "Error on unavailable source", - beforeFunc: func(obj *helmv1.HelmChart) { - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + beforeFunc: func(obj *sourcev1.HelmChart) { + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "unavailable", Kind: sourcev1.GitRepositoryKind, } @@ -671,7 +671,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, want: sreconcile.ResultEmpty, wantErr: &serror.Generic{Err: errors.New("gitrepositories.source.toolkit.fluxcd.io \"unavailable\" not found")}, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -683,8 +683,8 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, { name: "Stalling on unsupported source kind", - beforeFunc: func(obj *helmv1.HelmChart) { - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + beforeFunc: func(obj *sourcev1.HelmChart) { + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "unavailable", Kind: "Unsupported", } @@ -693,7 +693,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, want: sreconcile.ResultEmpty, wantErr: &serror.Stalling{Err: errors.New("unsupported source kind 'Unsupported'")}, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -714,9 +714,9 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { Artifact: gitArtifact, }, }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "gitrepository", Kind: sourcev1.GitRepositoryKind, } @@ -726,7 +726,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, want: sreconcile.ResultEmpty, wantErr: &serror.Stalling{Err: errors.New("values files merge error: no values file found at path")}, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -745,9 +745,9 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { }, Status: sourcev1.GitRepositoryStatus{}, }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" - obj.Spec.SourceRef = helmv1.LocalHelmChartSourceReference{ + obj.Spec.SourceRef = sourcev1.LocalHelmChartSourceReference{ Name: "gitrepository", Kind: sourcev1.GitRepositoryKind, } @@ -756,7 +756,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "foo") }, want: sreconcile.ResultRequeue, - assertFunc: func(g *WithT, build chart.Build, obj helmv1.HelmChart) { + assertFunc: func(g *WithT, build chart.Build, obj sourcev1.HelmChart) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.ObservedSourceArtifactRevision).To(Equal("foo")) @@ -774,7 +774,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmChart{}) + WithStatusSubresource(&sourcev1.HelmChart{}) if tt.source != nil { clientBuilder.WithRuntimeObjects(tt.source) @@ -787,13 +787,13 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := helmv1.HelmChart{ + obj := sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "chart", Namespace: "default", Generation: 1, }, - Spec: helmv1.HelmChartSpec{}, + Spec: sourcev1.HelmChartSpec{}, } if tt.beforeFunc != nil { tt.beforeFunc(&obj) @@ -859,19 +859,19 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { name string server options secret *corev1.Secret - beforeFunc func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) + beforeFunc func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) want sreconcile.Result wantErr error - assertFunc func(g *WithT, obj *helmv1.HelmChart, build chart.Build) + assertFunc func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) cleanFunc func(g *WithT, build *chart.Build) }{ { name: "Reconciles chart build", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = "helmchart" }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, _ *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, _ *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(higherChartVersion)) g.Expect(build.Path).ToNot(BeEmpty()) @@ -896,13 +896,13 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { "password": []byte("bar"), }, }, - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion repository.Spec.SecretRef = &meta.LocalObjectReference{Name: "auth"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, _ *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, _ *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion)) g.Expect(build.Path).ToNot(BeEmpty()) @@ -914,13 +914,13 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Uses artifact as build cache", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion)) g.Expect(build.Path).To(Equal(filepath.Join(serverFactory.Root(), obj.Status.Artifact.Path))) @@ -946,13 +946,13 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Sets Generation as VersionMetadata with values files", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Generation = 3 obj.Spec.ValuesFiles = []string{"values.yaml", "override.yaml"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, _ *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, _ *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(higherChartVersion + "+3")) g.Expect(build.Path).ToNot(BeEmpty()) @@ -1009,7 +1009,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Forces build on generation change", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Generation = 3 obj.Spec.Chart = chartName obj.Spec.Version = chartVersion @@ -1018,7 +1018,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion)) g.Expect(build.Path).ToNot(Equal(filepath.Join(serverFactory.Root(), obj.Status.Artifact.Path))) @@ -1030,14 +1030,14 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Event on unsuccessful secret retrieval", - beforeFunc: func(_ *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(_ *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { repository.Spec.SecretRef = &meta.LocalObjectReference{ Name: "invalid", } }, want: sreconcile.ResultEmpty, wantErr: &serror.Generic{Err: errors.New("failed to get authentication secret '/invalid'")}, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -1047,12 +1047,12 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Stalling on invalid client options", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { repository.Spec.URL = "file://unsupported" // Unsupported protocol }, want: sreconcile.ResultEmpty, wantErr: &serror.Stalling{Err: errors.New("scheme \"file\" not supported")}, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -1062,12 +1062,12 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Stalling on invalid repository URL", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { repository.Spec.URL = "://unsupported" // Invalid URL }, want: sreconcile.ResultEmpty, wantErr: &serror.Stalling{Err: errors.New("missing protocol scheme")}, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -1077,7 +1077,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "BuildError on temporary build error", - beforeFunc: func(obj *helmv1.HelmChart, _ *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, _ *sourcev1.HelmRepository) { obj.Spec.Chart = "invalid" }, want: sreconcile.ResultEmpty, @@ -1107,7 +1107,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.Scheme()). - WithStatusSubresource(&helmv1.HelmChart{}) + WithStatusSubresource(&sourcev1.HelmChart{}) if tt.secret != nil { clientBuilder.WithObjects(tt.secret.DeepCopy()) @@ -1124,25 +1124,25 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - repository := &helmv1.HelmRepository{ + repository := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: server.URL(), Timeout: &metav1.Duration{Duration: timeout}, }, - Status: helmv1.HelmRepositoryStatus{ + Status: sourcev1.HelmRepositoryStatus{ Artifact: &sourcev1.Artifact{ Path: "index.yaml", }, }, } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmChartSpec{}, + Spec: sourcev1.HelmChartSpec{}, } if tt.beforeFunc != nil { @@ -1198,10 +1198,10 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { tests := []struct { name string secret *corev1.Secret - beforeFunc func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) + beforeFunc func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) want sreconcile.Result wantErr error - assertFunc func(g *WithT, obj *helmv1.HelmChart, build chart.Build) + assertFunc func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) cleanFunc func(g *WithT, build *chart.Build) }{ { @@ -1217,13 +1217,13 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { `auth":"` + base64.StdEncoding.EncodeToString([]byte(testRegistryUsername+":"+testRegistryPassword)) + `"}}}`), }, }, - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version repository.Spec.SecretRef = &meta.LocalObjectReference{Name: "auth"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, _ *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, _ *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(metadata.Name)) g.Expect(build.Version).To(Equal(metadata.Version)) g.Expect(build.Path).ToNot(BeEmpty()) @@ -1244,13 +1244,13 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { "password": []byte(testRegistryPassword), }, }, - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version repository.Spec.SecretRef = &meta.LocalObjectReference{Name: "auth"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, _ *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, _ *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(metadata.Name)) g.Expect(build.Version).To(Equal(metadata.Version)) g.Expect(build.Path).ToNot(BeEmpty()) @@ -1262,13 +1262,13 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { }, { name: "Uses artifact as build cache", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(metadata.Name)) g.Expect(build.Version).To(Equal(metadata.Version)) g.Expect(build.Path).To(Equal(storage.LocalPath(*cachedArtifact.DeepCopy()))) @@ -1278,7 +1278,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { }, { name: "Forces build on generation change", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Generation = 3 obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version @@ -1287,7 +1287,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(metadata.Name)) g.Expect(build.Version).To(Equal(metadata.Version)) g.Expect(build.Path).ToNot(Equal(storage.LocalPath(*cachedArtifact.DeepCopy()))) @@ -1299,14 +1299,14 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { }, { name: "Event on unsuccessful secret retrieval", - beforeFunc: func(_ *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(_ *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { repository.Spec.SecretRef = &meta.LocalObjectReference{ Name: "invalid", } }, want: sreconcile.ResultEmpty, wantErr: &serror.Generic{Err: errors.New("failed to get authentication secret '/invalid'")}, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -1316,12 +1316,12 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { }, { name: "Stalling on invalid client options", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { repository.Spec.URL = "https://unsupported" // Unsupported protocol }, want: sreconcile.ResultEmpty, wantErr: &serror.Stalling{Err: errors.New("failed to construct Helm client: invalid OCI registry URL: https://unsupported")}, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Complete()).To(BeFalse()) g.Expect(obj.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{ @@ -1331,7 +1331,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { }, { name: "BuildError on temporary build error", - beforeFunc: func(obj *helmv1.HelmChart, _ *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, _ *sourcev1.HelmRepository) { obj.Spec.Chart = "invalid" }, want: sreconcile.ResultEmpty, @@ -1344,7 +1344,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.Scheme()). - WithStatusSubresource(&helmv1.HelmChart{}) + WithStatusSubresource(&sourcev1.HelmChart{}) if tt.secret != nil { clientBuilder.WithObjects(tt.secret.DeepCopy()) @@ -1359,23 +1359,23 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - repository := &helmv1.HelmRepository{ + repository := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", testRegistryServer.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: helmv1.GenericOCIProvider, - Type: helmv1.HelmRepositoryTypeOCI, + Provider: sourcev1beta2.GenericOCIProvider, + Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmChartSpec{}, + Spec: sourcev1.HelmChartSpec{}, } if tt.beforeFunc != nil { @@ -1431,7 +1431,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { tests := []struct { name string source sourcev1.Artifact - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr error assertFunc func(g *WithT, build chart.Build) @@ -1440,7 +1440,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "Resolves chart dependencies and builds", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchartwithdeps" }, want: sreconcile.ResultSuccess, @@ -1462,10 +1462,10 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "ReconcileStrategyRevision sets VersionMetadata", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart" obj.Spec.SourceRef.Kind = sourcev1.GitRepositoryKind - obj.Spec.ReconcileStrategy = helmv1.ReconcileStrategyRevision + obj.Spec.ReconcileStrategy = sourcev1.ReconcileStrategyRevision }, want: sreconcile.ResultSuccess, assertFunc: func(g *WithT, build chart.Build) { @@ -1481,7 +1481,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "ValuesFiles sets Generation as VersionMetadata", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Generation = 3 obj.Spec.Chart = "testdata/charts/helmchart" obj.Spec.SourceRef.Kind = sourcev1.GitRepositoryKind @@ -1508,7 +1508,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "Chart from storage cache", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" obj.Status.Artifact = cachedArtifact.DeepCopy() }, @@ -1541,7 +1541,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "Generation change forces rebuild", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Generation = 2 obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" obj.Status.Artifact = cachedArtifact.DeepCopy() @@ -1585,7 +1585,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { r := &HelmChartReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.Scheme()). - WithStatusSubresource(&helmv1.HelmChart{}). + WithStatusSubresource(&sourcev1.HelmChart{}). Build(), EventRecorder: record.NewFakeRecorder(32), Storage: storage, @@ -1594,12 +1594,12 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Name: "artifact", Namespace: "default", }, - Spec: helmv1.HelmChartSpec{}, + Spec: sourcev1.HelmChartSpec{}, } if tt.beforeFunc != nil { tt.beforeFunc(obj) @@ -1632,16 +1632,16 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { tests := []struct { name string build *chart.Build - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr bool assertConditions []metav1.Condition - afterFunc func(t *WithT, obj *helmv1.HelmChart) + afterFunc func(t *WithT, obj *sourcev1.HelmChart) }{ { name: "Incomplete build requeues and does not update status", build: &chart.Build{}, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, want: sreconcile.ResultRequeue, @@ -1652,10 +1652,10 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { { name: "Copying artifact to storage from build makes ArtifactInStorage=True", build: mockChartBuild("helmchart", "0.1.0", "testdata/charts/helmchart-0.1.0.tgz", nil), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.GetArtifact()).ToNot(BeNil()) t.Expect(obj.GetArtifact().Digest).To(Equal("sha256:bbdf96023c912c393b49d5238e227576ed0d20d1bb145d7476d817b80e20c11a")) t.Expect(obj.GetArtifact().Revision).To(Equal("0.1.0")) @@ -1665,7 +1665,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), }, }, { @@ -1675,13 +1675,13 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { Version: "0.1.0", Path: filepath.Join(testStorage.BasePath, "testdata/charts/helmchart-0.1.0.tgz"), }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{ Path: "testdata/charts/helmchart-0.1.0.tgz", } }, want: sreconcile.ResultSuccess, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.Status.Artifact.Path).To(Equal("testdata/charts/helmchart-0.1.0.tgz")) t.Expect(obj.Status.ObservedChartName).To(BeEmpty()) t.Expect(obj.Status.ObservedValuesFiles).To(BeNil()) @@ -1696,7 +1696,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { Path: filepath.Join(testStorage.BasePath, "testdata/charts/helmchart-0.1.0.tgz"), Packaged: true, }, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.ObservedChartName = "helmchart" obj.Status.Artifact = &sourcev1.Artifact{ Revision: "0.1.0", @@ -1704,21 +1704,21 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { } }, want: sreconcile.ResultSuccess, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.Status.Artifact.Path).To(Equal("testdata/charts/helmchart-0.1.0.tgz")) t.Expect(obj.Status.URL).To(BeEmpty()) }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPackageSucceededReason, "packaged 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPackageSucceededReason, "packaged 'helmchart' chart with version '0.1.0'"), }, }, { name: "Removes ArtifactOutdatedCondition after creating new artifact", build: mockChartBuild("helmchart", "0.1.0", "testdata/charts/helmchart-0.1.0.tgz", nil), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.GetArtifact()).ToNot(BeNil()) t.Expect(obj.GetArtifact().Digest).To(Equal("sha256:bbdf96023c912c393b49d5238e227576ed0d20d1bb145d7476d817b80e20c11a")) t.Expect(obj.GetArtifact().Revision).To(Equal("0.1.0")) @@ -1728,13 +1728,13 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), }, }, { name: "Creates latest symlink to the created artifact", build: mockChartBuild("helmchart", "0.1.0", "testdata/charts/helmchart-0.1.0.tgz", nil), - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.GetArtifact()).ToNot(BeNil()) localPath := testStorage.LocalPath(*obj.GetArtifact()) @@ -1745,7 +1745,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), }, }, { @@ -1797,19 +1797,19 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { r := &HelmChartReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmChart{}). + WithStatusSubresource(&sourcev1.HelmChart{}). Build(), EventRecorder: record.NewFakeRecorder(32), Storage: testStorage, patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "reconcile-artifact-", Generation: 1, }, - Status: helmv1.HelmChartStatus{}, + Status: sourcev1.HelmChartStatus{}, } if tt.beforeFunc != nil { tt.beforeFunc(obj) @@ -1835,10 +1835,10 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { func TestHelmChartReconciler_getSource(t *testing.T) { mocks := []client.Object{ - &helmv1.HelmRepository{ + &sourcev1.HelmRepository{ TypeMeta: metav1.TypeMeta{ - Kind: helmv1.HelmRepositoryKind, - APIVersion: helmv1.GroupVersion.String(), + Kind: sourcev1.HelmRepositoryKind, + APIVersion: sourcev1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "helmrepository", @@ -1855,10 +1855,10 @@ func TestHelmChartReconciler_getSource(t *testing.T) { Namespace: "foo", }, }, - &helmv1.Bucket{ + &sourcev1beta2.Bucket{ TypeMeta: metav1.TypeMeta{ - Kind: helmv1.BucketKind, - APIVersion: helmv1.GroupVersion.String(), + Kind: sourcev1beta2.BucketKind, + APIVersion: sourcev1beta2.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "bucket", @@ -1868,7 +1868,7 @@ func TestHelmChartReconciler_getSource(t *testing.T) { } clientBuilder := fakeclient.NewClientBuilder(). - WithStatusSubresource(&helmv1.HelmChart{}). + WithStatusSubresource(&sourcev1.HelmChart{}). WithObjects(mocks...) r := &HelmChartReconciler{ @@ -1878,18 +1878,18 @@ func TestHelmChartReconciler_getSource(t *testing.T) { tests := []struct { name string - obj *helmv1.HelmChart + obj *sourcev1.HelmChart want sourcev1.Source wantErr bool }{ { name: "Get HelmRepository source for reference", - obj: &helmv1.HelmChart{ + obj: &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Namespace: mocks[0].GetNamespace(), }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Name: mocks[0].GetName(), Kind: mocks[0].GetObjectKind().GroupVersionKind().Kind, }, @@ -1899,12 +1899,12 @@ func TestHelmChartReconciler_getSource(t *testing.T) { }, { name: "Get GitRepository source for reference", - obj: &helmv1.HelmChart{ + obj: &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Namespace: mocks[1].GetNamespace(), }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Name: mocks[1].GetName(), Kind: mocks[1].GetObjectKind().GroupVersionKind().Kind, }, @@ -1914,12 +1914,12 @@ func TestHelmChartReconciler_getSource(t *testing.T) { }, { name: "Get Bucket source for reference", - obj: &helmv1.HelmChart{ + obj: &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Namespace: mocks[2].GetNamespace(), }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Name: mocks[2].GetName(), Kind: mocks[2].GetObjectKind().GroupVersionKind().Kind, }, @@ -1929,12 +1929,12 @@ func TestHelmChartReconciler_getSource(t *testing.T) { }, { name: "Error on client error", - obj: &helmv1.HelmChart{ + obj: &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Namespace: mocks[2].GetNamespace(), }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Name: mocks[1].GetName(), Kind: mocks[2].GetObjectKind().GroupVersionKind().Kind, }, @@ -1944,9 +1944,9 @@ func TestHelmChartReconciler_getSource(t *testing.T) { }, { name: "Error on unsupported source kind", - obj: &helmv1.HelmChart{ - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ + obj: &sourcev1.HelmChart{ + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ Name: "unsupported", Kind: "Unsupported", }, @@ -1982,7 +1982,7 @@ func TestHelmChartReconciler_reconcileDelete(t *testing.T) { patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ Name: "reconcile-delete-", DeletionTimestamp: &metav1.Time{Time: time.Now()}, @@ -1990,10 +1990,10 @@ func TestHelmChartReconciler_reconcileDelete(t *testing.T) { sourcev1.SourceFinalizer, }, }, - Status: helmv1.HelmChartStatus{}, + Status: sourcev1.HelmChartStatus{}, } - artifact := testStorage.NewArtifactFor(helmv1.HelmChartKind, obj.GetObjectMeta(), "revision", "foo.txt") + artifact := testStorage.NewArtifactFor(sourcev1.HelmChartKind, obj.GetObjectMeta(), "revision", "foo.txt") obj.Status.Artifact = &artifact got, err := r.reconcileDelete(ctx, obj) @@ -2006,7 +2006,7 @@ func TestHelmChartReconciler_reconcileDelete(t *testing.T) { func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { // Helper to build simple helmChartReconcileFunc with result and error. buildReconcileFuncs := func(r sreconcile.Result, e error) helmChartReconcileFunc { - return func(_ context.Context, _ *patch.SerialPatcher, _ *helmv1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { + return func(_ context.Context, _ *patch.SerialPatcher, _ *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { return r, e } } @@ -2061,11 +2061,11 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { { name: "multiple object status conditions mutations", reconcileFuncs: []helmChartReconcileFunc{ - func(_ context.Context, _ *patch.SerialPatcher, obj *helmv1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { + func(_ context.Context, _ *patch.SerialPatcher, obj *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "new index revision") return sreconcile.ResultSuccess, nil }, - func(_ context.Context, _ *patch.SerialPatcher, obj *helmv1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { + func(_ context.Context, _ *patch.SerialPatcher, obj *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { conditions.MarkTrue(obj, meta.ReconcilingCondition, "Progressing", "creating artifact") return sreconcile.ResultSuccess, nil }, @@ -2115,16 +2115,16 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { r := &HelmChartReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmChart{}). + WithStatusSubresource(&sourcev1.HelmChart{}). Build(), patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Generation: tt.generation, }, - Status: helmv1.HelmChartStatus{ + Status: sourcev1.HelmChartStatus{ ObservedGeneration: tt.observedGeneration, }, } @@ -2171,13 +2171,13 @@ func mockChartBuild(name, version, path string, valuesFiles []string) *chart.Bui func TestHelmChartReconciler_statusConditions(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) assertConditions []metav1.Condition wantErr bool }{ { name: "positive conditions only", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "stored artifact for revision") }, assertConditions: []metav1.Condition{ @@ -2187,7 +2187,7 @@ func TestHelmChartReconciler_statusConditions(t *testing.T) { }, { name: "multiple failures", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get secret") conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, sourcev1.DirCreationFailedReason, "failed to create directory") conditions.MarkTrue(obj, sourcev1.BuildFailedCondition, "ChartPackageError", "some error") @@ -2204,7 +2204,7 @@ func TestHelmChartReconciler_statusConditions(t *testing.T) { }, { name: "mixed positive and negative conditions", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "stored artifact for revision") conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get secret") }, @@ -2221,10 +2221,10 @@ func TestHelmChartReconciler_statusConditions(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ TypeMeta: metav1.TypeMeta{ - Kind: helmv1.HelmChartKind, - APIVersion: helmv1.GroupVersion.String(), + Kind: sourcev1.HelmChartKind, + APIVersion: sourcev1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "helmchart", @@ -2234,7 +2234,7 @@ func TestHelmChartReconciler_statusConditions(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithObjects(obj). - WithStatusSubresource(&helmv1.HelmChart{}) + WithStatusSubresource(&sourcev1.HelmChart{}) c := clientBuilder.Build() @@ -2271,8 +2271,8 @@ func TestHelmChartReconciler_notify(t *testing.T) { name string res sreconcile.Result resErr error - oldObjBeforeFunc func(obj *helmv1.HelmChart) - newObjBeforeFunc func(obj *helmv1.HelmChart) + oldObjBeforeFunc func(obj *sourcev1.HelmChart) + newObjBeforeFunc func(obj *sourcev1.HelmChart) wantEvent string }{ { @@ -2284,7 +2284,7 @@ func TestHelmChartReconciler_notify(t *testing.T) { name: "new artifact", res: sreconcile.ResultSuccess, resErr: nil, - newObjBeforeFunc: func(obj *helmv1.HelmChart) { + newObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} }, wantEvent: "Normal ChartPackageSucceeded packaged", @@ -2293,12 +2293,12 @@ func TestHelmChartReconciler_notify(t *testing.T) { name: "recovery from failure", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmChart) { + oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *helmv1.HelmChart) { + newObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -2308,12 +2308,12 @@ func TestHelmChartReconciler_notify(t *testing.T) { name: "recovery and new artifact", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmChart) { + oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *helmv1.HelmChart) { + newObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -2323,11 +2323,11 @@ func TestHelmChartReconciler_notify(t *testing.T) { name: "no updates", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmChart) { + oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, - newObjBeforeFunc: func(obj *helmv1.HelmChart) { + newObjBeforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -2339,7 +2339,7 @@ func TestHelmChartReconciler_notify(t *testing.T) { g := NewWithT(t) recorder := record.NewFakeRecorder(32) - oldObj := &helmv1.HelmChart{} + oldObj := &sourcev1.HelmChart{} newObj := oldObj.DeepCopy() if tt.oldObjBeforeFunc != nil { @@ -2569,7 +2569,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmChart{}) + WithStatusSubresource(&sourcev1.HelmChart{}) workspaceDir := t.TempDir() @@ -2587,15 +2587,15 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) { metadata, err := loadTestChartToOCI(chartData, server, "testdata/certs/client.pem", "testdata/certs/client-key.pem", "testdata/certs/ca.pem") g.Expect(err).ToNot(HaveOccurred()) - repo := &helmv1.HelmRepository{ + repo := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "auth-strategy-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, - Type: helmv1.HelmRepositoryTypeOCI, - Provider: helmv1.GenericOCIProvider, + Type: sourcev1.HelmRepositoryTypeOCI, + Provider: sourcev1beta2.GenericOCIProvider, URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Insecure: tt.insecure, }, @@ -2632,15 +2632,15 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) { clientBuilder.WithObjects(repo) - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "auth-strategy-", }, - Spec: helmv1.HelmChartSpec{ + Spec: sourcev1.HelmChartSpec{ Chart: metadata.Name, Version: metadata.Version, - SourceRef: helmv1.LocalHelmChartSourceReference{ - Kind: helmv1.HelmRepositoryKind, + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, Name: repo.Name, }, Interval: metav1.Duration{Duration: interval}, @@ -2694,7 +2694,7 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t version string want sreconcile.Result wantErr bool - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) assertConditions []metav1.Condition revision string }{ @@ -2713,8 +2713,8 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t name: "signed image with correct subject and issuer should pass verification", version: "6.5.1", want: sreconcile.ResultSuccess, - beforeFunc: func(obj *helmv1.HelmChart) { - obj.Spec.Verify.MatchOIDCIdentity = []helmv1.OIDCIdentityMatch{ + beforeFunc: func(obj *sourcev1.HelmChart) { + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "^https://github.com/stefanprodan/podinfo.*$", @@ -2733,8 +2733,8 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t name: "signed image with incorrect and correct identity matchers should pass verification", version: "6.5.1", want: sreconcile.ResultSuccess, - beforeFunc: func(obj *helmv1.HelmChart) { - obj.Spec.Verify.MatchOIDCIdentity = []helmv1.OIDCIdentityMatch{ + beforeFunc: func(obj *sourcev1.HelmChart) { + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", Issuer: "^https://honeypot.com$", @@ -2758,8 +2758,8 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t version: "6.5.1", wantErr: true, want: sreconcile.ResultEmpty, - beforeFunc: func(obj *helmv1.HelmChart) { - obj.Spec.Verify.MatchOIDCIdentity = []helmv1.OIDCIdentityMatch{ + beforeFunc: func(obj *sourcev1.HelmChart) { + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", Issuer: "^https://honeypot.com$", @@ -2791,15 +2791,15 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t clientBuilder := fakeclient.NewClientBuilder() - repository := &helmv1.HelmRepository{ + repository := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: "oci://ghcr.io/stefanprodan/charts", Timeout: &metav1.Duration{Duration: timeout}, - Provider: helmv1.GenericOCIProvider, - Type: helmv1.HelmRepositoryTypeOCI, + Provider: sourcev1beta2.GenericOCIProvider, + Type: sourcev1.HelmRepositoryTypeOCI, }, } clientBuilder.WithObjects(repository) @@ -2813,18 +2813,18 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmchart-", }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ - Kind: helmv1.HelmRepositoryKind, + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, Name: repository.Name, }, Version: tt.version, Chart: "podinfo", - Verify: &helmv1.OCIRepositoryVerification{ + Verify: &sourcev1.OCIRepositoryVerification{ Provider: "cosign", }, }, @@ -2916,7 +2916,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t tests := []struct { name string shouldSign bool - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr bool wantErrMsg string @@ -2928,10 +2928,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t }{ { name: "unsigned charts should not pass verification", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "notation", SecretRef: &meta.LocalObjectReference{Name: "notation-config"}, } @@ -2947,10 +2947,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t { name: "signed charts should pass verification", shouldSign: true, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "notation", SecretRef: &meta.LocalObjectReference{Name: "notation-config"}, } @@ -2968,10 +2968,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t { name: "multiple certs should still pass verification", addMultipleCerts: true, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "notation", SecretRef: &meta.LocalObjectReference{Name: "notation-config"}, } @@ -2988,7 +2988,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t }, { name: "verify failed before, removed from spec, remove condition", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version obj.Spec.Verify = nil @@ -3007,10 +3007,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t }, { name: "no cert provided should not pass verification", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "notation", SecretRef: &meta.LocalObjectReference{Name: "notation-config"}, } @@ -3027,10 +3027,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t }, { name: "empty string should fail verification", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "notation", SecretRef: &meta.LocalObjectReference{Name: "notation-config"}, } @@ -3052,15 +3052,15 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t clientBuilder := fakeclient.NewClientBuilder() - repository := &helmv1.HelmRepository{ + repository := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: helmv1.GenericOCIProvider, - Type: helmv1.HelmRepositoryTypeOCI, + Provider: sourcev1beta2.GenericOCIProvider, + Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, } @@ -3112,13 +3112,13 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmchart-", }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ - Kind: helmv1.HelmRepositoryKind, + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, Name: repository.Name, }, }, @@ -3236,7 +3236,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes tests := []struct { name string shouldSign bool - beforeFunc func(obj *helmv1.HelmChart) + beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr bool wantErrMsg string @@ -3245,10 +3245,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes }{ { name: "unsigned charts should not pass verification", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "cosign", SecretRef: &meta.LocalObjectReference{Name: "cosign-key"}, } @@ -3263,10 +3263,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes }, { name: "unsigned charts should not pass keyless verification", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "cosign", } }, @@ -3280,10 +3280,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes { name: "signed charts should pass verification", shouldSign: true, - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Spec.Verify = &helmv1.OCIRepositoryVerification{ + obj.Spec.Verify = &sourcev1.OCIRepositoryVerification{ Provider: "cosign", SecretRef: &meta.LocalObjectReference{Name: "cosign-key"}, } @@ -3300,7 +3300,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes }, { name: "verify failed before, removed from spec, remove condition", - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version obj.Spec.Verify = nil @@ -3325,15 +3325,15 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes clientBuilder := fakeclient.NewClientBuilder() - repository := &helmv1.HelmRepository{ + repository := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: helmv1.GenericOCIProvider, - Type: helmv1.HelmRepositoryTypeOCI, + Provider: sourcev1beta2.GenericOCIProvider, + Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, } @@ -3357,13 +3357,13 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmChart{ + obj := &sourcev1.HelmChart{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmchart-", }, - Spec: helmv1.HelmChartSpec{ - SourceRef: helmv1.LocalHelmChartSourceReference{ - Kind: helmv1.HelmRepositoryKind, + Spec: sourcev1.HelmChartSpec{ + SourceRef: sourcev1.LocalHelmChartSourceReference{ + Kind: sourcev1.HelmRepositoryKind, Name: repository.Name, }, }, diff --git a/internal/controller/helmrepository_controller.go b/internal/controller/helmrepository_controller.go index d48b3c2f8..35bcfd08f 100644 --- a/internal/controller/helmrepository_controller.go +++ b/internal/controller/helmrepository_controller.go @@ -49,7 +49,6 @@ import ( rreconcile "github.com/fluxcd/pkg/runtime/reconcile" sourcev1 "github.com/fluxcd/source-controller/api/v1" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/cache" intdigest "github.com/fluxcd/source-controller/internal/digest" serror "github.com/fluxcd/source-controller/internal/error" @@ -61,7 +60,7 @@ import ( ) // helmRepositoryReadyCondition contains the information required to summarize a -// v1beta2.HelmRepository Ready Condition. +// v1.HelmRepository Ready Condition. var helmRepositoryReadyCondition = summarize.Conditions{ Target: meta.ReadyCondition, Owned: []string{ @@ -102,7 +101,7 @@ var helmRepositoryFailConditions = []string{ // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmrepositories/finalizers,verbs=get;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch -// HelmRepositoryReconciler reconciles a v1beta2.HelmRepository object. +// HelmRepositoryReconciler reconciles a v1.HelmRepository object. type HelmRepositoryReconciler struct { client.Client kuberecorder.EventRecorder @@ -124,10 +123,10 @@ type HelmRepositoryReconcilerOptions struct { } // helmRepositoryReconcileFunc is the function type for all the -// v1beta2.HelmRepository (sub)reconcile functions. The type implementations +// v1.HelmRepository (sub)reconcile functions. The type implementations // are grouped and executed serially to perform the complete reconcile of the // object. -type helmRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) +type helmRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) func (r *HelmRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error { return r.SetupWithManagerAndOptions(mgr, HelmRepositoryReconcilerOptions{}) @@ -137,7 +136,7 @@ func (r *HelmRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, r.patchOptions = getPatchOptions(helmRepositoryReadyCondition.Owned, r.ControllerName) return ctrl.NewControllerManagedBy(mgr). - For(&helmv1.HelmRepository{}). + For(&sourcev1.HelmRepository{}). WithEventFilter( predicate.And( intpredicates.HelmRepositoryOCIMigrationPredicate{}, @@ -155,7 +154,7 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque log := ctrl.LoggerFrom(ctx) // Fetch the HelmRepository - obj := &helmv1.HelmRepository{} + obj := &sourcev1.HelmRepository{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -164,7 +163,7 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque serialPatcher := patch.NewSerialPatcher(obj, r.Client) // If it's of type OCI, migrate the object to static. - if obj.Spec.Type == helmv1.HelmRepositoryTypeOCI { + if obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI { return r.migrationToStatic(ctx, serialPatcher, obj) } @@ -234,7 +233,7 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque // object. It returns early on the first call that returns // reconcile.ResultRequeue, or produces an error. func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, - obj *helmv1.HelmRepository, reconcilers []helmRepositoryReconcileFunc) (sreconcile.Result, error) { + obj *sourcev1.HelmRepository, reconcilers []helmRepositoryReconcileFunc) (sreconcile.Result, error) { oldObj := obj.DeepCopy() rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress") @@ -287,7 +286,7 @@ func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seri } // notify emits notification related to the reconciliation. -func (r *HelmRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *helmv1.HelmRepository, chartRepo *repository.ChartRepository, res sreconcile.Result, resErr error) { +func (r *HelmRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *sourcev1.HelmRepository, chartRepo *repository.ChartRepository, res sreconcile.Result, resErr error) { // Notify successful reconciliation for new artifact and recovery from any // failure. if resErr == nil && res == sreconcile.ResultSuccess && newObj.Status.Artifact != nil { @@ -331,7 +330,7 @@ func (r *HelmRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *h // The hostname of any URL in the Status of the object are updated, to ensure // they match the Storage server hostname of current runtime. func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, - obj *helmv1.HelmRepository, _ *sourcev1.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) { + obj *sourcev1.HelmRepository, _ *sourcev1.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -386,15 +385,15 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *pat } // reconcileSource attempts to fetch the Helm repository index using the -// specified configuration on the v1beta2.HelmRepository object. +// specified configuration on the v1.HelmRepository object. // -// When the fetch fails, it records v1beta2.FetchFailedCondition=True and +// When the fetch fails, it records v.FetchFailedCondition=True and // returns early. // If successful and the index is valid, any previous -// v1beta2.FetchFailedCondition is removed, and the repository.ChartRepository +// v1.FetchFailedCondition is removed, and the repository.ChartRepository // pointer is set to the newly fetched index. func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, - obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { + obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { // Ensure it's not an OCI URL. API validation ensures that only // http/https/oci scheme are allowed. if strings.HasPrefix(obj.Spec.URL, helmreg.OCIScheme) { @@ -483,7 +482,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc if err := chartRepo.LoadFromPath(); err != nil { e := serror.NewGeneric( fmt.Errorf("failed to load Helm repository from index YAML: %w", err), - helmv1.IndexationFailedReason, + sourcev1.IndexationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error()) return sreconcile.ResultEmpty, e @@ -496,7 +495,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc if revision.Validate() != nil { e := serror.NewGeneric( fmt.Errorf("failed to calculate revision: %w", err), - helmv1.IndexationFailedReason, + sourcev1.IndexationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error()) return sreconcile.ResultEmpty, e @@ -526,12 +525,12 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc // (Status) data on the object does not match the given. // // The inspection of the given data to the object is differed, ensuring any -// stale observations like v1beta2.ArtifactOutdatedCondition are removed. +// stale observations like v1.ArtifactOutdatedCondition are removed. // If the given Artifact does not differ from the object's current, it returns // early. // On a successful archive, the Artifact in the Status of the object is set, // and the symlink in the Storage is updated to its path. -func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { +func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { // Set the ArtifactInStorageCondition if there's no drift. defer func() { if obj.GetArtifact().HasRevision(artifact.Revision) { @@ -623,7 +622,7 @@ func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pa // reconcileDelete handles the deletion of the object. // It first garbage collects all Artifacts for the object from the Storage. // Removing the finalizer from the object if successful. -func (r *HelmRepositoryReconciler) reconcileDelete(ctx context.Context, obj *helmv1.HelmRepository) (sreconcile.Result, error) { +func (r *HelmRepositoryReconciler) reconcileDelete(ctx context.Context, obj *sourcev1.HelmRepository) (sreconcile.Result, error) { // Garbage collect the resource's artifacts if err := r.garbageCollect(ctx, obj); err != nil { // Return the error so we retry the failed garbage collection @@ -651,8 +650,8 @@ func (r *HelmRepositoryReconciler) reconcileDelete(ctx context.Context, obj *hel // - the deletion timestamp on the object is set // - the obj.Spec.Type has changed and artifacts are not supported by the new type // Which will result in the removal of all Artifacts for the objects. -func (r *HelmRepositoryReconciler) garbageCollect(ctx context.Context, obj *helmv1.HelmRepository) error { - if !obj.DeletionTimestamp.IsZero() || (obj.Spec.Type != "" && obj.Spec.Type != helmv1.HelmRepositoryTypeDefault) { +func (r *HelmRepositoryReconciler) garbageCollect(ctx context.Context, obj *sourcev1.HelmRepository) error { + if !obj.DeletionTimestamp.IsZero() || (obj.Spec.Type != "" && obj.Spec.Type != sourcev1.HelmRepositoryTypeDefault) { if deleted, err := r.Storage.RemoveAll(r.Storage.NewArtifactFor(obj.Kind, obj.GetObjectMeta(), "", "*")); err != nil { return serror.NewGeneric( fmt.Errorf("garbage collection for deleted resource failed: %w", err), @@ -703,7 +702,7 @@ func (r *HelmRepositoryReconciler) eventLogf(ctx context.Context, obj runtime.Ob } // migrateToStatic is HelmRepository OCI migration to static object. -func (r *HelmRepositoryReconciler) migrationToStatic(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository) (result ctrl.Result, err error) { +func (r *HelmRepositoryReconciler) migrationToStatic(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository) (result ctrl.Result, err error) { // Skip migration if suspended and not being deleted. if obj.Spec.Suspend && obj.DeletionTimestamp.IsZero() { return ctrl.Result{}, nil @@ -721,7 +720,7 @@ func (r *HelmRepositoryReconciler) migrationToStatic(ctx context.Context, sp *pa } // Delete finalizer and reset the status. controllerutil.RemoveFinalizer(obj, sourcev1.SourceFinalizer) - obj.Status = helmv1.HelmRepositoryStatus{} + obj.Status = sourcev1.HelmRepositoryStatus{} if err := sp.Patch(ctx, obj); err != nil { return ctrl.Result{}, err diff --git a/internal/controller/helmrepository_controller_test.go b/internal/controller/helmrepository_controller_test.go index 0da154a15..9724baf65 100644 --- a/internal/controller/helmrepository_controller_test.go +++ b/internal/controller/helmrepository_controller_test.go @@ -50,7 +50,6 @@ import ( "github.com/fluxcd/pkg/runtime/patch" sourcev1 "github.com/fluxcd/source-controller/api/v1" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/cache" intdigest "github.com/fluxcd/source-controller/internal/digest" "github.com/fluxcd/source-controller/internal/helm/getter" @@ -73,10 +72,10 @@ func TestHelmRepositoryReconciler_deleteBeforeFinalizer(t *testing.T) { g.Expect(k8sClient.Delete(ctx, namespace)).NotTo(HaveOccurred()) }) - helmrepo := &helmv1.HelmRepository{} + helmrepo := &sourcev1.HelmRepository{} helmrepo.Name = "test-helmrepo" helmrepo.Namespace = namespaceName - helmrepo.Spec = helmv1.HelmRepositorySpec{ + helmrepo.Spec = sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, URL: "https://example.com", } @@ -109,12 +108,12 @@ func TestHelmRepositoryReconciler_Reconcile(t *testing.T) { testServer.Start() defer testServer.Stop() - origObj := &helmv1.HelmRepository{ + origObj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-reconcile-", Namespace: "default", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, URL: testServer.URL(), }, @@ -175,7 +174,7 @@ func TestHelmRepositoryReconciler_Reconcile(t *testing.T) { func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *helmv1.HelmRepository, storage *Storage) error + beforeFunc func(obj *sourcev1.HelmRepository, storage *Storage) error want sreconcile.Result wantErr bool assertArtifact *sourcev1.Artifact @@ -184,7 +183,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }{ { name: "garbage collects", - beforeFunc: func(obj *helmv1.HelmRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmRepository, storage *Storage) error { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] @@ -234,7 +233,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }, { name: "notices missing artifact in storage", - beforeFunc: func(obj *helmv1.HelmRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmRepository, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "d", @@ -253,7 +252,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }, { name: "notices empty artifact digest", - beforeFunc: func(obj *helmv1.HelmRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmRepository, storage *Storage) error { f := "empty-digest.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -284,7 +283,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }, { name: "notices artifact digest mismatch", - beforeFunc: func(obj *helmv1.HelmRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmRepository, storage *Storage) error { f := "digest-mismatch.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -315,7 +314,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }, { name: "updates hostname on diff from current", - beforeFunc: func(obj *helmv1.HelmRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.HelmRepository, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", @@ -354,14 +353,14 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { r := &HelmRepositoryReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmRepository{}). + WithStatusSubresource(&sourcev1.HelmRepository{}). Build(), EventRecorder: record.NewFakeRecorder(32), Storage: testStorage, patchOptions: getPatchOptions(helmRepositoryReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Generation: 1, @@ -421,8 +420,8 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { server options url string secret *corev1.Secret - beforeFunc func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) - afterFunc func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) + beforeFunc func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) + afterFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) want sreconcile.Result wantErr bool assertConditions []metav1.Condition @@ -440,7 +439,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "ca.crt": tlsCA, }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.CertSecretRef = &meta.LocalObjectReference{Name: "ca-file"} }, assertConditions: []metav1.Condition{ @@ -464,7 +463,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "ca.crt": tlsCA, }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.CertSecretRef = &meta.LocalObjectReference{Name: "ca-file"} }, want: sreconcile.ResultSuccess, @@ -472,7 +471,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -494,7 +493,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "caFile": tlsCA, }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "ca-file"} }, want: sreconcile.ResultSuccess, @@ -502,7 +501,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -526,7 +525,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { }, Type: corev1.SecretTypeDockerConfigJson, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "ca-file"} }, want: sreconcile.ResultSuccess, @@ -534,7 +533,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -548,7 +547,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -570,7 +569,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "password": []byte("1234"), }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "basic-auth"} }, want: sreconcile.ResultSuccess, @@ -578,7 +577,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -602,7 +601,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { }, Type: corev1.SecretTypeDockerConfigJson, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "basic-auth"} }, want: sreconcile.ResultSuccess, @@ -610,7 +609,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -632,7 +631,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "ca.crt": []byte("invalid"), }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.CertSecretRef = &meta.LocalObjectReference{Name: "invalid-ca"} conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") @@ -643,7 +642,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -653,7 +652,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Invalid URL makes FetchFailed=True and returns stalling error", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.URL = strings.ReplaceAll(obj.Spec.URL, "http://", "") conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") @@ -665,7 +664,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -675,7 +674,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Unsupported scheme makes FetchFailed=True and returns stalling error", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.URL = strings.ReplaceAll(obj.Spec.URL, "http://", "ftp://") conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") @@ -687,7 +686,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -697,7 +696,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Missing secret returns FetchFailed=True and returns error", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "non-existing"} conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") @@ -708,7 +707,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -726,7 +725,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { "username": []byte("git"), }, }, - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "malformed-basic-auth"} conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") @@ -737,7 +736,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -747,7 +746,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Stored index with same revision", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Status.Artifact = &sourcev1.Artifact{ Revision: rev.String(), } @@ -760,7 +759,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -771,7 +770,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Stored index with different revision", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Status.Artifact = &sourcev1.Artifact{ Revision: "80bb3dd67c63095d985850459834ea727603727a370079de90d221191d375a86", } @@ -784,7 +783,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) @@ -796,7 +795,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { { name: "Existing artifact makes ArtifactOutdated=True", protocol: "http", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, rev digest.Digest) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, rev digest.Digest) { obj.Status.Artifact = &sourcev1.Artifact{ Path: "some-path", Revision: "some-rev", @@ -812,12 +811,12 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { } for _, tt := range tests { - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "auth-strategy-", Generation: 1, }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, }, @@ -868,7 +867,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmRepository{}) + WithStatusSubresource(&sourcev1.HelmRepository{}) if secret != nil { clientBuilder.WithObjects(secret.DeepCopy()) @@ -960,19 +959,19 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { tests := []struct { name string cache *cache.Cache - beforeFunc func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) - afterFunc func(t *WithT, obj *helmv1.HelmRepository, cache *cache.Cache) + beforeFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) + afterFunc func(t *WithT, obj *sourcev1.HelmRepository, cache *cache.Cache) want sreconcile.Result wantErr bool assertConditions []metav1.Condition }{ { name: "Archiving artifact to storage makes ArtifactInStorage=True and artifact is stored as JSON", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} }, want: sreconcile.ResultSuccess, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, cache *cache.Cache) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, cache *cache.Cache) { localPath := testStorage.LocalPath(*obj.GetArtifact()) b, err := os.ReadFile(localPath) t.Expect(err).To(Not(HaveOccurred())) @@ -985,7 +984,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { { name: "Archiving (loaded) artifact to storage adds to cache", cache: cache.New(10, time.Minute), - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { index.Index = &repo.IndexFile{ APIVersion: "v1", Generated: time.Now(), @@ -993,7 +992,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { obj.Spec.Interval = metav1.Duration{Duration: interval} }, want: sreconcile.ResultSuccess, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, cache *cache.Cache) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, cache *cache.Cache) { i, ok := cache.Get(obj.GetArtifact().Path) t.Expect(ok).To(BeTrue()) t.Expect(i).To(BeAssignableToTypeOf(&repo.IndexFile{})) @@ -1004,11 +1003,11 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Up-to-date artifact should not update status", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} obj.Status.Artifact = artifact.DeepCopy() }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, _ *cache.Cache) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, _ *cache.Cache) { t.Expect(obj.Status.URL).To(BeEmpty()) }, want: sreconcile.ResultSuccess, @@ -1018,7 +1017,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Removes ArtifactOutdatedCondition after creating a new artifact", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, @@ -1029,10 +1028,10 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Creates latest symlink to the created artifact", - beforeFunc: func(t *WithT, obj *helmv1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} }, - afterFunc: func(t *WithT, obj *helmv1.HelmRepository, _ *cache.Cache) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, _ *cache.Cache) { localPath := testStorage.LocalPath(*obj.GetArtifact()) symlinkPath := filepath.Join(filepath.Dir(localPath), "index.yaml") targetFile, err := os.Readlink(symlinkPath) @@ -1053,7 +1052,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { r := &HelmRepositoryReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmRepository{}). + WithStatusSubresource(&sourcev1.HelmRepository{}). Build(), EventRecorder: record.NewFakeRecorder(32), Storage: testStorage, @@ -1062,16 +1061,16 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { patchOptions: getPatchOptions(helmRepositoryReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ TypeMeta: metav1.TypeMeta{ - Kind: helmv1.HelmRepositoryKind, + Kind: sourcev1.HelmRepositoryKind, }, ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-bucket-", Generation: 1, Namespace: "default", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Timeout: &metav1.Duration{Duration: timeout}, URL: "https://example.com/index.yaml", }, @@ -1111,7 +1110,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { // Helper to build simple helmRepositoryReconcileFunc with result and error. buildReconcileFuncs := func(r sreconcile.Result, e error) helmRepositoryReconcileFunc { - return func(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + return func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { return r, e } } @@ -1166,11 +1165,11 @@ func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { { name: "multiple object status conditions mutations", reconcileFuncs: []helmRepositoryReconcileFunc{ - func(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "new index revision") return sreconcile.ResultSuccess, nil }, - func(ctx context.Context, sp *patch.SerialPatcher, obj *helmv1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { conditions.MarkTrue(obj, meta.ReconcilingCondition, meta.ProgressingReason, "creating artifact") return sreconcile.ResultSuccess, nil }, @@ -1220,16 +1219,16 @@ func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { r := &HelmRepositoryReconciler{ Client: fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&helmv1.HelmRepository{}). + WithStatusSubresource(&sourcev1.HelmRepository{}). Build(), patchOptions: getPatchOptions(helmRepositoryReadyCondition.Owned, "sc"), } - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Generation: tt.generation, }, - Status: helmv1.HelmRepositoryStatus{ + Status: sourcev1.HelmRepositoryStatus{ ObservedGeneration: tt.observedGeneration, }, } @@ -1254,13 +1253,13 @@ func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { func TestHelmRepositoryReconciler_statusConditions(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *helmv1.HelmRepository) + beforeFunc func(obj *sourcev1.HelmRepository) assertConditions []metav1.Condition wantErr bool }{ { name: "positive conditions only", - beforeFunc: func(obj *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmRepository) { conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "stored artifact for revision") }, assertConditions: []metav1.Condition{ @@ -1271,7 +1270,7 @@ func TestHelmRepositoryReconciler_statusConditions(t *testing.T) { }, { name: "multiple failures", - beforeFunc: func(obj *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmRepository) { conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get secret") conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, sourcev1.DirCreationFailedReason, "failed to create directory") conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "some error") @@ -1286,7 +1285,7 @@ func TestHelmRepositoryReconciler_statusConditions(t *testing.T) { }, { name: "mixed positive and negative conditions", - beforeFunc: func(obj *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmRepository) { conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "stored artifact for revision") conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get secret") }, @@ -1303,10 +1302,10 @@ func TestHelmRepositoryReconciler_statusConditions(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ TypeMeta: metav1.TypeMeta{ - Kind: helmv1.HelmRepositoryKind, - APIVersion: helmv1.GroupVersion.String(), + Kind: sourcev1.HelmRepositoryKind, + APIVersion: sourcev1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "helmrepo", @@ -1316,7 +1315,7 @@ func TestHelmRepositoryReconciler_statusConditions(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithObjects(obj). - WithStatusSubresource(&helmv1.HelmRepository{}) + WithStatusSubresource(&sourcev1.HelmRepository{}) c := clientBuilder.Build() @@ -1351,8 +1350,8 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name string res sreconcile.Result resErr error - oldObjBeforeFunc func(obj *helmv1.HelmRepository) - newObjBeforeFunc func(obj *helmv1.HelmRepository) + oldObjBeforeFunc func(obj *sourcev1.HelmRepository) + newObjBeforeFunc func(obj *sourcev1.HelmRepository) wantEvent string }{ { @@ -1364,7 +1363,7 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name: "new artifact with nil size", res: sreconcile.ResultSuccess, resErr: nil, - newObjBeforeFunc: func(obj *helmv1.HelmRepository) { + newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: nil} }, wantEvent: "Normal NewArtifact stored fetched index of unknown size", @@ -1373,7 +1372,7 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name: "new artifact", res: sreconcile.ResultSuccess, resErr: nil, - newObjBeforeFunc: func(obj *helmv1.HelmRepository) { + newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} }, wantEvent: "Normal NewArtifact stored fetched index of size", @@ -1382,12 +1381,12 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name: "recovery from failure", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmRepository) { + oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *helmv1.HelmRepository) { + newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -1397,12 +1396,12 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name: "recovery and new artifact", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmRepository) { + oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *helmv1.HelmRepository) { + newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -1412,11 +1411,11 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { name: "no updates", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *helmv1.HelmRepository) { + oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, - newObjBeforeFunc: func(obj *helmv1.HelmRepository) { + newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -1428,7 +1427,7 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { g := NewWithT(t) recorder := record.NewFakeRecorder(32) - oldObj := &helmv1.HelmRepository{} + oldObj := &sourcev1.HelmRepository{} newObj := oldObj.DeepCopy() if tt.oldObjBeforeFunc != nil { @@ -1475,12 +1474,12 @@ func TestHelmRepositoryReconciler_ReconcileTypeUpdatePredicateFilter(t *testing. testServer.Start() defer testServer.Stop() - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-reconcile-", Namespace: "default", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, URL: testServer.URL(), }, @@ -1524,7 +1523,7 @@ func TestHelmRepositoryReconciler_ReconcileTypeUpdatePredicateFilter(t *testing. g.Expect(res.Status).To(Equal(kstatus.CurrentStatus)) // Switch to a OCI helm repository type - obj.Spec.Type = helmv1.HelmRepositoryTypeOCI + obj.Spec.Type = sourcev1.HelmRepositoryTypeOCI obj.Spec.URL = fmt.Sprintf("oci://%s", testRegistryServer.registryHost) oldGen := obj.GetGeneration() @@ -1564,12 +1563,12 @@ func TestHelmRepositoryReconciler_ReconcileSpecUpdatePredicateFilter(t *testing. testServer.Start() defer testServer.Stop() - obj := &helmv1.HelmRepository{ + obj := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-reconcile-", Namespace: "default", }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ Interval: metav1.Duration{Duration: interval}, URL: testServer.URL(), }, @@ -1666,12 +1665,12 @@ func TestHelmRepositoryReconciler_InMemoryCaching(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - helmRepo := &helmv1.HelmRepository{ + helmRepo := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "helmrepository-", Namespace: ns.Name, }, - Spec: helmv1.HelmRepositorySpec{ + Spec: sourcev1.HelmRepositorySpec{ URL: testServer.URL(), }, } @@ -1725,7 +1724,7 @@ func TestHelmRepositoryReconciler_ociMigration(t *testing.T) { g.Expect(testEnv.Cleanup(ctx, testns)).ToNot(HaveOccurred()) }) - hr := &helmv1.HelmRepository{ + hr := &sourcev1.HelmRepository{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("hr-%s", randStringRunes(5)), Namespace: testns.Name, @@ -1736,8 +1735,8 @@ func TestHelmRepositoryReconciler_ociMigration(t *testing.T) { // Migrates newly created object with finalizer. hr.ObjectMeta.Finalizers = append(hr.ObjectMeta.Finalizers, "foo.bar", sourcev1.SourceFinalizer) - hr.Spec = helmv1.HelmRepositorySpec{ - Type: helmv1.HelmRepositoryTypeOCI, + hr.Spec = sourcev1.HelmRepositorySpec{ + Type: sourcev1.HelmRepositoryTypeOCI, URL: "oci://foo/bar", Interval: metav1.Duration{Duration: interval}, } diff --git a/internal/controller/ocirepository_controller_test.go b/internal/controller/ocirepository_controller_test.go index d136efd22..0e9f89885 100644 --- a/internal/controller/ocirepository_controller_test.go +++ b/internal/controller/ocirepository_controller_test.go @@ -1393,7 +1393,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, Spec: ociv1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - Verify: &ociv1.OCIRepositoryVerification{ + Verify: &sourcev1.OCIRepositoryVerification{ Provider: "notation", }, Interval: metav1.Duration{Duration: interval}, @@ -1713,7 +1713,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, Spec: ociv1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - Verify: &ociv1.OCIRepositoryVerification{ + Verify: &sourcev1.OCIRepositoryVerification{ Provider: "notation", }, Interval: metav1.Duration{Duration: interval}, @@ -2037,7 +2037,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, Spec: ociv1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - Verify: &ociv1.OCIRepositoryVerification{ + Verify: &sourcev1.OCIRepositoryVerification{ Provider: "cosign", }, Interval: metav1.Duration{Duration: interval}, @@ -2159,7 +2159,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, want: sreconcile.ResultSuccess, beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.Verify.MatchOIDCIdentity = []ociv1.OIDCIdentityMatch{ + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "^https://github.com/stefanprodan/podinfo.*$", @@ -2181,7 +2181,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, want: sreconcile.ResultSuccess, beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.Verify.MatchOIDCIdentity = []ociv1.OIDCIdentityMatch{ + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", Issuer: "^https://honeypot.com$", @@ -2208,7 +2208,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi wantErr: true, want: sreconcile.ResultEmpty, beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.Verify.MatchOIDCIdentity = []ociv1.OIDCIdentityMatch{ + obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", Issuer: "^https://honeypot.com$", @@ -2260,7 +2260,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, Spec: ociv1.OCIRepositorySpec{ URL: "oci://ghcr.io/stefanprodan/manifests/podinfo", - Verify: &ociv1.OCIRepositoryVerification{ + Verify: &sourcev1.OCIRepositoryVerification{ Provider: "cosign", }, Interval: metav1.Duration{Duration: interval}, diff --git a/internal/helm/getter/client_opts.go b/internal/helm/getter/client_opts.go index 58477ca70..c305b7385 100644 --- a/internal/helm/getter/client_opts.go +++ b/internal/helm/getter/client_opts.go @@ -32,7 +32,8 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/helm/registry" soci "github.com/fluxcd/source-controller/internal/oci" stls "github.com/fluxcd/source-controller/internal/tls" @@ -69,7 +70,7 @@ func (o ClientOpts) MustLoginToRegistry() bool { // auth mechanisms. // A temporary directory is created to store the certs files if needed and its path is returned along with the options object. It is the // caller's responsibility to clean up the directory. -func GetClientOpts(ctx context.Context, c client.Client, obj *helmv1.HelmRepository, url string) (*ClientOpts, string, error) { +func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) { hrOpts := &ClientOpts{ GetterOpts: []helmgetter.Option{ helmgetter.WithURL(url), @@ -77,7 +78,7 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *helmv1.HelmReposit helmgetter.WithPassCredentialsAll(obj.Spec.PassCredentials), }, } - ociRepo := obj.Spec.Type == helmv1.HelmRepositoryTypeOCI + ociRepo := obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI var ( certSecret *corev1.Secret @@ -135,7 +136,7 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *helmv1.HelmReposit return nil, "", fmt.Errorf("failed to configure login options: %w", err) } } - } else if obj.Spec.Provider != helmv1.GenericOCIProvider && obj.Spec.Type == helmv1.HelmRepositoryTypeOCI && ociRepo { + } else if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo { authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider) if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) { return nil, "", fmt.Errorf("failed to get credential from '%s': %w", obj.Spec.Provider, authErr) diff --git a/internal/helm/getter/client_opts_test.go b/internal/helm/getter/client_opts_test.go index f8acd79fb..b8bf15f28 100644 --- a/internal/helm/getter/client_opts_test.go +++ b/internal/helm/getter/client_opts_test.go @@ -29,7 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" - helmv1 "github.com/fluxcd/source-controller/api/v1beta2" + helmv1 "github.com/fluxcd/source-controller/api/v1" ) func TestGetClientOpts(t *testing.T) { diff --git a/internal/predicates/helmrepository_type_predicate.go b/internal/predicates/helmrepository_type_predicate.go index cc7c8fc7e..714d77942 100644 --- a/internal/predicates/helmrepository_type_predicate.go +++ b/internal/predicates/helmrepository_type_predicate.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" ) // HelmRepositoryOCIMigrationPredicate implements predicate functions to allow diff --git a/internal/predicates/helmrepository_type_predicate_test.go b/internal/predicates/helmrepository_type_predicate_test.go index 0d3489d1f..643e823e7 100644 --- a/internal/predicates/helmrepository_type_predicate_test.go +++ b/internal/predicates/helmrepository_type_predicate_test.go @@ -25,8 +25,7 @@ import ( "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/conditions" - v1 "github.com/fluxcd/source-controller/api/v1" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" ) func TestHelmRepositoryOCIMigrationPredicate_Create(t *testing.T) { @@ -161,7 +160,7 @@ func TestHelmRepositoryOCIMigrationPredicate_Update(t *testing.T) { Type: sourcev1.HelmRepositoryTypeDefault, } oldObj.Status = sourcev1.HelmRepositoryStatus{ - Artifact: &v1.Artifact{}, + Artifact: &sourcev1.Artifact{}, URL: "http://some-address", ObservedGeneration: 3, } diff --git a/main.go b/main.go index e2bd08efb..a0abb7c8c 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,7 @@ import ( "github.com/fluxcd/pkg/runtime/pprof" "github.com/fluxcd/pkg/runtime/probes" - v1 "github.com/fluxcd/source-controller/api/v1" + "github.com/fluxcd/source-controller/api/v1" "github.com/fluxcd/source-controller/api/v1beta2" // +kubebuilder:scaffold:imports @@ -199,7 +199,7 @@ func main() { DependencyRequeueInterval: requeueDependency, RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1beta2.GitRepositoryKind) + setupLog.Error(err, "unable to create controller", "controller", v1.GitRepositoryKind) os.Exit(1) } @@ -216,7 +216,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.HelmRepositoryReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1beta2.HelmRepositoryKind) + setupLog.Error(err, "unable to create controller", "controller", v1.HelmRepositoryKind) os.Exit(1) } @@ -234,7 +234,7 @@ func main() { }).SetupWithManagerAndOptions(ctx, mgr, controller.HelmChartReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1beta2.HelmChartKind) + setupLog.Error(err, "unable to create controller", "controller", v1.HelmChartKind) os.Exit(1) } @@ -247,7 +247,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.BucketReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Bucket") + setupLog.Error(err, "unable to create controller", "controller", v1beta2.BucketKind) os.Exit(1) } @@ -260,7 +260,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.OCIRepositoryReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "OCIRepository") + setupLog.Error(err, "unable to create controller", "controller", v1beta2.OCIRepositoryKind) os.Exit(1) } // +kubebuilder:scaffold:builder @@ -348,11 +348,11 @@ func mustSetupManager(metricsAddr, healthAddr string, maxConcurrent int, }, Cache: ctrlcache.Options{ ByObject: map[ctrlclient.Object]ctrlcache.ByObject{ - &v1.GitRepository{}: {Label: watchSelector}, - &v1beta2.HelmRepository{}: {Label: watchSelector}, - &v1beta2.HelmChart{}: {Label: watchSelector}, - &v1beta2.Bucket{}: {Label: watchSelector}, - &v1beta2.OCIRepository{}: {Label: watchSelector}, + &v1.GitRepository{}: {Label: watchSelector}, + &v1.HelmRepository{}: {Label: watchSelector}, + &v1.HelmChart{}: {Label: watchSelector}, + &v1beta2.Bucket{}: {Label: watchSelector}, + &v1beta2.OCIRepository{}: {Label: watchSelector}, }, }, Metrics: metricsserver.Options{ From 0a7f66b0e3186a2773351684f4b1a9651cdd23c3 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Apr 2024 17:42:04 +0300 Subject: [PATCH 2/7] docs: Add API spec for Helm v1 Signed-off-by: Stefan Prodan --- README.md | 14 +- api/v1/helmchart_types.go | 11 + api/v1/zz_generated.deepcopy.go | 5 + .../source.toolkit.fluxcd.io_helmcharts.yaml | 13 + docs/api/v1/source.md | 40 + docs/spec/v1/README.md | 2 + docs/spec/v1/helmcharts.md | 865 +++++++++++++++++ docs/spec/v1/helmrepositories.md | 914 ++++++++++++++++++ .../controller/helmchart_controller_test.go | 28 +- 9 files changed, 1871 insertions(+), 21 deletions(-) create mode 100644 docs/spec/v1/helmcharts.md create mode 100644 docs/spec/v1/helmrepositories.md diff --git a/README.md b/README.md index ee43f8e0c..393d35169 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ and is a core component of the [GitOps toolkit](https://fluxcd.io/flux/component ## APIs -| Kind | API Version | -|---------------------------------------------------------|------------------------------------| -| [GitRepository](docs/spec/v1/gitrepositories.md) | `source.toolkit.fluxcd.io/v1` | -| [OCIRepository](docs/spec/v1beta2/ocirepositories.md) | `source.toolkit.fluxcd.io/v1beta2` | -| [HelmRepository](docs/spec/v1beta2/helmrepositories.md) | `source.toolkit.fluxcd.io/v1beta2` | -| [HelmChart](docs/spec/v1beta2/helmcharts.md) | `source.toolkit.fluxcd.io/v1beta2` | -| [Bucket](docs/spec/v1beta2/buckets.md) | `source.toolkit.fluxcd.io/v1beta2` | +| Kind | API Version | +|-------------------------------------------------------|------------------------------------| +| [GitRepository](docs/spec/v1/gitrepositories.md) | `source.toolkit.fluxcd.io/v1` | +| [OCIRepository](docs/spec/v1beta2/ocirepositories.md) | `source.toolkit.fluxcd.io/v1beta2` | +| [HelmRepository](docs/spec/v1/helmrepositories.md) | `source.toolkit.fluxcd.io/v1` | +| [HelmChart](docs/spec/v1/helmcharts.md) | `source.toolkit.fluxcd.io/v1` | +| [Bucket](docs/spec/v1beta2/buckets.md) | `source.toolkit.fluxcd.io/v1beta2` | ## Features diff --git a/api/v1/helmchart_types.go b/api/v1/helmchart_types.go index c01700c29..1527e6bc9 100644 --- a/api/v1/helmchart_types.go +++ b/api/v1/helmchart_types.go @@ -78,6 +78,11 @@ type HelmChartSpec struct { // +deprecated ValuesFile string `json:"valuesFile,omitempty"` + // IgnoreMissingValuesFiles controls whether to silently ignore missing values + // files rather than failing. + // +optional + IgnoreMissingValuesFiles bool `json:"ignoreMissingValuesFiles,omitempty"` + // Suspend tells the controller to suspend the reconciliation of this // source. // +optional @@ -141,6 +146,12 @@ type HelmChartStatus struct { // +optional ObservedChartName string `json:"observedChartName,omitempty"` + // ObservedValuesFiles are the observed value files of the last successful + // reconciliation. + // It matches the chart in the last successfully reconciled artifact. + // +optional + ObservedValuesFiles []string `json:"observedValuesFiles,omitempty"` + // Conditions holds the conditions for the HelmChart. // +optional Conditions []metav1.Condition `json:"conditions,omitempty"` diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 6ef308061..38f4c41e3 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -360,6 +360,11 @@ func (in *HelmChartSpec) DeepCopy() *HelmChartSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HelmChartStatus) DeepCopyInto(out *HelmChartStatus) { *out = *in + if in.ObservedValuesFiles != nil { + in, out := &in.ObservedValuesFiles, &out.ObservedValuesFiles + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]metav1.Condition, len(*in)) diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 7f69d4347..45591d54a 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -745,6 +745,11 @@ spec: Chart is the name or path the Helm chart is available at in the SourceRef. type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean interval: description: |- Interval at which the HelmChart SourceRef is checked for updates. @@ -1020,6 +1025,14 @@ spec: ObservedSourceArtifactRevision is the last observed Artifact.Revision of the HelmChartSpec.SourceRef. type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array url: description: |- URL is the dynamic fetch link for the latest Artifact. diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index 547572b5e..3746ad76c 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -408,6 +408,19 @@ is merged before the ValuesFiles items. Ignored when omitted.

+ignoreMissingValuesFiles
+ +bool + + + +(Optional) +

IgnoreMissingValuesFiles controls whether to silently ignore missing values +files rather than failing.

+ + + + suspend
bool @@ -1492,6 +1505,19 @@ is merged before the ValuesFiles items. Ignored when omitted.

+ignoreMissingValuesFiles
+ +bool + + + +(Optional) +

IgnoreMissingValuesFiles controls whether to silently ignore missing values +files rather than failing.

+ + + + suspend
bool @@ -1599,6 +1625,20 @@ resolved chart reference.

+observedValuesFiles
+ +[]string + + + +(Optional) +

ObservedValuesFiles are the observed value files of the last successful +reconciliation. +It matches the chart in the last successfully reconciled artifact.

+ + + + conditions
diff --git a/docs/spec/v1/README.md b/docs/spec/v1/README.md index ae989ceb0..a87051a52 100644 --- a/docs/spec/v1/README.md +++ b/docs/spec/v1/README.md @@ -6,6 +6,8 @@ This is the v1 API specification for defining the desired state sources of Kuber * Source kinds: + [GitRepository](gitrepositories.md) + + [HelmRepository](helmrepositories.md) + + [HelmChart](helmcharts.md) ## Implementation diff --git a/docs/spec/v1/helmcharts.md b/docs/spec/v1/helmcharts.md new file mode 100644 index 000000000..eae4d5b9c --- /dev/null +++ b/docs/spec/v1/helmcharts.md @@ -0,0 +1,865 @@ +# Helm Charts + + + +The `HelmChart` API defines a Source to produce an Artifact for a Helm chart +archive with a set of specific configurations. + +## Example + +The following is an example of a HelmChart. It fetches and/or packages a Helm +chart and exposes it as a tarball (`.tgz`) Artifact for the specified +configuration: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: podinfo + namespace: default +spec: + interval: 5m0s + chart: podinfo + reconcileStrategy: ChartVersion + sourceRef: + kind: HelmRepository + name: podinfo + version: '5.*' +``` + +In the above example: + +- A HelmChart named `podinfo` is created, indicated by the `.metadata.name` + field. +- The source-controller fetches the Helm chart every five minutes from the + `podinfo` HelmRepository source reference, indicated by the + `.spec.sourceRef.kind` and `.spec.sourceRef.name` fields. +- The fetched Helm chart version is the latest available chart + version in the range specified in `spec.version`. This version is also used as + Artifact revision, reported in-cluster in the `.status.artifact.revision` + field. +- When the current Helm Chart version differs from the latest available chart + in the version range, it is fetched and/or packaged as a new Artifact. +- The new Artifact is reported in the `.status.artifact` field. + +You can run this example by saving the manifest into `helmchart.yaml`. + +**Note:** HelmChart is usually used by the helm-controller. Based on the +HelmRelease configuration, an associated HelmChart is created by the +helm-controller. + +1. Apply the resource on the cluster: + + ```sh + kubectl apply -f helmchart.yaml + ``` + +2. Run `kubectl get helmchart` to see the HelmChart: + + ```console + NAME CHART VERSION SOURCE KIND SOURCE NAME AGE READY STATUS + podinfo podinfo 5.* HelmRepository podinfo 53s True pulled 'podinfo' chart with version '5.2.1' + ``` + +3. Run `kubectl describe helmchart podinfo` to see the [Artifact](#artifact) and + [Conditions](#conditions) in the HelmChart's Status: + + ```console + Status: + Observed Source Artifact Revision: sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + Artifact: + Digest: sha256:6c3cc3b955bce1686036ae6822ee2ca0ef6ecb994e3f2d19eaf3ec03dcba84b3 + Last Update Time: 2022-02-13T11:24:10Z + Path: helmchart/default/podinfo/podinfo-5.2.1.tgz + Revision: 5.2.1 + Size: 14166 + URL: http://source-controller.flux-system.svc.cluster.local./helmchart/default/podinfo/podinfo-5.2.1.tgz + Conditions: + Last Transition Time: 2022-02-13T11:24:10Z + Message: pulled 'podinfo' chart with version '5.2.1' + Observed Generation: 1 + Reason: ChartPullSucceeded + Status: True + Type: Ready + Last Transition Time: 2022-02-13T11:24:10Z + Message: pulled 'podinfo' chart with version '5.2.1' + Observed Generation: 1 + Reason: ChartPullSucceeded + Status: True + Type: ArtifactInStorage + Observed Chart Name: podinfo + Observed Generation: 1 + URL: http://source-controller.flux-system.svc.cluster.local./helmchart/default/podinfo/latest.tar.gz + Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ChartPullSucceeded 2m51s source-controller pulled 'podinfo' chart with version '5.2.1' + ``` + +## Writing a HelmChart spec + +As with all other Kubernetes config, a HelmChart needs `apiVersion`, `kind`, and +`metadata` fields. The name of a HelmChart object must be a valid +[DNS subdomain name](https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + +A HelmChart also needs a +[`.spec` section](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). + +### Source reference + +`.spec.sourceRef` is a required field that specifies a reference to the Source +the chart is available at. + +Supported references are: +- [`HelmRepository`](helmrepositories.md) +- [`GitRepository`](gitrepositories.md) +- [`Bucket`](buckets.md) + +Although there are three kinds of source references, there are only two +underlying implementations. The artifact building process for `GitRepository` +and `Bucket` are the same as they are already built source artifacts. In case +of `HelmRepository`, a chart is fetched and/or packaged based on the +configuration of the Helm chart. + +For a `HelmChart` to be reconciled, the associated artifact in the source +reference must be ready. If the source artifact is not ready, the `HelmChart` +reconciliation is retried. + +When the `metadata.generation` of the `HelmChart` don't match with the +`status.observedGeneration`, the chart is fetched from source and/or packaged. +If there's no `.spec.valuesFiles` specified, the chart is only fetched from the +source, and not packaged. If `.spec.valuesFiles` are specified, the chart is +fetched and packaged with the values files. When the `metadata.generation` +matches the `status.observedGeneration`, the chart is only fetched from source +or from the cache if available, and not packaged. + +When using a `HelmRepository` source reference, the secret reference defined in +the Helm repository is used to fetch the chart. + +The HelmChart reconciliation behavior varies depending on the source reference +kind, see [reconcile strategy](#reconcile-strategy). + +The attributes of the generated artifact also varies depending on the source +reference kind, see [artifact](#artifact). + +### Chart + +`.spec.chart` is a required field that specifies the name or path the Helm chart +is available at in the [Source reference](#source-reference). + +For `HelmRepository` Source reference, it'll be just the name of the chart. + +```yaml +spec: + chart: podinfo + sourceRef: + name: podinfo + kind: HelmRepository +``` + +For `GitRepository` and `Bucket` Source reference, it'll be the path to the +Helm chart directory. + +```yaml +spec: + chart: ./charts/podinfo + sourceRef: + name: podinfo + kind: +``` + +### Version + +`.spec.version` is an optional field to specify the version of the chart in +semver. It is applicable only when the Source reference is a `HelmRepository`. +It is ignored for `GitRepository` and `Bucket` Source reference. It defaults to +the latest version of the chart with value `*`. + +Version can be a fixed semver, minor or patch semver range of a specific +version (i.e. `4.0.x`) or any semver range (i.e. `>=4.0.0 <5.0.0`). + +### Values files + +`.spec.valuesFiles` is an optional field to specify an alternative list of +values files to use as the chart values (values.yaml). The file paths are +expected to be relative to the Source reference. Values files are merged in the +order of the list with the last file overriding the first. It is ignored when +omitted. When values files are specified, the chart is fetched and packaged +with the provided values. + +```yaml +spec: + chart: + spec: + chart: podinfo + ... + valuesFiles: + - values.yaml + - values-production.yaml +``` + +Values files also affect the generated artifact revision, see +[artifact](#artifact). + +### Ignore missing values files + +`.spec.ignoreMissingValuesFiles` is an optional field to specify whether missing +values files should be ignored rather than be considered errors. It defaults to +`false`. + +When `.spec.valuesFiles` and `.spec.ignoreMissingValuesFiles` are specified, +the `.status.observedValuesFiles` field is populated with the list of values +files that were found and actually contributed to the packaged chart. + +### Reconcile strategy + +`.spec.reconcileStrategy` is an optional field to specify what enables the +creation of a new Artifact. Valid values are `ChartVersion` and `Revision`. +`ChartVersion` is used for creating a new artifact when the chart version +changes in a `HelmRepository`. `Revision` is used for creating a new artifact +when the source revision changes in a `GitRepository` or a `Bucket` Source. It +defaults to `ChartVersion`. + +**Note:** If the reconcile strategy is `ChartVersion` and the source reference +is a `GitRepository` or a `Bucket`, no new chart artifact is produced on updates +to the source unless the `version` in `Chart.yaml` is incremented. To produce +new chart artifact on change in source revision, set the reconcile strategy to +`Revision`. + +Reconcile strategy also affects the artifact version, see [artifact](#artifact) +for more details. + +### Interval + +`.spec.interval` is a required field that specifies the interval at which the +Helm Chart source must be checked for updates. + +After successfully reconciling a HelmChart object, the source-controller +requeues the object for inspection after the specified interval. The value must +be in a [Go recognized duration string format](https://pkg.go.dev/time#ParseDuration), +e.g. `10m0s` to look at the source for updates every 10 minutes. + +If the `.metadata.generation` of a resource changes (due to e.g. applying a +change to the spec), this is handled instantly outside the interval window. + +**Note:** The controller can be configured to apply a jitter to the interval in +order to distribute the load more evenly when multiple HelmChart objects are set +up with the same interval. For more information, please refer to the +[source-controller configuration options](https://fluxcd.io/flux/components/source/options/). + +### Suspend + +`.spec.suspend` is an optional field to suspend the reconciliation of a +HelmChart. When set to `true`, the controller will stop reconciling the +HelmChart, and changes to the resource or the Helm chart Source will not result +in a new Artifact. When the field is set to `false` or removed, it will resume. + +For practical information, see +[suspending and resuming](#suspending-and-resuming). + +### Verification + +**Note:** This feature is available only for Helm charts fetched from an OCI Registry. + +`.spec.verify` is an optional field to enable the verification of [Cosign](https://github.com/sigstore/cosign) or [Notation](https://github.com/notaryproject/notation) +signatures. The field offers three subfields: + +- `.provider`, to specify the verification provider. The supported options are `cosign` and `notation` at present. +- `.secretRef.name`, to specify a reference to a Secret in the same namespace as + the HelmChart, containing the public keys of trusted authors. For Notation this Secret should also include the [trust policy](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy) in + addition to the CA certificate. +- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers (only supported when using `cosign` as the verification provider). Please see + [Keyless verification](#keyless-verification) for more details. + +#### Cosign + +The `cosign` provider can be used to verify the signature of an OCI artifact using either a known public key or via the [Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: podinfo +spec: + verify: + provider: cosign + secretRef: + name: cosign-public-keys +``` + +When the verification succeeds, the controller adds a Condition with the +following attributes to the HelmChart's `.status.conditions`: + +- `type: SourceVerified` +- `status: "True"` +- `reason: Succeeded` + +##### Public keys verification + +To verify the authenticity of HelmChart hosted in an OCI Registry, create a Kubernetes +secret with the Cosign public keys: + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: cosign-public-keys +type: Opaque +data: + key1.pub: + key2.pub: +``` + +Note that the keys must have the `.pub` extension for Flux to make use of them. + +Flux will loop over the public keys and use them to verify a HelmChart's signature. +This allows for older HelmCharts to be valid as long as the right key is in the secret. + +##### Keyless verification + +For publicly available HelmCharts, which are signed using the +[Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure, +you can enable the verification by omitting the `.verify.secretRef` field. + +To verify the identity's subject and the OIDC issuer present in the Fulcio +certificate, you can specify a list of OIDC identity matchers using +`.spec.verify.matchOIDCIdentity`. The matcher provides two required fields: + +- `.issuer`, to specify a regexp that matches against the OIDC issuer. +- `.subject`, to specify a regexp that matches against the subject identity in + the certificate. +Both values should follow the [Go regular expression syntax](https://golang.org/s/re2syntax). + +The matchers are evaluated in an OR fashion, i.e. the identity is deemed to be +verified if any one matcher successfully matches against the identity. + +Example of verifying HelmCharts signed by the +[Cosign GitHub Action](https://github.com/sigstore/cosign-installer) with GitHub OIDC Token: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: podinfo +spec: + interval: 5m + chart: podinfo + reconcileStrategy: ChartVersion + sourceRef: + kind: HelmRepository + name: podinfo + version: ">=6.1.6" + verify: + provider: cosign + matchOIDCIdentity: + - issuer: "^https://token.actions.githubusercontent.com$" + subject: "^https://github.com/stefanprodan/podinfo.*$" +``` + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: podinfo +spec: + interval: 1m0s + url: oci://ghcr.io/stefanprodan/charts + type: "oci" +``` + +The controller verifies the signatures using the Fulcio root CA and the Rekor +instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/). + +Note that keyless verification is an **experimental feature**, using +custom root CAs or self-hosted Rekor instances are not currently supported. + +#### Notation + +The `notation` provider can be used to verify the signature of an OCI artifact using known +trust policy and CA certificate. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: podinfo +spec: + verify: + provider: notation + secretRef: + name: notation-config +``` + +When the verification succeeds, the controller adds a Condition with the +following attributes to the HelmChart's `.status.conditions`: + +- `type: SourceVerified` +- `status: "True"` +- `reason: Succeeded` + +To verify the authenticity of an OCI artifact, create a Kubernetes secret +containing Certificate Authority (CA) root certificates and the a `trust policy` + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: notation-config +type: Opaque +data: + certificate1.pem: + certificate2.crt: + trustpolicy.json: +``` + +Note that the CA certificates must have either `.pem` or `.crt` extension and your trust policy must +be named `trustpolicy.json` for Flux to make use of them. + +For more information on the signing and verification process see [Signing and Verification Workflow](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/signing-and-verification-workflow.md). + +Flux will loop over the certificates and use them to verify an artifact's signature. +This allows for older artifacts to be valid as long as the right certificate is in the secret. + +## Working with HelmCharts + +### Triggering a reconcile + +To manually tell the source-controller to reconcile a HelmChart outside the +[specified interval window](#interval), a HelmCHart can be annotated with +`reconcile.fluxcd.io/requestedAt: `. Annotating the resource +queues the object for reconciliation if the `` differs from +the last value the controller acted on, as reported in +[`.status.lastHandledReconcileAt`](#last-handled-reconcile-at). + +Using `kubectl`: + +```sh +kubectl annotate --field-manager=flux-client-side-apply --overwrite helmchart/ reconcile.fluxcd.io/requestedAt="$(date +%s)" +``` + +### Waiting for `Ready` + +When a change is applied, it is possible to wait for the HelmChart to reach a +[ready state](#ready-helmchart) using `kubectl`: + +```sh +kubectl wait helmchart/ --for=condition=ready --timeout=1m +``` + +### Suspending and resuming + +When you find yourself in a situation where you temporarily want to pause the +reconciliation of a HelmChart, you can suspend it using the +[`.spec.suspend` field](#suspend). + +#### Suspend a HelmChart + +In your YAML declaration: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: +spec: + suspend: true +``` + +Using `kubectl`: + +```sh +kubectl patch helmchart --field-manager=flux-client-side-apply -p '{\"spec\": {\"suspend\" : true }}' +``` + +**Note:** When a HelmChart has an Artifact and is suspended, and this +Artifact later disappears from the storage due to e.g. the source-controller +Pod being evicted from a Node, this will not be reflected in the +HelmChart's Status until it is resumed. + +#### Resume a HelmChart + +In your YAML declaration, comment out (or remove) the field: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: +spec: + # suspend: true +``` + +**Note:** Setting the field value to `false` has the same effect as removing +it, but does not allow for "hot patching" using e.g. `kubectl` while practicing +GitOps; as the manually applied patch would be overwritten by the declared +state in Git. + +Using `kubectl`: + +```sh +kubectl patch helmchart --field-manager=flux-client-side-apply -p '{\"spec\" : {\"suspend\" : false }}' +``` + +### Debugging a HelmChart + +There are several ways to gather information about a HelmChart for debugging +purposes. + +#### Describe the HelmChart + +Describing a HelmChart using `kubectl describe helmchart ` displays +the latest recorded information for the resource in the `Status` and `Events` +sections: + +```console +... +Status: +... + Conditions: + Last Transition Time: 2022-02-13T14:06:27Z + Message: invalid chart reference: failed to get chart version for remote reference: no 'podinfo' chart with version matching '9.*' found + Observed Generation: 3 + Reason: InvalidChartReference + Status: True + Type: Stalled + Last Transition Time: 2022-02-13T14:06:27Z + Message: invalid chart reference: failed to get chart version for remote reference: no 'podinfo' chart with version matching '9.*' found + Observed Generation: 3 + Reason: InvalidChartReference + Status: False + Type: Ready + Last Transition Time: 2022-02-13T14:06:27Z + Message: invalid chart reference: failed to get chart version for remote reference: no 'podinfo' chart with version matching '9.*' found + Observed Generation: 3 + Reason: InvalidChartReference + Status: True + Type: FetchFailed + Last Handled Reconcile At: 1644759954 + Observed Chart Name: podinfo + Observed Generation: 3 + URL: http://source-controller.flux-system.svc.cluster.local./helmchart/default/podinfo/latest.tar.gz +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Warning InvalidChartReference 11s source-controller invalid chart reference: failed to get chart version for remote reference: no 'podinfo' chart with ver +sion matching '9.*' found +``` + +#### Trace emitted Events + +To view events for specific HelmChart(s), `kubectl events` can be used in +combination with `--for` to list the Events for specific objects. For example, +running + +```sh +kubectl events --for HelmChart/ +``` + +lists + +```console +LAST SEEN TYPE REASON OBJECT MESSAGE +22s Warning InvalidChartReference helmchart/ invalid chart reference: failed to get chart version for remote reference: no 'podinfo' chart with version matching '9.*' found +2s Normal ChartPullSucceeded helmchart/ pulled 'podinfo' chart with version '6.0.3' +2s Normal ArtifactUpToDate helmchart/ artifact up-to-date with remote revision: '6.0.3' +``` + +Besides being reported in Events, the reconciliation errors are also logged by +the controller. The Flux CLI offer commands for filtering the logs for a +specific HelmChart, e.g. `flux logs --level=error --kind=HelmChart --name=`. + +### Improving resource consumption by enabling the cache + +When using a `HelmRepository` as Source for a `HelmChart`, the controller loads +the repository index in memory to find the latest version of the chart. + +The controller can be configured to cache Helm repository indexes in memory. +The cache is used to avoid loading repository indexes for every `HelmChart` +reconciliation. + +The following flags are provided to enable and configure the cache: +- `helm-cache-max-size`: The maximum size of the cache in number of indexes. + If `0`, then the cache is disabled. +- `helm-cache-ttl`: The TTL of an index in the cache. +- `helm-cache-purge-interval`: The interval at which the cache is purged of + expired items. + +The caching strategy is to pull a repository index from the cache if it is +available, otherwise to load the index, retrieve and build the chart, +then cache the index. The cached index TTL is refreshed every time the +Helm repository index is loaded with the `helm-cache-ttl` value. + +The cache is purged of expired items every `helm-cache-purge-interval`. + +When the cache is full, no more items can be added to the cache, and the +source-controller will report a warning event instead. + +In order to use the cache, set the related flags in the source-controller +Deployment config: + +```yaml + spec: + containers: + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election + - --storage-path=/data + - --storage-adv-addr=source-controller.$(RUNTIME_NAMESPACE).svc.cluster.local. + ## Helm cache with up to 10 items, i.e. 10 indexes. + - --helm-cache-max-size=10 + ## TTL of an index is 1 hour. + - --helm-cache-ttl=1h + ## Purge expired index every 10 minutes. + - --helm-cache-purge-interval=10m +``` + +## HelmChart Status + +### Artifact + +The HelmChart reports the last built chart as an Artifact object in the +`.status.artifact` of the resource. + +The Artifact file is a gzip compressed TAR archive (`-.tgz`), +and can be retrieved in-cluster from the `.status.artifact.url` HTTP address. + +#### Artifact example + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: +status: + artifact: + digest: sha256:e30b95a08787de69ffdad3c232d65cfb131b5b50c6fd44295f48a078fceaa44e + lastUpdateTime: "2022-02-10T18:53:47Z" + path: helmchart///-.tgz + revision: 6.0.3 + size: 14166 + url: http://source-controller.flux-system.svc.cluster.local./helmchart///-.tgz +``` + +When using a `HelmRepository` as the source reference and values files are +provided, the value of `status.artifact.revision` is the chart version combined +with the `HelmChart` object generation. For example, if the chart version is +`6.0.3` and the `HelmChart` object generation is `1`, the +`status.artifact.revision` value will be `6.0.3+1`. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: +status: + artifact: + digest: sha256:ee68224ded207ebb18a8e9730cf3313fa6bc1f31e6d8d3943ab541113559bb52 + lastUpdateTime: "2022-02-28T08:07:12Z" + path: helmchart///-6.0.3+1.tgz + revision: 6.0.3+1 + size: 14166 + url: http://source-controller.flux-system.svc.cluster.local./helmchart///-6.0.3+1.tgz + observedGeneration: 1 + ... +``` + +When using a `GitRepository` or a `Bucket` as the source reference and +`Revision` as the reconcile strategy, the value of `status.artifact.revision` is +the chart version combined with the first 12 characters of the revision of the +`GitRepository` or `Bucket`. For example if the chart version is `6.0.3` and the +revision of the `Bucket` is `4e5cbb7b97d00a8039b8810b90b922f4256fd3bd8f78b934b4892dae13f7ca87`, +the `status.artifact.revision` value will be `6.0.3+4e5cbb7b97d0`. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmChart +metadata: + name: +status: + artifact: + digest: sha256:8d1f0ac3f4b0e8759a32180086f17ac87ca04e5d46c356e67f97e97616ef4718 + lastUpdateTime: "2022-02-28T08:07:12Z" + path: helmchart///-6.0.3+4e5cbb7b97d0.tgz + revision: 6.0.3+4e5cbb7b97d0 + size: 14166 + url: http://source-controller.flux-system.svc.cluster.local./helmchart///-6.0.3+4e5cbb7b97d0.tgz +``` + +### Conditions + +A HelmChart enters various states during its lifecycle, reflected as [Kubernetes +Conditions][typical-status-properties]. +It can be [reconciling](#reconciling-helmchart) while fetching or building the +chart, it can be [ready](#ready-helmchart), it can +[fail during reconciliation](#failed-helmchart), or it can +[stall](#stalled-helmchart). + +The HelmChart API is compatible with the [kstatus +specification][kstatus-spec], +and reports `Reconciling` and `Stalled` conditions where applicable to +provide better (timeout) support to solutions polling the HelmChart to become +`Ready`. + +#### Reconciling HelmChart + +The source-controller marks a HelmChart as _reconciling_ when one of the +following is true: + +- There is no current Artifact for the HelmChart, or the reported Artifact is + determined to have disappeared from the storage. +- The generation of the HelmChart is newer than the [Observed + Generation](#observed-generation). +- The newly fetched Artifact revision differs from the current Artifact. + +When the HelmChart is "reconciling", the `Ready` Condition status becomes +`Unknown` when the controller detects drift, and the controller adds a Condition +with the following attributes to the HelmChart's `.status.conditions`: + +- `type: Reconciling` +- `status: "True"` +- `reason: Progressing` | `reason: ProgressingWithRetry` + +If the reconciling state is due to a new version, it adds an additional +Condition with the following attributes: + +- `type: ArtifactOutdated` +- `status: "True"` +- `reason: NewChart` + +Both Conditions have a ["negative polarity"][typical-status-properties], +and are only present on the HelmChart while their status value is `"True"`. + +#### Ready HelmChart + +The source-controller marks a HelmChart as _ready_ when it has the following +characteristics: + +- The HelmChart reports an [Artifact](#artifact). +- The reported Artifact exists in the controller's Artifact storage. +- The controller was able to fetch and build the Helm chart using the current + spec. +- The version/revision of the reported Artifact is up-to-date with the + latest version/revision of the Helm chart. + +When the HelmChart is "ready", the controller sets a Condition with the +following attributes in the HelmChart's `.status.conditions`: + +- `type: Ready` +- `status: "True"` +- `reason: Succeeded` + +This `Ready` Condition will retain a status value of `"True"` until the +HelmChart is marked as [reconciling](#reconciling-helmchart), or e.g. +a [transient error](#failed-helmchart) occurs due to a temporary network issue. + +When the HelmChart Artifact is archived in the controller's Artifact +storage, the controller sets a Condition with the following attributes in the +HelmChart's `.status.conditions`: + +- `type: ArtifactInStorage` +- `status: "True"` +- `reason: Succeeded` + +This `ArtifactInStorage` Condition will retain a status value of `"True"` until +the Artifact in the storage no longer exists. + +#### Failed HelmChart + +The source-controller may get stuck trying to produce an Artifact for a +HelmChart without completing. This can occur due to some of the following +factors: + +- The Helm chart Source is temporarily unavailable. +- The credentials in the [Source reference](#source-reference) Secret are + invalid. +- The HelmChart spec contains a generic misconfiguration. +- A storage related failure when storing the artifact. + +When this happens, the controller sets the `Ready` Condition status to `False`, +and adds a Condition with the following attributes to the HelmChart's +`.status.conditions`: + +- `type: FetchFailed` | `type: StorageOperationFailed` +- `status: "True"` +- `reason: AuthenticationFailed` | `reason: StorageOperationFailed` | `reason: URLInvalid` | `reason: IllegalPath` | `reason: Failed` + +This condition has a ["negative polarity"][typical-status-properties], +and is only present on the HelmChart while the status value is `"True"`. +There may be more arbitrary values for the `reason` field to provide accurate +reason for a condition. + +While the HelmChart has this Condition, the controller will continue to +attempt to produce an Artifact for the resource with an exponential backoff, +until it succeeds and the HelmChart is marked as [ready](#ready-helmchart). + +Note that a HelmChart can be [reconciling](#reconciling-helmchart) +while failing at the same time, for example due to a newly introduced +configuration issue in the HelmChart spec. When a reconciliation fails, the +`Reconciling` Condition reason would be `ProgressingWithRetry`. When the +reconciliation is performed again after the failure, the reason is updated to +`Progressing`. + +#### Stalled HelmChart + +The source-controller can mark a HelmChart as _stalled_ when it determines that +without changes to the spec, the reconciliation can not succeed. +For example because a HelmChart Version is set to a non-existing version. + +When this happens, the controller sets the same Conditions as when it +[fails](#failed-helmchart), but adds another Condition with the following +attributes to the HelmChart's `.status.conditions`: + +- `type: Stalled` +- `status: "True"` +- `reason: InvalidChartReference` + +While the HelmChart has this Condition, the controller will not requeue the +resource any further, and will stop reconciling the resource until a change to +the spec is made. + +### Observed Source Artifact Revision + +The source-controller reports the revision of the last +[Source reference's](#source-reference) Artifact the current chart was fetched +from in the HelmChart's `.status.observedSourceArtifactRevision`. It is used to +keep track of the source artifact revision and detect when a new source +artifact is available. + +### Observed Chart Name + +The source-controller reports the last resolved chart name of the Artifact +for the [`.spec.chart` field](#chart) in the HelmChart's +`.status.observedChartName`. It is used to keep track of the chart and detect +when a new chart is found. + +### Observed Generation + +The source-controller reports an [observed generation][typical-status-properties] +in the HelmChart's `.status.observedGeneration`. The observed generation is the +latest `.metadata.generation` which resulted in either a [ready state](#ready-helmchart), +or stalled due to error it can not recover from without human +intervention. + +### Last Handled Reconcile At + +The source-controller reports the last `reconcile.fluxcd.io/requestedAt` +annotation value it acted on in the `.status.lastHandledReconcileAt` field. + +For practical information about this field, see [triggering a +reconcile](#triggering-a-reconcile). + +[typical-status-properties]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties +[kstatus-spec]: https://github.com/kubernetes-sigs/cli-utils/tree/master/pkg/kstatus diff --git a/docs/spec/v1/helmrepositories.md b/docs/spec/v1/helmrepositories.md new file mode 100644 index 000000000..d8b6748e9 --- /dev/null +++ b/docs/spec/v1/helmrepositories.md @@ -0,0 +1,914 @@ +# Helm Repositories + + + +There are 2 [Helm repository types](#type) defined by the `HelmRepository` API: +- Helm HTTP/S repository, which defines a Source to produce an Artifact for a Helm +repository index YAML (`index.yaml`). +- OCI Helm repository, which defines a source that does not produce an Artifact. + It's a data container to store the information about the OCI repository that + can be used by [HelmChart](helmcharts.md) to access OCI Helm charts. + +## Examples + +### Helm HTTP/S repository + +The following is an example of a HelmRepository. It creates a YAML (`.yaml`) +Artifact from the fetched Helm repository index (in this example the [podinfo +repository](https://github.com/stefanprodan/podinfo)): + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: podinfo + namespace: default +spec: + interval: 5m0s + url: https://stefanprodan.github.io/podinfo +``` + +In the above example: + +- A HelmRepository named `podinfo` is created, indicated by the + `.metadata.name` field. +- The source-controller fetches the Helm repository index YAML every five + minutes from `https://stefanprodan.github.io/podinfo`, indicated by the + `.spec.interval` and `.spec.url` fields. +- The digest (algorithm defaults to SHA256) of the Helm repository index after + stable sorting the entries is used as Artifact revision, reported in-cluster + in the `.status.artifact.revision` field. +- When the current HelmRepository revision differs from the latest fetched + revision, it is stored as a new Artifact. +- The new Artifact is reported in the `.status.artifact` field. + +You can run this example by saving the manifest into `helmrepository.yaml`. + +1. Apply the resource on the cluster: + + ```sh + kubectl apply -f helmrepository.yaml + ``` + +2. Run `kubectl get helmrepository` to see the HelmRepository: + + ```console + NAME URL AGE READY STATUS + podinfo https://stefanprodan.github.io/podinfo 4s True stored artifact for revision 'sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111' + ``` + +3. Run `kubectl describe helmrepository podinfo` to see the [Artifact](#artifact) + and [Conditions](#conditions) in the HelmRepository's Status: + + ```console + ... + Status: + Artifact: + Digest: sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + Last Update Time: 2022-02-04T09:55:58Z + Path: helmrepository/default/podinfo/index-83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111.yaml + Revision: sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + Size: 40898 + URL: http://source-controller.flux-system.svc.cluster.local./helmrepository/default/podinfo/index-83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111.yaml + Conditions: + Last Transition Time: 2022-02-04T09:55:58Z + Message: stored artifact for revision 'sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111' + Observed Generation: 1 + Reason: Succeeded + Status: True + Type: Ready + Last Transition Time: 2022-02-04T09:55:58Z + Message: stored artifact for revision 'sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111' + Observed Generation: 1 + Reason: Succeeded + Status: True + Type: ArtifactInStorage + Observed Generation: 1 + URL: http://source-controller.flux-system.svc.cluster.local./helmrepository/default/podinfo/index.yaml + Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal NewArtifact 1m source-controller fetched index of size 30.88kB from 'https://stefanprodan.github.io/podinfo' + ``` + +### Helm OCI repository + +The following is an example of an OCI HelmRepository. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: podinfo + namespace: default +spec: + type: "oci" + interval: 5m0s + url: oci://ghcr.io/stefanprodan/charts +``` + +In the above example: + +- A HelmRepository named `podinfo` is created, indicated by the + `.metadata.name` field. +- A HelmChart that refers to this HelmRepository uses the URL in the `.spec.url` + field to access the OCI Helm chart. + +**NOTE:** The `.spec.interval` field is only used by the `default` Helm +repository and is ignored for any value in `oci` Helm repository. + +You can run this example by saving the manifest into `helmrepository.yaml`. + +1. Apply the resource on the cluster: + + ```sh + kubectl apply -f helmrepository.yaml + ``` + +2. Run `kubectl get helmrepository` to see the HelmRepository: + + ```console + NAME URL AGE READY STATUS + podinfo oci://ghcr.io/stefanprodan/charts 3m22s + ``` + +Because the OCI Helm repository is a data container, there's nothing to report +for `READY` and `STATUS` columns above. The existence of the object can be +considered to be ready for use. + +## Writing a HelmRepository spec + +As with all other Kubernetes config, a HelmRepository needs `apiVersion`, +`kind`, and `metadata` fields. The name of a HelmRepository object must be a +valid [DNS subdomain name](https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + +A HelmRepository also needs a +[`.spec` section](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). + +### Type + +`.spec.type` is an optional field that specifies the Helm repository type. + +Possible values are `default` for a Helm HTTP/S repository, or `oci` for an OCI Helm repository. + +### Provider + +`.spec.provider` is an optional field that allows specifying an OIDC provider used +for authentication purposes. + +Supported options are: +- `generic` +- `aws` +- `azure` +- `gcp` + +The `generic` provider can be used for public repositories or when static credentials +are used for authentication. If you do not specify `.spec.provider`, it defaults +to `generic`. + +**Note**: The provider field is supported only for Helm OCI repositories. The `spec.type` +field must be set to `oci`. + +#### AWS + +The `aws` provider can be used to authenticate automatically using the EKS worker +node IAM role or IAM Role for Service Accounts (IRSA), and by extension gain access +to ECR. + +##### EKS Worker Node IAM Role + +When the worker node IAM role has access to ECR, source-controller running on it +will also have access to ECR. + +##### IAM Role for Service Accounts (IRSA) + +When using IRSA to enable access to ECR, add the following patch to your bootstrap +repository, in the `flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + annotations: + eks.amazonaws.com/role-arn: + target: + kind: ServiceAccount + name: source-controller +``` + +Note that you can attach the AWS managed policy `arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly` +to the IAM role when using IRSA. + +#### Azure + +The `azure` provider can be used to authenticate automatically using Workload Identity, Kubelet Managed +Identity or Azure Active Directory pod-managed identity (aad-pod-identity), and +by extension gain access to ACR. + +##### Kubelet Managed Identity + +When the kubelet managed identity has access to ACR, source-controller running on +it will also have access to ACR. + +**Note:** If you have more than one identity configured on the cluster, you have to specify which one to use +by setting the `AZURE_CLIENT_ID` environment variable in the source-controller deployment. + +If you are running into further issues, please look at the +[troubleshooting guide](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/azidentity/TROUBLESHOOTING.md#azure-virtual-machine-managed-identity). + +##### Azure Workload Identity + +When using Workload Identity to enable access to ACR, add the following patch to +your bootstrap repository, in the `flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: |- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + namespace: flux-system + annotations: + azure.workload.identity/client-id: + labels: + azure.workload.identity/use: "true" + - patch: |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: source-controller + namespace: flux-system + labels: + azure.workload.identity/use: "true" + spec: + template: + metadata: + labels: + azure.workload.identity/use: "true" +``` + +Ensure Workload Identity is properly set up on your cluster and the mutating webhook is installed. +Create an identity that has access to ACR. Next, establish +a federated identity between the source-controller ServiceAccount and the +identity. Patch the source-controller Deployment and ServiceAccount as shown in the patch +above. Please take a look at this [guide](https://azure.github.io/azure-workload-identity/docs/quick-start.html#6-establish-federated-identity-credential-between-the-identity-and-the-service-account-issuer--subject). + +##### Deprecated: AAD Pod Identity + +**Warning:** The AAD Pod Identity project will be archived in +[September 2023](https://github.com/Azure/aad-pod-identity#-announcement), +and you are advised to use Workload Identity instead. + +When using aad-pod-identity to enable access to ACR, add the following patch to +your bootstrap repository, in the `flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: | + - op: add + path: /spec/template/metadata/labels/aadpodidbinding + value: + target: + kind: Deployment + name: source-controller +``` + +When using pod-managed identity on an AKS cluster, AAD Pod Identity has to be used +to give the `source-controller` pod access to the ACR. To do this, you have to install +`aad-pod-identity` on your cluster, create a managed identity that has access to the +container registry (this can also be the Kubelet identity if it has `AcrPull` role +assignment on the ACR), create an `AzureIdentity` and `AzureIdentityBinding` that describe +the managed identity and then label the `source-controller` deployment with the name of the +AzureIdentity as shown in the patch above. Please take a look at [this guide](https://azure.github.io/aad-pod-identity/docs/) +or [this one](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity) +if you want to use AKS pod-managed identities add-on that is in preview. + +#### GCP + +The `gcp` provider can be used to authenticate automatically using OAuth scopes or +Workload Identity, and by extension gain access to GCR or Artifact Registry. + +##### Access Scopes + +When the GKE nodes have the appropriate OAuth scope for accessing GCR and Artifact Registry, +source-controller running on it will also have access to them. + +##### GKE Workload Identity + +When using Workload Identity to enable access to GCR or Artifact Registry, add the +following patch to your bootstrap repository, in the `flux-system/kustomization.yaml` +file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + annotations: + iam.gke.io/gcp-service-account: + target: + kind: ServiceAccount + name: source-controller +``` + +The Artifact Registry service uses the permission `artifactregistry.repositories.downloadArtifacts` +that is located under the Artifact Registry Reader role. If you are using Google Container Registry service, +the needed permission is instead `storage.objects.list` which can be bound as part +of the Container Registry Service Agent role. Take a look at [this guide](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) +for more information about setting up GKE Workload Identity. + +### Insecure + +`.spec.insecure` is an optional field to allow connecting to an insecure (HTTP) +container registry server, if set to `true`. The default value is `false`, +denying insecure non-TLS connections when fetching Helm chart OCI artifacts. + +**Note**: The insecure field is supported only for Helm OCI repositories. +The `spec.type` field must be set to `oci`. + +### Interval + +**Note:** This field is ineffectual for [OCI Helm +Repositories](#helm-oci-repository). + +`.spec.interval` is a an optional field that specifies the interval which the +Helm repository index must be consulted at. When not set, the default value is +`1m`. + +After successfully reconciling a HelmRepository object, the source-controller +requeues the object for inspection after the specified interval. The value +must be in a [Go recognized duration string format](https://pkg.go.dev/time#ParseDuration), +e.g. `10m0s` to fetch the HelmRepository index YAML every 10 minutes. + +If the `.metadata.generation` of a resource changes (due to e.g. applying a +change to the spec), this is handled instantly outside the interval window. + +**Note:** The controller can be configured to apply a jitter to the interval in +order to distribute the load more evenly when multiple HelmRepository objects +are set up with the same interval. For more information, please refer to the +[source-controller configuration options](https://fluxcd.io/flux/components/source/options/). + +### URL + +`.spec.url` is a required field that depending on the [type of the HelmRepository object](#type) +specifies the HTTP/S or OCI address of a Helm repository. + +For OCI, the URL is expected to point to a registry repository, e.g. `oci://ghcr.io/fluxcd/source-controller`. + +For Helm repositories which require authentication, see [Secret reference](#secret-reference). + +### Timeout + +**Note:** This field is not applicable to [OCI Helm +Repositories](#helm-oci-repository). + +`.spec.timeout` is an optional field to specify a timeout for the fetch +operation. The value must be in a +[Go recognized duration string format](https://pkg.go.dev/time#ParseDuration), +e.g. `1m30s` for a timeout of one minute and thirty seconds. When not set, the +default value is `1m`. + +### Secret reference + +`.spec.secretRef.name` is an optional field to specify a name reference to a +Secret in the same namespace as the HelmRepository, containing authentication +credentials for the repository. + +#### Basic access authentication + +To authenticate towards a Helm repository using basic access authentication +(in other words: using a username and password), the referenced Secret is +expected to contain `.data.username` and `.data.password` values. + +For example: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: example + namespace: default +spec: + interval: 5m0s + url: https://example.com + secretRef: + name: example-user +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-user + namespace: default +stringData: + username: "user-123456" + password: "pass-123456" +``` + +OCI Helm repository example: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: podinfo + namespace: default +spec: + interval: 5m0s + url: oci://ghcr.io/my-user/my-private-repo + type: "oci" + secretRef: + name: oci-creds +--- +apiVersion: v1 +kind: Secret +metadata: + name: oci-creds + namespace: default +stringData: + username: "user-123456" + password: "pass-123456" +``` + +For OCI Helm repositories, Kubernetes secrets of type [kubernetes.io/dockerconfigjson](https://kubernetes.io/docs/concepts/configuration/secret/#secret-types) are also supported. +It is possible to create one such secret with `kubectl create secret docker-registry` +or using the Flux CLI: + +```yaml +flux create secret oci ghcr-auth \ + --url=ghcr.io \ + --username=flux \ + --password=${GITHUB_PAT} +``` + +**Warning:** Support for specifying TLS authentication data using this API has been +deprecated. Please use [`.spec.certSecretRef`](#cert-secret-reference) instead. +If the controller uses the secret specified by this field to configure TLS, then +a deprecation warning will be logged. + +### Cert secret reference + +`.spec.certSecretRef.name` is an optional field to specify a secret containing +TLS certificate data. The secret can contain the following keys: + +* `tls.crt` and `tls.key`, to specify the client certificate and private key used +for TLS client authentication. These must be used in conjunction, i.e. +specifying one without the other will lead to an error. +* `ca.crt`, to specify the CA certificate used to verify the server, which is +required if the server is using a self-signed certificate. + +If the server is using a self-signed certificate and has TLS client +authentication enabled, all three values are required. + +The Secret should be of type `Opaque` or `kubernetes.io/tls`. All the files in +the Secret are expected to be [PEM-encoded][pem-encoding]. Assuming you have +three files; `client.key`, `client.crt` and `ca.crt` for the client private key, +client certificate and the CA certificate respectively, you can generate the +required Secret using the `flux create secret tls` command: + +```sh +flux create secret tls --tls-key-file=client.key --tls-crt-file=client.crt --ca-crt-file=ca.crt +``` + +Example usage: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: example + namespace: default +spec: + interval: 5m0s + url: https://example.com + certSecretRef: + name: example-tls +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-tls + namespace: default +type: kubernetes.io/tls # or Opaque +data: + tls.crt: + tls.key: + # NOTE: Can be supplied without the above values + ca.crt: +``` + +### Pass credentials + +`.spec.passCredentials` is an optional field to allow the credentials from the +[Secret reference](#secret-reference) to be passed on to a host that does not +match the host as defined in URL. This may for example be required if the host +advertised chart URLs in the index differ from the specified URL. + +Enabling this should be done with caution, as it can potentially result in +credentials getting stolen in a man-in-the-middle attack. This feature only applies +to HTTP/S Helm repositories. + +### Suspend + +**Note:** This field is not applicable to [OCI Helm +Repositories](#helm-oci-repository). + +`.spec.suspend` is an optional field to suspend the reconciliation of a +HelmRepository. When set to `true`, the controller will stop reconciling the +HelmRepository, and changes to the resource or the Helm repository index will +not result in a new Artifact. When the field is set to `false` or removed, it +will resume. + +For practical information, see +[suspending and resuming](#suspending-and-resuming). + +## Working with HelmRepositories + +**Note:** This section does not apply to [OCI Helm +Repositories](#helm-oci-repository), being a data container, once created, they +are ready to used by [HelmCharts](helmcharts.md). + +### Triggering a reconcile + +To manually tell the source-controller to reconcile a HelmRepository outside the +[specified interval window](#interval), a HelmRepository can be annotated with +`reconcile.fluxcd.io/requestedAt: `. Annotating the resource +queues the object for reconciliation if the `` differs from +the last value the controller acted on, as reported in +[`.status.lastHandledReconcileAt`](#last-handled-reconcile-at). + +Using `kubectl`: + +```sh +kubectl annotate --field-manager=flux-client-side-apply --overwrite helmrepository/ reconcile.fluxcd.io/requestedAt="$(date +%s)" +``` + +Using `flux`: + +```sh +flux reconcile source helm +``` + +### Waiting for `Ready` + +When a change is applied, it is possible to wait for the HelmRepository to +reach a [ready state](#ready-helmrepository) using `kubectl`: + +```sh +kubectl wait helmrepository/ --for=condition=ready --timeout=1m +``` + +### Suspending and resuming + +When you find yourself in a situation where you temporarily want to pause the +reconciliation of a HelmRepository, you can suspend it using the +[`.spec.suspend` field](#suspend). + +#### Suspend a HelmRepository + +In your YAML declaration: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: +spec: + suspend: true +``` + +Using `kubectl`: + +```sh +kubectl patch helmrepository --field-manager=flux-client-side-apply -p '{\"spec\": {\"suspend\" : true }}' +``` + +Using `flux`: + +```sh +flux suspend source helm +``` + +**Note:** When a HelmRepository has an Artifact and is suspended, and this +Artifact later disappears from the storage due to e.g. the source-controller +Pod being evicted from a Node, this will not be reflected in the +HelmRepository's Status until it is resumed. + +#### Resume a HelmRepository + +In your YAML declaration, comment out (or remove) the field: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: +spec: + # suspend: true +``` + +**Note:** Setting the field value to `false` has the same effect as removing +it, but does not allow for "hot patching" using e.g. `kubectl` while practicing +GitOps; as the manually applied patch would be overwritten by the declared +state in Git. + +Using `kubectl`: + +```sh +kubectl patch helmrepository --field-manager=flux-client-side-apply -p '{\"spec\" : {\"suspend\" : false }}' +``` + +Using `flux`: + +```sh +flux resume source helm +``` + +### Debugging a HelmRepository + +**Note:** This section does not apply to [OCI Helm +Repositories](#helm-oci-repository), being a data container, they are static +objects that don't require debugging if valid. + +There are several ways to gather information about a HelmRepository for debugging +purposes. + +#### Describe the HelmRepository + +Describing a HelmRepository using `kubectl describe helmrepository ` +displays the latest recorded information for the resource in the `Status` and +`Events` sections: + +```console +... +Status: +... + Conditions: + Last Transition Time: 2022-02-04T13:41:56Z + Message: failed to construct Helm client: scheme "invalid" not supported + Observed Generation: 2 + Reason: Failed + Status: True + Type: Stalled + Last Transition Time: 2022-02-04T13:41:56Z + Message: failed to construct Helm client: scheme "invalid" not supported + Observed Generation: 2 + Reason: Failed + Status: False + Type: Ready + Last Transition Time: 2022-02-04T13:41:56Z + Message: failed to construct Helm client: scheme "invalid" not supported + Observed Generation: 2 + Reason: Failed + Status: True + Type: FetchFailed + Observed Generation: 2 + URL: http://source-controller.source-system.svc.cluster.local./helmrepository/default/podinfo/index.yaml +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Warning Failed 6s source-controller failed to construct Helm client: scheme "invalid" not supported +``` + +#### Trace emitted Events + +To view events for specific HelmRepository(s), `kubectl events` can be used in +combination with `--for` to list the Events for specific objects. For example, +running + +```sh +kubectl events --for HelmRepository/ +``` + +lists + +```console +LAST SEEN TYPE REASON OBJECT MESSAGE +107s Warning Failed helmrepository/ failed to construct Helm client: scheme "invalid" not supported +7s Normal NewArtifact helmrepository/ fetched index of size 30.88kB from 'https://stefanprodan.github.io/podinfo' +3s Normal ArtifactUpToDate helmrepository/ artifact up-to-date with remote revision: 'sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111' +``` + +Besides being reported in Events, the reconciliation errors are also logged by +the controller. The Flux CLI offer commands for filtering the logs for a +specific HelmRepository, e.g. `flux logs --level=error --kind=HelmRepository --name=`. + +## HelmRepository Status + +**Note:** This section does not apply to [OCI Helm +Repositories](#helm-oci-repository), they do not contain any information in the +status. + +### Artifact + +The HelmRepository reports the last fetched repository index as an Artifact +object in the `.status.artifact` of the resource. + +The Artifact file is an exact copy of the Helm repository index YAML +(`index-.yaml`) as fetched, and can be retrieved in-cluster from the +`.status.artifact.url` HTTP address. + +#### Artifact example + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: +status: + artifact: + digest: sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + lastUpdateTime: "2022-02-04T09:55:58Z" + path: helmrepository///index-83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111.yaml + revision: sha256:83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + size: 40898 + url: http://source-controller.flux-system.svc.cluster.local./helmrepository///index-83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111.yaml +``` + +### Conditions + +A HelmRepository enters various states during its lifecycle, reflected as [Kubernetes +Conditions][typical-status-properties]. +It can be [reconciling](#reconciling-helmrepository) while fetching the +repository index, it can be [ready](#ready-helmrepository), it can +[fail during reconciliation](#failed-helmrepository), or it can +[stall](#stalled-helmrepository). + +The HelmRepository API is compatible with the [kstatus +specification][kstatus-spec], +and reports `Reconciling` and `Stalled` conditions where applicable to +provide better (timeout) support to solutions polling the HelmRepository to become +`Ready`. + +#### Reconciling HelmRepository + +The source-controller marks a HelmRepository as _reconciling_ when one of the following +is true: + +- There is no current Artifact for the HelmRepository, or the reported Artifact + is determined to have disappeared from the storage. +- The generation of the HelmRepository is newer than the [Observed + Generation](#observed-generation). +- The newly fetched Artifact revision differs from the current Artifact. + +When the HelmRepository is "reconciling", the `Ready` Condition status becomes +`Unknown` when the controller detects drift, and the controller adds a Condition +with the following attributes to the HelmRepository's `.status.conditions`: + +- `type: Reconciling` +- `status: "True"` +- `reason: Progressing` | `reason: ProgressingWithRetry` + +If the reconciling state is due to a new revision, it adds an additional +Condition with the following attributes: + +- `type: ArtifactOutdated` +- `status: "True"` +- `reason: NewRevision` + +Both Conditions have a ["negative polarity"][typical-status-properties], +and are only present on the HelmRepository while their status value is `"True"`. + +#### Ready HelmRepository + +The source-controller marks a HelmRepository as _ready_ when it has the following +characteristics: + +- The HelmRepository reports an [Artifact](#artifact). +- The reported Artifact exists in the controller's Artifact storage. +- The controller was able to fetch the Helm repository index using the current + spec. +- The revision of the reported Artifact is up-to-date with the latest + revision of the Helm repository. + +When the HelmRepository is "ready", the controller sets a Condition with the following +attributes in the HelmRepository's `.status.conditions`: + +- `type: Ready` +- `status: "True"` +- `reason: Succeeded` + +This `Ready` Condition will retain a status value of `"True"` until the +HelmRepository is marked as [reconciling](#reconciling-helmrepository), or e.g. +a [transient error](#failed-helmrepository) occurs due to a temporary network +issue. + +When the HelmRepository Artifact is archived in the controller's Artifact +storage, the controller sets a Condition with the following attributes in the +HelmRepository's `.status.conditions`: + +- `type: ArtifactInStorage` +- `status: "True"` +- `reason: Succeeded` + +This `ArtifactInStorage` Condition will retain a status value of `"True"` until +the Artifact in the storage no longer exists. + +#### Failed HelmRepository + +The source-controller may get stuck trying to produce an Artifact for a +HelmRepository without completing. This can occur due to some of the following +factors: + +- The Helm repository [URL](#url) is temporarily unavailable. +- The [Secret reference](#secret-reference) contains a reference to a + non-existing Secret. +- The credentials in the referenced Secret are invalid. +- The HelmRepository spec contains a generic misconfiguration. +- A storage related failure when storing the artifact. + +When this happens, the controller sets the `Ready` Condition status to `False`, +and adds a Condition with the following attributes to the HelmRepository's +`.status.conditions`: + +- `type: FetchFailed` | `type: StorageOperationFailed` +- `status: "True"` +- `reason: AuthenticationFailed` | `reason: IndexationFailed` | `reason: Failed` + +This condition has a ["negative polarity"][typical-status-properties], +and is only present on the HelmRepository while the status value is `"True"`. +There may be more arbitrary values for the `reason` field to provide accurate +reason for a condition. + +While the HelmRepository has this Condition, the controller will continue to +attempt to produce an Artifact for the resource with an exponential backoff, +until it succeeds and the HelmRepository is marked as [ready](#ready-helmrepository). + +Note that a HelmRepository can be [reconciling](#reconciling-helmrepository) +while failing at the same time, for example due to a newly introduced +configuration issue in the HelmRepository spec. When a reconciliation fails, the +`Reconciling` Condition reason would be `ProgressingWithRetry`. When the +reconciliation is performed again after the failure, the reason is updated to +`Progressing`. + +#### Stalled HelmRepository + +The source-controller can mark a HelmRepository as _stalled_ when it determines +that without changes to the spec, the reconciliation can not succeed. +For example because a Helm repository URL with an unsupported protocol is +specified. + +When this happens, the controller sets the same Conditions as when it +[fails](#failed-helmrepository), but adds another Condition with the following +attributes to the HelmRepository's +`.status.conditions`: + +- `type: Stalled` +- `status: "True"` +- `reason: URLInvalid` + +While the HelmRepository has this Condition, the controller will not requeue +the resource any further, and will stop reconciling the resource until a change +to the spec is made. + +### Observed Generation + +The source-controller reports an [observed generation][typical-status-properties] +in the HelmRepository's `.status.observedGeneration`. The observed generation is +the latest `.metadata.generation` which resulted in either a [ready state](#ready-helmrepository), +or stalled due to error it can not recover from without human intervention. + +### Last Handled Reconcile At + +The source-controller reports the last `reconcile.fluxcd.io/requestedAt` +annotation value it acted on in the `.status.lastHandledReconcileAt` field. + +For practical information about this field, see [triggering a +reconcile](#triggering-a-reconcile). + +[pem-encoding]: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail +[typical-status-properties]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties +[kstatus-spec]: https://github.com/kubernetes-sigs/cli-utils/tree/master/pkg/kstatus diff --git a/internal/controller/helmchart_controller_test.go b/internal/controller/helmchart_controller_test.go index 06426068a..39f9991f1 100644 --- a/internal/controller/helmchart_controller_test.go +++ b/internal/controller/helmchart_controller_test.go @@ -929,14 +929,14 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Uses artifact as build cache with observedValuesFiles", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} obj.Status.ObservedValuesFiles = []string{"values.yaml", "override.yaml"} }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion)) g.Expect(build.Path).To(Equal(filepath.Join(serverFactory.Root(), obj.Status.Artifact.Path))) @@ -965,7 +965,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Missing values files are an error", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.ValuesFiles = []string{"missing.yaml"} }, @@ -973,14 +973,14 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "All missing values files ignored", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion obj.Spec.ValuesFiles = []string{"missing.yaml"} obj.Spec.IgnoreMissingValuesFiles = true }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion + "+0")) g.Expect(build.ValuesFiles).To(BeEmpty()) @@ -991,14 +991,14 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { }, { name: "Partial missing values files ignored", - beforeFunc: func(obj *helmv1.HelmChart, repository *helmv1.HelmRepository) { + beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion obj.Spec.ValuesFiles = []string{"values.yaml", "override.yaml", "invalid.yaml"} obj.Spec.IgnoreMissingValuesFiles = true }, want: sreconcile.ResultSuccess, - assertFunc: func(g *WithT, obj *helmv1.HelmChart, build chart.Build) { + assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { g.Expect(build.Name).To(Equal(chartName)) g.Expect(build.Version).To(Equal(chartVersion + "+0")) g.Expect(build.ValuesFiles).To(Equal([]string{"values.yaml", "override.yaml"})) @@ -1524,7 +1524,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { { name: "Chart from storage cache with ObservedValuesFiles", source: *chartsArtifact.DeepCopy(), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { obj.Spec.Chart = "testdata/charts/helmchart-0.1.0.tgz" obj.Status.Artifact = cachedArtifact.DeepCopy() obj.Status.ObservedValuesFiles = []string{"values.yaml", "override.yaml"} @@ -1751,10 +1751,10 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { { name: "Updates ObservedValuesFiles after creating new artifact", build: mockChartBuild("helmchart", "0.1.0", "testdata/charts/helmchart-0.1.0.tgz", []string{"values.yaml", "override.yaml"}), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.GetArtifact()).ToNot(BeNil()) t.Expect(obj.GetArtifact().Digest).To(Equal("sha256:bbdf96023c912c393b49d5238e227576ed0d20d1bb145d7476d817b80e20c11a")) t.Expect(obj.GetArtifact().Revision).To(Equal("0.1.0")) @@ -1764,18 +1764,18 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), }, }, { name: "Updates ObservedValuesFiles with IgnoreMissingValuesFiles after creating new artifact", build: mockChartBuild("helmchart", "0.1.0", "testdata/charts/helmchart-0.1.0.tgz", []string{"values.yaml", "override.yaml"}), - beforeFunc: func(obj *helmv1.HelmChart) { + beforeFunc: func(obj *sourcev1.HelmChart) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") obj.Spec.ValuesFiles = []string{"values.yaml", "missing.yaml", "override.yaml"} obj.Spec.IgnoreMissingValuesFiles = true }, - afterFunc: func(t *WithT, obj *helmv1.HelmChart) { + afterFunc: func(t *WithT, obj *sourcev1.HelmChart) { t.Expect(obj.GetArtifact()).ToNot(BeNil()) t.Expect(obj.GetArtifact().Digest).To(Equal("sha256:bbdf96023c912c393b49d5238e227576ed0d20d1bb145d7476d817b80e20c11a")) t.Expect(obj.GetArtifact().Revision).To(Equal("0.1.0")) @@ -1785,7 +1785,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, helmv1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), + *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, sourcev1.ChartPullSucceededReason, "pulled 'helmchart' chart with version '0.1.0'"), }, }, } From 0af6e16a5a23d155355a33dd9f1e549d95dbd3a3 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 2 May 2024 16:23:00 +0300 Subject: [PATCH 3/7] docs: Remove deprecated aad-pod-identity Signed-off-by: Stefan Prodan --- docs/spec/v1/helmrepositories.md | 40 ++-------------------------- docs/spec/v1beta2/ocirepositories.md | 40 ++-------------------------- 2 files changed, 4 insertions(+), 76 deletions(-) diff --git a/docs/spec/v1/helmrepositories.md b/docs/spec/v1/helmrepositories.md index d8b6748e9..94d6c5af5 100644 --- a/docs/spec/v1/helmrepositories.md +++ b/docs/spec/v1/helmrepositories.md @@ -211,9 +211,8 @@ to the IAM role when using IRSA. #### Azure -The `azure` provider can be used to authenticate automatically using Workload Identity, Kubelet Managed -Identity or Azure Active Directory pod-managed identity (aad-pod-identity), and -by extension gain access to ACR. +The `azure` provider can be used to authenticate automatically using Workload Identity and Kubelet Managed +Identity to gain access to ACR. ##### Kubelet Managed Identity @@ -269,41 +268,6 @@ a federated identity between the source-controller ServiceAccount and the identity. Patch the source-controller Deployment and ServiceAccount as shown in the patch above. Please take a look at this [guide](https://azure.github.io/azure-workload-identity/docs/quick-start.html#6-establish-federated-identity-credential-between-the-identity-and-the-service-account-issuer--subject). -##### Deprecated: AAD Pod Identity - -**Warning:** The AAD Pod Identity project will be archived in -[September 2023](https://github.com/Azure/aad-pod-identity#-announcement), -and you are advised to use Workload Identity instead. - -When using aad-pod-identity to enable access to ACR, add the following patch to -your bootstrap repository, in the `flux-system/kustomization.yaml` file: - -```yaml -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - gotk-components.yaml - - gotk-sync.yaml -patches: - - patch: | - - op: add - path: /spec/template/metadata/labels/aadpodidbinding - value: - target: - kind: Deployment - name: source-controller -``` - -When using pod-managed identity on an AKS cluster, AAD Pod Identity has to be used -to give the `source-controller` pod access to the ACR. To do this, you have to install -`aad-pod-identity` on your cluster, create a managed identity that has access to the -container registry (this can also be the Kubelet identity if it has `AcrPull` role -assignment on the ACR), create an `AzureIdentity` and `AzureIdentityBinding` that describe -the managed identity and then label the `source-controller` deployment with the name of the -AzureIdentity as shown in the patch above. Please take a look at [this guide](https://azure.github.io/aad-pod-identity/docs/) -or [this one](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity) -if you want to use AKS pod-managed identities add-on that is in preview. - #### GCP The `gcp` provider can be used to authenticate automatically using OAuth scopes or diff --git a/docs/spec/v1beta2/ocirepositories.md b/docs/spec/v1beta2/ocirepositories.md index f40dab066..aafd6c7fb 100644 --- a/docs/spec/v1beta2/ocirepositories.md +++ b/docs/spec/v1beta2/ocirepositories.md @@ -157,9 +157,8 @@ to the IAM role when using IRSA. #### Azure -The `azure` provider can be used to authenticate automatically using Workload Identity, Kubelet Managed -Identity or Azure Active Directory pod-managed identity (aad-pod-identity), -and by extension gain access to ACR. +The `azure` provider can be used to authenticate automatically using Workload Identity and Kubelet Managed +Identity to gain access to ACR. ##### Kubelet Managed Identity @@ -215,41 +214,6 @@ a federated identity between the source-controller ServiceAccount and the identity. Patch the source-controller Deployment and ServiceAccount as shown in the patch above. Please take a look at this [guide](https://azure.github.io/azure-workload-identity/docs/quick-start.html#6-establish-federated-identity-credential-between-the-identity-and-the-service-account-issuer--subject). -##### Deprecated: AAD Pod Identity - -**Note:** The AAD Pod Identity project will be archived in [September 2023](https://github.com/Azure/aad-pod-identity#-announcement), -and you are advised to use Workload Identity instead. - -When using aad-pod-identity to enable access to ACR, add the following patch to -your bootstrap repository, in the `flux-system/kustomization.yaml` file: - -```yaml -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - gotk-components.yaml - - gotk-sync.yaml -patches: - - patch: | - - op: add - path: /spec/template/metadata/labels/aadpodidbinding - value: - target: - kind: Deployment - name: source-controller -``` - -When using pod-managed identity on an AKS cluster, AAD Pod Identity -has to be used to give the `source-controller` pod access to the ACR. -To do this, you have to install `aad-pod-identity` on your cluster, create a managed identity -that has access to the container registry (this can also be the Kubelet identity -if it has `AcrPull` role assignment on the ACR), create an `AzureIdentity` and `AzureIdentityBinding` -that describe the managed identity and then label the `source-controller` deployment -with the name of the AzureIdentity as shown in the patch above. Please take a look -at [this guide](https://azure.github.io/aad-pod-identity/docs/) or -[this one](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity) -if you want to use AKS pod-managed identities add-on that is in preview. - #### GCP The `gcp` provider can be used to authenticate automatically using OAuth scopes From e72a6452344126621f26e1609f3fca5daf1ebc6f Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 2 May 2024 16:35:39 +0300 Subject: [PATCH 4/7] Update dependencies Signed-off-by: Stefan Prodan --- api/go.mod | 2 +- api/go.sum | 4 ++-- go.mod | 14 +++++++------- go.sum | 39 ++++++++++++++++++++------------------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/api/go.mod b/api/go.mod index e56cb4fce..b5c2a116a 100644 --- a/api/go.mod +++ b/api/go.mod @@ -6,7 +6,7 @@ require ( github.com/fluxcd/pkg/apis/acl v0.3.0 github.com/fluxcd/pkg/apis/meta v1.5.0 k8s.io/apimachinery v0.30.0 - sigs.k8s.io/controller-runtime v0.18.0 + sigs.k8s.io/controller-runtime v0.18.1 ) // Fix CVE-2022-28948 diff --git a/api/go.sum b/api/go.sum index c237bead6..ff9892145 100644 --- a/api/go.sum +++ b/api/go.sum @@ -103,8 +103,8 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.0 h1:Z7jKuX784TQSUL1TIyeuF7j8KXZ4RtSX0YgtjKcSTME= -sigs.k8s.io/controller-runtime v0.18.0/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= +sigs.k8s.io/controller-runtime v0.18.1 h1:RpWbigmuiylbxOCLy0tGnq1cU1qWPwNIQzoJk+QeJx4= +sigs.k8s.io/controller-runtime v0.18.1/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/go.mod b/go.mod index 653642558..fa0137471 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,8 @@ require ( github.com/fluxcd/pkg/helmtestserver v0.18.0 github.com/fluxcd/pkg/lockedfile v0.3.0 github.com/fluxcd/pkg/masktoken v0.4.0 - github.com/fluxcd/pkg/oci v0.37.0 - github.com/fluxcd/pkg/runtime v0.47.0 + github.com/fluxcd/pkg/oci v0.37.1 + github.com/fluxcd/pkg/runtime v0.47.1 github.com/fluxcd/pkg/sourceignore v0.7.0 github.com/fluxcd/pkg/ssh v0.13.0 github.com/fluxcd/pkg/tar v0.7.0 @@ -46,7 +46,7 @@ require ( github.com/minio/minio-go/v7 v7.0.70 github.com/notaryproject/notation-core-go v1.0.2 github.com/notaryproject/notation-go v1.1.0 - github.com/onsi/gomega v1.32.0 + github.com/onsi/gomega v1.33.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest/blake3 v0.0.0-20231212064514-429d0316a3dd github.com/opencontainers/image-spec v1.1.0 @@ -68,7 +68,7 @@ require ( k8s.io/client-go v0.30.0 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 oras.land/oras-go/v2 v2.5.0 - sigs.k8s.io/controller-runtime v0.18.0 + sigs.k8s.io/controller-runtime v0.18.1 sigs.k8s.io/yaml v1.4.0 ) @@ -116,8 +116,8 @@ require ( github.com/aliyun/credentials-go v1.3.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.10 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect @@ -126,7 +126,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect github.com/aws/smithy-go v1.20.2 // indirect diff --git a/go.sum b/go.sum index 217453b3c..e299a9b0b 100644 --- a/go.sum +++ b/go.sum @@ -159,10 +159,10 @@ github.com/aws/aws-sdk-go v1.51.6 h1:Ld36dn9r7P9IjU8WZSaswQ8Y/XUCRpewim5980DwYiU github.com/aws/aws-sdk-go v1.51.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= -github.com/aws/aws-sdk-go-v2/config v1.27.10 h1:PS+65jThT0T/snC5WjyfHHyUgG+eBoupSDV+f838cro= -github.com/aws/aws-sdk-go-v2/config v1.27.10/go.mod h1:BePM7Vo4OBpHreKRUMuDXX+/+JWP38FLkzl5m27/Jjs= -github.com/aws/aws-sdk-go-v2/credentials v1.17.10 h1:qDZ3EA2lv1KangvQB6y258OssCHD0xvaGiEDkG4X/10= -github.com/aws/aws-sdk-go-v2/credentials v1.17.10/go.mod h1:6t3sucOaYDwDssHQa0ojH1RpmVmF5/jArkye1b2FKMI= +github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= +github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= @@ -181,8 +181,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/g github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 h1:WzFol5Cd+yDxPAdnzTA5LmpHYSWinhmSj4rQChV0ee8= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.4/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= @@ -352,10 +352,10 @@ github.com/fluxcd/pkg/lockedfile v0.3.0 h1:tZkBAffcxyt4zMigHIKc54cKgN5I/kFF005gy github.com/fluxcd/pkg/lockedfile v0.3.0/go.mod h1:5iCYXAs953LlXZq7nTId9ZSGnHVvTfZ0mDmrDE49upk= github.com/fluxcd/pkg/masktoken v0.4.0 h1:pRItymXzW8dhT9Fd4XfnbrgKeySPeeLCrr6W1pgrUbM= github.com/fluxcd/pkg/masktoken v0.4.0/go.mod h1:MP1nCsr2tJbH8hnhZP4+7TfTR0ggrKOJgi9Bo7Mj/6M= -github.com/fluxcd/pkg/oci v0.37.0 h1:hiRNMIGN1jKC2SrC4uWkSEQkGJnrZmSFYOYRL8/vVro= -github.com/fluxcd/pkg/oci v0.37.0/go.mod h1:shriYSpwJFwORG3djxg5V6mifC6jXyRYbcXqdLd2kmY= -github.com/fluxcd/pkg/runtime v0.47.0 h1:m3BEgwTYJslIF0lqhZMw6ZcKD6bD+4Ut+Xd/8X86SZA= -github.com/fluxcd/pkg/runtime v0.47.0/go.mod h1:UgHy8DTkU2MFHDe2q3b+OP4mBYTsopGhSzWb8rHJa9Q= +github.com/fluxcd/pkg/oci v0.37.1 h1:p4rfCHZlBWL+Q5Xey51iiBRmoje0IevCBT0/r8iae3M= +github.com/fluxcd/pkg/oci v0.37.1/go.mod h1:LrVuX6VACenJ5ycQJxec+I7YJegCsE4nzRUV+6RuxcY= +github.com/fluxcd/pkg/runtime v0.47.1 h1:Q1tAFsp92uurWyoEe52AmMC4k+6DYTPBrUQDs+nz/9c= +github.com/fluxcd/pkg/runtime v0.47.1/go.mod h1:97a+PqpWMgQsoqh91uH3EQz+/DC7Uxc8xcu/rDHFC5c= github.com/fluxcd/pkg/sourceignore v0.7.0 h1:qQrB2o543wA1o4vgR62ufwkAaDp8+f8Wdj1HKDlmDrU= github.com/fluxcd/pkg/sourceignore v0.7.0/go.mod h1:A4GuZt2seJJkBm3kMiIx9nheoYZs98KTMr/A6/2fIro= github.com/fluxcd/pkg/ssh v0.13.0 h1:lPU1Gst8XIz7AU2dhdqVFaaOWd54/O1LZu62vH4JB/s= @@ -443,7 +443,8 @@ github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqw github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= @@ -526,8 +527,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= -github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -748,14 +749,14 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/open-policy-agent/opa v0.63.0 h1:ztNNste1v8kH0/vJMJNquE45lRvqwrM5mY9Ctr9xIXw= github.com/open-policy-agent/opa v0.63.0/go.mod h1:9VQPqEfoB2N//AToTxzZ1pVTVPUoF2Mhd64szzjWPpU= github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be h1:f2PlhC9pm5sqpBZFvnAoKj+KzXRzbjFMA+TqXfJdgho= @@ -1311,8 +1312,8 @@ oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= -sigs.k8s.io/controller-runtime v0.18.0 h1:Z7jKuX784TQSUL1TIyeuF7j8KXZ4RtSX0YgtjKcSTME= -sigs.k8s.io/controller-runtime v0.18.0/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= +sigs.k8s.io/controller-runtime v0.18.1 h1:RpWbigmuiylbxOCLy0tGnq1cU1qWPwNIQzoJk+QeJx4= +sigs.k8s.io/controller-runtime v0.18.1/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.17.1 h1:MYJBOP/yQ3/5tp4/sf6HiiMfNNyO97LmtnirH9SLNr4= From 522f57377b4b1c14dda180cee9e153fd745048ba Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 2 May 2024 16:45:30 +0300 Subject: [PATCH 5/7] Update samples to v1 APIs Signed-off-by: Stefan Prodan --- ...beta2_gitrepository.yaml => source_v1_gitrepository.yaml} | 0 ...epository.yaml => source_v1_helmchart_gitrepository.yaml} | 2 +- ...-oci.yaml => source_v1_helmchart_helmrepository-oci.yaml} | 2 +- ...pository.yaml => source_v1_helmchart_helmrepository.yaml} | 5 +++-- ...repository-oci.yaml => source_v1_helmrepository-oci.yaml} | 2 +- ...ta2_helmrepository.yaml => source_v1_helmrepository.yaml} | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) rename config/samples/{source_v1beta2_gitrepository.yaml => source_v1_gitrepository.yaml} (100%) rename config/samples/{source_v1beta2_helmchart_gitrepository.yaml => source_v1_helmchart_gitrepository.yaml} (78%) rename config/samples/{source_v1beta2_helmchart_helmrepository-oci.yaml => source_v1_helmchart_helmrepository-oci.yaml} (82%) rename config/samples/{source_v1beta2_helmchart_helmrepository.yaml => source_v1_helmchart_helmrepository.yaml} (63%) rename config/samples/{source_v1beta2_helmrepository-oci.yaml => source_v1_helmrepository-oci.yaml} (72%) rename config/samples/{source_v1beta2_helmrepository.yaml => source_v1_helmrepository.yaml} (73%) diff --git a/config/samples/source_v1beta2_gitrepository.yaml b/config/samples/source_v1_gitrepository.yaml similarity index 100% rename from config/samples/source_v1beta2_gitrepository.yaml rename to config/samples/source_v1_gitrepository.yaml diff --git a/config/samples/source_v1beta2_helmchart_gitrepository.yaml b/config/samples/source_v1_helmchart_gitrepository.yaml similarity index 78% rename from config/samples/source_v1beta2_helmchart_gitrepository.yaml rename to config/samples/source_v1_helmchart_gitrepository.yaml index 731d8d21b..680e7b184 100644 --- a/config/samples/source_v1beta2_helmchart_gitrepository.yaml +++ b/config/samples/source_v1_helmchart_gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: helmchart-git-sample diff --git a/config/samples/source_v1beta2_helmchart_helmrepository-oci.yaml b/config/samples/source_v1_helmchart_helmrepository-oci.yaml similarity index 82% rename from config/samples/source_v1beta2_helmchart_helmrepository-oci.yaml rename to config/samples/source_v1_helmchart_helmrepository-oci.yaml index d2cdc15c6..d9dd3279d 100644 --- a/config/samples/source_v1beta2_helmchart_helmrepository-oci.yaml +++ b/config/samples/source_v1_helmchart_helmrepository-oci.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: helmchart-sample-oci diff --git a/config/samples/source_v1beta2_helmchart_helmrepository.yaml b/config/samples/source_v1_helmchart_helmrepository.yaml similarity index 63% rename from config/samples/source_v1beta2_helmchart_helmrepository.yaml rename to config/samples/source_v1_helmchart_helmrepository.yaml index a6bd7c207..d1b43fe3e 100644 --- a/config/samples/source_v1beta2_helmchart_helmrepository.yaml +++ b/config/samples/source_v1_helmchart_helmrepository.yaml @@ -1,11 +1,12 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: helmchart-sample spec: chart: podinfo - version: '>=2.0.0 <3.0.0' + version: '6.x' sourceRef: kind: HelmRepository name: helmrepository-sample interval: 1m + ignoreMissingValuesFiles: true diff --git a/config/samples/source_v1beta2_helmrepository-oci.yaml b/config/samples/source_v1_helmrepository-oci.yaml similarity index 72% rename from config/samples/source_v1beta2_helmrepository-oci.yaml rename to config/samples/source_v1_helmrepository-oci.yaml index bc487c990..458dc73c2 100644 --- a/config/samples/source_v1beta2_helmrepository-oci.yaml +++ b/config/samples/source_v1_helmrepository-oci.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: helmrepository-sample-oci diff --git a/config/samples/source_v1beta2_helmrepository.yaml b/config/samples/source_v1_helmrepository.yaml similarity index 73% rename from config/samples/source_v1beta2_helmrepository.yaml rename to config/samples/source_v1_helmrepository.yaml index 4a2c7ab36..b7049cc0a 100644 --- a/config/samples/source_v1beta2_helmrepository.yaml +++ b/config/samples/source_v1_helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: helmrepository-sample From af6cfc4d61521985adae407cbb8dc1c337d97841 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 2 May 2024 16:54:42 +0300 Subject: [PATCH 6/7] Remove deprecated `valuesFile` from HelmChart v1 Signed-off-by: Stefan Prodan --- api/v1/helmchart_types.go | 23 +------ api/v1/zz_generated.deepcopy.go | 5 -- .../source.toolkit.fluxcd.io_helmcharts.yaml | 35 ----------- docs/api/v1/source.md | 62 ------------------- 4 files changed, 1 insertion(+), 124 deletions(-) diff --git a/api/v1/helmchart_types.go b/api/v1/helmchart_types.go index 1527e6bc9..137b16450 100644 --- a/api/v1/helmchart_types.go +++ b/api/v1/helmchart_types.go @@ -21,7 +21,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/fluxcd/pkg/apis/acl" "github.com/fluxcd/pkg/apis/meta" ) @@ -70,14 +69,6 @@ type HelmChartSpec struct { // +optional ValuesFiles []string `json:"valuesFiles,omitempty"` - // ValuesFile is an 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 specified here - // is merged before the ValuesFiles items. Ignored when omitted. - // +optional - // +deprecated - ValuesFile string `json:"valuesFile,omitempty"` - // IgnoreMissingValuesFiles controls whether to silently ignore missing values // files rather than failing. // +optional @@ -88,12 +79,6 @@ type HelmChartSpec struct { // +optional Suspend bool `json:"suspend,omitempty"` - // AccessFrom specifies an Access Control List for allowing cross-namespace - // references to this object. - // NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 - // +optional - AccessFrom *acl.AccessFrom `json:"accessFrom,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. @@ -203,13 +188,7 @@ func (in *HelmChart) GetArtifact() *Artifact { // GetValuesFiles returns a merged list of HelmChartSpec.ValuesFiles. func (in *HelmChart) GetValuesFiles() []string { - valuesFiles := in.Spec.ValuesFiles - - // Prepend the deprecated ValuesFile to the list - if in.Spec.ValuesFile != "" { - valuesFiles = append([]string{in.Spec.ValuesFile}, valuesFiles...) - } - return valuesFiles + return in.Spec.ValuesFiles } // +genclient diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 38f4c41e3..0616741d4 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -335,11 +335,6 @@ func (in *HelmChartSpec) DeepCopyInto(out *HelmChartSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.AccessFrom != nil { - in, out := &in.AccessFrom, &out.AccessFrom - *out = new(acl.AccessFrom) - (*in).DeepCopyInto(*out) - } if in.Verify != nil { in, out := &in.Verify, &out.Verify *out = new(OCIRepositoryVerification) diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 45591d54a..0fd4de457 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -63,34 +63,6 @@ spec: spec: description: HelmChartSpec specifies the desired state of a Helm chart. properties: - accessFrom: - description: |- - AccessFrom specifies an Access Control List for allowing cross-namespace - references to this object. - NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 - properties: - namespaceSelectors: - description: |- - NamespaceSelectors is the list of namespace selectors to which this ACL applies. - Items in this list are evaluated using a logical OR operation. - items: - description: |- - NamespaceSelector selects the namespaces to which this ACL applies. - An empty map of MatchLabels matches all namespaces in a cluster. - properties: - matchLabels: - additionalProperties: - type: string - description: |- - MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - type: array - required: - - namespaceSelectors - type: object chart: description: |- Chart is the name or path the Helm chart is available at in the @@ -147,13 +119,6 @@ spec: Suspend tells the controller to suspend the reconciliation of this source. type: boolean - valuesFile: - description: |- - ValuesFile is an 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 specified here - is merged before the ValuesFiles items. Ignored when omitted. - type: string valuesFiles: description: |- ValuesFiles is an alternative list of values files to use as the chart diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index 3746ad76c..96c42bdfa 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -393,21 +393,6 @@ overriding the first. Ignored when omitted.

-valuesFile
- -string - - - -(Optional) -

ValuesFile is an 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 specified here -is merged before the ValuesFiles items. Ignored when omitted.

- - - - ignoreMissingValuesFiles
bool @@ -434,22 +419,6 @@ source.

-accessFrom
- -
-github.com/fluxcd/pkg/apis/acl.AccessFrom - - - - -(Optional) -

AccessFrom specifies an Access Control List for allowing cross-namespace -references to this object. -NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

- - - - verify
@@ -1490,21 +1459,6 @@ overriding the first. Ignored when omitted.

-valuesFile
- -string - - - -(Optional) -

ValuesFile is an 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 specified here -is merged before the ValuesFiles items. Ignored when omitted.

- - - - ignoreMissingValuesFiles
bool @@ -1531,22 +1485,6 @@ source.

-accessFrom
- -
-github.com/fluxcd/pkg/apis/acl.AccessFrom - - - - -(Optional) -

AccessFrom specifies an Access Control List for allowing cross-namespace -references to this object. -NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092

- - - - verify
From 31c4df4a8d68f250575eaba65347c98ae76e2de6 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 2 May 2024 17:50:43 +0300 Subject: [PATCH 7/7] Deprecate v1beta1 APIs Signed-off-by: Stefan Prodan --- api/v1beta1/bucket_types.go | 1 + api/v1beta1/helmchart_types.go | 1 + api/v1beta1/helmrepository_types.go | 1 + .../bases/source.toolkit.fluxcd.io_buckets.yaml | 2 ++ .../bases/source.toolkit.fluxcd.io_helmcharts.yaml | 2 ++ .../source.toolkit.fluxcd.io_helmrepositories.yaml | 2 ++ internal/controller/helmchart_controller.go | 14 +++++++------- internal/controller/helmrepository_controller.go | 2 +- 8 files changed, 17 insertions(+), 8 deletions(-) diff --git a/api/v1beta1/bucket_types.go b/api/v1beta1/bucket_types.go index 2b717547a..d69ff648b 100644 --- a/api/v1beta1/bucket_types.go +++ b/api/v1beta1/bucket_types.go @@ -195,6 +195,7 @@ func (in *Bucket) GetInterval() metav1.Duration { // +genclient // +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta1 Bucket is deprecated, upgrade to v1beta2" // +kubebuilder:printcolumn:name="Endpoint",type=string,JSONPath=`.spec.endpoint` // +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="" diff --git a/api/v1beta1/helmchart_types.go b/api/v1beta1/helmchart_types.go index 74bcc2c12..d4c1564cc 100644 --- a/api/v1beta1/helmchart_types.go +++ b/api/v1beta1/helmchart_types.go @@ -234,6 +234,7 @@ func (in *HelmChart) GetValuesFiles() []string { // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=hc // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta1 HelmChart is deprecated, upgrade to v1" // +kubebuilder:printcolumn:name="Chart",type=string,JSONPath=`.spec.chart` // +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.version` // +kubebuilder:printcolumn:name="Source Kind",type=string,JSONPath=`.spec.sourceRef.kind` diff --git a/api/v1beta1/helmrepository_types.go b/api/v1beta1/helmrepository_types.go index 9151ff253..fe0ed7124 100644 --- a/api/v1beta1/helmrepository_types.go +++ b/api/v1beta1/helmrepository_types.go @@ -184,6 +184,7 @@ func (in *HelmRepository) GetInterval() metav1.Duration { // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=helmrepo // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta1 HelmRepository is deprecated, upgrade to v1" // +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url` // +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="" diff --git a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml index df327ac8b..de096bf51 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml @@ -27,6 +27,8 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date + deprecated: true + deprecationWarning: v1beta1 Bucket is deprecated, upgrade to v1beta2 name: v1beta1 schema: openAPIV3Schema: diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 0fd4de457..c07b6ade7 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -383,6 +383,8 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date + deprecated: true + deprecationWarning: v1beta1 HelmChart is deprecated, upgrade to v1 name: v1beta1 schema: openAPIV3Schema: diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml index dc081faa2..f199fcd20 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml @@ -347,6 +347,8 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date + deprecated: true + deprecationWarning: v1beta1 HelmRepository is deprecated, upgrade to v1 name: v1beta1 schema: openAPIV3Schema: diff --git a/internal/controller/helmchart_controller.go b/internal/controller/helmchart_controller.go index b8d2aa88f..614b43b53 100644 --- a/internal/controller/helmchart_controller.go +++ b/internal/controller/helmchart_controller.go @@ -159,7 +159,7 @@ type HelmChartReconcilerOptions struct { RateLimiter ratelimiter.RateLimiter } -// helmChartReconcileFunc is the function type for all the v1beta2.HelmChart +// helmChartReconcileFunc is the function type for all the v1.HelmChart // (sub)reconcile functions. The type implementations are grouped and // executed serially to perform the complete reconcile of the object. type helmChartReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) @@ -512,9 +512,9 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.Ser } // buildFromHelmRepository attempts to pull and/or package a Helm chart with -// the specified data from the v1beta2.HelmRepository and v1beta2.HelmChart +// the specified data from the v1.HelmRepository and v1.HelmChart // objects. -// In case of a failure it records v1beta2.FetchFailedCondition on the chart +// In case of a failure it records v1.FetchFailedCondition on the chart // object, and returns early. func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *sourcev1.HelmChart, repo *sourcev1.HelmRepository, b *chart.Build) (sreconcile.Result, error) { @@ -696,9 +696,9 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj * } // buildFromTarballArtifact attempts to pull and/or package a Helm chart with -// the specified data from the v1beta2.HelmChart object and the given -// v1beta2.Artifact. -// In case of a failure it records v1beta2.FetchFailedCondition on the chart +// the specified data from the v1.HelmChart object and the given +// v1.Artifact. +// In case of a failure it records v1.FetchFailedCondition on the chart // object, and returns early. func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj *sourcev1.HelmChart, source sourcev1.Artifact, b *chart.Build) (sreconcile.Result, error) { // Create temporary working directory @@ -824,7 +824,7 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj // (Status) data on the object does not match the given. // // The inspection of the given data to the object is differed, ensuring any -// stale observations like v1beta2.ArtifactOutdatedCondition are removed. +// stale observations like v1.ArtifactOutdatedCondition are removed. // If the given Artifact does not differ from the object's current, it returns // early. // On a successful archive, the Artifact in the Status of the object is set, diff --git a/internal/controller/helmrepository_controller.go b/internal/controller/helmrepository_controller.go index 35bcfd08f..4a680caed 100644 --- a/internal/controller/helmrepository_controller.go +++ b/internal/controller/helmrepository_controller.go @@ -387,7 +387,7 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *pat // reconcileSource attempts to fetch the Helm repository index using the // specified configuration on the v1.HelmRepository object. // -// When the fetch fails, it records v.FetchFailedCondition=True and +// When the fetch fails, it records v1.FetchFailedCondition=True and // returns early. // If successful and the index is valid, any previous // v1.FetchFailedCondition is removed, and the repository.ChartRepository