Make advanced templating backward-compatible (#833)
This is a follow-up for #823 Ref https://github.com/roboll/helmfile/pull/823#discussion_r319712283
This commit is contained in:
		
							parent
							
								
									01ae59fedd
								
							
						
					
					
						commit
						4bc99337b2
					
				|  | @ -102,7 +102,7 @@ Release Templating supports the following parts of release definition: | ||||||
| - `set` block values: | - `set` block values: | ||||||
|   ```yaml |   ```yaml | ||||||
|   # ... |   # ... | ||||||
|     set: |     setTemplate: | ||||||
|     - name: '{{`{{ .Release.Name }}`}}' |     - name: '{{`{{ .Release.Name }}`}}' | ||||||
|       values: '{{`{{ .Release.Namespace }}`}}' |       values: '{{`{{ .Release.Namespace }}`}}' | ||||||
|   # ... |   # ... | ||||||
|  | @ -110,7 +110,7 @@ Release Templating supports the following parts of release definition: | ||||||
| - `values` and `secrets` file paths: | - `values` and `secrets` file paths: | ||||||
|   ```yaml |   ```yaml | ||||||
|   # ... |   # ... | ||||||
|     values: |     valuesTemplate: | ||||||
|     - config/{{`{{ .Release.Name }}`}}/values.yaml |     - config/{{`{{ .Release.Name }}`}}/values.yaml | ||||||
|     secrets: |     secrets: | ||||||
|     - config/{{`{{ .Release.Name }}`}}/secrets.yaml |     - config/{{`{{ .Release.Name }}`}}/secrets.yaml | ||||||
|  | @ -119,7 +119,7 @@ Release Templating supports the following parts of release definition: | ||||||
| - inline `values` map: | - inline `values` map: | ||||||
|   ```yaml |   ```yaml | ||||||
|   # ... |   # ... | ||||||
|     values: |     valuesTemplate: | ||||||
|     - image: |     - image: | ||||||
|         tag: `{{ .Release.Labels.tag }}` |         tag: `{{ .Release.Labels.tag }}` | ||||||
|   # ... |   # ... | ||||||
|  |  | ||||||
|  | @ -93,6 +93,33 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R | ||||||
| 		result.Labels[key] = s.String() | 		result.Labels[key] = s.String() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if result.ValuesTemplate != nil && len(result.ValuesTemplate) > 0 { | ||||||
|  | 		for i, t := range result.ValuesTemplate { | ||||||
|  | 			switch ts := t.(type) { | ||||||
|  | 			case map[interface{}]interface{}: | ||||||
|  | 				serialized, err := yaml.Marshal(ts) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				s, err := renderer.RenderTemplateContentToBuffer([]byte(serialized)) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, serialized, err) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				var deserialized map[interface{}]interface{} | ||||||
|  | 
 | ||||||
|  | 				if err := yaml.Unmarshal(s.Bytes(), &deserialized); err != nil { | ||||||
|  | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				result.ValuesTemplate[i] = deserialized | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		result.Values = result.ValuesTemplate | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	for i, t := range result.Values { | 	for i, t := range result.Values { | ||||||
| 		switch ts := t.(type) { | 		switch ts := t.(type) { | ||||||
| 		case string: | 		case string: | ||||||
|  | @ -101,24 +128,6 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%s\": %v", r.Name, i, ts, err) | 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%s\": %v", r.Name, i, ts, err) | ||||||
| 			} | 			} | ||||||
| 			result.Values[i] = s.String() | 			result.Values[i] = s.String() | ||||||
| 		case map[interface{}]interface{}: |  | ||||||
| 			serialized, err := yaml.Marshal(ts) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			s, err := renderer.RenderTemplateContentToBuffer([]byte(serialized)) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, serialized, err) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			var deserialized map[interface{}]interface{} |  | ||||||
| 
 |  | ||||||
| 			if err := yaml.Unmarshal(s.Bytes(), &deserialized); err != nil { |  | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			result.Values[i] = deserialized |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -130,42 +139,46 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R | ||||||
| 		result.Secrets[i] = s.String() | 		result.Secrets[i] = s.String() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for i, val := range result.SetValues { | 	if result.SetValuesTemplate != nil && len(result.SetValuesTemplate) > 0 { | ||||||
| 		{ | 		for i, val := range result.SetValuesTemplate { | ||||||
| 			// name
 | 			{ | ||||||
| 			ts := val.Name | 				// name
 | ||||||
| 			s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | 				ts := val.Name | ||||||
| 			if err != nil { | 				s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].name = \"%s\": %v", r.Name, i, ts, err) | 				if err != nil { | ||||||
|  | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].name = \"%s\": %v", r.Name, i, ts, err) | ||||||
|  | 				} | ||||||
|  | 				result.SetValuesTemplate[i].Name = s.String() | ||||||
| 			} | 			} | ||||||
| 			result.SetValues[i].Name = s.String() | 			{ | ||||||
| 		} | 				// value
 | ||||||
| 		{ | 				ts := val.Value | ||||||
| 			// value
 | 				s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | ||||||
| 			ts := val.Value | 				if err != nil { | ||||||
| 			s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].value = \"%s\": %v", r.Name, i, ts, err) | ||||||
| 			if err != nil { | 				} | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].value = \"%s\": %v", r.Name, i, ts, err) | 				result.SetValuesTemplate[i].Value = s.String() | ||||||
| 			} | 			} | ||||||
| 			result.SetValues[i].Value = s.String() | 			{ | ||||||
| 		} | 				// file
 | ||||||
