Allow env var interpolation in `set` and `values` (#20)
* Allow env var interpolation in `set` and `values` * Use go templating instead of regex * Re-add 'env' section for backwards compatibility * Fix typo
This commit is contained in:
		
							parent
							
								
									12b8b7237b
								
							
						
					
					
						commit
						5da5cd1c39
					
				
							
								
								
									
										24
									
								
								README.md
								
								
								
								
							
							
						
						
									
										24
									
								
								README.md
								
								
								
								
							|  | @ -23,23 +23,25 @@ repositories: | ||||||
| 
 | 
 | ||||||
| charts: | charts: | ||||||
|   # Published chart example |   # Published chart example | ||||||
|   - name: vault                          # helm deployment name |   - name: vault                            # helm deployment name | ||||||
|     namespace: vault                     # target namespace |     namespace: vault                       # target namespace | ||||||
|     chart: roboll/vault-secret-manager   # chart reference (repository) |     chart: roboll/vault-secret-manager     # chart reference (repository) | ||||||
|     values: [ vault.yaml ]               # value files (--values) |     values: [ vault.yaml ]                 # value files (--values) | ||||||
|     set:                                 # values (--set) |     set:                                   # values (--set) | ||||||
|       - name: address |       - name: address | ||||||
|         value: https://vault.example.com |         value: https://vault.example.com | ||||||
|     env:                                 # values (--set) but value will be pulled from environment variables. Will throw an error if the environment variable is not set. |  | ||||||
|       - name: db.password |       - name: db.password | ||||||
|         value: DB_PASSWORD               # $DB_PASSOWRD needs to be set in the calling environment ex: export DB_PASSWORD='password1' |         value: {{ env "DB_PASSWORD" }}                   # value taken from environment variable. Will throw an error if the environment variable is not set. $DB_PASSWORD needs to be set in the calling environment ex: export DB_PASSWORD='password1' | ||||||
|  |       - name: proxy.domain | ||||||
|  |         value: "{{ env \"PLATFORM_ID\" }}.my-domain.com" # Interpolate environment variable with a fixed string | ||||||
| 
 | 
 | ||||||
|   # Local chart example |   # Local chart example | ||||||
|   - name: grafana                         # helm deployment name |   - name: grafana                            # helm deployment name | ||||||
|     namespace: another                    # target namespace |     namespace: another                       # target namespace | ||||||
|     chart: ../my-charts/grafana           # chart reference (relative path to manifest) |     chart: ../my-charts/grafana              # chart reference (relative path to manifest) | ||||||
|     values: |     values: | ||||||
|     - ../../my-values/grafana/values.yaml # Values file (relative path to manifest) |     - "../../my-values/grafana/values.yaml"             # Values file (relative path to manifest) | ||||||
|  |     - "./values/{{ env \"PLATFORM_ENV\" }}/config.yaml" # Values file taken from path with environment variable. $PLATFORM_ENV must be set in the calling environment. | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,12 +8,14 @@ import ( | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
|  | 	"text/template" | ||||||
| 
 | 
 | ||||||
| 	"github.com/roboll/helmfile/helmexec" | 	"github.com/roboll/helmfile/helmexec" | ||||||
| 
 | 
 | ||||||
| 	yaml "gopkg.in/yaml.v1" | 	yaml "gopkg.in/yaml.v1" | ||||||
| 	"path" | 	"path" | ||||||
| 	"regexp" | 	"regexp" | ||||||
|  | 	"bytes" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type HelmState struct { | type HelmState struct { | ||||||
|  | @ -28,14 +30,16 @@ type RepositorySpec struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ChartSpec struct { | type ChartSpec struct { | ||||||
| 	Chart   string `yaml:"chart"` | 	Chart     string `yaml:"chart"` | ||||||
| 	Version string `yaml:"version"` | 	Version   string `yaml:"version"` | ||||||
| 	Verify  bool   `yaml:"verify"` | 	Verify    bool   `yaml:"verify"` | ||||||
| 
 | 
 | ||||||
| 	Name      string     `yaml:"name"` | 	Name      string     `yaml:"name"` | ||||||
| 	Namespace string     `yaml:"namespace"` | 	Namespace string     `yaml:"namespace"` | ||||||
| 	Values    []string   `yaml:"values"` | 	Values    []string   `yaml:"values"` | ||||||
| 	SetValues []SetValue `yaml:"set"` | 	SetValues []SetValue `yaml:"set"` | ||||||
|  | 
 | ||||||
|  | 	// The 'env' section is not really necessary any longer, as 'set' would now provide the same functionality
 | ||||||
| 	EnvValues []SetValue `yaml:"env"` | 	EnvValues []SetValue `yaml:"env"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -59,6 +63,41 @@ func ReadFromFile(file string) (*HelmState, error) { | ||||||
| 	return &state, nil | 	return &state, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var /* const */ | ||||||
|  | 	stringTemplateFuncMap = template.FuncMap{ | ||||||
|  | 		"env": getEnvVar, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | var /* const */ | ||||||
|  | 	stringTemplate = template.New("stringTemplate").Funcs(stringTemplateFuncMap) | ||||||
|  | 
 | ||||||
|  | func getEnvVar(envVarName string) (string, error) { | ||||||
|  | 	envVarValue, isSet := os.LookupEnv(envVarName) | ||||||
|  | 
 | ||||||
|  | 	if !isSet { | ||||||
|  | 		errMsg := fmt.Sprintf("Environment Variable '%s' is not set. Please make sure it is set and try again.", envVarName) | ||||||
|  | 		return "", errors.New(errMsg) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return envVarValue, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func renderTemplateString(s string) (string, error) { | ||||||
|  | 	var t, parseErr = stringTemplate.Parse(s) | ||||||
|  | 	if parseErr != nil { | ||||||
|  | 		return "", parseErr | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var tplString bytes.Buffer | ||||||
|  | 	var execErr = t.Execute(&tplString, nil) | ||||||
|  | 
 | ||||||
|  | 	if execErr != nil { | ||||||
|  | 		return "", execErr | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return tplString.String(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (state *HelmState) SyncRepos(helm helmexec.Interface) []error { | func (state *HelmState) SyncRepos(helm helmexec.Interface) []error { | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
| 	errs := []error{} | 	errs := []error{} | ||||||
|  | @ -203,15 +242,28 @@ func flagsForChart(basePath string, chart *ChartSpec) ([]string, error) { | ||||||
| 	} | 	} | ||||||
| 	for _, value := range chart.Values { | 	for _, value := range chart.Values { | ||||||
| 		valfile := filepath.Join(basePath, value) | 		valfile := filepath.Join(basePath, value) | ||||||
| 		flags = append(flags, "--values", valfile) | 		valfileRendered, err := renderTemplateString(valfile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		flags = append(flags, "--values", valfileRendered) | ||||||
| 	} | 	} | ||||||
| 	if len(chart.SetValues) > 0 { | 	if len(chart.SetValues) > 0 { | ||||||
| 		val := []string{} | 		val := []string{} | ||||||
| 		for _, set := range chart.SetValues { | 		for _, set := range chart.SetValues { | ||||||
| 			val = append(val, fmt.Sprintf("%s=%s", set.Name, set.Value)) | 			renderedValue, err := renderTemplateString(set.Value) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			val = append(val, fmt.Sprintf("%s=%s", set.Name, renderedValue)) | ||||||
| 		} | 		} | ||||||
| 		flags = append(flags, "--set", strings.Join(val, ",")) | 		flags = append(flags, "--set", strings.Join(val, ",")) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	/*********** | ||||||
|  | 	 * START 'env' section for backwards compatibility | ||||||
|  | 	 ***********/ | ||||||
|  | 	// The 'env' section is not really necessary any longer, as 'set' would now provide the same functionality
 | ||||||
| 	if len(chart.EnvValues) > 0 { | 	if len(chart.EnvValues) > 0 { | ||||||
| 		val := []string{} | 		val := []string{} | ||||||
| 		envValErrs := []string{} | 		envValErrs := []string{} | ||||||
|  | @ -231,5 +283,9 @@ func flagsForChart(basePath string, chart *ChartSpec) ([]string, error) { | ||||||
| 		} | 		} | ||||||
| 		flags = append(flags, "--set", strings.Join(val, ",")) | 		flags = append(flags, "--set", strings.Join(val, ",")) | ||||||
| 	} | 	} | ||||||
|  | 	/************** | ||||||
|  | 	 * END 'env' section for backwards compatibility | ||||||
|  | 	 **************/ | ||||||
|  | 
 | ||||||
| 	return flags, nil | 	return flags, nil | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue