Commit 613f7e0d authored by Matt Butcher's avatar Matt Butcher Committed by GitHub

Merge pull request #2138 from technosophos/feat/1876-reuse-values

feat(helm): add --reuse-values flag to upgrade
parents bb010b97 daa39c26
......@@ -203,6 +203,9 @@ message UpdateReleaseRequest {
// wait, if true, will wait until all Pods, PVCs, and Services are in a ready state
// before marking the release as successful. It will wait for as long as timeout
bool wait = 9;
// ReuseValues will cause Tiller to reuse the values from the last release.
// This is ignored if reset_values is set.
bool reuse_values = 10;
}
// UpdateReleaseResponse is the response to an update request.
......
......@@ -72,6 +72,7 @@ type upgradeCmd struct {
version string
timeout int64
resetValues bool
reuseValues bool
wait bool
}
......@@ -114,6 +115,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&upgrade.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used")
f.Int64Var(&upgrade.timeout, "timeout", 300, "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)")
f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.")
f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, and Services are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
......@@ -177,6 +179,7 @@ func (u *upgradeCmd) run() error {
helm.UpgradeDisableHooks(u.disableHooks),
helm.UpgradeTimeout(u.timeout),
helm.ResetValues(u.resetValues),
helm.ReuseValues(u.reuseValues),
helm.UpgradeWait(u.wait))
if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
......
......@@ -109,6 +109,13 @@ func TestUpgradeCmd(t *testing.T) {
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 4, chart: ch2}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
},
{
name: "upgrade a release with --reuse-values",
args: []string{"funny-bunny", chartPath},
flags: []string{"--reuse-values", "true"},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 5, chart: ch2}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
},
{
name: "install a release with 'upgrade --install'",
args: []string{"zany-bunny", chartPath},
......
......@@ -155,6 +155,7 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
req.DisableHooks = h.opts.disableHooks
req.Recreate = h.opts.recreate
req.ResetValues = h.opts.resetValues
req.ReuseValues = h.opts.reuseValues
ctx := NewContext()
if h.opts.before != nil {
......
......@@ -66,6 +66,8 @@ type options struct {
histReq rls.GetHistoryRequest
// resetValues instructs Tiller to reset values to their defaults.
resetValues bool
// reuseValues instructs Tiller to reuse the values from the last release.
reuseValues bool
// release test options are applied directly to the test release history request
testReq rls.TestReleaseRequest
}
......@@ -323,6 +325,13 @@ func ResetValues(reset bool) UpdateOption {
}
}
// ReuseValues will (if true) trigger resetting the values to their original state.
func ReuseValues(reuse bool) UpdateOption {
return func(opts *options) {
opts.reuseValues = reuse
}
}
// UpgradeRecreate will (if true) recreate pods after upgrade.
func UpgradeRecreate(recreate bool) UpdateOption {
return func(opts *options) {
......
This diff is collapsed.
......@@ -354,13 +354,33 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
//
// This is skipped if the req.ResetValues flag is set, in which case the
// request values are not altered.
func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current *release.Release) {
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.")
return
return nil
}
// If req.Values is empty, but current. config is not, copy current into the
// 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")
// 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)
return err
}
nv, err := oldVals.YAML()
if err != nil {
return err
}
req.Chart.Values = &chart.Config{Raw: nv}
return nil
}
// If req.Values is empty, but current.Config is not, copy current into the
// request.
if (req.Values == nil || req.Values.Raw == "" || req.Values.Raw == "{}\n") &&
current.Config != nil &&
......@@ -369,6 +389,7 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current
log.Printf("Copying values from %s (v%d) to new release.", current.Name, current.Version)
req.Values = current.Config
}
return nil
}
// prepareUpdate builds an updated release for an update operation.
......@@ -388,7 +409,9 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
}
// If new values were not supplied in the upgrade, re-use the existing values.
s.reuseValues(req, currentRelease)
if err := s.reuseValues(req, currentRelease); err != nil {
return nil, nil, err
}
// Increment revision count. This is passed to templates, and also stored on
// the release object.
......
......@@ -717,7 +717,7 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected description %q, got %q", edesc, got)
}
}
func TestUpdateReleaseResetValues(t *testing.T) {
func TestUpdateRelease_ResetValues(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
rel := releaseStub()
......@@ -744,6 +744,71 @@ func TestUpdateReleaseResetValues(t *testing.T) {
}
}
func TestUpdateRelease_ReuseValues(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
req := &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "templates/hello", Data: []byte("hello: world")},
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
},
// Since reuseValues is set, this should get ignored.
Values: &chart.Config{Raw: "foo: bar\n"},
},
Values: &chart.Config{Raw: "name2: val2"},
ReuseValues: true,
}
res, err := rs.UpdateRelease(c, req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have been overwritten with the old value.
expect := "name: value\n"
if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw)
}
// This should have the newly-passed overrides.
expect = "name2: val2"
if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
}
}
func TestUpdateRelease_ResetReuseValues(t *testing.T) {
// This verifies that when both reset and reuse are set, reset wins.
c := helm.NewContext()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
req := &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "templates/hello", Data: []byte("hello: world")},
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
},
},
ResetValues: true,
ReuseValues: true,
}
res, err := rs.UpdateRelease(c, req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have been unset. Config: &chart.Config{Raw: `name: value`},
if res.Release.Config != nil && res.Release.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
}
}
func TestUpdateReleaseFailure(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment