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