|
|
|
@ -20,7 +20,6 @@ import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"path"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
@ -84,6 +83,7 @@ type ReleaseServer struct {
|
|
|
|
|
ReleaseModule
|
|
|
|
|
env *environment.Environment
|
|
|
|
|
clientset internalclientset.Interface
|
|
|
|
|
Log func(string, ...interface{})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewReleaseServer creates a new release server.
|
|
|
|
@ -101,6 +101,7 @@ func NewReleaseServer(env *environment.Environment, clientset internalclientset.
|
|
|
|
|
env: env,
|
|
|
|
|
clientset: clientset,
|
|
|
|
|
ReleaseModule: releaseModule,
|
|
|
|
|
Log: func(_ string, _ ...interface{}) {},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -268,7 +269,7 @@ func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease
|
|
|
|
|
// Skip errors if this is already deleted or failed.
|
|
|
|
|
return statusResp, nil
|
|
|
|
|
} else if err != nil {
|
|
|
|
|
log.Printf("warning: Get for %s failed: %v", rel.Name, err)
|
|
|
|
|
s.Log("warning: Get for %s failed: %v", rel.Name, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
rel.Info.Status.Resources = resp
|
|
|
|
@ -321,7 +322,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
|
|
|
|
|
res := &services.UpdateReleaseResponse{Release: updatedRelease}
|
|
|
|
|
|
|
|
|
|
if req.DryRun {
|
|
|
|
|
log.Printf("Dry run for %s", updatedRelease.Name)
|
|
|
|
|
s.Log("Dry run for %s", updatedRelease.Name)
|
|
|
|
|
res.Release.Info.Description = "Dry run complete"
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
@ -334,7 +335,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
|
|
|
|
|
}
|
|
|
|
|
if err := s.ReleaseModule.Update(originalRelease, updatedRelease, req, s.env); err != nil {
|
|
|
|
|
msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err)
|
|
|
|
|
log.Printf("warning: %s", msg)
|
|
|
|
|
s.Log("warning: %s", msg)
|
|
|
|
|
originalRelease.Info.Status.Code = release.Status_SUPERSEDED
|
|
|
|
|
updatedRelease.Info.Status.Code = release.Status_FAILED
|
|
|
|
|
updatedRelease.Info.Description = msg
|
|
|
|
@ -370,19 +371,19 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
|
|
|
|
|
func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current *release.Release) error {
|
|
|
|
|
if req.ResetValues {
|
|
|
|
|
// If ResetValues is set, we comletely ignore current.Config.
|
|
|
|
|
log.Print("Reset values to the chart's original version.")
|
|
|
|
|
s.Log("Reset values to the chart's original version.")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the ReuseValues flag is set, we always copy the old values over the new config's values.
|
|
|
|
|
if req.ReuseValues {
|
|
|
|
|
log.Print("Reusing the old release's values")
|
|
|
|
|
s.Log("Reusing the old release's values")
|
|
|
|
|
|
|
|
|
|
// We have to regenerate the old coalesced values:
|
|
|
|
|
oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
err := fmt.Errorf("failed to rebuild old values: %s", err)
|
|
|
|
|
log.Print(err)
|
|
|
|
|
s.Log("%s", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
nv, err := oldVals.YAML()
|
|
|
|
@ -399,7 +400,7 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current
|
|
|
|
|
current.Config != nil &&
|
|
|
|
|
current.Config.Raw != "" &&
|
|
|
|
|
current.Config.Raw != "{}\n" {
|
|
|
|
|
log.Printf("Copying values from %s (v%d) to new release.", current.Name, current.Version)
|
|
|
|
|
s.Log("Copying values from %s (v%d) to new release.", current.Name, current.Version)
|
|
|
|
|
req.Values = current.Config
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
@ -508,7 +509,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
|
|
|
|
|
res := &services.RollbackReleaseResponse{Release: targetRelease}
|
|
|
|
|
|
|
|
|
|
if req.DryRun {
|
|
|
|
|
log.Printf("Dry run for %s", targetRelease.Name)
|
|
|
|
|
s.Log("Dry run for %s", targetRelease.Name)
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -521,7 +522,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
|
|
|
|
|
|
|
|
|
|
if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil {
|
|
|
|
|
msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)
|
|
|
|
|
log.Printf("warning: %s", msg)
|
|
|
|
|
s.Log("warning: %s", msg)
|
|
|
|
|
currentRelease.Info.Status.Code = release.Status_SUPERSEDED
|
|
|
|
|
targetRelease.Info.Status.Code = release.Status_FAILED
|
|
|
|
|
targetRelease.Info.Description = msg
|
|
|
|
@ -565,7 +566,7 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*
|
|
|
|
|
rbv = crls.Version - 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Printf("rolling back %s (current: v%d, target: v%d)", req.Name, crls.Version, rbv)
|
|
|
|
|
s.Log("rolling back %s (current: v%d, target: v%d)", req.Name, crls.Version, rbv)
|
|
|
|
|
|
|
|
|
|
prls, err := s.env.Releases.Get(req.Name, rbv)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -617,7 +618,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
|
|
|
|
|
|
|
|
|
|
if st := rel.Info.Status.Code; reuse && (st == release.Status_DELETED || st == release.Status_FAILED) {
|
|
|
|
|
// Allowe re-use of names if the previous release is marked deleted.
|
|
|
|
|
log.Printf("reusing name %q", start)
|
|
|
|
|
s.Log("reusing name %q", start)
|
|
|
|
|
return start, nil
|
|
|
|
|
} else if reuse {
|
|
|
|
|
return "", errors.New("cannot re-use a name that is still in use")
|
|
|
|
@ -636,9 +637,9 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
|
|
|
|
|
if _, err := s.env.Releases.Get(name, 1); strings.Contains(err.Error(), "not found") {
|
|
|
|
|
return name, nil
|
|
|
|
|
}
|
|
|
|
|
log.Printf("info: Name %q is taken. Searching again.", name)
|
|
|
|
|
s.Log("info: Name %q is taken. Searching again.", name)
|
|
|
|
|
}
|
|
|
|
|
log.Printf("warning: No available release names found after %d tries", maxTries)
|
|
|
|
|
s.Log("warning: No available release names found after %d tries", maxTries)
|
|
|
|
|
return "ERROR", errors.New("no available release name found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -648,7 +649,7 @@ func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
|
|
|
|
|
if r, ok := s.env.EngineYard.Get(ch.Metadata.Engine); ok {
|
|
|
|
|
renderer = r
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("warning: %s requested non-existent template engine %s", ch.Metadata.Name, ch.Metadata.Engine)
|
|
|
|
|
s.Log("warning: %s requested non-existent template engine %s", ch.Metadata.Name, ch.Metadata.Engine)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return renderer
|
|
|
|
@ -658,7 +659,7 @@ func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
|
|
|
|
|
func (s *ReleaseServer) InstallRelease(c ctx.Context, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) {
|
|
|
|
|
rel, err := s.prepareRelease(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Failed install prepare step: %s", err)
|
|
|
|
|
s.Log("Failed install prepare step: %s", err)
|
|
|
|
|
res := &services.InstallReleaseResponse{Release: rel}
|
|
|
|
|
|
|
|
|
|
// On dry run, append the manifest contents to a failed release. This is
|
|
|
|
@ -671,7 +672,7 @@ func (s *ReleaseServer) InstallRelease(c ctx.Context, req *services.InstallRelea
|
|
|
|
|
|
|
|
|
|
res, err := s.performRelease(rel, req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Failed install perform step: %s", err)
|
|
|
|
|
s.Log("Failed install perform step: %s", err)
|
|
|
|
|
}
|
|
|
|
|
return res, err
|
|
|
|
|
}
|
|
|
|
@ -854,10 +855,10 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
|
|
|
|
|
func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) {
|
|
|
|
|
if reuse {
|
|
|
|
|
if err := s.env.Releases.Update(r); err != nil {
|
|
|
|
|
log.Printf("warning: Failed to update release %q: %s", r.Name, err)
|
|
|
|
|
s.Log("warning: Failed to update release %q: %s", r.Name, err)
|
|
|
|
|
}
|
|
|
|
|
} else if err := s.env.Releases.Create(r); err != nil {
|
|
|
|
|
log.Printf("warning: Failed to record release %q: %s", r.Name, err)
|
|
|
|
|
s.Log("warning: Failed to record release %q: %s", r.Name, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -866,7 +867,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
|
|
|
|
|
res := &services.InstallReleaseResponse{Release: r}
|
|
|
|
|
|
|
|
|
|
if req.DryRun {
|
|
|
|
|
log.Printf("Dry run for %s", r.Name)
|
|
|
|
|
s.Log("Dry run for %s", r.Name)
|
|
|
|
|
res.Release.Info.Description = "Dry run complete"
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
@ -901,7 +902,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
|
|
|
|
|
}
|
|
|
|
|
if err := s.ReleaseModule.Update(old, r, updateReq, s.env); err != nil {
|
|
|
|
|
msg := fmt.Sprintf("Release replace %q failed: %s", r.Name, err)
|
|
|
|
|
log.Printf("warning: %s", msg)
|
|
|
|
|
s.Log("warning: %s", msg)
|
|
|
|
|
old.Info.Status.Code = release.Status_SUPERSEDED
|
|
|
|
|
r.Info.Status.Code = release.Status_FAILED
|
|
|
|
|
r.Info.Description = msg
|
|
|
|
@ -915,7 +916,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
|
|
|
|
|
// regular manifests
|
|
|
|
|
if err := s.ReleaseModule.Create(r, req, s.env); err != nil {
|
|
|
|
|
msg := fmt.Sprintf("Release %q failed: %s", r.Name, err)
|
|
|
|
|
log.Printf("warning: %s", msg)
|
|
|
|
|
s.Log("warning: %s", msg)
|
|
|
|
|
r.Info.Status.Code = release.Status_FAILED
|
|
|
|
|
r.Info.Description = msg
|
|
|
|
|
s.recordRelease(r, false)
|
|
|
|
@ -927,7 +928,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
|
|
|
|
|
if !req.DisableHooks {
|
|
|
|
|
if err := s.execHook(r.Hooks, r.Name, r.Namespace, hooks.PostInstall, req.Timeout); err != nil {
|
|
|
|
|
msg := fmt.Sprintf("Release %q failed post-install: %s", r.Name, err)
|
|
|
|
|
log.Printf("warning: %s", msg)
|
|
|
|
|
s.Log("warning: %s", msg)
|
|
|
|
|
r.Info.Status.Code = release.Status_FAILED
|
|
|
|
|
r.Info.Description = msg
|
|
|
|
|
s.recordRelease(r, false)
|
|
|
|
@ -956,7 +957,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
|
|
|
|
|
return fmt.Errorf("unknown hook %q", hook)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Printf("Executing %s hooks for %s", hook, name)
|
|
|
|
|
s.Log("Executing %s hooks for %s", hook, name)
|
|
|
|
|
executingHooks := []*release.Hook{}
|
|
|
|
|
for _, h := range hs {
|
|
|
|
|
for _, e := range h.Events {
|
|
|
|
@ -972,20 +973,20 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
|
|
|
|
|
|
|
|
|
|
b := bytes.NewBufferString(h.Manifest)
|
|
|
|
|
if err := kubeCli.Create(namespace, b, timeout, false); err != nil {
|
|
|
|
|
log.Printf("warning: Release %q %s %s failed: %s", name, hook, h.Path, err)
|
|
|
|
|
s.Log("warning: Release %q %s %s failed: %s", name, hook, h.Path, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// No way to rewind a bytes.Buffer()?
|
|
|
|
|
b.Reset()
|
|
|
|
|
b.WriteString(h.Manifest)
|
|
|
|
|
if err := kubeCli.WatchUntilReady(namespace, b, timeout, false); err != nil {
|
|
|
|
|
log.Printf("warning: Release %q %s %s could not complete: %s", name, hook, h.Path, err)
|
|
|
|
|
s.Log("warning: Release %q %s %s could not complete: %s", name, hook, h.Path, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
h.LastRun = timeconv.Now()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Printf("Hooks complete for %s %s", hook, name)
|
|
|
|
|
s.Log("Hooks complete for %s %s", hook, name)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1007,7 +1008,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
defer s.env.Releases.UnlockRelease(req.Name)
|
|
|
|
|
|
|
|
|
|
if !ValidName.MatchString(req.Name) {
|
|
|
|
|
log.Printf("uninstall: Release not found: %s", req.Name)
|
|
|
|
|
s.Log("uninstall: Release not found: %s", req.Name)
|
|
|
|
|
return nil, errMissingRelease
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1017,7 +1018,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
|
|
|
|
|
rels, err := s.env.Releases.History(req.Name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("uninstall: Release not loaded: %s", req.Name)
|
|
|
|
|
s.Log("uninstall: Release not loaded: %s", req.Name)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if len(rels) < 1 {
|
|
|
|
@ -1032,7 +1033,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
if rel.Info.Status.Code == release.Status_DELETED {
|
|
|
|
|
if req.Purge {
|
|
|
|
|
if err := s.purgeReleases(rels...); err != nil {
|
|
|
|
|
log.Printf("uninstall: Failed to purge the release: %s", err)
|
|
|
|
|
s.Log("uninstall: Failed to purge the release: %s", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &services.UninstallReleaseResponse{Release: rel}, nil
|
|
|
|
@ -1040,7 +1041,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
return nil, fmt.Errorf("the release named %q is already deleted", req.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Printf("uninstall: Deleting %s", req.Name)
|
|
|
|
|
s.Log("uninstall: Deleting %s", req.Name)
|
|
|
|
|
rel.Info.Status.Code = release.Status_DELETING
|
|
|
|
|
rel.Info.Deleted = timeconv.Now()
|
|
|
|
|
rel.Info.Description = "Deletion in progress (or silently failed)"
|
|
|
|
@ -1055,7 +1056,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
// From here on out, the release is currently considered to be in Status_DELETING
|
|
|
|
|
// state.
|
|
|
|
|
if err := s.env.Releases.Update(rel); err != nil {
|
|
|
|
|
log.Printf("uninstall: Failed to store updated release: %s", err)
|
|
|
|
|
s.Log("uninstall: Failed to store updated release: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kept, errs := s.ReleaseModule.Delete(rel, req, s.env)
|
|
|
|
@ -1063,7 +1064,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
|
|
|
|
|
es := make([]string, 0, len(errs))
|
|
|
|
|
for _, e := range errs {
|
|
|
|
|
log.Printf("error: %v", e)
|
|
|
|
|
s.Log("error: %v", e)
|
|
|
|
|
es = append(es, e.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1079,13 +1080,13 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
|
|
|
|
|
if req.Purge {
|
|
|
|
|
err := s.purgeReleases(rels...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("uninstall: Failed to purge the release: %s", err)
|
|
|
|
|
s.Log("uninstall: Failed to purge the release: %s", err)
|
|
|
|
|
}
|
|
|
|
|
return res, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := s.env.Releases.Update(rel); err != nil {
|
|
|
|
|
log.Printf("uninstall: Failed to store updated release: %s", err)
|
|
|
|
|
s.Log("uninstall: Failed to store updated release: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(es) > 0 {
|
|
|
|
@ -1122,12 +1123,12 @@ func (s *ReleaseServer) RunReleaseTest(req *services.TestReleaseRequest, stream
|
|
|
|
|
|
|
|
|
|
tSuite, err := reltesting.NewTestSuite(rel)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Error creating test suite for %s", rel.Name)
|
|
|
|
|
s.Log("Error creating test suite for %s", rel.Name)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := tSuite.Run(testEnv); err != nil {
|
|
|
|
|
log.Printf("Error running test suite for %s", rel.Name)
|
|
|
|
|
s.Log("Error running test suite for %s", rel.Name)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1142,7 +1143,7 @@ func (s *ReleaseServer) RunReleaseTest(req *services.TestReleaseRequest, stream
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := s.env.Releases.Update(rel); err != nil {
|
|
|
|
|
log.Printf("test: Failed to store updated release: %s", err)
|
|
|
|
|
s.Log("test: Failed to store updated release: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|