Directly link provider instances via ResovedProvider

This is the first step in removing EvalContext.Provider functions

Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
Christian Mesh
2025-12-19 09:10:52 -05:00
parent 4f99815163
commit 335be600e4
18 changed files with 129 additions and 83 deletions

View File

@@ -20,7 +20,6 @@ import (
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/lang/evalchecks"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@@ -137,22 +136,3 @@ func resolveProviderInstance(ctx context.Context, keyExpr hcl.Expression, keySco
}
return parsedKey, diags
}
// getProvider returns the providers.Interface and schema for a given provider.
func getProvider(ctx context.Context, evalCtx EvalContext, addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey) (providers.Interface, providers.ProviderSchema, error) {
if addr.Provider.Type == "" {
// Should never happen
panic("GetProvider used with uninitialized provider configuration address")
}
provider := evalCtx.Provider(ctx, addr, providerKey)
if provider == nil {
return nil, providers.ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr.InstanceString(providerKey))
}
// Not all callers require a schema, so we will leave checking for a nil
// schema to the callers.
schema, err := evalCtx.ProviderSchema(ctx, addr)
if err != nil {
return nil, providers.ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", addr, err)
}
return provider, schema, nil
}

View File

@@ -304,6 +304,9 @@ func TestPlanGraphBuilder_ephemeralResourceDestroy(t *testing.T) {
evalCtx := &MockEvalContext{
ProviderProvider: testProvider("aws"),
}
found.ResolvedProvider.Instance = func(addrs.InstanceKey) providers.Configured {
return evalCtx.ProviderProvider
}
diags := found.Execute(t.Context(), evalCtx, walkPlanDestroy)
got := diags.Err().Error()
want := `An ephemeral resource planned for destroy: A destroy operation has been planned for the ephemeral resource "ephemeral.aws_secretmanager_secret.test". This is an OpenTofu error. Please report this.`

View File

@@ -49,12 +49,20 @@ const traceAttrProviderInstanceAddr = "opentofu.provider_instance.address"
// NodeApplyableProvider represents a configured provider.
type NodeApplyableProvider struct {
*NodeAbstractProvider
instances map[addrs.InstanceKey]providers.Configured
}
var (
_ GraphNodeExecutable = (*NodeApplyableProvider)(nil)
_ GraphNodeProvider = (*NodeApplyableProvider)(nil)
)
// GraphNodeProvider
func (n *NodeApplyableProvider) Instance(key addrs.InstanceKey) providers.Configured {
return n.instances[key]
}
// GraphNodeExecutable
func (n *NodeApplyableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) tfdiags.Diagnostics {
instances, diags := n.initInstances(ctx, evalCtx, op)
@@ -88,8 +96,13 @@ func (n *NodeApplyableProvider) initInstances(ctx context.Context, evalCtx EvalC
}
}
if n.instances == nil {
n.instances = map[addrs.InstanceKey]providers.Configured{}
}
for _, key := range initKeys {
_, err := evalCtx.InitProvider(ctx, n.Addr, key)
instance, err := evalCtx.InitProvider(ctx, n.Addr, key)
n.instances[key] = instance
diags = diags.Append(err)
}
if diags.HasErrors() {
@@ -98,9 +111,7 @@ func (n *NodeApplyableProvider) initInstances(ctx context.Context, evalCtx EvalC
instances := make(map[addrs.InstanceKey]providers.Interface)
for configKey, initKey := range instanceKeys {
provider, _, err := getProvider(ctx, evalCtx, n.Addr, initKey)
diags = diags.Append(err)
instances[configKey] = provider
instances[configKey] = evalCtx.Provider(ctx, n.Addr, initKey)
}
if diags.HasErrors() {
return nil, diags

View File

@@ -33,7 +33,6 @@ type NodeAbstractProvider struct {
var (
_ GraphNodeModulePath = (*NodeAbstractProvider)(nil)
_ GraphNodeReferencer = (*NodeAbstractProvider)(nil)
_ GraphNodeProvider = (*NodeAbstractProvider)(nil)
_ GraphNodeAttachProvider = (*NodeAbstractProvider)(nil)
_ GraphNodeAttachProviderConfigSchema = (*NodeAbstractProvider)(nil)
_ dag.GraphNodeDotter = (*NodeAbstractProvider)(nil)
@@ -88,6 +87,7 @@ func (n *NodeAbstractProvider) AttachProviderConfigSchema(schema *configschema.B
n.Schema = schema
}
// GraphNodeProvider
func (n *NodeAbstractProvider) MocksAndOverrides() (IsMocked bool, MockResources []*configs.MockResource, OverrideResources []*configs.OverrideResource) {
if n.Config == nil {
return false, nil, nil

View File

@@ -9,6 +9,7 @@ import (
"context"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@@ -18,12 +19,21 @@ import (
// with it.
type NodeEvalableProvider struct {
*NodeAbstractProvider
instance providers.Configured
}
var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)
var _ GraphNodeProvider = (*NodeEvalableProvider)(nil)
// GraphNodeProvider
func (n *NodeEvalableProvider) Instance(key addrs.InstanceKey) providers.Configured {
return n.instance
}
// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
_, err := evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
var err error
n.instance, err = evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
return diags.Append(err)
}

View File

@@ -46,7 +46,7 @@ func TestNodeApplyableProviderExecute(t *testing.T) {
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}
@@ -93,7 +93,7 @@ func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}
@@ -128,7 +128,7 @@ func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) {
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}
@@ -165,7 +165,7 @@ func TestNodeApplyableProviderExecute_sensitive(t *testing.T) {
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}
@@ -202,7 +202,7 @@ func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}
@@ -244,7 +244,7 @@ func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
Provider: addrs.NewDefaultProvider("foo"),
}
n := &NodeApplyableProvider{&NodeAbstractProvider{
n := &NodeApplyableProvider{NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
Config: config,
}}

View File

@@ -282,7 +282,7 @@ func (n *NodeAbstractResourceInstance) resolveProvider(ctx context.Context, eval
panic("EnsureProvider used with uninitialized provider configuration address")
}
provider := evalCtx.Provider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
provider := n.ResolvedProvider.Instance(n.ResolvedProviderKey)
if provider != nil {
// All good
return nil
@@ -3212,9 +3212,13 @@ func resourceInstancePrevRunAddr(evalCtx EvalContext, currentAddr addrs.AbsResou
}
func (n *NodeAbstractResourceInstance) getProvider(ctx context.Context, evalCtx EvalContext) (providers.Interface, providers.ProviderSchema, error) {
underlyingProvider, schema, err := getProvider(ctx, evalCtx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
underlyingProvider := n.ResolvedProvider.Instance(n.ResolvedProviderKey)
// Not all callers require a schema, so we will leave checking for a nil
// schema to the callers.
schema, err := evalCtx.ProviderSchema(ctx, n.ResolvedProvider.ProviderConfig)
if err != nil {
return nil, providers.ProviderSchema{}, err
return nil, providers.ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", n.ResolvedProvider.ProviderConfig, err)
}
var isOverridden bool

View File

@@ -15,6 +15,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@@ -173,7 +174,12 @@ func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) {
Addr: mustResourceInstanceAddr("aws_instance.foo"),
// instanceState: obj,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Instance: func(key addrs.InstanceKey) providers.Configured {
return mockProvider
},
},
},
}
evalCtx.ProviderProvider = mockProvider

View File

@@ -239,7 +239,7 @@ func getReadResourceInstanceStateTests(stateBuilder func(s *states.SyncState)) [
State: states.BuildState(stateBuilder),
Node: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return mockProvider }},
},
// Otherwise prevRunAddr fails, since we have no current Addr in the state
Addr: mustResourceInstanceAddr("aws_instance.bar"),
@@ -259,7 +259,7 @@ func getReadResourceInstanceStateTests(stateBuilder func(s *states.SyncState)) [
State: states.BuildState(stateBuilder),
Node: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return mockProvider }},
},
// Otherwise prevRunAddr fails, since we have no current Addr in the state
Addr: mustResourceInstanceAddr("aws_instance.bar"),
@@ -279,7 +279,7 @@ func getReadResourceInstanceStateTests(stateBuilder func(s *states.SyncState)) [
State: states.BuildState(stateBuilder),
Node: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return mockProviderWithStateChange }},
},
// Otherwise prevRunAddr fails, since we have no current Addr in the state
Addr: mustResourceInstanceAddr("aws_instance.bar"),
@@ -300,7 +300,7 @@ func getReadResourceInstanceStateTests(stateBuilder func(s *states.SyncState)) [
State: states.BuildState(stateBuilder),
Node: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return mockProviderWithMoveUnsupported }},
},
Addr: mustResourceInstanceAddr("aws_instance.bar"),
},

