github.com/sl1pm4t/terraform@v0.6.4-0.20170725213156-870617d22df3/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 func TestImport_providerConfigWithVar(t *testing.T) { 114 defer testChdir(t, testFixturePath("import-provider-var"))() 115 116 statePath := testTempFile(t) 117 118 p := testProvider() 119 ui := new(cli.MockUi) 120 c := &ImportCommand{ 121 Meta: Meta{ 122 testingOverrides: metaOverridesForProvider(p), 123 Ui: ui, 124 }, 125 } 126 127 p.ImportStateFn = nil 128 p.ImportStateReturn = []*terraform.InstanceState{ 129 &terraform.InstanceState{ 130 ID: "yay", 131 Ephemeral: terraform.EphemeralState{ 132 Type: "test_instance", 133 }, 134 }, 135 } 136 137 configured := false 138 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 139 configured = true 140 141 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 142 return fmt.Errorf("bad value: %#v", v) 143 } 144 145 return nil 146 } 147 148 args := []string{ 149 "-state", statePath, 150 "-var", "foo=bar", 151 "test_instance.foo", 152 "bar", 153 } 154 if code := c.Run(args); code != 0 { 155 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 156 } 157 158 // Verify that we were called 159 if !configured { 160 t.Fatal("Configure should be called") 161 } 162 163 if !p.ImportStateCalled { 164 t.Fatal("ImportState should be called") 165 } 166 167 testStateOutput(t, statePath, testImportStr) 168 } 169 170 func TestImport_providerConfigWithVarDefault(t *testing.T) { 171 defer testChdir(t, testFixturePath("import-provider-var-default"))() 172 173 statePath := testTempFile(t) 174 175 p := testProvider() 176 ui := new(cli.MockUi) 177 c := &ImportCommand{ 178 Meta: Meta{ 179 testingOverrides: metaOverridesForProvider(p), 180 Ui: ui, 181 }, 182 } 183 184 p.ImportStateFn = nil 185 p.ImportStateReturn = []*terraform.InstanceState{ 186 &terraform.InstanceState{ 187 ID: "yay", 188 Ephemeral: terraform.EphemeralState{ 189 Type: "test_instance", 190 }, 191 }, 192 } 193 194 configured := false 195 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 196 configured = true 197 198 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 199 return fmt.Errorf("bad value: %#v", v) 200 } 201 202 return nil 203 } 204 205 args := []string{ 206 "-state", statePath, 207 "test_instance.foo", 208 "bar", 209 } 210 if code := c.Run(args); code != 0 { 211 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 212 } 213 214 // Verify that we were called 215 if !configured { 216 t.Fatal("Configure should be called") 217 } 218 219 if !p.ImportStateCalled { 220 t.Fatal("ImportState should be called") 221 } 222 223 testStateOutput(t, statePath, testImportStr) 224 } 225 226 func TestImport_providerConfigWithVarFile(t *testing.T) { 227 defer testChdir(t, testFixturePath("import-provider-var-file"))() 228 229 statePath := testTempFile(t) 230 231 p := testProvider() 232 ui := new(cli.MockUi) 233 c := &ImportCommand{ 234 Meta: Meta{ 235 testingOverrides: metaOverridesForProvider(p), 236 Ui: ui, 237 }, 238 } 239 240 p.ImportStateFn = nil 241 p.ImportStateReturn = []*terraform.InstanceState{ 242 &terraform.InstanceState{ 243 ID: "yay", 244 Ephemeral: terraform.EphemeralState{ 245 Type: "test_instance", 246 }, 247 }, 248 } 249 250 configured := false 251 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 252 configured = true 253 254 if v, ok := c.Get("foo"); !ok || v.(string) != "bar" { 255 return fmt.Errorf("bad value: %#v", v) 256 } 257 258 return nil 259 } 260 261 args := []string{ 262 "-state", statePath, 263 "-var-file", "blah.tfvars", 264 "test_instance.foo", 265 "bar", 266 } 267 if code := c.Run(args); code != 0 { 268 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 269 } 270 271 // Verify that we were called 272 if !configured { 273 t.Fatal("Configure should be called") 274 } 275 276 if !p.ImportStateCalled { 277 t.Fatal("ImportState should be called") 278 } 279 280 testStateOutput(t, statePath, testImportStr) 281 } 282 283 func TestImport_customProvider(t *testing.T) { 284 defer testChdir(t, testFixturePath("import-provider-aliased"))() 285 286 statePath := testTempFile(t) 287 288 p := testProvider() 289 ui := new(cli.MockUi) 290 c := &ImportCommand{ 291 Meta: Meta{ 292 testingOverrides: metaOverridesForProvider(p), 293 Ui: ui, 294 }, 295 } 296 297 p.ImportStateFn = nil 298 p.ImportStateReturn = []*terraform.InstanceState{ 299 &terraform.InstanceState{ 300 ID: "yay", 301 Ephemeral: terraform.EphemeralState{ 302 Type: "test_instance", 303 }, 304 }, 305 } 306 307 args := []string{ 308 "-provider", "test.alias", 309 "-state", statePath, 310 "test_instance.foo", 311 "bar", 312 } 313 if code := c.Run(args); code != 0 { 314 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 315 } 316 317 if !p.ImportStateCalled { 318 t.Fatal("ImportState should be called") 319 } 320 321 testStateOutput(t, statePath, testImportCustomProviderStr) 322 } 323 324 func TestImport_missingResourceConfig(t *testing.T) { 325 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 326 327 statePath := testTempFile(t) 328 329 p := testProvider() 330 ui := new(cli.MockUi) 331 c := &ImportCommand{ 332 Meta: Meta{ 333 testingOverrides: metaOverridesForProvider(p), 334 Ui: ui, 335 }, 336 } 337 338 args := []string{ 339 "-state", statePath, 340 "test_instance.foo", 341 "bar", 342 } 343 code := c.Run(args) 344 if code != 1 { 345 t.Fatalf("import succeeded; expected failure") 346 } 347 348 msg := ui.ErrorWriter.String() 349 if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) { 350 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 351 } 352 } 353 354 func TestImport_missingModuleConfig(t *testing.T) { 355 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 356 357 statePath := testTempFile(t) 358 359 p := testProvider() 360 ui := new(cli.MockUi) 361 c := &ImportCommand{ 362 Meta: Meta{ 363 testingOverrides: metaOverridesForProvider(p), 364 Ui: ui, 365 }, 366 } 367 368 args := []string{ 369 "-state", statePath, 370 "module.baz.test_instance.foo", 371 "bar", 372 } 373 code := c.Run(args) 374 if code != 1 { 375 t.Fatalf("import succeeded; expected failure") 376 } 377 378 msg := ui.ErrorWriter.String() 379 if want := `module.baz does not exist in the configuration`; !strings.Contains(msg, want) { 380 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 381 } 382 } 383 384 func TestImport_dataResource(t *testing.T) { 385 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 386 387 statePath := testTempFile(t) 388 389 p := testProvider() 390 ui := new(cli.MockUi) 391 c := &ImportCommand{ 392 Meta: Meta{ 393 testingOverrides: metaOverridesForProvider(p), 394 Ui: ui, 395 }, 396 } 397 398 args := []string{ 399 "-state", statePath, 400 "data.test_data_source.foo", 401 "bar", 402 } 403 code := c.Run(args) 404 if code != 1 { 405 t.Fatalf("import succeeded; expected failure") 406 } 407 408 msg := ui.ErrorWriter.String() 409 if want := `resource address must refer to a managed resource`; !strings.Contains(msg, want) { 410 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 411 } 412 } 413 414 func TestImport_invalidResourceAddr(t *testing.T) { 415 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 416 417 statePath := testTempFile(t) 418 419 p := testProvider() 420 ui := new(cli.MockUi) 421 c := &ImportCommand{ 422 Meta: Meta{ 423 testingOverrides: metaOverridesForProvider(p), 424 Ui: ui, 425 }, 426 } 427 428 args := []string{ 429 "-state", statePath, 430 "bananas", 431 "bar", 432 } 433 code := c.Run(args) 434 if code != 1 { 435 t.Fatalf("import succeeded; expected failure") 436 } 437 438 msg := ui.ErrorWriter.String() 439 if want := `invalid resource address "bananas"`; !strings.Contains(msg, want) { 440 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 441 } 442 } 443 444 func TestImport_targetIsModule(t *testing.T) { 445 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 446 447 statePath := testTempFile(t) 448 449 p := testProvider() 450 ui := new(cli.MockUi) 451 c := &ImportCommand{ 452 Meta: Meta{ 453 testingOverrides: metaOverridesForProvider(p), 454 Ui: ui, 455 }, 456 } 457 458 args := []string{ 459 "-state", statePath, 460 "module.foo", 461 "bar", 462 } 463 code := c.Run(args) 464 if code != 1 { 465 t.Fatalf("import succeeded; expected failure") 466 } 467 468 msg := ui.ErrorWriter.String() 469 if want := `resource address must include a full resource spec`; !strings.Contains(msg, want) { 470 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 471 } 472 } 473 474 // make sure we search the full plugin path during import 475 func TestImport_pluginDir(t *testing.T) { 476 td := tempDir(t) 477 copy.CopyDir(testFixturePath("import-provider"), td) 478 defer os.RemoveAll(td) 479 defer testChdir(t, td)() 480 481 // make a fake provider in a custom plugin directory 482 if err := os.Mkdir("plugins", 0755); err != nil { 483 t.Fatal(err) 484 } 485 if err := ioutil.WriteFile("plugins/terraform-provider-test_v1.1.1_x4", []byte("invalid binary"), 0755); err != nil { 486 t.Fatal(err) 487 } 488 489 ui := new(cli.MockUi) 490 c := &ImportCommand{ 491 Meta: Meta{ 492 Ui: ui, 493 }, 494 } 495 496 // store our custom plugin path, which would normally happen during init 497 if err := c.storePluginPath([]string{"./plugins"}); err != nil { 498 t.Fatal(err) 499 } 500 501 // Now we need to go through some plugin init. 502 // This discovers our fake plugin and writes the lock file. 503 initCmd := &InitCommand{ 504 Meta: Meta{ 505 pluginPath: []string{"./plugins"}, 506 Ui: new(cli.MockUi), 507 }, 508 providerInstaller: &discovery.ProviderInstaller{ 509 PluginProtocolVersion: plugin.Handshake.ProtocolVersion, 510 }, 511 } 512 if err := initCmd.getProviders(".", nil, false); err != nil { 513 t.Fatal(err) 514 } 515 516 args := []string{ 517 "test_instance.foo", 518 "bar", 519 } 520 if code := c.Run(args); code == 0 { 521 t.Fatalf("expected error, got: %s", ui.OutputWriter) 522 } 523 524 outMsg := ui.OutputWriter.String() 525 // if we were missing a plugin, the output will have some explanation 526 // about requirements. If discovery starts verifying binary compatibility, 527 // we will need to write a dummy provider above. 528 if strings.Contains(outMsg, "requirements") { 529 t.Fatal("unexpected output:", outMsg) 530 } 531 532 // We wanted a plugin execution error, rather than a requirement error. 533 // Looking for "exec" in the error should suffice for now. 534 errMsg := ui.ErrorWriter.String() 535 if !strings.Contains(errMsg, "exec") { 536 t.Fatal("unexpected error:", errMsg) 537 } 538 } 539 540 const testImportStr = ` 541 test_instance.foo: 542 ID = yay 543 provider = test 544 ` 545 546 const testImportCustomProviderStr = ` 547 test_instance.foo: 548 ID = yay 549 provider = test.alias 550 `