github.com/jd3nn1s/terraform@v0.9.6-0.20170906225847-13878347b7a1/command/import_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/terraform/helper/copy" 11 "github.com/hashicorp/terraform/plugin" 12 "github.com/hashicorp/terraform/plugin/discovery" 13 "github.com/hashicorp/terraform/terraform" 14 "github.com/mitchellh/cli" 15 ) 16 17 func TestImport(t *testing.T) { 18 defer testChdir(t, testFixturePath("import-provider-implicit"))() 19 20 statePath := testTempFile(t) 21 22 p := testProvider() 23 ui := new(cli.MockUi) 24 c := &ImportCommand{ 25 Meta: Meta{ 26 testingOverrides: metaOverridesForProvider(p), 27 Ui: ui, 28 }, 29 } 30 31 p.ImportStateFn = nil 32 p.ImportStateReturn = []*terraform.InstanceState{ 33 &terraform.InstanceState{ 34 ID: "yay", 35 Ephemeral: terraform.EphemeralState{ 36 Type: "test_instance", 37 }, 38 }, 39 } 40 41 args := []string{ 42 "-state", statePath, 43 "test_instance.foo", 44 "bar", 45 } 46 if code := c.Run(args); code != 0 { 47 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 48 } 49 50 if !p.ImportStateCalled { 51 t.Fatal("ImportState should be called") 52 } 53 54 testStateOutput(t, statePath, testImportStr) 55 } 56 57 func TestImport_providerConfig(t *testing.T) { 58 defer testChdir(t, testFixturePath("import-provider"))() 59 60 statePath := testTempFile(t) 61 62 p := testProvider() 63 ui := new(cli.MockUi) 64 c := &ImportCommand{ 65 Meta: Meta{ 66 testingOverrides: metaOverridesForProvider(p), 67 Ui: ui, 68 }, 69 } 70 71 p.ImportStateFn = nil 72 p.ImportStateReturn = []*terraform.InstanceState{ 73 &terraform.InstanceState{ 74 ID: "yay", 75 Ephemeral: terraform.EphemeralState{ 76 Type: "test_instance", 77 }, 78 }, 79 } 80 81 configured := false 82 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 83 configured = true 84 85 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 86 return fmt.Errorf("bad value: %#v", v) 87 } 88 89 return nil 90 } 91 92 args := []string{ 93 "-state", statePath, 94 "test_instance.foo", 95 "bar", 96 } 97 if code := c.Run(args); code != 0 { 98 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 99 } 100 101 // Verify that we were called 102 if !configured { 103 t.Fatal("Configure should be called") 104 } 105 106 if !p.ImportStateCalled { 107 t.Fatal("ImportState should be called") 108 } 109 110 testStateOutput(t, statePath, testImportStr) 111 } 112 113 // "remote" state provided by the "local" backend 114 func TestImport_remoteState(t *testing.T) { 115 td := tempDir(t) 116 copy.CopyDir(testFixturePath("import-provider-remote-state"), td) 117 defer os.RemoveAll(td) 118 defer testChdir(t, td)() 119 120 statePath := "imported.tfstate" 121 122 // init our backend 123 ui := new(cli.MockUi) 124 m := Meta{ 125 testingOverrides: metaOverridesForProvider(testProvider()), 126 Ui: ui, 127 } 128 129 ic := &InitCommand{ 130 Meta: m, 131 providerInstaller: &mockProviderInstaller{ 132 Providers: map[string][]string{ 133 "test": []string{"1.2.3"}, 134 }, 135 136 Dir: m.pluginDir(), 137 }, 138 } 139 140 if code := ic.Run([]string{}); code != 0 { 141 t.Fatalf("bad: \n%s", ui.ErrorWriter) 142 } 143 144 p := testProvider() 145 ui = new(cli.MockUi) 146 c := &ImportCommand{ 147 Meta: Meta{ 148 testingOverrides: metaOverridesForProvider(p), 149 Ui: ui, 150 }, 151 } 152 153 p.ImportStateFn = nil 154 p.ImportStateReturn = []*terraform.InstanceState{ 155 &terraform.InstanceState{ 156 ID: "yay", 157 Ephemeral: terraform.EphemeralState{ 158 Type: "test_instance", 159 }, 160 }, 161 } 162 163 configured := false 164 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 165 configured = true 166 167 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 168 return fmt.Errorf("bad value: %#v", v) 169 } 170 171 return nil 172 } 173 174 args := []string{ 175 "test_instance.foo", 176 "bar", 177 } 178 if code := c.Run(args); code != 0 { 179 fmt.Println(ui.OutputWriter) 180 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 181 } 182 183 // Verify that we were called 184 if !configured { 185 t.Fatal("Configure should be called") 186 } 187 188 if !p.ImportStateCalled { 189 t.Fatal("ImportState should be called") 190 } 191 192 testStateOutput(t, statePath, testImportStr) 193 } 194 195 func TestImport_providerConfigWithVar(t *testing.T) { 196 defer testChdir(t, testFixturePath("import-provider-var"))() 197 198 statePath := testTempFile(t) 199 200 p := testProvider() 201 ui := new(cli.MockUi) 202 c := &ImportCommand{ 203 Meta: Meta{ 204 testingOverrides: metaOverridesForProvider(p), 205 Ui: ui, 206 }, 207 } 208 209 p.ImportStateFn = nil 210 p.ImportStateReturn = []*terraform.InstanceState{ 211 &terraform.InstanceState{ 212 ID: "yay", 213 Ephemeral: terraform.EphemeralState{ 214 Type: "test_instance", 215 }, 216 }, 217 } 218 219 configured := false 220 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 221 configured = true 222 223 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 224 return fmt.Errorf("bad value: %#v", v) 225 } 226 227 return nil 228 } 229 230 args := []string{ 231 "-state", statePath, 232 "-var", "foo=bar", 233 "test_instance.foo", 234 "bar", 235 } 236 if code := c.Run(args); code != 0 { 237 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 238 } 239 240 // Verify that we were called 241 if !configured { 242 t.Fatal("Configure should be called") 243 } 244 245 if !p.ImportStateCalled { 246 t.Fatal("ImportState should be called") 247 } 248 249 testStateOutput(t, statePath, testImportStr) 250 } 251 252 func TestImport_providerConfigWithVarDefault(t *testing.T) { 253 defer testChdir(t, testFixturePath("import-provider-var-default"))() 254 255 statePath := testTempFile(t) 256 257 p := testProvider() 258 ui := new(cli.MockUi) 259 c := &ImportCommand{ 260 Meta: Meta{ 261 testingOverrides: metaOverridesForProvider(p), 262 Ui: ui, 263 }, 264 } 265 266 p.ImportStateFn = nil 267 p.ImportStateReturn = []*terraform.InstanceState{ 268 &terraform.InstanceState{ 269 ID: "yay", 270 Ephemeral: terraform.EphemeralState{ 271 Type: "test_instance", 272 }, 273 }, 274 } 275 276 configured := false 277 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 278 configured = true 279 280 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 281 return fmt.Errorf("bad value: %#v", v) 282 } 283 284 return nil 285 } 286 287 args := []string{ 288 "-state", statePath, 289 "test_instance.foo", 290 "bar", 291 } 292 if code := c.Run(args); code != 0 { 293 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 294 } 295 296 // Verify that we were called 297 if !configured { 298 t.Fatal("Configure should be called") 299 } 300 301 if !p.ImportStateCalled { 302 t.Fatal("ImportState should be called") 303 } 304 305 testStateOutput(t, statePath, testImportStr) 306 } 307 308 func TestImport_providerConfigWithVarFile(t *testing.T) { 309 defer testChdir(t, testFixturePath("import-provider-var-file"))() 310 311 statePath := testTempFile(t) 312 313 p := testProvider() 314 ui := new(cli.MockUi) 315 c := &ImportCommand{ 316 Meta: Meta{ 317 testingOverrides: metaOverridesForProvider(p), 318 Ui: ui, 319 }, 320 } 321 322 p.ImportStateFn = nil 323 p.ImportStateReturn = []*terraform.InstanceState{ 324 &terraform.InstanceState{ 325 ID: "yay", 326 Ephemeral: terraform.EphemeralState{ 327 Type: "test_instance", 328 }, 329 }, 330 } 331 332 configured := false 333 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 334 configured = true 335 336 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 337 return fmt.Errorf("bad value: %#v", v) 338 } 339 340 return nil 341 } 342 343 args := []string{ 344 "-state", statePath, 345 "-var-file", "blah.tfvars", 346 "test_instance.foo", 347 "bar", 348 } 349 if code := c.Run(args); code != 0 { 350 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 351 } 352 353 // Verify that we were called 354 if !configured { 355 t.Fatal("Configure should be called") 356 } 357 358 if !p.ImportStateCalled { 359 t.Fatal("ImportState should be called") 360 } 361 362 testStateOutput(t, statePath, testImportStr) 363 } 364 365 func TestImport_customProvider(t *testing.T) { 366 defer testChdir(t, testFixturePath("import-provider-aliased"))() 367 368 statePath := testTempFile(t) 369 370 p := testProvider() 371 ui := new(cli.MockUi) 372 c := &ImportCommand{ 373 Meta: Meta{ 374 testingOverrides: metaOverridesForProvider(p), 375 Ui: ui, 376 }, 377 } 378 379 p.ImportStateFn = nil 380 p.ImportStateReturn = []*terraform.InstanceState{ 381 &terraform.InstanceState{ 382 ID: "yay", 383 Ephemeral: terraform.EphemeralState{ 384 Type: "test_instance", 385 }, 386 }, 387 } 388 389 args := []string{ 390 "-provider", "test.alias", 391 "-state", statePath, 392 "test_instance.foo", 393 "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 if !p.ImportStateCalled { 400 t.Fatal("ImportState should be called") 401 } 402 403 testStateOutput(t, statePath, testImportCustomProviderStr) 404 } 405 406 func TestImport_missingResourceConfig(t *testing.T) { 407 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 408 409 statePath := testTempFile(t) 410 411 p := testProvider() 412 ui := new(cli.MockUi) 413 c := &ImportCommand{ 414 Meta: Meta{ 415 testingOverrides: metaOverridesForProvider(p), 416 Ui: ui, 417 }, 418 } 419 420 args := []string{ 421 "-state", statePath, 422 "test_instance.foo", 423 "bar", 424 } 425 code := c.Run(args) 426 if code != 1 { 427 t.Fatalf("import succeeded; expected failure") 428 } 429 430 msg := ui.ErrorWriter.String() 431 if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) { 432 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 433 } 434 } 435 436 func TestImport_missingModuleConfig(t *testing.T) { 437 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 438 439 statePath := testTempFile(t) 440 441 p := testProvider() 442 ui := new(cli.MockUi) 443 c := &ImportCommand{ 444 Meta: Meta{ 445 testingOverrides: metaOverridesForProvider(p), 446 Ui: ui, 447 }, 448 } 449 450 args := []string{ 451 "-state", statePath, 452 "module.baz.test_instance.foo", 453 "bar", 454 } 455 code := c.Run(args) 456 if code != 1 { 457 t.Fatalf("import succeeded; expected failure") 458 } 459 460 msg := ui.ErrorWriter.String() 461 if want := `module.baz does not exist in the configuration`; !strings.Contains(msg, want) { 462 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 463 } 464 } 465 466 func TestImport_dataResource(t *testing.T) { 467 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 468 469 statePath := testTempFile(t) 470 471 p := testProvider() 472 ui := new(cli.MockUi) 473 c := &ImportCommand{ 474 Meta: Meta{ 475 testingOverrides: metaOverridesForProvider(p), 476 Ui: ui, 477 }, 478 } 479 480 args := []string{ 481 "-state", statePath, 482 "data.test_data_source.foo", 483 "bar", 484 } 485 code := c.Run(args) 486 if code != 1 { 487 t.Fatalf("import succeeded; expected failure") 488 } 489 490 msg := ui.ErrorWriter.String() 491 if want := `resource address must refer to a managed resource`; !strings.Contains(msg, want) { 492 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 493 } 494 } 495 496 func TestImport_invalidResourceAddr(t *testing.T) { 497 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 498 499 statePath := testTempFile(t) 500 501 p := testProvider() 502 ui := new(cli.MockUi) 503 c := &ImportCommand{ 504 Meta: Meta{ 505 testingOverrides: metaOverridesForProvider(p), 506 Ui: ui, 507 }, 508 } 509 510 args := []string{ 511 "-state", statePath, 512 "bananas", 513 "bar", 514 } 515 code := c.Run(args) 516 if code != 1 { 517 t.Fatalf("import succeeded; expected failure") 518 } 519 520 msg := ui.ErrorWriter.String() 521 if want := `invalid resource address "bananas"`; !strings.Contains(msg, want) { 522 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 523 } 524 } 525 526 func TestImport_targetIsModule(t *testing.T) { 527 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 528 529 statePath := testTempFile(t) 530 531 p := testProvider() 532 ui := new(cli.MockUi) 533 c := &ImportCommand{ 534 Meta: Meta{ 535 testingOverrides: metaOverridesForProvider(p), 536 Ui: ui, 537 }, 538 } 539 540 args := []string{ 541 "-state", statePath, 542 "module.foo", 543 "bar", 544 } 545 code := c.Run(args) 546 if code != 1 { 547 t.Fatalf("import succeeded; expected failure") 548 } 549 550 msg := ui.ErrorWriter.String() 551 if want := `resource address must include a full resource spec`; !strings.Contains(msg, want) { 552 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 553 } 554 } 555 556 // make sure we search the full plugin path during import 557 func TestImport_pluginDir(t *testing.T) { 558 td := tempDir(t) 559 copy.CopyDir(testFixturePath("import-provider"), td) 560 defer os.RemoveAll(td) 561 defer testChdir(t, td)() 562 563 // make a fake provider in a custom plugin directory 564 if err := os.Mkdir("plugins", 0755); err != nil { 565 t.Fatal(err) 566 } 567 if err := ioutil.WriteFile("plugins/terraform-provider-test_v1.1.1_x4", []byte("invalid binary"), 0755); err != nil { 568 t.Fatal(err) 569 } 570 571 ui := new(cli.MockUi) 572 c := &ImportCommand{ 573 Meta: Meta{ 574 Ui: ui, 575 }, 576 } 577 578 // store our custom plugin path, which would normally happen during init 579 if err := c.storePluginPath([]string{"./plugins"}); err != nil { 580 t.Fatal(err) 581 } 582 583 // Now we need to go through some plugin init. 584 // This discovers our fake plugin and writes the lock file. 585 initCmd := &InitCommand{ 586 Meta: Meta{ 587 pluginPath: []string{"./plugins"}, 588 Ui: new(cli.MockUi), 589 }, 590 providerInstaller: &discovery.ProviderInstaller{ 591 PluginProtocolVersion: plugin.Handshake.ProtocolVersion, 592 }, 593 } 594 if err := initCmd.getProviders(".", nil, false); err != nil { 595 t.Fatal(err) 596 } 597 598 args := []string{ 599 "test_instance.foo", 600 "bar", 601 } 602 if code := c.Run(args); code == 0 { 603 t.Fatalf("expected error, got: %s", ui.OutputWriter) 604 } 605 606 outMsg := ui.OutputWriter.String() 607 // if we were missing a plugin, the output will have some explanation 608 // about requirements. If discovery starts verifying binary compatibility, 609 // we will need to write a dummy provider above. 610 if strings.Contains(outMsg, "requirements") { 611 t.Fatal("unexpected output:", outMsg) 612 } 613 614 // We wanted a plugin execution error, rather than a requirement error. 615 // Looking for "exec" in the error should suffice for now. 616 errMsg := ui.ErrorWriter.String() 617 if !strings.Contains(errMsg, "exec") { 618 t.Fatal("unexpected error:", errMsg) 619 } 620 } 621 622 const testImportStr = ` 623 test_instance.foo: 624 ID = yay 625 provider = test 626 ` 627 628 const testImportCustomProviderStr = ` 629 test_instance.foo: 630 ID = yay 631 provider = test.alias 632 `