Add ReconcileStrategy to HelmChart
This commit adds a `ReconcileStrategy` field to the `HelmChart` resource, which allows defining when a new chart should be packaged and/or published if it originates from a `Bucket` or `GitRepository` resource. The two available strategies are: - `ChartVersion`: creates a new artifact when the version of the Helm chart as defined in the `Chart.yaml` from the Source is different from the current version. - `Revision`: creates a new artifact when the revision of the Source is different from the current revision. For the `Revision` strategy, the (checksum part of the) revision of the artifact the chart originatesfrom is added as SemVer metadata. A chart from a `GitRepository` with Artifact revision `main/f0faacd5164a875ebdbd9e3fab778f49c5aadbbc` and a chart with e.g. SemVer `0.1.0` will be published as `0.1.0+f0faacd5164a875ebdbd9e3fab778f49c5aadbbc`. A chart from a `Bucket` with Artifact revision `f0faacd5164a875ebdbd9e3fab778f49c5aadbbc` and a chart with e.g. SemVer `0.1.0` will be published as `0.1.0+f0faacd5164a875ebdbd9e3fab778f49c5aadbbc`. Signed-off-by: Dylan Arbour <arbourd@users.noreply.github.com>
This commit is contained in:
parent
c4cc0a7ccf
commit
27c385b957
|
@ -45,6 +45,15 @@ type HelmChartSpec struct {
|
|||
// +required
|
||||
Interval metav1.Duration `json:"interval"`
|
||||
|
||||
// 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"`
|
||||
|
||||
// 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
|
||||
|
@ -65,6 +74,14 @@ type HelmChartSpec struct {
|
|||
Suspend bool `json:"suspend,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 {
|
||||
|
|
|
@ -62,6 +62,13 @@ spec:
|
|||
interval:
|
||||
description: 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.
|
||||
enum:
|
||||
- ChartVersion
|
||||
- Revision
|
||||
type: string
|
||||
sourceRef:
|
||||
description: The reference to the Source the chart is available at.
|
||||
properties:
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/go-logr/logr"
|
||||
helmchart "helm.sh/helm/v3/pkg/chart"
|
||||
|
@ -526,9 +527,29 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
|
|||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion(helmChart.Metadata.Version)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("semver error: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
version := v.String()
|
||||
if chart.Spec.ReconcileStrategy == sourcev1.ReconcileStrategyRevision {
|
||||
// Isolate the commit SHA from GitRepository type artifacts by removing the branch/ prefix.
|
||||
splitRev := strings.Split(artifact.Revision, "/")
|
||||
v, err := v.SetMetadata(splitRev[len(splitRev)-1])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("semver error: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
version = v.String()
|
||||
helmChart.Metadata.Version = v.String()
|
||||
}
|
||||
|
||||
// Return early if the revision is still the same as the current chart artifact
|
||||
newArtifact := r.Storage.NewArtifactFor(chart.Kind, chart.ObjectMeta.GetObjectMeta(), helmChart.Metadata.Version,
|
||||
fmt.Sprintf("%s-%s.tgz", helmChart.Metadata.Name, helmChart.Metadata.Version))
|
||||
newArtifact := r.Storage.NewArtifactFor(chart.Kind, chart.ObjectMeta.GetObjectMeta(), version,
|
||||
fmt.Sprintf("%s-%s.tgz", helmChart.Metadata.Name, version))
|
||||
if !force && apimeta.IsStatusConditionTrue(chart.Status.Conditions, meta.ReadyCondition) && chart.GetArtifact().HasRevision(newArtifact.Revision) {
|
||||
if newArtifact.URL != artifact.URL {
|
||||
r.Storage.SetArtifactURL(chart.GetArtifact())
|
||||
|
|
|
@ -709,7 +709,7 @@ var _ = Describe("HelmChartReconciler", func() {
|
|||
err = f.Close()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = wt.Commit("Chart version bump", &git.CommitOptions{
|
||||
commit, err := wt.Commit("Chart version bump", &git.CommitOptions{
|
||||
Author: &object.Signature{
|
||||
Name: "John Doe",
|
||||
Email: "john@example.com",
|
||||
|
@ -735,6 +735,21 @@ var _ = Describe("HelmChartReconciler", func() {
|
|||
Expect(helmChart.Values["testDefault"]).To(BeTrue())
|
||||
Expect(helmChart.Values["testOverride"]).To(BeFalse())
|
||||
|
||||
When("Setting reconcileStrategy to Revision", func() {
|
||||
updated := &sourcev1.HelmChart{}
|
||||
Expect(k8sClient.Get(context.Background(), key, updated)).To(Succeed())
|
||||
updated.Spec.ReconcileStrategy = sourcev1.ReconcileStrategyRevision
|
||||
Expect(k8sClient.Update(context.Background(), updated)).To(Succeed())
|
||||
got := &sourcev1.HelmChart{}
|
||||
Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), key, got)
|
||||
return got.Status.Artifact.Revision != updated.Status.Artifact.Revision &&
|
||||
storage.ArtifactExist(*got.Status.Artifact)
|
||||
}, timeout, interval).Should(BeTrue())
|
||||
Expect(got.Status.Artifact.Revision).To(ContainSubstring(updated.Status.Artifact.Revision))
|
||||
Expect(got.Status.Artifact.Revision).To(ContainSubstring(commit.String()))
|
||||
})
|
||||
|
||||
When("Setting valid valuesFiles attribute", func() {
|
||||
updated := &sourcev1.HelmChart{}
|
||||
Expect(k8sClient.Get(context.Background(), key, updated)).To(Succeed())
|
||||
|
|
|
@ -555,6 +555,21 @@ Kubernetes meta/v1.Duration
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>reconcileStrategy</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Determines what enables reconciliation. Valid values are (‘ChartVersion’,
|
||||
‘Revision’). See the documentation of the values for an explanation on their
|
||||
behavior.
|
||||
Defaults to ChartVersion when omitted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>valuesFiles</code><br>
|
||||
<em>
|
||||
[]string
|
||||
|
@ -1613,6 +1628,21 @@ Kubernetes meta/v1.Duration
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>reconcileStrategy</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Determines what enables reconciliation. Valid values are (‘ChartVersion’,
|
||||
‘Revision’). See the documentation of the values for an explanation on their
|
||||
behavior.
|
||||
Defaults to ChartVersion when omitted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>valuesFiles</code><br>
|
||||
<em>
|
||||
[]string
|
||||
|
|
|
@ -28,6 +28,15 @@ type HelmChartSpec struct {
|
|||
// +required
|
||||
Interval metav1.Duration `json:"interval"`
|
||||
|
||||
// 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"`
|
||||
|
||||
// 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
|
||||
|
@ -49,6 +58,18 @@ type HelmChartSpec struct {
|
|||
}
|
||||
```
|
||||
|
||||
### Reconciliation strategies
|
||||
|
||||
```go
|
||||
const (
|
||||
// ReconcileStrategyChartVersion creates a new chart artifact when the version of the Helm chart is different.
|
||||
ReconcileStrategyChartVersion string = "ChartVersion"
|
||||
|
||||
// ReconcileStrategyRevision creates a new chart artifact when the Revision of the SourceRef is different.
|
||||
ReconcileStrategyRevision string = "Revision"
|
||||
)
|
||||
```
|
||||
|
||||
### Reference types
|
||||
|
||||
```go
|
||||
|
@ -230,6 +251,23 @@ spec:
|
|||
- ./charts/podinfo/values-production.yaml
|
||||
```
|
||||
|
||||
Reconcile with every change to the source revision:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||
kind: HelmChart
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: default
|
||||
spec:
|
||||
chart: ./charts/podinfo
|
||||
sourceRef:
|
||||
name: podinfo
|
||||
kind: GitRepository
|
||||
interval: 10m
|
||||
reconcileStrategy: Revision
|
||||
```
|
||||
|
||||
## Status examples
|
||||
|
||||
Successful chart pull:
|
||||
|
|
Loading…
Reference in New Issue