diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go index 8e7fd3acd..bed61114f 100644 --- a/pkg/tiller/release_install.go +++ b/pkg/tiller/release_install.go @@ -162,7 +162,9 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install // update old release status old.Info.Status.Code = release.Status_SUPERSEDED - s.recordRelease(old, true) + if err := s.recordRelease(old, true); err != nil { + return res, err + } // update new release with next revision number // so as to append to the old release's history @@ -172,7 +174,9 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install Recreate: false, Timeout: req.Timeout, } - s.recordRelease(r, false) + if err := s.recordRelease(r, false); err != nil { + return res, err + } if err := s.ReleaseModule.Update(old, r, updateReq, s.env); err != nil { msg := fmt.Sprintf("Release replace %q failed: %s", r.Name, err) s.Log("warning: %s", msg) @@ -187,7 +191,9 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install default: // nothing to replace, create as normal // regular manifests - s.recordRelease(r, false) + if err := s.recordRelease(r, false); err != nil { + return res, err + } if err := s.ReleaseModule.Create(r, req, s.env); err != nil { msg := fmt.Sprintf("Release %q failed: %s", r.Name, err) s.Log("warning: %s", msg) diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 44d5d847a..0eb07a291 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -307,14 +307,17 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values return hooks, b, notes, nil } -func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) { +func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) error { if reuse { if err := s.env.Releases.Update(r); err != nil { s.Log("warning: Failed to update release %s: %s", r.Name, err) + return err } } else if err := s.env.Releases.Create(r); err != nil { s.Log("warning: Failed to record release %s: %s", r.Name, err) + return err } + return nil } func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook string, timeout int64) error { diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index b7b14a4f1..cd23eafdc 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -18,6 +18,7 @@ package tiller import ( "errors" + "fmt" "io" "os" "regexp" @@ -104,6 +105,18 @@ func rsFixture() *ReleaseServer { } } +func rsFixtureWithDriver(driver driver.Driver) *ReleaseServer { + clientset := fake.NewSimpleClientset() + return &ReleaseServer{ + ReleaseModule: &LocalReleaseModule{ + clientset: clientset, + }, + env: MockEnvironmentDriver(driver), + clientset: clientset, + Log: func(_ string, _ ...interface{}) {}, + } +} + // chartStub creates a fully stubbed out chart. func chartStub() *chart.Chart { return &chart.Chart{ @@ -263,6 +276,52 @@ func TestUniqName(t *testing.T) { } } +func TestRecordRelease(t *testing.T) { + driver := &mockDriverError{} + rs := rsFixtureWithDriver(driver) + + rel := releaseStub() + + driverError := fmt.Errorf("driver failure") + + tests := []struct { + description string + reuse bool + error error + }{ + { + description: "no reuse, no error", + reuse: false, + error: nil, + }, + { + description: "reuse, no error", + reuse: true, + error: nil, + }, + { + description: "no reuse, error", + reuse: false, + error: driverError, + }, + { + description: "reuse, error", + reuse: true, + error: driverError, + }, + } + + for _, tc := range tests { + t.Run(tc.description, func(t *testing.T) { + driver.err = tc.error + err := rs.recordRelease(rel, tc.reuse) + if tc.error != err { + t.Errorf("expected error didn't happen, want %v, got %v", tc.error, err) + } + }) + } +} + func releaseWithKeepStub(rlsName string) *release.Release { ch := &chart.Chart{ Metadata: &chart.Metadata{ @@ -295,6 +354,13 @@ func MockEnvironment() *environment.Environment { return e } +func MockEnvironmentDriver(driver driver.Driver) *environment.Environment { + e := environment.New() + e.Releases = storage.Init(driver) + e.KubeClient = &environment.PrintingKubeClient{Out: os.Stdout} + return e +} + func newUpdateFailingKubeClient() *updateFailingKubeClient { return &updateFailingKubeClient{ PrintingKubeClient: environment.PrintingKubeClient{Out: os.Stdout}, @@ -353,3 +419,20 @@ func (rs mockRunReleaseTestServer) SetTrailer(m metadata.MD) {} func (rs mockRunReleaseTestServer) SendMsg(v interface{}) error { return nil } func (rs mockRunReleaseTestServer) RecvMsg(v interface{}) error { return nil } func (rs mockRunReleaseTestServer) Context() context.Context { return helm.NewContext() } + +type mockDriverError struct { + rel *release.Release + err error +} + +func (de mockDriverError) Name() string { return "mockDriverError" } +func (de mockDriverError) Create(key string, rls *release.Release) error { return de.err } +func (de mockDriverError) Update(key string, rls *release.Release) error { return de.err } +func (de mockDriverError) Delete(key string) (*release.Release, error) { return de.rel, de.err } +func (de mockDriverError) Get(key string) (*release.Release, error) { return de.rel, de.err } +func (de mockDriverError) Query(labels map[string]string) ([]*release.Release, error) { + return []*release.Release{de.rel}, de.err +} +func (de mockDriverError) List(filter func(*release.Release) bool) ([]*release.Release, error) { + return []*release.Release{de.rel}, de.err +}