feat: make environment context available (#832)
* feat: make environment context available
This feature adds the "{{.Environment.KubeContext}}" variable.
Discussion #829
Signed-off-by: sewieland <sebastian.wieland@iav.de>
* chore: fix tests which compare logging outputs
This commit adds an addtional space wherever needed to the expected log outputs due to the added "KubeContext" in the environment struct.
Discussion #829
Signed-off-by: Sebastian Wieland <wieland.s@mailbox.org>
* docs: added documentation for `Environment.KubeContext`
Discussion #829
Signed-off-by: Sebastian Wieland <wieland.s@mailbox.org>
* test: make sure the `Environment.KubeContext` is mapped out correctly
Discussion #829
Signed-off-by: Sebastian Wieland <wieland.s@mailbox.org>
---------
Signed-off-by: sewieland <sebastian.wieland@iav.de>
Signed-off-by: Sebastian Wieland <wieland.s@mailbox.org>
Co-authored-by: sewieland <sebastian.wieland@iav.de>
This commit is contained in:
parent
c299cd930d
commit
8b3ad5b793
|
|
@ -3,13 +3,14 @@
|
||||||
- `Environment`: The information about the environment. This is set by the
|
- `Environment`: The information about the environment. This is set by the
|
||||||
`--environment` flag. It has several objects inside of it:
|
`--environment` flag. It has several objects inside of it:
|
||||||
- `Environment.Name`: The name of the environment
|
- `Environment.Name`: The name of the environment
|
||||||
|
- `Environment.KubeContext`: The kube context to be used by default for releases in the environment.
|
||||||
- `Values`: Values passed into the environment.
|
- `Values`: Values passed into the environment.
|
||||||
- `StateValues`: alias for `Values`.
|
- `StateValues`: alias for `Values`.
|
||||||
- `Namespace`: The namespace to be released into
|
- `Namespace`: The namespace to be released into
|
||||||
|
|
||||||
# release template built-in objects
|
# release template built-in objects
|
||||||
|
|
||||||
it be used for the below tow cases:
|
it be used for the below two cases:
|
||||||
|
|
||||||
1. release definition
|
1. release definition
|
||||||
```
|
```
|
||||||
|
|
@ -56,6 +57,7 @@ releases:
|
||||||
- `Environment`: The information about the environment. This is set by the
|
- `Environment`: The information about the environment. This is set by the
|
||||||
`--environment` flag. It has several objects inside of it:
|
`--environment` flag. It has several objects inside of it:
|
||||||
- `Environment.Name`: The name of the environment
|
- `Environment.Name`: The name of the environment
|
||||||
|
- `Environment.KubeContext`: The kube context to be used by default for releases in the environment.
|
||||||
- `Chart`: The chart name for the release.
|
- `Chart`: The chart name for the release.
|
||||||
- `KubeContext`: The kube context to be used for the release
|
- `KubeContext`: The kube context to be used for the release
|
||||||
- `Namespace`: The namespace to be released into
|
- `Namespace`: The namespace to be released into
|
||||||
|
|
|
||||||
|
|
@ -1353,6 +1353,67 @@ releases:
|
||||||
For templating, imagine that you created a hook that generates a helm chart on-the-fly by running an external tool like ksonnet, kustomize, or your own template engine.
|
For templating, imagine that you created a hook that generates a helm chart on-the-fly by running an external tool like ksonnet, kustomize, or your own template engine.
|
||||||
It will allow you to write your helm releases with any language you like, while still leveraging goodies provided by helm.
|
It will allow you to write your helm releases with any language you like, while still leveraging goodies provided by helm.
|
||||||
|
|
||||||
|
### Hooks, Kubectl and Environments
|
||||||
|
|
||||||
|
Hooks can also be used in combination with small tasks using `kubectl` directly,
|
||||||
|
e.g.: in order to install a custom storage class.
|
||||||
|
|
||||||
|
In the following example, a specific release depends on a custom storage class.
|
||||||
|
Further, all enviroments have a default kube context configured where releases are deployed into.
|
||||||
|
The `.Environment.KubeContext` is used in order to apply / remove the YAML to the correct context depending on the environment.
|
||||||
|
|
||||||
|
`environments.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environments:
|
||||||
|
dev:
|
||||||
|
values:
|
||||||
|
- ../values/default.yaml
|
||||||
|
- ../values/dev.yaml
|
||||||
|
kubeContext: dev-cluster
|
||||||
|
prod:
|
||||||
|
values:
|
||||||
|
- ../values/default.yaml
|
||||||
|
- ../values/prod.yaml
|
||||||
|
kubeContext: prod-cluster
|
||||||
|
```
|
||||||
|
|
||||||
|
`helmfile.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bases:
|
||||||
|
- ./environments.yaml
|
||||||
|
|
||||||
|
---
|
||||||
|
releases:
|
||||||
|
- name: myService
|
||||||
|
namespace: my-ns
|
||||||
|
installed: true
|
||||||
|
chart: mychart
|
||||||
|
version: "1.2.3"
|
||||||
|
values:
|
||||||
|
- ../services/my-service/values.yaml.gotmpl
|
||||||
|
hooks:
|
||||||
|
- events: ["presync"]
|
||||||
|
showlogs: true
|
||||||
|
command: "kubectl"
|
||||||
|
args:
|
||||||
|
- "apply"
|
||||||
|
- "-f"
|
||||||
|
- "./custom-storage-class.yaml"
|
||||||
|
- "--context"
|
||||||
|
- "{{`{{.Environment.KubeContext}}`}}"
|
||||||
|
- events: ["postuninstall"]
|
||||||
|
showlogs: true
|
||||||
|
command: "kubectl"
|
||||||
|
args:
|
||||||
|
- "delete"
|
||||||
|
- "-f"
|
||||||
|
- "./custom-storage-class.yaml"
|
||||||
|
- "--context"
|
||||||
|
- "{{`{{.Environment.KubeContext}}`}}"
|
||||||
|
```
|
||||||
|
|
||||||
### Global Hooks
|
### Global Hooks
|
||||||
|
|
||||||
In contrast to the per release hooks mentioned above these are run only once at the very beginning and end of the execution of a helmfile command and only the `prepare` and `cleanup` hooks are available respectively.
|
In contrast to the per release hooks mentioned above these are run only once at the very beginning and end of the execution of a helmfile command and only the `prepare` and `cleanup` hooks are available respectively.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
type Environment struct {
|
type Environment struct {
|
||||||
Name string
|
Name string
|
||||||
|
KubeContext string
|
||||||
Values map[string]interface{}
|
Values map[string]interface{}
|
||||||
Defaults map[string]interface{}
|
Defaults map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +20,7 @@ var EmptyEnvironment Environment
|
||||||
func New(name string) *Environment {
|
func New(name string) *Environment {
|
||||||
return &Environment{
|
return &Environment{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
KubeContext: "",
|
||||||
Values: map[string]interface{}{},
|
Values: map[string]interface{}{},
|
||||||
Defaults: map[string]interface{}{},
|
Defaults: map[string]interface{}{},
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +55,7 @@ func (e Environment) DeepCopy() Environment {
|
||||||
|
|
||||||
return Environment{
|
return Environment{
|
||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
|
KubeContext: e.KubeContext,
|
||||||
Values: values,
|
Values: values,
|
||||||
Defaults: defaults,
|
Defaults: defaults,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ func (c *StateCreator) loadEnvValues(st *HelmState, name string, failOnMissingEn
|
||||||
return nil, &UndefinedEnvError{msg: fmt.Sprintf("environment \"%s\" is not defined", name)}
|
return nil, &UndefinedEnvError{msg: fmt.Sprintf("environment \"%s\" is not defined", name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
newEnv := &environment.Environment{Name: name, Values: envVals}
|
newEnv := &environment.Environment{Name: name, Values: envVals, KubeContext: envSpec.KubeContext}
|
||||||
|
|
||||||
if ctxEnv != nil {
|
if ctxEnv != nil {
|
||||||
intCtxEnv := *ctxEnv
|
intCtxEnv := *ctxEnv
|
||||||
|
|
|
||||||
|
|
@ -489,3 +489,58 @@ func TestReadFromYaml_Helmfiles_Selectors(t *testing.T) {
|
||||||
require.Equalf(t, test.helmfiles, st.Helmfiles, "for path %s", test.path)
|
require.Equalf(t, test.helmfiles, st.Helmfiles, "for path %s", test.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadFromYaml_EnvironmentContext(t *testing.T) {
|
||||||
|
yamlFile := "/example/path/to/helmfile.yaml"
|
||||||
|
yamlContent := []byte(`environments:
|
||||||
|
production:
|
||||||
|
values: []
|
||||||
|
kubeContext: myCtx
|
||||||
|
|
||||||
|
releases:
|
||||||
|
- name: myrelease
|
||||||
|
namespace: mynamespace
|
||||||
|
chart: mychart
|
||||||
|
values:
|
||||||
|
- values.yaml.gotmpl
|
||||||
|
`)
|
||||||
|
|
||||||
|
valuesFile := "/example/path/to/values.yaml.gotmpl"
|
||||||
|
valuesContent := []byte(`envName: {{ .Environment.Name }}
|
||||||
|
envContext: {{ .Environment.KubeContext }}
|
||||||
|
releaseName: {{ .Release.Name }}
|
||||||
|
releaseContext: {{ .Release.KubeContext }}
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedValues := `envName: production
|
||||||
|
envContext: myCtx
|
||||||
|
releaseName: myrelease
|
||||||
|
releaseContext:
|
||||||
|
`
|
||||||
|
|
||||||
|
testFs := testhelper.NewTestFs(map[string]string{
|
||||||
|
valuesFile: string(valuesContent),
|
||||||
|
})
|
||||||
|
testFs.Cwd = "/example/path/to"
|
||||||
|
|
||||||
|
r := remote.NewRemote(logger, testFs.Cwd, testFs.ToFileSystem())
|
||||||
|
state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", r, false, "").
|
||||||
|
ParseAndLoad(yamlContent, filepath.Dir(yamlFile), yamlFile, "production", true, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
release := state.Releases[0]
|
||||||
|
|
||||||
|
state.ApplyOverrides(&release)
|
||||||
|
|
||||||
|
actualValuesData, err := state.RenderReleaseValuesFileToBytes(&release, valuesFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
actualValues := string(actualValuesData)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedValues, actualValues) {
|
||||||
|
t.Errorf("unexpected values: expected=%v, actual=%v", expectedValues, actualValues)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue