github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/command/init_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "reflect" 9 "runtime" 10 "sort" 11 "strings" 12 "testing" 13 14 "github.com/hashicorp/terraform/backend/local" 15 "github.com/hashicorp/terraform/helper/copy" 16 "github.com/hashicorp/terraform/plugin/discovery" 17 "github.com/hashicorp/terraform/state" 18 "github.com/hashicorp/terraform/terraform" 19 "github.com/mitchellh/cli" 20 ) 21 22 func TestInit_empty(t *testing.T) { 23 // Create a temporary working directory that is empty 24 td := tempDir(t) 25 os.MkdirAll(td, 0755) 26 defer os.RemoveAll(td) 27 defer testChdir(t, td)() 28 29 ui := new(cli.MockUi) 30 c := &InitCommand{ 31 Meta: Meta{ 32 testingOverrides: metaOverridesForProvider(testProvider()), 33 Ui: ui, 34 }, 35 } 36 37 args := []string{} 38 if code := c.Run(args); code != 0 { 39 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 40 } 41 } 42 43 func TestInit_multipleArgs(t *testing.T) { 44 ui := new(cli.MockUi) 45 c := &InitCommand{ 46 Meta: Meta{ 47 testingOverrides: metaOverridesForProvider(testProvider()), 48 Ui: ui, 49 }, 50 } 51 52 args := []string{ 53 "bad", 54 "bad", 55 } 56 if code := c.Run(args); code != 1 { 57 t.Fatalf("bad: \n%s", ui.OutputWriter.String()) 58 } 59 } 60 61 func TestInit_fromModule_explicitDest(t *testing.T) { 62 dir := tempDir(t) 63 64 ui := new(cli.MockUi) 65 c := &InitCommand{ 66 Meta: Meta{ 67 testingOverrides: metaOverridesForProvider(testProvider()), 68 Ui: ui, 69 }, 70 } 71 72 args := []string{ 73 "-from-module=" + testFixturePath("init"), 74 dir, 75 } 76 if code := c.Run(args); code != 0 { 77 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 78 } 79 80 if _, err := os.Stat(filepath.Join(dir, "hello.tf")); err != nil { 81 t.Fatalf("err: %s", err) 82 } 83 } 84 85 func TestInit_fromModule_cwdDest(t *testing.T) { 86 // Create a temporary working directory that is empty 87 td := tempDir(t) 88 os.MkdirAll(td, os.ModePerm) 89 defer os.RemoveAll(td) 90 defer testChdir(t, td)() 91 92 ui := new(cli.MockUi) 93 c := &InitCommand{ 94 Meta: Meta{ 95 testingOverrides: metaOverridesForProvider(testProvider()), 96 Ui: ui, 97 }, 98 } 99 100 args := []string{ 101 "-from-module=" + testFixturePath("init"), 102 } 103 if code := c.Run(args); code != 0 { 104 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 105 } 106 107 if _, err := os.Stat(filepath.Join(td, "hello.tf")); err != nil { 108 t.Fatalf("err: %s", err) 109 } 110 } 111 112 // https://github.com/hashicorp/terraform/issues/518 113 func TestInit_fromModule_dstInSrc(t *testing.T) { 114 dir := tempDir(t) 115 if err := os.MkdirAll(dir, 0755); err != nil { 116 t.Fatalf("err: %s", err) 117 } 118 119 // Change to the temporary directory 120 cwd, err := os.Getwd() 121 if err != nil { 122 t.Fatalf("err: %s", err) 123 } 124 if err := os.Chdir(dir); err != nil { 125 t.Fatalf("err: %s", err) 126 } 127 defer os.Chdir(cwd) 128 129 if _, err := os.Create("issue518.tf"); err != nil { 130 t.Fatalf("err: %s", err) 131 } 132 133 ui := new(cli.MockUi) 134 c := &InitCommand{ 135 Meta: Meta{ 136 testingOverrides: metaOverridesForProvider(testProvider()), 137 Ui: ui, 138 }, 139 } 140 141 args := []string{ 142 "-from-module=.", 143 "foo", 144 } 145 if code := c.Run(args); code != 0 { 146 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 147 } 148 149 if _, err := os.Stat(filepath.Join(dir, "foo", "issue518.tf")); err != nil { 150 t.Fatalf("err: %s", err) 151 } 152 } 153 154 func TestInit_get(t *testing.T) { 155 // Create a temporary working directory that is empty 156 td := tempDir(t) 157 copy.CopyDir(testFixturePath("init-get"), td) 158 defer os.RemoveAll(td) 159 defer testChdir(t, td)() 160 161 ui := new(cli.MockUi) 162 c := &InitCommand{ 163 Meta: Meta{ 164 testingOverrides: metaOverridesForProvider(testProvider()), 165 Ui: ui, 166 }, 167 } 168 169 args := []string{} 170 if code := c.Run(args); code != 0 { 171 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 172 } 173 174 // Check output 175 output := ui.OutputWriter.String() 176 if !strings.Contains(output, "Getting source") { 177 t.Fatalf("doesn't look like get: %s", output) 178 } 179 } 180 181 func TestInit_getUpgradeModules(t *testing.T) { 182 // Create a temporary working directory that is empty 183 td := tempDir(t) 184 os.MkdirAll(td, 0755) 185 // copy.CopyDir(testFixturePath("init-get"), td) 186 defer os.RemoveAll(td) 187 defer testChdir(t, td)() 188 189 ui := new(cli.MockUi) 190 c := &InitCommand{ 191 Meta: Meta{ 192 testingOverrides: metaOverridesForProvider(testProvider()), 193 Ui: ui, 194 }, 195 } 196 197 args := []string{ 198 "-get=true", 199 "-get-plugins=false", 200 "-upgrade", 201 testFixturePath("init-get"), 202 } 203 if code := c.Run(args); code != 0 { 204 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 205 } 206 207 // Check output 208 output := ui.OutputWriter.String() 209 if !strings.Contains(output, "Updating source") { 210 t.Fatalf("doesn't look like get upgrade: %s", output) 211 } 212 } 213 214 func TestInit_backend(t *testing.T) { 215 // Create a temporary working directory that is empty 216 td := tempDir(t) 217 copy.CopyDir(testFixturePath("init-backend"), td) 218 defer os.RemoveAll(td) 219 defer testChdir(t, td)() 220 221 ui := new(cli.MockUi) 222 c := &InitCommand{ 223 Meta: Meta{ 224 testingOverrides: metaOverridesForProvider(testProvider()), 225 Ui: ui, 226 }, 227 } 228 229 args := []string{} 230 if code := c.Run(args); code != 0 { 231 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 232 } 233 234 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 235 t.Fatalf("err: %s", err) 236 } 237 } 238 239 func TestInit_backendUnset(t *testing.T) { 240 // Create a temporary working directory that is empty 241 td := tempDir(t) 242 copy.CopyDir(testFixturePath("init-backend"), td) 243 defer os.RemoveAll(td) 244 defer testChdir(t, td)() 245 246 { 247 ui := new(cli.MockUi) 248 c := &InitCommand{ 249 Meta: Meta{ 250 testingOverrides: metaOverridesForProvider(testProvider()), 251 Ui: ui, 252 }, 253 } 254 255 // Init 256 args := []string{} 257 if code := c.Run(args); code != 0 { 258 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 259 } 260 261 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 262 t.Fatalf("err: %s", err) 263 } 264 } 265 266 { 267 // Unset 268 if err := ioutil.WriteFile("main.tf", []byte(""), 0644); err != nil { 269 t.Fatalf("err: %s", err) 270 } 271 272 ui := new(cli.MockUi) 273 c := &InitCommand{ 274 Meta: Meta{ 275 testingOverrides: metaOverridesForProvider(testProvider()), 276 Ui: ui, 277 }, 278 } 279 280 args := []string{"-force-copy"} 281 if code := c.Run(args); code != 0 { 282 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 283 } 284 285 s := testStateRead(t, filepath.Join( 286 DefaultDataDir, DefaultStateFilename)) 287 if !s.Backend.Empty() { 288 t.Fatal("should not have backend config") 289 } 290 } 291 } 292 293 func TestInit_backendConfigFile(t *testing.T) { 294 // Create a temporary working directory that is empty 295 td := tempDir(t) 296 copy.CopyDir(testFixturePath("init-backend-config-file"), td) 297 defer os.RemoveAll(td) 298 defer testChdir(t, td)() 299 300 ui := new(cli.MockUi) 301 c := &InitCommand{ 302 Meta: Meta{ 303 testingOverrides: metaOverridesForProvider(testProvider()), 304 Ui: ui, 305 }, 306 } 307 308 args := []string{"-backend-config", "input.config"} 309 if code := c.Run(args); code != 0 { 310 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 311 } 312 313 // Read our saved backend config and verify we have our settings 314 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 315 if v := state.Backend.Config["path"]; v != "hello" { 316 t.Fatalf("bad: %#v", v) 317 } 318 } 319 320 func TestInit_backendConfigFileChange(t *testing.T) { 321 // Create a temporary working directory that is empty 322 td := tempDir(t) 323 copy.CopyDir(testFixturePath("init-backend-config-file-change"), td) 324 defer os.RemoveAll(td) 325 defer testChdir(t, td)() 326 327 // Ask input 328 defer testInputMap(t, map[string]string{ 329 "backend-migrate-to-new": "no", 330 })() 331 332 ui := new(cli.MockUi) 333 c := &InitCommand{ 334 Meta: Meta{ 335 testingOverrides: metaOverridesForProvider(testProvider()), 336 Ui: ui, 337 }, 338 } 339 340 args := []string{"-backend-config", "input.config"} 341 if code := c.Run(args); code != 0 { 342 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 343 } 344 345 // Read our saved backend config and verify we have our settings 346 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 347 if v := state.Backend.Config["path"]; v != "hello" { 348 t.Fatalf("bad: %#v", v) 349 } 350 } 351 352 func TestInit_backendConfigKV(t *testing.T) { 353 // Create a temporary working directory that is empty 354 td := tempDir(t) 355 copy.CopyDir(testFixturePath("init-backend-config-kv"), td) 356 defer os.RemoveAll(td) 357 defer testChdir(t, td)() 358 359 ui := new(cli.MockUi) 360 c := &InitCommand{ 361 Meta: Meta{ 362 testingOverrides: metaOverridesForProvider(testProvider()), 363 Ui: ui, 364 }, 365 } 366 367 args := []string{"-backend-config", "path=hello"} 368 if code := c.Run(args); code != 0 { 369 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 370 } 371 372 // Read our saved backend config and verify we have our settings 373 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 374 if v := state.Backend.Config["path"]; v != "hello" { 375 t.Fatalf("bad: %#v", v) 376 } 377 } 378 379 func TestInit_targetSubdir(t *testing.T) { 380 // Create a temporary working directory that is empty 381 td := tempDir(t) 382 os.MkdirAll(td, 0755) 383 defer os.RemoveAll(td) 384 defer testChdir(t, td)() 385 386 // copy the source into a subdir 387 copy.CopyDir(testFixturePath("init-backend"), filepath.Join(td, "source")) 388 389 ui := new(cli.MockUi) 390 c := &InitCommand{ 391 Meta: Meta{ 392 testingOverrides: metaOverridesForProvider(testProvider()), 393 Ui: ui, 394 }, 395 } 396 397 args := []string{ 398 "source", 399 } 400 if code := c.Run(args); code != 0 { 401 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 402 } 403 404 if _, err := os.Stat(filepath.Join(td, DefaultDataDir, DefaultStateFilename)); err != nil { 405 t.Fatalf("err: %s", err) 406 } 407 408 // a data directory should not have been added to out working dir 409 if _, err := os.Stat(filepath.Join(td, "source", DefaultDataDir)); !os.IsNotExist(err) { 410 t.Fatalf("err: %s", err) 411 } 412 } 413 414 func TestInit_backendReinitWithExtra(t *testing.T) { 415 td := tempDir(t) 416 copy.CopyDir(testFixturePath("init-backend-empty"), td) 417 defer os.RemoveAll(td) 418 defer testChdir(t, td)() 419 420 m := testMetaBackend(t, nil) 421 opts := &BackendOpts{ 422 ConfigExtra: map[string]interface{}{"path": "hello"}, 423 Init: true, 424 } 425 426 b, err := m.backendConfig(opts) 427 if err != nil { 428 t.Fatal(err) 429 } 430 431 ui := new(cli.MockUi) 432 c := &InitCommand{ 433 Meta: Meta{ 434 testingOverrides: metaOverridesForProvider(testProvider()), 435 Ui: ui, 436 }, 437 } 438 439 args := []string{"-backend-config", "path=hello"} 440 if code := c.Run(args); code != 0 { 441 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 442 } 443 444 // Read our saved backend config and verify we have our settings 445 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 446 if v := state.Backend.Config["path"]; v != "hello" { 447 t.Fatalf("bad: %#v", v) 448 } 449 450 if state.Backend.Hash != b.Hash { 451 t.Fatal("mismatched state and config backend hashes") 452 } 453 454 if state.Backend.Rehash() != b.Rehash() { 455 t.Fatal("mismatched state and config re-hashes") 456 } 457 458 // init again and make sure nothing changes 459 if code := c.Run(args); code != 0 { 460 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 461 } 462 state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 463 if v := state.Backend.Config["path"]; v != "hello" { 464 t.Fatalf("bad: %#v", v) 465 } 466 467 if state.Backend.Hash != b.Hash { 468 t.Fatal("mismatched state and config backend hashes") 469 } 470 } 471 472 // move option from config to -backend-config args 473 func TestInit_backendReinitConfigToExtra(t *testing.T) { 474 td := tempDir(t) 475 copy.CopyDir(testFixturePath("init-backend"), td) 476 defer os.RemoveAll(td) 477 defer testChdir(t, td)() 478 479 ui := new(cli.MockUi) 480 c := &InitCommand{ 481 Meta: Meta{ 482 testingOverrides: metaOverridesForProvider(testProvider()), 483 Ui: ui, 484 }, 485 } 486 487 if code := c.Run([]string{"-input=false"}); code != 0 { 488 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 489 } 490 491 // Read our saved backend config and verify we have our settings 492 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 493 if v := state.Backend.Config["path"]; v != "foo" { 494 t.Fatalf("bad: %#v", v) 495 } 496 497 backendHash := state.Backend.Hash 498 499 // init again but remove the path option from the config 500 cfg := "terraform {\n backend \"local\" {}\n}\n" 501 if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil { 502 t.Fatal(err) 503 } 504 505 args := []string{"-input=false", "-backend-config=path=foo"} 506 if code := c.Run(args); code != 0 { 507 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 508 } 509 state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 510 511 if state.Backend.Hash == backendHash { 512 t.Fatal("state.Backend.Hash was not updated") 513 } 514 } 515 516 // make sure inputFalse stops execution on migrate 517 func TestInit_inputFalse(t *testing.T) { 518 td := tempDir(t) 519 copy.CopyDir(testFixturePath("init-backend"), td) 520 defer os.RemoveAll(td) 521 defer testChdir(t, td)() 522 523 ui := new(cli.MockUi) 524 c := &InitCommand{ 525 Meta: Meta{ 526 testingOverrides: metaOverridesForProvider(testProvider()), 527 Ui: ui, 528 }, 529 } 530 531 args := []string{"-input=false", "-backend-config=path=foo"} 532 if code := c.Run([]string{"-input=false"}); code != 0 { 533 t.Fatalf("bad: \n%s", ui.ErrorWriter) 534 } 535 536 // write different states for foo and bar 537 s := terraform.NewState() 538 s.Lineage = "foo" 539 if err := (&state.LocalState{Path: "foo"}).WriteState(s); err != nil { 540 t.Fatal(err) 541 } 542 s.Lineage = "bar" 543 if err := (&state.LocalState{Path: "bar"}).WriteState(s); err != nil { 544 t.Fatal(err) 545 } 546 547 ui = new(cli.MockUi) 548 c = &InitCommand{ 549 Meta: Meta{ 550 testingOverrides: metaOverridesForProvider(testProvider()), 551 Ui: ui, 552 }, 553 } 554 555 args = []string{"-input=false", "-backend-config=path=bar"} 556 if code := c.Run(args); code == 0 { 557 t.Fatal("init should have failed", ui.OutputWriter) 558 } 559 560 errMsg := ui.ErrorWriter.String() 561 if !strings.Contains(errMsg, "input disabled") { 562 t.Fatal("expected input disabled error, got", errMsg) 563 } 564 565 ui = new(cli.MockUi) 566 c = &InitCommand{ 567 Meta: Meta{ 568 testingOverrides: metaOverridesForProvider(testProvider()), 569 Ui: ui, 570 }, 571 } 572 573 // A missing input=false should abort rather than loop infinitely 574 args = []string{"-backend-config=path=bar"} 575 if code := c.Run(args); code == 0 { 576 t.Fatal("init should have failed", ui.OutputWriter) 577 } 578 } 579 580 func TestInit_getProvider(t *testing.T) { 581 // Create a temporary working directory that is empty 582 td := tempDir(t) 583 copy.CopyDir(testFixturePath("init-get-providers"), td) 584 defer os.RemoveAll(td) 585 defer testChdir(t, td)() 586 587 overrides := metaOverridesForProvider(testProvider()) 588 ui := new(cli.MockUi) 589 m := Meta{ 590 testingOverrides: overrides, 591 Ui: ui, 592 } 593 installer := &mockProviderInstaller{ 594 Providers: map[string][]string{ 595 // looking for an exact version 596 "exact": []string{"1.2.3"}, 597 // config requires >= 2.3.3 598 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 599 // config specifies 600 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 601 }, 602 603 Dir: m.pluginDir(), 604 } 605 606 c := &InitCommand{ 607 Meta: m, 608 providerInstaller: installer, 609 } 610 611 args := []string{ 612 "-backend=false", // should be possible to install plugins without backend init 613 } 614 if code := c.Run(args); code != 0 { 615 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 616 } 617 618 if !installer.PurgeUnusedCalled { 619 t.Errorf("init didn't purge providers, but should have") 620 } 621 622 // check that we got the providers for our config 623 exactPath := filepath.Join(c.pluginDir(), installer.FileName("exact", "1.2.3")) 624 if _, err := os.Stat(exactPath); os.IsNotExist(err) { 625 t.Fatal("provider 'exact' not downloaded") 626 } 627 greaterThanPath := filepath.Join(c.pluginDir(), installer.FileName("greater_than", "2.3.4")) 628 if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) { 629 t.Fatal("provider 'greater_than' not downloaded") 630 } 631 betweenPath := filepath.Join(c.pluginDir(), installer.FileName("between", "2.3.4")) 632 if _, err := os.Stat(betweenPath); os.IsNotExist(err) { 633 t.Fatal("provider 'between' not downloaded") 634 } 635 636 t.Run("future-state", func(t *testing.T) { 637 // getting providers should fail if a state from a newer version of 638 // terraform exists, since InitCommand.getProviders needs to inspect that 639 // state. 640 s := terraform.NewState() 641 s.TFVersion = "100.1.0" 642 local := &state.LocalState{ 643 Path: local.DefaultStateFilename, 644 } 645 if err := local.WriteState(s); err != nil { 646 t.Fatal(err) 647 } 648 649 ui := new(cli.MockUi) 650 m.Ui = ui 651 c := &InitCommand{ 652 Meta: m, 653 providerInstaller: installer, 654 } 655 656 if code := c.Run(nil); code == 0 { 657 t.Fatal("expected error, got:", ui.OutputWriter) 658 } 659 660 errMsg := ui.ErrorWriter.String() 661 if !strings.Contains(errMsg, "future Terraform version") { 662 t.Fatal("unexpected error:", errMsg) 663 } 664 }) 665 } 666 667 // make sure we can locate providers in various paths 668 func TestInit_findVendoredProviders(t *testing.T) { 669 // Create a temporary working directory that is empty 670 td := tempDir(t) 671 672 configDirName := "init-get-providers" 673 copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName)) 674 defer os.RemoveAll(td) 675 defer testChdir(t, td)() 676 677 ui := new(cli.MockUi) 678 m := Meta{ 679 testingOverrides: metaOverridesForProvider(testProvider()), 680 Ui: ui, 681 } 682 683 c := &InitCommand{ 684 Meta: m, 685 providerInstaller: &mockProviderInstaller{}, 686 } 687 688 // make our plugin paths 689 if err := os.MkdirAll(c.pluginDir(), 0755); err != nil { 690 t.Fatal(err) 691 } 692 if err := os.MkdirAll(DefaultPluginVendorDir, 0755); err != nil { 693 t.Fatal(err) 694 } 695 696 // add some dummy providers 697 // the auto plugin directory 698 exactPath := filepath.Join(c.pluginDir(), "terraform-provider-exact_v1.2.3_x4") 699 if err := ioutil.WriteFile(exactPath, []byte("test bin"), 0755); err != nil { 700 t.Fatal(err) 701 } 702 // the vendor path 703 greaterThanPath := filepath.Join(DefaultPluginVendorDir, "terraform-provider-greater_than_v2.3.4_x4") 704 if err := ioutil.WriteFile(greaterThanPath, []byte("test bin"), 0755); err != nil { 705 t.Fatal(err) 706 } 707 // Check the current directory too 708 betweenPath := filepath.Join(".", "terraform-provider-between_v2.3.4_x4") 709 if err := ioutil.WriteFile(betweenPath, []byte("test bin"), 0755); err != nil { 710 t.Fatal(err) 711 } 712 713 args := []string{configDirName} 714 if code := c.Run(args); code != 0 { 715 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 716 } 717 } 718 719 // make sure we can locate providers defined in the legacy rc file 720 func TestInit_rcProviders(t *testing.T) { 721 // Create a temporary working directory that is empty 722 td := tempDir(t) 723 724 configDirName := "init-legacy-rc" 725 copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName)) 726 defer os.RemoveAll(td) 727 defer testChdir(t, td)() 728 729 pluginDir := filepath.Join(td, "custom") 730 pluginPath := filepath.Join(pluginDir, "terraform-provider-legacy") 731 732 ui := new(cli.MockUi) 733 m := Meta{ 734 Ui: ui, 735 PluginOverrides: &PluginOverrides{ 736 Providers: map[string]string{ 737 "legacy": pluginPath, 738 }, 739 }, 740 } 741 742 c := &InitCommand{ 743 Meta: m, 744 providerInstaller: &mockProviderInstaller{}, 745 } 746 747 // make our plugin paths 748 if err := os.MkdirAll(pluginDir, 0755); err != nil { 749 t.Fatal(err) 750 } 751 752 if err := ioutil.WriteFile(pluginPath, []byte("test bin"), 0755); err != nil { 753 t.Fatal(err) 754 } 755 756 args := []string{configDirName} 757 if code := c.Run(args); code != 0 { 758 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 759 } 760 } 761 762 func TestInit_getUpgradePlugins(t *testing.T) { 763 // Create a temporary working directory that is empty 764 td := tempDir(t) 765 copy.CopyDir(testFixturePath("init-get-providers"), td) 766 defer os.RemoveAll(td) 767 defer testChdir(t, td)() 768 769 ui := new(cli.MockUi) 770 m := Meta{ 771 testingOverrides: metaOverridesForProvider(testProvider()), 772 Ui: ui, 773 } 774 775 installer := &mockProviderInstaller{ 776 Providers: map[string][]string{ 777 // looking for an exact version 778 "exact": []string{"1.2.3"}, 779 // config requires >= 2.3.3 780 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 781 // config specifies 782 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 783 }, 784 785 Dir: m.pluginDir(), 786 } 787 788 err := os.MkdirAll(m.pluginDir(), os.ModePerm) 789 if err != nil { 790 t.Fatal(err) 791 } 792 exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1")) 793 err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm) 794 if err != nil { 795 t.Fatal(err) 796 } 797 greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater_than", "2.3.3")) 798 err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm) 799 if err != nil { 800 t.Fatal(err) 801 } 802 betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install 803 err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm) 804 if err != nil { 805 t.Fatal(err) 806 } 807 808 c := &InitCommand{ 809 Meta: m, 810 providerInstaller: installer, 811 } 812 813 args := []string{ 814 "-upgrade=true", 815 } 816 if code := c.Run(args); code != 0 { 817 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 818 } 819 820 files, err := ioutil.ReadDir(m.pluginDir()) 821 if err != nil { 822 t.Fatal(err) 823 } 824 825 if !installer.PurgeUnusedCalled { 826 t.Errorf("init -upgrade didn't purge providers, but should have") 827 } 828 829 gotFilenames := make([]string, len(files)) 830 for i, info := range files { 831 gotFilenames[i] = info.Name() 832 } 833 sort.Strings(gotFilenames) 834 835 wantFilenames := []string{ 836 "lock.json", 837 838 // no "between" because the file in cwd overrides it 839 840 // The mock PurgeUnused doesn't actually purge anything, so the dir 841 // includes both our old and new versions. 842 "terraform-provider-exact_v0.0.1_x4", 843 "terraform-provider-exact_v1.2.3_x4", 844 "terraform-provider-greater_than_v2.3.3_x4", 845 "terraform-provider-greater_than_v2.3.4_x4", 846 } 847 848 if !reflect.DeepEqual(gotFilenames, wantFilenames) { 849 t.Errorf("wrong directory contents after upgrade\ngot: %#v\nwant: %#v", gotFilenames, wantFilenames) 850 } 851 852 } 853 854 func TestInit_getProviderMissing(t *testing.T) { 855 // Create a temporary working directory that is empty 856 td := tempDir(t) 857 copy.CopyDir(testFixturePath("init-get-providers"), td) 858 defer os.RemoveAll(td) 859 defer testChdir(t, td)() 860 861 ui := new(cli.MockUi) 862 m := Meta{ 863 testingOverrides: metaOverridesForProvider(testProvider()), 864 Ui: ui, 865 } 866 867 installer := &mockProviderInstaller{ 868 Providers: map[string][]string{ 869 // looking for exact version 1.2.3 870 "exact": []string{"1.2.4"}, 871 // config requires >= 2.3.3 872 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 873 // config specifies 874 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 875 }, 876 877 Dir: m.pluginDir(), 878 } 879 880 c := &InitCommand{ 881 Meta: m, 882 providerInstaller: installer, 883 } 884 885 args := []string{} 886 if code := c.Run(args); code == 0 { 887 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 888 } 889 890 if !strings.Contains(ui.ErrorWriter.String(), "no suitable version for provider") { 891 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 892 } 893 } 894 895 func TestInit_getProviderHaveLegacyVersion(t *testing.T) { 896 // Create a temporary working directory that is empty 897 td := tempDir(t) 898 copy.CopyDir(testFixturePath("init-providers-lock"), td) 899 defer os.RemoveAll(td) 900 defer testChdir(t, td)() 901 902 if err := ioutil.WriteFile("terraform-provider-test", []byte("provider bin"), 0755); err != nil { 903 t.Fatal(err) 904 } 905 906 // provider test has a version constraint in the config, which should 907 // trigger the getProvider error below. 908 ui := new(cli.MockUi) 909 c := &InitCommand{ 910 Meta: Meta{ 911 testingOverrides: metaOverridesForProvider(testProvider()), 912 Ui: ui, 913 }, 914 providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, error) { 915 return discovery.PluginMeta{}, fmt.Errorf("EXPECTED PROVIDER ERROR %s", provider) 916 }), 917 } 918 919 args := []string{} 920 if code := c.Run(args); code == 0 { 921 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 922 } 923 924 if !strings.Contains(ui.ErrorWriter.String(), "EXPECTED PROVIDER ERROR test") { 925 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 926 } 927 } 928 929 func TestInit_getProviderCheckRequiredVersion(t *testing.T) { 930 // Create a temporary working directory that is empty 931 td := tempDir(t) 932 copy.CopyDir(testFixturePath("init-check-required-version"), td) 933 defer os.RemoveAll(td) 934 defer testChdir(t, td)() 935 936 ui := new(cli.MockUi) 937 c := &InitCommand{ 938 Meta: Meta{ 939 testingOverrides: metaOverridesForProvider(testProvider()), 940 Ui: ui, 941 }, 942 } 943 944 args := []string{} 945 if code := c.Run(args); code != 1 { 946 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 947 } 948 } 949 950 func TestInit_providerLockFile(t *testing.T) { 951 // Create a temporary working directory that is empty 952 td := tempDir(t) 953 copy.CopyDir(testFixturePath("init-provider-lock-file"), td) 954 defer os.RemoveAll(td) 955 defer testChdir(t, td)() 956 957 ui := new(cli.MockUi) 958 m := Meta{ 959 testingOverrides: metaOverridesForProvider(testProvider()), 960 Ui: ui, 961 } 962 963 installer := &mockProviderInstaller{ 964 Providers: map[string][]string{ 965 "test": []string{"1.2.3"}, 966 }, 967 968 Dir: m.pluginDir(), 969 } 970 971 c := &InitCommand{ 972 Meta: m, 973 providerInstaller: installer, 974 } 975 976 args := []string{} 977 if code := c.Run(args); code != 0 { 978 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 979 } 980 981 providersLockFile := fmt.Sprintf( 982 ".terraform/plugins/%s_%s/lock.json", 983 runtime.GOOS, runtime.GOARCH, 984 ) 985 buf, err := ioutil.ReadFile(providersLockFile) 986 if err != nil { 987 t.Fatalf("failed to read providers lock file %s: %s", providersLockFile, err) 988 } 989 // The hash in here is for the empty files that mockGetProvider produces 990 wantLockFile := strings.TrimSpace(` 991 { 992 "test": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 993 } 994 `) 995 if string(buf) != wantLockFile { 996 t.Errorf("wrong provider lock file contents\ngot: %s\nwant: %s", buf, wantLockFile) 997 } 998 } 999 1000 func TestInit_pluginDirReset(t *testing.T) { 1001 td, err := ioutil.TempDir("", "tf") 1002 if err != nil { 1003 t.Fatal(err) 1004 } 1005 defer os.RemoveAll(td) 1006 defer testChdir(t, td)() 1007 1008 ui := new(cli.MockUi) 1009 c := &InitCommand{ 1010 Meta: Meta{ 1011 testingOverrides: metaOverridesForProvider(testProvider()), 1012 Ui: ui, 1013 }, 1014 providerInstaller: &mockProviderInstaller{}, 1015 } 1016 1017 // make our vendor paths 1018 pluginPath := []string{"a", "b", "c"} 1019 for _, p := range pluginPath { 1020 if err := os.MkdirAll(p, 0755); err != nil { 1021 t.Fatal(err) 1022 } 1023 } 1024 1025 // run once and save the -plugin-dir 1026 args := []string{"-plugin-dir", "a"} 1027 if code := c.Run(args); code != 0 { 1028 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1029 } 1030 1031 pluginDirs, err := c.loadPluginPath() 1032 if err != nil { 1033 t.Fatal(err) 1034 } 1035 1036 if len(pluginDirs) != 1 || pluginDirs[0] != "a" { 1037 t.Fatalf(`expected plugin dir ["a"], got %q`, pluginDirs) 1038 } 1039 1040 ui = new(cli.MockUi) 1041 c = &InitCommand{ 1042 Meta: Meta{ 1043 testingOverrides: metaOverridesForProvider(testProvider()), 1044 Ui: ui, 1045 }, 1046 providerInstaller: &mockProviderInstaller{}, 1047 } 1048 1049 // make sure we remove the plugin-dir record 1050 args = []string{"-plugin-dir="} 1051 if code := c.Run(args); code != 0 { 1052 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1053 } 1054 1055 pluginDirs, err = c.loadPluginPath() 1056 if err != nil { 1057 t.Fatal(err) 1058 } 1059 1060 if len(pluginDirs) != 0 { 1061 t.Fatalf("expected no plugin dirs got %q", pluginDirs) 1062 } 1063 } 1064 1065 // Test user-supplied -plugin-dir 1066 func TestInit_pluginDirProviders(t *testing.T) { 1067 td := tempDir(t) 1068 copy.CopyDir(testFixturePath("init-get-providers"), td) 1069 defer os.RemoveAll(td) 1070 defer testChdir(t, td)() 1071 1072 ui := new(cli.MockUi) 1073 m := Meta{ 1074 testingOverrides: metaOverridesForProvider(testProvider()), 1075 Ui: ui, 1076 } 1077 1078 c := &InitCommand{ 1079 Meta: m, 1080 providerInstaller: &mockProviderInstaller{}, 1081 } 1082 1083 // make our vendor paths 1084 pluginPath := []string{"a", "b", "c"} 1085 for _, p := range pluginPath { 1086 if err := os.MkdirAll(p, 0755); err != nil { 1087 t.Fatal(err) 1088 } 1089 } 1090 1091 // add some dummy providers in our plugin dirs 1092 for i, name := range []string{ 1093 "terraform-provider-exact_v1.2.3_x4", 1094 "terraform-provider-greater_than_v2.3.4_x4", 1095 "terraform-provider-between_v2.3.4_x4", 1096 } { 1097 1098 if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil { 1099 t.Fatal(err) 1100 } 1101 } 1102 1103 args := []string{ 1104 "-plugin-dir", "a", 1105 "-plugin-dir", "b", 1106 "-plugin-dir", "c", 1107 } 1108 if code := c.Run(args); code != 0 { 1109 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1110 } 1111 } 1112 1113 // Test user-supplied -plugin-dir doesn't allow auto-install 1114 func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) { 1115 td := tempDir(t) 1116 copy.CopyDir(testFixturePath("init-get-providers"), td) 1117 defer os.RemoveAll(td) 1118 defer testChdir(t, td)() 1119 1120 ui := new(cli.MockUi) 1121 m := Meta{ 1122 testingOverrides: metaOverridesForProvider(testProvider()), 1123 Ui: ui, 1124 } 1125 1126 c := &InitCommand{ 1127 Meta: m, 1128 providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, error) { 1129 t.Fatalf("plugin installer should not have been called for %q", provider) 1130 return discovery.PluginMeta{}, nil 1131 }), 1132 } 1133 1134 // make our vendor paths 1135 pluginPath := []string{"a", "b"} 1136 for _, p := range pluginPath { 1137 if err := os.MkdirAll(p, 0755); err != nil { 1138 t.Fatal(err) 1139 } 1140 } 1141 1142 // add some dummy providers in our plugin dirs 1143 for i, name := range []string{ 1144 "terraform-provider-exact_v1.2.3_x4", 1145 "terraform-provider-greater_than_v2.3.4_x4", 1146 } { 1147 1148 if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil { 1149 t.Fatal(err) 1150 } 1151 } 1152 1153 args := []string{ 1154 "-plugin-dir", "a", 1155 "-plugin-dir", "b", 1156 } 1157 if code := c.Run(args); code == 0 { 1158 // should have been an error 1159 t.Fatalf("bad: \n%s", ui.OutputWriter) 1160 } 1161 } 1162 1163 // Verify that plugin-dir doesn't prevent discovery of internal providers 1164 func TestInit_pluginWithInternal(t *testing.T) { 1165 td := tempDir(t) 1166 copy.CopyDir(testFixturePath("init-internal"), td) 1167 defer os.RemoveAll(td) 1168 defer testChdir(t, td)() 1169 1170 ui := new(cli.MockUi) 1171 m := Meta{ 1172 testingOverrides: metaOverridesForProvider(testProvider()), 1173 Ui: ui, 1174 } 1175 1176 c := &InitCommand{ 1177 Meta: m, 1178 } 1179 1180 args := []string{"-plugin-dir", "./"} 1181 //args := []string{} 1182 if code := c.Run(args); code != 0 { 1183 t.Fatalf("error: %s", ui.ErrorWriter) 1184 } 1185 }