diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 1c2818403..7a2a8d247 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -40,10 +40,8 @@ func NewClient(opts ...Option) *Client { func (c *Client) init() *Client { env := environment.New() - env.Releases = storage.Init(c.opts.driver) - env.KubeClient = c.opts.kubeClient - - c.tiller = tiller.NewReleaseServer(env, c.opts.discovery) + c.tiller = tiller.NewReleaseServer(env, c.opts.discovery, c.opts.kubeClient) + c.tiller.Releases = storage.Init(c.opts.driver) return c } diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go index eaae7e9e5..653d458ec 100644 --- a/pkg/tiller/environment/environment.go +++ b/pkg/tiller/environment/environment.go @@ -33,8 +33,6 @@ import ( "k8s.io/helm/pkg/engine" "k8s.io/helm/pkg/hapi/chart" "k8s.io/helm/pkg/kube" - "k8s.io/helm/pkg/storage" - "k8s.io/helm/pkg/storage/driver" ) // GoTplEngine is the name of the Go template engine, as registered in the EngineYard. @@ -202,10 +200,6 @@ func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(namespace string, reade type Environment struct { // EngineYard provides access to the known template engines. EngineYard EngineYard - // Releases stores records of releases. - Releases *storage.Storage - // KubeClient is a Kubernetes API client. - KubeClient KubeClient } // New returns an environment initialized with the defaults. @@ -219,6 +213,5 @@ func New() *Environment { return &Environment{ EngineYard: ey, - Releases: storage.Init(driver.NewMemory()), } } diff --git a/pkg/tiller/environment/environment_test.go b/pkg/tiller/environment/environment_test.go index 6b89d80f1..72d4a2a96 100644 --- a/pkg/tiller/environment/environment_test.go +++ b/pkg/tiller/environment/environment_test.go @@ -90,8 +90,6 @@ func TestEngine(t *testing.T) { func TestKubeClient(t *testing.T) { kc := &mockKubeClient{} - env := New() - env.KubeClient = kc manifests := map[string]string{ "foo": "name: value\n", @@ -104,7 +102,7 @@ func TestKubeClient(t *testing.T) { b.WriteString(content) } - if err := env.KubeClient.Create("sharry-bobbins", b, 300, false); err != nil { + if err := kc.Create("sharry-bobbins", b, 300, false); err != nil { t.Errorf("Kubeclient failed: %s", err) } } diff --git a/pkg/tiller/release_content.go b/pkg/tiller/release_content.go index 54e4518ec..899c3a79b 100644 --- a/pkg/tiller/release_content.go +++ b/pkg/tiller/release_content.go @@ -29,8 +29,8 @@ func (s *ReleaseServer) GetReleaseContent(req *hapi.GetReleaseContentRequest) (* } if req.Version <= 0 { - return s.env.Releases.Last(req.Name) + return s.Releases.Last(req.Name) } - return s.env.Releases.Get(req.Name, req.Version) + return s.Releases.Get(req.Name, req.Version) } diff --git a/pkg/tiller/release_content_test.go b/pkg/tiller/release_content_test.go index a52c5f029..45cdaf481 100644 --- a/pkg/tiller/release_content_test.go +++ b/pkg/tiller/release_content_test.go @@ -25,7 +25,7 @@ import ( func TestGetReleaseContent(t *testing.T) { rs := rsFixture() rel := releaseStub() - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } diff --git a/pkg/tiller/release_history.go b/pkg/tiller/release_history.go index 7d0008844..d4e560232 100644 --- a/pkg/tiller/release_history.go +++ b/pkg/tiller/release_history.go @@ -30,7 +30,7 @@ func (s *ReleaseServer) GetHistory(req *hapi.GetHistoryRequest) ([]*release.Rele } s.Log("getting history for release %s", req.Name) - h, err := s.env.Releases.History(req.Name) + h, err := s.Releases.History(req.Name) if err != nil { return nil, err } diff --git a/pkg/tiller/release_history_test.go b/pkg/tiller/release_history_test.go index e247c79e1..2c4de7b18 100644 --- a/pkg/tiller/release_history_test.go +++ b/pkg/tiller/release_history_test.go @@ -69,7 +69,7 @@ func TestGetHistory_WithRevisions(t *testing.T) { srv := rsFixture() for _, rls := range hist { - if err := srv.env.Releases.Create(rls); err != nil { + if err := srv.Releases.Create(rls); err != nil { t.Fatalf("Failed to create release: %s", err) } } @@ -100,7 +100,7 @@ func TestGetHistory_WithNoRevisions(t *testing.T) { // create release 'sad-panda' with no revision history rls := namedReleaseStub("sad-panda", rpb.Status_DEPLOYED) srv := rsFixture() - srv.env.Releases.Create(rls) + srv.Releases.Create(rls) for _, tt := range tests { res, err := srv.GetHistory(tt.req) diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go index 852c618b0..251250b18 100644 --- a/pkg/tiller/release_install.go +++ b/pkg/tiller/release_install.go @@ -125,7 +125,7 @@ func (s *ReleaseServer) prepareRelease(req *hapi.InstallReleaseRequest) (*releas rel.Info.Status.Notes = notesTxt } - err = validateManifest(s.env.KubeClient, req.Namespace, manifestDoc.Bytes()) + err = validateManifest(s.KubeClient, req.Namespace, manifestDoc.Bytes()) return rel, err } @@ -147,7 +147,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *hapi.InstallRele s.Log("install hooks disabled for %s", req.Name) } - switch h, err := s.env.Releases.History(req.Name); { + switch h, err := s.Releases.History(req.Name); { // if this is a replace operation, append to the release history case req.ReuseName && err == nil && len(h) >= 1: s.Log("name reuse for %s requested, replacing release", req.Name) @@ -170,7 +170,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *hapi.InstallRele Timeout: req.Timeout, } s.recordRelease(r, false) - if err := s.Update(old, r, updateReq); err != nil { + if err := s.updateRelease(old, r, updateReq); err != nil { msg := fmt.Sprintf("Release replace %q failed: %s", r.Name, err) s.Log("warning: %s", msg) old.Info.Status.Code = release.Status_SUPERSEDED @@ -186,7 +186,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *hapi.InstallRele // regular manifests s.recordRelease(r, false) b := bytes.NewBufferString(r.Manifest) - if err := s.env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait); err != nil { + if err := s.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait); err != nil { msg := fmt.Sprintf("Release %q failed: %s", r.Name, err) s.Log("warning: %s", msg) r.Info.Status.Code = release.Status_FAILED diff --git a/pkg/tiller/release_install_test.go b/pkg/tiller/release_install_test.go index 02803966d..397db0a96 100644 --- a/pkg/tiller/release_install_test.go +++ b/pkg/tiller/release_install_test.go @@ -40,9 +40,9 @@ func TestInstallRelease(t *testing.T) { t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace) } - rel, err := rs.env.Releases.Get(res.Name, res.Version) + rel, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } t.Logf("rel: %v", rel) @@ -95,9 +95,9 @@ func TestInstallRelease_WithNotes(t *testing.T) { t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace) } - rel, err := rs.env.Releases.Get(res.Name, res.Version) + rel, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } t.Logf("rel: %v", rel) @@ -154,9 +154,9 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace) } - rel, err := rs.env.Releases.Get(res.Name, res.Version) + rel, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } t.Logf("rel: %v", rel) @@ -212,9 +212,9 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { t.Errorf("Expected release name.") } - rel, err := rs.env.Releases.Get(res.Name, res.Version) + rel, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } t.Logf("rel: %v", rel) @@ -262,7 +262,7 @@ func TestInstallRelease_DryRun(t *testing.T) { t.Errorf("Should not contain template data for an empty file. %s", res.Manifest) } - if _, err := rs.env.Releases.Get(res.Name, res.Version); err == nil { + if _, err := rs.Releases.Get(res.Name, res.Version); err == nil { t.Errorf("Expected no stored release.") } @@ -281,7 +281,7 @@ func TestInstallRelease_DryRun(t *testing.T) { func TestInstallRelease_NoHooks(t *testing.T) { rs := rsFixture() - rs.env.Releases.Create(releaseStub()) + rs.Releases.Create(releaseStub()) req := installRequest(withDisabledHooks()) res, err := rs.InstallRelease(req) @@ -296,8 +296,8 @@ func TestInstallRelease_NoHooks(t *testing.T) { func TestInstallRelease_FailedHooks(t *testing.T) { rs := rsFixture() - rs.env.Releases.Create(releaseStub()) - rs.env.KubeClient = newHookFailingKubeClient() + rs.Releases.Create(releaseStub()) + rs.KubeClient = newHookFailingKubeClient() req := installRequest() res, err := rs.InstallRelease(req) @@ -314,7 +314,7 @@ func TestInstallRelease_ReuseName(t *testing.T) { rs := rsFixture() rel := releaseStub() rel.Info.Status.Code = release.Status_DELETED - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := installRequest( withReuseName(), diff --git a/pkg/tiller/release_list.go b/pkg/tiller/release_list.go index e1a902554..c4cb17fc2 100644 --- a/pkg/tiller/release_list.go +++ b/pkg/tiller/release_list.go @@ -30,7 +30,7 @@ func (s *ReleaseServer) ListReleases(req *hapi.ListReleasesRequest) ([]*release. req.StatusCodes = []release.StatusCode{release.Status_DEPLOYED} } - rels, err := s.env.Releases.ListFilterAll(func(r *release.Release) bool { + rels, err := s.Releases.ListFilterAll(func(r *release.Release) bool { for _, sc := range req.StatusCodes { if sc == r.Info.Status.Code { return true diff --git a/pkg/tiller/release_list_test.go b/pkg/tiller/release_list_test.go index 9df2256ba..18ee692ba 100644 --- a/pkg/tiller/release_list_test.go +++ b/pkg/tiller/release_list_test.go @@ -30,7 +30,7 @@ func TestListReleases(t *testing.T) { for i := 0; i < num; i++ { rel := releaseStub() rel.Name = fmt.Sprintf("rel-%d", i) - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } } @@ -54,7 +54,7 @@ func TestListReleasesByStatus(t *testing.T) { namedReleaseStub("sextant", release.Status_UNKNOWN), } for _, stub := range stubs { - if err := rs.env.Releases.Create(stub); err != nil { + if err := rs.Releases.Create(stub); err != nil { t.Fatalf("Could not create stub: %s", err) } } @@ -119,7 +119,7 @@ func TestListReleasesSort(t *testing.T) { for i := num; i > 0; i-- { rel := releaseStub() rel.Name = fmt.Sprintf("rel-%d", i) - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } } @@ -162,7 +162,7 @@ func TestListReleasesFilter(t *testing.T) { for i := 0; i < num; i++ { rel := releaseStub() rel.Name = names[i] - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } } diff --git a/pkg/tiller/release_rollback.go b/pkg/tiller/release_rollback.go index 6084dc074..457a5d0bc 100644 --- a/pkg/tiller/release_rollback.go +++ b/pkg/tiller/release_rollback.go @@ -36,7 +36,7 @@ func (s *ReleaseServer) RollbackRelease(req *hapi.RollbackReleaseRequest) (*rele if !req.DryRun { s.Log("creating rolled back release for %s", req.Name) - if err := s.env.Releases.Create(targetRelease); err != nil { + if err := s.Releases.Create(targetRelease); err != nil { return nil, err } } @@ -48,7 +48,7 @@ func (s *ReleaseServer) RollbackRelease(req *hapi.RollbackReleaseRequest) (*rele if !req.DryRun { s.Log("updating status for rolled back release for %s", req.Name) - if err := s.env.Releases.Update(targetRelease); err != nil { + if err := s.Releases.Update(targetRelease); err != nil { return res, err } } @@ -68,7 +68,7 @@ func (s *ReleaseServer) prepareRollback(req *hapi.RollbackReleaseRequest) (*rele return nil, nil, errInvalidRevision } - currentRelease, err := s.env.Releases.Last(req.Name) + currentRelease, err := s.Releases.Last(req.Name) if err != nil { return nil, nil, err } @@ -80,7 +80,7 @@ func (s *ReleaseServer) prepareRollback(req *hapi.RollbackReleaseRequest) (*rele s.Log("rolling back %s (current: v%d, target: v%d)", req.Name, currentRelease.Version, previousVersion) - previousRelease, err := s.env.Releases.Get(req.Name, previousVersion) + previousRelease, err := s.Releases.Get(req.Name, previousVersion) if err != nil { return nil, nil, err } @@ -128,7 +128,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R c := bytes.NewBufferString(currentRelease.Manifest) t := bytes.NewBufferString(targetRelease.Manifest) - if err := s.env.KubeClient.Update(targetRelease.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait); err != nil { + if err := s.KubeClient.Update(targetRelease.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait); err != nil { msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) s.Log("warning: %s", msg) currentRelease.Info.Status.Code = release.Status_SUPERSEDED @@ -146,7 +146,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R } } - deployed, err := s.env.Releases.DeployedAll(currentRelease.Name) + deployed, err := s.Releases.DeployedAll(currentRelease.Name) if err != nil { return nil, err } diff --git a/pkg/tiller/release_rollback_test.go b/pkg/tiller/release_rollback_test.go index 161e248b8..4095ec7a7 100644 --- a/pkg/tiller/release_rollback_test.go +++ b/pkg/tiller/release_rollback_test.go @@ -27,7 +27,7 @@ import ( func TestRollbackRelease(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) upgradedRel := upgradeReleaseVersion(rel) upgradedRel.Hooks = []*release.Hook{ { @@ -43,8 +43,8 @@ func TestRollbackRelease(t *testing.T) { } upgradedRel.Manifest = "hello world" - rs.env.Releases.Update(rel) - rs.env.Releases.Create(upgradedRel) + rs.Releases.Update(rel) + rs.Releases.Create(upgradedRel) req := &hapi.RollbackReleaseRequest{ Name: rel.Name, @@ -70,9 +70,9 @@ func TestRollbackRelease(t *testing.T) { t.Errorf("Expected release version to be %v, got %v", 3, res.Version) } - updated, err := rs.env.Releases.Get(res.Name, res.Version) + updated, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } if len(updated.Hooks) != 2 { @@ -84,17 +84,17 @@ func TestRollbackRelease(t *testing.T) { } anotherUpgradedRelease := upgradeReleaseVersion(upgradedRel) - rs.env.Releases.Update(upgradedRel) - rs.env.Releases.Create(anotherUpgradedRelease) + rs.Releases.Update(upgradedRel) + rs.Releases.Create(anotherUpgradedRelease) res, err = rs.RollbackRelease(req) if err != nil { t.Fatalf("Failed rollback: %s", err) } - updated, err = rs.env.Releases.Get(res.Name, res.Version) + updated, err = rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Errorf("Expected release for %s (%v).", res.Name, rs.Releases) } if len(updated.Hooks) != 1 { @@ -136,22 +136,20 @@ func TestRollbackRelease(t *testing.T) { func TestRollbackWithReleaseVersion(t *testing.T) { rs := rsFixture() - rs.Log = t.Logf - rs.env.Releases.Log = t.Logf rel2 := releaseStub() rel2.Name = "other" - rs.env.Releases.Create(rel2) + rs.Releases.Create(rel2) rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) v2 := upgradeReleaseVersion(rel) - rs.env.Releases.Update(rel) - rs.env.Releases.Create(v2) + rs.Releases.Update(rel) + rs.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) + rs.Releases.Update(v2) + rs.Releases.Create(v3) req := &hapi.RollbackReleaseRequest{ Name: rel.Name, @@ -164,7 +162,7 @@ func TestRollbackWithReleaseVersion(t *testing.T) { t.Fatalf("Failed rollback: %s", err) } // check that v2 is now in a SUPERSEDED state - oldRel, err := rs.env.Releases.Get(rel.Name, 2) + oldRel, err := rs.Releases.Get(rel.Name, 2) if err != nil { t.Fatalf("Failed to retrieve v1: %s", err) } @@ -172,7 +170,7 @@ func TestRollbackWithReleaseVersion(t *testing.T) { t.Errorf("Expected v2 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) + otherRel, err := rs.Releases.Get(rel2.Name, 1) if err != nil { t.Fatalf("Failed to retrieve other v1: %s", err) } @@ -196,10 +194,10 @@ func TestRollbackReleaseNoHooks(t *testing.T) { }, }, } - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) upgradedRel := upgradeReleaseVersion(rel) - rs.env.Releases.Update(rel) - rs.env.Releases.Create(upgradedRel) + rs.Releases.Update(rel) + rs.Releases.Create(upgradedRel) req := &hapi.RollbackReleaseRequest{ Name: rel.Name, @@ -219,17 +217,17 @@ func TestRollbackReleaseNoHooks(t *testing.T) { func TestRollbackReleaseFailure(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) upgradedRel := upgradeReleaseVersion(rel) - rs.env.Releases.Update(rel) - rs.env.Releases.Create(upgradedRel) + rs.Releases.Update(rel) + rs.Releases.Create(upgradedRel) req := &hapi.RollbackReleaseRequest{ Name: rel.Name, DisableHooks: true, } - rs.env.KubeClient = newUpdateFailingKubeClient() + rs.KubeClient = newUpdateFailingKubeClient() res, err := rs.RollbackRelease(req) if err == nil { t.Error("Expected failed rollback") @@ -239,7 +237,7 @@ func TestRollbackReleaseFailure(t *testing.T) { t.Errorf("Expected FAILED release. Got %v", targetStatus) } - oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) + oldRelease, err := rs.Releases.Get(rel.Name, rel.Version) if err != nil { t.Errorf("Expected to be able to get previous release") } diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index db6f150da..33366d572 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -20,7 +20,6 @@ import ( "bytes" "errors" "fmt" - "log" "path" "regexp" "strings" @@ -36,8 +35,9 @@ import ( "k8s.io/helm/pkg/hapi/chart" "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/hooks" - "k8s.io/helm/pkg/kube" relutil "k8s.io/helm/pkg/releaseutil" + "k8s.io/helm/pkg/storage" + "k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/tiller/environment" "k8s.io/helm/pkg/version" ) @@ -84,15 +84,23 @@ var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+ type ReleaseServer struct { env *environment.Environment discovery discovery.DiscoveryInterface - Log func(string, ...interface{}) + + // Releases stores records of releases. + Releases *storage.Storage + // KubeClient is a Kubernetes API client. + KubeClient environment.KubeClient + + Log func(string, ...interface{}) } // NewReleaseServer creates a new release server. -func NewReleaseServer(env *environment.Environment, discovery discovery.DiscoveryInterface) *ReleaseServer { +func NewReleaseServer(env *environment.Environment, discovery discovery.DiscoveryInterface, kubeClient environment.KubeClient) *ReleaseServer { return &ReleaseServer{ - env: env, - discovery: discovery, - Log: func(_ string, _ ...interface{}) {}, + env: env, + discovery: discovery, + Releases: storage.Init(driver.NewMemory()), + KubeClient: kubeClient, + Log: func(_ string, _ ...interface{}) {}, } } @@ -168,7 +176,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { return "", fmt.Errorf("release name %q exceeds max length of %d", start, releaseNameMaxLen) } - h, err := s.env.Releases.History(start) + h, err := s.Releases.History(start) if err != nil || len(h) < 1 { return start, nil } @@ -193,7 +201,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { if len(name) > releaseNameMaxLen { name = name[:releaseNameMaxLen] } - if _, err := s.env.Releases.Get(name, 1); strings.Contains(err.Error(), "not found") { + if _, err := s.Releases.Get(name, 1); strings.Contains(err.Error(), "not found") { return name, nil } s.Log("info: generated name %s is taken. Searching again.", name) @@ -325,10 +333,10 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values // recordRelease with an update operation in case reuse has been set. func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) { if reuse { - if err := s.env.Releases.Update(r); err != nil { + if err := s.Releases.Update(r); err != nil { s.Log("warning: Failed to update release %s: %s", r.Name, err) } - } else if err := s.env.Releases.Create(r); err != nil { + } else if err := s.Releases.Create(r); err != nil { s.Log("warning: Failed to record release %s: %s", r.Name, err) } } @@ -352,12 +360,12 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin executingHooks = sortByHookWeight(executingHooks) for _, h := range executingHooks { - if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.BeforeHookCreation, name, namespace, hook, s.env.KubeClient); err != nil { + if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.BeforeHookCreation, name, namespace, hook, s.KubeClient); err != nil { return err } b := bytes.NewBufferString(h.Manifest) - if err := s.env.KubeClient.Create(namespace, b, timeout, false); err != nil { + if err := s.KubeClient.Create(namespace, b, timeout, false); err != nil { s.Log("warning: Release %s %s %s failed: %s", name, hook, h.Path, err) return err } @@ -365,11 +373,11 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin b.Reset() b.WriteString(h.Manifest) - if err := s.env.KubeClient.WatchUntilReady(namespace, b, timeout, false); err != nil { + if err := s.KubeClient.WatchUntilReady(namespace, b, timeout, false); err != nil { s.Log("warning: Release %s %s %s could not complete: %s", name, hook, h.Path, err) // If a hook is failed, checkout the annotation of the hook to determine whether the hook should be deleted // under failed condition. If so, then clear the corresponding resource object in the hook - if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.HookFailed, name, namespace, hook, s.env.KubeClient); err != nil { + if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.HookFailed, name, namespace, hook, s.KubeClient); err != nil { return err } return err @@ -380,7 +388,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin // If all hooks are succeeded, checkout the annotation of each hook to determine whether the hook should be deleted // under succeeded condition. If so, then clear the corresponding resource object in each hook for _, h := range executingHooks { - if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.HookSucceeded, name, namespace, hook, s.env.KubeClient); err != nil { + if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.HookSucceeded, name, namespace, hook, s.KubeClient); err != nil { return err } h.LastRun = time.Now() @@ -431,49 +439,3 @@ func hookHasDeletePolicy(h *release.Hook, policy string) bool { } return false } - -// Update performs an update from current to target release -func (s *ReleaseServer) Update(current, target *release.Release, req *hapi.UpdateReleaseRequest) error { - c := bytes.NewBufferString(current.Manifest) - t := bytes.NewBufferString(target.Manifest) - return s.env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) -} - -// Delete deletes the release and returns manifests that were kept in the deletion process -func (s *ReleaseServer) Delete(rel *release.Release, req *hapi.UninstallReleaseRequest) (kept string, errs []error) { - vs, err := GetVersionSet(s.discovery) - if err != nil { - return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)} - } - - manifests := relutil.SplitManifests(rel.Manifest) - _, files, err := sortManifests(manifests, vs, UninstallOrder) - if err != nil { - // We could instead just delete everything in no particular order. - // FIXME: One way to delete at this point would be to try a label-based - // deletion. The problem with this is that we could get a false positive - // and delete something that was not legitimately part of this release. - return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} - } - - filesToKeep, filesToDelete := filterManifestsToKeep(files) - if len(filesToKeep) > 0 { - kept = summarizeKeptManifests(filesToKeep, s.env.KubeClient, rel.Namespace) - } - - for _, file := range filesToDelete { - b := bytes.NewBufferString(strings.TrimSpace(file.Content)) - if b.Len() == 0 { - continue - } - if err := s.env.KubeClient.Delete(rel.Namespace, b); err != nil { - log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err) - if err == kube.ErrNoObjectsVisited { - // Rewrite the message from "no objects visited" - err = errors.New("object not found, skipping delete") - } - errs = append(errs, err) - } - } - return kept, errs -} diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index 9d1d70409..56621acd3 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -88,12 +88,10 @@ data: ` func rsFixture() *ReleaseServer { + env := environment.New() dc := fake.NewSimpleClientset().Discovery() - return &ReleaseServer{ - env: MockEnvironment(), - discovery: dc, - Log: func(_ string, _ ...interface{}) {}, - } + kc := &environment.PrintingKubeClient{Out: ioutil.Discard} + return NewReleaseServer(env, dc, kc) } type chartOptions struct { @@ -315,8 +313,8 @@ func TestUniqName(t *testing.T) { rel2.Name = "happy-panda" rel2.Info.Status.Code = release.Status_DELETED - rs.env.Releases.Create(rel1) - rs.env.Releases.Create(rel2) + rs.Releases.Create(rel1) + rs.Releases.Create(rel2) tests := []struct { name string @@ -375,12 +373,6 @@ func releaseWithKeepStub(rlsName string) *release.Release { } } -func MockEnvironment() *environment.Environment { - e := environment.New() - e.KubeClient = &environment.PrintingKubeClient{Out: ioutil.Discard} - return e -} - func newUpdateFailingKubeClient() *updateFailingKubeClient { return &updateFailingKubeClient{ PrintingKubeClient: environment.PrintingKubeClient{Out: os.Stdout}, @@ -494,13 +486,13 @@ func (kc *mockHooksKubeClient) WaitAndGetCompletedPodPhase(namespace string, rea func deletePolicyStub(kubeClient *mockHooksKubeClient) *ReleaseServer { e := environment.New() - e.KubeClient = kubeClient dc := fake.NewSimpleClientset().Discovery() return &ReleaseServer{ - env: e, - discovery: dc, - Log: func(_ string, _ ...interface{}) {}, + env: e, + discovery: dc, + KubeClient: kubeClient, + Log: func(_ string, _ ...interface{}) {}, } } diff --git a/pkg/tiller/release_status.go b/pkg/tiller/release_status.go index 2fccd5114..ed4bc8cdb 100644 --- a/pkg/tiller/release_status.go +++ b/pkg/tiller/release_status.go @@ -36,13 +36,13 @@ func (s *ReleaseServer) GetReleaseStatus(req *hapi.GetReleaseStatusRequest) (*ha if req.Version <= 0 { var err error - rel, err = s.env.Releases.Last(req.Name) + rel, err = s.Releases.Last(req.Name) if err != nil { return nil, fmt.Errorf("getting deployed release %q: %s", req.Name, err) } } else { var err error - if rel, err = s.env.Releases.Get(req.Name, req.Version); err != nil { + if rel, err = s.Releases.Get(req.Name, req.Version); err != nil { return nil, fmt.Errorf("getting release '%s' (v%d): %s", req.Name, req.Version, err) } } @@ -63,7 +63,7 @@ func (s *ReleaseServer) GetReleaseStatus(req *hapi.GetReleaseStatusRequest) (*ha // Ok, we got the status of the release as we had jotted down, now we need to match the // manifest we stashed away with reality from the cluster. - resp, err := s.env.KubeClient.Get(rel.Namespace, bytes.NewBufferString(rel.Manifest)) + resp, err := s.KubeClient.Get(rel.Namespace, bytes.NewBufferString(rel.Manifest)) if sc == release.Status_DELETED || sc == release.Status_FAILED { // Skip errors if this is already deleted or failed. return statusResp, nil diff --git a/pkg/tiller/release_status_test.go b/pkg/tiller/release_status_test.go index 0676bf967..90f9ef1e9 100644 --- a/pkg/tiller/release_status_test.go +++ b/pkg/tiller/release_status_test.go @@ -26,7 +26,7 @@ import ( func TestGetReleaseStatus(t *testing.T) { rs := rsFixture() rel := releaseStub() - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } @@ -47,7 +47,7 @@ func TestGetReleaseStatusDeleted(t *testing.T) { rs := rsFixture() rel := releaseStub() rel.Info.Status.Code = release.Status_DELETED - if err := rs.env.Releases.Create(rel); err != nil { + if err := rs.Releases.Create(rel); err != nil { t.Fatalf("Could not store mock release: %s", err) } diff --git a/pkg/tiller/release_testing.go b/pkg/tiller/release_testing.go index 9932233f4..385405f88 100644 --- a/pkg/tiller/release_testing.go +++ b/pkg/tiller/release_testing.go @@ -32,7 +32,7 @@ func (s *ReleaseServer) RunReleaseTest(req *hapi.TestReleaseRequest) (<-chan *ha } // finds the non-deleted release with the given name - rel, err := s.env.Releases.Last(req.Name) + rel, err := s.Releases.Last(req.Name) if err != nil { errc <- err return nil, errc @@ -41,7 +41,7 @@ func (s *ReleaseServer) RunReleaseTest(req *hapi.TestReleaseRequest) (<-chan *ha ch := make(chan *hapi.TestReleaseResponse, 1) testEnv := &reltesting.Environment{ Namespace: rel.Namespace, - KubeClient: s.env.KubeClient, + KubeClient: s.KubeClient, Timeout: req.Timeout, Mesages: ch, } @@ -68,7 +68,7 @@ func (s *ReleaseServer) RunReleaseTest(req *hapi.TestReleaseRequest) (<-chan *ha testEnv.DeleteTestPods(tSuite.TestManifests) } - if err := s.env.Releases.Update(rel); err != nil { + if err := s.Releases.Update(rel); err != nil { s.Log("test: Failed to store updated release: %s", err) } }() diff --git a/pkg/tiller/release_uninstall.go b/pkg/tiller/release_uninstall.go index 2cb9f1123..1b7e1f192 100644 --- a/pkg/tiller/release_uninstall.go +++ b/pkg/tiller/release_uninstall.go @@ -17,6 +17,8 @@ limitations under the License. package tiller import ( + "bytes" + "errors" "fmt" "strings" "time" @@ -24,6 +26,7 @@ import ( "k8s.io/helm/pkg/hapi" "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/hooks" + "k8s.io/helm/pkg/kube" relutil "k8s.io/helm/pkg/releaseutil" ) @@ -34,7 +37,7 @@ func (s *ReleaseServer) UninstallRelease(req *hapi.UninstallReleaseRequest) (*ha return nil, err } - rels, err := s.env.Releases.History(req.Name) + rels, err := s.Releases.History(req.Name) if err != nil { s.Log("uninstall: Release not loaded: %s", req.Name) return nil, err @@ -75,11 +78,11 @@ func (s *ReleaseServer) UninstallRelease(req *hapi.UninstallReleaseRequest) (*ha // From here on out, the release is currently considered to be in Status_DELETING // state. - if err := s.env.Releases.Update(rel); err != nil { + if err := s.Releases.Update(rel); err != nil { s.Log("uninstall: Failed to store updated release: %s", err) } - kept, errs := s.Delete(rel, req) + kept, errs := s.deleteRelease(rel) res.Info = kept if !req.DisableHooks { @@ -100,7 +103,7 @@ func (s *ReleaseServer) UninstallRelease(req *hapi.UninstallReleaseRequest) (*ha return res, err } - if err := s.env.Releases.Update(rel); err != nil { + if err := s.Releases.Update(rel); err != nil { s.Log("uninstall: Failed to store updated release: %s", err) } @@ -120,9 +123,48 @@ func joinErrors(errs []error) string { func (s *ReleaseServer) purgeReleases(rels ...*release.Release) error { for _, rel := range rels { - if _, err := s.env.Releases.Delete(rel.Name, rel.Version); err != nil { + if _, err := s.Releases.Delete(rel.Name, rel.Version); err != nil { return err } } return nil } + +// deleteRelease deletes the release and returns manifests that were kept in the deletion process +func (s *ReleaseServer) deleteRelease(rel *release.Release) (kept string, errs []error) { + vs, err := GetVersionSet(s.discovery) + if err != nil { + return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)} + } + + manifests := relutil.SplitManifests(rel.Manifest) + _, files, err := sortManifests(manifests, vs, UninstallOrder) + if err != nil { + // We could instead just delete everything in no particular order. + // FIXME: One way to delete at this point would be to try a label-based + // deletion. The problem with this is that we could get a false positive + // and delete something that was not legitimately part of this release. + return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} + } + + filesToKeep, filesToDelete := filterManifestsToKeep(files) + if len(filesToKeep) > 0 { + kept = summarizeKeptManifests(filesToKeep, s.KubeClient, rel.Namespace) + } + + for _, file := range filesToDelete { + b := bytes.NewBufferString(strings.TrimSpace(file.Content)) + if b.Len() == 0 { + continue + } + if err := s.KubeClient.Delete(rel.Namespace, b); err != nil { + s.Log("uninstall: Failed deletion of %q: %s", rel.Name, err) + if err == kube.ErrNoObjectsVisited { + // Rewrite the message from "no objects visited" + err = errors.New("object not found, skipping delete") + } + errs = append(errs, err) + } + } + return kept, errs +} diff --git a/pkg/tiller/release_uninstall_test.go b/pkg/tiller/release_uninstall_test.go index 4bc226273..f0eca06b5 100644 --- a/pkg/tiller/release_uninstall_test.go +++ b/pkg/tiller/release_uninstall_test.go @@ -26,7 +26,7 @@ import ( func TestUninstallRelease(t *testing.T) { rs := rsFixture() - rs.env.Releases.Create(releaseStub()) + rs.Releases.Create(releaseStub()) req := &hapi.UninstallReleaseRequest{ Name: "angry-panda", @@ -61,10 +61,10 @@ func TestUninstallRelease(t *testing.T) { func TestUninstallPurgeRelease(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) upgradedRel := upgradeReleaseVersion(rel) - rs.env.Releases.Update(rel) - rs.env.Releases.Create(upgradedRel) + rs.Releases.Update(rel) + rs.Releases.Create(upgradedRel) req := &hapi.UninstallReleaseRequest{ Name: "angry-panda", @@ -98,7 +98,7 @@ func TestUninstallPurgeRelease(t *testing.T) { func TestUninstallPurgeDeleteRelease(t *testing.T) { rs := rsFixture() - rs.env.Releases.Create(releaseStub()) + rs.Releases.Create(releaseStub()) req := &hapi.UninstallReleaseRequest{ Name: "angry-panda", @@ -123,7 +123,7 @@ func TestUninstallPurgeDeleteRelease(t *testing.T) { func TestUninstallReleaseWithKeepPolicy(t *testing.T) { rs := rsFixture() name := "angry-bunny" - rs.env.Releases.Create(releaseWithKeepStub(name)) + rs.Releases.Create(releaseWithKeepStub(name)) req := &hapi.UninstallReleaseRequest{ Name: name, @@ -153,7 +153,7 @@ func TestUninstallReleaseWithKeepPolicy(t *testing.T) { func TestUninstallReleaseNoHooks(t *testing.T) { rs := rsFixture() - rs.env.Releases.Create(releaseStub()) + rs.Releases.Create(releaseStub()) req := &hapi.UninstallReleaseRequest{ Name: "angry-panda", diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go index 3e3312c77..645638791 100644 --- a/pkg/tiller/release_update.go +++ b/pkg/tiller/release_update.go @@ -17,6 +17,7 @@ limitations under the License. package tiller import ( + "bytes" "fmt" "strings" "time" @@ -45,7 +46,7 @@ func (s *ReleaseServer) UpdateRelease(req *hapi.UpdateReleaseRequest) (*release. if !req.DryRun { s.Log("creating updated release for %s", req.Name) - if err := s.env.Releases.Create(updatedRelease); err != nil { + if err := s.Releases.Create(updatedRelease); err != nil { return nil, err } } @@ -58,7 +59,7 @@ func (s *ReleaseServer) UpdateRelease(req *hapi.UpdateReleaseRequest) (*release. if !req.DryRun { s.Log("updating status for updated release for %s", req.Name) - if err := s.env.Releases.Update(updatedRelease); err != nil { + if err := s.Releases.Update(updatedRelease); err != nil { return res, err } } @@ -73,7 +74,7 @@ func (s *ReleaseServer) prepareUpdate(req *hapi.UpdateReleaseRequest) (*release. } // finds the deployed release with the given name - currentRelease, err := s.env.Releases.Deployed(req.Name) + currentRelease, err := s.Releases.Deployed(req.Name) if err != nil { return nil, nil, err } @@ -84,7 +85,7 @@ func (s *ReleaseServer) prepareUpdate(req *hapi.UpdateReleaseRequest) (*release. } // finds the non-deleted release with the given name - lastRelease, err := s.env.Releases.Last(req.Name) + lastRelease, err := s.Releases.Last(req.Name) if err != nil { return nil, nil, err } @@ -136,14 +137,14 @@ func (s *ReleaseServer) prepareUpdate(req *hapi.UpdateReleaseRequest) (*release. if len(notesTxt) > 0 { updatedRelease.Info.Status.Notes = notesTxt } - err = validateManifest(s.env.KubeClient, currentRelease.Namespace, manifestDoc.Bytes()) + err = validateManifest(s.KubeClient, currentRelease.Namespace, manifestDoc.Bytes()) return currentRelease, updatedRelease, err } // performUpdateForce performs the same action as a `helm delete && helm install --replace`. func (s *ReleaseServer) performUpdateForce(req *hapi.UpdateReleaseRequest) (*release.Release, error) { // find the last release with the given name - oldRelease, err := s.env.Releases.Last(req.Name) + oldRelease, err := s.Releases.Last(req.Name) if err != nil { return nil, err } @@ -186,7 +187,7 @@ func (s *ReleaseServer) performUpdateForce(req *hapi.UpdateReleaseRequest) (*rel } // delete manifests from the old release - _, errs := s.Delete(oldRelease, nil) + _, errs := s.deleteRelease(oldRelease) oldRelease.Info.Status.Code = release.Status_DELETED oldRelease.Info.Description = "Deletion complete" @@ -213,7 +214,7 @@ func (s *ReleaseServer) performUpdateForce(req *hapi.UpdateReleaseRequest) (*rel // update new release with next revision number so as to append to the old release's history newRelease.Version = oldRelease.Version + 1 s.recordRelease(newRelease, false) - if err := s.Update(oldRelease, newRelease, req); err != nil { + if err := s.updateRelease(oldRelease, newRelease, req); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", newRelease.Name, err) s.Log("warning: %s", msg) newRelease.Info.Status.Code = release.Status_FAILED @@ -257,7 +258,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R } else { s.Log("update hooks disabled for %s", req.Name) } - if err := s.Update(originalRelease, updatedRelease, req); err != nil { + if err := s.updateRelease(originalRelease, updatedRelease, req); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err) s.Log("warning: %s", msg) updatedRelease.Info.Status.Code = release.Status_FAILED @@ -282,3 +283,10 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R return updatedRelease, nil } + +// updateRelease performs an update from current to target release +func (s *ReleaseServer) updateRelease(current, target *release.Release, req *hapi.UpdateReleaseRequest) error { + c := bytes.NewBufferString(current.Manifest) + t := bytes.NewBufferString(target.Manifest) + return s.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) +} diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index 7e1f5e4c4..6f6f6c814 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -30,7 +30,7 @@ import ( func TestUpdateRelease(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -102,7 +102,7 @@ func TestUpdateRelease(t *testing.T) { func TestUpdateRelease_ResetValues(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -225,7 +225,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { func TestUpdateRelease_ReuseValues(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -262,7 +262,7 @@ func TestUpdateRelease_ResetReuseValues(t *testing.T) { // This verifies that when both reset and reuse are set, reset wins. rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -290,9 +290,8 @@ func TestUpdateRelease_ResetReuseValues(t *testing.T) { func TestUpdateReleaseFailure(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) - rs.env.KubeClient = newUpdateFailingKubeClient() - rs.Log = t.Logf + rs.Releases.Create(rel) + rs.KubeClient = newUpdateFailingKubeClient() req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -321,7 +320,7 @@ func TestUpdateReleaseFailure(t *testing.T) { t.Errorf("Expected description %q, got %q", expectedDescription, got) } - oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) + oldRelease, err := rs.Releases.Get(rel.Name, rel.Version) if err != nil { t.Errorf("Expected to be able to get previous release") } @@ -333,8 +332,7 @@ func TestUpdateReleaseFailure(t *testing.T) { func TestUpdateReleaseFailure_Force(t *testing.T) { rs := rsFixture() rel := namedReleaseStub("forceful-luke", release.Status_FAILED) - rs.env.Releases.Create(rel) - rs.Log = t.Logf + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -364,7 +362,7 @@ func TestUpdateReleaseFailure_Force(t *testing.T) { t.Errorf("Expected description %q, got %q", expectedDescription, got) } - oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) + oldRelease, err := rs.Releases.Get(rel.Name, rel.Version) if err != nil { t.Errorf("Expected to be able to get previous release") } @@ -376,7 +374,7 @@ func TestUpdateReleaseFailure_Force(t *testing.T) { func TestUpdateReleaseNoHooks(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -404,7 +402,7 @@ func TestUpdateReleaseNoHooks(t *testing.T) { func TestUpdateReleaseNoChanges(t *testing.T) { rs := rsFixture() rel := releaseStub() - rs.env.Releases.Create(rel) + rs.Releases.Create(rel) req := &hapi.UpdateReleaseRequest{ Name: rel.Name, @@ -419,9 +417,9 @@ func TestUpdateReleaseNoChanges(t *testing.T) { } func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res *release.Release) *release.Release { - storedRelease, err := rs.env.Releases.Get(res.Name, res.Version) + storedRelease, err := rs.Releases.Get(res.Name, res.Version) if err != nil { - t.Fatalf("Expected release for %s (%v).", res.Name, rs.env.Releases) + t.Fatalf("Expected release for %s (%v).", res.Name, rs.Releases) } if !reflect.DeepEqual(storedRelease, res) {