| 		{ | 				ts := val.File | ||||||
| 			// file
 | 				s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | ||||||
| 			ts := val.File | 				if err != nil { | ||||||
| 			s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].file = \"%s\": %v", r.Name, i, ts, err) | ||||||
| 			if err != nil { | 				} | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].file = \"%s\": %v", r.Name, i, ts, err) | 				result.SetValuesTemplate[i].File = s.String() | ||||||
| 			} | 			} | ||||||
| 			result.SetValues[i].File = s.String() | 			for j, ts := range val.Values { | ||||||
| 		} | 				// values
 | ||||||
| 		for j, ts := range val.Values { | 				s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | ||||||
| 			// values
 | 				if err != nil { | ||||||
| 			s, err := renderer.RenderTemplateContentToBuffer([]byte(ts)) | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".set[%d].values[%d] = \"%s\": %v", r.Name, i, j, ts, err) | ||||||
| 			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() | ||||||
| 			} | 			} | ||||||
| 			result.SetValues[i].Values[j] = s.String() |  | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		result.SetValues = result.SetValuesTemplate | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return result, nil | 	return result, nil | ||||||
|  |  | ||||||
|  | @ -153,6 +153,9 @@ type ReleaseSpec struct { | ||||||
| 	Secrets   []string          `yaml:"secrets,omitempty"` | 	Secrets   []string          `yaml:"secrets,omitempty"` | ||||||
| 	SetValues []SetValue        `yaml:"set,omitempty"` | 	SetValues []SetValue        `yaml:"set,omitempty"` | ||||||
| 
 | 
 | ||||||
|  | 	ValuesTemplate    []interface{} `yaml:"valuesTemplate,omitempty"` | ||||||
|  | 	SetValuesTemplate []SetValue    `yaml:"setTemplate,omitempty"` | ||||||
|  | 
 | ||||||
| 	// The 'env' section is not really necessary any longer, as 'set' would now provide the same functionality
 | 	// The 'env' section is not really necessary any longer, as 'set' would now provide the same functionality
 | ||||||
| 	EnvValues []SetValue `yaml:"env,omitempty"` | 	EnvValues []SetValue `yaml:"env,omitempty"` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,13 +31,13 @@ func TestHelmState_executeTemplates(t *testing.T) { | ||||||
| 		{ | 		{ | ||||||
| 			name: "Has template expressions in chart, values, secrets, version, labels", | 			name: "Has template expressions in chart, values, secrets, version, labels", | ||||||
| 			input: ReleaseSpec{ | 			input: ReleaseSpec{ | ||||||
| 				Chart:     "test-charts/{{ .Release.Name }}", | 				Chart:          "test-charts/{{ .Release.Name }}", | ||||||
| 				Version:   "{{ .Release.Name }}-0.1", | 				Version:        "{{ .Release.Name }}-0.1", | ||||||
| 				Name:      "test-app", | 				Name:           "test-app", | ||||||
| 				Namespace: "test-namespace-{{ .Release.Name }}", | 				Namespace:      "test-namespace-{{ .Release.Name }}", | ||||||
| 				Values:    []interface{}{"config/{{ .Environment.Name }}/{{ .Release.Name }}/values.yaml"}, | 				ValuesTemplate: []interface{}{"config/{{ .Environment.Name }}/{{ .Release.Name }}/values.yaml"}, | ||||||
| 				Secrets:   []string{"config/{{ .Environment.Name }}/{{ .Release.Name }}/secrets.yaml"}, | 				Secrets:        []string{"config/{{ .Environment.Name }}/{{ .Release.Name }}/secrets.yaml"}, | ||||||
| 				Labels:    map[string]string{"id": "{{ .Release.Name }}"}, | 				Labels:         map[string]string{"id": "{{ .Release.Name }}"}, | ||||||
| 			}, | 			}, | ||||||
| 			want: ReleaseSpec{ | 			want: ReleaseSpec{ | ||||||
| 				Chart:     "test-charts/test-app", | 				Chart:     "test-charts/test-app", | ||||||
|  | @ -94,7 +94,7 @@ func TestHelmState_executeTemplates(t *testing.T) { | ||||||
| 				Chart:     "test-charts/chart", | 				Chart:     "test-charts/chart", | ||||||
| 				Name:      "test-app", | 				Name:      "test-app", | ||||||
| 				Namespace: "dev", | 				Namespace: "dev", | ||||||
| 				SetValues: []SetValue{ | 				SetValuesTemplate: []SetValue{ | ||||||
| 					SetValue{Name: "val1", Value: "{{ .Release.Name }}-val1"}, | 					SetValue{Name: "val1", Value: "{{ .Release.Name }}-val1"}, | ||||||
| 					SetValue{Name: "val2", File: "{{ .Release.Name }}.yml"}, | 					SetValue{Name: "val2", File: "{{ .Release.Name }}.yml"}, | ||||||
| 					SetValue{Name: "val3", Values: []string{"{{ .Release.Name }}-val2", "{{ .Release.Name }}-val3"}}, | 					SetValue{Name: "val3", Values: []string{"{{ .Release.Name }}-val2", "{{ .Release.Name }}-val3"}}, | ||||||
|  | @ -114,11 +114,11 @@ func TestHelmState_executeTemplates(t *testing.T) { | ||||||
| 		{ | 		{ | ||||||
| 			name: "Has template in values (map)", | 			name: "Has template in values (map)", | ||||||
| 			input: ReleaseSpec{ | 			input: ReleaseSpec{ | ||||||
| 				Chart:     "test-charts/chart", | 				Chart:          "test-charts/chart", | ||||||
| 				Verify:    nil, | 				Verify:         nil, | ||||||
| 				Name:      "app", | 				Name:           "app", | ||||||
| 				Namespace: "dev", | 				Namespace:      "dev", | ||||||
| 				Values:    []interface{}{map[string]string{"key": "{{ .Release.Name }}-val0"}}, | 				ValuesTemplate: []interface{}{map[string]string{"key": "{{ .Release.Name }}-val0"}}, | ||||||
| 			}, | 			}, | ||||||
| 			want: ReleaseSpec{ | 			want: ReleaseSpec{ | ||||||
| 				Chart:     "test-charts/chart", | 				Chart:     "test-charts/chart", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue