Skip to content

Commit

Permalink
Merge pull request #305 from arbourd/values-files
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddeco committed Apr 19, 2021
2 parents 3508bc3 + 4a834e1 commit f56c96f
Show file tree
Hide file tree
Showing 9 changed files with 469 additions and 33 deletions.
25 changes: 23 additions & 2 deletions api/v1beta1/helmchart_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,19 @@ type HelmChartSpec struct {
// +required
Interval metav1.Duration `json:"interval"`

// Alternative values file to use as the default chart values, expected to be a
// relative path in the SourceRef. Ignored when omitted.
// 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.
// +optional
// +deprecated
ValuesFile string `json:"valuesFile,omitempty"`

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

// GetValuesFiles returns a merged list of 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
// +genclient:Namespaced
// +kubebuilder:object:root=true
Expand Down
7 changes: 6 additions & 1 deletion api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,19 @@ spec:
type: boolean
valuesFile:
description: Alternative values file to use as the default chart values,
expected to be a relative path in the SourceRef. Ignored when omitted.
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.
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.
items:
type: string
type: array
version:
default: '*'
description: The chart version semver expression, ignored for charts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ spec:
kind: GitRepository
name: podinfo
chart: charts/podinfo
valuesFile: charts/podinfo/values-prod.yaml
valuesFile: charts/podinfo/values.yaml
valuesFiles:
- charts/podinfo/values-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ spec:
kind: HelmRepository
name: podinfo
chart: podinfo
valuesFile: values-prod.yaml
valuesFile: values.yaml
valuesFiles:
- values-prod.yaml
90 changes: 69 additions & 21 deletions controllers/helmchart_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"sigs.k8s.io/yaml"

"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/events"
"github.com/fluxcd/pkg/runtime/metrics"
"github.com/fluxcd/pkg/runtime/predicates"
"github.com/fluxcd/pkg/runtime/transform"
"github.com/fluxcd/pkg/untar"

sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
Expand Down Expand Up @@ -380,30 +382,57 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
readyMessage = fmt.Sprintf("Fetched revision: %s", newArtifact.Revision)
)
switch {
case chart.Spec.ValuesFile != "" && chart.Spec.ValuesFile != chartutil.ValuesfileName:
case len(chart.GetValuesFiles()) > 0:
var (
tmpDir string
pkgPath string
)
valuesMap := make(map[string]interface{})

// Load the chart
helmChart, err := loader.LoadArchive(res)
if err != nil {
err = fmt.Errorf("load chart error: %w", err)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

// Find override file and retrieve contents
var valuesData []byte
cfn := filepath.Clean(chart.Spec.ValuesFile)
for _, f := range helmChart.Files {
if f.Name == cfn {
valuesData = f.Data
break
for _, v := range chart.GetValuesFiles() {
if v == "values.yaml" {
valuesMap = transform.MergeMaps(valuesMap, helmChart.Values)
continue
}

var valuesData []byte
cfn := filepath.Clean(v)
for _, f := range helmChart.Files {
if f.Name == cfn {
valuesData = f.Data
break
}
}
if valuesData == nil {
err = fmt.Errorf("invalid values file path: %s", v)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

yamlMap := make(map[string]interface{})
err = yaml.Unmarshal(valuesData, &yamlMap)
if err != nil {
err = fmt.Errorf("unmarshaling values from %s failed: %w", v, err)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

valuesMap = transform.MergeMaps(valuesMap, yamlMap)
}

yamlBytes, err := yaml.Marshal(valuesMap)
if err != nil {
err = fmt.Errorf("marshaling values failed: %w", err)
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
}

// Overwrite values file
if changed, err := helm.OverwriteChartDefaultValues(helmChart, valuesData); err != nil {
if changed, err := helm.OverwriteChartDefaultValues(helmChart, yamlBytes); err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
} else if !changed {
// No changes, skip to write original package to storage
Expand Down Expand Up @@ -508,22 +537,41 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
// or write the chart directly to storage.
pkgPath := chartPath
isValuesFileOverriden := false
if chart.Spec.ValuesFile != "" {
srcPath, err := securejoin.SecureJoin(tmpDir, chart.Spec.ValuesFile)
if err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}
if f, err := os.Stat(srcPath); os.IsNotExist(err) || !f.Mode().IsRegular() {
err = fmt.Errorf("invalid values file path: %s", chart.Spec.ValuesFile)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
if len(chart.GetValuesFiles()) > 0 {
valuesMap := make(map[string]interface{})
for _, v := range chart.GetValuesFiles() {
srcPath, err := securejoin.SecureJoin(tmpDir, v)
if err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}
if f, err := os.Stat(srcPath); os.IsNotExist(err) || !f.Mode().IsRegular() {
err = fmt.Errorf("invalid values file path: %s", v)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

valuesData, err := ioutil.ReadFile(srcPath)
if err != nil {
err = fmt.Errorf("failed to read from values file '%s': %w", v, err)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

yamlMap := make(map[string]interface{})
err = yaml.Unmarshal(valuesData, &yamlMap)
if err != nil {
err = fmt.Errorf("unmarshaling values from %s failed: %w", v, err)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}

valuesMap = transform.MergeMaps(valuesMap, yamlMap)
}

valuesData, err := ioutil.ReadFile(srcPath)
yamlBytes, err := yaml.Marshal(valuesMap)
if err != nil {
err = fmt.Errorf("failed to read from values file '%s': %w", chart.Spec.ValuesFile, err)
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
err = fmt.Errorf("marshaling values failed: %w", err)
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
}
isValuesFileOverriden, err = helm.OverwriteChartDefaultValues(helmChart, valuesData)

isValuesFileOverriden, err = helm.OverwriteChartDefaultValues(helmChart, yamlBytes)
if err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPackageFailedReason, err.Error()), err
}
Expand Down
Loading

0 comments on commit f56c96f

Please sign in to comment.