Merge pull request #14 from jrnt30/relative-path-resolution
Relative path resolution changes
This commit is contained in:
		
						commit
						d604fe094a
					
				|  | @ -1 +1,2 @@ | ||||||
| dist/ | dist/ | ||||||
|  | .idea/ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | # Paths Overivew  | ||||||
|  | Using manifest files in conjunction with command line argument can be a bit confusing.   | ||||||
|  | 
 | ||||||
|  | A few rules to clear up this ambiguity:  | ||||||
|  | 
 | ||||||
|  | - Absolute paths are always resolved as absolute paths | ||||||
|  | - Relative paths referenced *in* the helmfile manifest itself are relative to that manifest | ||||||
|  | - Relative paths referenced on the command line are relative to the current working directory the user is in | ||||||
|  | 
 | ||||||
|  | ### Examples | ||||||
|  | There are several examples that we can go through in the `/examples` folder which demonstrate this. | ||||||
|  | 
 | ||||||
|  | **Local Execution** | ||||||
|  | 
 | ||||||
|  | This is an example of a Helmfile manifest referencing a local value directly.  | ||||||
|  | 
 | ||||||
|  | Indirect: | ||||||
|  | ``` | ||||||
|  | helmfile -f examples/deployments/local/charts.yaml sync | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Direct:  | ||||||
|  | ``` | ||||||
|  | cd examples/deployments/local/ | ||||||
|  | helmfile sync | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Relative Paths in Helmfile** | ||||||
|  | 
 | ||||||
|  | This is an example of a Helmfile manifest using relative paths for values.  | ||||||
|  | 
 | ||||||
|  | Indirect: | ||||||
|  | ``` | ||||||
|  | helmfile -f examples/deployments/dev/charts.yaml sync | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Direct:  | ||||||
|  | ``` | ||||||
|  | cd examples/deployments/dev/ | ||||||
|  | helmfile sync | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Relative Paths in Helmfile w/ --values overrides** | ||||||
|  | 
 | ||||||
|  | This is an example of a Helmfile manifest using relative paths for values including an additional `--values` from the command line.   | ||||||
|  | 
 | ||||||
|  | NOTE: The `--values` is resolved relative to the CWD of the terminal *not* the Helmfile manifest.  You can see this with the `replicas` being adjusted to 3 now for the deployment. | ||||||
|  | 
 | ||||||
