Skip to content

Commit

Permalink
feat: add environments values inheritance
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Chenal <vincent.chenal@protonmail.com>
  • Loading branch information
Vince-Chenal committed May 16, 2023
1 parent 641e1f8 commit 250e323
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 19 deletions.
2 changes: 1 addition & 1 deletion pkg/app/desired_state_file_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (ld *desiredStateLoader) Load(f string, opts LoadOpts) (*state.HelmState, e
return nil, fmt.Errorf("bug: opts.CalleePath was nil: f=%s, opts=%v", f, opts)
}
storage := state.NewStorage(opts.CalleePath, ld.logger, ld.fs)
envld := state.NewEnvironmentValuesLoader(storage, ld.fs, ld.logger, ld.remote)
envld := state.NewEnvironmentValuesLoader(storage, ld.fs, ld.logger, ld.remote, false)
handler := state.MissingFileHandlerError
vals, err := envld.LoadEnvironmentValues(&handler, args, environment.New(ld.env), ld.env)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/state/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ func (st *HelmState) loadValuesEntries(missingFileHandler *string, entries []int
var envVals map[string]interface{}

valuesEntries := append([]interface{}{}, entries...)
ld := NewEnvironmentValuesLoader(st.storage(), st.fs, st.logger, remote)
ld := NewEnvironmentValuesLoader(st.storage(), st.fs, st.logger, remote, st.Environments[envName].LayeredValues)
var err error
envVals, err = ld.LoadEnvironmentValues(missingFileHandler, valuesEntries, ctxEnv, envName)
if err != nil {
Expand Down
7 changes: 4 additions & 3 deletions pkg/state/environment.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package state

type EnvironmentSpec struct {
Values []interface{} `yaml:"values,omitempty"`
Secrets []string `yaml:"secrets,omitempty"`
KubeContext string `yaml:"kubeContext,omitempty"`
Values []interface{} `yaml:"values,omitempty"`
Secrets []string `yaml:"secrets,omitempty"`
KubeContext string `yaml:"kubeContext,omitempty"`
LayeredValues bool `yaml:"layeredValues,omitempty"`

// MissingFileHandler instructs helmfile to fail when unable to find a environment values file listed
// under `environments.NAME.values`.
Expand Down
19 changes: 13 additions & 6 deletions pkg/state/envvals_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ type EnvironmentValuesLoader struct {
logger *zap.SugaredLogger

remote *remote.Remote

layeredValues bool
}

func NewEnvironmentValuesLoader(storage *Storage, fs *filesystem.FileSystem, logger *zap.SugaredLogger, remote *remote.Remote) *EnvironmentValuesLoader {
func NewEnvironmentValuesLoader(storage *Storage, fs *filesystem.FileSystem, logger *zap.SugaredLogger, remote *remote.Remote, layeredValues bool) *EnvironmentValuesLoader {
return &EnvironmentValuesLoader{
storage: storage,
fs: fs,
logger: logger,
remote: remote,
storage: storage,
fs: fs,
logger: logger,
remote: remote,
layeredValues: layeredValues,
}
}

Expand Down Expand Up @@ -58,7 +61,11 @@ func (ld *EnvironmentValuesLoader) LoadEnvironmentValues(missingFileHandler *str
env = *ctxEnv
}

tmplData := NewEnvironmentTemplateData(env, "", map[string]interface{}{})
baseData := map[string]interface{}{}
if ld.layeredValues {
baseData = result
}
tmplData := NewEnvironmentTemplateData(env, "", baseData)
r := tmpl.NewFileRenderer(ld.fs, filepath.Dir(f), tmplData)
bytes, err := r.RenderToBytes(f)
if err != nil {
Expand Down
34 changes: 26 additions & 8 deletions pkg/state/envvals_loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/helmfile/helmfile/pkg/remote"
)

func newLoader() *EnvironmentValuesLoader {
func newLoader(layeredValues bool) *EnvironmentValuesLoader {
log := helmexec.NewLogger(io.Discard, "debug")

storage := &Storage{
Expand All @@ -22,12 +22,12 @@ func newLoader() *EnvironmentValuesLoader {
logger: log,
}

return NewEnvironmentValuesLoader(storage, storage.fs, log, remote.NewRemote(log, "/tmp", storage.fs))
return NewEnvironmentValuesLoader(storage, storage.fs, log, remote.NewRemote(log, "/tmp", storage.fs), layeredValues)
}

// See https://github.com/roboll/helmfile/pull/1169
func TestEnvValsLoad_SingleValuesFile(t *testing.T) {
l := newLoader()
l := newLoader(false)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"testdata/values.5.yaml"}, nil, "")
if err != nil {
Expand All @@ -44,7 +44,7 @@ func TestEnvValsLoad_SingleValuesFile(t *testing.T) {
}

func TestEnvValsLoad_EnvironmentNameFile(t *testing.T) {
l := newLoader()
l := newLoader(false)

expected := map[string]interface{}{
"envName": "test",
Expand Down Expand Up @@ -101,7 +101,7 @@ func TestEnvValsLoad_EnvironmentNameFile(t *testing.T) {

// Fetch Environment values from remote
func TestEnvValsLoad_SingleValuesFileRemote(t *testing.T) {
l := newLoader()
l := newLoader(false)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"git::https://github.com/helm/helm.git@cmd/helm/testdata/output/values.yaml?ref=v3.8.0"}, nil, "")
if err != nil {
Expand All @@ -119,7 +119,7 @@ func TestEnvValsLoad_SingleValuesFileRemote(t *testing.T) {

// See https://github.com/roboll/helmfile/issues/1150
func TestEnvValsLoad_OverwriteNilValue_Issue1150(t *testing.T) {
l := newLoader()
l := newLoader(false)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"testdata/values.1.yaml", "testdata/values.2.yaml"}, nil, "")
if err != nil {
Expand All @@ -141,7 +141,7 @@ func TestEnvValsLoad_OverwriteNilValue_Issue1150(t *testing.T) {

// See https://github.com/roboll/helmfile/issues/1154
func TestEnvValsLoad_OverwriteWithNilValue_Issue1154(t *testing.T) {
l := newLoader()
l := newLoader(false)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"testdata/values.3.yaml", "testdata/values.4.yaml"}, nil, "")
if err != nil {
Expand All @@ -164,7 +164,7 @@ func TestEnvValsLoad_OverwriteWithNilValue_Issue1154(t *testing.T) {

// See https://github.com/roboll/helmfile/issues/1168
func TestEnvValsLoad_OverwriteEmptyValue_Issue1168(t *testing.T) {
l := newLoader()
l := newLoader(false)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"testdata/issues/1168/addons.yaml", "testdata/issues/1168/addons2.yaml"}, nil, "")
if err != nil {
Expand All @@ -187,3 +187,21 @@ func TestEnvValsLoad_OverwriteEmptyValue_Issue1168(t *testing.T) {
t.Errorf(diff)
}
}

func TestEnvValsLoad_LayeredValues(t *testing.T) {
l := newLoader(true)

actual, err := l.LoadEnvironmentValues(nil, []interface{}{"testdata/layered1.yaml", "testdata/layered2.yaml.gotmpl"}, nil, "")
if err != nil {
t.Fatal(err)
}

expected := map[string]interface{}{
"somevalue": string("foo"),
"someothervalue": string("new foo"),
}

if diff := cmp.Diff(expected, actual); diff != "" {
t.Errorf(diff)
}
}
1 change: 1 addition & 0 deletions pkg/state/testdata/layered1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
somevalue: foo
1 change: 1 addition & 0 deletions pkg/state/testdata/layered2.yaml.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
someothervalue: "new {{ .Values.somevalue }}"

0 comments on commit 250e323

Please sign in to comment.