Merge pull request #1273 from roboll/fix-chartify
fix: Follow-up fixes for #1172
This commit is contained in:
		
						commit
						930f91a70d
					
				|  | @ -89,3 +89,49 @@ At this point, Helmfile can generate a complete kustomization from the base kust | ||||||
| which can be included in the temporary chart. | which can be included in the temporary chart. | ||||||
| 
 | 
 | ||||||
| After all, Helmfile just installs the temporary chart like standard charts, which allows you to manage everything with Helmfile regardless of each app is declared using a Helm chart or a kustomization. | After all, Helmfile just installs the temporary chart like standard charts, which allows you to manage everything with Helmfile regardless of each app is declared using a Helm chart or a kustomization. | ||||||
|  | 
 | ||||||
|  | Please also see [test/advanced/helmfile.yaml](https://github.com/roboll/helmfile/tree/master/test/advanced/helmfile.yaml) for an example of kustomization support and more. | ||||||
|  | 
 | ||||||
|  | ## Adhoc Customization of Helm charts | ||||||
|  | 
 | ||||||
|  | You can add/update any Kubernetes resource field rendered from a Helm chart by specifying `releases[].strategicMergePatches`: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | repositories: | ||||||
|  | - name: incubator | ||||||
|  |   url: https://kubernetes-charts-incubator.storage.googleapis.com | ||||||
|  | 
 | ||||||
|  | releases: | ||||||
|  | - name: raw1 | ||||||
|  |   chart: incubator/raw | ||||||
|  |   values: | ||||||
|  |   - resources: | ||||||
|  |     - apiVersion: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       metadata: | ||||||
|  |         name: raw1 | ||||||
|  |         namespace: default | ||||||
|  |       data: | ||||||
|  |         foo: FOO | ||||||
|  |   strategicMergePatches: | ||||||
|  |     - apiVersion: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       metadata: | ||||||
|  |         name: raw1 | ||||||
|  |         namespace: default | ||||||
|  |       data: | ||||||
|  |         bar: BAR | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Running `helmfile template` on the above example results in a ConfigMap called `raw` whose `data` is: | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  | foo: FOO | ||||||
|  | bar: BAR | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Please note that the second `data` field `bar` is coming from the strategic-merge patch defined in the above helmfile.yaml. | ||||||
|  | 
 | ||||||
|  | There's also `releases[].jsonPatches` that works similarly to `strategicMergePatches` but has additional capability to remove fields. | ||||||
|  | 
 | ||||||
|  | Please also see [test/advanced/helmfile.yaml](https://github.com/roboll/helmfile/tree/master/test/advanced/helmfile.yaml) for an example of patching support and more. | ||||||
|  |  | ||||||
|  | @ -1,7 +1,10 @@ | ||||||
| package state | package state | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"github.com/roboll/helmfile/pkg/helmexec" | ||||||
| 	"github.com/variantdev/chartify" | 	"github.com/variantdev/chartify" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -19,11 +22,22 @@ func (st *HelmState) appendHelmXFlags(flags []string, release *ReleaseSpec) ([]s | ||||||
| 	return flags, nil | 	return flags, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (st *HelmState) PrepareChartify(release *ReleaseSpec) (bool, *chartify.ChartifyOpts) { | func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) (bool, *chartify.ChartifyOpts, error) { | ||||||
| 	var opts chartify.ChartifyOpts | 	var opts chartify.ChartifyOpts | ||||||
| 
 | 
 | ||||||
| 	var shouldRun bool | 	var shouldRun bool | ||||||
| 
 | 
 | ||||||
|  | 	opts.EnableKustomizeAlphaPlugins = true | ||||||
|  | 
 | ||||||
|  | 	opts.ChartVersion = release.Version | ||||||
|  | 
 | ||||||
|  | 	dir := filepath.Join(st.basePath, release.Chart) | ||||||
|  | 	if stat, _ := os.Stat(dir); stat != nil && stat.IsDir() { | ||||||
|  | 		if exists, err := st.fileExists(filepath.Join(dir, "Chart.yaml")); err == nil && !exists { | ||||||
|  | 			shouldRun = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	for _, d := range release.Dependencies { | 	for _, d := range release.Dependencies { | ||||||
| 		var dep string | 		var dep string | ||||||
| 
 | 
 | ||||||
|  | @ -52,7 +66,7 @@ func (st *HelmState) PrepareChartify(release *ReleaseSpec) (bool, *chartify.Char | ||||||
| 	if len(jsonPatches) > 0 { | 	if len(jsonPatches) > 0 { | ||||||
| 		generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler) | 		generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return false, nil | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for _, f := range generatedFiles { | 		for _, f := range generatedFiles { | ||||||
|  | @ -68,7 +82,7 @@ func (st *HelmState) PrepareChartify(release *ReleaseSpec) (bool, *chartify.Char | ||||||
| 	if len(strategicMergePatches) > 0 { | 	if len(strategicMergePatches) > 0 { | ||||||
| 		generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler) | 		generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return false, nil | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for _, f := range generatedFiles { | 		for _, f := range generatedFiles { | ||||||
|  | @ -80,5 +94,14 @@ func (st *HelmState) PrepareChartify(release *ReleaseSpec) (bool, *chartify.Char | ||||||
| 		shouldRun = true | 		shouldRun = true | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return shouldRun, &opts | 	if shouldRun { | ||||||
|  | 		generatedFiles, err := st.generateValuesFiles(helm, release, workerIndex) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		opts.ValuesFiles = generatedFiles | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return shouldRun, &opts, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -718,6 +718,7 @@ func PrepareCharts(helm helmexec.Interface, st *HelmState, dir string, concurren | ||||||
| 	type downloadResults struct { | 	type downloadResults struct { | ||||||
| 		releaseName string | 		releaseName string | ||||||
| 		chartPath   string | 		chartPath   string | ||||||
|  | 		err         error | ||||||
| 	} | 	} | ||||||
| 	errs := []error{} | 	errs := []error{} | ||||||
| 
 | 
 | ||||||
|  | @ -739,11 +740,17 @@ func PrepareCharts(helm helmexec.Interface, st *HelmState, dir string, concurren | ||||||
| 			} | 			} | ||||||
| 			close(jobQueue) | 			close(jobQueue) | ||||||
| 		}, | 		}, | ||||||
| 		func(_ int) { | 		func(workerIndex int) { | ||||||
| 			for release := range jobQueue { | 			for release := range jobQueue { | ||||||
| 				var chartPath string | 				var chartPath string | ||||||
| 
 | 
 | ||||||
| 				if shouldChartify, opts := st.PrepareChartify(release); shouldChartify { | 				shouldChartify, opts, err := st.PrepareChartify(helm, release, workerIndex) | ||||||
|  | 				if err != nil { | ||||||
|  | 					results <- &downloadResults{err: err} | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if shouldChartify { | ||||||
| 					c := chartify.New( | 					c := chartify.New( | ||||||
| 						chartify.HelmBin(st.DefaultHelmBinary), | 						chartify.HelmBin(st.DefaultHelmBinary), | ||||||
| 						chartify.UseHelm3(helm3), | 						chartify.UseHelm3(helm3), | ||||||
|  | @ -787,12 +794,18 @@ func PrepareCharts(helm helmexec.Interface, st *HelmState, dir string, concurren | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				results <- &downloadResults{release.Name, chartPath} | 				results <- &downloadResults{releaseName: release.Name, chartPath: chartPath} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| 		func() { | 		func() { | ||||||
| 			for i := 0; i < len(st.Releases); i++ { | 			for i := 0; i < len(st.Releases); i++ { | ||||||
| 				downloadRes := <-results | 				downloadRes := <-results | ||||||
|  | 
 | ||||||
|  | 				if downloadRes.err != nil { | ||||||
|  | 					errs = append(errs, downloadRes.err) | ||||||
|  | 
 | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
| 				temp[downloadRes.releaseName] = downloadRes.chartPath | 				temp[downloadRes.releaseName] = downloadRes.chartPath | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | @ -1886,12 +1899,7 @@ func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingF | ||||||
| 	return generatedFiles, nil | 	return generatedFiles, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (st *HelmState) namespaceAndValuesFlags(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) ([]string, error) { | func (st *HelmState) generateVanillaValuesFiles(release *ReleaseSpec) ([]string, error) { | ||||||
| 	flags := []string{} |  | ||||||
| 	if release.Namespace != "" { |  | ||||||
| 		flags = append(flags, "--namespace", release.Namespace) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	values := []interface{}{} | 	values := []interface{}{} | ||||||
| 	for _, v := range release.Values { | 	for _, v := range release.Values { | ||||||
| 		switch typedValue := v.(type) { | 		switch typedValue := v.(type) { | ||||||
|  | @ -1918,12 +1926,14 @@ func (st *HelmState) namespaceAndValuesFlags(helm helmexec.Interface, release *R | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, f := range generatedFiles { |  | ||||||
| 		flags = append(flags, "--values", f) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	release.generatedValues = append(release.generatedValues, generatedFiles...) | 	release.generatedValues = append(release.generatedValues, generatedFiles...) | ||||||
| 
 | 
 | ||||||
|  | 	return generatedFiles, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (st *HelmState) generateSecretValuesFiles(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) ([]string, error) { | ||||||
|  | 	var generatedFiles []string | ||||||
|  | 
 | ||||||
| 	for _, value := range release.Secrets { | 	for _, value := range release.Secrets { | ||||||
| 		paths, skip, err := st.storage().resolveFile(release.MissingFileHandler, "secrets", release.ValuesPathPrefix+value) | 		paths, skip, err := st.storage().resolveFile(release.MissingFileHandler, "secrets", release.ValuesPathPrefix+value) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -1944,9 +1954,45 @@ func (st *HelmState) namespaceAndValuesFlags(helm helmexec.Interface, release *R | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		release.generatedValues = append(release.generatedValues, valfile) | 		generatedFiles = append(generatedFiles, valfile) | ||||||
| 		flags = append(flags, "--values", valfile) |  | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	release.generatedValues = append(release.generatedValues, generatedFiles...) | ||||||
|  | 
 | ||||||
|  | 	return generatedFiles, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (st *HelmState) generateValuesFiles(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) ([]string, error) { | ||||||
|  | 	valuesFiles, err := st.generateVanillaValuesFiles(release) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	secretValuesFiles, err := st.generateSecretValuesFiles(helm, release, workerIndex) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	files := append(valuesFiles, secretValuesFiles...) | ||||||
|  | 
 | ||||||
|  | 	return files, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (st *HelmState) namespaceAndValuesFlags(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) ([]string, error) { | ||||||
|  | 	flags := []string{} | ||||||
|  | 	if release.Namespace != "" { | ||||||
|  | 		flags = append(flags, "--namespace", release.Namespace) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	generatedFiles, err := st.generateValuesFiles(helm, release, workerIndex) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, f := range generatedFiles { | ||||||
|  | 		flags = append(flags, "--values", f) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if len(release.SetValues) > 0 { | 	if len(release.SetValues) > 0 { | ||||||
| 		for _, set := range release.SetValues { | 		for _, set := range release.SetValues { | ||||||
| 			if set.Value != "" { | 			if set.Value != "" { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,49 @@ | ||||||
|  | repositories: | ||||||
|  | - name: incubator | ||||||
|  |   url: https://kubernetes-charts-incubator.storage.googleapis.com | ||||||
|  | 
 | ||||||
|  | releases: | ||||||
|  | - name: kustomapp | ||||||
|  |   chart: ./kustomapp | ||||||
|  |   values: | ||||||
|  |   - namePrefix: kustomapp- | ||||||
|  | - name: raw1 | ||||||
|  |   chart: incubator/raw | ||||||
|  |   values: | ||||||
|  |   - resources: | ||||||
|  |     - apiVersion: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       metadata: | ||||||
|  |         name: raw1 | ||||||
|  |         namespace: default | ||||||
|  |       data: | ||||||
|  |         foo: FOO | ||||||
|  |   strategicMergePatches: | ||||||
|  |     - apiVersion: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       metadata: | ||||||
|  |         name: raw1 | ||||||
|  |         namespace: default | ||||||
|  |       data: | ||||||
|  |         bar: BAR | ||||||
|  | - name: raw2 | ||||||
|  |   chart: incubator/raw | ||||||
|  |   values: | ||||||
|  |   - resources: | ||||||
|  |     - apiVersion: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       metadata: | ||||||
|  |         name: raw2 | ||||||
|  |         namespace: default | ||||||
|  |       data: | ||||||
|  |         foo: FOO | ||||||
|  |   jsonPatches: | ||||||
|  |   - target: | ||||||
|  |       version: v1 | ||||||
|  |       kind: ConfigMap | ||||||
|  |       name: raw2 | ||||||
|  |       namespace: default | ||||||
|  |     patch: | ||||||
|  |       - op: replace | ||||||
|  |         path: /data/baz | ||||||
|  |         value: "BAZ" | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: ConfigMap | ||||||
|  | metadata: | ||||||
|  |   name: kustomapp | ||||||
|  |   namespace: default | ||||||
|  | data: | ||||||
|  |   kustomappfoo: FOO | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | resources: | ||||||
|  | - all.yaml | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: ConfigMap | ||||||
|  | metadata: | ||||||
|  |   name: kustomapp2 | ||||||
|  |   namespace: default | ||||||
|  | data: | ||||||
|  |   kustomappfoo: FOO | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | resources: | ||||||
|  | - all.yaml | ||||||
		Loading…
	
		Reference in New Issue