View File

@@ -202,7 +202,10 @@ func TestNodePlanDeposedResourceInstanceObject_Execute(t *testing.T) {
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
},
DeposedKey: deposedKey,
@@ -231,14 +234,17 @@ func TestNodeDestroyDeposedResourceInstanceObject_Execute(t *testing.T) {
deposedKey := states.NewDeposedKey()
state := states.NewState()
absResourceAddr := "test_instance.foo"
evalCtx, _ := initMockEvalContext(t.Context(), absResourceAddr, deposedKey)
evalCtx, p := initMockEvalContext(t.Context(), absResourceAddr, deposedKey)
absResource := mustResourceInstanceAddr(absResourceAddr)
node := NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
},
DeposedKey: deposedKey,
@@ -279,7 +285,10 @@ func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *
node := &NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return mockProvider },
},
},
Addr: mustResourceInstanceAddr("aws_instance.foo"),
},
@@ -311,7 +320,10 @@ func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: mustResourceInstanceAddr("test_object.foo"),
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
},
DeposedKey: states.NewDeposedKey(),
@@ -327,14 +339,17 @@ func TestNodeForgetDeposedResourceInstanceObject_Execute(t *testing.T) {
deposedKey := states.NewDeposedKey()
state := states.NewState()
absResourceAddr := "test_instance.foo"
evalCtx, _ := initMockEvalContext(t.Context(), absResourceAddr, deposedKey)
evalCtx, p := initMockEvalContext(t.Context(), absResourceAddr, deposedKey)
absResource := mustResourceInstanceAddr(absResourceAddr)
node := NodeForgetDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
},
DeposedKey: deposedKey,

