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.
This commit is contained in:
parent
990acca758
commit
b79adeae02
|
@ -261,7 +261,9 @@ func (r *Resource) ProviderFullName() string {
|
||||||
// the provider name is inferred from the resource type name.
|
// the provider name is inferred from the resource type name.
|
||||||
func ResourceProviderFullName(resourceType, explicitProvider string) string {
|
func ResourceProviderFullName(resourceType, explicitProvider string) string {
|
||||||
if explicitProvider != "" {
|
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, '_')
|
idx := strings.IndexRune(resourceType, '_')
|
||||||
|
|
|
@ -147,6 +147,7 @@ func TestNewContextState(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
||||||
|
t.Helper()
|
||||||
// Enable the shadow graph
|
// Enable the shadow graph
|
||||||
opts.Shadow = true
|
opts.Shadow = true
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,9 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
|
||||||
// Get the state if we have it, if not we build it
|
// Get the state if we have it, if not we build it
|
||||||
rs := n.ResourceState
|
rs := n.ResourceState
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
rs = &ResourceState{}
|
rs = &ResourceState{
|
||||||
|
Provider: n.ResolvedProvider,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the config isn't empty we update the state
|
// If the config isn't empty we update the state
|
||||||
|
|
|
@ -2,6 +2,7 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
|
@ -25,6 +26,11 @@ type NodeAbstractProvider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveProviderName(name string, path []string) string {
|
func ResolveProviderName(name string, path []string) string {
|
||||||
|
if strings.Contains(name, "provider.") {
|
||||||
|
// already resolved
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
name = fmt.Sprintf("provider.%s", name)
|
name = fmt.Sprintf("provider.%s", name)
|
||||||
if len(path) >= 1 {
|
if len(path) >= 1 {
|
||||||
name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name)
|
name = fmt.Sprintf("%s.%s", modulePrefixStr(path), name)
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (n *NodeApplyableResource) evalTreeDataResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -308,7 +308,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -332,7 +332,7 @@ func (n *NodeApplyableResource) evalTreeManagedResource(
|
||||||
Else: &EvalWriteState{
|
Else: &EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,7 +149,9 @@ func (n *NodeDestroyResource) EvalTree() EvalNode {
|
||||||
// Get our state
|
// Get our state
|
||||||
rs := n.ResourceState
|
rs := n.ResourceState
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
rs = &ResourceState{}
|
rs = &ResourceState{
|
||||||
|
Provider: n.ResolvedProvider,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var diffApply *InstanceDiff
|
var diffApply *InstanceDiff
|
||||||
|
|
|
@ -112,7 +112,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -177,7 +177,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateId,
|
Name: stateId,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -251,7 +251,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState(
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: stateID,
|
Name: stateID,
|
||||||
ResourceType: n.Config.Type,
|
ResourceType: n.Config.Type,
|
||||||
Provider: n.Config.Provider,
|
Provider: n.ResolvedProvider,
|
||||||
Dependencies: stateDeps,
|
Dependencies: stateDeps,
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.ProviderName,
|
Provider: n.ResolvedProvider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
@ -157,7 +157,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Provider: n.ProviderName,
|
Provider: n.ResolvedProvider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,7 +52,8 @@ type GraphNodeCloseProvider interface {
|
||||||
|
|
||||||
// GraphNodeProviderConsumer is an interface that nodes that require
|
// GraphNodeProviderConsumer is an interface that nodes that require
|
||||||
// a provider must implement. ProvidedBy must return the name of the provider
|
// 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 {
|
type GraphNodeProviderConsumer interface {
|
||||||
ProvidedBy() string
|
ProvidedBy() string
|
||||||
// Set the resolved provider address for this resource.
|
// Set the resolved provider address for this resource.
|
||||||
|
@ -127,7 +128,6 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
||||||
// in the graph are evaluated.
|
// in the graph are evaluated.
|
||||||
type CloseProviderTransformer struct{}
|
type CloseProviderTransformer struct{}
|
||||||
|
|
||||||
// FIXME: this doesn't close providers if the root provider is disabled
|
|
||||||
func (t *CloseProviderTransformer) Transform(g *Graph) error {
|
func (t *CloseProviderTransformer) Transform(g *Graph) error {
|
||||||
pm := providerVertexMap(g)
|
pm := providerVertexMap(g)
|
||||||
cpm := make(map[string]*graphNodeCloseProvider)
|
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
|
// providerMapKey is a helper that gives us the key to use for the
|
||||||
// maps returned by things such as providerVertexMap.
|
// maps returned by things such as providerVertexMap.
|
||||||
func providerMapKey(k string, v dag.Vertex) string {
|
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
|
// we create a dummy provider to
|
||||||
var path []string
|
var path []string
|
||||||
if sp, ok := v.(GraphNodeSubPath); ok {
|
if sp, ok := v.(GraphNodeSubPath); ok {
|
||||||
|
|
Loading…
Reference in New Issue