github.com/hugorut/terraform@v1.1.3/src/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go (about) 1 package main 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "testing" 8 9 expect "github.com/Netflix/go-expect" 10 tfe "github.com/hashicorp/go-tfe" 11 "github.com/hugorut/terraform/src/e2e" 12 ) 13 14 func Test_migrate_remote_backend_name_to_tfc_name(t *testing.T) { 15 skipIfMissingEnvVar(t) 16 skipWithoutRemoteTerraformVersion(t) 17 18 ctx := context.Background() 19 operations := []operationSets{ 20 { 21 prep: func(t *testing.T, orgName, dir string) { 22 remoteWorkspace := "remote-workspace" 23 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 24 writeMainTF(t, tfBlock, dir) 25 }, 26 commands: []tfCommand{ 27 { 28 command: []string{"init"}, 29 expectedCmdOutput: `Successfully configured the backend "remote"!`, 30 }, 31 { 32 command: []string{"apply", "-auto-approve"}, 33 expectedCmdOutput: `Apply complete!`, 34 }, 35 }, 36 }, 37 { 38 prep: func(t *testing.T, orgName, dir string) { 39 wsName := "cloud-workspace" 40 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 41 writeMainTF(t, tfBlock, dir) 42 }, 43 commands: []tfCommand{ 44 { 45 command: []string{"init", "-ignore-remote-version"}, 46 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 47 userInput: []string{"yes", "yes"}, 48 postInputOutput: []string{ 49 `Should Terraform migrate your existing state?`, 50 `Terraform Cloud has been successfully initialized!`}, 51 }, 52 { 53 command: []string{"workspace", "show"}, 54 expectedCmdOutput: `cloud-workspace`, 55 }, 56 }, 57 }, 58 } 59 validations := func(t *testing.T, orgName string) { 60 expectedName := "cloud-workspace" 61 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 62 if err != nil { 63 t.Fatal(err) 64 } 65 if ws == nil { 66 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 67 } 68 } 69 70 exp, err := expect.NewConsole(defaultOpts()...) 71 if err != nil { 72 t.Fatal(err) 73 } 74 defer exp.Close() 75 76 tmpDir, err := ioutil.TempDir("", "terraform-test") 77 if err != nil { 78 t.Fatal(err) 79 } 80 defer os.RemoveAll(tmpDir) 81 82 tf := e2e.NewBinary(terraformBin, tmpDir) 83 tf.AddEnv(cliConfigFileEnv) 84 defer tf.Close() 85 86 organization, cleanup := createOrganization(t) 87 defer cleanup() 88 for _, op := range operations { 89 op.prep(t, organization.Name, tf.WorkDir()) 90 for _, tfCmd := range op.commands { 91 cmd := tf.Cmd(tfCmd.command...) 92 cmd.Stdin = exp.Tty() 93 cmd.Stdout = exp.Tty() 94 cmd.Stderr = exp.Tty() 95 96 err = cmd.Start() 97 if err != nil { 98 t.Fatal(err) 99 } 100 101 if tfCmd.expectedCmdOutput != "" { 102 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 103 if err != nil { 104 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 105 } 106 } 107 108 lenInput := len(tfCmd.userInput) 109 lenInputOutput := len(tfCmd.postInputOutput) 110 if lenInput > 0 { 111 for i := 0; i < lenInput; i++ { 112 input := tfCmd.userInput[i] 113 exp.SendLine(input) 114 // use the index to find the corresponding 115 // output that matches the input. 116 if lenInputOutput-1 >= i { 117 output := tfCmd.postInputOutput[i] 118 _, err := exp.ExpectString(output) 119 if err != nil { 120 t.Fatal(err) 121 } 122 } 123 } 124 } 125 126 err = cmd.Wait() 127 if err != nil { 128 t.Fatal(err) 129 } 130 } 131 } 132 133 if validations != nil { 134 validations(t, organization.Name) 135 } 136 } 137 138 func Test_migrate_remote_backend_name_to_tfc_same_name(t *testing.T) { 139 skipIfMissingEnvVar(t) 140 skipWithoutRemoteTerraformVersion(t) 141 ctx := context.Background() 142 operations := []operationSets{ 143 { 144 prep: func(t *testing.T, orgName, dir string) { 145 remoteWorkspace := "remote-workspace" 146 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 147 writeMainTF(t, tfBlock, dir) 148 }, 149 commands: []tfCommand{ 150 { 151 command: []string{"init"}, 152 expectedCmdOutput: `Successfully configured the backend "remote"!`, 153 }, 154 { 155 command: []string{"apply", "-auto-approve"}, 156 postInputOutput: []string{`Apply complete!`}, 157 }, 158 }, 159 }, 160 { 161 prep: func(t *testing.T, orgName, dir string) { 162 wsName := "remote-workspace" 163 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 164 writeMainTF(t, tfBlock, dir) 165 }, 166 commands: []tfCommand{ 167 { 168 command: []string{"init", "-ignore-remote-version"}, 169 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 170 userInput: []string{"yes", "yes"}, 171 postInputOutput: []string{ 172 `Should Terraform migrate your existing state?`, 173 `Terraform Cloud has been successfully initialized!`}, 174 }, 175 { 176 command: []string{"workspace", "show"}, 177 expectedCmdOutput: `remote-workspace`, 178 }, 179 }, 180 }, 181 } 182 validations := func(t *testing.T, orgName string) { 183 expectedName := "remote-workspace" 184 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 185 if err != nil { 186 t.Fatal(err) 187 } 188 if ws == nil { 189 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 190 } 191 } 192 193 exp, err := expect.NewConsole(defaultOpts()...) 194 if err != nil { 195 t.Fatal(err) 196 } 197 defer exp.Close() 198 199 tmpDir, err := ioutil.TempDir("", "terraform-test") 200 if err != nil { 201 t.Fatal(err) 202 } 203 defer os.RemoveAll(tmpDir) 204 205 tf := e2e.NewBinary(terraformBin, tmpDir) 206 tf.AddEnv(cliConfigFileEnv) 207 defer tf.Close() 208 209 organization, cleanup := createOrganization(t) 210 defer cleanup() 211 for _, op := range operations { 212 op.prep(t, organization.Name, tf.WorkDir()) 213 for _, tfCmd := range op.commands { 214 cmd := tf.Cmd(tfCmd.command...) 215 cmd.Stdin = exp.Tty() 216 cmd.Stdout = exp.Tty() 217 cmd.Stderr = exp.Tty() 218 219 err = cmd.Start() 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 if tfCmd.expectedCmdOutput != "" { 225 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 226 if err != nil { 227 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 228 } 229 } 230 231 lenInput := len(tfCmd.userInput) 232 lenInputOutput := len(tfCmd.postInputOutput) 233 if lenInput > 0 { 234 for i := 0; i < lenInput; i++ { 235 input := tfCmd.userInput[i] 236 exp.SendLine(input) 237 // use the index to find the corresponding 238 // output that matches the input. 239 if lenInputOutput-1 >= i { 240 output := tfCmd.postInputOutput[i] 241 _, err := exp.ExpectString(output) 242 if err != nil { 243 t.Fatal(err) 244 } 245 } 246 } 247 } 248 249 err = cmd.Wait() 250 if err != nil { 251 t.Fatal(err) 252 } 253 } 254 } 255 256 if validations != nil { 257 validations(t, organization.Name) 258 } 259 } 260 261 func Test_migrate_remote_backend_name_to_tfc_name_different_org(t *testing.T) { 262 skipIfMissingEnvVar(t) 263 skipWithoutRemoteTerraformVersion(t) 264 265 ctx := context.Background() 266 operations := []operationSets{ 267 { 268 prep: func(t *testing.T, orgName, dir string) { 269 remoteWorkspace := "remote-workspace" 270 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 271 writeMainTF(t, tfBlock, dir) 272 }, 273 commands: []tfCommand{ 274 { 275 command: []string{"init"}, 276 expectedCmdOutput: `Successfully configured the backend "remote"!`, 277 }, 278 { 279 command: []string{"apply", "-auto-approve"}, 280 postInputOutput: []string{`Apply complete!`}, 281 }, 282 }, 283 }, 284 { 285 prep: func(t *testing.T, orgName, dir string) { 286 wsName := "remote-workspace" 287 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 288 writeMainTF(t, tfBlock, dir) 289 }, 290 commands: []tfCommand{ 291 { 292 command: []string{"init", "-ignore-remote-version"}, 293 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 294 userInput: []string{"yes", "yes"}, 295 postInputOutput: []string{ 296 `Should Terraform migrate your existing state?`, 297 `Terraform Cloud has been successfully initialized!`}, 298 }, 299 { 300 command: []string{"workspace", "show"}, 301 expectedCmdOutput: `remote-workspace`, 302 }, 303 }, 304 }, 305 } 306 validations := func(t *testing.T, orgName string) { 307 expectedName := "remote-workspace" 308 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 309 if err != nil { 310 t.Fatal(err) 311 } 312 if ws == nil { 313 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 314 } 315 } 316 317 exp, err := expect.NewConsole(defaultOpts()...) 318 if err != nil { 319 t.Fatal(err) 320 } 321 defer exp.Close() 322 323 tmpDir, err := ioutil.TempDir("", "terraform-test") 324 if err != nil { 325 t.Fatal(err) 326 } 327 defer os.RemoveAll(tmpDir) 328 329 tf := e2e.NewBinary(terraformBin, tmpDir) 330 tf.AddEnv(cliConfigFileEnv) 331 defer tf.Close() 332 333 orgOne, cleanupOne := createOrganization(t) 334 orgTwo, cleanupTwo := createOrganization(t) 335 defer cleanupOne() 336 defer cleanupTwo() 337 orgs := []string{orgOne.Name, orgTwo.Name} 338 var orgName string 339 for index, op := range operations { 340 orgName = orgs[index] 341 op.prep(t, orgName, tf.WorkDir()) 342 for _, tfCmd := range op.commands { 343 cmd := tf.Cmd(tfCmd.command...) 344 cmd.Stdin = exp.Tty() 345 cmd.Stdout = exp.Tty() 346 cmd.Stderr = exp.Tty() 347 348 err = cmd.Start() 349 if err != nil { 350 t.Fatal(err) 351 } 352 353 if tfCmd.expectedCmdOutput != "" { 354 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 355 if err != nil { 356 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 357 } 358 } 359 360 lenInput := len(tfCmd.userInput) 361 lenInputOutput := len(tfCmd.postInputOutput) 362 if lenInput > 0 { 363 for i := 0; i < lenInput; i++ { 364 input := tfCmd.userInput[i] 365 exp.SendLine(input) 366 // use the index to find the corresponding 367 // output that matches the input. 368 if lenInputOutput-1 >= i { 369 output := tfCmd.postInputOutput[i] 370 _, err := exp.ExpectString(output) 371 if err != nil { 372 t.Fatal(err) 373 } 374 } 375 } 376 } 377 378 err = cmd.Wait() 379 if err != nil { 380 t.Fatal(err) 381 } 382 } 383 } 384 385 if validations != nil { 386 validations(t, orgName) 387 } 388 } 389 390 func Test_migrate_remote_backend_name_to_tfc_tags(t *testing.T) { 391 skipIfMissingEnvVar(t) 392 skipWithoutRemoteTerraformVersion(t) 393 394 ctx := context.Background() 395 operations := []operationSets{ 396 { 397 prep: func(t *testing.T, orgName, dir string) { 398 remoteWorkspace := "remote-workspace" 399 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 400 writeMainTF(t, tfBlock, dir) 401 }, 402 commands: []tfCommand{ 403 { 404 command: []string{"init"}, 405 expectedCmdOutput: `Successfully configured the backend "remote"!`, 406 }, 407 { 408 command: []string{"apply", "-auto-approve"}, 409 postInputOutput: []string{`Apply complete!`}, 410 }, 411 { 412 command: []string{"workspace", "show"}, 413 expectedCmdOutput: `default`, 414 }, 415 }, 416 }, 417 { 418 prep: func(t *testing.T, orgName, dir string) { 419 tag := "app" 420 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 421 writeMainTF(t, tfBlock, dir) 422 }, 423 commands: []tfCommand{ 424 { 425 command: []string{"init", "-ignore-remote-version"}, 426 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 427 userInput: []string{"yes", "cloud-workspace", "yes"}, 428 postInputOutput: []string{ 429 `Should Terraform migrate your existing state?`, 430 `Terraform Cloud requires all workspaces to be given an explicit name.`, 431 `Terraform Cloud has been successfully initialized!`}, 432 }, 433 { 434 command: []string{"workspace", "show"}, 435 expectedCmdOutput: `cloud-workspace`, 436 }, 437 }, 438 }, 439 } 440 validations := func(t *testing.T, orgName string) { 441 wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ 442 Tags: tfe.String("app"), 443 }) 444 if err != nil { 445 t.Fatal(err) 446 } 447 if len(wsList.Items) != 1 { 448 t.Fatalf("Expected number of workspaces to be 1, but got %d", len(wsList.Items)) 449 } 450 ws := wsList.Items[0] 451 if ws.Name != "cloud-workspace" { 452 t.Fatalf("Expected workspace to be `cloud-workspace`, but is %s", ws.Name) 453 } 454 } 455 456 exp, err := expect.NewConsole(defaultOpts()...) 457 if err != nil { 458 t.Fatal(err) 459 } 460 defer exp.Close() 461 462 tmpDir, err := ioutil.TempDir("", "terraform-test") 463 if err != nil { 464 t.Fatal(err) 465 } 466 defer os.RemoveAll(tmpDir) 467 468 tf := e2e.NewBinary(terraformBin, tmpDir) 469 tf.AddEnv(cliConfigFileEnv) 470 defer tf.Close() 471 472 organization, cleanup := createOrganization(t) 473 defer cleanup() 474 for _, op := range operations { 475 op.prep(t, organization.Name, tf.WorkDir()) 476 for _, tfCmd := range op.commands { 477 cmd := tf.Cmd(tfCmd.command...) 478 cmd.Stdin = exp.Tty() 479 cmd.Stdout = exp.Tty() 480 cmd.Stderr = exp.Tty() 481 482 err = cmd.Start() 483 if err != nil { 484 t.Fatal(err) 485 } 486 487 if tfCmd.expectedCmdOutput != "" { 488 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 489 if err != nil { 490 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 491 } 492 } 493 494 lenInput := len(tfCmd.userInput) 495 lenInputOutput := len(tfCmd.postInputOutput) 496 if lenInput > 0 { 497 for i := 0; i < lenInput; i++ { 498 input := tfCmd.userInput[i] 499 exp.SendLine(input) 500 // use the index to find the corresponding 501 // output that matches the input. 502 if lenInputOutput-1 >= i { 503 output := tfCmd.postInputOutput[i] 504 _, err := exp.ExpectString(output) 505 if err != nil { 506 t.Fatal(err) 507 } 508 } 509 } 510 } 511 512 err = cmd.Wait() 513 if err != nil { 514 t.Fatal(err) 515 } 516 } 517 } 518 519 if validations != nil { 520 validations(t, organization.Name) 521 } 522 } 523 524 func Test_migrate_remote_backend_prefix_to_tfc_name_strategy_single_workspace(t *testing.T) { 525 skipIfMissingEnvVar(t) 526 skipWithoutRemoteTerraformVersion(t) 527 528 ctx := context.Background() 529 operations := []operationSets{ 530 { 531 prep: func(t *testing.T, orgName, dir string) { 532 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 533 prefix := "app-" 534 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 535 writeMainTF(t, tfBlock, dir) 536 }, 537 commands: []tfCommand{ 538 { 539 command: []string{"init"}, 540 expectedCmdOutput: `Terraform has been successfully initialized!`, 541 }, 542 { 543 command: []string{"apply", "-auto-approve"}, 544 postInputOutput: []string{`Apply complete!`}, 545 }, 546 }, 547 }, 548 { 549 prep: func(t *testing.T, orgName, dir string) { 550 wsName := "cloud-workspace" 551 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 552 writeMainTF(t, tfBlock, dir) 553 }, 554 commands: []tfCommand{ 555 { 556 command: []string{"init", "-ignore-remote-version"}, 557 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 558 userInput: []string{"yes", "yes"}, 559 postInputOutput: []string{ 560 `Should Terraform migrate your existing state?`, 561 `Terraform Cloud has been successfully initialized!`}, 562 }, 563 { 564 command: []string{"workspace", "show"}, 565 expectedCmdOutput: `cloud-workspace`, 566 }, 567 }, 568 }, 569 } 570 validations := func(t *testing.T, orgName string) { 571 expectedName := "cloud-workspace" 572 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 573 if err != nil { 574 t.Fatal(err) 575 } 576 if ws == nil { 577 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 578 } 579 } 580 581 exp, err := expect.NewConsole(defaultOpts()...) 582 if err != nil { 583 t.Fatal(err) 584 } 585 defer exp.Close() 586 587 tmpDir, err := ioutil.TempDir("", "terraform-test") 588 if err != nil { 589 t.Fatal(err) 590 } 591 defer os.RemoveAll(tmpDir) 592 593 tf := e2e.NewBinary(terraformBin, tmpDir) 594 tf.AddEnv(cliConfigFileEnv) 595 defer tf.Close() 596 597 organization, cleanup := createOrganization(t) 598 defer cleanup() 599 for _, op := range operations { 600 op.prep(t, organization.Name, tf.WorkDir()) 601 for _, tfCmd := range op.commands { 602 cmd := tf.Cmd(tfCmd.command...) 603 cmd.Stdin = exp.Tty() 604 cmd.Stdout = exp.Tty() 605 cmd.Stderr = exp.Tty() 606 607 err = cmd.Start() 608 if err != nil { 609 t.Fatal(err) 610 } 611 612 if tfCmd.expectedCmdOutput != "" { 613 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 614 if err != nil { 615 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 616 } 617 } 618 619 lenInput := len(tfCmd.userInput) 620 lenInputOutput := len(tfCmd.postInputOutput) 621 if lenInput > 0 { 622 for i := 0; i < lenInput; i++ { 623 input := tfCmd.userInput[i] 624 exp.SendLine(input) 625 // use the index to find the corresponding 626 // output that matches the input. 627 if lenInputOutput-1 >= i { 628 output := tfCmd.postInputOutput[i] 629 got, err := exp.ExpectString(output) 630 if err != nil { 631 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", output, err, got) 632 } 633 } 634 } 635 } 636 637 err = cmd.Wait() 638 if err != nil { 639 t.Fatal(err) 640 } 641 } 642 } 643 644 if validations != nil { 645 validations(t, organization.Name) 646 } 647 } 648 649 func Test_migrate_remote_backend_prefix_to_tfc_name_strategy_multi_workspace(t *testing.T) { 650 skipIfMissingEnvVar(t) 651 skipWithoutRemoteTerraformVersion(t) 652 653 ctx := context.Background() 654 operations := []operationSets{ 655 { 656 prep: func(t *testing.T, orgName, dir string) { 657 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 658 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) 659 prefix := "app-" 660 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 661 writeMainTF(t, tfBlock, dir) 662 }, 663 commands: []tfCommand{ 664 { 665 command: []string{"init"}, 666 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 667 userInput: []string{"1"}, 668 postInputOutput: []string{`Terraform has been successfully initialized!`}, 669 }, 670 { 671 command: []string{"apply", "-auto-approve"}, 672 postInputOutput: []string{`Apply complete!`}, 673 }, 674 { 675 command: []string{"workspace", "list"}, 676 expectedCmdOutput: "* one", // app name retrieved via prefix 677 }, 678 { 679 command: []string{"workspace", "select", "two"}, 680 expectedCmdOutput: `Switched to workspace "two".`, // app name retrieved via prefix 681 }, 682 }, 683 }, 684 { 685 prep: func(t *testing.T, orgName, dir string) { 686 wsName := "cloud-workspace" 687 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 688 writeMainTF(t, tfBlock, dir) 689 }, 690 commands: []tfCommand{ 691 { 692 command: []string{"init", "-ignore-remote-version"}, 693 expectedCmdOutput: `Do you want to copy only your current workspace?`, 694 userInput: []string{"yes"}, 695 postInputOutput: []string{ 696 `Terraform Cloud has been successfully initialized!`}, 697 }, 698 { 699 command: []string{"workspace", "show"}, 700 expectedCmdOutput: `cloud-workspace`, 701 }, 702 }, 703 }, 704 } 705 validations := func(t *testing.T, orgName string) { 706 expectedName := "cloud-workspace" 707 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 708 if err != nil { 709 t.Fatal(err) 710 } 711 if ws == nil { 712 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 713 } 714 wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{}) 715 if err != nil { 716 t.Fatal(err) 717 } 718 if len(wsList.Items) != 3 { 719 t.Fatalf("expected number of workspaces in this org to be 3, but got %d", len(wsList.Items)) 720 } 721 _, empty := getWorkspace(wsList.Items, "cloud-workspace") 722 if empty { 723 t.Fatalf("expected workspaces to include 'cloud-workspace' but didn't.") 724 } 725 _, empty = getWorkspace(wsList.Items, "app-one") 726 if empty { 727 t.Fatalf("expected workspaces to include 'app-one' but didn't.") 728 } 729 _, empty = getWorkspace(wsList.Items, "app-two") 730 if empty { 731 t.Fatalf("expected workspaces to include 'app-two' but didn't.") 732 } 733 } 734 735 exp, err := expect.NewConsole(defaultOpts()...) 736 if err != nil { 737 t.Fatal(err) 738 } 739 defer exp.Close() 740 741 tmpDir, err := ioutil.TempDir("", "terraform-test") 742 if err != nil { 743 t.Fatal(err) 744 } 745 defer os.RemoveAll(tmpDir) 746 747 tf := e2e.NewBinary(terraformBin, tmpDir) 748 tf.AddEnv(cliConfigFileEnv) 749 defer tf.Close() 750 751 organization, cleanup := createOrganization(t) 752 defer cleanup() 753 for _, op := range operations { 754 op.prep(t, organization.Name, tf.WorkDir()) 755 for _, tfCmd := range op.commands { 756 cmd := tf.Cmd(tfCmd.command...) 757 cmd.Stdin = exp.Tty() 758 cmd.Stdout = exp.Tty() 759 cmd.Stderr = exp.Tty() 760 761 err = cmd.Start() 762 if err != nil { 763 t.Fatal(err) 764 } 765 766 if tfCmd.expectedCmdOutput != "" { 767 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 768 if err != nil { 769 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 770 } 771 } 772 773 lenInput := len(tfCmd.userInput) 774 lenInputOutput := len(tfCmd.postInputOutput) 775 if lenInput > 0 { 776 for i := 0; i < lenInput; i++ { 777 input := tfCmd.userInput[i] 778 exp.SendLine(input) 779 // use the index to find the corresponding 780 // output that matches the input. 781 if lenInputOutput-1 >= i { 782 output := tfCmd.postInputOutput[i] 783 _, err := exp.ExpectString(output) 784 if err != nil { 785 t.Fatal(err) 786 } 787 } 788 } 789 } 790 791 err = cmd.Wait() 792 if err != nil { 793 t.Fatal(err) 794 } 795 } 796 } 797 798 if validations != nil { 799 validations(t, organization.Name) 800 } 801 } 802 803 func Test_migrate_remote_backend_prefix_to_tfc_tags_strategy_single_workspace(t *testing.T) { 804 skipIfMissingEnvVar(t) 805 skipWithoutRemoteTerraformVersion(t) 806 807 ctx := context.Background() 808 operations := []operationSets{ 809 { 810 prep: func(t *testing.T, orgName, dir string) { 811 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 812 prefix := "app-" 813 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 814 writeMainTF(t, tfBlock, dir) 815 }, 816 commands: []tfCommand{ 817 { 818 command: []string{"init"}, 819 expectedCmdOutput: `Terraform has been successfully initialized!`, 820 }, 821 { 822 command: []string{"apply", "-auto-approve"}, 823 postInputOutput: []string{`Apply complete!`}, 824 }, 825 }, 826 }, 827 { 828 prep: func(t *testing.T, orgName, dir string) { 829 tag := "app" 830 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 831 writeMainTF(t, tfBlock, dir) 832 }, 833 commands: []tfCommand{ 834 { 835 command: []string{"init", "-ignore-remote-version"}, 836 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 837 userInput: []string{"yes", "cloud-workspace", "yes"}, 838 postInputOutput: []string{ 839 `Should Terraform migrate your existing state?`, 840 `Terraform Cloud requires all workspaces to be given an explicit name.`, 841 `Terraform Cloud has been successfully initialized!`}, 842 }, 843 { 844 command: []string{"workspace", "list"}, 845 expectedCmdOutput: `cloud-workspace`, 846 }, 847 }, 848 }, 849 } 850 validations := func(t *testing.T, orgName string) { 851 expectedName := "cloud-workspace" 852 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 853 if err != nil { 854 t.Fatal(err) 855 } 856 if ws == nil { 857 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 858 } 859 } 860 861 exp, err := expect.NewConsole(defaultOpts()...) 862 if err != nil { 863 t.Fatal(err) 864 } 865 defer exp.Close() 866 867 tmpDir, err := ioutil.TempDir("", "terraform-test") 868 if err != nil { 869 t.Fatal(err) 870 } 871 defer os.RemoveAll(tmpDir) 872 873 tf := e2e.NewBinary(terraformBin, tmpDir) 874 tf.AddEnv(cliConfigFileEnv) 875 defer tf.Close() 876 877 organization, cleanup := createOrganization(t) 878 defer cleanup() 879 for _, op := range operations { 880 op.prep(t, organization.Name, tf.WorkDir()) 881 for _, tfCmd := range op.commands { 882 cmd := tf.Cmd(tfCmd.command...) 883 cmd.Stdin = exp.Tty() 884 cmd.Stdout = exp.Tty() 885 cmd.Stderr = exp.Tty() 886 887 err = cmd.Start() 888 if err != nil { 889 t.Fatal(err) 890 } 891 892 if tfCmd.expectedCmdOutput != "" { 893 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 894 if err != nil { 895 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 896 } 897 } 898 899 lenInput := len(tfCmd.userInput) 900 lenInputOutput := len(tfCmd.postInputOutput) 901 if lenInput > 0 { 902 for i := 0; i < lenInput; i++ { 903 input := tfCmd.userInput[i] 904 exp.SendLine(input) 905 // use the index to find the corresponding 906 // output that matches the input. 907 if lenInputOutput-1 >= i { 908 output := tfCmd.postInputOutput[i] 909 _, err := exp.ExpectString(output) 910 if err != nil { 911 t.Fatal(err) 912 } 913 } 914 } 915 } 916 917 err = cmd.Wait() 918 if err != nil { 919 t.Fatal(err) 920 } 921 } 922 } 923 924 if validations != nil { 925 validations(t, organization.Name) 926 } 927 } 928 929 func Test_migrate_remote_backend_prefix_to_tfc_tags_strategy_multi_workspace(t *testing.T) { 930 skipIfMissingEnvVar(t) 931 skipWithoutRemoteTerraformVersion(t) 932 933 ctx := context.Background() 934 operations := []operationSets{ 935 { 936 prep: func(t *testing.T, orgName, dir string) { 937 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 938 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) 939 prefix := "app-" 940 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 941 writeMainTF(t, tfBlock, dir) 942 }, 943 commands: []tfCommand{ 944 { 945 command: []string{"init"}, 946 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 947 userInput: []string{"1"}, 948 postInputOutput: []string{`Terraform has been successfully initialized!`}, 949 }, 950 { 951 command: []string{"apply"}, 952 expectedCmdOutput: `Do you want to perform these actions in workspace "app-one"?`, 953 userInput: []string{"yes"}, 954 postInputOutput: []string{`Apply complete!`}, 955 }, 956 { 957 command: []string{"workspace", "select", "two"}, 958 }, 959 { 960 command: []string{"apply"}, 961 expectedCmdOutput: `Do you want to perform these actions in workspace "app-two"?`, 962 userInput: []string{"yes"}, 963 postInputOutput: []string{`Apply complete!`}, 964 }, 965 }, 966 }, 967 { 968 prep: func(t *testing.T, orgName, dir string) { 969 tag := "app" 970 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 971 writeMainTF(t, tfBlock, dir) 972 }, 973 commands: []tfCommand{ 974 { 975 command: []string{"init", "-ignore-remote-version"}, 976 expectedCmdOutput: `Do you wish to proceed?`, 977 userInput: []string{"yes"}, 978 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 979 }, 980 { 981 command: []string{"workspace", "show"}, 982 expectedCmdOutput: "app-two", 983 }, 984 { 985 command: []string{"workspace", "select", "app-one"}, 986 expectedCmdOutput: `Switched to workspace "app-one".`, 987 }, 988 }, 989 }, 990 } 991 validations := func(t *testing.T, orgName string) { 992 wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ 993 Tags: tfe.String("app"), 994 }) 995 if err != nil { 996 t.Fatal(err) 997 } 998 if len(wsList.Items) != 2 { 999 t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items)) 1000 } 1001 ws, empty := getWorkspace(wsList.Items, "app-one") 1002 if empty { 1003 t.Fatalf("expected workspaces to include 'app-one' but didn't.") 1004 } 1005 if len(ws.TagNames) == 0 { 1006 t.Fatalf("expected workspaces 'one' to have tags.") 1007 } 1008 ws, empty = getWorkspace(wsList.Items, "app-two") 1009 if empty { 1010 t.Fatalf("expected workspaces to include 'app-two' but didn't.") 1011 } 1012 if len(ws.TagNames) == 0 { 1013 t.Fatalf("expected workspaces 'app-two' to have tags.") 1014 } 1015 } 1016 1017 exp, err := expect.NewConsole(defaultOpts()...) 1018 if err != nil { 1019 t.Fatal(err) 1020 } 1021 defer exp.Close() 1022 1023 tmpDir, err := ioutil.TempDir("", "terraform-test") 1024 if err != nil { 1025 t.Fatal(err) 1026 } 1027 defer os.RemoveAll(tmpDir) 1028 1029 tf := e2e.NewBinary(terraformBin, tmpDir) 1030 tf.AddEnv(cliConfigFileEnv) 1031 defer tf.Close() 1032 1033 organization, cleanup := createOrganization(t) 1034 defer cleanup() 1035 for _, op := range operations { 1036 op.prep(t, organization.Name, tf.WorkDir()) 1037 for _, tfCmd := range op.commands { 1038 cmd := tf.Cmd(tfCmd.command...) 1039 cmd.Stdin = exp.Tty() 1040 cmd.Stdout = exp.Tty() 1041 cmd.Stderr = exp.Tty() 1042 1043 err = cmd.Start() 1044 if err != nil { 1045 t.Fatal(err) 1046 } 1047 1048 if tfCmd.expectedCmdOutput != "" { 1049 got, err := exp.ExpectString(tfCmd.expectedCmdOutput) 1050 if err != nil { 1051 t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) 1052 } 1053 } 1054 1055 lenInput := len(tfCmd.userInput) 1056 lenInputOutput := len(tfCmd.postInputOutput) 1057 if lenInput > 0 { 1058 for i := 0; i < lenInput; i++ { 1059 input := tfCmd.userInput[i] 1060 exp.SendLine(input) 1061 // use the index to find the corresponding 1062 // output that matches the input. 1063 if lenInputOutput-1 >= i { 1064 output := tfCmd.postInputOutput[i] 1065 _, err := exp.ExpectString(output) 1066 if err != nil { 1067 t.Fatal(err) 1068 } 1069 } 1070 } 1071 } 1072 1073 err = cmd.Wait() 1074 if err != nil { 1075 t.Fatal(err) 1076 } 1077 } 1078 } 1079 1080 if validations != nil { 1081 validations(t, organization.Name) 1082 } 1083 }