github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/state_mv_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 "github.com/mitchellh/cli" 12 13 "github.com/hashicorp/terraform/internal/addrs" 14 "github.com/hashicorp/terraform/internal/states" 15 ) 16 17 func TestStateMv(t *testing.T) { 18 state := states.BuildState(func(s *states.SyncState) { 19 s.SetResourceInstanceCurrent( 20 addrs.Resource{ 21 Mode: addrs.ManagedResourceMode, 22 Type: "test_instance", 23 Name: "foo", 24 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 25 &states.ResourceInstanceObjectSrc{ 26 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 27 Status: states.ObjectReady, 28 }, 29 addrs.AbsProviderConfig{ 30 Provider: addrs.NewDefaultProvider("test"), 31 Module: addrs.RootModule, 32 }, 33 ) 34 s.SetResourceInstanceCurrent( 35 addrs.Resource{ 36 Mode: addrs.ManagedResourceMode, 37 Type: "test_instance", 38 Name: "baz", 39 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 40 &states.ResourceInstanceObjectSrc{ 41 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 42 Status: states.ObjectReady, 43 Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")}, 44 }, 45 addrs.AbsProviderConfig{ 46 Provider: addrs.NewDefaultProvider("test"), 47 Module: addrs.RootModule, 48 }, 49 ) 50 }) 51 statePath := testStateFile(t, state) 52 53 p := testProvider() 54 ui := new(cli.MockUi) 55 view, _ := testView(t) 56 c := &StateMvCommand{ 57 StateMeta{ 58 Meta: Meta{ 59 testingOverrides: metaOverridesForProvider(p), 60 Ui: ui, 61 View: view, 62 }, 63 }, 64 } 65 66 args := []string{ 67 "-state", statePath, 68 "test_instance.foo", 69 "test_instance.bar", 70 } 71 if code := c.Run(args); code != 0 { 72 t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String()) 73 } 74 75 // Test it is correct 76 testStateOutput(t, statePath, testStateMvOutput) 77 78 // Test we have backups 79 backups := testStateBackups(t, filepath.Dir(statePath)) 80 if len(backups) != 1 { 81 t.Fatalf("bad: %#v", backups) 82 } 83 testStateOutput(t, backups[0], testStateMvOutputOriginal) 84 85 // Change the single instance to a counted instance 86 args = []string{ 87 "-state", statePath, 88 "test_instance.bar", 89 "test_instance.bar[0]", 90 } 91 if code := c.Run(args); code != 0 { 92 t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String()) 93 } 94 95 // extract the resource and verify the mode 96 s := testStateRead(t, statePath) 97 addr, diags := addrs.ParseAbsResourceStr("test_instance.bar") 98 if diags.HasErrors() { 99 t.Fatal(diags.Err()) 100 } 101 for key := range s.Resource(addr).Instances { 102 if _, ok := key.(addrs.IntKey); !ok { 103 t.Fatalf("expected each mode List, got key %q", key) 104 } 105 } 106 107 // change from list to map 108 args = []string{ 109 "-state", statePath, 110 "test_instance.bar[0]", 111 "test_instance.bar[\"baz\"]", 112 } 113 if code := c.Run(args); code != 0 { 114 t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String()) 115 } 116 117 // extract the resource and verify the mode 118 s = testStateRead(t, statePath) 119 addr, diags = addrs.ParseAbsResourceStr("test_instance.bar") 120 if diags.HasErrors() { 121 t.Fatal(diags.Err()) 122 } 123 for key := range s.Resource(addr).Instances { 124 if _, ok := key.(addrs.StringKey); !ok { 125 t.Fatalf("expected each mode map, found key %q", key) 126 } 127 } 128 129 // change from from map back to single 130 args = []string{ 131 "-state", statePath, 132 "test_instance.bar[\"baz\"]", 133 "test_instance.bar", 134 } 135 if code := c.Run(args); code != 0 { 136 t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String()) 137 } 138 139 // extract the resource and verify the mode 140 s = testStateRead(t, statePath) 141 addr, diags = addrs.ParseAbsResourceStr("test_instance.bar") 142 if diags.HasErrors() { 143 t.Fatal(diags.Err()) 144 } 145 for key := range s.Resource(addr).Instances { 146 if key != addrs.NoKey { 147 t.Fatalf("expected no each mode, found key %q", key) 148 } 149 } 150 151 } 152 153 func TestStateMv_backupAndBackupOutOptionsWithNonLocalBackend(t *testing.T) { 154 state := states.BuildState(func(s *states.SyncState) { 155 s.SetResourceInstanceCurrent( 156 addrs.Resource{ 157 Mode: addrs.ManagedResourceMode, 158 Type: "test_instance", 159 Name: "foo", 160 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 161 &states.ResourceInstanceObjectSrc{ 162 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 163 Status: states.ObjectReady, 164 }, 165 addrs.AbsProviderConfig{ 166 Provider: addrs.NewDefaultProvider("test"), 167 Module: addrs.RootModule, 168 }, 169 ) 170 }) 171 172 t.Run("backup option specified", func(t *testing.T) { 173 td := t.TempDir() 174 testCopyDir(t, testFixturePath("init-backend-http"), td) 175 defer testChdir(t, td)() 176 177 backupPath := filepath.Join(td, "backup") 178 179 // Set up our backend state using mock state 180 dataState, srv := testBackendState(t, state, 200) 181 defer srv.Close() 182 testStateFileRemote(t, dataState) 183 184 p := testProvider() 185 ui := new(cli.MockUi) 186 view, _ := testView(t) 187 c := &StateMvCommand{ 188 StateMeta{ 189 Meta: Meta{ 190 testingOverrides: metaOverridesForProvider(p), 191 Ui: ui, 192 View: view, 193 }, 194 }, 195 } 196 197 args := []string{ 198 "-backup", backupPath, 199 "test_instance.foo", 200 "test_instance.bar", 201 } 202 if code := c.Run(args); code == 0 { 203 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 204 } 205 206 gotErr := ui.ErrorWriter.String() 207 wantErr := ` 208 Error: Invalid command line options: -backup 209 210 Command line options -backup and -backup-out are legacy options that operate 211 on a local state file only. You must specify a local state file with the 212 -state option or switch to the local backend. 213 214 ` 215 if gotErr != wantErr { 216 t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr) 217 } 218 }) 219 220 t.Run("backup-out option specified", func(t *testing.T) { 221 td := t.TempDir() 222 testCopyDir(t, testFixturePath("init-backend-http"), td) 223 defer testChdir(t, td)() 224 225 backupOutPath := filepath.Join(td, "backup-out") 226 227 // Set up our backend state using mock state 228 dataState, srv := testBackendState(t, state, 200) 229 defer srv.Close() 230 testStateFileRemote(t, dataState) 231 232 p := testProvider() 233 ui := new(cli.MockUi) 234 view, _ := testView(t) 235 c := &StateMvCommand{ 236 StateMeta{ 237 Meta: Meta{ 238 testingOverrides: metaOverridesForProvider(p), 239 Ui: ui, 240 View: view, 241 }, 242 }, 243 } 244 245 args := []string{ 246 "-backup-out", backupOutPath, 247 "test_instance.foo", 248 "test_instance.bar", 249 } 250 if code := c.Run(args); code == 0 { 251 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 252 } 253 254 gotErr := ui.ErrorWriter.String() 255 wantErr := ` 256 Error: Invalid command line options: -backup-out 257 258 Command line options -backup and -backup-out are legacy options that operate 259 on a local state file only. You must specify a local state file with the 260 -state option or switch to the local backend. 261 262 ` 263 if gotErr != wantErr { 264 t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr) 265 } 266 }) 267 268 t.Run("backup and backup-out options specified", func(t *testing.T) { 269 td := t.TempDir() 270 testCopyDir(t, testFixturePath("init-backend-http"), td) 271 defer testChdir(t, td)() 272 273 backupPath := filepath.Join(td, "backup") 274 backupOutPath := filepath.Join(td, "backup-out") 275 276 // Set up our backend state using mock state 277 dataState, srv := testBackendState(t, state, 200) 278 defer srv.Close() 279 testStateFileRemote(t, dataState) 280 281 p := testProvider() 282 ui := new(cli.MockUi) 283 view, _ := testView(t) 284 c := &StateMvCommand{ 285 StateMeta{ 286 Meta: Meta{ 287 testingOverrides: metaOverridesForProvider(p), 288 Ui: ui, 289 View: view, 290 }, 291 }, 292 } 293 294 args := []string{ 295 "-backup", backupPath, 296 "-backup-out", backupOutPath, 297 "test_instance.foo", 298 "test_instance.bar", 299 } 300 if code := c.Run(args); code == 0 { 301 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 302 } 303 304 gotErr := ui.ErrorWriter.String() 305 wantErr := ` 306 Error: Invalid command line options: -backup, -backup-out 307 308 Command line options -backup and -backup-out are legacy options that operate 309 on a local state file only. You must specify a local state file with the 310 -state option or switch to the local backend. 311 312 ` 313 if gotErr != wantErr { 314 t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr) 315 } 316 }) 317 318 t.Run("backup option specified with state option", func(t *testing.T) { 319 td := t.TempDir() 320 testCopyDir(t, testFixturePath("init-backend-http"), td) 321 defer testChdir(t, td)() 322 323 statePath := testStateFile(t, state) 324 backupPath := filepath.Join(td, "backup") 325 326 // Set up our backend state using mock state 327 dataState, srv := testBackendState(t, state, 200) 328 defer srv.Close() 329 testStateFileRemote(t, dataState) 330 331 p := testProvider() 332 ui := new(cli.MockUi) 333 view, _ := testView(t) 334 c := &StateMvCommand{ 335 StateMeta{ 336 Meta: Meta{ 337 testingOverrides: metaOverridesForProvider(p), 338 Ui: ui, 339 View: view, 340 }, 341 }, 342 } 343 344 args := []string{ 345 "-state", statePath, 346 "-backup", backupPath, 347 "test_instance.foo", 348 "test_instance.bar", 349 } 350 if code := c.Run(args); code != 0 { 351 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 352 } 353 354 // Test it is correct 355 testStateOutput(t, statePath, testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput) 356 }) 357 358 t.Run("backup-out option specified with state option", func(t *testing.T) { 359 td := t.TempDir() 360 testCopyDir(t, testFixturePath("init-backend-http"), td) 361 defer testChdir(t, td)() 362 363 statePath := testStateFile(t, state) 364 backupOutPath := filepath.Join(td, "backup-out") 365 366 // Set up our backend state using mock state 367 dataState, srv := testBackendState(t, state, 200) 368 defer srv.Close() 369 testStateFileRemote(t, dataState) 370 371 p := testProvider() 372 ui := new(cli.MockUi) 373 view, _ := testView(t) 374 c := &StateMvCommand{ 375 StateMeta{ 376 Meta: Meta{ 377 testingOverrides: metaOverridesForProvider(p), 378 Ui: ui, 379 View: view, 380 }, 381 }, 382 } 383 384 args := []string{ 385 "-state", statePath, 386 "-backup-out", backupOutPath, 387 "test_instance.foo", 388 "test_instance.bar", 389 } 390 if code := c.Run(args); code != 0 { 391 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 392 } 393 394 // Test it is correct 395 testStateOutput(t, statePath, testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput) 396 }) 397 } 398 399 func TestStateMv_resourceToInstance(t *testing.T) { 400 // A single resource (no count defined) 401 state := states.BuildState(func(s *states.SyncState) { 402 s.SetResourceInstanceCurrent( 403 addrs.Resource{ 404 Mode: addrs.ManagedResourceMode, 405 Type: "test_instance", 406 Name: "foo", 407 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 408 &states.ResourceInstanceObjectSrc{ 409 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 410 Status: states.ObjectReady, 411 }, 412 addrs.AbsProviderConfig{ 413 Provider: addrs.NewDefaultProvider("test"), 414 Module: addrs.RootModule, 415 }, 416 ) 417 s.SetResourceInstanceCurrent( 418 addrs.Resource{ 419 Mode: addrs.ManagedResourceMode, 420 Type: "test_instance", 421 Name: "baz", 422 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 423 &states.ResourceInstanceObjectSrc{ 424 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 425 Status: states.ObjectReady, 426 Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")}, 427 }, 428 addrs.AbsProviderConfig{ 429 Provider: addrs.NewDefaultProvider("test"), 430 Module: addrs.RootModule, 431 }, 432 ) 433 s.SetResourceProvider( 434 addrs.Resource{ 435 Mode: addrs.ManagedResourceMode, 436 Type: "test_instance", 437 Name: "bar", 438 }.Absolute(addrs.RootModuleInstance), 439 addrs.AbsProviderConfig{ 440 Provider: addrs.NewDefaultProvider("test"), 441 Module: addrs.RootModule, 442 }, 443 ) 444 }) 445 statePath := testStateFile(t, state) 446 447 p := testProvider() 448 ui := new(cli.MockUi) 449 view, _ := testView(t) 450 c := &StateMvCommand{ 451 StateMeta{ 452 Meta: Meta{ 453 testingOverrides: metaOverridesForProvider(p), 454 Ui: ui, 455 View: view, 456 }, 457 }, 458 } 459 460 args := []string{ 461 "-state", statePath, 462 "test_instance.foo", 463 "test_instance.bar[0]", 464 } 465 if code := c.Run(args); code != 0 { 466 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 467 } 468 469 // Test it is correct 470 testStateOutput(t, statePath, ` 471 test_instance.bar.0: 472 ID = bar 473 provider = provider["registry.terraform.io/hashicorp/test"] 474 bar = value 475 foo = value 476 test_instance.baz: 477 ID = foo 478 provider = provider["registry.terraform.io/hashicorp/test"] 479 bar = value 480 foo = value 481 `) 482 483 // Test we have backups 484 backups := testStateBackups(t, filepath.Dir(statePath)) 485 if len(backups) != 1 { 486 t.Fatalf("bad: %#v", backups) 487 } 488 testStateOutput(t, backups[0], testStateMvOutputOriginal) 489 } 490 491 func TestStateMv_resourceToInstanceErr(t *testing.T) { 492 state := states.BuildState(func(s *states.SyncState) { 493 s.SetResourceInstanceCurrent( 494 addrs.Resource{ 495 Mode: addrs.ManagedResourceMode, 496 Type: "test_instance", 497 Name: "foo", 498 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), 499 &states.ResourceInstanceObjectSrc{ 500 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 501 Status: states.ObjectReady, 502 }, 503 addrs.AbsProviderConfig{ 504 Provider: addrs.NewDefaultProvider("test"), 505 Module: addrs.RootModule, 506 }, 507 ) 508 s.SetResourceProvider( 509 addrs.Resource{ 510 Mode: addrs.ManagedResourceMode, 511 Type: "test_instance", 512 Name: "bar", 513 }.Absolute(addrs.RootModuleInstance), 514 addrs.AbsProviderConfig{ 515 Provider: addrs.NewDefaultProvider("test"), 516 Module: addrs.RootModule, 517 }, 518 ) 519 }) 520 statePath := testStateFile(t, state) 521 522 p := testProvider() 523 ui := cli.NewMockUi() 524 view, _ := testView(t) 525 526 c := &StateMvCommand{ 527 StateMeta{ 528 Meta: Meta{ 529 testingOverrides: metaOverridesForProvider(p), 530 Ui: ui, 531 View: view, 532 }, 533 }, 534 } 535 536 args := []string{ 537 "-state", statePath, 538 "test_instance.foo", 539 "test_instance.bar[0]", 540 } 541 542 if code := c.Run(args); code == 0 { 543 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 544 } 545 546 expectedErr := ` 547 Error: Invalid target address 548 549 Cannot move test_instance.foo to test_instance.bar[0]: the source is a whole 550 resource (not a resource instance) so the target must also be a whole 551 resource. 552 553 ` 554 errOutput := ui.ErrorWriter.String() 555 if errOutput != expectedErr { 556 t.Errorf("wrong output\n%s", cmp.Diff(errOutput, expectedErr)) 557 } 558 } 559 560 func TestStateMv_resourceToInstanceErrInAutomation(t *testing.T) { 561 state := states.BuildState(func(s *states.SyncState) { 562 s.SetResourceInstanceCurrent( 563 addrs.Resource{ 564 Mode: addrs.ManagedResourceMode, 565 Type: "test_instance", 566 Name: "foo", 567 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), 568 &states.ResourceInstanceObjectSrc{ 569 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 570 Status: states.ObjectReady, 571 }, 572 addrs.AbsProviderConfig{ 573 Provider: addrs.NewDefaultProvider("test"), 574 Module: addrs.RootModule, 575 }, 576 ) 577 s.SetResourceProvider( 578 addrs.Resource{ 579 Mode: addrs.ManagedResourceMode, 580 Type: "test_instance", 581 Name: "bar", 582 }.Absolute(addrs.RootModuleInstance), 583 addrs.AbsProviderConfig{ 584 Provider: addrs.NewDefaultProvider("test"), 585 Module: addrs.RootModule, 586 }, 587 ) 588 }) 589 statePath := testStateFile(t, state) 590 591 p := testProvider() 592 ui := new(cli.MockUi) 593 view, _ := testView(t) 594 c := &StateMvCommand{ 595 StateMeta{ 596 Meta: Meta{ 597 testingOverrides: metaOverridesForProvider(p), 598 Ui: ui, 599 View: view, 600 RunningInAutomation: true, 601 }, 602 }, 603 } 604 605 args := []string{ 606 "-state", statePath, 607 "test_instance.foo", 608 "test_instance.bar[0]", 609 } 610 611 if code := c.Run(args); code == 0 { 612 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 613 } 614 615 expectedErr := ` 616 Error: Invalid target address 617 618 Cannot move test_instance.foo to test_instance.bar[0]: the source is a whole 619 resource (not a resource instance) so the target must also be a whole 620 resource. 621 622 ` 623 errOutput := ui.ErrorWriter.String() 624 if errOutput != expectedErr { 625 t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", errOutput, expectedErr) 626 t.Errorf("%s", cmp.Diff(errOutput, expectedErr)) 627 } 628 } 629 630 func TestStateMv_instanceToResource(t *testing.T) { 631 state := states.BuildState(func(s *states.SyncState) { 632 s.SetResourceInstanceCurrent( 633 addrs.Resource{ 634 Mode: addrs.ManagedResourceMode, 635 Type: "test_instance", 636 Name: "foo", 637 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), 638 &states.ResourceInstanceObjectSrc{ 639 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 640 Status: states.ObjectReady, 641 }, 642 addrs.AbsProviderConfig{ 643 Provider: addrs.NewDefaultProvider("test"), 644 Module: addrs.RootModule, 645 }, 646 ) 647 s.SetResourceInstanceCurrent( 648 addrs.Resource{ 649 Mode: addrs.ManagedResourceMode, 650 Type: "test_instance", 651 Name: "baz", 652 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 653 &states.ResourceInstanceObjectSrc{ 654 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 655 Status: states.ObjectReady, 656 }, 657 addrs.AbsProviderConfig{ 658 Provider: addrs.NewDefaultProvider("test"), 659 Module: addrs.RootModule, 660 }, 661 ) 662 }) 663 statePath := testStateFile(t, state) 664 665 p := testProvider() 666 ui := new(cli.MockUi) 667 view, _ := testView(t) 668 c := &StateMvCommand{ 669 StateMeta{ 670 Meta: Meta{ 671 testingOverrides: metaOverridesForProvider(p), 672 Ui: ui, 673 View: view, 674 }, 675 }, 676 } 677 678 args := []string{ 679 "-state", statePath, 680 "test_instance.foo[0]", 681 "test_instance.bar", 682 } 683 if code := c.Run(args); code != 0 { 684 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 685 } 686 687 // Test it is correct 688 testStateOutput(t, statePath, ` 689 test_instance.bar: 690 ID = bar 691 provider = provider["registry.terraform.io/hashicorp/test"] 692 bar = value 693 foo = value 694 test_instance.baz: 695 ID = foo 696 provider = provider["registry.terraform.io/hashicorp/test"] 697 bar = value 698 foo = value 699 `) 700 701 // Test we have backups 702 backups := testStateBackups(t, filepath.Dir(statePath)) 703 if len(backups) != 1 { 704 t.Fatalf("bad: %#v", backups) 705 } 706 testStateOutput(t, backups[0], ` 707 test_instance.baz: 708 ID = foo 709 provider = provider["registry.terraform.io/hashicorp/test"] 710 bar = value 711 foo = value 712 test_instance.foo.0: 713 ID = bar 714 provider = provider["registry.terraform.io/hashicorp/test"] 715 bar = value 716 foo = value 717 `) 718 } 719 720 func TestStateMv_instanceToNewResource(t *testing.T) { 721 state := states.BuildState(func(s *states.SyncState) { 722 s.SetResourceInstanceCurrent( 723 addrs.Resource{ 724 Mode: addrs.ManagedResourceMode, 725 Type: "test_instance", 726 Name: "foo", 727 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), 728 &states.ResourceInstanceObjectSrc{ 729 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 730 Status: states.ObjectReady, 731 }, 732 addrs.AbsProviderConfig{ 733 Provider: addrs.NewDefaultProvider("test"), 734 Module: addrs.RootModule, 735 }, 736 ) 737 }) 738 statePath := testStateFile(t, state) 739 740 p := testProvider() 741 ui := new(cli.MockUi) 742 view, _ := testView(t) 743 c := &StateMvCommand{ 744 StateMeta{ 745 Meta: Meta{ 746 testingOverrides: metaOverridesForProvider(p), 747 Ui: ui, 748 View: view, 749 }, 750 }, 751 } 752 753 args := []string{ 754 "-state", statePath, 755 "test_instance.foo[0]", 756 "test_instance.bar[\"new\"]", 757 } 758 if code := c.Run(args); code != 0 { 759 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 760 } 761 762 // Test it is correct 763 testStateOutput(t, statePath, ` 764 test_instance.bar["new"]: 765 ID = bar 766 provider = provider["registry.terraform.io/hashicorp/test"] 767 bar = value 768 foo = value 769 `) 770 771 // now move the instance to a new resource in a new module 772 args = []string{ 773 "-state", statePath, 774 "test_instance.bar[\"new\"]", 775 "module.test.test_instance.baz[\"new\"]", 776 } 777 if code := c.Run(args); code != 0 { 778 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 779 } 780 781 // Test it is correct 782 testStateOutput(t, statePath, ` 783 <no state> 784 module.test: 785 test_instance.baz["new"]: 786 ID = bar 787 provider = provider["registry.terraform.io/hashicorp/test"] 788 bar = value 789 foo = value 790 `) 791 } 792 793 func TestStateMv_differentResourceTypes(t *testing.T) { 794 state := states.BuildState(func(s *states.SyncState) { 795 s.SetResourceInstanceCurrent( 796 addrs.Resource{ 797 Mode: addrs.ManagedResourceMode, 798 Type: "test_instance", 799 Name: "foo", 800 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 801 &states.ResourceInstanceObjectSrc{ 802 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 803 Status: states.ObjectReady, 804 }, 805 addrs.AbsProviderConfig{ 806 Provider: addrs.NewDefaultProvider("test"), 807 Module: addrs.RootModule, 808 }, 809 ) 810 }) 811 statePath := testStateFile(t, state) 812 813 p := testProvider() 814 ui := new(cli.MockUi) 815 view, _ := testView(t) 816 c := &StateMvCommand{ 817 StateMeta{ 818 Meta: Meta{ 819 testingOverrides: metaOverridesForProvider(p), 820 Ui: ui, 821 View: view, 822 }, 823 }, 824 } 825 826 args := []string{ 827 "-state", statePath, 828 "test_instance.foo", 829 "test_network.bar", 830 } 831 if code := c.Run(args); code == 0 { 832 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 833 } 834 835 gotErr := ui.ErrorWriter.String() 836 wantErr := ` 837 Error: Invalid state move request 838 839 Cannot move test_instance.foo to test_network.bar: resource types don't 840 match. 841 842 ` 843 if gotErr != wantErr { 844 t.Fatalf("expected initialization error\ngot:\n%s\n\nwant:%s", gotErr, wantErr) 845 } 846 } 847 848 // don't modify backend state is we supply a -state flag 849 func TestStateMv_explicitWithBackend(t *testing.T) { 850 td := t.TempDir() 851 testCopyDir(t, testFixturePath("init-backend"), td) 852 defer testChdir(t, td)() 853 854 backupPath := filepath.Join(td, "backup") 855 856 state := states.BuildState(func(s *states.SyncState) { 857 s.SetResourceInstanceCurrent( 858 addrs.Resource{ 859 Mode: addrs.ManagedResourceMode, 860 Type: "test_instance", 861 Name: "foo", 862 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 863 &states.ResourceInstanceObjectSrc{ 864 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 865 Status: states.ObjectReady, 866 }, 867 addrs.AbsProviderConfig{ 868 Provider: addrs.NewDefaultProvider("test"), 869 Module: addrs.RootModule, 870 }, 871 ) 872 s.SetResourceInstanceCurrent( 873 addrs.Resource{ 874 Mode: addrs.ManagedResourceMode, 875 Type: "test_instance", 876 Name: "baz", 877 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 878 &states.ResourceInstanceObjectSrc{ 879 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 880 Status: states.ObjectReady, 881 }, 882 addrs.AbsProviderConfig{ 883 Provider: addrs.NewDefaultProvider("test"), 884 Module: addrs.RootModule, 885 }, 886 ) 887 }) 888 statePath := testStateFile(t, state) 889 890 // init our backend 891 ui := new(cli.MockUi) 892 view, _ := testView(t) 893 ic := &InitCommand{ 894 Meta: Meta{ 895 testingOverrides: metaOverridesForProvider(testProvider()), 896 Ui: ui, 897 View: view, 898 }, 899 } 900 901 args := []string{} 902 if code := ic.Run(args); code != 0 { 903 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 904 } 905 906 // only modify statePath 907 p := testProvider() 908 ui = new(cli.MockUi) 909 c := &StateMvCommand{ 910 StateMeta{ 911 Meta: Meta{ 912 testingOverrides: metaOverridesForProvider(p), 913 Ui: ui, 914 View: view, 915 }, 916 }, 917 } 918 919 args = []string{ 920 "-backup", backupPath, 921 "-state", statePath, 922 "test_instance.foo", 923 "test_instance.bar", 924 } 925 if code := c.Run(args); code != 0 { 926 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 927 } 928 929 // Test it is correct 930 testStateOutput(t, statePath, testStateMvOutput) 931 } 932 933 func TestStateMv_backupExplicit(t *testing.T) { 934 state := states.BuildState(func(s *states.SyncState) { 935 s.SetResourceInstanceCurrent( 936 addrs.Resource{ 937 Mode: addrs.ManagedResourceMode, 938 Type: "test_instance", 939 Name: "foo", 940 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 941 &states.ResourceInstanceObjectSrc{ 942 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 943 Status: states.ObjectReady, 944 }, 945 addrs.AbsProviderConfig{ 946 Provider: addrs.NewDefaultProvider("test"), 947 Module: addrs.RootModule, 948 }, 949 ) 950 s.SetResourceInstanceCurrent( 951 addrs.Resource{ 952 Mode: addrs.ManagedResourceMode, 953 Type: "test_instance", 954 Name: "baz", 955 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 956 &states.ResourceInstanceObjectSrc{ 957 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 958 Status: states.ObjectReady, 959 Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")}, 960 }, 961 addrs.AbsProviderConfig{ 962 Provider: addrs.NewDefaultProvider("test"), 963 Module: addrs.RootModule, 964 }, 965 ) 966 }) 967 statePath := testStateFile(t, state) 968 backupPath := statePath + ".backup.test" 969 970 p := testProvider() 971 ui := new(cli.MockUi) 972 view, _ := testView(t) 973 c := &StateMvCommand{ 974 StateMeta{ 975 Meta: Meta{ 976 testingOverrides: metaOverridesForProvider(p), 977 Ui: ui, 978 View: view, 979 }, 980 }, 981 } 982 983 args := []string{ 984 "-backup", backupPath, 985 "-state", statePath, 986 "test_instance.foo", 987 "test_instance.bar", 988 } 989 if code := c.Run(args); code != 0 { 990 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 991 } 992 993 // Test it is correct 994 testStateOutput(t, statePath, testStateMvOutput) 995 996 // Test backup 997 testStateOutput(t, backupPath, testStateMvOutputOriginal) 998 } 999 1000 func TestStateMv_stateOutNew(t *testing.T) { 1001 state := states.BuildState(func(s *states.SyncState) { 1002 s.SetResourceInstanceCurrent( 1003 addrs.Resource{ 1004 Mode: addrs.ManagedResourceMode, 1005 Type: "test_instance", 1006 Name: "foo", 1007 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1008 &states.ResourceInstanceObjectSrc{ 1009 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1010 Status: states.ObjectReady, 1011 }, 1012 addrs.AbsProviderConfig{ 1013 Provider: addrs.NewDefaultProvider("test"), 1014 Module: addrs.RootModule, 1015 }, 1016 ) 1017 }) 1018 statePath := testStateFile(t, state) 1019 stateOutPath := statePath + ".out" 1020 1021 p := testProvider() 1022 ui := new(cli.MockUi) 1023 view, _ := testView(t) 1024 c := &StateMvCommand{ 1025 StateMeta{ 1026 Meta: Meta{ 1027 testingOverrides: metaOverridesForProvider(p), 1028 Ui: ui, 1029 View: view, 1030 }, 1031 }, 1032 } 1033 1034 args := []string{ 1035 "-state", statePath, 1036 "-state-out", stateOutPath, 1037 "test_instance.foo", 1038 "test_instance.bar", 1039 } 1040 if code := c.Run(args); code != 0 { 1041 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1042 } 1043 1044 // Test it is correct 1045 testStateOutput(t, stateOutPath, testStateMvOutput_stateOut) 1046 testStateOutput(t, statePath, testStateMvOutput_stateOutSrc) 1047 1048 // Test we have backups 1049 backups := testStateBackups(t, filepath.Dir(statePath)) 1050 if len(backups) != 1 { 1051 t.Fatalf("bad: %#v", backups) 1052 } 1053 testStateOutput(t, backups[0], testStateMvOutput_stateOutOriginal) 1054 } 1055 1056 func TestStateMv_stateOutExisting(t *testing.T) { 1057 stateSrc := states.BuildState(func(s *states.SyncState) { 1058 s.SetResourceInstanceCurrent( 1059 addrs.Resource{ 1060 Mode: addrs.ManagedResourceMode, 1061 Type: "test_instance", 1062 Name: "foo", 1063 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1064 &states.ResourceInstanceObjectSrc{ 1065 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1066 Status: states.ObjectReady, 1067 }, 1068 addrs.AbsProviderConfig{ 1069 Provider: addrs.NewDefaultProvider("test"), 1070 Module: addrs.RootModule, 1071 }, 1072 ) 1073 }) 1074 statePath := testStateFile(t, stateSrc) 1075 1076 stateDst := states.BuildState(func(s *states.SyncState) { 1077 s.SetResourceInstanceCurrent( 1078 addrs.Resource{ 1079 Mode: addrs.ManagedResourceMode, 1080 Type: "test_instance", 1081 Name: "qux", 1082 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1083 &states.ResourceInstanceObjectSrc{ 1084 AttrsJSON: []byte(`{"id":"bar"}`), 1085 Status: states.ObjectReady, 1086 }, 1087 addrs.AbsProviderConfig{ 1088 Provider: addrs.NewDefaultProvider("test"), 1089 Module: addrs.RootModule, 1090 }, 1091 ) 1092 }) 1093 stateOutPath := testStateFile(t, stateDst) 1094 1095 p := testProvider() 1096 ui := new(cli.MockUi) 1097 view, _ := testView(t) 1098 c := &StateMvCommand{ 1099 StateMeta{ 1100 Meta: Meta{ 1101 testingOverrides: metaOverridesForProvider(p), 1102 Ui: ui, 1103 View: view, 1104 }, 1105 }, 1106 } 1107 1108 args := []string{ 1109 "-state", statePath, 1110 "-state-out", stateOutPath, 1111 "test_instance.foo", 1112 "test_instance.bar", 1113 } 1114 if code := c.Run(args); code != 0 { 1115 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1116 } 1117 1118 // Test it is correct 1119 testStateOutput(t, stateOutPath, testStateMvExisting_stateDst) 1120 testStateOutput(t, statePath, testStateMvExisting_stateSrc) 1121 1122 // Test we have backups 1123 backups := testStateBackups(t, filepath.Dir(statePath)) 1124 if len(backups) != 1 { 1125 t.Fatalf("bad: %#v", backups) 1126 } 1127 testStateOutput(t, backups[0], testStateMvExisting_stateSrcOriginal) 1128 1129 backups = testStateBackups(t, filepath.Dir(stateOutPath)) 1130 if len(backups) != 1 { 1131 t.Fatalf("bad: %#v", backups) 1132 } 1133 testStateOutput(t, backups[0], testStateMvExisting_stateDstOriginal) 1134 } 1135 1136 func TestStateMv_noState(t *testing.T) { 1137 testCwd(t) 1138 1139 p := testProvider() 1140 ui := new(cli.MockUi) 1141 view, _ := testView(t) 1142 c := &StateMvCommand{ 1143 StateMeta{ 1144 Meta: Meta{ 1145 testingOverrides: metaOverridesForProvider(p), 1146 Ui: ui, 1147 View: view, 1148 }, 1149 }, 1150 } 1151 1152 args := []string{"from", "to"} 1153 if code := c.Run(args); code != 1 { 1154 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1155 } 1156 } 1157 1158 func TestStateMv_stateOutNew_count(t *testing.T) { 1159 state := states.BuildState(func(s *states.SyncState) { 1160 s.SetResourceInstanceCurrent( 1161 addrs.Resource{ 1162 Mode: addrs.ManagedResourceMode, 1163 Type: "test_instance", 1164 Name: "foo", 1165 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), 1166 &states.ResourceInstanceObjectSrc{ 1167 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 1168 Status: states.ObjectReady, 1169 }, 1170 addrs.AbsProviderConfig{ 1171 Provider: addrs.NewDefaultProvider("test"), 1172 Module: addrs.RootModule, 1173 }, 1174 ) 1175 s.SetResourceInstanceCurrent( 1176 addrs.Resource{ 1177 Mode: addrs.ManagedResourceMode, 1178 Type: "test_instance", 1179 Name: "foo", 1180 }.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance), 1181 &states.ResourceInstanceObjectSrc{ 1182 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1183 Status: states.ObjectReady, 1184 }, 1185 addrs.AbsProviderConfig{ 1186 Provider: addrs.NewDefaultProvider("test"), 1187 Module: addrs.RootModule, 1188 }, 1189 ) 1190 s.SetResourceInstanceCurrent( 1191 addrs.Resource{ 1192 Mode: addrs.ManagedResourceMode, 1193 Type: "test_instance", 1194 Name: "bar", 1195 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1196 &states.ResourceInstanceObjectSrc{ 1197 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1198 Status: states.ObjectReady, 1199 }, 1200 addrs.AbsProviderConfig{ 1201 Provider: addrs.NewDefaultProvider("test"), 1202 Module: addrs.RootModule, 1203 }, 1204 ) 1205 }) 1206 statePath := testStateFile(t, state) 1207 stateOutPath := statePath + ".out" 1208 1209 p := testProvider() 1210 ui := new(cli.MockUi) 1211 view, _ := testView(t) 1212 c := &StateMvCommand{ 1213 StateMeta{ 1214 Meta: Meta{ 1215 testingOverrides: metaOverridesForProvider(p), 1216 Ui: ui, 1217 View: view, 1218 }, 1219 }, 1220 } 1221 1222 args := []string{ 1223 "-state", statePath, 1224 "-state-out", stateOutPath, 1225 "test_instance.foo", 1226 "test_instance.bar", 1227 } 1228 if code := c.Run(args); code != 0 { 1229 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1230 } 1231 1232 // Test it is correct 1233 testStateOutput(t, stateOutPath, testStateMvCount_stateOut) 1234 testStateOutput(t, statePath, testStateMvCount_stateOutSrc) 1235 1236 // Test we have backups 1237 backups := testStateBackups(t, filepath.Dir(statePath)) 1238 if len(backups) != 1 { 1239 t.Fatalf("bad: %#v", backups) 1240 } 1241 testStateOutput(t, backups[0], testStateMvCount_stateOutOriginal) 1242 } 1243 1244 // Modules with more than 10 resources were sorted lexically, causing the 1245 // indexes in the new location to change. 1246 func TestStateMv_stateOutNew_largeCount(t *testing.T) { 1247 state := states.BuildState(func(s *states.SyncState) { 1248 // test_instance.foo has 11 instances, all the same except for their ids 1249 for i := 0; i < 11; i++ { 1250 s.SetResourceInstanceCurrent( 1251 addrs.Resource{ 1252 Mode: addrs.ManagedResourceMode, 1253 Type: "test_instance", 1254 Name: "foo", 1255 }.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance), 1256 &states.ResourceInstanceObjectSrc{ 1257 AttrsJSON: []byte(fmt.Sprintf(`{"id":"foo%d","foo":"value","bar":"value"}`, i)), 1258 Status: states.ObjectReady, 1259 }, 1260 addrs.AbsProviderConfig{ 1261 Provider: addrs.NewDefaultProvider("test"), 1262 Module: addrs.RootModule, 1263 }, 1264 ) 1265 } 1266 s.SetResourceInstanceCurrent( 1267 addrs.Resource{ 1268 Mode: addrs.ManagedResourceMode, 1269 Type: "test_instance", 1270 Name: "bar", 1271 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1272 &states.ResourceInstanceObjectSrc{ 1273 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1274 Status: states.ObjectReady, 1275 }, 1276 addrs.AbsProviderConfig{ 1277 Provider: addrs.NewDefaultProvider("test"), 1278 Module: addrs.RootModule, 1279 }, 1280 ) 1281 }) 1282 statePath := testStateFile(t, state) 1283 stateOutPath := statePath + ".out" 1284 1285 p := testProvider() 1286 ui := new(cli.MockUi) 1287 view, _ := testView(t) 1288 c := &StateMvCommand{ 1289 StateMeta{ 1290 Meta: Meta{ 1291 testingOverrides: metaOverridesForProvider(p), 1292 Ui: ui, 1293 View: view, 1294 }, 1295 }, 1296 } 1297 1298 args := []string{ 1299 "-state", statePath, 1300 "-state-out", stateOutPath, 1301 "test_instance.foo", 1302 "test_instance.bar", 1303 } 1304 if code := c.Run(args); code != 0 { 1305 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1306 } 1307 1308 // Test it is correct 1309 testStateOutput(t, stateOutPath, testStateMvLargeCount_stateOut) 1310 testStateOutput(t, statePath, testStateMvLargeCount_stateOutSrc) 1311 1312 // Test we have backups 1313 backups := testStateBackups(t, filepath.Dir(statePath)) 1314 if len(backups) != 1 { 1315 t.Fatalf("bad: %#v", backups) 1316 } 1317 testStateOutput(t, backups[0], testStateMvLargeCount_stateOutOriginal) 1318 } 1319 1320 func TestStateMv_stateOutNew_nestedModule(t *testing.T) { 1321 state := states.BuildState(func(s *states.SyncState) { 1322 s.SetResourceInstanceCurrent( 1323 addrs.Resource{ 1324 Mode: addrs.ManagedResourceMode, 1325 Type: "test_instance", 1326 Name: "foo", 1327 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("child1", addrs.NoKey)), 1328 &states.ResourceInstanceObjectSrc{ 1329 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1330 Status: states.ObjectReady, 1331 }, 1332 addrs.AbsProviderConfig{ 1333 Provider: addrs.NewDefaultProvider("test"), 1334 Module: addrs.RootModule, 1335 }, 1336 ) 1337 s.SetResourceInstanceCurrent( 1338 addrs.Resource{ 1339 Mode: addrs.ManagedResourceMode, 1340 Type: "test_instance", 1341 Name: "foo", 1342 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("child2", addrs.NoKey)), 1343 &states.ResourceInstanceObjectSrc{ 1344 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1345 Status: states.ObjectReady, 1346 }, 1347 addrs.AbsProviderConfig{ 1348 Provider: addrs.NewDefaultProvider("test"), 1349 Module: addrs.RootModule, 1350 }, 1351 ) 1352 }) 1353 1354 statePath := testStateFile(t, state) 1355 stateOutPath := statePath + ".out" 1356 1357 p := testProvider() 1358 ui := new(cli.MockUi) 1359 view, _ := testView(t) 1360 c := &StateMvCommand{ 1361 StateMeta{ 1362 Meta: Meta{ 1363 testingOverrides: metaOverridesForProvider(p), 1364 Ui: ui, 1365 View: view, 1366 }, 1367 }, 1368 } 1369 1370 args := []string{ 1371 "-state", statePath, 1372 "-state-out", stateOutPath, 1373 "module.foo", 1374 "module.bar", 1375 } 1376 if code := c.Run(args); code != 0 { 1377 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1378 } 1379 1380 // Test it is correct 1381 testStateOutput(t, stateOutPath, testStateMvNestedModule_stateOut) 1382 testStateOutput(t, statePath, testStateMvNestedModule_stateOutSrc) 1383 1384 // Test we have backups 1385 backups := testStateBackups(t, filepath.Dir(statePath)) 1386 if len(backups) != 1 { 1387 t.Fatalf("bad: %#v", backups) 1388 } 1389 testStateOutput(t, backups[0], testStateMvNestedModule_stateOutOriginal) 1390 } 1391 1392 func TestStateMv_toNewModule(t *testing.T) { 1393 state := states.BuildState(func(s *states.SyncState) { 1394 s.SetResourceInstanceCurrent( 1395 addrs.Resource{ 1396 Mode: addrs.ManagedResourceMode, 1397 Type: "test_instance", 1398 Name: "bar", 1399 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1400 &states.ResourceInstanceObjectSrc{ 1401 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1402 Status: states.ObjectReady, 1403 }, 1404 addrs.AbsProviderConfig{ 1405 Provider: addrs.NewDefaultProvider("test"), 1406 Module: addrs.RootModule, 1407 }, 1408 ) 1409 }) 1410 1411 statePath := testStateFile(t, state) 1412 stateOutPath1 := statePath + ".out1" 1413 stateOutPath2 := statePath + ".out2" 1414 1415 p := testProvider() 1416 ui := new(cli.MockUi) 1417 view, _ := testView(t) 1418 c := &StateMvCommand{ 1419 StateMeta{ 1420 Meta: Meta{ 1421 testingOverrides: metaOverridesForProvider(p), 1422 Ui: ui, 1423 View: view, 1424 }, 1425 }, 1426 } 1427 1428 args := []string{ 1429 "-state", statePath, 1430 "-state-out", stateOutPath1, 1431 "test_instance.bar", 1432 "module.bar.test_instance.bar", 1433 } 1434 if code := c.Run(args); code != 0 { 1435 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1436 } 1437 1438 // Test it is correct 1439 testStateOutput(t, stateOutPath1, testStateMvNewModule_stateOut) 1440 testStateOutput(t, statePath, testStateMvNestedModule_stateOutSrc) 1441 1442 // Test we have backups 1443 backups := testStateBackups(t, filepath.Dir(statePath)) 1444 if len(backups) != 1 { 1445 t.Fatalf("bad: %#v", backups) 1446 } 1447 testStateOutput(t, backups[0], testStateMvNewModule_stateOutOriginal) 1448 1449 // now verify we can move the module itself 1450 args = []string{ 1451 "-state", stateOutPath1, 1452 "-state-out", stateOutPath2, 1453 "module.bar", 1454 "module.foo", 1455 } 1456 if code := c.Run(args); code != 0 { 1457 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1458 } 1459 testStateOutput(t, stateOutPath2, testStateMvModuleNewModule_stateOut) 1460 } 1461 1462 func TestStateMv_withinBackend(t *testing.T) { 1463 td := t.TempDir() 1464 testCopyDir(t, testFixturePath("backend-unchanged"), td) 1465 defer testChdir(t, td)() 1466 1467 state := states.BuildState(func(s *states.SyncState) { 1468 s.SetResourceInstanceCurrent( 1469 addrs.Resource{ 1470 Mode: addrs.ManagedResourceMode, 1471 Type: "test_instance", 1472 Name: "foo", 1473 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1474 &states.ResourceInstanceObjectSrc{ 1475 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1476 Status: states.ObjectReady, 1477 }, 1478 addrs.AbsProviderConfig{ 1479 Provider: addrs.NewDefaultProvider("test"), 1480 Module: addrs.RootModule, 1481 }, 1482 ) 1483 s.SetResourceInstanceCurrent( 1484 addrs.Resource{ 1485 Mode: addrs.ManagedResourceMode, 1486 Type: "test_instance", 1487 Name: "baz", 1488 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1489 &states.ResourceInstanceObjectSrc{ 1490 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 1491 Status: states.ObjectReady, 1492 Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")}, 1493 }, 1494 addrs.AbsProviderConfig{ 1495 Provider: addrs.NewDefaultProvider("test"), 1496 Module: addrs.RootModule, 1497 }, 1498 ) 1499 }) 1500 1501 // the local backend state file is "foo" 1502 statePath := "local-state.tfstate" 1503 backupPath := "local-state.backup" 1504 1505 f, err := os.Create(statePath) 1506 if err != nil { 1507 t.Fatal(err) 1508 } 1509 defer f.Close() 1510 1511 if err := writeStateForTesting(state, f); err != nil { 1512 t.Fatal(err) 1513 } 1514 1515 p := testProvider() 1516 ui := new(cli.MockUi) 1517 view, _ := testView(t) 1518 c := &StateMvCommand{ 1519 StateMeta{ 1520 Meta: Meta{ 1521 testingOverrides: metaOverridesForProvider(p), 1522 Ui: ui, 1523 View: view, 1524 }, 1525 }, 1526 } 1527 1528 args := []string{ 1529 "-backup", backupPath, 1530 "test_instance.foo", 1531 "test_instance.bar", 1532 } 1533 if code := c.Run(args); code != 0 { 1534 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1535 } 1536 1537 testStateOutput(t, statePath, testStateMvOutput) 1538 testStateOutput(t, backupPath, testStateMvOutputOriginal) 1539 } 1540 1541 func TestStateMv_fromBackendToLocal(t *testing.T) { 1542 td := t.TempDir() 1543 testCopyDir(t, testFixturePath("backend-unchanged"), td) 1544 defer testChdir(t, td)() 1545 1546 state := states.NewState() 1547 state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent( 1548 mustResourceAddr("test_instance.foo").Resource.Instance(addrs.NoKey), 1549 &states.ResourceInstanceObjectSrc{ 1550 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1551 Status: states.ObjectReady, 1552 }, 1553 addrs.AbsProviderConfig{ 1554 Provider: addrs.NewDefaultProvider("test"), 1555 Module: addrs.RootModule, 1556 }, 1557 ) 1558 state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent( 1559 mustResourceAddr("test_instance.baz").Resource.Instance(addrs.NoKey), 1560 &states.ResourceInstanceObjectSrc{ 1561 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 1562 Status: states.ObjectReady, 1563 }, 1564 addrs.AbsProviderConfig{ 1565 Provider: addrs.NewDefaultProvider("test"), 1566 Module: addrs.RootModule, 1567 }, 1568 ) 1569 1570 // the local backend state file is "foo" 1571 statePath := "local-state.tfstate" 1572 1573 // real "local" state file 1574 statePathOut := "real-local.tfstate" 1575 1576 f, err := os.Create(statePath) 1577 if err != nil { 1578 t.Fatal(err) 1579 } 1580 defer f.Close() 1581 1582 if err := writeStateForTesting(state, f); err != nil { 1583 t.Fatal(err) 1584 } 1585 1586 p := testProvider() 1587 ui := new(cli.MockUi) 1588 view, _ := testView(t) 1589 c := &StateMvCommand{ 1590 StateMeta{ 1591 Meta: Meta{ 1592 testingOverrides: metaOverridesForProvider(p), 1593 Ui: ui, 1594 View: view, 1595 }, 1596 }, 1597 } 1598 1599 args := []string{ 1600 "-state-out", statePathOut, 1601 "test_instance.foo", 1602 "test_instance.bar", 1603 } 1604 if code := c.Run(args); code != 0 { 1605 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1606 } 1607 1608 testStateOutput(t, statePathOut, testStateMvCount_stateOutSrc) 1609 1610 // the backend state should be left with only baz 1611 testStateOutput(t, statePath, testStateMvOriginal_backend) 1612 } 1613 1614 // This test covers moving the only resource in a module to a new address in 1615 // that module, which triggers the maybePruneModule functionality. This caused 1616 // a panic report: https://github.com/hashicorp/terraform/issues/25520 1617 func TestStateMv_onlyResourceInModule(t *testing.T) { 1618 state := states.BuildState(func(s *states.SyncState) { 1619 s.SetResourceInstanceCurrent( 1620 addrs.Resource{ 1621 Mode: addrs.ManagedResourceMode, 1622 Type: "test_instance", 1623 Name: "foo", 1624 }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey)), 1625 &states.ResourceInstanceObjectSrc{ 1626 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1627 Status: states.ObjectReady, 1628 }, 1629 addrs.AbsProviderConfig{ 1630 Provider: addrs.NewDefaultProvider("test"), 1631 Module: addrs.RootModule, 1632 }, 1633 ) 1634 }) 1635 1636 statePath := testStateFile(t, state) 1637 testStateOutput(t, statePath, testStateMvOnlyResourceInModule_original) 1638 1639 p := testProvider() 1640 ui := new(cli.MockUi) 1641 view, _ := testView(t) 1642 c := &StateMvCommand{ 1643 StateMeta{ 1644 Meta: Meta{ 1645 testingOverrides: metaOverridesForProvider(p), 1646 Ui: ui, 1647 View: view, 1648 }, 1649 }, 1650 } 1651 1652 args := []string{ 1653 "-state", statePath, 1654 "module.foo.test_instance.foo", 1655 "module.foo.test_instance.bar", 1656 } 1657 if code := c.Run(args); code != 0 { 1658 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 1659 } 1660 1661 // Test it is correct 1662 testStateOutput(t, statePath, testStateMvOnlyResourceInModule_output) 1663 1664 // Test we have backups 1665 backups := testStateBackups(t, filepath.Dir(statePath)) 1666 if len(backups) != 1 { 1667 t.Fatalf("bad: %#v", backups) 1668 } 1669 testStateOutput(t, backups[0], testStateMvOnlyResourceInModule_original) 1670 } 1671 1672 func TestStateMvHelp(t *testing.T) { 1673 c := &StateMvCommand{} 1674 if strings.ContainsRune(c.Help(), '\t') { 1675 t.Fatal("help text contains tab character, which will result in poor formatting") 1676 } 1677 } 1678 1679 func TestStateMvInvalidSourceAddress(t *testing.T) { 1680 state := states.BuildState(func(s *states.SyncState) {}) 1681 statePath := testStateFile(t, state) 1682 1683 p := testProvider() 1684 ui := new(cli.MockUi) 1685 view, _ := testView(t) 1686 c := &StateMvCommand{ 1687 StateMeta{ 1688 Meta: Meta{ 1689 testingOverrides: metaOverridesForProvider(p), 1690 Ui: ui, 1691 View: view, 1692 }, 1693 }, 1694 } 1695 1696 args := []string{ 1697 "-state", statePath, 1698 "foo.bar1", 1699 "foo.bar2", 1700 } 1701 code := c.Run(args) 1702 if code != 1 { 1703 t.Fatalf("expected error code 1, got:\n%d", code) 1704 } 1705 } 1706 1707 func TestStateMv_checkRequiredVersion(t *testing.T) { 1708 // Create a temporary working directory that is empty 1709 td := t.TempDir() 1710 testCopyDir(t, testFixturePath("command-check-required-version"), td) 1711 defer testChdir(t, td)() 1712 1713 state := states.BuildState(func(s *states.SyncState) { 1714 s.SetResourceInstanceCurrent( 1715 addrs.Resource{ 1716 Mode: addrs.ManagedResourceMode, 1717 Type: "test_instance", 1718 Name: "foo", 1719 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1720 &states.ResourceInstanceObjectSrc{ 1721 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 1722 Status: states.ObjectReady, 1723 }, 1724 addrs.AbsProviderConfig{ 1725 Provider: addrs.NewDefaultProvider("test"), 1726 Module: addrs.RootModule, 1727 }, 1728 ) 1729 s.SetResourceInstanceCurrent( 1730 addrs.Resource{ 1731 Mode: addrs.ManagedResourceMode, 1732 Type: "test_instance", 1733 Name: "baz", 1734 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 1735 &states.ResourceInstanceObjectSrc{ 1736 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 1737 Status: states.ObjectReady, 1738 Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")}, 1739 }, 1740 addrs.AbsProviderConfig{ 1741 Provider: addrs.NewDefaultProvider("test"), 1742 Module: addrs.RootModule, 1743 }, 1744 ) 1745 }) 1746 statePath := testStateFile(t, state) 1747 1748 p := testProvider() 1749 ui := new(cli.MockUi) 1750 view, _ := testView(t) 1751 c := &StateMvCommand{ 1752 StateMeta{ 1753 Meta: Meta{ 1754 testingOverrides: metaOverridesForProvider(p), 1755 Ui: ui, 1756 View: view, 1757 }, 1758 }, 1759 } 1760 1761 args := []string{ 1762 "-state", statePath, 1763 "test_instance.foo", 1764 "test_instance.bar", 1765 } 1766 1767 if code := c.Run(args); code != 1 { 1768 t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) 1769 } 1770 1771 // State is unchanged 1772 testStateOutput(t, statePath, testStateMvOutputOriginal) 1773 1774 // Required version diags are correct 1775 errStr := ui.ErrorWriter.String() 1776 if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) { 1777 t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr) 1778 } 1779 if strings.Contains(errStr, `required_version = ">= 0.13.0"`) { 1780 t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr) 1781 } 1782 } 1783 1784 const testStateMvOutputOriginal = ` 1785 test_instance.baz: 1786 ID = foo 1787 provider = provider["registry.terraform.io/hashicorp/test"] 1788 bar = value 1789 foo = value 1790 1791 Dependencies: 1792 test_instance.foo 1793 test_instance.foo: 1794 ID = bar 1795 provider = provider["registry.terraform.io/hashicorp/test"] 1796 bar = value 1797 foo = value 1798 ` 1799 1800 const testStateMvOutput = ` 1801 test_instance.bar: 1802 ID = bar 1803 provider = provider["registry.terraform.io/hashicorp/test"] 1804 bar = value 1805 foo = value 1806 test_instance.baz: 1807 ID = foo 1808 provider = provider["registry.terraform.io/hashicorp/test"] 1809 bar = value 1810 foo = value 1811 ` 1812 1813 const testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput = ` 1814 test_instance.bar: 1815 ID = bar 1816 provider = provider["registry.terraform.io/hashicorp/test"] 1817 bar = value 1818 foo = value 1819 ` 1820 1821 const testStateMvCount_stateOut = ` 1822 test_instance.bar.0: 1823 ID = foo 1824 provider = provider["registry.terraform.io/hashicorp/test"] 1825 bar = value 1826 foo = value 1827 test_instance.bar.1: 1828 ID = bar 1829 provider = provider["registry.terraform.io/hashicorp/test"] 1830 bar = value 1831 foo = value 1832 ` 1833 1834 const testStateMvCount_stateOutSrc = ` 1835 test_instance.bar: 1836 ID = bar 1837 provider = provider["registry.terraform.io/hashicorp/test"] 1838 bar = value 1839 foo = value 1840 ` 1841 1842 const testStateMvCount_stateOutOriginal = ` 1843 test_instance.bar: 1844 ID = bar 1845 provider = provider["registry.terraform.io/hashicorp/test"] 1846 bar = value 1847 foo = value 1848 test_instance.foo.0: 1849 ID = foo 1850 provider = provider["registry.terraform.io/hashicorp/test"] 1851 bar = value 1852 foo = value 1853 test_instance.foo.1: 1854 ID = bar 1855 provider = provider["registry.terraform.io/hashicorp/test"] 1856 bar = value 1857 foo = value 1858 ` 1859 1860 const testStateMvLargeCount_stateOut = ` 1861 test_instance.bar.0: 1862 ID = foo0 1863 provider = provider["registry.terraform.io/hashicorp/test"] 1864 bar = value 1865 foo = value 1866 test_instance.bar.1: 1867 ID = foo1 1868 provider = provider["registry.terraform.io/hashicorp/test"] 1869 bar = value 1870 foo = value 1871 test_instance.bar.2: 1872 ID = foo2 1873 provider = provider["registry.terraform.io/hashicorp/test"] 1874 bar = value 1875 foo = value 1876 test_instance.bar.3: 1877 ID = foo3 1878 provider = provider["registry.terraform.io/hashicorp/test"] 1879 bar = value 1880 foo = value 1881 test_instance.bar.4: 1882 ID = foo4 1883 provider = provider["registry.terraform.io/hashicorp/test"] 1884 bar = value 1885 foo = value 1886 test_instance.bar.5: 1887 ID = foo5 1888 provider = provider["registry.terraform.io/hashicorp/test"] 1889 bar = value 1890 foo = value 1891 test_instance.bar.6: 1892 ID = foo6 1893 provider = provider["registry.terraform.io/hashicorp/test"] 1894 bar = value 1895 foo = value 1896 test_instance.bar.7: 1897 ID = foo7 1898 provider = provider["registry.terraform.io/hashicorp/test"] 1899 bar = value 1900 foo = value 1901 test_instance.bar.8: 1902 ID = foo8 1903 provider = provider["registry.terraform.io/hashicorp/test"] 1904 bar = value 1905 foo = value 1906 test_instance.bar.9: 1907 ID = foo9 1908 provider = provider["registry.terraform.io/hashicorp/test"] 1909 bar = value 1910 foo = value 1911 test_instance.bar.10: 1912 ID = foo10 1913 provider = provider["registry.terraform.io/hashicorp/test"] 1914 bar = value 1915 foo = value 1916 ` 1917 1918 const testStateMvLargeCount_stateOutSrc = ` 1919 test_instance.bar: 1920 ID = bar 1921 provider = provider["registry.terraform.io/hashicorp/test"] 1922 bar = value 1923 foo = value 1924 ` 1925 1926 const testStateMvLargeCount_stateOutOriginal = ` 1927 test_instance.bar: 1928 ID = bar 1929 provider = provider["registry.terraform.io/hashicorp/test"] 1930 bar = value 1931 foo = value 1932 test_instance.foo.0: 1933 ID = foo0 1934 provider = provider["registry.terraform.io/hashicorp/test"] 1935 bar = value 1936 foo = value 1937 test_instance.foo.1: 1938 ID = foo1 1939 provider = provider["registry.terraform.io/hashicorp/test"] 1940 bar = value 1941 foo = value 1942 test_instance.foo.2: 1943 ID = foo2 1944 provider = provider["registry.terraform.io/hashicorp/test"] 1945 bar = value 1946 foo = value 1947 test_instance.foo.3: 1948 ID = foo3 1949 provider = provider["registry.terraform.io/hashicorp/test"] 1950 bar = value 1951 foo = value 1952 test_instance.foo.4: 1953 ID = foo4 1954 provider = provider["registry.terraform.io/hashicorp/test"] 1955 bar = value 1956 foo = value 1957 test_instance.foo.5: 1958 ID = foo5 1959 provider = provider["registry.terraform.io/hashicorp/test"] 1960 bar = value 1961 foo = value 1962 test_instance.foo.6: 1963 ID = foo6 1964 provider = provider["registry.terraform.io/hashicorp/test"] 1965 bar = value 1966 foo = value 1967 test_instance.foo.7: 1968 ID = foo7 1969 provider = provider["registry.terraform.io/hashicorp/test"] 1970 bar = value 1971 foo = value 1972 test_instance.foo.8: 1973 ID = foo8 1974 provider = provider["registry.terraform.io/hashicorp/test"] 1975 bar = value 1976 foo = value 1977 test_instance.foo.9: 1978 ID = foo9 1979 provider = provider["registry.terraform.io/hashicorp/test"] 1980 bar = value 1981 foo = value 1982 test_instance.foo.10: 1983 ID = foo10 1984 provider = provider["registry.terraform.io/hashicorp/test"] 1985 bar = value 1986 foo = value 1987 ` 1988 1989 const testStateMvNestedModule_stateOut = ` 1990 <no state> 1991 module.bar.child1: 1992 test_instance.foo: 1993 ID = bar 1994 provider = provider["registry.terraform.io/hashicorp/test"] 1995 bar = value 1996 foo = value 1997 module.bar.child2: 1998 test_instance.foo: 1999 ID = bar 2000 provider = provider["registry.terraform.io/hashicorp/test"] 2001 bar = value 2002 foo = value 2003 ` 2004 2005 const testStateMvNewModule_stateOut = ` 2006 <no state> 2007 module.bar: 2008 test_instance.bar: 2009 ID = bar 2010 provider = provider["registry.terraform.io/hashicorp/test"] 2011 bar = value 2012 foo = value 2013 ` 2014 2015 const testStateMvModuleNewModule_stateOut = ` 2016 <no state> 2017 module.foo: 2018 test_instance.bar: 2019 ID = bar 2020 provider = provider["registry.terraform.io/hashicorp/test"] 2021 bar = value 2022 foo = value 2023 ` 2024 2025 const testStateMvNewModule_stateOutOriginal = ` 2026 test_instance.bar: 2027 ID = bar 2028 provider = provider["registry.terraform.io/hashicorp/test"] 2029 bar = value 2030 foo = value 2031 ` 2032 2033 const testStateMvNestedModule_stateOutSrc = ` 2034 <no state> 2035 ` 2036 2037 const testStateMvNestedModule_stateOutOriginal = ` 2038 <no state> 2039 module.foo.child1: 2040 test_instance.foo: 2041 ID = bar 2042 provider = provider["registry.terraform.io/hashicorp/test"] 2043 bar = value 2044 foo = value 2045 module.foo.child2: 2046 test_instance.foo: 2047 ID = bar 2048 provider = provider["registry.terraform.io/hashicorp/test"] 2049 bar = value 2050 foo = value 2051 ` 2052 2053 const testStateMvOutput_stateOut = ` 2054 test_instance.bar: 2055 ID = bar 2056 provider = provider["registry.terraform.io/hashicorp/test"] 2057 bar = value 2058 foo = value 2059 ` 2060 2061 const testStateMvOutput_stateOutSrc = ` 2062 <no state> 2063 ` 2064 2065 const testStateMvOutput_stateOutOriginal = ` 2066 test_instance.foo: 2067 ID = bar 2068 provider = provider["registry.terraform.io/hashicorp/test"] 2069 bar = value 2070 foo = value 2071 ` 2072 2073 const testStateMvExisting_stateSrc = ` 2074 <no state> 2075 ` 2076 2077 const testStateMvExisting_stateDst = ` 2078 test_instance.bar: 2079 ID = bar 2080 provider = provider["registry.terraform.io/hashicorp/test"] 2081 bar = value 2082 foo = value 2083 test_instance.qux: 2084 ID = bar 2085 provider = provider["registry.terraform.io/hashicorp/test"] 2086 ` 2087 2088 const testStateMvExisting_stateSrcOriginal = ` 2089 test_instance.foo: 2090 ID = bar 2091 provider = provider["registry.terraform.io/hashicorp/test"] 2092 bar = value 2093 foo = value 2094 ` 2095 2096 const testStateMvExisting_stateDstOriginal = ` 2097 test_instance.qux: 2098 ID = bar 2099 provider = provider["registry.terraform.io/hashicorp/test"] 2100 ` 2101 2102 const testStateMvOriginal_backend = ` 2103 test_instance.baz: 2104 ID = foo 2105 provider = provider["registry.terraform.io/hashicorp/test"] 2106 bar = value 2107 foo = value 2108 ` 2109 2110 const testStateMvOnlyResourceInModule_original = ` 2111 <no state> 2112 module.foo: 2113 test_instance.foo.0: 2114 ID = bar 2115 provider = provider["registry.terraform.io/hashicorp/test"] 2116 bar = value 2117 foo = value 2118 ` 2119 2120 const testStateMvOnlyResourceInModule_output = ` 2121 <no state> 2122 module.foo: 2123 test_instance.bar.0: 2124 ID = bar 2125 provider = provider["registry.terraform.io/hashicorp/test"] 2126 bar = value 2127 foo = value 2128 `