Implements import with specified provider

This allows the import with a specified provider.
So far it was not possible to get resources imported from a different provider
than the default.
This commit is contained in:
Daniel Spangenberg 2016-11-23 10:44:52 +01:00
parent b335418d0d
commit 804a5bd3c5
7 changed files with 119 additions and 16 deletions

View File

@ -32,6 +32,7 @@ func (c *ImportCommand) Run(args []string) int {
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
cmdFlags.StringVar(&configPath, "config", pwd, "path")
cmdFlags.StringVar(&c.Meta.provider, "provider", "", "provider")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
return 1
@ -62,8 +63,9 @@ func (c *ImportCommand) Run(args []string) int {
newState, err := ctx.Import(&terraform.ImportOpts{
Targets: []*terraform.ImportTarget{
&terraform.ImportTarget{
Addr: args[0],
ID: args[1],
Addr: args[0],
ID: args[1],
Provider: c.Meta.provider,
},
},
})
@ -138,6 +140,8 @@ Options:
-state-out=path Path to write updated state file. By default, the
"-state" path will be used.
-provider=provider Provider used for import. Defaults to: ""
`
return strings.TrimSpace(helpText)
}

View File

@ -844,8 +844,53 @@ func TestRefresh_displaysOutputs(t *testing.T) {
}
*/
func TestImport_customProvider(t *testing.T) {
statePath := testTempFile(t)
p := testProvider()
ui := new(cli.MockUi)
c := &ImportCommand{
Meta: Meta{
ContextOpts: testCtxConfig(p),
Ui: ui,
},
}
p.ImportStateFn = nil
p.ImportStateReturn = []*terraform.InstanceState{
&terraform.InstanceState{
ID: "yay",
Ephemeral: terraform.EphemeralState{
Type: "test_instance",
},
},
}
args := []string{
"-provider", "test.alias",
"-state", statePath,
"test_instance.foo",
"bar",
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
if !p.ImportStateCalled {
t.Fatal("ImportState should be called")
}
testStateOutput(t, statePath, testImportCustomProviderStr)
}
const testImportStr = `
test_instance.foo:
ID = yay
provider = test
`
const testImportCustomProviderStr = `
test_instance.foo:
ID = yay
provider = test.alias
`

View File

@ -72,11 +72,14 @@ type Meta struct {
// allowed when walking the graph
//
// shadow is used to enable/disable the shadow graph
//
// provider is to specify specific resource providers
statePath string
stateOutPath string
backupPath string
parallelism int
shadow bool
provider string
}
// initStatePaths is used to initialize the default values for

View File

@ -23,6 +23,9 @@ type ImportTarget struct {
// ID is the ID of the resource to import. This is resource-specific.
ID string
// Provider string
Provider string
}
// Import takes already-created external resources and brings them

View File

@ -1,3 +1,4 @@
// TODO
package terraform
import (
@ -32,7 +33,6 @@ func TestContextImport_basic(t *testing.T) {
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportStr)
if actual != expected {
@ -621,6 +621,41 @@ func TestContextImport_multiStateSame(t *testing.T) {
}
}
func TestContextImport_customProvider(t *testing.T) {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, err := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: "aws_instance.foo",
ID: "bar",
Provider: "aws.alias",
},
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportCustomProviderStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
const testImportStr = `
aws_instance.foo:
ID = foo
@ -700,3 +735,9 @@ aws_instance.foo:
provider = aws
foo = bar
`
const testImportCustomProviderStr = `
aws_instance.foo:
ID = foo
provider = aws.alias
`

View File

@ -21,8 +21,9 @@ func (t *ImportStateTransformer) Transform(g *Graph) error {
}
nodes = append(nodes, &graphNodeImportState{
Addr: addr,
ID: target.ID,
Addr: addr,
ID: target.ID,
Provider: target.Provider,
})
}
@ -35,8 +36,9 @@ func (t *ImportStateTransformer) Transform(g *Graph) error {
}
type graphNodeImportState struct {
Addr *ResourceAddress // Addr is the resource address to import to
ID string // ID is the ID to import as
Addr *ResourceAddress // Addr is the resource address to import to
ID string // ID is the ID to import as
Provider string // Provider string
states []*InstanceState
}
@ -46,7 +48,7 @@ func (n *graphNodeImportState) Name() string {
}
func (n *graphNodeImportState) ProvidedBy() []string {
return []string{resourceProvider(n.Addr.Type, "")}
return []string{resourceProvider(n.Addr.Type, n.Provider)}
}
// GraphNodeSubPath
@ -147,9 +149,10 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
// is safe.
for i, state := range n.states {
g.Add(&graphNodeImportStateSub{
Target: addrs[i],
Path_: n.Path(),
State: state,
Target: addrs[i],
Path_: n.Path(),
State: state,
Provider: n.Provider,
})
}
@ -167,9 +170,10 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
// and is part of the subgraph. This node is responsible for refreshing
// and adding a resource to the state once it is imported.
type graphNodeImportStateSub struct {
Target *ResourceAddress
State *InstanceState
Path_ []string
Target *ResourceAddress
State *InstanceState
Path_ []string
Provider string
}
func (n *graphNodeImportStateSub) Name() string {
@ -212,7 +216,7 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode {
return &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Name: resourceProvider(info.Type, ""),
Name: resourceProvider(info.Type, n.Provider),
Output: &provider,
},
&EvalRefresh{
@ -229,7 +233,7 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode {
&EvalWriteState{
Name: key.String(),
ResourceType: info.Type,
Provider: resourceProvider(info.Type, ""),
Provider: resourceProvider(info.Type, n.Provider),
State: &state,
},
},

View File

@ -49,6 +49,9 @@ The command-line flags are all optional. The list of available flags are:
the state path. Ignored when [remote state](/docs/state/remote/index.html) is
used.
* `-provider=provider` - Provider used for import. Defaults to the default
provider of the resource to import.
## Provider Configuration
Terraform will attempt to load configuration files that configure the