github.com/koderover/helm@v2.17.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 TestUpdateReleasePendingError(t *testing.T) { 108 c := helm.NewContext() 109 rs := rsFixture() 110 rel := releaseStub() 111 rs.env.Releases.Create(rel) 112 rel2 := releaseStub() 113 rel2.Info.Status.Code = release.Status_PENDING_UPGRADE 114 rel2.Version = 2 115 rs.env.Releases.Create(rel2) 116 117 req := &services.UpdateReleaseRequest{ 118 Name: rel.Name, 119 Chart: &chart.Chart{ 120 Metadata: &chart.Metadata{Name: "hello"}, 121 Templates: []*chart.Template{ 122 {Name: "templates/hello", Data: []byte("hello: world")}, 123 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 124 }, 125 }, 126 } 127 _, err := rs.UpdateRelease(c, req) 128 if err == nil { 129 t.Fatalf("Expected failure to update") 130 } 131 } 132 func TestUpdateRelease_ResetValues(t *testing.T) { 133 c := helm.NewContext() 134 rs := rsFixture() 135 rel := releaseStub() 136 rs.env.Releases.Create(rel) 137 138 req := &services.UpdateReleaseRequest{ 139 Name: rel.Name, 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(manifestWithUpgradeHooks)}, 145 }, 146 }, 147 ResetValues: true, 148 } 149 res, err := rs.UpdateRelease(c, req) 150 if err != nil { 151 t.Fatalf("Failed updated: %s", err) 152 } 153 // This should have been unset. Config: &chart.Config{Raw: `name: value`}, 154 if res.Release.Config != nil && res.Release.Config.Raw != "" { 155 t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw) 156 } 157 } 158 159 func TestUpdateRelease_ReuseValuesWithNoValues(t *testing.T) { 160 c := helm.NewContext() 161 rs := rsFixture() 162 163 installReq := &services.InstallReleaseRequest{ 164 Namespace: "spaced", 165 Chart: &chart.Chart{ 166 Metadata: &chart.Metadata{Name: "hello"}, 167 Templates: []*chart.Template{ 168 {Name: "templates/hello", Data: []byte("hello: world")}, 169 {Name: "templates/hooks", Data: []byte(manifestWithHook)}, 170 }, 171 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 172 }, 173 } 174 175 installResp, err := rs.InstallRelease(c, installReq) 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 rel := installResp.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 }, 188 }, 189 Values: &chart.Config{Raw: "{}\n"}, 190 ReuseValues: true, 191 } 192 193 if _, err := rs.UpdateRelease(c, req); err != nil { 194 t.Fatalf("Failed updated: %s", err) 195 } 196 } 197 198 func TestUpdateRelease_NestedReuseValues(t *testing.T) { 199 c := helm.NewContext() 200 rs := rsFixture() 201 202 installReq := &services.InstallReleaseRequest{ 203 Namespace: "spaced", 204 Chart: &chart.Chart{ 205 Metadata: &chart.Metadata{Name: "hello"}, 206 Templates: []*chart.Template{ 207 {Name: "templates/hello", Data: []byte("hello: world")}, 208 }, 209 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 210 }, 211 Values: &chart.Config{Raw: ` 212 foo: bar 213 root: 214 nested: nestedValue 215 anotherNested: anotherNestedValue 216 `}, 217 } 218 219 installResp, err := rs.InstallRelease(c, installReq) 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 rel := installResp.Release 225 req := &services.UpdateReleaseRequest{ 226 Name: rel.Name, 227 Chart: &chart.Chart{ 228 Metadata: &chart.Metadata{Name: "hello"}, 229 Templates: []*chart.Template{ 230 {Name: "templates/hello", Data: []byte("hello: world")}, 231 }, 232 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 233 }, 234 Values: &chart.Config{Raw: ` 235 root: 236 nested: newNestedValue 237 `}, 238 ReuseValues: true, 239 } 240 241 res, err := rs.UpdateRelease(c, req) 242 if err != nil { 243 t.Fatalf("Failed updated: %s", err) 244 } 245 246 expect, _ := chartutil.ReadValues([]byte(` 247 foo: bar 248 root: 249 nested: newNestedValue 250 anotherNested: anotherNestedValue 251 `)) 252 253 requestConfig, err := chartutil.ReadValues([]byte(res.Release.Config.Raw)) 254 if err != nil { 255 t.Errorf("Request config could not be parsed: %v", err) 256 } 257 258 if !reflect.DeepEqual(expect, requestConfig) { 259 t.Errorf("Expected request config to be %v, got %v", expect, requestConfig) 260 } 261 } 262 263 // This is a regression test for bug found in issue #3655 264 func TestUpdateRelease_ComplexReuseValues(t *testing.T) { 265 c := helm.NewContext() 266 rs := rsFixture() 267 268 installReq := &services.InstallReleaseRequest{ 269 Namespace: "spaced", 270 Chart: &chart.Chart{ 271 Metadata: &chart.Metadata{Name: "hello"}, 272 Templates: []*chart.Template{ 273 {Name: "templates/hello", Data: []byte("hello: world")}, 274 {Name: "templates/hooks", Data: []byte(manifestWithHook)}, 275 }, 276 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 277 }, 278 Values: &chart.Config{Raw: "foo: bar"}, 279 } 280 281 fmt.Println("Running Install release with foo: bar override") 282 installResp, err := rs.InstallRelease(c, installReq) 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 rel := installResp.Release 288 req := &services.UpdateReleaseRequest{ 289 Name: rel.Name, 290 Chart: &chart.Chart{ 291 Metadata: &chart.Metadata{Name: "hello"}, 292 Templates: []*chart.Template{ 293 {Name: "templates/hello", Data: []byte("hello: world")}, 294 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 295 }, 296 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 297 }, 298 } 299 300 fmt.Println("Running Update release with no overrides and no reuse-values flag") 301 res, err := rs.UpdateRelease(c, req) 302 if err != nil { 303 t.Fatalf("Failed updated: %s", err) 304 } 305 306 expect := "foo: bar" 307 if res.Release.Config != nil && res.Release.Config.Raw != expect { 308 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) 309 } 310 311 rel = res.Release 312 req = &services.UpdateReleaseRequest{ 313 Name: rel.Name, 314 Chart: &chart.Chart{ 315 Metadata: &chart.Metadata{Name: "hello"}, 316 Templates: []*chart.Template{ 317 {Name: "templates/hello", Data: []byte("hello: world")}, 318 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 319 }, 320 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 321 }, 322 Values: &chart.Config{Raw: "foo2: bar2"}, 323 ReuseValues: true, 324 } 325 326 fmt.Println("Running Update release with foo2: bar2 override and reuse-values") 327 res, err = rs.UpdateRelease(c, req) 328 if err != nil { 329 t.Fatalf("Failed updated: %s", err) 330 } 331 332 // This should have the newly-passed overrides. 333 expect = "foo: bar\nfoo2: bar2\n" 334 if res.Release.Config != nil && res.Release.Config.Raw != expect { 335 t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) 336 } 337 338 rel = res.Release 339 req = &services.UpdateReleaseRequest{ 340 Name: rel.Name, 341 Chart: &chart.Chart{ 342 Metadata: &chart.Metadata{Name: "hello"}, 343 Templates: []*chart.Template{ 344 {Name: "templates/hello", Data: []byte("hello: world")}, 345 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 346 }, 347 Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, 348 }, 349 Values: &chart.Config{Raw: "foo: baz"}, 350 ReuseValues: true, 351 } 352 353 fmt.Println("Running Update release with foo=baz override with reuse-values flag") 354 res, err = rs.UpdateRelease(c, req) 355 if err != nil { 356 t.Fatalf("Failed updated: %s", err) 357 } 358 expect = "foo: baz\nfoo2: bar2\n" 359 if res.Release.Config != nil && res.Release.Config.Raw != expect { 360 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) 361 } 362 } 363 364 func TestUpdateRelease_ReuseValues(t *testing.T) { 365 c := helm.NewContext() 366 rs := rsFixture() 367 rel := releaseStub() 368 rs.env.Releases.Create(rel) 369 370 req := &services.UpdateReleaseRequest{ 371 Name: rel.Name, 372 Chart: &chart.Chart{ 373 Metadata: &chart.Metadata{Name: "hello"}, 374 Templates: []*chart.Template{ 375 {Name: "templates/hello", Data: []byte("hello: world")}, 376 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 377 }, 378 // Since reuseValues is set, this should get ignored. 379 Values: &chart.Config{Raw: "foo: bar\n"}, 380 }, 381 Values: &chart.Config{Raw: "name2: val2"}, 382 ReuseValues: true, 383 } 384 res, err := rs.UpdateRelease(c, req) 385 if err != nil { 386 t.Fatalf("Failed updated: %s", err) 387 } 388 // This should have been overwritten with the old value. 389 expect := "name: value\n" 390 if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect { 391 t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw) 392 } 393 // This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub() 394 expect = "name: value\nname2: val2\n" 395 if res.Release.Config != nil && res.Release.Config.Raw != expect { 396 t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) 397 } 398 compareStoredAndReturnedRelease(t, *rs, *res) 399 } 400 401 func TestUpdateRelease_ResetReuseValues(t *testing.T) { 402 // This verifies that when both reset and reuse are set, reset wins. 403 c := helm.NewContext() 404 rs := rsFixture() 405 rel := releaseStub() 406 rs.env.Releases.Create(rel) 407 408 req := &services.UpdateReleaseRequest{ 409 Name: rel.Name, 410 Chart: &chart.Chart{ 411 Metadata: &chart.Metadata{Name: "hello"}, 412 Templates: []*chart.Template{ 413 {Name: "templates/hello", Data: []byte("hello: world")}, 414 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 415 }, 416 }, 417 ResetValues: true, 418 ReuseValues: true, 419 } 420 res, err := rs.UpdateRelease(c, req) 421 if err != nil { 422 t.Fatalf("Failed updated: %s", err) 423 } 424 // This should have been unset. Config: &chart.Config{Raw: `name: value`}, 425 if res.Release.Config != nil && res.Release.Config.Raw != "" { 426 t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw) 427 } 428 compareStoredAndReturnedRelease(t, *rs, *res) 429 } 430 431 func TestUpdateReleaseFailure(t *testing.T) { 432 c := helm.NewContext() 433 rs := rsFixture() 434 rel := releaseStub() 435 rs.env.Releases.Create(rel) 436 rs.env.KubeClient = newUpdateFailingKubeClient() 437 rs.Log = t.Logf 438 439 req := &services.UpdateReleaseRequest{ 440 Name: rel.Name, 441 DisableHooks: true, 442 Chart: &chart.Chart{ 443 Metadata: &chart.Metadata{Name: "hello"}, 444 Templates: []*chart.Template{ 445 {Name: "templates/something", Data: []byte("hello: world")}, 446 }, 447 }, 448 } 449 450 res, err := rs.UpdateRelease(c, req) 451 if err == nil { 452 t.Error("Expected failed update") 453 } 454 455 if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_FAILED { 456 t.Errorf("Expected FAILED release. Got %d", updatedStatus) 457 } 458 459 compareStoredAndReturnedRelease(t, *rs, *res) 460 461 expectedDescription := "Upgrade \"angry-panda\" failed: Failed update in kube client" 462 if got := res.Release.Info.Description; got != expectedDescription { 463 t.Errorf("Expected description %q, got %q", expectedDescription, got) 464 } 465 466 oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) 467 if err != nil { 468 t.Errorf("Expected to be able to get previous release") 469 } 470 if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DEPLOYED { 471 t.Errorf("Expected Deployed status on previous Release version. Got %v", oldStatus) 472 } 473 } 474 475 func TestUpdateReleaseFailure_Force(t *testing.T) { 476 c := helm.NewContext() 477 rs := rsFixture() 478 rel := namedReleaseStub("forceful-luke", release.Status_FAILED) 479 rs.env.Releases.Create(rel) 480 rs.Log = t.Logf 481 482 req := &services.UpdateReleaseRequest{ 483 Name: rel.Name, 484 DisableHooks: true, 485 Chart: &chart.Chart{ 486 Metadata: &chart.Metadata{Name: "hello"}, 487 Templates: []*chart.Template{ 488 {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.'")}, 489 }, 490 }, 491 Force: true, 492 } 493 494 res, err := rs.UpdateRelease(c, req) 495 if err != nil { 496 t.Errorf("Expected successful update, got %v", err) 497 } 498 499 if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_DEPLOYED { 500 t.Errorf("Expected DEPLOYED release. Got %d", updatedStatus) 501 } 502 503 compareStoredAndReturnedRelease(t, *rs, *res) 504 505 expectedDescription := "Upgrade complete" 506 if got := res.Release.Info.Description; got != expectedDescription { 507 t.Errorf("Expected description %q, got %q", expectedDescription, got) 508 } 509 510 oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version) 511 if err != nil { 512 t.Errorf("Expected to be able to get previous release") 513 } 514 if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DELETED { 515 t.Errorf("Expected Deleted status on previous Release version. Got %v", oldStatus) 516 } 517 } 518 519 func TestUpdateReleaseNoHooks(t *testing.T) { 520 c := helm.NewContext() 521 rs := rsFixture() 522 rel := releaseStub() 523 rs.env.Releases.Create(rel) 524 525 req := &services.UpdateReleaseRequest{ 526 Name: rel.Name, 527 DisableHooks: true, 528 Chart: &chart.Chart{ 529 Metadata: &chart.Metadata{Name: "hello"}, 530 Templates: []*chart.Template{ 531 {Name: "templates/hello", Data: []byte("hello: world")}, 532 {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, 533 }, 534 }, 535 } 536 537 res, err := rs.UpdateRelease(c, req) 538 if err != nil { 539 t.Fatalf("Failed updated: %s", err) 540 } 541 542 if hl := res.Release.Hooks[0].LastRun; hl != nil { 543 t.Errorf("Expected that no hooks were run. Got %d", hl) 544 } 545 546 } 547 548 func TestUpdateReleaseNoChanges(t *testing.T) { 549 c := helm.NewContext() 550 rs := rsFixture() 551 rel := releaseStub() 552 rs.env.Releases.Create(rel) 553 554 req := &services.UpdateReleaseRequest{ 555 Name: rel.Name, 556 DisableHooks: true, 557 Chart: rel.GetChart(), 558 } 559 560 _, err := rs.UpdateRelease(c, req) 561 if err != nil { 562 t.Fatalf("Failed updated: %s", err) 563 } 564 } 565 566 func TestUpdateReleaseCustomDescription(t *testing.T) { 567 c := helm.NewContext() 568 rs := rsFixture() 569 rel := releaseStub() 570 rs.env.Releases.Create(rel) 571 572 customDescription := "foo" 573 574 req := &services.UpdateReleaseRequest{ 575 Name: rel.Name, 576 Chart: rel.GetChart(), 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 TestUpdateReleaseCustomDescription_Force(t *testing.T) { 591 c := helm.NewContext() 592 rs := rsFixture() 593 rel := releaseStub() 594 rs.env.Releases.Create(rel) 595 596 customDescription := "foo" 597 598 req := &services.UpdateReleaseRequest{ 599 Name: rel.Name, 600 Chart: rel.GetChart(), 601 Force: true, 602 Description: customDescription, 603 } 604 605 res, err := rs.UpdateRelease(c, req) 606 if err != nil { 607 t.Fatalf("Failed updated: %s", err) 608 } 609 if res.Release.Info.Description != customDescription { 610 t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description) 611 } 612 compareStoredAndReturnedRelease(t, *rs, *res) 613 } 614 615 func TestUpdateReleasePendingInstall_Force(t *testing.T) { 616 c := helm.NewContext() 617 rs := rsFixture() 618 rel := namedReleaseStub("forceful-luke", release.Status_PENDING_INSTALL) 619 rs.env.Releases.Create(rel) 620 621 req := &services.UpdateReleaseRequest{ 622 Name: rel.Name, 623 Chart: rel.GetChart(), 624 Force: true, 625 } 626 627 _, err := rs.UpdateRelease(c, req) 628 if err == nil { 629 t.Error("Expected failed update") 630 } 631 632 expectedError := "a release named forceful-luke is in use, cannot re-use a name that is still in use" 633 got := err.Error() 634 if err.Error() != expectedError { 635 t.Errorf("Expected error %q, got %q", expectedError, got) 636 } 637 } 638 639 func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release { 640 storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version) 641 if err != nil { 642 t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases) 643 } 644 645 if !proto.Equal(storedRelease, res.Release) { 646 t.Errorf("Stored release doesn't match returned Release") 647 } 648 649 return storedRelease 650 }