Skip to content

Commit

Permalink
Merge pull request #308 from arbourd/ignore-version
Browse files Browse the repository at this point in the history
Add reconcile strategy for HelmCharts
  • Loading branch information
hiddeco authored Oct 8, 2021
2 parents c4cc0a7 + 27c385b commit d382eca
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 3 deletions.
17 changes: 17 additions & 0 deletions api/v1beta1/helmchart_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
25 changes: 23 additions & 2 deletions controllers/helmchart_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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())
Expand Down
17 changes: 16 additions & 1 deletion controllers/helmchart_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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())
Expand Down
30 changes: 30 additions & 0 deletions docs/api/source.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 (&lsquo;ChartVersion&rsquo;,
&lsquo;Revision&rsquo;). 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
Expand Down Expand Up @@ -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 (&lsquo;ChartVersion&rsquo;,
&lsquo;Revision&rsquo;). 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
Expand Down
38 changes: 38 additions & 0 deletions docs/spec/v1beta1/helmcharts.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit d382eca

Please sign in to comment.