github.com/latiif/helm@v2.15.0+incompatible/pkg/tiller/release_update_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tiller 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/golang/protobuf/proto" 26 27 "k8s.io/helm/pkg/chartutil" 28 "k8s.io/helm/pkg/helm" 29 "k8s.io/helm/pkg/proto/hapi/chart" 30 "k8s.io/helm/pkg/proto/hapi/release" 31 "k8s.io/helm/pkg/proto/hapi/services" 32 ) 33 34 func TestUpdateRelease(t *testing.T) { 35 c := helm.NewContext() 36 rs := rsFixture() 37 rel := releaseStub() 38 rs.env.Releases.Create(rel) 39 40 req := &services.UpdateReleaseRequest{ 41 Name: rel.Name, 42 Chart: &chart.Chart{ 43 Metadata: &chart.Metadata{Name: "hello"}, 44 Templates: []*chart.Template{ 45 {Name: "templates/hello", Data: []byte("hello: world")}, 46 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 47 }, 48 }, 49 } 50 res, err := rs.UpdateRelease(c, req) 51 if err != nil { 52 t.Fatalf("Failed updated: %s", err) 53 } 54 55 if res.Release.Name == "" { 56 t.Errorf("Expected release name.") 57 } 58 59 if res.Release.Name != rel.Name { 60 t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name) 61 } 62 63 if res.Release.Namespace != rel.Namespace { 64 t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace) 65 } 66 67 updated := compareStoredAndReturnedRelease(t, *rs, *res) 68 69 if len(updated.Hooks) != 1 { 70 t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks)) 71 } 72 if updated.Hooks[0].Manifest != manifestWithUpgradeHooks { 73 t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest) 74 } 75 76 if updated.Hooks[0].Events[0] != release.Hook_POST_UPGRADE { 77 t.Errorf("Expected event 0 to be post upgrade") 78 } 79 80 if updated.Hooks[0].Events[1] != release.Hook_PRE_UPGRADE { 81 t.Errorf("Expected event 0 to be pre upgrade") 82 } 83 84 if len(updated.Manifest) == 0 { 85 t.Errorf("Expected manifest in %v", res) 86 } 87 88 if res.Release.Config == nil { 89 t.Errorf("Got release without config: %#v", res.Release) 90 } else if res.Release.Config.Raw != rel.Config.Raw { 91 t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw) 92 } 93 94 if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") { 95 t.Errorf("unexpected output: %s", updated.Manifest) 96 } 97 98 if res.Release.Version != 2 { 99 t.Errorf("Expected release version to be %v, got %v", 2, res.Release.Version) 100 } 101 102 edesc := "Upgrade complete" 103 if got := res.Release.Info.Description; got != edesc { 104 t.Errorf("Expected description %q, got %q", edesc, got) 105 } 106 } 107 func TestUpdateRelease_ResetValues(t *testing.T) { 108 c := helm.NewContext() 109 rs := rsFixture() 110 rel := releaseStub() 111 rs.env.Releases.Create(rel) 112 113 req := &services.UpdateReleaseRequest{ 114 Name: rel.Name, 115 Chart: &chart.Chart{ 116 Metadata: &chart.Metadata{Name: "hello"}, 117 Templates: []*chart.Template{ 118 {Name: "templates/hello", Data: []byte("hello: world")}, 119 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 120 }, 121 }, 122 ResetValues: true, 123 } 124 res, err := rs.UpdateRelease(c, req) 125 if err != nil { 126 t.Fatalf("Failed updated: %s", err) 127 } 128 // This should have been unset. Config: &chart.Config{Raw: `name: value`}, 129 if res.Release.Config != nil && res.Release.Config.Raw != "" { 130 t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw) 131 } 132 } 133 134 func TestUpdateRelease_ReuseValuesWithNoValues(t *testing.T) { 135 c := helm.NewContext() 136 rs := rsFixture() 137 138 installReq := &services.InstallReleaseRequest{ 139 Namespace: "spaced", 140 Chart: &chart.Chart{ 141 Metadata: &chart.Metadata{Name: "hello"}, 142 Templates: []*chart.Template{ 143 {Name: "templates/hello", Data: []byte("hello: world")}, 144 {Name: "templates/hooks", Data: []byte(manifestWithHook)}, 145 }, 146 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 147 }, 148 } 149 150 installResp, err := rs.InstallRelease(c, installReq) 151 if err != nil { 152 t.Fatal(err) 153 } 154 155 rel := installResp.Release 156 req := &services.UpdateReleaseRequest{ 157 Name: rel.Name, 158 Chart: &chart.Chart{ 159 Metadata: &chart.Metadata{Name: "hello"}, 160 Templates: []*chart.Template{ 161 {Name: "templates/hello", Data: []byte("hello: world")}, 162 }, 163 }, 164 Values: &chart.Config{Raw: "{}\n"}, 165 ReuseValues: true, 166 } 167 168 if _, err := rs.UpdateRelease(c, req); err != nil { 169 t.Fatalf("Failed updated: %s", err) 170 } 171 } 172 173 func TestUpdateRelease_NestedReuseValues(t *testing.T) { 174 c := helm.NewContext() 175 rs := rsFixture() 176 177 installReq := &services.InstallReleaseRequest{ 178 Namespace: "spaced", 179 Chart: &chart.Chart{ 180 Metadata: &chart.Metadata{Name: "hello"}, 181 Templates: []*chart.Template{ 182 {Name: "templates/hello", Data: []byte("hello: world")}, 183 }, 184 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 185 }, 186 Values: &chart.Config{Raw: ` 187 foo: bar 188 root: 189 nested: nestedValue 190 anotherNested: anotherNestedValue 191 `}, 192 } 193 194 installResp, err := rs.InstallRelease(c, installReq) 195 if err != nil { 196 t.Fatal(err) 197 } 198 199 rel := installResp.Release 200 req := &services.UpdateReleaseRequest{ 201 Name: rel.Name, 202 Chart: &chart.Chart{ 203 Metadata: &chart.Metadata{Name: "hello"}, 204 Templates: []*chart.Template{ 205 {Name: "templates/hello", Data: []byte("hello: world")}, 206 }, 207 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 208 }, 209 Values: &chart.Config{Raw: ` 210 root: 211 nested: newNestedValue 212 `}, 213 ReuseValues: true, 214 } 215 216 res, err := rs.UpdateRelease(c, req) 217 if err != nil { 218 t.Fatalf("Failed updated: %s", err) 219 } 220 221 expect, _ := chartutil.ReadValues([]byte(` 222 foo: bar 223 root: 224 nested: newNestedValue 225 anotherNested: anotherNestedValue 226 `)) 227 228 requestConfig, err := chartutil.ReadValues([]byte(res.Release.Config.Raw)) 229 if err != nil { 230 t.Errorf("Request config could not be parsed: %v", err) 231 } 232 233 if !reflect.DeepEqual(expect, requestConfig) { 234 t.Errorf("Expected request config to be %v, got %v", expect, requestConfig) 235 } 236 } 237 238 // This is a regression test for bug found in issue #3655 239 func TestUpdateRelease_ComplexReuseValues(t *testing.T) { 240 c := helm.NewContext() 241 rs := rsFixture() 242 243 installReq := &services.InstallReleaseRequest{ 244 Namespace: "spaced", 245 Chart: &chart.Chart{ 246 Metadata: &chart.Metadata{Name: "hello"}, 247 Templates: []*chart.Template{ 248 {Name: "templates/hello", Data: []byte("hello: world")}, 249 {Name: "templates/hooks", Data: []byte(manifestWithHook)}, 250 }, 251 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 252 }, 253 Values: &chart.Config{Raw: "foo: bar"}, 254 } 255 256 fmt.Println("Running Install release with foo: bar override") 257 installResp, err := rs.InstallRelease(c, installReq) 258 if err != nil { 259 t.Fatal(err) 260 } 261 262 rel := installResp.Release 263 req := &services.UpdateReleaseRequest{ 264 Name: rel.Name, 265 Chart: &chart.Chart{ 266 Metadata: &chart.Metadata{Name: "hello"}, 267 Templates: []*chart.Template{ 268 {Name: "templates/hello", Data: []byte("hello: world")}, 269 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 270 }, 271 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 272 }, 273 } 274 275 fmt.Println("Running Update release with no overrides and no reuse-values flag") 276 res, err := rs.UpdateRelease(c, req) 277 if err != nil { 278 t.Fatalf("Failed updated: %s", err) 279 } 280 281 expect := "foo: bar" 282 if res.Release.Config != nil && res.Release.Config.Raw != expect { 283 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) 284 } 285 286 rel = res.Release 287 req = &services.UpdateReleaseRequest{ 288 Name: rel.Name, 289 Chart: &chart.Chart{ 290 Metadata: &chart.Metadata{Name: "hello"}, 291 Templates: []*chart.Template{ 292 {Name: "templates/hello", Data: []byte("hello: world")}, 293 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 294 }, 295 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 296 }, 297 Values: &chart.Config{Raw: "foo2: bar2"}, 298 ReuseValues: true, 299 } 300 301 fmt.Println("Running Update release with foo2: bar2 override and reuse-values") 302 res, err = rs.UpdateRelease(c, req) 303 if err != nil { 304 t.Fatalf("Failed updated: %s", err) 305 } 306 307 // This should have the newly-passed overrides. 308 expect = "foo: bar\nfoo2: bar2\n" 309 if res.Release.Config != nil && res.Release.Config.Raw != expect { 310 t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) 311 } 312 313 rel = res.Release 314 req = &services.UpdateReleaseRequest{ 315 Name: rel.Name, 316 Chart: &chart.Chart{ 317 Metadata: &chart.Metadata{Name: "hello"}, 318 Templates: []*chart.Template{ 319 {Name: "templates/hello", Data: []byte("hello: world")}, 320 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 321 }, 322 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 323 }, 324 Values: &chart.Config{Raw: "foo: baz"}, 325 ReuseValues: true, 326 } 327 328 fmt.Println("Running Update release with foo=baz override with reuse-values flag") 329 res, err = rs.UpdateRelease(c, req) 330 if err != nil { 331 t.Fatalf("Failed updated: %s", err) 332 } 333 expect = "foo: baz\nfoo2: bar2\n" 334 if res.Release.Config != nil && res.Release.Config.Raw != expect { 335 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) 336 } 337 } 338 339 func TestUpdateRelease_ReuseValues(t *testing.T) { 340 c := helm.NewContext() 341 rs := rsFixture() 342 rel := releaseStub() 343 rs.env.Releases.Create(rel) 344 345 req := &services.UpdateReleaseRequest{ 346 Name: rel.Name, 347 Chart: &chart.Chart{ 348 Metadata: &chart.Metadata{Name: "hello"}, 349 Templates: []*chart.Template{ 350 {Name: "templates/hello", Data: []byte("hello: world")}, 351 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 352 }, 353 // Since reuseValues is set, this should get ignored. 354 Values: &chart.Config{Raw: "foo: bar\n"}, 355 }, 356 Values: &chart.Config{Raw: "name2: val2"}, 357 ReuseValues: true, 358 } 359 res, err := rs.UpdateRelease(c, req) 360 if err != nil { 361 t.Fatalf("Failed updated: %s", err) 362 } 363 // This should have been overwritten with the old value. 364 expect := "name: value\n" 365 if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect { 366 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw) 367 } 368 // This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub() 369 expect = "name: value\nname2: val2\n" 370 if res.Release.Config != nil && res.Release.Config.Raw != expect { 371 t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) 372 } 373 compareStoredAndReturnedRelease(t, *rs, *res) 374 } 375 376 func TestUpdateRelease_ResetReuseValues(t *testing.T) { 377 // This verifies that when both reset and reuse are set, reset wins. 378 c := helm.NewContext() 379 rs := rsFixture() 380 rel := releaseStub() 381 rs.env.Releases.Create(rel) 382 383 req := &services.UpdateReleaseRequest{ 384 Name: rel.Name, 385 Chart: &chart.Chart{ 386 Metadata: &chart.Metadata{Name: "hello"}, 387 Templates: []*chart.Template{ 388 {Name: "templates/hello", Data: []byte("hello: world")}, 389 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 390 }, 391 }, 392 ResetValues: true, 393 ReuseValues: true, 394 } 395 res, err := rs.UpdateRelease(c, req) 396 if err != nil { 397 t.Fatalf("Failed updated: %s", err) 398 } 399 // This should have been unset. Config: &chart.Config{Raw: `name: value`}, 400 if res.Release.Config != nil && res.Release.Config.Raw != "" { 401 t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw) 402 } 403 compareStoredAndReturnedRelease(t, *rs, *res) 404 } 405 406 func TestUpdateReleaseFailure(t *testing.T) { 407 c := helm.NewContext() 408 rs := rsFixture() 409 rel := releaseStub() 410 rs.env.Releases.Create(rel) 411 rs.env.KubeClient = newUpdateFailingKubeClient() 412 rs.Log = t.Logf 413 414 req := &services.UpdateReleaseRequest{ 415 Name: rel.Name, 416 DisableHooks: true, 417 Chart: &chart.Chart{ 418 Metadata: &chart.Metadata{Name: "hello"}, 419 Templates: []*chart.Template{ 420 {Name: "templates/something", Data: []byte("hello: world")}, 421 }, 422 }, 423 } 424 425 res, err := rs.UpdateRelease(c, req) 426 if err == nil { 427 t.Error("Expected failed update") 428 } 429 430 if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_FAILED { 431 t.Errorf("Expected FAILED release. Got %d", updatedStatus) 432 } 433 434 compareStoredAndReturnedRelease(t, *rs, *res) 435 436 expectedDescription := "Upgrade \"angry-panda\" failed: Failed update in kube client" 437 if got := res.Release.Info.Description; got != expectedDescription { 438 t.Errorf("Expected description %q, got %q", expectedDescription, got) 439 } 440 441 oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) 442 if err != nil { 443 t.Errorf("Expected to be able to get previous release") 444 } 445 if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DEPLOYED { 446 t.Errorf("Expected Deployed status on previous Release version. Got %v", oldStatus) 447 } 448 } 449 450 func TestUpdateReleaseFailure_Force(t *testing.T) { 451 c := helm.NewContext() 452 rs := rsFixture() 453 rel := namedReleaseStub("forceful-luke", release.Status_FAILED) 454 rs.env.Releases.Create(rel) 455 rs.Log = t.Logf 456 457 req := &services.UpdateReleaseRequest{ 458 Name: rel.Name, 459 DisableHooks: true, 460 Chart: &chart.Chart{ 461 Metadata: &chart.Metadata{Name: "hello"}, 462 Templates: []*chart.Template{ 463 {Name: "templates/something", Data: []byte("text: 'Did you ever hear the tragedy of Darth Plagueis the Wise? I thought not. It’s not a story the Jedi would tell you. It’s a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and so wise he could use the Force to influence the Midichlorians to create life... He had such a knowledge of the Dark Side that he could even keep the ones he cared about from dying. The Dark Side of the Force is a pathway to many abilities some consider to be unnatural. He became so powerful... The only thing he was afraid of was losing his power, which eventually, of course, he did. Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep. Ironic. He could save others from death, but not himself.'")}, 464 }, 465 }, 466 Force: true, 467 } 468 469 res, err := rs.UpdateRelease(c, req) 470 if err != nil { 471 t.Errorf("Expected successful update, got %v", err) 472 } 473 474 if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_DEPLOYED { 475 t.Errorf("Expected DEPLOYED release. Got %d", updatedStatus) 476 } 477 478 compareStoredAndReturnedRelease(t, *rs, *res) 479 480 expectedDescription := "Upgrade complete" 481 if got := res.Release.Info.Description; got != expectedDescription { 482 t.Errorf("Expected description %q, got %q", expectedDescription, got) 483 } 484 485 oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) 486 if err != nil { 487 t.Errorf("Expected to be able to get previous release") 488 } 489 if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DELETED { 490 t.Errorf("Expected Deleted status on previous Release version. Got %v", oldStatus) 491 } 492 } 493 494 func TestUpdateReleaseNoHooks(t *testing.T) { 495 c := helm.NewContext() 496 rs := rsFixture() 497 rel := releaseStub() 498 rs.env.Releases.Create(rel) 499 500 req := &services.UpdateReleaseRequest{ 501 Name: rel.Name, 502 DisableHooks: true, 503 Chart: &chart.Chart{ 504 Metadata: &chart.Metadata{Name: "hello"}, 505 Templates: []*chart.Template{ 506 {Name: "templates/hello", Data: []byte("hello: world")}, 507 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 508 }, 509 }, 510 } 511 512 res, err := rs.UpdateRelease(c, req) 513 if err != nil { 514 t.Fatalf("Failed updated: %s", err) 515 } 516 517 if hl := res.Release.Hooks[0].LastRun; hl != nil { 518 t.Errorf("Expected that no hooks were run. Got %d", hl) 519 } 520 521 } 522 523 func TestUpdateReleaseNoChanges(t *testing.T) { 524 c := helm.NewContext() 525 rs := rsFixture() 526 rel := releaseStub() 527 rs.env.Releases.Create(rel) 528 529 req := &services.UpdateReleaseRequest{ 530 Name: rel.Name, 531 DisableHooks: true, 532 Chart: rel.GetChart(), 533 } 534 535 _, err := rs.UpdateRelease(c, req) 536 if err != nil { 537 t.Fatalf("Failed updated: %s", err) 538 } 539 } 540 541 func TestUpdateReleaseCustomDescription(t *testing.T) { 542 c := helm.NewContext() 543 rs := rsFixture() 544 rel := releaseStub() 545 rs.env.Releases.Create(rel) 546 547 customDescription := "foo" 548 549 req := &services.UpdateReleaseRequest{ 550 Name: rel.Name, 551 Chart: rel.GetChart(), 552 Description: customDescription, 553 } 554 555 res, err := rs.UpdateRelease(c, req) 556 if err != nil { 557 t.Fatalf("Failed updated: %s", err) 558 } 559 if res.Release.Info.Description != customDescription { 560 t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description) 561 } 562 compareStoredAndReturnedRelease(t, *rs, *res) 563 } 564 565 func TestUpdateReleaseCustomDescription_Force(t *testing.T) { 566 c := helm.NewContext() 567 rs := rsFixture() 568 rel := releaseStub() 569 rs.env.Releases.Create(rel) 570 571 customDescription := "foo" 572 573 req := &services.UpdateReleaseRequest{ 574 Name: rel.Name, 575 Chart: rel.GetChart(), 576 Force: true, 577 Description: customDescription, 578 } 579 580 res, err := rs.UpdateRelease(c, req) 581 if err != nil { 582 t.Fatalf("Failed updated: %s", err) 583 } 584 if res.Release.Info.Description != customDescription { 585 t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description) 586 } 587 compareStoredAndReturnedRelease(t, *rs, *res) 588 } 589 590 func TestUpdateReleasePendingInstall_Force(t *testing.T) { 591 c := helm.NewContext() 592 rs := rsFixture() 593 rel := namedReleaseStub("forceful-luke", release.Status_PENDING_INSTALL) 594 rs.env.Releases.Create(rel) 595 596 req := &services.UpdateReleaseRequest{ 597 Name: rel.Name, 598 Chart: rel.GetChart(), 599 Force: true, 600 } 601 602 _, err := rs.UpdateRelease(c, req) 603 if err == nil { 604 t.Error("Expected failed update") 605 } 606 607 expectedError := "a release named forceful-luke is in use, cannot re-use a name that is still in use" 608 got := err.Error() 609 if err.Error() != expectedError { 610 t.Errorf("Expected error %q, got %q", expectedError, got) 611 } 612 } 613 614 func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release { 615 storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version) 616 if err != nil { 617 t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases) 618 } 619 620 if !proto.Equal(storedRelease, res.Release) { 621 t.Errorf("Stored release doesn't match returned Release") 622 } 623 624 return storedRelease 625 }