diff --git a/api/v1beta2/helmchart_types.go b/api/v1beta2/helmchart_types.go index be66c418..1df61b97 100644 --- a/api/v1beta2/helmchart_types.go +++ b/api/v1beta2/helmchart_types.go @@ -28,28 +28,29 @@ import ( // HelmChartKind is the string representation of a HelmChart. const HelmChartKind = "HelmChart" -// HelmChartSpec defines the desired state of a Helm chart. +// HelmChartSpec specifies the desired state of a Helm chart. type HelmChartSpec struct { - // The name or path the Helm chart is available at in the SourceRef. + // Chart is the name or path the Helm chart is available at in the + // SourceRef. // +required Chart string `json:"chart"` - // The chart version semver expression, ignored for charts from GitRepository - // and Bucket sources. Defaults to latest when omitted. + // 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"` - // The reference to the Source the chart is available at. + // SourceRef is the reference to the Source the chart is available at. // +required SourceRef LocalHelmChartSourceReference `json:"sourceRef"` - // The interval at which to check the Source for updates. + // Interval is the interval at which to check the Source for updates. // +required Interval metav1.Duration `json:"interval"` - // Determines what enables the creation of a new artifact. Valid values are - // ('ChartVersion', 'Revision'). + // 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 @@ -57,26 +58,30 @@ type HelmChartSpec struct { // +optional ReconcileStrategy string `json:"reconcileStrategy,omitempty"` - // 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. + // 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"` - // 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 defined here is merged before the - // ValuesFiles items. Ignored when omitted. + // 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"` - // This flag tells the controller to suspend the reconciliation of this source. + // Suspend tells the controller to suspend the reconciliation of this + // source. // +optional Suspend bool `json:"suspend,omitempty"` - // AccessFrom defines an Access Control List for allowing cross-namespace references to this object. + // 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"` } @@ -107,18 +112,19 @@ type LocalHelmChartSourceReference struct { Name string `json:"name"` } -// HelmChartStatus defines the observed state of the HelmChart. +// HelmChartStatus records the observed state of the HelmChart. type HelmChartStatus struct { - // ObservedGeneration is the last observed generation. + // 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 Source reference. + // of the HelmChartSpec.SourceRef. // +optional ObservedSourceArtifactRevision string `json:"observedSourceArtifactRevision,omitempty"` - // ObservedChartName is the last observed chart name as defined by the + // ObservedChartName is the last observed chart name as specified by the // resolved chart reference. // +optional ObservedChartName string `json:"observedChartName,omitempty"` @@ -127,11 +133,13 @@ type HelmChartStatus struct { // +optional Conditions []metav1.Condition `json:"conditions,omitempty"` - // URL is the fetch link for the last chart pulled. + // 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 chart sync. + // Artifact represents the output of the last successful reconciliation. // +optional Artifact *Artifact `json:"artifact,omitempty"` @@ -139,19 +147,11 @@ type HelmChartStatus struct { } const ( - // ChartPullFailedReason represents the fact that the pull of the Helm chart - // failed. - ChartPullFailedReason string = "ChartPullFailed" - - // ChartPullSucceededReason represents the fact that the pull of the Helm chart + // ChartPullSucceededReason signals that the pull of the Helm chart // succeeded. ChartPullSucceededReason string = "ChartPullSucceeded" - // ChartPackageFailedReason represent the fact that the package of the Helm - // chart failed. - ChartPackageFailedReason string = "ChartPackageFailed" - - // ChartPackageSucceededReason represents the fact that the package of the Helm + // ChartPackageSucceededReason signals that the package of the Helm // chart succeeded. ChartPackageSucceededReason string = "ChartPackageSucceeded" ) @@ -166,23 +166,19 @@ func (in *HelmChart) SetConditions(conditions []metav1.Condition) { in.Status.Conditions = conditions } -// GetRequeueAfter returns the duration after which the source must be reconciled again. +// GetRequeueAfter returns the duration after which the source must be +// reconciled again. func (in HelmChart) GetRequeueAfter() time.Duration { return in.Spec.Interval.Duration } -// GetInterval returns the interval at which the source is reconciled. -// Deprecated: use GetRequeueAfter instead. -func (in HelmChart) GetInterval() metav1.Duration { - return in.Spec.Interval -} - -// GetArtifact returns the latest artifact from the source if present in the status sub-resource. +// 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 ValuesFiles. +// GetValuesFiles returns a merged list of HelmChartSpec.ValuesFiles. func (in *HelmChart) GetValuesFiles() []string { valuesFiles := in.Spec.ValuesFiles @@ -193,12 +189,6 @@ func (in *HelmChart) GetValuesFiles() []string { return valuesFiles } -// GetStatusConditions returns a pointer to the Status.Conditions slice. -// Deprecated: use GetConditions instead. -func (in *HelmChart) GetStatusConditions() *[]metav1.Condition { - return &in.Status.Conditions -} - // +genclient // +genclient:Namespaced // +kubebuilder:storageversion @@ -213,7 +203,7 @@ func (in *HelmChart) GetStatusConditions() *[]metav1.Condition { // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" -// HelmChart is the Schema for the helmcharts API +// HelmChart is the Schema for the helmcharts API. type HelmChart struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -223,9 +213,8 @@ type HelmChart struct { Status HelmChartStatus `json:"status,omitempty"` } +// HelmChartList contains a list of HelmChart objects. // +kubebuilder:object:root=true - -// HelmChartList contains a list of HelmChart type HelmChartList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 06de2d4e..deb7a667 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -299,7 +299,7 @@ spec: name: v1beta2 schema: openAPIV3Schema: - description: HelmChart is the Schema for the helmcharts API + description: HelmChart is the Schema for the helmcharts API. properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -314,11 +314,12 @@ spec: metadata: type: object spec: - description: HelmChartSpec defines the desired state of a Helm chart. + description: HelmChartSpec specifies the desired state of a Helm chart. properties: accessFrom: - description: AccessFrom defines an Access Control List for allowing - cross-namespace references to this object. + 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 @@ -344,24 +345,26 @@ spec: - namespaceSelectors type: object chart: - description: The name or path the Helm chart is available at in the - SourceRef. + description: Chart is the name or path the Helm chart is available + at in the SourceRef. type: string interval: - description: The interval at which to check the Source for updates. + description: Interval is the interval at which to check the Source + for updates. type: string reconcileStrategy: default: ChartVersion - description: 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. + 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: The reference to the Source the chart is available at. + description: SourceRef is the reference to the Source the chart is + available at. properties: apiVersion: description: APIVersion of the referent. @@ -382,28 +385,30 @@ spec: - name type: object suspend: - description: This flag tells the controller to suspend the reconciliation + description: Suspend tells the controller to suspend the reconciliation of this source. type: boolean valuesFile: - description: 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 defined here - is merged before the ValuesFiles items. Ignored when omitted. + 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: 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. + 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 version: default: '*' - description: The chart version semver expression, ignored for charts - from GitRepository and Bucket sources. Defaults to latest when omitted. + 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 @@ -413,11 +418,11 @@ spec: status: default: observedGeneration: -1 - description: HelmChartStatus defines the observed state of the HelmChart. + description: HelmChartStatus records the observed state of the HelmChart. properties: artifact: description: Artifact represents the output of the last successful - chart sync. + reconciliation. properties: checksum: description: Checksum is the SHA256 checksum of the Artifact file. @@ -524,18 +529,21 @@ spec: type: string observedChartName: description: ObservedChartName is the last observed chart name as - defined by the resolved chart reference. + specified by the resolved chart reference. type: string observedGeneration: - description: ObservedGeneration is the last observed generation. + 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 Source reference. + of the HelmChartSpec.SourceRef. type: string url: - description: URL is the fetch link for the last chart pulled. + 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 diff --git a/controllers/helmchart_controller.go b/controllers/helmchart_controller.go index 9777c33c..89209120 100644 --- a/controllers/helmchart_controller.go +++ b/controllers/helmchart_controller.go @@ -63,9 +63,9 @@ import ( "github.com/fluxcd/source-controller/internal/util" ) -// helmChartReadyConditions contains all the conditions information +// helmChartReadyCondition contains all the conditions information // needed for HelmChart Ready status conditions summary calculation. -var helmChartReadyConditions = summarize.Conditions{ +var helmChartReadyCondition = summarize.Conditions{ Target: meta.ReadyCondition, Owned: []string{ sourcev1.BuildFailedCondition, @@ -114,7 +114,10 @@ type HelmChartReconcilerOptions struct { MaxConcurrentReconciles int } -type helmChartReconcilerFunc func(ctx context.Context, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) +// 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, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) func (r *HelmChartReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmChartReconcilerOptions) error { if err := mgr.GetCache().IndexField(context.TODO(), &sourcev1.HelmRepository{}, sourcev1.HelmRepositoryURLIndexKey, @@ -182,7 +185,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( defer func() { summarizeHelper := summarize.NewHelper(r.EventRecorder, patchHelper) summarizeOpts := []summarize.Option{ - summarize.WithConditions(helmChartReadyConditions), + summarize.WithConditions(helmChartReadyCondition), summarize.WithReconcileResult(recResult), summarize.WithReconcileError(retErr), summarize.WithIgnoreNotFound(), @@ -190,7 +193,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( summarize.RecordContextualError, summarize.RecordReconcileReq, ), - summarize.WithResultBuilder(sreconcile.AlwaysRequeueResultBuilder{RequeueAfter: obj.GetInterval().Duration}), + summarize.WithResultBuilder(sreconcile.AlwaysRequeueResultBuilder{RequeueAfter: obj.GetRequeueAfter()}), } result, retErr = summarizeHelper.SummarizeAndPatch(ctx, obj, summarizeOpts...) @@ -214,7 +217,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } // Reconcile actual object - reconcilers := []helmChartReconcilerFunc{ + reconcilers := []helmChartReconcileFunc{ r.reconcileStorage, r.reconcileSource, r.reconcileArtifact, @@ -223,9 +226,10 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return } -// reconcile steps through the actual reconciliation tasks for the object, it returns early on the first step that -// produces an error. -func (r *HelmChartReconciler) reconcile(ctx context.Context, obj *sourcev1.HelmChart, reconcilers []helmChartReconcilerFunc) (sreconcile.Result, error) { +// reconcile iterates through the gitRepositoryReconcileFunc 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, obj *sourcev1.HelmChart, reconcilers []helmChartReconcileFunc) (sreconcile.Result, error) { if obj.Generation != obj.Status.ObservedGeneration { conditions.MarkReconciling(obj, "NewGeneration", "reconciling new object generation (%d)", obj.Generation) } @@ -255,14 +259,17 @@ func (r *HelmChartReconciler) reconcile(ctx context.Context, obj *sourcev1.HelmC return res, resErr } -// reconcileStorage ensures the current state of the storage matches the desired and previously observed state. +// reconcileStorage ensures the current state of the storage matches the +// desired and previously observed state. // -// All artifacts for the resource except for the current one are garbage collected from the storage. -// If the artifact in the Status object of the resource disappeared from storage, it is removed from the object. -// If the object does not have an artifact in its Status object, a v1beta1.ArtifactUnavailableCondition is set. -// If the hostname of the URLs on the object do not match the current storage server hostname, they are updated. -// -// The caller should assume a failure if an error is returned, or the BuildResult is zero. +// All Artifacts for the object except for the current one in the Status are +// garbage collected from the Storage. +// If the Artifact in the Status of the object disappeared from the Storage, +// it is removed from the object. +// If the object does not have an Artifact in its Status, a Reconciling +// 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, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -364,6 +371,11 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1 } } +// buildFromHelmRepository attempts to pull and/or package a Helm chart with +// the specified data from the v1beta2.HelmRepository and v1beta2.HelmChart +// 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 *sourcev1.HelmChart, repo *sourcev1.HelmRepository, b *chart.Build) (sreconcile.Result, error) { @@ -460,6 +472,10 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj * return sreconcile.ResultSuccess, nil } +// buildFromHelmRepository attempts to pull and/or package a Helm chart with +// the specified data v1beta2.HelmChart object and the given 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 *sourcev1.HelmChart, source sourcev1.Artifact, b *chart.Build) (sreconcile.Result, error) { // Create temporary working directory tmpDir, err := util.TempDirForObj("", obj) @@ -589,8 +605,15 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj return sreconcile.ResultSuccess, nil } -// reconcileArtifact reconciles the given chart.Build to an v1beta1.Artifact in the Storage, and records it -// on the object. +// reconcileArtifact archives a new Artifact to the Storage, if the current +// (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. +// 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 *HelmChartReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.HelmChart, b *chart.Build) (sreconcile.Result, error) { // Without a complete chart build, there is little to reconcile if !b.Complete() { @@ -697,8 +720,9 @@ func (r *HelmChartReconciler) getSource(ctx context.Context, obj *sourcev1.HelmC return s, nil } -// reconcileDelete handles the delete of an object. It first garbage collects all artifacts for the object from the -// artifact storage, if successful, the finalizer is removed from the object. +// 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 *sourcev1.HelmChart) (sreconcile.Result, error) { // Garbage collect the resource's artifacts if err := r.garbageCollect(ctx, obj); err != nil { @@ -713,9 +737,11 @@ func (r *HelmChartReconciler) reconcileDelete(ctx context.Context, obj *sourcev1 return sreconcile.ResultEmpty, nil } -// garbageCollect performs a garbage collection for the given v1beta1.HelmChart. It removes all but the current -// artifact, unless the deletion timestamp is set. Which will result in the removal of all artifacts for the -// resource. +// garbageCollect performs a garbage collection for the given object. +// +// 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 *sourcev1.HelmChart) error { if !obj.DeletionTimestamp.IsZero() { if deleted, err := r.Storage.RemoveAll(r.Storage.NewArtifactFor(obj.Kind, obj.GetObjectMeta(), "", "*")); err != nil { @@ -923,9 +949,11 @@ func (r *HelmChartReconciler) requestsForBucketChange(o client.Object) []reconci return reqs } -// eventLogf records event and logs at the same time. This log is different from -// the debug log in the event recorder in the sense that this is a simple log, -// the event recorder debug log contains complete details about the event. +// eventLogf records event and logs at the same time. +// +// This log is different from the debug log in the EventRecorder, in the sense +// that this is a simple log. While the debug log contains complete details +// about the event. func (r *HelmChartReconciler) eventLogf(ctx context.Context, obj runtime.Object, eventType string, reason string, messageFmt string, args ...interface{}) { msg := fmt.Sprintf(messageFmt, args...) // Log and emit event. diff --git a/controllers/helmchart_controller_test.go b/controllers/helmchart_controller_test.go index 8944966a..de84e3be 100644 --- a/controllers/helmchart_controller_test.go +++ b/controllers/helmchart_controller_test.go @@ -125,7 +125,7 @@ func TestHelmChartReconciler_Reconcile(t *testing.T) { }, timeout).Should(BeTrue()) // Check if the object status is valid. - condns := &status.Conditions{NegativePolarity: helmChartReadyConditions.NegativePolarity} + condns := &status.Conditions{NegativePolarity: helmChartReadyCondition.NegativePolarity} checker := status.NewChecker(testEnv.Client, testEnv.GetScheme(), condns) checker.CheckErr(ctx, obj) @@ -1342,8 +1342,8 @@ func TestHelmChartReconciler_reconcileDelete(t *testing.T) { } func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { - // Helper to build simple helmChartReconcilerFunc with result and error. - buildReconcileFuncs := func(r sreconcile.Result, e error) helmChartReconcilerFunc { + // Helper to build simple helmChartReconcileFunc with result and error. + buildReconcileFuncs := func(r sreconcile.Result, e error) helmChartReconcileFunc { return func(_ context.Context, _ *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { return r, e } @@ -1353,14 +1353,14 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { name string generation int64 observedGeneration int64 - reconcileFuncs []helmChartReconcilerFunc + reconcileFuncs []helmChartReconcileFunc wantResult sreconcile.Result wantErr bool assertConditions []metav1.Condition }{ { name: "successful reconciliations", - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ buildReconcileFuncs(sreconcile.ResultSuccess, nil), }, wantResult: sreconcile.ResultSuccess, @@ -1370,7 +1370,7 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { name: "successful reconciliation with generation difference", generation: 3, observedGeneration: 2, - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ buildReconcileFuncs(sreconcile.ResultSuccess, nil), }, wantResult: sreconcile.ResultSuccess, @@ -1381,7 +1381,7 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { }, { name: "failed reconciliation", - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ buildReconcileFuncs(sreconcile.ResultEmpty, fmt.Errorf("some error")), }, wantResult: sreconcile.ResultEmpty, @@ -1389,7 +1389,7 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { }, { name: "multiple object status conditions mutations", - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ func(_ context.Context, obj *sourcev1.HelmChart, _ *chart.Build) (sreconcile.Result, error) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "new index revision") return sreconcile.ResultSuccess, nil @@ -1408,7 +1408,7 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { }, { name: "subrecs with one result=Requeue, no error", - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ buildReconcileFuncs(sreconcile.ResultSuccess, nil), buildReconcileFuncs(sreconcile.ResultRequeue, nil), buildReconcileFuncs(sreconcile.ResultSuccess, nil), @@ -1418,7 +1418,7 @@ func TestHelmChartReconciler_reconcileSubRecs(t *testing.T) { }, { name: "subrecs with error before result=Requeue", - reconcileFuncs: []helmChartReconcilerFunc{ + reconcileFuncs: []helmChartReconcileFunc{ buildReconcileFuncs(sreconcile.ResultSuccess, nil), buildReconcileFuncs(sreconcile.ResultEmpty, fmt.Errorf("some error")), buildReconcileFuncs(sreconcile.ResultRequeue, nil), diff --git a/docs/api/source.md b/docs/api/source.md index 43b51e56..157653b4 100644 --- a/docs/api/source.md +++ b/docs/api/source.md @@ -486,7 +486,7 @@ GitRepositoryStatus

HelmChart

-

HelmChart is the Schema for the helmcharts API

+

HelmChart is the Schema for the helmcharts API.

@@ -549,7 +549,8 @@ string @@ -561,8 +562,8 @@ string @@ -575,7 +576,7 @@ LocalHelmChartSourceReference @@ -588,7 +589,7 @@ Kubernetes meta/v1.Duration @@ -600,8 +601,8 @@ string @@ -615,10 +616,11 @@ Defaults to ChartVersion when omitted.

@@ -630,10 +632,10 @@ string @@ -645,7 +647,8 @@ bool @@ -659,7 +662,9 @@ github.com/fluxcd/pkg/apis/acl.AccessFrom
-

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

+

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

(Optional) -

The chart version semver expression, ignored for charts from GitRepository -and Bucket sources. Defaults to latest when omitted.

+

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

-

The reference to the Source the chart is available at.

+

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

-

The interval at which to check the Source for updates.

+

Interval is the interval at which to check the Source for updates.

(Optional) -

Determines what enables the creation of a new artifact. Valid values are -(‘ChartVersion’, ‘Revision’). +

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.

(Optional) -

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.

+

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

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

+

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

This flag tells the controller to suspend the reconciliation of this source.

+

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

(Optional) -

AccessFrom defines an Access Control List for allowing cross-namespace references to this object.

+

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

@@ -1295,7 +1300,7 @@ string (Optional) -

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

+

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

When GitRepositorySpec.GitImplementation is set to ‘go-git’, a shallow clone of the specified branch is performed.

@@ -1309,7 +1314,7 @@ string (Optional) -

Tag to checkout, takes precedence over Branch.

+

Tag to check out, takes precedence over Branch.

@@ -1321,7 +1326,7 @@ string (Optional) -

SemVer tag expression to checkout, takes precedence over Tag.

+

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

@@ -1333,7 +1338,7 @@ string (Optional) -

Commit SHA to checkout, takes precedence over all reference fields.

+

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

When GitRepositorySpec.GitImplementation is set to ‘go-git’, this can be combined with Branch to shallow clone the branch, in which the commit is expected to exist.

@@ -1694,7 +1699,7 @@ authors.

(Appears on: HelmChart)

-

HelmChartSpec defines the desired state of a Helm chart.

+

HelmChartSpec specifies the desired state of a Helm chart.

@@ -1713,7 +1718,8 @@ string @@ -1725,8 +1731,8 @@ string @@ -1739,7 +1745,7 @@ LocalHelmChartSourceReference @@ -1752,7 +1758,7 @@ Kubernetes meta/v1.Duration @@ -1764,8 +1770,8 @@ string @@ -1779,10 +1785,11 @@ Defaults to ChartVersion when omitted.

@@ -1794,10 +1801,10 @@ string @@ -1809,7 +1816,8 @@ bool @@ -1823,7 +1831,9 @@ github.com/fluxcd/pkg/apis/acl.AccessFrom @@ -1836,7 +1846,7 @@ github.com/fluxcd/pkg/apis/acl.AccessFrom (Appears on:HelmChart)

-

HelmChartStatus defines the observed state of the HelmChart.

+

HelmChartStatus records the observed state of the HelmChart.

-

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

+

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

(Optional) -

The chart version semver expression, ignored for charts from GitRepository -and Bucket sources. Defaults to latest when omitted.

+

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

-

The reference to the Source the chart is available at.

+

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

-

The interval at which to check the Source for updates.

+

Interval is the interval at which to check the Source for updates.

(Optional) -

Determines what enables the creation of a new artifact. Valid values are -(‘ChartVersion’, ‘Revision’). +

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.

(Optional) -

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.

+

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

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

+

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

This flag tells the controller to suspend the reconciliation of this source.

+

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

(Optional) -

AccessFrom defines an Access Control List for allowing cross-namespace references to this object.

+

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

@@ -1856,7 +1866,8 @@ int64 @@ -1869,7 +1880,7 @@ string @@ -1881,7 +1892,7 @@ string @@ -1908,7 +1919,9 @@ string @@ -1922,7 +1935,7 @@ Artifact diff --git a/docs/spec/v1beta2/README.md b/docs/spec/v1beta2/README.md index 7e5ab30b..91784805 100644 --- a/docs/spec/v1beta2/README.md +++ b/docs/spec/v1beta2/README.md @@ -7,7 +7,7 @@ This is the v1beta2 API specification for defining the desired state sources of * Source kinds: + [GitRepository](gitrepositories.md) + [HelmRepository](helmrepositories.md) - + HelmChart + + [HelmChart](helmcharts.md) + [Bucket](buckets.md) ## Implementation diff --git a/docs/spec/v1beta2/helmcharts.md b/docs/spec/v1beta2/helmcharts.md new file mode 100644 index 00000000..2e78131f --- /dev/null +++ b/docs/spec/v1beta2/helmcharts.md @@ -0,0 +1,481 @@ +# 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/v1beta2 +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 READY STATUS AGE + podinfo podinfo 5.* HelmRepository podinfo True pulled 'podinfo' chart with version '5.2.1' 53s + ``` + +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: 83a3c595163a6ff0333e0154c790383b5be441b9db632cb36da11db1c4ece111 + Artifact: + Checksum: 6c3cc3b955bce1686036ae6822ee2ca0ef6ecb994e3f2d19eaf3ec03dcba84b3 + Last Update Time: 2022-02-13T11:24:10Z + Path: helmchart/default/podinfo/podinfo-5.2.1.tgz + Revision: 5.2.1 + 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 + 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). + +### 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. + +### Source reference + +`.spec.sourceRef` is a required field that specifies a reference to the Source +the chart is available at. `.spec.sourceRef.kind` must be one of +`HelmRepository`, `GitRepository` or `Bucket`. `.spec.sourceRef.name` is the +name of the referred kind. + +### 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. For GitRepository and +Bucket Source reference, it'll be the path to the Helm chart directory. + +### 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 `*`. + +### 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. + +### 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 the HelmRepository. `Revision` is used for creating a new artifact +when the source revision changes in GitRepository or Bucket Source references. +It defaults to `ChartVersion`. + +### 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). + +## 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 --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/v1beta2 +kind: HelmChart +metadata: + name: +spec: + suspend: true +``` + +Using `kubectl`: + +```sh +kubectl patch helmchart -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/v1beta2 +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 -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 get events` can be used in +combination with `--field-selector` to list the Events for specific objects. +For example, running + +```sh +kubectl get events --field-selector involvedObject.kind=HelmChart,involvedObject.name= +``` + +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' +``` + +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=`. + +## 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/v1beta2 +kind: HelmChart +metadata: + name: +status: + artifact: + checksum: e30b95a08787de69ffdad3c232d65cfb131b5b50c6fd44295f48a078fceaa44e + lastUpdateTime: "2022-02-10T18:53:47Z" + path: helmchart///-.tgz + revision: 6.0.3 + url: http://source-controller.flux-system.svc.cluster.local./helmchart///-.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 +`False`, and the controller adds a Condition with the following attributes to +the HelmChart's `.status.conditions`: + +- `type: Reconciling` +- `status: "True"` +- `reason: NewGeneration` | `reason: NoArtifact` + +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. + +#### 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. + +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` +- `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"`. + +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. + +#### 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 +[Source reference's](#source-reference) Artifact the current chart was fetched +from in the HelmChart's `.status.observedSourceArtifactRevision`. + +### Observed Chart Name + +The source-controller reports the resolved chart name of the current Artifact +for the [`.spec.chart` field](#chart) in the HelmChart's +`.status.observedChartName`. + +### 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
(Optional) -

ObservedGeneration is the last observed generation.

+

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

(Optional)

ObservedSourceArtifactRevision is the last observed Artifact.Revision -of the Source reference.

+of the HelmChartSpec.SourceRef.

(Optional) -

ObservedChartName is the last observed chart name as defined by the +

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

(Optional) -

URL is the fetch link for the last chart pulled.

+

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

Artifact represents the output of the last successful chart sync.

+

Artifact represents the output of the last successful reconciliation.