Merge pull request #231 from mumoshu/partly-allow-duplicate-release-name
fix: helmfile should fail on duplicate release name after filtered by labels
This commit is contained in:
commit
b6d2ee9d43
33
main.go
33
main.go
|
|
@ -397,7 +397,18 @@ func eachDesiredStateDo(c *cli.Context, converge func(*state.HelmState, helmexec
|
||||||
}
|
}
|
||||||
allSelectorNotMatched := true
|
allSelectorNotMatched := true
|
||||||
for _, f := range desiredStateFiles {
|
for _, f := range desiredStateFiles {
|
||||||
state, helm, noReleases, err := loadDesiredStateFromFile(c, f)
|
yamlBuf, err := state.RenderTemplateFileToBuffer(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
state, helm, noReleases, err := loadDesiredStateFromFile(
|
||||||
|
yamlBuf.Bytes(),
|
||||||
|
f,
|
||||||
|
c.GlobalString("kube-context"),
|
||||||
|
c.GlobalString("namespace"),
|
||||||
|
c.GlobalStringSlice("selector"),
|
||||||
|
c.App.Metadata["logger"].(*zap.SugaredLogger),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -474,14 +485,8 @@ func directoryExistsAt(path string) bool {
|
||||||
return err == nil && fileInfo.Mode().IsDir()
|
return err == nil && fileInfo.Mode().IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDesiredStateFromFile(c *cli.Context, file string) (*state.HelmState, helmexec.Interface, bool, error) {
|
func loadDesiredStateFromFile(yaml []byte, file string, kubeContext, namespace string, labels []string, logger *zap.SugaredLogger) (*state.HelmState, helmexec.Interface, bool, error) {
|
||||||
kubeContext := c.GlobalString("kube-context")
|
st, err := state.CreateFromYaml(yaml, file, logger)
|
||||||
namespace := c.GlobalString("namespace")
|
|
||||||
labels := c.GlobalStringSlice("selector")
|
|
||||||
|
|
||||||
logger := c.App.Metadata["logger"].(*zap.SugaredLogger)
|
|
||||||
|
|
||||||
st, err := state.CreateFromFile(file, logger)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, false, fmt.Errorf("failed to read %s: %v", file, err)
|
return nil, nil, false, fmt.Errorf("failed to read %s: %v", file, err)
|
||||||
}
|
}
|
||||||
|
|
@ -510,6 +515,16 @@ func loadDesiredStateFromFile(c *cli.Context, file string) (*state.HelmState, he
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releaseNameCounts := map[string]int{}
|
||||||
|
for _, r := range st.Releases {
|
||||||
|
releaseNameCounts[r.Name] += 1
|
||||||
|
}
|
||||||
|
for name, c := range releaseNameCounts {
|
||||||
|
if c > 1 {
|
||||||
|
return nil, nil, false, fmt.Errorf("duplicate release \"%s\" found: there were %d releases named \"%s\" matching specified selector", name, c, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// See https://github.com/roboll/helmfile/issues/193
|
||||||
|
func TestReadFromYaml_DuplicateReleaseName(t *testing.T) {
|
||||||
|
yamlFile := "example/path/to/yaml/file"
|
||||||
|
yamlContent := []byte(`releases:
|
||||||
|
- name: myrelease1
|
||||||
|
chart: mychart1
|
||||||
|
labels:
|
||||||
|
stage: pre
|
||||||
|
foo: bar
|
||||||
|
- name: myrelease1
|
||||||
|
chart: mychart2
|
||||||
|
labels:
|
||||||
|
stage: post
|
||||||
|
`)
|
||||||
|
_, _, _, err := loadDesiredStateFromFile(yamlContent, yamlFile, "default", "default", []string{}, logger)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error expected but not happened")
|
||||||
|
}
|
||||||
|
if err.Error() != "duplicate release \"myrelease1\" found: there were 2 releases named \"myrelease1\" matching specified selector" {
|
||||||
|
t.Errorf("unexpected error happened: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,17 +84,17 @@ type SetValue struct {
|
||||||
File string `yaml:"file"`
|
File string `yaml:"file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFromFile loads the helmfile from disk and processes the template
|
// CreateFromTemplateFile loads the helmfile from disk and processes the template
|
||||||
func CreateFromFile(file string, logger *zap.SugaredLogger) (*HelmState, error) {
|
func CreateFromTemplateFile(file string, logger *zap.SugaredLogger) (*HelmState, error) {
|
||||||
yamlBuf, err := renderTemplateFileToBuffer(file)
|
yamlBuf, err := RenderTemplateFileToBuffer(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return readFromYaml(yamlBuf.Bytes(), file, logger)
|
return CreateFromYaml(yamlBuf.Bytes(), file, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFromYaml(content []byte, file string, logger *zap.SugaredLogger) (*HelmState, error) {
|
func CreateFromYaml(content []byte, file string, logger *zap.SugaredLogger) (*HelmState, error) {
|
||||||
var state HelmState
|
var state HelmState
|
||||||
|
|
||||||
state.BaseChartPath, _ = filepath.Abs(filepath.Dir(file))
|
state.BaseChartPath, _ = filepath.Abs(filepath.Dir(file))
|
||||||
|
|
@ -111,16 +111,6 @@ func readFromYaml(content []byte, file string, logger *zap.SugaredLogger) (*Helm
|
||||||
state.DeprecatedReleases = []ReleaseSpec{}
|
state.DeprecatedReleases = []ReleaseSpec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseNameCounts := map[string]int{}
|
|
||||||
for _, r := range state.Releases {
|
|
||||||
releaseNameCounts[r.Name] += 1
|
|
||||||
}
|
|
||||||
for name, c := range releaseNameCounts {
|
|
||||||
if c > 1 {
|
|
||||||
return nil, fmt.Errorf("invalid helmfile: duplicate release name found: there were %d releases named \"%s\"", c, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.logger = logger
|
state.logger = logger
|
||||||
|
|
||||||
return &state, nil
|
return &state, nil
|
||||||
|
|
@ -144,7 +134,7 @@ func getRequiredEnv(name string) (string, error) {
|
||||||
return "", fmt.Errorf("required env var `%s` is not set", name)
|
return "", fmt.Errorf("required env var `%s` is not set", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderTemplateFileToBuffer(file string) (*bytes.Buffer, error) {
|
func RenderTemplateFileToBuffer(file string) (*bytes.Buffer, error) {
|
||||||
content, err := ioutil.ReadFile(file)
|
content, err := ioutil.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -712,7 +702,7 @@ func (state *HelmState) namespaceAndValuesFlags(helm helmexec.Interface, basePat
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
yamlBuf, err := renderTemplateFileToBuffer(path)
|
yamlBuf, err := RenderTemplateFileToBuffer(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ func TestReadFromYaml(t *testing.T) {
|
||||||
namespace: mynamespace
|
namespace: mynamespace
|
||||||
chart: mychart
|
chart: mychart
|
||||||
`)
|
`)
|
||||||
state, err := readFromYaml(yamlContent, yamlFile, logger)
|
state, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unxpected error: %v", err)
|
t.Errorf("unxpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +42,7 @@ func TestReadFromYaml_StrictUnmarshalling(t *testing.T) {
|
||||||
namespace: mynamespace
|
namespace: mynamespace
|
||||||
releases: mychart
|
releases: mychart
|
||||||
`)
|
`)
|
||||||
_, err := readFromYaml(yamlContent, yamlFile, logger)
|
_, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected an error for wrong key 'releases' which is not in struct")
|
t.Error("expected an error for wrong key 'releases' which is not in struct")
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ func TestReadFromYaml_DeprecatedReleaseReferences(t *testing.T) {
|
||||||
- name: myrelease
|
- name: myrelease
|
||||||
chart: mychart
|
chart: mychart
|
||||||
`)
|
`)
|
||||||
state, err := readFromYaml(yamlContent, yamlFile, logger)
|
state, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unxpected error: %v", err)
|
t.Errorf("unxpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ releases:
|
||||||
- name: myrelease2
|
- name: myrelease2
|
||||||
chart: mychart2
|
chart: mychart2
|
||||||
`)
|
`)
|
||||||
_, err := readFromYaml(yamlContent, yamlFile, logger)
|
_, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error")
|
t.Error("expected error")
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +112,7 @@ func TestReadFromYaml_FilterReleasesOnLabels(t *testing.T) {
|
||||||
{LabelFilter{positiveLabels: [][]string{[]string{"tier", "frontend"}}, negativeLabels: [][]string{[]string{"foo", "bar"}}},
|
{LabelFilter{positiveLabels: [][]string{[]string{"tier", "frontend"}}, negativeLabels: [][]string{[]string{"foo", "bar"}}},
|
||||||
[]bool{false, true, false}},
|
[]bool{false, true, false}},
|
||||||
}
|
}
|
||||||
state, err := readFromYaml(yamlContent, yamlFile, logger)
|
state, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +151,7 @@ func TestReadFromYaml_FilterNegatives(t *testing.T) {
|
||||||
{LabelFilter{negativeLabels: [][]string{[]string{"stage", "pre"}, []string{"stage", "post"}}},
|
{LabelFilter{negativeLabels: [][]string{[]string{"stage", "pre"}, []string{"stage", "post"}}},
|
||||||
[]bool{false, false, true}},
|
[]bool{false, false, true}},
|
||||||
}
|
}
|
||||||
state, err := readFromYaml(yamlContent, yamlFile, logger)
|
state, err := CreateFromYaml(yamlContent, yamlFile, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -164,29 +164,6 @@ func TestReadFromYaml_FilterNegatives(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/roboll/helmfile/issues/193
|
|
||||||
func TestReadFromYaml_DuplicateReleaseName(t *testing.T) {
|
|
||||||
yamlFile := "example/path/to/yaml/file"
|
|
||||||
yamlContent := []byte(`releases:
|
|
||||||
- name: myrelease1
|
|
||||||
chart: mychart1
|
|
||||||
labels:
|
|
||||||
stage: pre
|
|
||||||
foo: bar
|
|
||||||
- name: myrelease1
|
|
||||||
chart: mychart2
|
|
||||||
labels:
|
|
||||||
stage: post
|
|
||||||
`)
|
|
||||||
_, err := readFromYaml(yamlContent, yamlFile, logger)
|
|
||||||
if err == nil {
|
|
||||||
t.Error("error expected but not happened")
|
|
||||||
}
|
|
||||||
if err.Error() != "invalid helmfile: duplicate release name found: there were 2 releases named \"myrelease1\"" {
|
|
||||||
t.Errorf("unexpected error happened: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLabelParsing(t *testing.T) {
|
func TestLabelParsing(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
labelString string
|
labelString string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue