From aca26fd7846d3a4698ba18572ff8cf021e48fc53 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 28 Apr 2016 11:46:46 +0200 Subject: [PATCH] terraform: ImportTransformer, EvalImportState --- terraform/context_import_test.go | 34 ++++--------- terraform/eval_import_state.go | 32 ++++++++++++ terraform/graph_builder_import.go | 3 ++ terraform/transform_import_state.go | 78 +++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 terraform/eval_import_state.go create mode 100644 terraform/transform_import_state.go diff --git a/terraform/context_import_test.go b/terraform/context_import_test.go index cd0becb6d..2b633ae6a 100644 --- a/terraform/context_import_test.go +++ b/terraform/context_import_test.go @@ -1,19 +1,8 @@ package terraform -/* import ( - "bytes" - "fmt" - "os" - "reflect" - "sort" "strings" - "sync" - "sync/atomic" "testing" - "time" - - "github.com/hashicorp/terraform/config/module" ) func TestContextImport(t *testing.T) { @@ -24,24 +13,23 @@ func TestContextImport(t *testing.T) { }, }) - if _, err := ctx.Plan(); err != nil { - t.Fatalf("err: %s", err) - } - - state, err := ctx.Apply() + state, err := ctx.Import(&ImportOpts{ + Targets: []*ImportTarget{ + &ImportTarget{ + Addr: "aws_instance.foo", + ID: "bar", + }, + }, + }) if err != nil { t.Fatalf("err: %s", err) } - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyStr) + expected := strings.TrimSpace(testImportStr) if actual != expected { t.Fatalf("bad: \n%s", actual) } } -*/ + +const testImportStr = `` diff --git a/terraform/eval_import_state.go b/terraform/eval_import_state.go new file mode 100644 index 000000000..c85ab8aa9 --- /dev/null +++ b/terraform/eval_import_state.go @@ -0,0 +1,32 @@ +package terraform + +import ( + "fmt" +) + +// EvalImportState is an EvalNode implementation that performs an +// ImportState operation on a provider. This will return the imported +// states but won't modify any actual state. +type EvalImportState struct { + Provider *ResourceProvider + Info *InstanceInfo + Output *[]*InstanceState +} + +// TODO: test +func (n *EvalImportState) Eval(ctx EvalContext) (interface{}, error) { + provider := *n.Provider + + // Refresh! + state, err := provider.ImportState(n.Info) + if err != nil { + return nil, fmt.Errorf( + "import %s (id: %s): %s", n.Info.Type, n.Info.Id, err) + } + + if n.Output != nil { + *n.Output = state + } + + return nil, nil +} diff --git a/terraform/graph_builder_import.go b/terraform/graph_builder_import.go index eece5c8bb..737c29705 100644 --- a/terraform/graph_builder_import.go +++ b/terraform/graph_builder_import.go @@ -23,6 +23,9 @@ func (b *ImportGraphBuilder) Build(path []string) (*Graph, error) { // to build a complete graph. func (b *ImportGraphBuilder) Steps() []GraphTransformer { steps := []GraphTransformer{ + // Add the import steps + &ImportStateTransformer{Targets: b.ImportTargets}, + // Provider-related transformations &MissingProviderTransformer{Providers: b.Providers}, &ProviderTransformer{}, diff --git a/terraform/transform_import_state.go b/terraform/transform_import_state.go new file mode 100644 index 000000000..15f437159 --- /dev/null +++ b/terraform/transform_import_state.go @@ -0,0 +1,78 @@ +package terraform + +import ( + "fmt" +) + +// ImportStateTransformer is a GraphTransformer that adds nodes to the +// graph to represent the imports we want to do for resources. +type ImportStateTransformer struct { + Targets []*ImportTarget +} + +func (t *ImportStateTransformer) Transform(g *Graph) error { + nodes := make([]*graphNodeImportState, 0, len(t.Targets)) + for _, target := range t.Targets { + addr, err := ParseResourceAddress(target.Addr) + if err != nil { + return fmt.Errorf( + "failed to parse resource address '%s': %s", + target.Addr, err) + } + + nodes = append(nodes, &graphNodeImportState{ + Addr: addr, + ID: target.ID, + }) + } + + // Build the graph vertices + for _, n := range nodes { + g.Add(n) + } + + return nil +} + +type graphNodeImportState struct { + Addr *ResourceAddress // Addr is the resource address to import to + ID string // ID is the ID to import as +} + +func (n *graphNodeImportState) Name() string { + return fmt.Sprintf("import %s (id: %s)", n.Addr, n.ID) +} + +func (n *graphNodeImportState) ProvidedBy() []string { + return []string{resourceProvider(n.Addr.Type, "")} +} + +// GraphNodeSubPath +func (n *graphNodeImportState) Path() []string { + return n.Addr.Path +} + +// GraphNodeEvalable impl. +func (n *graphNodeImportState) EvalTree() EvalNode { + var provider ResourceProvider + var states []*InstanceState + info := &InstanceInfo{ + Id: n.ID, + ModulePath: n.Addr.Path, + Type: n.Addr.Type, + } + + return &EvalSequence{ + Nodes: []EvalNode{ + &EvalGetProvider{ + Name: n.ProvidedBy()[0], + Output: &provider, + }, + &EvalImportState{ + Provider: &provider, + Info: info, + Output: &states, + }, + }, + } +}