diff --git a/terraform/context.go b/terraform/context.go index 3e2e8aa3e..707a8749f 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -353,8 +353,20 @@ func (c *Context) Apply() (*State, error) { // Copy our own state c.state = c.state.DeepCopy() - // Build the graph - graph, err := c.Graph(&ContextGraphOpts{Validate: true}) + // Build the graph. If it is a destroy operation, we use the + // standard graph builder. If it is an apply operation, we use + // our new graph builder. + var graph *Graph + var err error + if c.destroy { + graph, err = c.Graph(&ContextGraphOpts{Validate: true}) + } else { + graph, err = (&ApplyGraphBuilder{ + Diff: c.diff, + Providers: c.providersList(), + Provisioners: c.provisionersList(), + }).Build(RootModulePath) + } if err != nil { return nil, err } @@ -709,6 +721,24 @@ func (c *Context) walk( return walker, realErr } +func (c *Context) providersList() []string { + providers := make([]string, 0, len(c.providers)) + for k, _ := range c.providers { + providers = append(providers, k) + } + + return providers +} + +func (c *Context) provisionersList() []string { + provisioners := make([]string, 0, len(c.provisioners)) + for k, _ := range c.provisioners { + provisioners = append(provisioners, k) + } + + return provisioners +} + // parseVariableAsHCL parses the value of a single variable as would have been specified // on the command line via -var or in an environment variable named TF_VAR_x, where x is // the name of the variable. In order to get around the restriction of HCL requiring a diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index f11263f52..8e7ccce38 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -1751,7 +1751,7 @@ func TestContext2Apply_multiVar(t *testing.T) { actual := state.RootModule().Outputs["output"] expected := "bar0,bar1,bar2" - if actual.Value != expected { + if actual == nil || actual.Value != expected { t.Fatalf("bad: \n%s", actual) } @@ -4483,8 +4483,8 @@ func TestContext2Apply_targetedModuleResource(t *testing.T) { } mod := state.ModuleByPath([]string{"root", "child"}) - if len(mod.Resources) != 1 { - t.Fatalf("expected 1 resource, got: %#v", mod.Resources) + if mod == nil || len(mod.Resources) != 1 { + t.Fatalf("expected 1 resource, got: %#v", mod) } checkStateString(t, state, ` diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index f5f84d719..f168a6a3d 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -38,6 +38,9 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { steps := []GraphTransformer{ // Creates all the nodes represented in the diff. &DiffTransformer{Diff: b.Diff}, + + // Single root + &RootTransformer{}, } return steps diff --git a/terraform/resource.go b/terraform/resource.go index 7f1ec3ca4..904d441af 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -72,6 +72,10 @@ type InstanceInfo struct { // HumanId is a unique Id that is human-friendly and useful for UI elements. func (i *InstanceInfo) HumanId() string { + if i == nil { + return "" + } + if len(i.ModulePath) <= 1 { return i.Id }