ref(pkg/tiller): flatten package structure for storage

pull/3945/head
Adam Reese 8 years ago
parent 05da851eb9
commit 2a97768b5c
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -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
}

@ -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()),
}
}

@ -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)
}
}

@ -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)
}

@ -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)
}

@ -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
}

@ -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)

@ -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

@ -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(),

@ -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

@ -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)
}
}

@ -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
}

@ -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")
}

@ -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,14 +84,22 @@ 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
// 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,
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
}

@ -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,12 +486,12 @@ 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,
KubeClient: kubeClient,
Log: func(_ string, _ ...interface{}) {},
}
}

@ -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

@ -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)
}

@ -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)
}
}()

@ -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
}

@ -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",

@ -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)
}

@ -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) {

Loading…
Cancel
Save