Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ValuesFiles to HelmChart spec #305

Merged
merged 1 commit into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Comment on lines +400 to +403
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default values are not available from the filesystem, only via helmChart.Values

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note this @relu


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
}
arbourd marked this conversation as resolved.
Show resolved Hide resolved

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