fix upgrade of broken install

If the first `upgrade --install` results in a state FAILED, you can not
run the same command `upgrade --install` again without a failure.
This happens becuase we are search only for releases with the status DEPLOYED.
This change will if the search for DEPLOYED fails, then try to search for a release
with the state FAILED, and if found upgrade that.

This fixes issue #3353
pull/3437/head
Soren Mathiasen 8 years ago
parent 1f87bf031a
commit a406094436
No known key found for this signature in database
GPG Key ID: E298D274FA10C0E1

@ -18,7 +18,6 @@ package storage // import "k8s.io/helm/pkg/storage"
import (
"fmt"
"strings"
rspb "k8s.io/helm/pkg/proto/hapi/release"
relutil "k8s.io/helm/pkg/releaseutil"
@ -128,13 +127,30 @@ func (s *Storage) Deployed(name string) (*rspb.Release, error) {
"OWNER": "TILLER",
"STATUS": "DEPLOYED",
})
if err == nil {
return ls[0], nil
}
if strings.Contains(err.Error(), "not found") {
if err != nil || len(ls) == 0 {
return nil, fmt.Errorf("%q has no deployed releases", name)
}
return nil, err
return ls[0], nil
}
// Failed returns the failed release with the provided release name, or
// returns ErrReleaseNotFound if not found.
func (s *Storage) Failed(name string) (*rspb.Release, error) {
s.Log("getting failed release from %q history", name)
ls, err := s.Driver.Query(map[string]string{
"NAME": name,
"OWNER": "TILLER",
"STATUS": "FAILED",
})
if err != nil || len(ls) == 0 {
return nil, fmt.Errorf("%q has no failed releases", name)
}
return ls[0], nil
}
// History returns the revision history for the release with the provided name, or

@ -325,6 +325,31 @@ func TestStorageLast(t *testing.T) {
}
}
func TestStorageFailed(t *testing.T) {
storage := Init(driver.NewMemory())
const name = "angry-bird"
// Set up storage with test releases.
setup := func() {
// release records
rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.Status_FAILED}.ToRelease()
// create the release records in the storage
assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
}
setup()
h, err := storage.Failed(name)
if err != nil {
t.Fatalf("Failed to query for failed release (%v): %v\n", name, err)
}
if h.Info.Status.Code != rspb.Status_FAILED {
t.Errorf("Expected a failed status, got %s", h.Info.Status.Code)
}
}
type ReleaseTestData struct {
Name string
Version int32

@ -309,6 +309,20 @@ func newHookFailingKubeClient() *hookFailingKubeClient {
}
}
func newInstallFailingKubClient() *installFailingKubeClient {
return &installFailingKubeClient{
PrintingKubeClient: environment.PrintingKubeClient{Out: os.Stdout},
}
}
type installFailingKubeClient struct {
environment.PrintingKubeClient
}
func (h *installFailingKubeClient) Create(namespace string, reader io.Reader, timeout int64, shouldWait bool) error {
return errors.New("Failed create")
}
type hookFailingKubeClient struct {
environment.PrintingKubeClient
}

@ -72,9 +72,12 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
// finds the deployed release with the given name
currentRelease, err := s.env.Releases.Deployed(req.Name)
if err != nil {
return nil, nil, err
// try to find a failed release we can upgrade
currentRelease, err = s.env.Releases.Failed(req.Name)
if err != nil {
return nil, nil, err
}
}
// If new values were not supplied in the upgrade, re-use the existing values.
if err := s.reuseValues(req, currentRelease); err != nil {
return nil, nil, err

@ -239,6 +239,49 @@ func TestUpdateReleaseFailure(t *testing.T) {
}
}
func TestUpdateInstalledFailure(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
rel := releaseStub()
rs.env.KubeClient = newInstallFailingKubClient()
rs.Log = t.Logf
_, err := rs.InstallRelease(c, &services.InstallReleaseRequest{
Name: rel.Name,
DisableHooks: true,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "templates/something", Data: []byte("hello: world")},
},
},
})
if err == nil {
t.Error("Expected failed install")
}
// check that the first release failed
_, err = rs.env.Releases.Failed(rel.Name)
if err != nil {
t.Fatalf("Failed to get failed: %s", err)
}
okReq := &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "templates/hello", Data: []byte("hello: world")},
},
},
}
// try to update a release where the previous version was a failure
_, err = rs.UpdateRelease(c, okReq)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
}
func TestUpdateReleaseNoHooks(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()

Loading…
Cancel
Save