Skip to content

Commit f56c96f

Browse files
authored
Merge pull request #305 from arbourd/values-files
2 parents 3508bc3 + 4a834e1 commit f56c96f

File tree

9 files changed

+469
-33
lines changed

9 files changed

+469
-33
lines changed

api/v1beta1/helmchart_types.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,19 @@ type HelmChartSpec struct {
4545
// +required
4646
Interval metav1.Duration `json:"interval"`
4747

48-
// Alternative values file to use as the default chart values, expected to be a
49-
// relative path in the SourceRef. Ignored when omitted.
48+
// Alternative list of values files to use as the chart values (values.yaml
49+
// is not included by default), expected to be a relative path in the SourceRef.
50+
// Values files are merged in the order of this list with the last file overriding
51+
// the first. Ignored when omitted.
5052
// +optional
53+
ValuesFiles []string `json:"valuesFiles,omitempty"`
54+
55+
// Alternative values file to use as the default chart values, expected to
56+
// be a relative path in the SourceRef. Deprecated in favor of ValuesFiles,
57+
// for backwards compatibility the file defined here is merged before the
58+
// ValuesFiles items. Ignored when omitted.
59+
// +optional
60+
// +deprecated
5161
ValuesFile string `json:"valuesFile,omitempty"`
5262

5363
// This flag tells the controller to suspend the reconciliation of this source.
@@ -168,6 +178,17 @@ func (in *HelmChart) GetInterval() metav1.Duration {
168178
return in.Spec.Interval
169179
}
170180

181+
// GetValuesFiles returns a merged list of ValuesFiles.
182+
func (in *HelmChart) GetValuesFiles() []string {
183+
valuesFiles := in.Spec.ValuesFiles
184+
185+
// Prepend the deprecated ValuesFile to the list
186+
if in.Spec.ValuesFile != "" {
187+
valuesFiles = append([]string{in.Spec.ValuesFile}, valuesFiles...)
188+
}
189+
return valuesFiles
190+
}
191+
171192
// +genclient
172193
// +genclient:Namespaced
173194
// +kubebuilder:object:root=true

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,19 @@ spec:
9494
type: boolean
9595
valuesFile:
9696
description: Alternative values file to use as the default chart values,
97-
expected to be a relative path in the SourceRef. Ignored when omitted.
97+
expected to be a relative path in the SourceRef. Deprecated in favor
98+
of ValuesFiles, for backwards compatibility the file defined here
99+
is merged before the ValuesFiles items. Ignored when omitted.
98100
type: string
101+
valuesFiles:
102+
description: Alternative list of values files to use as the chart
103+
values (values.yaml is not included by default), expected to be
104+
a relative path in the SourceRef. Values files are merged in the
105+
order of this list with the last file overriding the first. Ignored
106+
when omitted.
107+
items:
108+
type: string
109+
type: array
99110
version:
100111
default: '*'
101112
description: The chart version semver expression, ignored for charts

config/testdata/helmchart-valuesfile/helmchart_gitrepository.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ spec:
88
kind: GitRepository
99
name: podinfo
1010
chart: charts/podinfo
11-
valuesFile: charts/podinfo/values-prod.yaml
11+
valuesFile: charts/podinfo/values.yaml
12+
valuesFiles:
13+
- charts/podinfo/values-prod.yaml

config/testdata/helmchart-valuesfile/helmchart_helmrepository.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ spec:
88
kind: HelmRepository
99
name: podinfo
1010
chart: podinfo
11-
valuesFile: values-prod.yaml
11+
valuesFile: values.yaml
12+
valuesFiles:
13+
- values-prod.yaml

controllers/helmchart_controller.go

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ import (
4949
"sigs.k8s.io/controller-runtime/pkg/predicate"
5050
"sigs.k8s.io/controller-runtime/pkg/reconcile"
5151
"sigs.k8s.io/controller-runtime/pkg/source"
52+
"sigs.k8s.io/yaml"
5253

5354
"github.com/fluxcd/pkg/apis/meta"
5455
"github.com/fluxcd/pkg/runtime/events"
5556
"github.com/fluxcd/pkg/runtime/metrics"
5657
"github.com/fluxcd/pkg/runtime/predicates"
58+
"github.com/fluxcd/pkg/runtime/transform"
5759
"github.com/fluxcd/pkg/untar"
5860

5961
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
@@ -380,30 +382,57 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
380382
readyMessage = fmt.Sprintf("Fetched revision: %s", newArtifact.Revision)
381383
)
382384
switch {
383-
case chart.Spec.ValuesFile != "" && chart.Spec.ValuesFile != chartutil.ValuesfileName:
385+
case len(chart.GetValuesFiles()) > 0:
384386
var (
385387
tmpDir string
386388
pkgPath string
387389
)
390+
valuesMap := make(map[string]interface{})
391+
388392
// Load the chart
389393
helmChart, err := loader.LoadArchive(res)
390394
if err != nil {
391395
err = fmt.Errorf("load chart error: %w", err)
392396
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
393397
}
394398

395-
// Find override file and retrieve contents
396-
var valuesData []byte
397-
cfn := filepath.Clean(chart.Spec.ValuesFile)
398-
for _, f := range helmChart.Files {
399-
if f.Name == cfn {
400-
valuesData = f.Data
401-
break
399+
for _, v := range chart.GetValuesFiles() {
400+
if v == "values.yaml" {
401+
valuesMap = transform.MergeMaps(valuesMap, helmChart.Values)
402+
continue
403+
}
404+
405+
var valuesData []byte
406+
cfn := filepath.Clean(v)
407+
for _, f := range helmChart.Files {
408+
if f.Name == cfn {
409+
valuesData = f.Data
410+
break
411+
}
402412
}
413+
if valuesData == nil {
414+
err = fmt.Errorf("invalid values file path: %s", v)
415+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
416+
}
417+
418+
yamlMap := make(map[string]interface{})
419+
err = yaml.Unmarshal(valuesData, &yamlMap)
420+
if err != nil {
421+
err = fmt.Errorf("unmarshaling values from %s failed: %w", v, err)
422+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
423+
}
424+
425+
valuesMap = transform.MergeMaps(valuesMap, yamlMap)
426+
}
427+
428+
yamlBytes, err := yaml.Marshal(valuesMap)
429+
if err != nil {
430+
err = fmt.Errorf("marshaling values failed: %w", err)
431+
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
403432
}
404433

405434
// Overwrite values file
406-
if changed, err := helm.OverwriteChartDefaultValues(helmChart, valuesData); err != nil {
435+
if changed, err := helm.OverwriteChartDefaultValues(helmChart, yamlBytes); err != nil {
407436
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
408437
} else if !changed {
409438
// No changes, skip to write original package to storage
@@ -508,22 +537,41 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
508537
// or write the chart directly to storage.
509538
pkgPath := chartPath
510539
isValuesFileOverriden := false
511-
if chart.Spec.ValuesFile != "" {
512-
srcPath, err := securejoin.SecureJoin(tmpDir, chart.Spec.ValuesFile)
513-
if err != nil {
514-
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
515-
}
516-
if f, err := os.Stat(srcPath); os.IsNotExist(err) || !f.Mode().IsRegular() {
517-
err = fmt.Errorf("invalid values file path: %s", chart.Spec.ValuesFile)
518-
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
540+
if len(chart.GetValuesFiles()) > 0 {
541+
valuesMap := make(map[string]interface{})
542+
for _, v := range chart.GetValuesFiles() {
543+
srcPath, err := securejoin.SecureJoin(tmpDir, v)
544+
if err != nil {
545+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
546+
}
547+
if f, err := os.Stat(srcPath); os.IsNotExist(err) || !f.Mode().IsRegular() {
548+
err = fmt.Errorf("invalid values file path: %s", v)
549+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
550+
}
551+
552+
valuesData, err := ioutil.ReadFile(srcPath)
553+
if err != nil {
554+
err = fmt.Errorf("failed to read from values file '%s': %w", v, err)
555+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
556+
}
557+
558+
yamlMap := make(map[string]interface{})
559+
err = yaml.Unmarshal(valuesData, &yamlMap)
560+
if err != nil {
561+
err = fmt.Errorf("unmarshaling values from %s failed: %w", v, err)
562+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
563+
}
564+
565+
valuesMap = transform.MergeMaps(valuesMap, yamlMap)
519566
}
520567

521-
valuesData, err := ioutil.ReadFile(srcPath)
568+
yamlBytes, err := yaml.Marshal(valuesMap)
522569
if err != nil {
523-
err = fmt.Errorf("failed to read from values file '%s': %w", chart.Spec.ValuesFile, err)
524-
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
570+
err = fmt.Errorf("marshaling values failed: %w", err)
571+
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
525572
}
526-
isValuesFileOverriden, err = helm.OverwriteChartDefaultValues(helmChart, valuesData)
573+
574+
isValuesFileOverriden, err = helm.OverwriteChartDefaultValues(helmChart, yamlBytes)
527575
if err != nil {
528576
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
529577
}

0 commit comments

Comments
 (0)