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:
parent
c575587e1f
commit
7b11ce851a
|
|
@ -100,9 +100,11 @@ bar: {{ readFile "bar.txt" }}
|
||||||
}
|
}
|
||||||
|
|
||||||
valuesFile := "/example/path/to/values.yaml.gotmpl"
|
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{
|
testFs := testhelper.NewTestFs(map[string]string{
|
||||||
fooYamlFile: string(fooYamlContent),
|
fooYamlFile: string(fooYamlContent),
|
||||||
|
|
@ -124,7 +126,11 @@ bar: {{ readFile "bar.txt" }}
|
||||||
t.Errorf("unexpected environment values: expected=%v, actual=%v", expected, actual)
|
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 {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
|
||||||
|
|
||||||
jsonPatches := release.JSONPatches
|
jsonPatches := release.JSONPatches
|
||||||
if len(jsonPatches) > 0 {
|
if len(jsonPatches) > 0 {
|
||||||
generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler)
|
generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, jsonPatches, release.MissingFileHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clean, err
|
return nil, clean, err
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
|
||||||
|
|
||||||
strategicMergePatches := release.StrategicMergePatches
|
strategicMergePatches := release.StrategicMergePatches
|
||||||
if len(strategicMergePatches) > 0 {
|
if len(strategicMergePatches) > 0 {
|
||||||
generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler)
|
generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, strategicMergePatches, release.MissingFileHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clean, err
|
return nil, clean, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2084,8 +2084,14 @@ func (st *HelmState) flagsForLint(helm helmexec.Interface, release *ReleaseSpec,
|
||||||
return flags, files, nil
|
return flags, files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) RenderValuesFileToBytes(path string) ([]byte, error) {
|
func (st *HelmState) RenderReleaseValuesFileToBytes(release *ReleaseSpec, path string) ([]byte, error) {
|
||||||
r := tmpl.NewFileRenderer(st.readFile, filepath.Dir(path), st.valuesFileTemplateData())
|
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)
|
rawBytes, err := r.RenderToBytes(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{}
|
generatedFiles := []string{}
|
||||||
|
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
|
|
@ -2183,7 +2189,7 @@ func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingF
|
||||||
}
|
}
|
||||||
path := paths[0]
|
path := paths[0]
|
||||||
|
|
||||||
yamlBytes, err := st.RenderValuesFileToBytes(path)
|
yamlBytes, err := st.RenderReleaseValuesFileToBytes(release, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return generatedFiles, fmt.Errorf("failed to render values files \"%s\": %v", typedValue, err)
|
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"])
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,16 @@ func (st *HelmState) Values() (map[string]interface{}, error) {
|
||||||
return st.Env.GetMergedValues()
|
return st.Env.GetMergedValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) mustLoadVals() map[string]interface{} {
|
func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[string]interface{}) releaseTemplateData {
|
||||||
vals, err := st.Values()
|
return releaseTemplateData{
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return vals
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st *HelmState) valuesFileTemplateData() EnvironmentTemplateData {
|
|
||||||
return EnvironmentTemplateData{
|
|
||||||
Environment: st.Env,
|
Environment: st.Env,
|
||||||
Namespace: st.OverrideNamespace,
|
Values: vals,
|
||||||
Values: st.mustLoadVals(),
|
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 {
|
for i, rt := range st.Releases {
|
||||||
successFlag := false
|
successFlag := false
|
||||||
for it, prev := 0, &rt; it < 6; it++ {
|
for it, prev := 0, &rt; it < 6; it++ {
|
||||||
tmplData := releaseTemplateData{
|
tmplData := st.createReleaseTemplateData(prev, vals)
|
||||||
Environment: st.Env,
|
|
||||||
Release: *prev,
|
|
||||||
Values: vals,
|
|
||||||
}
|
|
||||||
renderer := tmpl.NewFileRenderer(st.readFile, st.basePath, tmplData)
|
renderer := tmpl.NewFileRenderer(st.readFile, st.basePath, tmplData)
|
||||||
r, err := rt.ExecuteTemplateExpressions(renderer)
|
r, err := rt.ExecuteTemplateExpressions(renderer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,28 @@ type EnvironmentTemplateData struct {
|
||||||
Values map[string]interface{}
|
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 {
|
type releaseTemplateData struct {
|
||||||
// Environment is accessible as `.Environment` from any template expression executed by the renderer
|
// Environment is accessible as `.Environment` from any template expression executed by the renderer
|
||||||
Environment environment.Environment
|
Environment environment.Environment
|
||||||
// Release is accessible as `.Release` from any template expression executed by the renderer
|
// Release is accessible as `.Release` from any template expression executed by the renderer.
|
||||||
Release ReleaseSpec
|
// 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 is accessible as `.Values` and it contains default state values overrode by environment values and override values.
|
||||||
Values map[string]interface{}
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue