From b79adeae029a7573c9bebe60b72532a1b58780ad Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 7 Nov 2017 13:09:36 -0500 Subject: [PATCH] save resolved providers for resources to state Use the ResourceState.Provider field to store the full name of the provider used during apply. This field is only used when a resource is removed from the config, and will allow that resource to be removed by the exact same provider with which it was created. Modify the locations which might accept the alue of the ResourceState.Provider field to detect that the name is resolved. --- config/config.go | 4 +++- terraform/context_test.go | 1 + terraform/node_data_refresh.go | 4 +++- terraform/node_provider_abstract.go | 6 ++++++ terraform/node_resource_apply.go | 6 +++--- terraform/node_resource_destroy.go | 4 +++- terraform/node_resource_plan_instance.go | 4 ++-- terraform/node_resource_refresh.go | 2 +- terraform/transform_deposed.go | 4 ++-- terraform/transform_provider.go | 9 +++++++-- 10 files changed, 31 insertions(+), 13 deletions(-) diff --git a/config/config.go b/config/config.go index f36d90847..ebf30e0cd 100644 --- a/config/config.go +++ b/config/config.go @@ -261,7 +261,9 @@ func (r *Resource) ProviderFullName() string { // the provider name is inferred from the resource type name. func ResourceProviderFullName(resourceType, explicitProvider string) string { if explicitProvider != "" { - return explicitProvider + // check for an explicit provider name, or return the original + parts := strings.SplitAfter(explicitProvider, "provider.") + return parts[len(parts)-1] } idx := strings.IndexRune(resourceType, '_') diff --git a/terraform/context_test.go b/terraform/context_test.go index b7064bef0..eec91e3aa 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -147,6 +147,7 @@ func TestNewContextState(t *testing.T) { } func testContext2(t *testing.T, opts *ContextOpts) *Context { + t.Helper() // Enable the shadow graph opts.Shadow = true diff --git a/terraform/node_data_refresh.go b/terraform/node_data_refresh.go index 15d9b8f9c..7ab76c235 100644 --- a/terraform/node_data_refresh.go +++ b/terraform/node_data_refresh.go @@ -108,7 +108,9 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode { // Get the state if we have it, if not we build it rs := n.ResourceState if rs == nil { - rs = &ResourceState{} + rs = &ResourceState{ + Provider: n.ResolvedProvider, + } } // If the config isn't empty we update the state diff --git a/terraform/node_provider_abstract.go b/terraform/node_provider_abstract.go index 2b346a44c..9e490f7b4 100644 --- a/terraform/node_provider_abstract.go +++ b/terraform/node_provider_abstract.go @@ -2,6 +2,7 @@ package terraform import ( "fmt" + "strings" "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/dag" @@ -25,6 +26,11 @@ type NodeAbstractProvider struct { } func ResolveProviderName(name string, path []string) string { + if strings.Contains(name, "provider.") { + // already resolved + return name + } + name = fmt.Sprintf("provider.%s", name) if len(path) >= 1 { name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name) diff --git a/terraform/node_resource_apply.go b/terraform/node_resource_apply.go index 807b1f416..9f6d69fd3 100644 --- a/terraform/node_resource_apply.go +++ b/terraform/node_resource_apply.go @@ -158,7 +158,7 @@ func (n *NodeApplyableResource) evalTreeDataResource( &EvalWriteState{ Name: stateId, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, @@ -308,7 +308,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource( &EvalWriteState{ Name: stateId, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, @@ -332,7 +332,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource( Else: &EvalWriteState{ Name: stateId, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, diff --git a/terraform/node_resource_destroy.go b/terraform/node_resource_destroy.go index cffb9ae60..74a1e5494 100644 --- a/terraform/node_resource_destroy.go +++ b/terraform/node_resource_destroy.go @@ -149,7 +149,9 @@ func (n *NodeDestroyResource) EvalTree() EvalNode { // Get our state rs := n.ResourceState if rs == nil { - rs = &ResourceState{} + rs = &ResourceState{ + Provider: n.ResolvedProvider, + } } var diffApply *InstanceDiff diff --git a/terraform/node_resource_plan_instance.go b/terraform/node_resource_plan_instance.go index 25a76a99f..7d9fcddb5 100644 --- a/terraform/node_resource_plan_instance.go +++ b/terraform/node_resource_plan_instance.go @@ -112,7 +112,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource( &EvalWriteState{ Name: stateId, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, @@ -177,7 +177,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource( &EvalWriteState{ Name: stateId, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, diff --git a/terraform/node_resource_refresh.go b/terraform/node_resource_refresh.go index d504e7de4..c18c95f96 100644 --- a/terraform/node_resource_refresh.go +++ b/terraform/node_resource_refresh.go @@ -251,7 +251,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState( &EvalWriteState{ Name: stateID, ResourceType: n.Config.Type, - Provider: n.Config.Provider, + Provider: n.ResolvedProvider, Dependencies: stateDeps, State: &state, }, diff --git a/terraform/transform_deposed.go b/terraform/transform_deposed.go index c3c87a299..87a1f9c98 100644 --- a/terraform/transform_deposed.go +++ b/terraform/transform_deposed.go @@ -108,7 +108,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode { &EvalWriteStateDeposed{ Name: n.ResourceName, ResourceType: n.ResourceType, - Provider: n.ProviderName, + Provider: n.ResolvedProvider, State: &state, Index: n.Index, }, @@ -157,7 +157,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode { &EvalWriteStateDeposed{ Name: n.ResourceName, ResourceType: n.ResourceType, - Provider: n.ProviderName, + Provider: n.ResolvedProvider, State: &state, Index: n.Index, }, diff --git a/terraform/transform_provider.go b/terraform/transform_provider.go index 5a2af25f7..6d7ab28e9 100644 --- a/terraform/transform_provider.go +++ b/terraform/transform_provider.go @@ -52,7 +52,8 @@ type GraphNodeCloseProvider interface { // GraphNodeProviderConsumer is an interface that nodes that require // a provider must implement. ProvidedBy must return the name of the provider -// to use. +// to use. This may be a provider by type, type.alias or a fully resolved +// provider name type GraphNodeProviderConsumer interface { ProvidedBy() string // Set the resolved provider address for this resource. @@ -127,7 +128,6 @@ func (t *ProviderTransformer) Transform(g *Graph) error { // in the graph are evaluated. type CloseProviderTransformer struct{} -// FIXME: this doesn't close providers if the root provider is disabled func (t *CloseProviderTransformer) Transform(g *Graph) error { pm := providerVertexMap(g) cpm := make(map[string]*graphNodeCloseProvider) @@ -286,6 +286,11 @@ func (t *PruneProviderTransformer) Transform(g *Graph) error { // providerMapKey is a helper that gives us the key to use for the // maps returned by things such as providerVertexMap. func providerMapKey(k string, v dag.Vertex) string { + if strings.Contains(k, "provider.") { + // this is already resolved + return k + } + // we create a dummy provider to var path []string if sp, ok := v.(GraphNodeSubPath); ok {