From 9c721a41311ec64d6ac4d4a857bb294290c4980a Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Fri, 25 Sep 2020 11:15:53 -0400 Subject: [PATCH] terraform: improved refactor of EvalWriteResourceState EvalWriteResourceState finds new life as a method called WriteResourceState on NodeAbstractResource. --- terraform/node_resource_abstract.go | 50 +++++++++++++++++++++++++++++ terraform/node_resource_apply.go | 40 ++--------------------- terraform/node_resource_plan.go | 39 ++-------------------- 3 files changed, 54 insertions(+), 75 deletions(-) diff --git a/terraform/node_resource_abstract.go b/terraform/node_resource_abstract.go index 50abadb38..f74d651f3 100644 --- a/terraform/node_resource_abstract.go +++ b/terraform/node_resource_abstract.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/lang" "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) // ConcreteResourceNodeFunc is a callback type used to convert an @@ -446,6 +447,55 @@ func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotN } } +// WriteResourceState ensures that a suitable resource-level state record is +// present in the state, if that's required for the "each mode" of that +// resource. +//å +// This is important primarily for the situation where count = 0, since this +// eval is the only change we get to set the resource "each mode" to list +// in that case, allowing expression evaluation to see it as a zero-element list +// rather than as not set at all. +func (n *NodeAbstractResource) WriteResourceState(ctx EvalContext, addr addrs.AbsResource) error { + var diags tfdiags.Diagnostics + state := ctx.State() + + // We'll record our expansion decision in the shared "expander" object + // so that later operations (i.e. DynamicExpand and expression evaluation) + // can refer to it. Since this node represents the abstract module, we need + // to expand the module here to create all resources. + expander := ctx.InstanceExpander() + + switch { + case n.Config.Count != nil: + count, countDiags := evaluateCountExpression(n.Config.Count, ctx) + diags = diags.Append(countDiags) + if countDiags.HasErrors() { + return diags.Err() + } + + state.SetResourceProvider(addr, n.ResolvedProvider) + expander.SetResourceCount(addr.Module, n.Addr.Resource, count) + + case n.Config.ForEach != nil: + forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx) + diags = diags.Append(forEachDiags) + if forEachDiags.HasErrors() { + return diags.Err() + } + + // This method takes care of all of the business logic of updating this + // while ensuring that any existing instances are preserved, etc. + state.SetResourceProvider(addr, n.ResolvedProvider) + expander.SetResourceForEach(addr.Module, n.Addr.Resource, forEach) + + default: + state.SetResourceProvider(addr, n.ResolvedProvider) + expander.SetResourceSingle(addr.Module, n.Addr.Resource) + } + + return nil +} + // graphNodesAreResourceInstancesInDifferentInstancesOfSameModule is an // annoyingly-task-specific helper function that returns true if and only if // the following conditions hold: diff --git a/terraform/node_resource_apply.go b/terraform/node_resource_apply.go index 0a9d94883..44ef6d509 100644 --- a/terraform/node_resource_apply.go +++ b/terraform/node_resource_apply.go @@ -6,7 +6,6 @@ import ( "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/lang" - "github.com/hashicorp/terraform/tfdiags" ) // nodeExpandApplyableResource handles the first layer of resource @@ -109,41 +108,6 @@ func (n *NodeApplyableResource) Execute(ctx EvalContext, op walkOperation) error return nil } - var diags tfdiags.Diagnostics - state := ctx.State() - - // We'll record our expansion decision in the shared "expander" object - // so that later operations (i.e. DynamicExpand and expression evaluation) - // can refer to it. Since this node represents the abstract module, we need - // to expand the module here to create all resources. - expander := ctx.InstanceExpander() - - switch { - case n.Config.Count != nil: - count, countDiags := evaluateCountExpression(n.Config.Count, ctx) - diags = diags.Append(countDiags) - if countDiags.HasErrors() { - return diags.Err() - } - - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceCount(n.Addr.Module, n.Addr.Resource, count) - - case n.Config.ForEach != nil: - forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx) - diags = diags.Append(forEachDiags) - if forEachDiags.HasErrors() { - return diags.Err() - } - - // This method takes care of all of the business logic of updating this - // while ensuring that any existing instances are preserved, etc. - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceForEach(n.Addr.Module, n.Addr.Resource, forEach) - - default: - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceSingle(n.Addr.Module, n.Addr.Resource) - } - return nil + err := n.WriteResourceState(ctx, n.Addr) + return err } diff --git a/terraform/node_resource_plan.go b/terraform/node_resource_plan.go index 510d1a056..13bd1c65b 100644 --- a/terraform/node_resource_plan.go +++ b/terraform/node_resource_plan.go @@ -185,43 +185,8 @@ func (n *NodePlannableResource) Execute(ctx EvalContext, op walkOperation) error return nil } - var diags tfdiags.Diagnostics - state := ctx.State() - - // We'll record our expansion decision in the shared "expander" object - // so that later operations (i.e. DynamicExpand and expression evaluation) - // can refer to it. Since this node represents the abstract module, we need - // to expand the module here to create all resources. - expander := ctx.InstanceExpander() - - switch { - case n.Config.Count != nil: - count, countDiags := evaluateCountExpression(n.Config.Count, ctx) - diags = diags.Append(countDiags) - if countDiags.HasErrors() { - return diags.Err() - } - - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceCount(n.Addr.Module, n.Addr.Resource, count) - - case n.Config.ForEach != nil: - forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx) - diags = diags.Append(forEachDiags) - if forEachDiags.HasErrors() { - return diags.Err() - } - - // This method takes care of all of the business logic of updating this - // while ensuring that any existing instances are preserved, etc. - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceForEach(n.Addr.Module, n.Addr.Resource, forEach) - - default: - state.SetResourceProvider(n.Addr, n.ResolvedProvider) - expander.SetResourceSingle(n.Addr.Module, n.Addr.Resource) - } - return nil + err := n.WriteResourceState(ctx, n.Addr) + return err } // GraphNodeDestroyerCBD