github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/init_test.go (about) 1 package command 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "path/filepath" 10 "reflect" 11 "runtime" 12 "sort" 13 "strings" 14 "testing" 15 16 "github.com/mitchellh/cli" 17 "github.com/zclconf/go-cty/cty" 18 19 "github.com/hashicorp/terraform/addrs" 20 "github.com/hashicorp/terraform/backend/local" 21 "github.com/hashicorp/terraform/configs" 22 "github.com/hashicorp/terraform/helper/copy" 23 "github.com/hashicorp/terraform/plugin/discovery" 24 "github.com/hashicorp/terraform/state" 25 "github.com/hashicorp/terraform/states" 26 "github.com/hashicorp/terraform/states/statemgr" 27 "github.com/hashicorp/terraform/terraform" 28 "github.com/hashicorp/terraform/tfdiags" 29 ) 30 31 func TestInit_empty(t *testing.T) { 32 // Create a temporary working directory that is empty 33 td := tempDir(t) 34 os.MkdirAll(td, 0755) 35 defer os.RemoveAll(td) 36 defer testChdir(t, td)() 37 38 ui := new(cli.MockUi) 39 c := &InitCommand{ 40 Meta: Meta{ 41 testingOverrides: metaOverridesForProvider(testProvider()), 42 Ui: ui, 43 }, 44 } 45 46 args := []string{} 47 if code := c.Run(args); code != 0 { 48 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 49 } 50 } 51 52 func TestInit_multipleArgs(t *testing.T) { 53 ui := new(cli.MockUi) 54 c := &InitCommand{ 55 Meta: Meta{ 56 testingOverrides: metaOverridesForProvider(testProvider()), 57 Ui: ui, 58 }, 59 } 60 61 args := []string{ 62 "bad", 63 "bad", 64 } 65 if code := c.Run(args); code != 1 { 66 t.Fatalf("bad: \n%s", ui.OutputWriter.String()) 67 } 68 } 69 70 func TestInit_fromModule_explicitDest(t *testing.T) { 71 dir := tempDir(t) 72 err := os.Mkdir(dir, os.ModePerm) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 ui := new(cli.MockUi) 78 c := &InitCommand{ 79 Meta: Meta{ 80 testingOverrides: metaOverridesForProvider(testProvider()), 81 Ui: ui, 82 }, 83 } 84 85 if _, err := os.Stat(DefaultStateFilename); err == nil { 86 // This should never happen; it indicates a bug in another test 87 // is causing a terraform.tfstate to get left behind in our directory 88 // here, which can interfere with our init process in a way that 89 // isn't relevant to this test. 90 fullPath, _ := filepath.Abs(DefaultStateFilename) 91 t.Fatalf("some other test has left terraform.tfstate behind:\n%s", fullPath) 92 } 93 94 args := []string{ 95 "-from-module=" + testFixturePath("init"), 96 dir, 97 } 98 if code := c.Run(args); code != 0 { 99 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 100 } 101 102 if _, err := os.Stat(filepath.Join(dir, "hello.tf")); err != nil { 103 t.Fatalf("err: %s", err) 104 } 105 } 106 107 func TestInit_fromModule_cwdDest(t *testing.T) { 108 // Create a temporary working directory that is empty 109 td := tempDir(t) 110 os.MkdirAll(td, os.ModePerm) 111 defer os.RemoveAll(td) 112 defer testChdir(t, td)() 113 114 ui := new(cli.MockUi) 115 c := &InitCommand{ 116 Meta: Meta{ 117 testingOverrides: metaOverridesForProvider(testProvider()), 118 Ui: ui, 119 }, 120 } 121 122 args := []string{ 123 "-from-module=" + testFixturePath("init"), 124 } 125 if code := c.Run(args); code != 0 { 126 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 127 } 128 129 if _, err := os.Stat(filepath.Join(td, "hello.tf")); err != nil { 130 t.Fatalf("err: %s", err) 131 } 132 } 133 134 // https://github.com/hashicorp/terraform/issues/518 135 func TestInit_fromModule_dstInSrc(t *testing.T) { 136 dir := tempDir(t) 137 if err := os.MkdirAll(dir, 0755); err != nil { 138 t.Fatalf("err: %s", err) 139 } 140 141 // Change to the temporary directory 142 cwd, err := os.Getwd() 143 if err != nil { 144 t.Fatalf("err: %s", err) 145 } 146 if err := os.Chdir(dir); err != nil { 147 t.Fatalf("err: %s", err) 148 } 149 defer os.Chdir(cwd) 150 151 if err := os.Mkdir("foo", os.ModePerm); err != nil { 152 t.Fatal(err) 153 } 154 155 if _, err := os.Create("issue518.tf"); err != nil { 156 t.Fatalf("err: %s", err) 157 } 158 159 ui := new(cli.MockUi) 160 c := &InitCommand{ 161 Meta: Meta{ 162 testingOverrides: metaOverridesForProvider(testProvider()), 163 Ui: ui, 164 }, 165 } 166 167 args := []string{ 168 "-from-module=.", 169 "foo", 170 } 171 if code := c.Run(args); code != 0 { 172 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 173 } 174 175 if _, err := os.Stat(filepath.Join(dir, "foo", "issue518.tf")); err != nil { 176 t.Fatalf("err: %s", err) 177 } 178 } 179 180 func TestInit_get(t *testing.T) { 181 // Create a temporary working directory that is empty 182 td := tempDir(t) 183 copy.CopyDir(testFixturePath("init-get"), td) 184 defer os.RemoveAll(td) 185 defer testChdir(t, td)() 186 187 ui := new(cli.MockUi) 188 c := &InitCommand{ 189 Meta: Meta{ 190 testingOverrides: metaOverridesForProvider(testProvider()), 191 Ui: ui, 192 }, 193 } 194 195 args := []string{} 196 if code := c.Run(args); code != 0 { 197 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 198 } 199 200 // Check output 201 output := ui.OutputWriter.String() 202 if !strings.Contains(output, "foo in foo") { 203 t.Fatalf("doesn't look like we installed module 'foo': %s", output) 204 } 205 } 206 207 func TestInit_getUpgradeModules(t *testing.T) { 208 // Create a temporary working directory that is empty 209 td := tempDir(t) 210 os.MkdirAll(td, 0755) 211 // copy.CopyDir(testFixturePath("init-get"), td) 212 defer os.RemoveAll(td) 213 defer testChdir(t, td)() 214 215 ui := new(cli.MockUi) 216 c := &InitCommand{ 217 Meta: Meta{ 218 testingOverrides: metaOverridesForProvider(testProvider()), 219 Ui: ui, 220 }, 221 } 222 223 args := []string{ 224 "-get=true", 225 "-get-plugins=false", 226 "-upgrade", 227 testFixturePath("init-get"), 228 } 229 if code := c.Run(args); code != 0 { 230 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 231 } 232 233 // Check output 234 output := ui.OutputWriter.String() 235 if !strings.Contains(output, "Upgrading modules...") { 236 t.Fatalf("doesn't look like get upgrade: %s", output) 237 } 238 } 239 240 func TestInit_backend(t *testing.T) { 241 // Create a temporary working directory that is empty 242 td := tempDir(t) 243 copy.CopyDir(testFixturePath("init-backend"), td) 244 defer os.RemoveAll(td) 245 defer testChdir(t, td)() 246 247 ui := new(cli.MockUi) 248 c := &InitCommand{ 249 Meta: Meta{ 250 testingOverrides: metaOverridesForProvider(testProvider()), 251 Ui: ui, 252 }, 253 } 254 255 args := []string{} 256 if code := c.Run(args); code != 0 { 257 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 258 } 259 260 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 261 t.Fatalf("err: %s", err) 262 } 263 } 264 265 func TestInit_backendUnset(t *testing.T) { 266 // Create a temporary working directory that is empty 267 td := tempDir(t) 268 copy.CopyDir(testFixturePath("init-backend"), td) 269 defer os.RemoveAll(td) 270 defer testChdir(t, td)() 271 272 { 273 log.Printf("[TRACE] TestInit_backendUnset: beginning first init") 274 275 ui := cli.NewMockUi() 276 c := &InitCommand{ 277 Meta: Meta{ 278 testingOverrides: metaOverridesForProvider(testProvider()), 279 Ui: ui, 280 }, 281 } 282 283 // Init 284 args := []string{} 285 if code := c.Run(args); code != 0 { 286 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 287 } 288 log.Printf("[TRACE] TestInit_backendUnset: first init complete") 289 t.Logf("First run output:\n%s", ui.OutputWriter.String()) 290 t.Logf("First run errors:\n%s", ui.ErrorWriter.String()) 291 292 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 293 t.Fatalf("err: %s", err) 294 } 295 } 296 297 { 298 log.Printf("[TRACE] TestInit_backendUnset: beginning second init") 299 300 // Unset 301 if err := ioutil.WriteFile("main.tf", []byte(""), 0644); err != nil { 302 t.Fatalf("err: %s", err) 303 } 304 305 ui := cli.NewMockUi() 306 c := &InitCommand{ 307 Meta: Meta{ 308 testingOverrides: metaOverridesForProvider(testProvider()), 309 Ui: ui, 310 }, 311 } 312 313 args := []string{"-force-copy"} 314 if code := c.Run(args); code != 0 { 315 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 316 } 317 log.Printf("[TRACE] TestInit_backendUnset: second init complete") 318 t.Logf("Second run output:\n%s", ui.OutputWriter.String()) 319 t.Logf("Second run errors:\n%s", ui.ErrorWriter.String()) 320 321 s := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 322 if !s.Backend.Empty() { 323 t.Fatal("should not have backend config") 324 } 325 } 326 } 327 328 func TestInit_backendConfigFile(t *testing.T) { 329 // Create a temporary working directory that is empty 330 td := tempDir(t) 331 copy.CopyDir(testFixturePath("init-backend-config-file"), td) 332 defer os.RemoveAll(td) 333 defer testChdir(t, td)() 334 335 ui := new(cli.MockUi) 336 c := &InitCommand{ 337 Meta: Meta{ 338 testingOverrides: metaOverridesForProvider(testProvider()), 339 Ui: ui, 340 }, 341 } 342 343 args := []string{"-backend-config", "input.config"} 344 if code := c.Run(args); code != 0 { 345 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 346 } 347 348 // Read our saved backend config and verify we have our settings 349 state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 350 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want { 351 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 352 } 353 } 354 355 func TestInit_backendConfigFileChange(t *testing.T) { 356 // Create a temporary working directory that is empty 357 td := tempDir(t) 358 copy.CopyDir(testFixturePath("init-backend-config-file-change"), td) 359 defer os.RemoveAll(td) 360 defer testChdir(t, td)() 361 362 // Ask input 363 defer testInputMap(t, map[string]string{ 364 "backend-migrate-to-new": "no", 365 })() 366 367 ui := new(cli.MockUi) 368 c := &InitCommand{ 369 Meta: Meta{ 370 testingOverrides: metaOverridesForProvider(testProvider()), 371 Ui: ui, 372 }, 373 } 374 375 args := []string{"-backend-config", "input.config"} 376 if code := c.Run(args); code != 0 { 377 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 378 } 379 380 // Read our saved backend config and verify we have our settings 381 state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 382 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want { 383 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 384 } 385 } 386 387 func TestInit_backendConfigKV(t *testing.T) { 388 // Create a temporary working directory that is empty 389 td := tempDir(t) 390 copy.CopyDir(testFixturePath("init-backend-config-kv"), td) 391 defer os.RemoveAll(td) 392 defer testChdir(t, td)() 393 394 ui := new(cli.MockUi) 395 c := &InitCommand{ 396 Meta: Meta{ 397 testingOverrides: metaOverridesForProvider(testProvider()), 398 Ui: ui, 399 }, 400 } 401 402 args := []string{"-backend-config", "path=hello"} 403 if code := c.Run(args); code != 0 { 404 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 405 } 406 407 // Read our saved backend config and verify we have our settings 408 state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 409 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want { 410 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 411 } 412 } 413 414 func TestInit_backendConfigKVReInit(t *testing.T) { 415 // Create a temporary working directory that is empty 416 td := tempDir(t) 417 copy.CopyDir(testFixturePath("init-backend-config-kv"), td) 418 defer os.RemoveAll(td) 419 defer testChdir(t, td)() 420 421 ui := new(cli.MockUi) 422 c := &InitCommand{ 423 Meta: Meta{ 424 testingOverrides: metaOverridesForProvider(testProvider()), 425 Ui: ui, 426 }, 427 } 428 429 args := []string{"-backend-config", "path=test"} 430 if code := c.Run(args); code != 0 { 431 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 432 } 433 434 ui = new(cli.MockUi) 435 c = &InitCommand{ 436 Meta: Meta{ 437 testingOverrides: metaOverridesForProvider(testProvider()), 438 Ui: ui, 439 }, 440 } 441 442 // a second init should require no changes, nor should it change the backend. 443 args = []string{"-input=false"} 444 if code := c.Run(args); code != 0 { 445 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 446 } 447 448 // make sure the backend is configured how we expect 449 configState := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 450 cfg := map[string]interface{}{} 451 if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil { 452 t.Fatal(err) 453 } 454 if cfg["path"] != "test" { 455 t.Fatalf(`expected backend path="test", got path="%v"`, cfg["path"]) 456 } 457 458 // override the -backend-config options by settings 459 args = []string{"-input=false", "-backend-config", ""} 460 if code := c.Run(args); code != 0 { 461 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 462 } 463 464 // make sure the backend is configured how we expect 465 configState = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 466 cfg = map[string]interface{}{} 467 if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil { 468 t.Fatal(err) 469 } 470 if cfg["path"] != nil { 471 t.Fatalf(`expected backend path="<nil>", got path="%v"`, cfg["path"]) 472 } 473 } 474 475 func TestInit_backendConfigKVReInitWithConfigDiff(t *testing.T) { 476 // Create a temporary working directory that is empty 477 td := tempDir(t) 478 copy.CopyDir(testFixturePath("init-backend"), td) 479 defer os.RemoveAll(td) 480 defer testChdir(t, td)() 481 482 ui := new(cli.MockUi) 483 c := &InitCommand{ 484 Meta: Meta{ 485 testingOverrides: metaOverridesForProvider(testProvider()), 486 Ui: ui, 487 }, 488 } 489 490 args := []string{"-input=false"} 491 if code := c.Run(args); code != 0 { 492 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 493 } 494 495 ui = new(cli.MockUi) 496 c = &InitCommand{ 497 Meta: Meta{ 498 testingOverrides: metaOverridesForProvider(testProvider()), 499 Ui: ui, 500 }, 501 } 502 503 // a second init with identical config should require no changes, nor 504 // should it change the backend. 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 510 // make sure the backend is configured how we expect 511 configState := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 512 cfg := map[string]interface{}{} 513 if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil { 514 t.Fatal(err) 515 } 516 if cfg["path"] != "foo" { 517 t.Fatalf(`expected backend path="foo", got path="%v"`, cfg["foo"]) 518 } 519 } 520 521 func TestInit_backendCli_no_config_block(t *testing.T) { 522 // Create a temporary working directory that is empty 523 td := tempDir(t) 524 copy.CopyDir(testFixturePath("init"), td) 525 defer os.RemoveAll(td) 526 defer testChdir(t, td)() 527 528 ui := new(cli.MockUi) 529 c := &InitCommand{ 530 Meta: Meta{ 531 testingOverrides: metaOverridesForProvider(testProvider()), 532 Ui: ui, 533 }, 534 } 535 536 args := []string{"-backend-config", "path=test"} 537 if code := c.Run(args); code != 0 { 538 t.Fatalf("got exit status %d; want 0\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) 539 } 540 541 errMsg := ui.ErrorWriter.String() 542 if !strings.Contains(errMsg, "Warning: Missing backend configuration") { 543 t.Fatal("expected missing backend block warning, got", errMsg) 544 } 545 } 546 547 func TestInit_targetSubdir(t *testing.T) { 548 // Create a temporary working directory that is empty 549 td := tempDir(t) 550 os.MkdirAll(td, 0755) 551 defer os.RemoveAll(td) 552 defer testChdir(t, td)() 553 554 // copy the source into a subdir 555 copy.CopyDir(testFixturePath("init-backend"), filepath.Join(td, "source")) 556 557 ui := new(cli.MockUi) 558 c := &InitCommand{ 559 Meta: Meta{ 560 testingOverrides: metaOverridesForProvider(testProvider()), 561 Ui: ui, 562 }, 563 } 564 565 args := []string{ 566 "source", 567 } 568 if code := c.Run(args); code != 0 { 569 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 570 } 571 572 if _, err := os.Stat(filepath.Join(td, DefaultDataDir, DefaultStateFilename)); err != nil { 573 t.Fatalf("err: %s", err) 574 } 575 576 // a data directory should not have been added to out working dir 577 if _, err := os.Stat(filepath.Join(td, "source", DefaultDataDir)); !os.IsNotExist(err) { 578 t.Fatalf("err: %s", err) 579 } 580 } 581 582 func TestInit_backendReinitWithExtra(t *testing.T) { 583 td := tempDir(t) 584 copy.CopyDir(testFixturePath("init-backend-empty"), td) 585 defer os.RemoveAll(td) 586 defer testChdir(t, td)() 587 588 m := testMetaBackend(t, nil) 589 opts := &BackendOpts{ 590 ConfigOverride: configs.SynthBody("synth", map[string]cty.Value{ 591 "path": cty.StringVal("hello"), 592 }), 593 Init: true, 594 } 595 596 _, cHash, err := m.backendConfig(opts) 597 if err != nil { 598 t.Fatal(err) 599 } 600 601 ui := new(cli.MockUi) 602 c := &InitCommand{ 603 Meta: Meta{ 604 testingOverrides: metaOverridesForProvider(testProvider()), 605 Ui: ui, 606 }, 607 } 608 609 args := []string{"-backend-config", "path=hello"} 610 if code := c.Run(args); code != 0 { 611 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 612 } 613 614 // Read our saved backend config and verify we have our settings 615 state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 616 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want { 617 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 618 } 619 620 if state.Backend.Hash != uint64(cHash) { 621 t.Fatal("mismatched state and config backend hashes") 622 } 623 624 // init again and make sure nothing changes 625 if code := c.Run(args); code != 0 { 626 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 627 } 628 state = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 629 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want { 630 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 631 } 632 if state.Backend.Hash != uint64(cHash) { 633 t.Fatal("mismatched state and config backend hashes") 634 } 635 } 636 637 // move option from config to -backend-config args 638 func TestInit_backendReinitConfigToExtra(t *testing.T) { 639 td := tempDir(t) 640 copy.CopyDir(testFixturePath("init-backend"), td) 641 defer os.RemoveAll(td) 642 defer testChdir(t, td)() 643 644 ui := new(cli.MockUi) 645 c := &InitCommand{ 646 Meta: Meta{ 647 testingOverrides: metaOverridesForProvider(testProvider()), 648 Ui: ui, 649 }, 650 } 651 652 if code := c.Run([]string{"-input=false"}); code != 0 { 653 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 654 } 655 656 // Read our saved backend config and verify we have our settings 657 state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 658 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"foo","workspace_dir":null}`; got != want { 659 t.Errorf("wrong config\ngot: %s\nwant: %s", got, want) 660 } 661 662 backendHash := state.Backend.Hash 663 664 // init again but remove the path option from the config 665 cfg := "terraform {\n backend \"local\" {}\n}\n" 666 if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil { 667 t.Fatal(err) 668 } 669 670 // We need a fresh InitCommand here because the old one now has our configuration 671 // file cached inside it, so it won't re-read the modification we just made. 672 c = &InitCommand{ 673 Meta: Meta{ 674 testingOverrides: metaOverridesForProvider(testProvider()), 675 Ui: ui, 676 }, 677 } 678 679 args := []string{"-input=false", "-backend-config=path=foo"} 680 if code := c.Run(args); code != 0 { 681 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 682 } 683 state = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 684 if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"foo","workspace_dir":null}`; got != want { 685 t.Errorf("wrong config after moving to arg\ngot: %s\nwant: %s", got, want) 686 } 687 688 if state.Backend.Hash == backendHash { 689 t.Fatal("state.Backend.Hash was not updated") 690 } 691 } 692 693 // make sure inputFalse stops execution on migrate 694 func TestInit_inputFalse(t *testing.T) { 695 td := tempDir(t) 696 copy.CopyDir(testFixturePath("init-backend"), td) 697 defer os.RemoveAll(td) 698 defer testChdir(t, td)() 699 700 ui := new(cli.MockUi) 701 c := &InitCommand{ 702 Meta: Meta{ 703 testingOverrides: metaOverridesForProvider(testProvider()), 704 Ui: ui, 705 }, 706 } 707 708 args := []string{"-input=false", "-backend-config=path=foo"} 709 if code := c.Run([]string{"-input=false"}); code != 0 { 710 t.Fatalf("bad: \n%s", ui.ErrorWriter) 711 } 712 713 // write different states for foo and bar 714 fooState := states.BuildState(func(s *states.SyncState) { 715 s.SetOutputValue( 716 addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance), 717 cty.StringVal("foo"), 718 false, // not sensitive 719 ) 720 }) 721 if err := statemgr.NewFilesystem("foo").WriteState(fooState); err != nil { 722 t.Fatal(err) 723 } 724 barState := states.BuildState(func(s *states.SyncState) { 725 s.SetOutputValue( 726 addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance), 727 cty.StringVal("bar"), 728 false, // not sensitive 729 ) 730 }) 731 if err := statemgr.NewFilesystem("bar").WriteState(barState); err != nil { 732 t.Fatal(err) 733 } 734 735 ui = new(cli.MockUi) 736 c = &InitCommand{ 737 Meta: Meta{ 738 testingOverrides: metaOverridesForProvider(testProvider()), 739 Ui: ui, 740 }, 741 } 742 743 args = []string{"-input=false", "-backend-config=path=bar"} 744 if code := c.Run(args); code == 0 { 745 t.Fatal("init should have failed", ui.OutputWriter) 746 } 747 748 errMsg := ui.ErrorWriter.String() 749 if !strings.Contains(errMsg, "input disabled") { 750 t.Fatal("expected input disabled error, got", errMsg) 751 } 752 753 ui = new(cli.MockUi) 754 c = &InitCommand{ 755 Meta: Meta{ 756 testingOverrides: metaOverridesForProvider(testProvider()), 757 Ui: ui, 758 }, 759 } 760 761 // A missing input=false should abort rather than loop infinitely 762 args = []string{"-backend-config=path=baz"} 763 if code := c.Run(args); code == 0 { 764 t.Fatal("init should have failed", ui.OutputWriter) 765 } 766 } 767 768 func TestInit_getProvider(t *testing.T) { 769 // Create a temporary working directory that is empty 770 td := tempDir(t) 771 copy.CopyDir(testFixturePath("init-get-providers"), td) 772 defer os.RemoveAll(td) 773 defer testChdir(t, td)() 774 775 overrides := metaOverridesForProvider(testProvider()) 776 ui := new(cli.MockUi) 777 m := Meta{ 778 testingOverrides: overrides, 779 Ui: ui, 780 } 781 installer := &mockProviderInstaller{ 782 Providers: map[string][]string{ 783 // looking for an exact version 784 "exact": []string{"1.2.3"}, 785 // config requires >= 2.3.3 786 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 787 // config specifies 788 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 789 }, 790 791 Dir: m.pluginDir(), 792 } 793 794 c := &InitCommand{ 795 Meta: m, 796 providerInstaller: installer, 797 } 798 799 args := []string{ 800 "-backend=false", // should be possible to install plugins without backend init 801 } 802 if code := c.Run(args); code != 0 { 803 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 804 } 805 806 if !installer.PurgeUnusedCalled { 807 t.Errorf("init didn't purge providers, but should have") 808 } 809 810 // check that we got the providers for our config 811 exactPath := filepath.Join(c.pluginDir(), installer.FileName("exact", "1.2.3")) 812 if _, err := os.Stat(exactPath); os.IsNotExist(err) { 813 t.Fatal("provider 'exact' not downloaded") 814 } 815 greaterThanPath := filepath.Join(c.pluginDir(), installer.FileName("greater_than", "2.3.4")) 816 if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) { 817 t.Fatal("provider 'greater_than' not downloaded") 818 } 819 betweenPath := filepath.Join(c.pluginDir(), installer.FileName("between", "2.3.4")) 820 if _, err := os.Stat(betweenPath); os.IsNotExist(err) { 821 t.Fatal("provider 'between' not downloaded") 822 } 823 824 t.Run("future-state", func(t *testing.T) { 825 // getting providers should fail if a state from a newer version of 826 // terraform exists, since InitCommand.getProviders needs to inspect that 827 // state. 828 s := terraform.NewState() 829 s.TFVersion = "100.1.0" 830 local := &state.LocalState{ 831 Path: local.DefaultStateFilename, 832 } 833 if err := local.WriteState(s); err != nil { 834 t.Fatal(err) 835 } 836 837 ui := new(cli.MockUi) 838 m.Ui = ui 839 c := &InitCommand{ 840 Meta: m, 841 providerInstaller: installer, 842 } 843 844 if code := c.Run(nil); code == 0 { 845 t.Fatal("expected error, got:", ui.OutputWriter) 846 } 847 848 errMsg := ui.ErrorWriter.String() 849 if !strings.Contains(errMsg, "which is newer than current") { 850 t.Fatal("unexpected error:", errMsg) 851 } 852 }) 853 } 854 855 // make sure we can locate providers in various paths 856 func TestInit_findVendoredProviders(t *testing.T) { 857 // Create a temporary working directory that is empty 858 td := tempDir(t) 859 860 configDirName := "init-get-providers" 861 copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName)) 862 defer os.RemoveAll(td) 863 defer testChdir(t, td)() 864 865 ui := new(cli.MockUi) 866 m := Meta{ 867 testingOverrides: metaOverridesForProvider(testProvider()), 868 Ui: ui, 869 } 870 871 c := &InitCommand{ 872 Meta: m, 873 providerInstaller: &mockProviderInstaller{}, 874 } 875 876 // make our plugin paths 877 if err := os.MkdirAll(c.pluginDir(), 0755); err != nil { 878 t.Fatal(err) 879 } 880 if err := os.MkdirAll(DefaultPluginVendorDir, 0755); err != nil { 881 t.Fatal(err) 882 } 883 884 // add some dummy providers 885 // the auto plugin directory 886 exactPath := filepath.Join(c.pluginDir(), "terraform-provider-exact_v1.2.3_x4") 887 if err := ioutil.WriteFile(exactPath, []byte("test bin"), 0755); err != nil { 888 t.Fatal(err) 889 } 890 // the vendor path 891 greaterThanPath := filepath.Join(DefaultPluginVendorDir, "terraform-provider-greater_than_v2.3.4_x4") 892 if err := ioutil.WriteFile(greaterThanPath, []byte("test bin"), 0755); err != nil { 893 t.Fatal(err) 894 } 895 // Check the current directory too 896 betweenPath := filepath.Join(".", "terraform-provider-between_v2.3.4_x4") 897 if err := ioutil.WriteFile(betweenPath, []byte("test bin"), 0755); err != nil { 898 t.Fatal(err) 899 } 900 901 args := []string{configDirName} 902 if code := c.Run(args); code != 0 { 903 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 904 } 905 } 906 907 // make sure we can locate providers defined in the legacy rc file 908 func TestInit_rcProviders(t *testing.T) { 909 // Create a temporary working directory that is empty 910 td := tempDir(t) 911 912 configDirName := "init-legacy-rc" 913 copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName)) 914 defer os.RemoveAll(td) 915 defer testChdir(t, td)() 916 917 pluginDir := filepath.Join(td, "custom") 918 pluginPath := filepath.Join(pluginDir, "terraform-provider-legacy") 919 920 ui := new(cli.MockUi) 921 m := Meta{ 922 Ui: ui, 923 PluginOverrides: &PluginOverrides{ 924 Providers: map[string]string{ 925 "legacy": pluginPath, 926 }, 927 }, 928 } 929 930 c := &InitCommand{ 931 Meta: m, 932 providerInstaller: &mockProviderInstaller{}, 933 } 934 935 // make our plugin paths 936 if err := os.MkdirAll(pluginDir, 0755); err != nil { 937 t.Fatal(err) 938 } 939 940 if err := ioutil.WriteFile(pluginPath, []byte("test bin"), 0755); err != nil { 941 t.Fatal(err) 942 } 943 944 args := []string{configDirName} 945 if code := c.Run(args); code != 0 { 946 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 947 } 948 } 949 950 func TestInit_providerSource(t *testing.T) { 951 // Create a temporary working directory that is empty 952 td := tempDir(t) 953 954 configDirName := "init-required-providers" 955 copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName)) 956 defer os.RemoveAll(td) 957 defer testChdir(t, td)() 958 959 ui := new(cli.MockUi) 960 m := Meta{ 961 testingOverrides: metaOverridesForProvider(testProvider()), 962 Ui: ui, 963 } 964 965 c := &InitCommand{ 966 Meta: m, 967 providerInstaller: &mockProviderInstaller{}, 968 } 969 970 // make our plugin paths 971 if err := os.MkdirAll(c.pluginDir(), 0755); err != nil { 972 t.Fatal(err) 973 } 974 if err := os.MkdirAll(DefaultPluginVendorDir, 0755); err != nil { 975 t.Fatal(err) 976 } 977 978 // add some dummy providers 979 // the auto plugin directory 980 testPath := filepath.Join(c.pluginDir(), "terraform-provider-test_v1.2.3_x4") 981 if err := ioutil.WriteFile(testPath, []byte("test bin"), 0755); err != nil { 982 t.Fatal(err) 983 } 984 // the vendor path 985 sourcePath := filepath.Join(DefaultPluginVendorDir, "terraform-provider-source_v1.2.3_x4") 986 if err := ioutil.WriteFile(sourcePath, []byte("test bin"), 0755); err != nil { 987 t.Fatal(err) 988 } 989 990 args := []string{configDirName} 991 992 if code := c.Run(args); code != 0 { 993 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 994 } 995 if strings.Contains(ui.OutputWriter.String(), "Terraform has initialized, but configuration upgrades may be needed") { 996 t.Fatalf("unexpected \"configuration upgrade\" warning in output") 997 } 998 } 999 1000 func TestInit_getUpgradePlugins(t *testing.T) { 1001 // Create a temporary working directory that is empty 1002 td := tempDir(t) 1003 copy.CopyDir(testFixturePath("init-get-providers"), td) 1004 defer os.RemoveAll(td) 1005 defer testChdir(t, td)() 1006 1007 ui := new(cli.MockUi) 1008 m := Meta{ 1009 testingOverrides: metaOverridesForProvider(testProvider()), 1010 Ui: ui, 1011 } 1012 1013 installer := &mockProviderInstaller{ 1014 Providers: map[string][]string{ 1015 // looking for an exact version 1016 "exact": []string{"1.2.3"}, 1017 // config requires >= 2.3.3 1018 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 1019 // config specifies 1020 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 1021 }, 1022 1023 Dir: m.pluginDir(), 1024 } 1025 1026 err := os.MkdirAll(m.pluginDir(), os.ModePerm) 1027 if err != nil { 1028 t.Fatal(err) 1029 } 1030 exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1")) 1031 err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm) 1032 if err != nil { 1033 t.Fatal(err) 1034 } 1035 greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater_than", "2.3.3")) 1036 err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm) 1037 if err != nil { 1038 t.Fatal(err) 1039 } 1040 betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install 1041 err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm) 1042 if err != nil { 1043 t.Fatal(err) 1044 } 1045 1046 c := &InitCommand{ 1047 Meta: m, 1048 providerInstaller: installer, 1049 } 1050 1051 args := []string{ 1052 "-upgrade=true", 1053 } 1054 if code := c.Run(args); code != 0 { 1055 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 1056 } 1057 1058 files, err := ioutil.ReadDir(m.pluginDir()) 1059 if err != nil { 1060 t.Fatal(err) 1061 } 1062 1063 if !installer.PurgeUnusedCalled { 1064 t.Errorf("init -upgrade didn't purge providers, but should have") 1065 } 1066 1067 gotFilenames := make([]string, len(files)) 1068 for i, info := range files { 1069 gotFilenames[i] = info.Name() 1070 } 1071 sort.Strings(gotFilenames) 1072 1073 wantFilenames := []string{ 1074 "lock.json", 1075 1076 // no "between" because the file in cwd overrides it 1077 1078 // The mock PurgeUnused doesn't actually purge anything, so the dir 1079 // includes both our old and new versions. 1080 "terraform-provider-exact_v0.0.1_x4", 1081 "terraform-provider-exact_v1.2.3_x4", 1082 "terraform-provider-greater_than_v2.3.3_x4", 1083 "terraform-provider-greater_than_v2.3.4_x4", 1084 } 1085 1086 if !reflect.DeepEqual(gotFilenames, wantFilenames) { 1087 t.Errorf("wrong directory contents after upgrade\ngot: %#v\nwant: %#v", gotFilenames, wantFilenames) 1088 } 1089 1090 } 1091 1092 func TestInit_getProviderMissing(t *testing.T) { 1093 // Create a temporary working directory that is empty 1094 td := tempDir(t) 1095 copy.CopyDir(testFixturePath("init-get-providers"), td) 1096 defer os.RemoveAll(td) 1097 defer testChdir(t, td)() 1098 1099 ui := new(cli.MockUi) 1100 m := Meta{ 1101 testingOverrides: metaOverridesForProvider(testProvider()), 1102 Ui: ui, 1103 } 1104 1105 installer := &mockProviderInstaller{ 1106 Providers: map[string][]string{ 1107 // looking for exact version 1.2.3 1108 "exact": []string{"1.2.4"}, 1109 // config requires >= 2.3.3 1110 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 1111 // config specifies 1112 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 1113 }, 1114 1115 Dir: m.pluginDir(), 1116 } 1117 1118 c := &InitCommand{ 1119 Meta: m, 1120 providerInstaller: installer, 1121 } 1122 1123 args := []string{} 1124 if code := c.Run(args); code == 0 { 1125 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 1126 } 1127 1128 if !strings.Contains(ui.ErrorWriter.String(), "no suitable version for provider") { 1129 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 1130 } 1131 } 1132 1133 func TestInit_getProviderHaveLegacyVersion(t *testing.T) { 1134 // Create a temporary working directory that is empty 1135 td := tempDir(t) 1136 copy.CopyDir(testFixturePath("init-providers-lock"), td) 1137 defer os.RemoveAll(td) 1138 defer testChdir(t, td)() 1139 1140 if err := ioutil.WriteFile("terraform-provider-test", []byte("provider bin"), 0755); err != nil { 1141 t.Fatal(err) 1142 } 1143 1144 // provider test has a version constraint in the config, which should 1145 // trigger the getProvider error below. 1146 ui := new(cli.MockUi) 1147 c := &InitCommand{ 1148 Meta: Meta{ 1149 testingOverrides: metaOverridesForProvider(testProvider()), 1150 Ui: ui, 1151 }, 1152 providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) { 1153 return discovery.PluginMeta{}, tfdiags.Diagnostics{}, fmt.Errorf("EXPECTED PROVIDER ERROR %s", provider) 1154 }), 1155 } 1156 1157 args := []string{} 1158 if code := c.Run(args); code == 0 { 1159 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 1160 } 1161 1162 if !strings.Contains(ui.ErrorWriter.String(), "EXPECTED PROVIDER ERROR test") { 1163 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 1164 } 1165 } 1166 1167 func TestInit_checkRequiredVersion(t *testing.T) { 1168 // Create a temporary working directory that is empty 1169 td := tempDir(t) 1170 copy.CopyDir(testFixturePath("init-check-required-version"), td) 1171 defer os.RemoveAll(td) 1172 defer testChdir(t, td)() 1173 1174 ui := cli.NewMockUi() 1175 c := &InitCommand{ 1176 Meta: Meta{ 1177 testingOverrides: metaOverridesForProvider(testProvider()), 1178 Ui: ui, 1179 }, 1180 } 1181 1182 args := []string{} 1183 if code := c.Run(args); code != 1 { 1184 t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) 1185 } 1186 } 1187 1188 func TestInit_providerLockFile(t *testing.T) { 1189 // Create a temporary working directory that is empty 1190 td := tempDir(t) 1191 copy.CopyDir(testFixturePath("init-provider-lock-file"), td) 1192 defer os.RemoveAll(td) 1193 defer testChdir(t, td)() 1194 1195 ui := new(cli.MockUi) 1196 m := Meta{ 1197 testingOverrides: metaOverridesForProvider(testProvider()), 1198 Ui: ui, 1199 } 1200 1201 installer := &mockProviderInstaller{ 1202 Providers: map[string][]string{ 1203 "test": []string{"1.2.3"}, 1204 }, 1205 1206 Dir: m.pluginDir(), 1207 } 1208 1209 c := &InitCommand{ 1210 Meta: m, 1211 providerInstaller: installer, 1212 } 1213 1214 args := []string{} 1215 if code := c.Run(args); code != 0 { 1216 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 1217 } 1218 1219 providersLockFile := fmt.Sprintf( 1220 ".terraform/plugins/%s_%s/lock.json", 1221 runtime.GOOS, runtime.GOARCH, 1222 ) 1223 buf, err := ioutil.ReadFile(providersLockFile) 1224 if err != nil { 1225 t.Fatalf("failed to read providers lock file %s: %s", providersLockFile, err) 1226 } 1227 // The hash in here is for the empty files that mockGetProvider produces 1228 wantLockFile := strings.TrimSpace(` 1229 { 1230 "test": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 1231 } 1232 `) 1233 if string(buf) != wantLockFile { 1234 t.Errorf("wrong provider lock file contents\ngot: %s\nwant: %s", buf, wantLockFile) 1235 } 1236 } 1237 1238 func TestInit_pluginDirReset(t *testing.T) { 1239 td := testTempDir(t) 1240 defer os.RemoveAll(td) 1241 defer testChdir(t, td)() 1242 1243 ui := new(cli.MockUi) 1244 c := &InitCommand{ 1245 Meta: Meta{ 1246 testingOverrides: metaOverridesForProvider(testProvider()), 1247 Ui: ui, 1248 }, 1249 providerInstaller: &mockProviderInstaller{}, 1250 } 1251 1252 // make our vendor paths 1253 pluginPath := []string{"a", "b", "c"} 1254 for _, p := range pluginPath { 1255 if err := os.MkdirAll(p, 0755); err != nil { 1256 t.Fatal(err) 1257 } 1258 } 1259 1260 // run once and save the -plugin-dir 1261 args := []string{"-plugin-dir", "a"} 1262 if code := c.Run(args); code != 0 { 1263 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1264 } 1265 1266 pluginDirs, err := c.loadPluginPath() 1267 if err != nil { 1268 t.Fatal(err) 1269 } 1270 1271 if len(pluginDirs) != 1 || pluginDirs[0] != "a" { 1272 t.Fatalf(`expected plugin dir ["a"], got %q`, pluginDirs) 1273 } 1274 1275 ui = new(cli.MockUi) 1276 c = &InitCommand{ 1277 Meta: Meta{ 1278 testingOverrides: metaOverridesForProvider(testProvider()), 1279 Ui: ui, 1280 }, 1281 providerInstaller: &mockProviderInstaller{}, 1282 } 1283 1284 // make sure we remove the plugin-dir record 1285 args = []string{"-plugin-dir="} 1286 if code := c.Run(args); code != 0 { 1287 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1288 } 1289 1290 pluginDirs, err = c.loadPluginPath() 1291 if err != nil { 1292 t.Fatal(err) 1293 } 1294 1295 if len(pluginDirs) != 0 { 1296 t.Fatalf("expected no plugin dirs got %q", pluginDirs) 1297 } 1298 } 1299 1300 // Test user-supplied -plugin-dir 1301 func TestInit_pluginDirProviders(t *testing.T) { 1302 td := tempDir(t) 1303 copy.CopyDir(testFixturePath("init-get-providers"), td) 1304 defer os.RemoveAll(td) 1305 defer testChdir(t, td)() 1306 1307 ui := new(cli.MockUi) 1308 m := Meta{ 1309 testingOverrides: metaOverridesForProvider(testProvider()), 1310 Ui: ui, 1311 } 1312 1313 c := &InitCommand{ 1314 Meta: m, 1315 providerInstaller: &mockProviderInstaller{}, 1316 } 1317 1318 // make our vendor paths 1319 pluginPath := []string{"a", "b", "c"} 1320 for _, p := range pluginPath { 1321 if err := os.MkdirAll(p, 0755); err != nil { 1322 t.Fatal(err) 1323 } 1324 } 1325 1326 // add some dummy providers in our plugin dirs 1327 for i, name := range []string{ 1328 "terraform-provider-exact_v1.2.3_x4", 1329 "terraform-provider-greater_than_v2.3.4_x4", 1330 "terraform-provider-between_v2.3.4_x4", 1331 } { 1332 1333 if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil { 1334 t.Fatal(err) 1335 } 1336 } 1337 1338 args := []string{ 1339 "-plugin-dir", "a", 1340 "-plugin-dir", "b", 1341 "-plugin-dir", "c", 1342 } 1343 if code := c.Run(args); code != 0 { 1344 t.Fatalf("bad: \n%s", ui.ErrorWriter) 1345 } 1346 } 1347 1348 // Test user-supplied -plugin-dir doesn't allow auto-install 1349 func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) { 1350 td := tempDir(t) 1351 copy.CopyDir(testFixturePath("init-get-providers"), td) 1352 defer os.RemoveAll(td) 1353 defer testChdir(t, td)() 1354 1355 ui := new(cli.MockUi) 1356 m := Meta{ 1357 testingOverrides: metaOverridesForProvider(testProvider()), 1358 Ui: ui, 1359 } 1360 1361 c := &InitCommand{ 1362 Meta: m, 1363 providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) { 1364 t.Fatalf("plugin installer should not have been called for %q", provider) 1365 return discovery.PluginMeta{}, tfdiags.Diagnostics{}, nil 1366 }), 1367 } 1368 1369 // make our vendor paths 1370 pluginPath := []string{"a", "b"} 1371 for _, p := range pluginPath { 1372 if err := os.MkdirAll(p, 0755); err != nil { 1373 t.Fatal(err) 1374 } 1375 } 1376 1377 // add some dummy providers in our plugin dirs 1378 for i, name := range []string{ 1379 "terraform-provider-exact_v1.2.3_x4", 1380 "terraform-provider-greater_than_v2.3.4_x4", 1381 } { 1382 1383 if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil { 1384 t.Fatal(err) 1385 } 1386 } 1387 1388 args := []string{ 1389 "-plugin-dir", "a", 1390 "-plugin-dir", "b", 1391 } 1392 if code := c.Run(args); code == 0 { 1393 // should have been an error 1394 t.Fatalf("bad: \n%s", ui.OutputWriter) 1395 } 1396 } 1397 1398 // Verify that plugin-dir doesn't prevent discovery of internal providers 1399 func TestInit_pluginWithInternal(t *testing.T) { 1400 td := tempDir(t) 1401 copy.CopyDir(testFixturePath("init-internal"), td) 1402 defer os.RemoveAll(td) 1403 defer testChdir(t, td)() 1404 1405 ui := new(cli.MockUi) 1406 m := Meta{ 1407 testingOverrides: metaOverridesForProvider(testProvider()), 1408 Ui: ui, 1409 } 1410 1411 c := &InitCommand{ 1412 Meta: m, 1413 } 1414 1415 args := []string{"-plugin-dir", "./"} 1416 //args := []string{} 1417 if code := c.Run(args); code != 0 { 1418 t.Fatalf("error: %s", ui.ErrorWriter) 1419 } 1420 } 1421 1422 func TestInit_012UpgradeNeeded(t *testing.T) { 1423 td := tempDir(t) 1424 copy.CopyDir(testFixturePath("init-012upgrade"), td) 1425 defer os.RemoveAll(td) 1426 defer testChdir(t, td)() 1427 1428 ui := cli.NewMockUi() 1429 m := Meta{ 1430 testingOverrides: metaOverridesForProvider(testProvider()), 1431 Ui: ui, 1432 } 1433 1434 installer := &mockProviderInstaller{ 1435 Providers: map[string][]string{ 1436 "null": []string{"1.0.0"}, 1437 }, 1438 Dir: m.pluginDir(), 1439 } 1440 1441 c := &InitCommand{ 1442 Meta: m, 1443 providerInstaller: installer, 1444 } 1445 1446 args := []string{} 1447 if code := c.Run(args); code != 0 { 1448 t.Errorf("wrong exit status %d; want 0\nerror output:\n%s", code, ui.ErrorWriter.String()) 1449 } 1450 1451 output := ui.OutputWriter.String() 1452 if !strings.Contains(output, "terraform 0.12upgrade") { 1453 t.Errorf("doesn't look like we detected the need for config upgrade:\n%s", output) 1454 } 1455 } 1456 1457 func TestInit_012UpgradeNeededInAutomation(t *testing.T) { 1458 td := tempDir(t) 1459 copy.CopyDir(testFixturePath("init-012upgrade"), td) 1460 defer os.RemoveAll(td) 1461 defer testChdir(t, td)() 1462 1463 ui := cli.NewMockUi() 1464 m := Meta{ 1465 testingOverrides: metaOverridesForProvider(testProvider()), 1466 Ui: ui, 1467 RunningInAutomation: true, 1468 } 1469 1470 installer := &mockProviderInstaller{ 1471 Providers: map[string][]string{ 1472 "null": []string{"1.0.0"}, 1473 }, 1474 Dir: m.pluginDir(), 1475 } 1476 1477 c := &InitCommand{ 1478 Meta: m, 1479 providerInstaller: installer, 1480 } 1481 1482 args := []string{} 1483 if code := c.Run(args); code != 0 { 1484 t.Errorf("wrong exit status %d; want 0\nerror output:\n%s", code, ui.ErrorWriter.String()) 1485 } 1486 1487 output := ui.OutputWriter.String() 1488 if !strings.Contains(output, "Run terraform init for this configuration at a shell prompt") { 1489 t.Errorf("doesn't look like we instructed to run Terraform locally:\n%s", output) 1490 } 1491 if strings.Contains(output, "terraform 0.12upgrade") { 1492 // We don't prompt with an exact command in automation mode, since 1493 // the upgrade process is interactive and so it cannot be run in 1494 // automation. 1495 t.Errorf("looks like we incorrectly gave an upgrade command to run:\n%s", output) 1496 } 1497 } 1498 1499 func TestInit_syntaxErrorVersionSniff(t *testing.T) { 1500 // Create a temporary working directory that is empty 1501 td := tempDir(t) 1502 copy.CopyDir(testFixturePath("init-sniff-version-error"), td) 1503 defer os.RemoveAll(td) 1504 defer testChdir(t, td)() 1505 1506 ui := new(cli.MockUi) 1507 c := &InitCommand{ 1508 Meta: Meta{ 1509 testingOverrides: metaOverridesForProvider(testProvider()), 1510 Ui: ui, 1511 }, 1512 } 1513 1514 args := []string{} 1515 if code := c.Run(args); code != 0 { 1516 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 1517 } 1518 1519 // Check output. 1520 // Currently, this lands in the "upgrade may be needed" codepath, because 1521 // the intentional syntax error in our test fixture is something that 1522 // "terraform 0.12upgrade" could fix. 1523 output := ui.OutputWriter.String() 1524 if got, want := output, "Terraform has initialized, but configuration upgrades may be needed"; !strings.Contains(got, want) { 1525 t.Fatalf("wrong output\ngot:\n%s\n\nwant: message containing %q", got, want) 1526 } 1527 } 1528 1529 func TestInit_RequiredProviderSource(t *testing.T) { 1530 // Create a temporary working directory that is empty 1531 td := tempDir(t) 1532 copy.CopyDir(testFixturePath("init-provider-source"), td) 1533 defer os.RemoveAll(td) 1534 defer testChdir(t, td)() 1535 1536 ui := new(cli.MockUi) 1537 m := Meta{ 1538 testingOverrides: metaOverridesForProvider(testProvider()), 1539 Ui: ui, 1540 } 1541 installer := &mockProviderInstaller{ 1542 Providers: map[string][]string{ 1543 "test": []string{"1.2.3"}, 1544 }, 1545 Dir: m.pluginDir(), 1546 } 1547 1548 c := &InitCommand{ 1549 Meta: m, 1550 providerInstaller: installer, 1551 } 1552 1553 args := []string{} 1554 if code := c.Run(args); code != 0 { 1555 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 1556 } 1557 1558 // Check output for expected warning. 1559 output := ui.ErrorWriter.String() 1560 if got, want := output, "Warning: Provider source not supported in Terraform v0.12"; !strings.Contains(got, want) { 1561 t.Fatalf("wrong output\ngot:\n%s\n\nwant: message containing %q", got, want) 1562 } 1563 }