|  | Indirect: | ||||||
|  | ``` | ||||||
|  | helmfile -f examples/deployments/dev/charts.yaml sync --values values/replica-values.yaml | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Direct:  | ||||||
|  | ``` | ||||||
|  | cd examples/deployments/dev/ | ||||||
|  | helmfile sync --values ../../values/replica-values.yaml | ||||||
|  | ``` | ||||||
							
								
								
									
										22
									
								
								README.md
								
								
								
								
							
							
						
						
									
										22
									
								
								README.md
								
								
								
								
							|  | @ -22,9 +22,10 @@ repositories: | ||||||
|     url: http://roboll.io/charts |     url: http://roboll.io/charts | ||||||
| 
 | 
 | ||||||
| charts: | charts: | ||||||
|  |   # 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 |     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 | ||||||
|  | @ -33,6 +34,13 @@ charts: | ||||||
|       - 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: DB_PASSWORD               # $DB_PASSOWRD needs to be set in the calling environment ex: export DB_PASSWORD='password1' | ||||||
| 
 | 
 | ||||||
|  |   # Local chart example | ||||||
|  |   - name: grafana                         # helm deployment name | ||||||
|  |     namespace: another                    # target namespace | ||||||
|  |     chart: ../my-charts/grafana           # chart reference (relative path to manifest) | ||||||
|  |     values: | ||||||
|  |     - ../../my-values/grafana/values.yaml # Values file (relative path to manifest) | ||||||
|  | 
 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## install | ## install | ||||||
|  | @ -72,3 +80,15 @@ the charts/releases defined in the manifest. | ||||||
| Under the covers Helmfile is simply using the `helm diff` plugin, so that needs to be installed prior.  For Helm 2.3+ | Under the covers Helmfile is simply using the `helm diff` plugin, so that needs to be installed prior.  For Helm 2.3+ | ||||||
| you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details | you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details | ||||||
| please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin). | please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin). | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## Paths Overview | ||||||
|  | Using manifest files in conjunction with command line argument can be a bit confusing.   | ||||||
|  | 
 | ||||||
|  | A few rules to clear up this ambiguity:  | ||||||
|  | 
 | ||||||
|  | - Absolute paths are always resolved as absolute paths | ||||||
|  | - Relative paths referenced *in* the helmfile manifest itself are relative to that manifest | ||||||
|  | - Relative paths referenced on the command line are relative to the current working directory the user is in | ||||||
|  | 
 | ||||||
|  | For additional context, take a look at [paths examples](PATHS.md) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | # Patterns to ignore when building packages. | ||||||
|  | # This supports shell glob matching, relative path matching, and | ||||||
|  | # negation (prefixed with !). Only one pattern per line. | ||||||
|  | .DS_Store | ||||||
|  | # Common VCS dirs | ||||||
|  | .git/ | ||||||
|  | .gitignore | ||||||
|  | .bzr/ | ||||||
|  | .bzrignore | ||||||
|  | .hg/ | ||||||
|  | .hgignore | ||||||
|  | .svn/ | ||||||
|  | # Common backup files | ||||||
|  | *.swp | ||||||
|  | *.bak | ||||||
|  | *.tmp | ||||||
|  | *~ | ||||||
|  | # Various IDEs | ||||||
|  | .project | ||||||
|  | .idea/ | ||||||
|  | *.tmproj | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | apiVersion: v1 | ||||||
|  | description: demonstration of local file path references in Helmfile | ||||||
|  | name: paths-example | ||||||
|  | version: 0.1.0 | ||||||
|  | @ -0,0 +1,16 @@ | ||||||
|  | {{/* vim: set filetype=mustache: */}} | ||||||
|  | {{/* | ||||||
|  | Expand the name of the chart. | ||||||
|  | */}} | ||||||
|  | {{- define "name" -}} | ||||||
|  | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} | ||||||
|  | {{- end -}} | ||||||
|  | 
 | ||||||
|  | {{/* | ||||||
|  | Create a default fully qualified app name. | ||||||
|  | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||||
|  | */}} | ||||||
|  | {{- define "fullname" -}} | ||||||
|  | {{- $name := default .Chart.Name .Values.nameOverride -}} | ||||||
|  | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} | ||||||
|  | {{- end -}} | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | apiVersion: extensions/v1beta1 | ||||||
|  | kind: Deployment | ||||||
|  | metadata: | ||||||
|  |   name: {{ template "fullname" . }} | ||||||
|  |   labels: | ||||||
|  |     app: {{ template "name" . }} | ||||||
|  |     chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} | ||||||
|  |     release: {{ .Release.Name }} | ||||||
|  |     heritage: {{ .Release.Service }} | ||||||
|  | spec: | ||||||
|  |   replicas: {{ .Values.replicaCount }} | ||||||
|  |   template: | ||||||
|  |     metadata: | ||||||
|  |       labels: | ||||||
|  |         app: {{ template "name" . }} | ||||||
|  |         release: {{ .Release.Name }} | ||||||
|  |     spec: | ||||||
|  |       containers: | ||||||
|  |         - name: {{ .Chart.Name }} | ||||||
|  |           image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" | ||||||
|  |           imagePullPolicy: {{ .Values.image.pullPolicy }} | ||||||
|  |           ports: | ||||||
|  |             - containerPort: {{ .Values.service.internalPort }} | ||||||
|  |           livenessProbe: | ||||||
|  |             httpGet: | ||||||
|  |               path: / | ||||||
|  |               port: {{ .Values.service.internalPort }} | ||||||
|  |           readinessProbe: | ||||||
|  |             httpGet: | ||||||
|  |               path: / | ||||||
|  |               port: {{ .Values.service.internalPort }} | ||||||
|  |           resources: | ||||||
|  | {{ toYaml .Values.resources | indent 12 }} | ||||||
|  |     {{- if .Values.nodeSelector }} | ||||||
|  |       nodeSelector: | ||||||
|  | {{ toYaml .Values.nodeSelector | indent 8 }} | ||||||
|  |     {{- end }} | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: Service | ||||||
|  | metadata: | ||||||
|  |   name: {{ template "fullname" . }} | ||||||
|  |   labels: | ||||||
|  |     app: {{ template "name" . }} | ||||||
|  |     chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} | ||||||
|  |     release: {{ .Release.Name }} | ||||||
|  |     heritage: {{ .Release.Service }} | ||||||
|  | spec: | ||||||
|  |   type: {{ .Values.service.type }} | ||||||
|  |   ports: | ||||||
|  |     - port: {{ .Values.service.externalPort }} | ||||||
|  |       targetPort: {{ .Values.service.internalPort }} | ||||||
|  |       protocol: TCP | ||||||
|  |       name: {{ .Values.service.name }} | ||||||
|  |   selector: | ||||||
|  |     app: {{ template "name" . }} | ||||||
|  |     release: {{ .Release.Name }} | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | # Default values for paths-example. | ||||||
|  | # This is a YAML-formatted file. | ||||||
|  | # Declare variables to be passed into your templates. | ||||||
|  | replicaCount: 1 | ||||||
|  | image: | ||||||
|  |   repository: nginx | ||||||
|  |   tag: stable | ||||||
|  |   pullPolicy: IfNotPresent | ||||||
|  | service: | ||||||
|  |   name: nginx | ||||||
|  |   type: ClusterIP | ||||||
|  |   externalPort: 80 | ||||||
|  |   internalPort: 80 | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | charts: | ||||||
|  |   - name: dev-paths-example | ||||||
|  |     namespace: dev | ||||||
|  |     chart: ../../charts/paths-example/ | ||||||
|  |     values: | ||||||
|  |     - ../../values/dev/paths-example/values.yaml # Values file (relative path to manifest) | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | charts: | ||||||
|  |   - name: local-paths-example | ||||||
|  |     namespace: local | ||||||
|  |     chart: ../../charts/paths-example/ | ||||||
|  |     values: | ||||||
|  |     - values.yaml # Values file (relative path to manifest) | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | # Dev specific overrides | ||||||
|  | nameOverride: local-nginx | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | charts: | ||||||
|  |   - name: prod-paths-example | ||||||
|  |     namespace: prod | ||||||
|  |     chart: ../../charts/paths-example/ | ||||||
|  |     values: | ||||||
|  |     - ../../values/prod/paths-example/values.yaml # Values file (relative path to manifest) | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | charts: | ||||||
|  |   # Published chart example | ||||||
|  |   - name: grafana                         # helm deployment name | ||||||
|  |     namespace: grafana                    # target namespace | ||||||
|  |     chart: stable/grafana                 # chart reference (repository) | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | # Dev specific overrides | ||||||
|  | nameOverride: dev-nginx | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | # Prod specific overrides | ||||||
|  | nameOverride: prod-nginx | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | # Example used to override value explicitly via CLI | ||||||
|  | replicaCount: 3 | ||||||
|  | @ -6,8 +6,6 @@ import ( | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/exec" | 	"os/exec" | ||||||
| 	"path/filepath" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -48,27 +46,7 @@ func (helm *execer) UpdateRepo() error { | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func normalizeChart(chart string) (string, error) { |  | ||||||
| 	regex, err := regexp.Compile("^[.]?./") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	if !regex.MatchString(chart) { |  | ||||||
| 		return chart, nil |  | ||||||
| 	} |  | ||||||
| 	wd, err := os.Getwd() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	path := filepath.Join(wd, chart) |  | ||||||
| 	return path, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (helm *execer) SyncChart(name, chart string, flags ...string) error { | func (helm *execer) SyncChart(name, chart string, flags ...string) error { | ||||||
| 	chart, err := normalizeChart(chart) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	out, err := helm.exec(append([]string{"upgrade", "--install", name, chart}, flags...)...) | 	out, err := helm.exec(append([]string{"upgrade", "--install", name, chart}, flags...)...) | ||||||
| 	if helm.writer != nil { | 	if helm.writer != nil { | ||||||
| 		helm.writer.Write(out) | 		helm.writer.Write(out) | ||||||
|  | @ -77,10 +55,6 @@ func (helm *execer) SyncChart(name, chart string, flags ...string) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (helm *execer) DiffChart(name, chart string, flags ...string) error { | func (helm *execer) DiffChart(name, chart string, flags ...string) error { | ||||||
| 	chart, err := normalizeChart(chart) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	out, err := helm.exec(append([]string{"diff", name, chart}, flags...)...) | 	out, err := helm.exec(append([]string{"diff", name, chart}, flags...)...) | ||||||
| 	if helm.writer != nil { | 	if helm.writer != nil { | ||||||
| 		helm.writer.Write(out) | 		helm.writer.Write(out) | ||||||
|  |  | ||||||
|  | @ -12,11 +12,14 @@ import ( | ||||||
| 	"github.com/roboll/helmfile/helmexec" | 	"github.com/roboll/helmfile/helmexec" | ||||||
| 
 | 
 | ||||||
| 	yaml "gopkg.in/yaml.v1" | 	yaml "gopkg.in/yaml.v1" | ||||||
|  | 	"path" | ||||||
|  | 	"regexp" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type HelmState struct { | type HelmState struct { | ||||||
| 	Repositories []RepositorySpec `yaml:"repositories"` | 	BaseChartPath string | ||||||
| 	Charts       []ChartSpec      `yaml:"charts"` | 	Repositories  []RepositorySpec `yaml:"repositories"` | ||||||
|  | 	Charts        []ChartSpec      `yaml:"charts"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type RepositorySpec struct { | type RepositorySpec struct { | ||||||
|  | @ -48,6 +51,8 @@ func ReadFromFile(file string) (*HelmState, error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var state HelmState | 	var state HelmState | ||||||
|  | 
 | ||||||
|  | 	state.BaseChartPath, _ = filepath.Abs(path.Dir(file)) | ||||||
| 	if err := yaml.Unmarshal(content, &state); err != nil { | 	if err := yaml.Unmarshal(content, &state); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | @ -86,20 +91,19 @@ func (state *HelmState) SyncCharts(helm helmexec.Interface, additonalValues []st | ||||||
| 	for _, chart := range state.Charts { | 	for _, chart := range state.Charts { | ||||||
| 		wg.Add(1) | 		wg.Add(1) | ||||||
| 		go func(wg *sync.WaitGroup, chart ChartSpec) { | 		go func(wg *sync.WaitGroup, chart ChartSpec) { | ||||||
| 			flags, flagsErr := flagsForChart(&chart) | 			flags, flagsErr := flagsForChart(state.BaseChartPath, &chart) | ||||||
| 			if flagsErr != nil { | 			if flagsErr != nil { | ||||||
| 				errs = append(errs, flagsErr) | 				errs = append(errs, flagsErr) | ||||||
| 			} | 			} | ||||||
| 			for _, value := range additonalValues { | 			for _, value := range additonalValues { | ||||||
| 				wd, wdErr := os.Getwd() | 				valfile, err := filepath.Abs(value) | ||||||
| 				if wdErr != nil { | 				if err != nil { | ||||||
| 					errs = append(errs, wdErr) | 					errs = append(errs, err) | ||||||
| 				} | 				} | ||||||
| 				valfile := filepath.Join(wd, value) |  | ||||||
| 				flags = append(flags, "--values", valfile) | 				flags = append(flags, "--values", valfile) | ||||||
| 			} | 			} | ||||||
| 			if len(errs) == 0 { | 			if len(errs) == 0 { | ||||||
| 				if err := helm.SyncChart(chart.Name, chart.Chart, flags...); err != nil { | 				if err := helm.SyncChart(chart.Name, normalizeChart(state.BaseChartPath, chart.Chart), flags...); err != nil { | ||||||
| 					errs = append(errs, err) | 					errs = append(errs, err) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | @ -124,20 +128,19 @@ func (state *HelmState) DiffCharts(helm helmexec.Interface, additonalValues []st | ||||||
| 		go func(wg *sync.WaitGroup, chart ChartSpec) { | 		go func(wg *sync.WaitGroup, chart ChartSpec) { | ||||||
| 			// Plugin command doesn't support explicit namespace
 | 			// Plugin command doesn't support explicit namespace
 | ||||||
| 			chart.Namespace = "" | 			chart.Namespace = "" | ||||||
| 			flags, flagsErr := flagsForChart(&chart) | 			flags, flagsErr := flagsForChart(state.BaseChartPath, &chart) | ||||||
| 			if flagsErr != nil { | 			if flagsErr != nil { | ||||||
| 				errs = append(errs, flagsErr) | 				errs = append(errs, flagsErr) | ||||||
| 			} | 			} | ||||||
| 			for _, value := range additonalValues { | 			for _, value := range additonalValues { | ||||||
| 				wd, wdErr := os.Getwd() | 				valfile, err := filepath.Abs(value) | ||||||
| 				if wdErr != nil { | 				if err != nil { | ||||||
| 					errs = append(errs, wdErr) | 					errs = append(errs, err) | ||||||
| 				} | 				} | ||||||
| 				valfile := filepath.Join(wd, value) |  | ||||||
| 				flags = append(flags, "--values", valfile) | 				flags = append(flags, "--values", valfile) | ||||||
| 			} | 			} | ||||||
| 			if len(errs) == 0 { | 			if len(errs) == 0 { | ||||||
| 				if err := helm.DiffChart(chart.Name, chart.Chart, flags...); err != nil { | 				if err := helm.DiffChart(chart.Name, normalizeChart(state.BaseChartPath, chart.Chart), flags...); err != nil { | ||||||
| 					errs = append(errs, err) | 					errs = append(errs, err) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | @ -175,7 +178,19 @@ func (state *HelmState) DeleteCharts(helm helmexec.Interface) []error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func flagsForChart(chart *ChartSpec) ([]string, error) { | // normalizeChart allows for the distinction between a file path reference and repository references.
 | ||||||
|  | // - Any single (or double character) followed by a `/` will be considered a local file reference and
 | ||||||
|  | // 	 be constructed relative to the `base path`.
 | ||||||
|  | // - Everything else is assumed to be an absolute path or an actual <repository>/<chart> reference.
 | ||||||
|  | func normalizeChart(basePath, chart string) (string) { | ||||||
|  | 	regex, _ := regexp.Compile("^[.]?./") | ||||||
|  | 	if !regex.MatchString(chart) { | ||||||
|  | 		return chart | ||||||
|  | 	} | ||||||
|  | 	return filepath.Join(basePath, chart) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func flagsForChart(basePath string, chart *ChartSpec) ([]string, error) { | ||||||
| 	flags := []string{} | 	flags := []string{} | ||||||
| 	if chart.Version != "" { | 	if chart.Version != "" { | ||||||
| 		flags = append(flags, "--version", chart.Version) | 		flags = append(flags, "--version", chart.Version) | ||||||
|  | @ -187,11 +202,7 @@ func flagsForChart(chart *ChartSpec) ([]string, error) { | ||||||
| 		flags = append(flags, "--namespace", chart.Namespace) | 		flags = append(flags, "--namespace", chart.Namespace) | ||||||
| 	} | 	} | ||||||
| 	for _, value := range chart.Values { | 	for _, value := range chart.Values { | ||||||
| 		wd, err := os.Getwd() | 		valfile := filepath.Join(basePath, value) | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		valfile := filepath.Join(wd, value) |  | ||||||
| 		flags = append(flags, "--values", valfile) | 		flags = append(flags, "--values", valfile) | ||||||
| 	} | 	} | ||||||
| 	if len(chart.SetValues) > 0 { | 	if len(chart.SetValues) > 0 { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue