fix: support array of maps in set/setTemplate values (#2615)
Changed SetValue.Values type from []string to []any to allow passing
maps (not just strings) in the values field of set/setTemplate.
Previously, YAML like:
setTemplate:
- name: source.helm.parameters
values:
- name: demo
- version: v2
would fail with 'cannot unmarshal !!map into string'. Map values are
now serialized to JSON when generating --set flags.
Fixes #1021
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
parent
fbf4f31c02
commit
7391453cbe
|
|
@ -193,13 +193,18 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R
|
|||
}
|
||||
result.SetValuesTemplate[i].File = s.String()
|
||||
}
|
||||
for j, ts := range val.Values {
|
||||
for j, tv := range val.Values {
|
||||
// values
|
||||
s, err := renderer.RenderTemplateContentToBuffer([]byte(ts))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].values[%d] = \"%s\": %v", r.Name, i, j, ts, err)
|
||||
switch ts := tv.(type) {
|
||||
case string:
|
||||
s, err := renderer.RenderTemplateContentToBuffer([]byte(ts))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].values[%d] = \"%s\": %v", r.Name, i, j, ts, err)
|
||||
}
|
||||
result.SetValuesTemplate[i].Values[j] = s.String()
|
||||
default:
|
||||
result.SetValuesTemplate[i].Values[j] = ts
|
||||
}
|
||||
result.SetValuesTemplate[i].Values[j] = s.String()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -576,10 +576,10 @@ type Release struct {
|
|||
|
||||
// SetValue are the key values to set on a helm release
|
||||
type SetValue struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
File string `yaml:"file,omitempty"`
|
||||
Values []string `yaml:"values,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
File string `yaml:"file,omitempty"`
|
||||
Values []any `yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
// AffectedReleases hold the list of released that where updated, deleted, or in error
|
||||
|
|
@ -4570,7 +4570,7 @@ func (st *HelmState) setFlags(setValues []SetValue) ([]string, error) {
|
|||
} else if set.File != "" {
|
||||
flags = append(flags, "--set-file", fmt.Sprintf("%s=%s", escape(set.Name), st.storage().normalizeSetFilePath(set.File, runtime.GOOS)))
|
||||
} else if len(set.Values) > 0 {
|
||||
renderedValues, err := renderValsSecrets(st.valsRuntime, set.Values...)
|
||||
renderedValues, err := renderValsSecretsAny(st.valsRuntime, set.Values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -4598,7 +4598,7 @@ func (st *HelmState) setStringFlags(setValues []SetValue) ([]string, error) {
|
|||
}
|
||||
flags = append(flags, "--set-string", fmt.Sprintf("%s=%s", escape(set.Name), escape(renderedValue[0])))
|
||||
} else if len(set.Values) > 0 {
|
||||
renderedValues, err := renderValsSecrets(st.valsRuntime, set.Values...)
|
||||
renderedValues, err := renderValsSecretsAny(st.valsRuntime, set.Values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -4635,6 +4635,43 @@ func renderValsSecrets(e vals.Evaluator, input ...string) ([]string, error) {
|
|||
return output, nil
|
||||
}
|
||||
|
||||
// renderValsSecretsAny renders 'ref+.*' secrets in a slice of any-typed values.
|
||||
// Map values are serialized to JSON; string values are rendered via vals.
|
||||
func renderValsSecretsAny(e vals.Evaluator, input []any) ([]string, error) {
|
||||
output := make([]string, len(input))
|
||||
if len(input) == 0 {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
strInputs := make([]string, 0, len(input))
|
||||
strIndexMap := make([]int, 0, len(input))
|
||||
for i, v := range input {
|
||||
switch tv := v.(type) {
|
||||
case string:
|
||||
strInputs = append(strInputs, tv)
|
||||
strIndexMap = append(strIndexMap, i)
|
||||
default:
|
||||
jsonBytes, err := json.Marshal(tv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal set value at index %d: %w", i, err)
|
||||
}
|
||||
output[i] = string(jsonBytes)
|
||||
}
|
||||
}
|
||||
|
||||
if len(strInputs) > 0 {
|
||||
rendered, err := renderValsSecrets(e, strInputs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for idx, renderedIdx := range strIndexMap {
|
||||
output[renderedIdx] = rendered[idx]
|
||||
}
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func hideChartCredentials(chartCredentials string) (string, error) {
|
||||
u, err := url.Parse(chartCredentials)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ func TestHelmState_executeTemplates(t *testing.T) {
|
|||
SetValuesTemplate: []SetValue{
|
||||
{Name: "val1", Value: "{{ .Release.Name }}-val1"},
|
||||
{Name: "val2", File: "{{ .Release.Name }}.yml"},
|
||||
{Name: "val3", Values: []string{"{{ .Release.Name }}-val2", "{{ .Release.Name }}-val3"}},
|
||||
{Name: "val3", Values: []any{"{{ .Release.Name }}-val2", "{{ .Release.Name }}-val3"}},
|
||||
{Name: "val4", Value: "{{ .Release.Chart }}-{{ .Release.ChartVersion}}"},
|
||||
},
|
||||
},
|
||||
|
|
@ -108,7 +108,7 @@ func TestHelmState_executeTemplates(t *testing.T) {
|
|||
SetValues: []SetValue{
|
||||
{Name: "val1", Value: "test-app-val1"},
|
||||
{Name: "val2", File: "test-app.yml"},
|
||||
{Name: "val3", Values: []string{"test-app-val2", "test-app-val3"}},
|
||||
{Name: "val3", Values: []any{"test-app-val2", "test-app-val3"}},
|
||||
{Name: "val4", Value: "test-charts/chart-1.5"},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2096,7 +2096,7 @@ func TestHelmState_SyncReleases(t *testing.T) {
|
|||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "foo.bar[0]",
|
||||
Values: []string{
|
||||
Values: []any{
|
||||
"A",
|
||||
"B",
|
||||
},
|
||||
|
|
@ -2107,6 +2107,26 @@ func TestHelmState_SyncReleases(t *testing.T) {
|
|||
helm: &exectest.Helm{},
|
||||
wantReleases: []exectest.Release{{Name: "releaseName", Flags: []string{"--set", "foo.bar[0]={A,B}", "--reset-values"}}},
|
||||
},
|
||||
{
|
||||
name: "set array of map values",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "source.helm.parameters",
|
||||
Values: []any{
|
||||
map[string]any{"name": "demo"},
|
||||
map[string]any{"version": "v2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helm: &exectest.Helm{},
|
||||
wantReleases: []exectest.Release{{Name: "releaseName", Flags: []string{"--set", "source.helm.parameters={\\{\"name\":\"demo\"\\},\\{\"version\":\"v2\"\\}}", "--reset-values"}}},
|
||||
},
|
||||
{
|
||||
name: "post renderer helm 3",
|
||||
releases: []ReleaseSpec{
|
||||
|
|
@ -2709,7 +2729,7 @@ func TestHelmState_DiffReleases(t *testing.T) {
|
|||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "foo.bar[0]",
|
||||
Values: []string{
|
||||
Values: []any{
|
||||
"A",
|
||||
"B",
|
||||
},
|
||||
|
|
@ -5698,7 +5718,7 @@ func TestHelmState_setStringFlags(t *testing.T) {
|
|||
setStringValues: []SetValue{
|
||||
{
|
||||
Name: "key",
|
||||
Values: []string{"value1", "value2"},
|
||||
Values: []any{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
want: []string{"--set-string", "key={value1,value2}"},
|
||||
|
|
|
|||
Loading…
Reference in New Issue