diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 40fc558a1..6d5f589b9 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -25,6 +25,8 @@ import ( "k8s.io/helm/pkg/storage/driver" ) +const NoReleasesErr = "has no deployed releases" + // Storage represents a storage engine for a Release. type Storage struct { driver.Driver @@ -124,13 +126,13 @@ func (s *Storage) Deployed(name string) (*rspb.Release, error) { ls, err := s.DeployedAll(name) if err != nil { if strings.Contains(err.Error(), "not found") { - return nil, fmt.Errorf("%q has no deployed releases", name) + return nil, fmt.Errorf("%q %s", name, NoReleasesErr) } return nil, err } if len(ls) == 0 { - return nil, fmt.Errorf("%q has no deployed releases", name) + return nil, fmt.Errorf("%q %s", name, NoReleasesErr) } return ls[0], err @@ -150,7 +152,7 @@ func (s *Storage) DeployedAll(name string) ([]*rspb.Release, error) { return ls, nil } if strings.Contains(err.Error(), "not found") { - return nil, fmt.Errorf("%q has no deployed releases", name) + return nil, fmt.Errorf("%q %s", name, NoReleasesErr) } return nil, err } diff --git a/pkg/tiller/release_rollback.go b/pkg/tiller/release_rollback.go index 75e282fb8..1f72c3256 100644 --- a/pkg/tiller/release_rollback.go +++ b/pkg/tiller/release_rollback.go @@ -18,6 +18,8 @@ package tiller import ( "fmt" + "k8s.io/helm/pkg/storage" + "strings" ctx "golang.org/x/net/context" @@ -151,11 +153,16 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R } } + // update the current release + s.Log("superseding previous deployment %d", currentRelease.Version) + currentRelease.Info.Status.Code = release.Status_SUPERSEDED + s.recordRelease(currentRelease, true) + + // Supersede all previous deployments, see issue #2941. deployed, err := s.env.Releases.DeployedAll(currentRelease.Name) - if err != nil { + if err != nil && !strings.Contains(err.Error(), storage.NoReleasesErr) { return nil, err } - // Supersede all previous deployments, see issue #2941. for _, r := range deployed { s.Log("superseding previous deployment %d", r.Version) r.Info.Status.Code = release.Status_SUPERSEDED diff --git a/pkg/tiller/release_rollback_test.go b/pkg/tiller/release_rollback_test.go index d7909ed8b..6aa895a63 100644 --- a/pkg/tiller/release_rollback_test.go +++ b/pkg/tiller/release_rollback_test.go @@ -169,7 +169,7 @@ func TestRollbackWithReleaseVersion(t *testing.T) { // check that v2 is now in a SUPERSEDED state oldRel, err := rs.env.Releases.Get(rel.Name, 2) if err != nil { - t.Fatalf("Failed to retrieve v1: %s", err) + t.Fatalf("Failed to retrieve v2: %s", err) } if oldRel.Info.Status.Code != release.Status_SUPERSEDED { t.Errorf("Expected v2 to be in a SUPERSEDED state, got %q", oldRel.Info.Status.Code) @@ -184,6 +184,72 @@ func TestRollbackWithReleaseVersion(t *testing.T) { } } +func TestRollbackDeleted(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rs.Log = t.Logf + rs.env.Releases.Log = t.Logf + rel2 := releaseStub() + rel2.Name = "other" + rs.env.Releases.Create(rel2) + rel := releaseStub() + rs.env.Releases.Create(rel) + v2 := upgradeReleaseVersion(rel) + rs.env.Releases.Update(rel) + rs.env.Releases.Create(v2) + v3 := upgradeReleaseVersion(v2) + // retain the original release as DEPLOYED while the update should fail + v2.Info.Status.Code = release.Status_DEPLOYED + v3.Info.Status.Code = release.Status_FAILED + rs.env.Releases.Update(v2) + rs.env.Releases.Create(v3) + + req1 := &services.UninstallReleaseRequest{ + Name: rel.Name, + DisableHooks: true, + } + + _, err := rs.UninstallRelease(c, req1) + if err != nil { + t.Fatalf("Failed uninstall: %s", err) + } + + oldRel, err := rs.env.Releases.Get(rel.Name, 3) + if err != nil { + t.Fatalf("Failed to retrieve v3: %s", err) + } + if oldRel.Info.Status.Code != release.Status_DELETED { + t.Errorf("Expected v3 to be in a DELETED state, got %q", oldRel.Info.Status.Code) + } + + req2 := &services.RollbackReleaseRequest{ + Name: rel.Name, + DisableHooks: true, + Version: 2, + } + + _, err = rs.RollbackRelease(c, req2) + if err != nil { + t.Fatalf("Failed rollback: %s", err) + } + // check that v3 is now in a SUPERSEDED state + oldRel, err = rs.env.Releases.Get(rel.Name, 3) + if err != nil { + t.Fatalf("Failed to retrieve v3: %s", err) + } + if oldRel.Info.Status.Code != release.Status_SUPERSEDED { + t.Errorf("Expected v3 to be in a SUPERSEDED state, got %q", oldRel.Info.Status.Code) + } + // make sure we didn't update some other deployments. + otherRel, err := rs.env.Releases.Get(rel2.Name, 1) + if err != nil { + t.Fatalf("Failed to retrieve other v1: %s", err) + } + if otherRel.Info.Status.Code != release.Status_DEPLOYED { + t.Errorf("Expected other deployed release to stay untouched, got %q", otherRel.Info.Status.Code) + } +} + func TestRollbackReleaseNoHooks(t *testing.T) { c := helm.NewContext() rs := rsFixture()