command: validate import resource address early

Previously we deferred validation of the resource address on the import
command until we were in the core guts, which caused the error responses
to be rather unhelpful.

By validating these things early we can give better feedback to the user.
This commit is contained in:
Martin Atkins 2017-05-16 18:20:08 -07:00
parent f6305fcc27
commit 7d8719150c
3 changed files with 130 additions and 0 deletions

View File

@ -50,6 +50,23 @@ func (c *ImportCommand) Run(args []string) int {
return 1 return 1
} }
// Validate the provided resource address for syntax
addr, err := terraform.ParseResourceAddress(args[0])
if err != nil {
c.Ui.Error(fmt.Sprintf(importCommandInvalidAddressFmt, err))
return 1
}
if !addr.HasResourceSpec() {
// module.foo target isn't allowed for import
c.Ui.Error(importCommandMissingResourceSpecMsg)
return 1
}
if addr.Mode != config.ManagedResourceMode {
// can't import to a data resource address
c.Ui.Error(importCommandResourceModeMsg)
return 1
}
// Load the module // Load the module
var mod *module.Tree var mod *module.Tree
if configPath != "" { if configPath != "" {
@ -204,3 +221,20 @@ Options:
func (c *ImportCommand) Synopsis() string { func (c *ImportCommand) Synopsis() string {
return "Import existing infrastructure into Terraform" return "Import existing infrastructure into Terraform"
} }
const importCommandInvalidAddressFmt = `Error: %s
For information on valid syntax, see:
https://www.terraform.io/docs/internals/resource-addressing.html
`
const importCommandMissingResourceSpecMsg = `Error: resource address must include a full resource spec
For information on valid syntax, see:
https://www.terraform.io/docs/internals/resource-addressing.html
`
const importCommandResourceModeMsg = `Error: resource address must refer to a managed resource.
Data resources cannot be imported.
`

View File

@ -2,6 +2,7 @@ package command
import ( import (
"fmt" "fmt"
"strings"
"testing" "testing"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -315,6 +316,96 @@ func TestImport_customProvider(t *testing.T) {
testStateOutput(t, statePath, testImportCustomProviderStr) testStateOutput(t, statePath, testImportCustomProviderStr)
} }
func TestImport_dataResource(t *testing.T) {
defer testChdir(t, testFixturePath("import-missing-resource-config"))()
statePath := testTempFile(t)
p := testProvider()
ui := new(cli.MockUi)
c := &ImportCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
args := []string{
"-state", statePath,
"data.test_data_source.foo",
"bar",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("import succeeded; expected failure")
}
msg := ui.ErrorWriter.String()
if want := `resource address must refer to a managed resource`; !strings.Contains(msg, want) {
t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
}
}
func TestImport_invalidResourceAddr(t *testing.T) {
defer testChdir(t, testFixturePath("import-missing-resource-config"))()
statePath := testTempFile(t)
p := testProvider()
ui := new(cli.MockUi)
c := &ImportCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
args := []string{
"-state", statePath,
"bananas",
"bar",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("import succeeded; expected failure")
}
msg := ui.ErrorWriter.String()
if want := `invalid resource address "bananas"`; !strings.Contains(msg, want) {
t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
}
}
func TestImport_targetIsModule(t *testing.T) {
defer testChdir(t, testFixturePath("import-missing-resource-config"))()
statePath := testTempFile(t)
p := testProvider()
ui := new(cli.MockUi)
c := &ImportCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
args := []string{
"-state", statePath,
"module.foo",
"bar",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("import succeeded; expected failure")
}
msg := ui.ErrorWriter.String()
if want := `resource address must include a full resource spec`; !strings.Contains(msg, want) {
t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
}
}
const testImportStr = ` const testImportStr = `
test_instance.foo: test_instance.foo:
ID = yay ID = yay

View File

@ -0,0 +1,5 @@
provider "test" {
}
# No resource block present, so import fails