diff --git a/terraform/context.go b/terraform/context.go index 8ddad3331..667ee0473 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -53,6 +53,8 @@ type ContextOpts struct { // Context represents all the context that Terraform needs in order to // perform operations on infrastructure. This structure is built using // NewContext. See the documentation for that. +// +// Extra functions on Context can be found in context_*.go files. type Context struct { destroy bool diff *Diff diff --git a/terraform/context_import.go b/terraform/context_import.go new file mode 100644 index 000000000..83cb1aeaf --- /dev/null +++ b/terraform/context_import.go @@ -0,0 +1,63 @@ +package terraform + +// ImportOpts are used as the configuration for Import. +type ImportOpts struct { + Targets []*ImportTarget +} + +// ImportTarget is a single resource to import. +type ImportTarget struct { + // Addr is the full resource address of the resource to import. + // Example: "module.foo.aws_instance.bar" + Addr string + + // ID is the ID of the resource to import. This is resource-specific. + ID string +} + +// Import takes already-created external resources and brings them +// under Terraform management. Import requires the exact type, name, and ID +// of the resources to import. +// +// This operation is idempotent. If the requested resource is already +// imported, no changes are made to the state. +// +// Further, this operation also gracefully handles partial state. If during +// an import there is a failure, all previously imported resources remain +// imported. +func (c *Context) Import(opts *ImportOpts) (*State, error) { + // Hold a lock since we can modify our own state here + v := c.acquireRun() + defer c.releaseRun(v) + + // Copy our own state + c.state = c.state.DeepCopy() + + // Get supported providers (for the graph builder) + providers := make([]string, 0, len(c.providers)) + for k, _ := range c.providers { + providers = append(providers, k) + } + + // Initialize our graph builder + builder := &ImportGraphBuilder{ + ImportTargets: opts.Targets, + Providers: providers, + } + + // Build the graph! + graph, err := builder.Build(RootModulePath) + if err != nil { + return nil, err + } + + // Walk it + if _, err := c.walk(graph, walkImport); err != nil { + return nil, err + } + + // Clean the state + c.state.prune() + + return c.state, nil +} diff --git a/terraform/graph_builder_import.go b/terraform/graph_builder_import.go new file mode 100644 index 000000000..eece5c8bb --- /dev/null +++ b/terraform/graph_builder_import.go @@ -0,0 +1,43 @@ +package terraform + +// ImportGraphBuilder implements GraphBuilder and is responsible for building +// a graph for importing resources into Terraform. This is a much, much +// simpler graph than a normal configuration graph. +type ImportGraphBuilder struct { + // ImportTargets are the list of resources to import. + ImportTargets []*ImportTarget + + // Providers is the list of providers supported. + Providers []string +} + +// Build builds the graph according to the steps returned by Steps. +func (b *ImportGraphBuilder) Build(path []string) (*Graph, error) { + return (&BasicGraphBuilder{ + Steps: b.Steps(), + Validate: true, + }).Build(path) +} + +// Steps returns the ordered list of GraphTransformers that must be executed +// to build a complete graph. +func (b *ImportGraphBuilder) Steps() []GraphTransformer { + steps := []GraphTransformer{ + // Provider-related transformations + &MissingProviderTransformer{Providers: b.Providers}, + &ProviderTransformer{}, + &DisableProviderTransformer{}, + &PruneProviderTransformer{}, + + // Single root + &RootTransformer{}, + + // Insert nodes to close opened plugin connections + &CloseProviderTransformer{}, + + // Optimize + &TransitiveReductionTransformer{}, + } + + return steps +} diff --git a/terraform/graph_walk_operation.go b/terraform/graph_walk_operation.go index f2de24134..3fb374819 100644 --- a/terraform/graph_walk_operation.go +++ b/terraform/graph_walk_operation.go @@ -14,4 +14,5 @@ const ( walkRefresh walkValidate walkDestroy + walkImport )