Merge pull request #32260 from hashicorp/jbardin/resolved-provided-by

ProvidedBy should return the resolved provider
This commit is contained in:
James Bardin 2022-11-22 09:53:41 -05:00 committed by GitHub
commit 2b14670dfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 43 deletions

View File

@ -68,6 +68,10 @@ type NodeAbstractResource struct {
// The address of the provider this resource will use // The address of the provider this resource will use
ResolvedProvider addrs.AbsProviderConfig ResolvedProvider addrs.AbsProviderConfig
// storedProviderConfig is the provider address retrieved from the
// state. This is defined here for access within the ProvidedBy method, but
// will be set from the embedding instance type when the state is attached.
storedProviderConfig addrs.AbsProviderConfig
// This resource may expand into instances which need to be imported. // This resource may expand into instances which need to be imported.
importTargets []*ImportTarget importTargets []*ImportTarget
@ -231,6 +235,11 @@ func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) {
// GraphNodeProviderConsumer // GraphNodeProviderConsumer
func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) { func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
// Once the provider is fully resolved, we can return the known value.
if n.ResolvedProvider.Provider.Type != "" {
return n.ResolvedProvider, true
}
// If we have a config we prefer that above all else // If we have a config we prefer that above all else
if n.Config != nil { if n.Config != nil {
relAddr := n.Config.ProviderConfigAddr() relAddr := n.Config.ProviderConfigAddr()
@ -240,6 +249,14 @@ func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
}, false }, false
} }
// See if we have a valid provider config from the state.
if n.storedProviderConfig.Provider.Type != "" {
// An address from the state must match exactly, since we must ensure
// we refresh/destroy a resource with the same provider configuration
// that created it.
return n.storedProviderConfig, true
}
// No provider configuration found; return a default address // No provider configuration found; return a default address
return addrs.AbsProviderConfig{ return addrs.AbsProviderConfig{
Provider: n.Provider(), Provider: n.Provider(),
@ -252,6 +269,9 @@ func (n *NodeAbstractResource) Provider() addrs.Provider {
if n.Config != nil { if n.Config != nil {
return n.Config.Provider return n.Config.Provider
} }
if n.storedProviderConfig.Provider.Type != "" {
return n.storedProviderConfig.Provider
}
return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ImpliedProvider()) return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ImpliedProvider())
} }

View File

@ -31,10 +31,6 @@ type NodeAbstractResourceInstance struct {
// These are set via the AttachState method. // These are set via the AttachState method.
instanceState *states.ResourceInstance instanceState *states.ResourceInstance
// storedProviderConfig is the provider address retrieved from the
// state, but since it is only stored in the whole Resource rather than the
// ResourceInstance, we extract it out here.
storedProviderConfig addrs.AbsProviderConfig
Dependencies []addrs.ConfigResource Dependencies []addrs.ConfigResource
@ -109,43 +105,6 @@ func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResourc
return nil return nil
} }
// GraphNodeProviderConsumer
func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.ProviderConfig, bool) {
// If we have a config we prefer that above all else
if n.Config != nil {
relAddr := n.Config.ProviderConfigAddr()
return addrs.LocalProviderConfig{
LocalName: relAddr.LocalName,
Alias: relAddr.Alias,
}, false
}
// See if we have a valid provider config from the state.
if n.storedProviderConfig.Provider.Type != "" {
// An address from the state must match exactly, since we must ensure
// we refresh/destroy a resource with the same provider configuration
// that created it.
return n.storedProviderConfig, true
}
// No provider configuration found; return a default address
return addrs.AbsProviderConfig{
Provider: n.Provider(),
Module: n.ModulePath(),
}, false
}
// GraphNodeProviderConsumer
func (n *NodeAbstractResourceInstance) Provider() addrs.Provider {
if n.Config != nil {
return n.Config.Provider
}
if n.storedProviderConfig.Provider.Type != "" {
return n.storedProviderConfig.Provider
}
return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ContainingResource().ImpliedProvider())
}
// GraphNodeResourceInstance // GraphNodeResourceInstance
func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance { func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance {
return n.Addr return n.Addr

View File

@ -125,9 +125,10 @@ func TestNodeAbstractResourceInstanceProvider(t *testing.T) {
// function. (This would not be valid for some other functions.) // function. (This would not be valid for some other functions.)
Addr: test.Addr, Addr: test.Addr,
NodeAbstractResource: NodeAbstractResource{ NodeAbstractResource: NodeAbstractResource{
Config: test.Config, Addr: test.Addr.ConfigResource(),
Config: test.Config,
storedProviderConfig: test.StoredProviderConfig,
}, },
storedProviderConfig: test.StoredProviderConfig,
} }
got := node.Provider() got := node.Provider()
if got != test.Want { if got != test.Want {

View File

@ -112,6 +112,73 @@ func TestNodeAbstractResourceProvider(t *testing.T) {
} }
} }
// Make sure ProvideBy returns the final resolved provider
func TestNodeAbstractResourceSetProvider(t *testing.T) {
node := &NodeAbstractResource{
// Just enough NodeAbstractResource for the Provider function.
// (This would not be valid for some other functions.)
Addr: addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "terraform_remote_state",
Name: "baz",
}.InModule(addrs.RootModule),
Config: &configs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "terraform_remote_state",
Name: "baz",
// Just enough configs.Resource for the Provider method. Not
// actually valid for general use.
Provider: addrs.Provider{
Hostname: addrs.DefaultProviderRegistryHost,
Namespace: "awesomecorp",
Type: "happycloud",
},
},
}
p, exact := node.ProvidedBy()
if exact {
t.Fatalf("no exact provider should be found from this confniguration, got %q\n", p)
}
// the implied non-exact provider should be "terraform"
lpc, ok := p.(addrs.LocalProviderConfig)
if !ok {
t.Fatalf("expected LocalProviderConfig, got %#v\n", p)
}
if lpc.LocalName != "terraform" {
t.Fatalf("expected non-exact provider of 'terraform', got %q", lpc.LocalName)
}
// now set a resolved provider for the resource
resolved := addrs.AbsProviderConfig{
Provider: addrs.Provider{
Hostname: addrs.DefaultProviderRegistryHost,
Namespace: "awesomecorp",
Type: "happycloud",
},
Module: addrs.RootModule,
Alias: "test",
}
node.SetProvider(resolved)
p, exact = node.ProvidedBy()
if !exact {
t.Fatalf("exact provider should be found, got %q\n", p)
}
apc, ok := p.(addrs.AbsProviderConfig)
if !ok {
t.Fatalf("expected AbsProviderConfig, got %#v\n", p)
}
if apc.String() != resolved.String() {
t.Fatalf("incorrect resolved config: got %#v, wanted %#v\n", apc, resolved)
}
}
func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) { func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{