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 f36d908479..ebf30e0cd6 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 b7064bef0f..eec91e3aa9 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 15d9b8f9cb..7ab76c2353 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 2b346a44c5..9e490f7b4f 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 807b1f4169..9f6d69fd3c 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 cffb9ae60b..74a1e54943 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 25a76a99fc..7d9fcddb55 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 d504e7de41..c18c95f968 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 c3c87a299b..87a1f9c987 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 5a2af25f70..6d7ab28e9c 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 {