parent
43a54486a1
commit
37ea442515
109
app_test.go
109
app_test.go
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/roboll/helmfile/helmexec"
|
"github.com/roboll/helmfile/helmexec"
|
||||||
"github.com/roboll/helmfile/state"
|
"github.com/roboll/helmfile/state"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -302,3 +303,111 @@ releases:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See https://github.com/roboll/helmfile/issues/312
|
||||||
|
func TestFindAndIterateOverDesiredStates_ReverseOrder(t *testing.T) {
|
||||||
|
absPaths := map[string]string{
|
||||||
|
".": "/path/to",
|
||||||
|
"/path/to/helmfile.d": "/path/to/helmfile.d",
|
||||||
|
}
|
||||||
|
dirs := map[string]bool{
|
||||||
|
"helmfile.d": true,
|
||||||
|
}
|
||||||
|
files := map[string]string{
|
||||||
|
"helmfile.yaml": `
|
||||||
|
helmfiles:
|
||||||
|
- helmfile.d/a*.yaml
|
||||||
|
- helmfile.d/b*.yaml
|
||||||
|
`,
|
||||||
|
"/path/to/helmfile.d/a1.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: zipkin
|
||||||
|
chart: stable/zipkin
|
||||||
|
`,
|
||||||
|
"/path/to/helmfile.d/a2.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: prometheus
|
||||||
|
chart: stable/prometheus
|
||||||
|
- name: elasticsearch
|
||||||
|
chart: stable/elasticsearch
|
||||||
|
`,
|
||||||
|
"/path/to/helmfile.d/b.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: grafana
|
||||||
|
chart: stable/grafana
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
globMatches := map[string][]string{
|
||||||
|
"/path/to/helmfile.d/a*.yaml": []string{"/path/to/helmfile.d/a1.yaml", "/path/to/helmfile.d/a2.yaml"},
|
||||||
|
"/path/to/helmfile.d/b*.yaml": []string{"/path/to/helmfile.d/b.yaml"},
|
||||||
|
}
|
||||||
|
fileExistsAt := func(path string) bool {
|
||||||
|
_, ok := files[path]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
directoryExistsAt := func(path string) bool {
|
||||||
|
_, ok := dirs[path]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
readFile := func(filename string) ([]byte, error) {
|
||||||
|
str, ok := files[filename]
|
||||||
|
if !ok {
|
||||||
|
return []byte(nil), fmt.Errorf("no file found: %s", filename)
|
||||||
|
}
|
||||||
|
return []byte(str), nil
|
||||||
|
}
|
||||||
|
glob := func(pattern string) ([]string, error) {
|
||||||
|
matches, ok := globMatches[pattern]
|
||||||
|
if !ok {
|
||||||
|
return []string(nil), fmt.Errorf("no file matched: %s", pattern)
|
||||||
|
}
|
||||||
|
return matches, nil
|
||||||
|
}
|
||||||
|
abs := func(path string) (string, error) {
|
||||||
|
a, ok := absPaths[path]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("abs: unexpected path: %s", path)
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []string{"grafana", "elasticsearch", "prometheus", "zipkin"}
|
||||||
|
|
||||||
|
testcases := []struct {
|
||||||
|
reverse bool
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{reverse: false, expected: []string{"zipkin", "prometheus", "elasticsearch", "grafana"}},
|
||||||
|
{reverse: true, expected: []string{"grafana", "elasticsearch", "prometheus", "zipkin"}},
|
||||||
|
}
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
actual := []string{}
|
||||||
|
|
||||||
|
collectReleases := func(st *state.HelmState, helm helmexec.Interface) []error {
|
||||||
|
for _, r := range st.Releases {
|
||||||
|
actual = append(actual, r.Name)
|
||||||
|
}
|
||||||
|
return []error{}
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &app{
|
||||||
|
readFile: readFile,
|
||||||
|
glob: glob,
|
||||||
|
abs: abs,
|
||||||
|
fileExistsAt: fileExistsAt,
|
||||||
|
directoryExistsAt: directoryExistsAt,
|
||||||
|
kubeContext: "default",
|
||||||
|
logger: helmexec.NewLogger(os.Stderr, "debug"),
|
||||||
|
reverse: testcase.reverse,
|
||||||
|
}
|
||||||
|
err := app.FindAndIterateOverDesiredStates(
|
||||||
|
"helmfile.yaml", collectReleases, "", []string{}, "default",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(testcase.expected, actual) {
|
||||||
|
t.Errorf("releases did not match: expected=%v actual=%v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
54
main.go
54
main.go
|
|
@ -418,7 +418,7 @@ Do you really want to apply?
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface) []error {
|
return findAndIterateOverDesiredStatesUsingFlagsWithReverse(c, true, func(state *state.HelmState, helm helmexec.Interface) []error {
|
||||||
purge := c.Bool("purge")
|
purge := c.Bool("purge")
|
||||||
|
|
||||||
args := args.GetArgs(c.String("args"), state)
|
args := args.GetArgs(c.String("args"), state)
|
||||||
|
|
@ -542,9 +542,14 @@ type app struct {
|
||||||
abs func(string) (string, error)
|
abs func(string) (string, error)
|
||||||
fileExistsAt func(string) bool
|
fileExistsAt func(string) bool
|
||||||
directoryExistsAt func(string) bool
|
directoryExistsAt func(string) bool
|
||||||
|
reverse bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAndIterateOverDesiredStatesUsingFlags(c *cli.Context, converge func(*state.HelmState, helmexec.Interface) []error) error {
|
func findAndIterateOverDesiredStatesUsingFlags(c *cli.Context, converge func(*state.HelmState, helmexec.Interface) []error) error {
|
||||||
|
return findAndIterateOverDesiredStatesUsingFlagsWithReverse(c, false, converge)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findAndIterateOverDesiredStatesUsingFlagsWithReverse(c *cli.Context, reverse bool, converge func(*state.HelmState, helmexec.Interface) []error) error {
|
||||||
fileOrDir := c.GlobalString("file")
|
fileOrDir := c.GlobalString("file")
|
||||||
kubeContext := c.GlobalString("kube-context")
|
kubeContext := c.GlobalString("kube-context")
|
||||||
namespace := c.GlobalString("namespace")
|
namespace := c.GlobalString("namespace")
|
||||||
|
|
@ -564,6 +569,7 @@ func findAndIterateOverDesiredStatesUsingFlags(c *cli.Context, converge func(*st
|
||||||
directoryExistsAt: directoryExistsAt,
|
directoryExistsAt: directoryExistsAt,
|
||||||
kubeContext: kubeContext,
|
kubeContext: kubeContext,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
reverse: reverse,
|
||||||
}
|
}
|
||||||
if err := app.FindAndIterateOverDesiredStates(fileOrDir, converge, namespace, selectors, env); err != nil {
|
if err := app.FindAndIterateOverDesiredStates(fileOrDir, converge, namespace, selectors, env); err != nil {
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
|
|
@ -703,25 +709,16 @@ func (a *app) FindAndIterateOverDesiredStates(fileOrDir string, converge func(*s
|
||||||
|
|
||||||
if len(st.Helmfiles) > 0 {
|
if len(st.Helmfiles) > 0 {
|
||||||
noMatchInSubHelmfiles := true
|
noMatchInSubHelmfiles := true
|
||||||
for _, globPattern := range st.Helmfiles {
|
for _, m := range st.Helmfiles {
|
||||||
helmfileRelativePattern := st.JoinBase(globPattern)
|
if err := a.FindAndIterateOverDesiredStates(m, converge, namespace, selectors, env); err != nil {
|
||||||
matches, err := a.glob(helmfileRelativePattern)
|
switch err.(type) {
|
||||||
if err != nil {
|
case *noMatchingHelmfileError:
|
||||||
return fmt.Errorf("failed processing %s: %v", globPattern, err)
|
|
||||||
}
|
|
||||||
sort.Strings(matches)
|
|
||||||
|
|
||||||
for _, m := range matches {
|
default:
|
||||||
if err := a.FindAndIterateOverDesiredStates(m, converge, namespace, selectors, env); err != nil {
|
return fmt.Errorf("failed processing %s: %v", m, err)
|
||||||
switch err.(type) {
|
|
||||||
case *noMatchingHelmfileError:
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("failed processing %s: %v", globPattern, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
noMatchInSubHelmfiles = false
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
noMatchInSubHelmfiles = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
noMatchInHelmfiles = noMatchInHelmfiles && noMatchInSubHelmfiles
|
noMatchInHelmfiles = noMatchInHelmfiles && noMatchInSubHelmfiles
|
||||||
|
|
@ -807,6 +804,27 @@ func (a *app) loadDesiredStateFromYaml(yaml []byte, file string, namespace strin
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
helmfiles := []string{}
|
||||||
|
for _, globPattern := range st.Helmfiles {
|
||||||
|
helmfileRelativePattern := st.JoinBase(globPattern)
|
||||||
|
matches, err := a.glob(helmfileRelativePattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("failed processing %s: %v", globPattern, err)
|
||||||
|
}
|
||||||
|
sort.Strings(matches)
|
||||||
|
|
||||||
|
helmfiles = append(helmfiles, matches...)
|
||||||
|
}
|
||||||
|
st.Helmfiles = helmfiles
|
||||||
|
|
||||||
|
if a.reverse {
|
||||||
|
rev := func(i, j int) bool {
|
||||||
|
return j < i
|
||||||
|
}
|
||||||
|
sort.Slice(st.Releases, rev)
|
||||||
|
sort.Slice(st.Helmfiles, rev)
|
||||||
|
}
|
||||||
|
|
||||||
if a.kubeContext != "" {
|
if a.kubeContext != "" {
|
||||||
if st.Context != "" {
|
if st.Context != "" {
|
||||||
log.Printf("err: Cannot use option --kube-context and set attribute context.")
|
log.Printf("err: Cannot use option --kube-context and set attribute context.")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue