Use --namespace value within Helmfile template (#343)
* Use --namespace value within Helmfile template (#326). * Tabs and spaces. * Tab/spaces fix. * Pacifying "go fmt". * Hard-coding namespace in test convenience function. * MR feedback: Add comment to exported identifier. * MR feedback: Put comment in correct location. * fix(ci): fix never-ending build issue by auto-approving `helmfile delete`
This commit is contained in:
parent
6453768f2e
commit
1ade353c1a
|
|
@ -83,6 +83,9 @@ releases:
|
||||||
values:
|
values:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
|
# set a templated value
|
||||||
|
- name: namespace
|
||||||
|
value: {{ .Namespace }}
|
||||||
# will attempt to decrypt it using helm-secrets plugin
|
# will attempt to decrypt it using helm-secrets plugin
|
||||||
secrets:
|
secrets:
|
||||||
- vault_secret.yaml
|
- vault_secret.yaml
|
||||||
|
|
@ -200,7 +203,7 @@ GLOBAL OPTIONS:
|
||||||
--quiet, -q Silence output. Equivalent to log-level warn
|
--quiet, -q Silence output. Equivalent to log-level warn
|
||||||
--kube-context value Set kubectl context. Uses current context by default
|
--kube-context value Set kubectl context. Uses current context by default
|
||||||
--log-level value Set log level, default info
|
--log-level value Set log level, default info
|
||||||
--namespace value, -n value Set namespace. Uses the namespace set in the context by default
|
--namespace value, -n value Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}
|
||||||
--selector value, -l value Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
|
--selector value, -l value Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
|
||||||
A release must match all labels in a group in order to be used. Multiple groups can be specified at once.
|
A release must match all labels in a group in order to be used. Multiple groups can be specified at once.
|
||||||
--selector tier=frontend,tier!=proxy --selector tier=backend. Will match all frontend, non-proxy releases AND all backend releases.
|
--selector tier=frontend,tier!=proxy --selector tier=backend. Will match all frontend, non-proxy releases AND all backend releases.
|
||||||
|
|
|
||||||
6
main.go
6
main.go
|
|
@ -91,7 +91,7 @@ func main() {
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "namespace, n",
|
Name: "namespace, n",
|
||||||
Usage: "Set namespace. Uses the namespace set in the context by default",
|
Usage: "Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}",
|
||||||
},
|
},
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
Name: "selector, l",
|
Name: "selector, l",
|
||||||
|
|
@ -638,6 +638,7 @@ func prependLineNumbers(text string) string {
|
||||||
type twoPassRenderer struct {
|
type twoPassRenderer struct {
|
||||||
reader func(string) ([]byte, error)
|
reader func(string) ([]byte, error)
|
||||||
env string
|
env string
|
||||||
|
namespace string
|
||||||
filename string
|
filename string
|
||||||
logger *zap.SugaredLogger
|
logger *zap.SugaredLogger
|
||||||
abs func(string) (string, error)
|
abs func(string) (string, error)
|
||||||
|
|
@ -673,7 +674,7 @@ func (r *twoPassRenderer) renderTemplate(content []byte) (*bytes.Buffer, error)
|
||||||
// try a first pass render. This will always succeed, but can produce a limited env
|
// try a first pass render. This will always succeed, but can produce a limited env
|
||||||
firstPassEnv := r.renderEnvironment(content)
|
firstPassEnv := r.renderEnvironment(content)
|
||||||
|
|
||||||
secondPassRenderer := tmpl.NewFileRenderer(r.reader, filepath.Dir(r.filename), firstPassEnv)
|
secondPassRenderer := tmpl.NewFileRenderer(r.reader, filepath.Dir(r.filename), firstPassEnv, r.namespace)
|
||||||
yamlBuf, err := secondPassRenderer.RenderTemplateContentToBuffer(content)
|
yamlBuf, err := secondPassRenderer.RenderTemplateContentToBuffer(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if r.logger != nil {
|
if r.logger != nil {
|
||||||
|
|
@ -704,6 +705,7 @@ func (a *app) FindAndIterateOverDesiredStates(fileOrDir string, converge func(*s
|
||||||
r := &twoPassRenderer{
|
r := &twoPassRenderer{
|
||||||
reader: a.readFile,
|
reader: a.readFile,
|
||||||
env: env,
|
env: env,
|
||||||
|
namespace: namespace,
|
||||||
filename: f,
|
filename: f,
|
||||||
logger: a.logger,
|
logger: a.logger,
|
||||||
abs: a.abs,
|
abs: a.abs,
|
||||||
|
|
|
||||||
39
main_test.go
39
main_test.go
|
|
@ -45,6 +45,7 @@ func makeRenderer(readFile func(string) ([]byte, error), env string) *twoPassRen
|
||||||
return &twoPassRenderer{
|
return &twoPassRenderer{
|
||||||
reader: readFile,
|
reader: readFile,
|
||||||
env: env,
|
env: env,
|
||||||
|
namespace: "namespace",
|
||||||
filename: "",
|
filename: "",
|
||||||
logger: logger,
|
logger: logger,
|
||||||
abs: filepath.Abs,
|
abs: filepath.Abs,
|
||||||
|
|
@ -99,7 +100,7 @@ releases:
|
||||||
|
|
||||||
func TestReadFromYaml_RenderTemplate(t *testing.T) {
|
func TestReadFromYaml_RenderTemplate(t *testing.T) {
|
||||||
|
|
||||||
defaultValuesYalm := []byte(`
|
defaultValuesYaml := []byte(`
|
||||||
releaseName: "hello"
|
releaseName: "hello"
|
||||||
conditionalReleaseTag: "yes"
|
conditionalReleaseTag: "yes"
|
||||||
`)
|
`)
|
||||||
|
|
@ -127,7 +128,7 @@ releases:
|
||||||
if !strings.HasSuffix(filename, expectedFilename) {
|
if !strings.HasSuffix(filename, expectedFilename) {
|
||||||
return nil, fmt.Errorf("unexpected filename: expected=%s, actual=%s", expectedFilename, filename)
|
return nil, fmt.Errorf("unexpected filename: expected=%s, actual=%s", expectedFilename, filename)
|
||||||
}
|
}
|
||||||
return defaultValuesYalm, nil
|
return defaultValuesYaml, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r := makeRenderer(fileReader, "staging")
|
r := makeRenderer(fileReader, "staging")
|
||||||
|
|
@ -158,7 +159,7 @@ releases:
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadFromYaml_RenderTemplateWithValuesReferenceError(t *testing.T) {
|
func TestReadFromYaml_RenderTemplateWithValuesReferenceError(t *testing.T) {
|
||||||
defaultValuesYalm := []byte("")
|
defaultValuesYaml := []byte("")
|
||||||
|
|
||||||
yamlContent := []byte(`
|
yamlContent := []byte(`
|
||||||
environments:
|
environments:
|
||||||
|
|
@ -176,7 +177,7 @@ releases:
|
||||||
|
|
||||||
// make a reader that returns a simulated context
|
// make a reader that returns a simulated context
|
||||||
fileReader := func(filename string) ([]byte, error) {
|
fileReader := func(filename string) ([]byte, error) {
|
||||||
return defaultValuesYalm, nil
|
return defaultValuesYaml, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r := makeRenderer(fileReader, "staging")
|
r := makeRenderer(fileReader, "staging")
|
||||||
|
|
@ -193,7 +194,7 @@ releases:
|
||||||
// This does not apply to .gotmpl files, which is a nice side-effect.
|
// This does not apply to .gotmpl files, which is a nice side-effect.
|
||||||
func TestReadFromYaml_RenderTemplateWithGotmpl(t *testing.T) {
|
func TestReadFromYaml_RenderTemplateWithGotmpl(t *testing.T) {
|
||||||
|
|
||||||
defaultValuesYalmGotmpl := []byte(`
|
defaultValuesYamlGotmpl := []byte(`
|
||||||
releaseName: {{ readFile "nonIgnoredFile" }}
|
releaseName: {{ readFile "nonIgnoredFile" }}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
|
@ -215,7 +216,7 @@ releases:
|
||||||
if strings.HasSuffix(filename, "nonIgnoredFile") {
|
if strings.HasSuffix(filename, "nonIgnoredFile") {
|
||||||
return []byte("release-a"), nil
|
return []byte("release-a"), nil
|
||||||
}
|
}
|
||||||
return defaultValuesYalmGotmpl, nil
|
return defaultValuesYamlGotmpl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r := makeRenderer(fileReader, "staging")
|
r := makeRenderer(fileReader, "staging")
|
||||||
|
|
@ -232,3 +233,29 @@ releases:
|
||||||
t.Fatal("release should have been declared")
|
t.Fatal("release should have been declared")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadFromYaml_RenderTemplateWithNamespace(t *testing.T) {
|
||||||
|
defaultValuesYaml := []byte(``)
|
||||||
|
yamlContent := []byte(`releases:
|
||||||
|
- name: {{ .Namespace }}-myrelease
|
||||||
|
chart: mychart
|
||||||
|
`)
|
||||||
|
|
||||||
|
// make a reader that returns a simulated context
|
||||||
|
fileReader := func(filename string) ([]byte, error) {
|
||||||
|
return defaultValuesYaml, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r := makeRenderer(fileReader, "staging")
|
||||||
|
yamlBuf, err := r.renderTemplate(yamlContent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var state state.HelmState
|
||||||
|
err = yaml.Unmarshal(yamlBuf.Bytes(), &state)
|
||||||
|
|
||||||
|
if state.Releases[0].Name != "namespace-myrelease" {
|
||||||
|
t.Errorf("release name should be namespace-myrelease")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ wait_deploy_ready httpbin-httpbin
|
||||||
retry 5 "curl --fail $(minikube service --url --namespace=${test_ns} httpbin-httpbin)/status/200"
|
retry 5 "curl --fail $(minikube service --url --namespace=${test_ns} httpbin-httpbin)/status/200"
|
||||||
[ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK"
|
[ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK"
|
||||||
info "Deleting release"
|
info "Deleting release"
|
||||||
${helmfile} -f ${dir}/happypath.yaml delete
|
${helmfile} -f ${dir}/happypath.yaml delete --auto-approve
|
||||||
${helm} status --namespace=${test_ns} httpbin &> /dev/null && fail "release should not exist anymore after a delete"
|
${helm} status --namespace=${test_ns} httpbin &> /dev/null && fail "release should not exist anymore after a delete"
|
||||||
test_pass "happypath"
|
test_pass "happypath"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,15 @@ type templateFileRenderer struct {
|
||||||
type TemplateData struct {
|
type TemplateData struct {
|
||||||
// Environment is accessible as `.Environment` from any template executed by the renderer
|
// Environment is accessible as `.Environment` from any template executed by the renderer
|
||||||
Environment environment.Environment
|
Environment environment.Environment
|
||||||
|
// Namespace is accessible as `.Namespace` from any non-values template executed by the renderer
|
||||||
|
Namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileRenderer interface {
|
type FileRenderer interface {
|
||||||
RenderTemplateFileToBuffer(file string) (*bytes.Buffer, error)
|
RenderTemplateFileToBuffer(file string) (*bytes.Buffer, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileRenderer(readFile func(filename string) ([]byte, error), basePath string, env environment.Environment) *templateFileRenderer {
|
func NewFileRenderer(readFile func(filename string) ([]byte, error), basePath string, env environment.Environment, namespace string) *templateFileRenderer {
|
||||||
return &templateFileRenderer{
|
return &templateFileRenderer{
|
||||||
ReadFile: readFile,
|
ReadFile: readFile,
|
||||||
Context: &Context{
|
Context: &Context{
|
||||||
|
|
@ -31,6 +33,7 @@ func NewFileRenderer(readFile func(filename string) ([]byte, error), basePath st
|
||||||
},
|
},
|
||||||
Data: TemplateData{
|
Data: TemplateData{
|
||||||
Environment: env,
|
Environment: env,
|
||||||
|
Namespace: namespace,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ type renderer struct {
|
||||||
func NewRenderer(readFile func(filename string) ([]byte, error), basePath string, env environment.Environment) *renderer {
|
func NewRenderer(readFile func(filename string) ([]byte, error), basePath string, env environment.Environment) *renderer {
|
||||||
return &renderer{
|
return &renderer{
|
||||||
readFile: readFile,
|
readFile: readFile,
|
||||||
tmplFileRenderer: tmpl.NewFileRenderer(readFile, basePath, env),
|
tmplFileRenderer: tmpl.NewFileRenderer(readFile, basePath, env, ""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue