feat: Allow .Release.Name to be used in gotmpl values templates (#1424)

This adds the ability to utilize `.Release` inside of gotmpl files as discussed [here](https://github.com/roboll/helmfile/issues/760).

Resolves: https://github.com/roboll/helmfile/issues/760

Co-authored-by: Yusuke Kuoka <ykuoka@gmail.com>
This commit is contained in:
Joshua Hansen 2020-08-28 21:07:46 -07:00 committed by GitHub
parent c575587e1f
commit 7b11ce851a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 30 deletions

View File

@ -100,9 +100,11 @@ bar: {{ readFile "bar.txt" }}
}
valuesFile := "/example/path/to/values.yaml.gotmpl"
valuesContent := []byte(`env: {{ .Environment.Name }}`)
valuesContent := []byte(`env: {{ .Environment.Name }}
releaseName: {{ .Release.Name }}`)
expectedValues := `env: production`
expectedValues := `env: production
releaseName: myrelease`
testFs := testhelper.NewTestFs(map[string]string{
fooYamlFile: string(fooYamlContent),
@ -124,7 +126,11 @@ bar: {{ readFile "bar.txt" }}
t.Errorf("unexpected environment values: expected=%v, actual=%v", expected, actual)
}
actualValuesData, err := state.RenderValuesFileToBytes(valuesFile)
var release = ReleaseSpec{
Name: "myrelease",
}
actualValuesData, err := state.RenderReleaseValuesFileToBytes(&release, valuesFile)
if err != nil {
t.Errorf("unexpected error: %v", err)
}

View File

@ -114,7 +114,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
jsonPatches := release.JSONPatches
if len(jsonPatches) > 0 {
generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler)
generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, jsonPatches, release.MissingFileHandler)
if err != nil {
return nil, clean, err
}
@ -130,7 +130,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
strategicMergePatches := release.StrategicMergePatches
if len(strategicMergePatches) > 0 {
generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler)
generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, strategicMergePatches, release.MissingFileHandler)
if err != nil {
return nil, clean, err
}

View File

@ -2084,8 +2084,14 @@ func (st *HelmState) flagsForLint(helm helmexec.Interface, release *ReleaseSpec,
return flags, files, nil
}
func (st *HelmState) RenderValuesFileToBytes(path string) ([]byte, error) {
r := tmpl.NewFileRenderer(st.readFile, filepath.Dir(path), st.valuesFileTemplateData())
func (st *HelmState) RenderReleaseValuesFileToBytes(release *ReleaseSpec, path string) ([]byte, error) {
vals, err := st.Values()
if err != nil {
return nil, err
}
templateData := st.createReleaseTemplateData(release, vals)
r := tmpl.NewFileRenderer(st.readFile, filepath.Dir(path), templateData)
rawBytes, err := r.RenderToBytes(path)
if err != nil {
return nil, err
@ -2164,7 +2170,7 @@ func (st *HelmState) removeFiles(files []string) {
}
}
func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingFileHandler *string) ([]string, error) {
func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, values []interface{}, missingFileHandler *string) ([]string, error) {
generatedFiles := []string{}
for _, value := range values {
@ -2183,7 +2189,7 @@ func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingF
}
path := paths[0]
yamlBytes, err := st.RenderValuesFileToBytes(path)
yamlBytes, err := st.RenderReleaseValuesFileToBytes(release, path)
if err != nil {
return generatedFiles, fmt.Errorf("failed to render values files \"%s\": %v", typedValue, err)
}
@ -2240,7 +2246,7 @@ func (st *HelmState) generateVanillaValuesFiles(release *ReleaseSpec) ([]string,
return nil, fmt.Errorf("Failed to render values in %s for release %s: type %T isn't supported", st.FilePath, release.Name, valuesMapSecretsRendered["values"])
}
generatedFiles, err := st.generateTemporaryValuesFiles(valuesSecretsRendered, release.MissingFileHandler)
generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, valuesSecretsRendered, release.MissingFileHandler)
if err != nil {
return nil, err
}

View File

@ -12,19 +12,16 @@ func (st *HelmState) Values() (map[string]interface{}, error) {
return st.Env.GetMergedValues()
}
func (st *HelmState) mustLoadVals() map[string]interface{} {
vals, err := st.Values()
if err != nil {
panic(err)
}
return vals
}
func (st *HelmState) valuesFileTemplateData() EnvironmentTemplateData {
return EnvironmentTemplateData{
func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[string]interface{}) releaseTemplateData {
return releaseTemplateData{
Environment: st.Env,
Namespace: st.OverrideNamespace,
Values: st.mustLoadVals(),
Values: vals,
Release: releaseTemplateDataRelease{
Name: release.Name,
Chart: release.Chart,
Namespace: release.Namespace,
Labels: release.Labels,
},
}
}
@ -88,11 +85,7 @@ func (st *HelmState) ExecuteTemplates() (*HelmState, error) {
for i, rt := range st.Releases {
successFlag := false
for it, prev := 0, &rt; it < 6; it++ {
tmplData := releaseTemplateData{
Environment: st.Env,
Release: *prev,
Values: vals,
}
tmplData := st.createReleaseTemplateData(prev, vals)
renderer := tmpl.NewFileRenderer(st.readFile, st.basePath, tmplData)
r, err := rt.ExecuteTemplateExpressions(renderer)
if err != nil {

View File

@ -19,12 +19,28 @@ type EnvironmentTemplateData struct {
Values map[string]interface{}
}
// releaseTemplateData provides variables accessible while executing golang text/template expressions in releases of a helmfile YAML file
// releaseTemplateData provides variables accessible while executing golang text/template expressions in release templates
// and release values templates within a Helmfile YAML file.
type releaseTemplateData struct {
// Environment is accessible as `.Environment` from any template expression executed by the renderer
Environment environment.Environment
// Release is accessible as `.Release` from any template expression executed by the renderer
Release ReleaseSpec
// Release is accessible as `.Release` from any template expression executed by the renderer.
// It contains a subset of ReleaseSpec that is known to be useful to dynamically render values.
Release releaseTemplateDataRelease
// Values is accessible as `.Values` and it contains default state values overrode by environment values and override values.
Values map[string]interface{}
}
type releaseTemplateDataRelease struct {
// Name is basically ReleaseSpec.Name exposed to the template
Name string
// Namespace is HelmState.OverrideNamespace, or if it's empty, ReleaseSpec.Namespace.
Namespace string
// Labels is ReleaseSpec.Labels
Labels map[string]string
// Chart is ReleaseSpec.Chart
Chart string
}