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:
parent
f6305fcc27
commit
7d8719150c
|
@ -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.
|
||||||
|
`
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
provider "test" {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# No resource block present, so import fails
|
Loading…
Reference in New Issue