Skip to content

Commit 4dd2178

Browse files
Michelle NooraliMatthew Fisher
authored andcommitted
fix(pkg/tiller): reuseValues combines all prev val
Resolves #3655 We were seeing that when running helm upgrade with the reuse-values flag enabled that you could end up in the position where overrides a.k.a computed values from previous revisions were not being saved on the updated revision. This left us in a weird position where some computed values would disappear mysteriously in the abyss. That happened because computed values from previous revisions weren't merged with the new computed values every time the reuse-values flag was used. This PR merges computed values from the previous revisions so you don't end up in that kind of conundrum. (cherry picked from commit 9266731)
1 parent 030d2c0 commit 4dd2178

File tree

2 files changed

+120
-2
lines changed

2 files changed

+120
-2
lines changed

pkg/tiller/release_server.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"strings"
2626

2727
"github.com/technosophos/moniker"
28+
"gopkg.in/yaml.v2"
2829
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930
"k8s.io/client-go/discovery"
3031
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
@@ -135,7 +136,22 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current
135136
if err != nil {
136137
return err
137138
}
139+
140+
// merge new values with current
141+
req.Values.Raw = current.Config.Raw + "\n" + req.Values.Raw
138142
req.Chart.Values = &chart.Config{Raw: nv}
143+
144+
// yaml unmarshal and marshal to remove duplicate keys
145+
y := map[string]interface{}{}
146+
if err := yaml.Unmarshal([]byte(req.Values.Raw), &y); err != nil {
147+
return err
148+
}
149+
data, err := yaml.Marshal(y)
150+
if err != nil {
151+
return err
152+
}
153+
154+
req.Values.Raw = string(data)
139155
return nil
140156
}
141157

pkg/tiller/release_update_test.go

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package tiller
1818

1919
import (
20+
"fmt"
2021
"strings"
2122
"testing"
2223

@@ -128,6 +129,107 @@ func TestUpdateRelease_ResetValues(t *testing.T) {
128129
}
129130
}
130131

132+
// This is a regression test for bug found in issue #3655
133+
func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
134+
c := helm.NewContext()
135+
rs := rsFixture()
136+
137+
installReq := &services.InstallReleaseRequest{
138+
Namespace: "spaced",
139+
Chart: &chart.Chart{
140+
Metadata: &chart.Metadata{Name: "hello"},
141+
Templates: []*chart.Template{
142+
{Name: "templates/hello", Data: []byte("hello: world")},
143+
{Name: "templates/hooks", Data: []byte(manifestWithHook)},
144+
},
145+
Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
146+
},
147+
Values: &chart.Config{Raw: "foo: bar"},
148+
}
149+
150+
fmt.Println("Running Install release with foo: bar override")
151+
installResp, err := rs.InstallRelease(c, installReq)
152+
if err != nil {
153+
t.Fatal(err)
154+
}
155+
156+
rel := installResp.Release
157+
req := &services.UpdateReleaseRequest{
158+
Name: rel.Name,
159+
Chart: &chart.Chart{
160+
Metadata: &chart.Metadata{Name: "hello"},
161+
Templates: []*chart.Template{
162+
{Name: "templates/hello", Data: []byte("hello: world")},
163+
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
164+
},
165+
Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
166+
},
167+
}
168+
169+
fmt.Println("Running Update release with no overrides and no reuse-values flag")
170+
res, err := rs.UpdateRelease(c, req)
171+
if err != nil {
172+
t.Fatalf("Failed updated: %s", err)
173+
}
174+
175+
expect := "foo: bar"
176+
if res.Release.Config != nil && res.Release.Config.Raw != expect {
177+
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
178+
}
179+
180+
rel = res.Release
181+
req = &services.UpdateReleaseRequest{
182+
Name: rel.Name,
183+
Chart: &chart.Chart{
184+
Metadata: &chart.Metadata{Name: "hello"},
185+
Templates: []*chart.Template{
186+
{Name: "templates/hello", Data: []byte("hello: world")},
187+
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
188+
},
189+
Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
190+
},
191+
Values: &chart.Config{Raw: "foo2: bar2"},
192+
ReuseValues: true,
193+
}
194+
195+
fmt.Println("Running Update release with foo2: bar2 override and reuse-values")
196+
res, err = rs.UpdateRelease(c, req)
197+
if err != nil {
198+
t.Fatalf("Failed updated: %s", err)
199+
}
200+
201+
// This should have the newly-passed overrides.
202+
expect = "foo: bar\nfoo2: bar2\n"
203+
if res.Release.Config != nil && res.Release.Config.Raw != expect {
204+
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
205+
}
206+
207+
rel = res.Release
208+
req = &services.UpdateReleaseRequest{
209+
Name: rel.Name,
210+
Chart: &chart.Chart{
211+
Metadata: &chart.Metadata{Name: "hello"},
212+
Templates: []*chart.Template{
213+
{Name: "templates/hello", Data: []byte("hello: world")},
214+
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
215+
},
216+
Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
217+
},
218+
Values: &chart.Config{Raw: "foo: baz"},
219+
ReuseValues: true,
220+
}
221+
222+
fmt.Println("Running Update release with foo=baz override with reuse-values flag")
223+
res, err = rs.UpdateRelease(c, req)
224+
if err != nil {
225+
t.Fatalf("Failed updated: %s", err)
226+
}
227+
expect = "foo: baz\nfoo2: bar2\n"
228+
if res.Release.Config != nil && res.Release.Config.Raw != expect {
229+
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
230+
}
231+
}
232+
131233
func TestUpdateRelease_ReuseValues(t *testing.T) {
132234
c := helm.NewContext()
133235
rs := rsFixture()
@@ -157,8 +259,8 @@ func TestUpdateRelease_ReuseValues(t *testing.T) {
157259
if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect {
158260
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw)
159261
}
160-
// This should have the newly-passed overrides.
161-
expect = "name2: val2"
262+
// This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub()
263+
expect = "name: value\nname2: val2"
162264
if res.Release.Config != nil && res.Release.Config.Raw != expect {
163265
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
164266
}

0 commit comments

Comments
 (0)