View File

@@ -100,11 +100,7 @@ func (n *graphNodeImportState) Execute(ctx context.Context, evalCtx EvalContext,
n.ResolvedProviderKey = asAbsNode.ResolvedProviderKey
log.Printf("[TRACE] graphNodeImportState: importing using %s", n.ResolvedProvider.ProviderConfig.InstanceString(n.ResolvedProviderKey))
provider, _, err := getProvider(ctx, evalCtx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
}
provider := n.ResolvedProvider.Instance(n.ResolvedProviderKey)
// import state
absAddr := n.Addr.Resource.Absolute(evalCtx.Path())

View File

@@ -234,7 +234,9 @@ func TestNodeResourcePlanOrphan_Execute(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
}},
},
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
Addr: absResource,
},
@@ -309,7 +311,9 @@ func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
}},
},
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
Addr: mustResourceInstanceAddr("test_object.foo"),
},
@@ -392,7 +396,9 @@ func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
}},
},
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
Addr: mustResourceInstanceAddr("test_object.foo"),
},

View File

@@ -187,7 +187,8 @@ func (n *NodeValidatableResource) evaluateBlock(ctx context.Context, evalCtx Eva
func (n *NodeValidatableResource) validateResource(ctx context.Context, evalCtx EvalContext) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
provider, providerSchema, err := getProvider(ctx, evalCtx, n.ResolvedProvider.ProviderConfig, addrs.NoKey) // Provider Instance Keys are ignored during validate
provider := n.ResolvedProvider.Instance(addrs.NoKey) // Provider Instance Keys are ignored during validate
providerSchema, err := evalCtx.ProviderSchema(ctx, n.ResolvedProvider.ProviderConfig)
diags = diags.Append(err)
if diags.HasErrors() {
return diags

View File

@@ -190,7 +190,10 @@ func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T)
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{
ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Instance: func(key addrs.InstanceKey) providers.Configured { return p },
},
},
}
@@ -258,7 +261,7 @@ func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testin
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -292,7 +295,7 @@ func TestNodeValidatableResource_ValidateResource_ephemeralResource(t *testing.T
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("ephemeral.test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -382,7 +385,7 @@ func TestNodeValidatableResource_ValidateResource_dataSource(t *testing.T) {
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -418,7 +421,7 @@ func TestNodeValidatableResource_ValidateResource_valid(t *testing.T) {
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_object.foo"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -455,7 +458,7 @@ func TestNodeValidatableResource_ValidateResource_warningsAndErrorsPassedThrough
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -517,7 +520,7 @@ func TestNodeValidatableResource_ValidateResource_invalidDependsOn(t *testing.T)
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -601,7 +604,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesNonexisten
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -684,7 +687,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesComputed(t
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}
@@ -812,7 +815,7 @@ func TestNodeValidatableResource_ValidateResource_suggestion(t *testing.T) {
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr(fmt.Sprintf("%s%s.bar", prefix, tt.rtype)),
Config: rc,
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`), Instance: func(addrs.InstanceKey) providers.Configured { return p }},
},
}

View File

@@ -10,6 +10,7 @@ import (
"fmt"
"log"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/dag"
@@ -27,7 +28,7 @@ type GraphNodeAttachResourceSchema interface {
// GraphNodeAttachProviderConfigSchema is an interface implemented by node types
// that need a provider configuration schema attached.
type GraphNodeAttachProviderConfigSchema interface {
GraphNodeProvider
ProviderAddr() addrs.AbsProviderConfig
AttachProviderConfigSchema(*configschema.Block)
}

View File

@@ -49,7 +49,7 @@ func TestGraphNodeImportStateExecute(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
}},
}, Instance: func(addrs.InstanceKey) providers.Configured { return provider }},
}
diags := node.Execute(t.Context(), evalCtx, walkImport)
@@ -105,7 +105,7 @@ func TestGraphNodeImportStateSubExecute(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
}},
}, Instance: func(addrs.InstanceKey) providers.Configured { return provider }},
}
diags := node.Execute(t.Context(), evalCtx, walkImport)
if diags.HasErrors() {
@@ -167,7 +167,7 @@ func TestGraphNodeImportStateSubExecuteNull(t *testing.T) {
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
}},
}, Instance: func(addrs.InstanceKey) providers.Configured { return provider }},
}
diags := node.Execute(t.Context(), evalCtx, walkImport)
if !diags.HasErrors() {

View File

@@ -14,6 +14,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/dag"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@@ -53,6 +54,7 @@ type GraphNodeProvider interface {
GraphNodeModulePath
ProviderAddr() addrs.AbsProviderConfig
Name() string
Instance(addrs.InstanceKey) providers.Configured
// For test framework
MocksAndOverrides() (IsMocked bool, MockResources []*configs.MockResource, OverrideResources []*configs.OverrideResource)
}
@@ -80,6 +82,8 @@ type ResolvedProvider struct {
KeyResource bool
KeyExact addrs.InstanceKey
Instance func(addrs.InstanceKey) providers.Configured
// Test overrides
IsMocked bool
MockResources []*configs.MockResource
@@ -179,6 +183,7 @@ func (t *ProviderTransformer) Transform(_ context.Context, g *Graph) error {
resolved := ResolvedProvider{
ProviderConfig: target.ProviderAddr(),
Instance: target.Instance,
// Pass through key data
KeyExpression: req.KeyExpression,
KeyModule: req.KeyModule,
@@ -254,6 +259,7 @@ func (t *ProviderTransformer) Transform(_ context.Context, g *Graph) error {
}
}
resolved.ProviderConfig = target.ProviderAddr()
resolved.Instance = target.Instance
// Include test mocking and override extensions
resolved.IsMocked, resolved.MockResources, resolved.OverrideResources = target.MocksAndOverrides()
@@ -324,7 +330,7 @@ func (t *ProviderUnconfiguredTransformer) Transform(_ context.Context, g *Graph)
pAddr := applyableProvider.ProviderAddr()
log.Printf("[TRACE] ProviderFunctionTransformer: replacing NodeApplyableProvider with NodeEvalableProvider for %s since it's missing configuration and there are no consumers of it", pAddr)
unconfiguredProvider := &NodeEvalableProvider{
&NodeAbstractProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: pAddr,
},
}
@@ -433,7 +439,7 @@ func (t *ProviderFunctionTransformer) Transform(_ context.Context, g *Graph) err
log.Printf("[TRACE] ProviderFunctionTransformer: creating init-only node for %s", stubAddr)
provider = &NodeEvalableProvider{
&NodeAbstractProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: stubAddr,
},
}
@@ -542,7 +548,7 @@ func (t *MissingProviderTransformer) Transform(_ context.Context, g *Graph) erro
// Initialize factory
if t.Concrete == nil {
t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
return a
return &NodeEvalableProvider{NodeAbstractProvider: a}
}
}
@@ -711,6 +717,10 @@ func (n *graphNodeProxyProvider) MocksAndOverrides() (IsMocked bool, MockResourc
return n.Target().MocksAndOverrides()
}
func (n *graphNodeProxyProvider) Instance(key addrs.InstanceKey) providers.Configured {
return n.Target().Instance(key)
}
// Find the *single* keyExpression that is used in the provider
// chain. This is not ideal, but it works with current constraints on this feature
func (n *graphNodeProxyProvider) TargetExpr() (hcl.Expression, addrs.Module) {
@@ -868,7 +878,7 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config)
if t.Concrete != nil {
v = t.Concrete(abstract)
} else {
v = abstract
v = &NodeEvalableProvider{NodeAbstractProvider: abstract}
}
// Add it to the graph

View File

@@ -239,7 +239,7 @@ func TestMissingProviderTransformer(t *testing.T) {
func TestMissingProviderTransformer_grandchildMissing(t *testing.T) {
mod := testModule(t, "transform-provider-missing-grandchild")
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
{
@@ -304,7 +304,7 @@ func TestPruneProviderTransformer(t *testing.T) {
// the child module resource is attached to the configured parent provider
func TestProviderConfigTransformer_parentProviders(t *testing.T) {
mod := testModule(t, "transform-provider-inherit")
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
{
@@ -324,7 +324,7 @@ func TestProviderConfigTransformer_parentProviders(t *testing.T) {
// the child module resource is attached to the configured grand-parent provider
func TestProviderConfigTransformer_grandparentProviders(t *testing.T) {
mod := testModule(t, "transform-provider-grandchild-inherit")
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
{
@@ -358,7 +358,7 @@ resource "test_object" "a" {
}
`,
})
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
{
@@ -436,7 +436,7 @@ resource "test_object" "a" {
}
`,
})
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
{
@@ -478,7 +478,7 @@ terraform {
provider "test" {
}
`})
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
concrete := func(a *NodeAbstractProvider) dag.Vertex { return &NodeEvalableProvider{NodeAbstractProvider: a} }
g := testProviderTransformerGraph(t, mod)
tf := ProviderConfigTransformer{
@@ -517,7 +517,7 @@ output "output_test" {
`})
concrete := func(a *NodeAbstractProvider) dag.Vertex {
return &NodeApplyableProvider{
a,
NodeAbstractProvider: a,
}
}