fix: `helmfile destroy` should delete releases in the specified tiller namespace (#536)
Actually, 4 helm commands including "list", "diff", "status" and "delete" were not taking tiller-rerelated flags into account in helmfile. This fixes all these commands. Fixes #534
This commit is contained in:
parent
f522ba320b
commit
0e00cdf2a5
|
|
@ -103,16 +103,16 @@ func (helm *execer) SyncRelease(name, chart string, flags ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (helm *execer) ReleaseStatus(name string) error {
|
||||
func (helm *execer) ReleaseStatus(name string, flags ...string) error {
|
||||
helm.logger.Infof("Getting status %v", name)
|
||||
out, err := helm.exec(append([]string{"status", name})...)
|
||||
out, err := helm.exec(append([]string{"status", name}, flags...)...)
|
||||
helm.write(out)
|
||||
return err
|
||||
}
|
||||
|
||||
func (helm *execer) List(filter string) (string, error) {
|
||||
func (helm *execer) List(filter string, flags ...string) (string, error) {
|
||||
helm.logger.Infof("Listing releases matching %v", filter)
|
||||
out, err := helm.exec(append([]string{"list", filter})...)
|
||||
out, err := helm.exec(append([]string{"list", filter}, flags...)...)
|
||||
helm.write(out)
|
||||
return string(out), err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ type Interface interface {
|
|||
TemplateRelease(chart string, flags ...string) error
|
||||
Fetch(chart string, flags ...string) error
|
||||
Lint(chart string, flags ...string) error
|
||||
ReleaseStatus(name string) error
|
||||
ReleaseStatus(name string, flags ...string) error
|
||||
DeleteRelease(name string, flags ...string) error
|
||||
TestRelease(name string, flags ...string) error
|
||||
List(filter string) (string, error)
|
||||
List(filter string, flags ...string) (string, error)
|
||||
DecryptSecret(name string) (string, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,8 +277,8 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu
|
|||
return res, errs
|
||||
}
|
||||
|
||||
func isReleaseInstalled(helm helmexec.Interface, release ReleaseSpec) (bool, error) {
|
||||
out, err := helm.List("^" + release.Name + "$")
|
||||
func (st *HelmState) isReleaseInstalled(helm helmexec.Interface, release ReleaseSpec) (bool, error) {
|
||||
out, err := helm.List("^"+release.Name+"$", st.tillerFlags(&release)...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if out != "" {
|
||||
|
|
@ -292,7 +292,7 @@ func (st *HelmState) DetectReleasesToBeDeleted(helm helmexec.Interface) ([]*Rele
|
|||
for i, _ := range st.Releases {
|
||||
release := st.Releases[i]
|
||||
if !release.Desired() {
|
||||
installed, err := isReleaseInstalled(helm, release)
|
||||
installed, err := st.isReleaseInstalled(helm, release)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if installed {
|
||||
|
|
@ -330,7 +330,7 @@ func (st *HelmState) SyncReleases(helm helmexec.Interface, additionalValues []st
|
|||
chart := normalizeChart(st.basePath, release.Chart)
|
||||
var relErr *ReleaseError
|
||||
if !release.Desired() {
|
||||
installed, err := isReleaseInstalled(helm, *release)
|
||||
installed, err := st.isReleaseInstalled(helm, *release)
|
||||
if err != nil {
|
||||
relErr = &ReleaseError{release, err}
|
||||
} else if installed {
|
||||
|
|
@ -735,7 +735,11 @@ func (st *HelmState) ReleaseStatuses(helm helmexec.Interface, workerLimit int) [
|
|||
if !release.Desired() {
|
||||
return nil
|
||||
}
|
||||
return helm.ReleaseStatus(release.Name)
|
||||
|
||||
flags := []string{}
|
||||
flags = st.appendTillerFlags(flags, &release)
|
||||
|
||||
return helm.ReleaseStatus(release.Name, flags...)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -750,7 +754,9 @@ func (st *HelmState) DeleteReleases(helm helmexec.Interface, purge bool) []error
|
|||
if purge {
|
||||
flags = append(flags, "--purge")
|
||||
}
|
||||
installed, err := isReleaseInstalled(helm, release)
|
||||
flags = st.appendTillerFlags(flags, &release)
|
||||
|
||||
installed, err := st.isReleaseInstalled(helm, release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -773,6 +779,8 @@ func (st *HelmState) TestReleases(helm helmexec.Interface, cleanup bool, timeout
|
|||
flags = append(flags, "--cleanup")
|
||||
}
|
||||
flags = append(flags, "--timeout", strconv.Itoa(timeout))
|
||||
flags = st.appendTillerFlags(flags, &release)
|
||||
|
||||
return helm.TestRelease(release.Name, flags...)
|
||||
})
|
||||
}
|
||||
|
|
@ -976,6 +984,15 @@ func findChartDirectory(topLevelDir string) (string, error) {
|
|||
}
|
||||
|
||||
func (st *HelmState) appendTillerFlags(flags []string, release *ReleaseSpec) []string {
|
||||
adds := st.tillerFlags(release)
|
||||
for _, a := range adds {
|
||||
flags = append(flags, a)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func (st *HelmState) tillerFlags(release *ReleaseSpec) []string {
|
||||
flags := []string{}
|
||||
if release.TillerNamespace != "" {
|
||||
flags = append(flags, "--tiller-namespace", release.TillerNamespace)
|
||||
} else if st.HelmDefaults.TillerNamespace != "" {
|
||||
|
|
|
|||
|
|
@ -631,12 +631,18 @@ func Test_normalizeChart(t *testing.T) {
|
|||
|
||||
// mocking helmexec.Interface
|
||||
|
||||
type listKey struct {
|
||||
filter string
|
||||
flags string
|
||||
}
|
||||
|
||||
type mockHelmExec struct {
|
||||
charts []string
|
||||
repo []string
|
||||
releases []mockRelease
|
||||
deleted []mockRelease
|
||||
lists map[string]string
|
||||
lists map[listKey]string
|
||||
diffed []mockRelease
|
||||
}
|
||||
|
||||
type mockRelease struct {
|
||||
|
|
@ -682,21 +688,22 @@ func (helm *mockHelmExec) SyncRelease(name, chart string, flags ...string) error
|
|||
return nil
|
||||
}
|
||||
func (helm *mockHelmExec) DiffRelease(name, chart string, flags ...string) error {
|
||||
helm.diffed = append(helm.diffed, mockRelease{name: name, flags: flags})
|
||||
return nil
|
||||
}
|
||||
func (helm *mockHelmExec) ReleaseStatus(release string) error {
|
||||
func (helm *mockHelmExec) ReleaseStatus(release string, flags ...string) error {
|
||||
if strings.Contains(release, "error") {
|
||||
return errors.New("error")
|
||||
}
|
||||
helm.releases = append(helm.releases, mockRelease{name: release, flags: []string{}})
|
||||
helm.releases = append(helm.releases, mockRelease{name: release, flags: flags})
|
||||
return nil
|
||||
}
|
||||
func (helm *mockHelmExec) DeleteRelease(name string, flags ...string) error {
|
||||
helm.deleted = append(helm.deleted, mockRelease{name: name, flags: flags})
|
||||
return nil
|
||||
}
|
||||
func (helm *mockHelmExec) List(filter string) (string, error) {
|
||||
return helm.lists[filter], nil
|
||||
func (helm *mockHelmExec) List(filter string, flags ...string) (string, error) {
|
||||
return helm.lists[listKey{filter: filter, flags: strings.Join(flags, "")}], nil
|
||||
}
|
||||
func (helm *mockHelmExec) DecryptSecret(name string) (string, error) {
|
||||
return "", nil
|
||||
|
|
@ -807,6 +814,18 @@ func TestHelmState_SyncReleases(t *testing.T) {
|
|||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{}}},
|
||||
},
|
||||
{
|
||||
name: "with tiller args",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
TillerNamespace: "tillerns",
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{"--tiller-namespace", "tillerns"}}},
|
||||
},
|
||||
{
|
||||
name: "escaped values",
|
||||
releases: []ReleaseSpec{
|
||||
|
|
@ -887,6 +906,120 @@ func TestHelmState_SyncReleases(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestHelmState_DiffReleases(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
releases []ReleaseSpec
|
||||
helm *mockHelmExec
|
||||
wantReleases []mockRelease
|
||||
}{
|
||||
{
|
||||
name: "normal release",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{}}},
|
||||
},
|
||||
{
|
||||
name: "with tiller args",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
TillerNamespace: "tillerns",
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{"--tiller-namespace", "tillerns"}}},
|
||||
},
|
||||
{
|
||||
name: "escaped values",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "someList",
|
||||
Value: "a,b,c",
|
||||
},
|
||||
{
|
||||
Name: "json",
|
||||
Value: "{\"name\": \"john\"}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{"--set", "someList=a\\,b\\,c", "--set", "json=\\{\"name\": \"john\"\\}"}}},
|
||||
},
|
||||
{
|
||||
name: "set single value from file",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "foo",
|
||||
Value: "FOO",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
File: "path/to/bar",
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
Value: "BAZ",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{"--set", "foo=FOO", "--set-file", "bar=path/to/bar", "--set", "baz=BAZ"}}},
|
||||
},
|
||||
{
|
||||
name: "set single array value in an array",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseName",
|
||||
Chart: "foo",
|
||||
SetValues: []SetValue{
|
||||
{
|
||||
Name: "foo.bar[0]",
|
||||
Values: []string{
|
||||
"A",
|
||||
"B",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
wantReleases: []mockRelease{{"releaseName", []string{"--set", "foo.bar[0]={A,B}"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
state := &HelmState{
|
||||
Releases: tt.releases,
|
||||
logger: logger,
|
||||
}
|
||||
_, err := state.DiffReleases(tt.helm, []string{}, 1, false, false, false)
|
||||
if err != nil {
|
||||
fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.helm.diffed, tt.wantReleases) {
|
||||
t.Errorf("HelmState.DiffReleases() for [%s] = %v, want %v", tt.name, tt.helm.releases, tt.wantReleases)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelmState_SyncReleasesCleanup(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -1156,6 +1289,17 @@ func TestHelmState_ReleaseStatuses(t *testing.T) {
|
|||
helm: &mockHelmExec{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "with tiller args",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseA",
|
||||
TillerNamespace: "tillerns",
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
want: []mockRelease{{"releaseA", []string{"--tiller-namespace", "tillerns"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
i := func(t *testing.T) {
|
||||
|
|
@ -1196,6 +1340,7 @@ func TestHelmState_TestReleasesNoCleanUp(t *testing.T) {
|
|||
helm *mockHelmExec
|
||||
want []mockRelease
|
||||
wantErr bool
|
||||
tillerNamespace string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
|
|
@ -1228,6 +1373,17 @@ func TestHelmState_TestReleasesNoCleanUp(t *testing.T) {
|
|||
helm: &mockHelmExec{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with tiller args",
|
||||
releases: []ReleaseSpec{
|
||||
{
|
||||
Name: "releaseA",
|
||||
TillerNamespace: "tillerns",
|
||||
},
|
||||
},
|
||||
helm: &mockHelmExec{},
|
||||
want: []mockRelease{{"releaseA", []string{"--timeout", "1", "--tiller-namespace", "tillerns"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
i := func(t *testing.T) {
|
||||
|
|
@ -1303,6 +1459,8 @@ func TestHelmState_Delete(t *testing.T) {
|
|||
desired *bool
|
||||
installed bool
|
||||
purge bool
|
||||
flags string
|
||||
tillerNamespace string
|
||||
}{
|
||||
{
|
||||
name: "desired and installed (purge=false)",
|
||||
|
|
@ -1376,12 +1534,23 @@ func TestHelmState_Delete(t *testing.T) {
|
|||
purge: true,
|
||||
deleted: []mockRelease{},
|
||||
},
|
||||
{
|
||||
name: "with tiller args",
|
||||
wantErr: false,
|
||||
desired: nil,
|
||||
installed: true,
|
||||
purge: true,
|
||||
tillerNamespace: "tillerns",
|
||||
flags: "--tiller-namespacetillerns",
|
||||
deleted: []mockRelease{{"releaseA", []string{"--purge", "--tiller-namespace", "tillerns"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
i := func(t *testing.T) {
|
||||
release := ReleaseSpec{
|
||||
Name: "releaseA",
|
||||
Installed: tt.desired,
|
||||
TillerNamespace: tt.tillerNamespace,
|
||||
}
|
||||
releases := []ReleaseSpec{
|
||||
release,
|
||||
|
|
@ -1391,15 +1560,15 @@ func TestHelmState_Delete(t *testing.T) {
|
|||
logger: logger,
|
||||
}
|
||||
helm := &mockHelmExec{
|
||||
lists: map[string]string{},
|
||||
lists: map[listKey]string{},
|
||||
deleted: []mockRelease{},
|
||||
}
|
||||
if tt.installed {
|
||||
helm.lists["^releaseA$"] = "releaseA"
|
||||
helm.lists[listKey{filter: "^releaseA$", flags: tt.flags}] = "releaseA"
|
||||
}
|
||||
errs := state.DeleteReleases(helm, tt.purge)
|
||||
if (errs != nil) != tt.wantErr {
|
||||
t.Errorf("DeleteREleases() for %s error = %v, wantErr %v", tt.name, errs, tt.wantErr)
|
||||
t.Errorf("DeleteReleases() for %s error = %v, wantErr %v", tt.name, errs, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(tt.deleted, helm.deleted) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue