tofu: EvalContext provider methods take context.Context

Continuing the ongoing work of getting context.Context wired in everywhere
we might want to generate OpenTelemetry traces, this completes all of the
provider-related methods of EvalContext.

Unfortunately there is still one remaining path not included here: the
EvalContext.EvaluationScope method needs to somehow arrange for contexts
to reach the provider-defined functions so that we can pass the context
to providers.Interface.CallFunction, which is tricky because that has to
get through the cty function API that wasn't designed for functions that
are backed by network calls. We'll deal with that in a subsequent commit
because it's likely to be a more invasive change than the
relatively-mechanical wiring updates included here.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
Martin Atkins
2025-06-16 14:30:54 -07:00
parent 59659c8009
commit 9d93b939f5
19 changed files with 55 additions and 55 deletions

View File

@@ -314,7 +314,7 @@ func TestContext_contextValuesPropagation(t *testing.T) {
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ValidateProviderConfig",
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ValidateDataResourceConfig",
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ValidateResourceConfig",
//"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).Configure", // FIXME: Not working yet
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ConfigureProvider",
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ReadDataSource",
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).PlanResourceChange",
"github.com/opentofu/opentofu/internal/tofu.(*MockProvider).ApplyResourceChange",

View File

@@ -47,7 +47,7 @@ type EvalContext interface {
// It is an error to initialize the same provider more than once. This
// method will panic if the module instance address of the given provider
// configuration does not match the Path() of the EvalContext.
InitProvider(addr addrs.AbsProviderConfig, key addrs.InstanceKey) (providers.Interface, error)
InitProvider(ctx context.Context, addr addrs.AbsProviderConfig, key addrs.InstanceKey) (providers.Interface, error)
// Provider gets the provider instance with the given address (already
// initialized) or returns nil if the provider isn't initialized.
@@ -56,7 +56,7 @@ type EvalContext interface {
// resources in one module are able to use providers from other modules.
// InitProvider must've been called on the EvalContext of the module
// that owns the given provider before calling this method.
Provider(addrs.AbsProviderConfig, addrs.InstanceKey) providers.Interface
Provider(context.Context, addrs.AbsProviderConfig, addrs.InstanceKey) providers.Interface
// ProviderSchema retrieves the schema for a particular provider, which
// must have already been initialized with InitProvider.
@@ -69,7 +69,7 @@ type EvalContext interface {
//
// This method will panic if the module instance address of the given
// provider configuration does not match the Path() of the EvalContext.
CloseProvider(addrs.AbsProviderConfig) error
CloseProvider(context.Context, addrs.AbsProviderConfig) error
// ConfigureProvider configures the provider with the given
// configuration. This is a separate context call because this call
@@ -78,15 +78,15 @@ type EvalContext interface {
//
// This method will panic if the module instance address of the given
// provider configuration does not match the Path() of the EvalContext.
ConfigureProvider(addrs.AbsProviderConfig, addrs.InstanceKey, cty.Value) tfdiags.Diagnostics
ConfigureProvider(context.Context, addrs.AbsProviderConfig, addrs.InstanceKey, cty.Value) tfdiags.Diagnostics
// ProviderInput and SetProviderInput are used to configure providers
// from user input.
//
// These methods will panic if the module instance address of the given
// provider configuration does not match the Path() of the EvalContext.
ProviderInput(addrs.AbsProviderConfig) map[string]cty.Value
SetProviderInput(addrs.AbsProviderConfig, map[string]cty.Value)
ProviderInput(context.Context, addrs.AbsProviderConfig) map[string]cty.Value
SetProviderInput(context.Context, addrs.AbsProviderConfig, map[string]cty.Value)
// Provisioner gets the provisioner instance with the given name.
Provisioner(string) (provisioners.Interface, error)

View File

@@ -128,7 +128,7 @@ func (c *BuiltinEvalContext) Input() UIInput {
return c.InputValue
}
func (c *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig, providerInstanceKey addrs.InstanceKey) (providers.Interface, error) {
func (c *BuiltinEvalContext) InitProvider(ctx context.Context, addr addrs.AbsProviderConfig, providerInstanceKey addrs.InstanceKey) (providers.Interface, error) {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
@@ -153,7 +153,7 @@ func (c *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig, provider
// We cannot wrap providers.Factory itself, because factories don't support aliases.
pc, ok := c.Evaluator.Config.Module.GetProviderConfig(addr.Provider.Type, addr.Alias)
if ok && pc.IsMocked {
testP, err := newProviderForTestWithSchema(p, p.GetProviderSchema(context.TODO()))
testP, err := newProviderForTestWithSchema(p, p.GetProviderSchema(ctx))
if err != nil {
return nil, err
}
@@ -170,7 +170,7 @@ func (c *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig, provider
return p, nil
}
func (c *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig, key addrs.InstanceKey) providers.Interface {
func (c *BuiltinEvalContext) Provider(_ context.Context, addr addrs.AbsProviderConfig, key addrs.InstanceKey) providers.Interface {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
@@ -188,7 +188,7 @@ func (c *BuiltinEvalContext) ProviderSchema(ctx context.Context, addr addrs.AbsP
return c.Plugins.ProviderSchema(ctx, addr.Provider)
}
func (c *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
func (c *BuiltinEvalContext) CloseProvider(ctx context.Context, addr addrs.AbsProviderConfig) error {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
@@ -198,7 +198,7 @@ func (c *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
providerMap := c.ProviderCache[providerAddrKey]
if providerMap != nil {
for _, provider := range providerMap {
err := provider.Close(context.TODO())
err := provider.Close(ctx)
if err != nil {
diags = diags.Append(err)
}
@@ -212,7 +212,7 @@ func (c *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
return nil
}
func (c *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
func (c *BuiltinEvalContext) ConfigureProvider(ctx context.Context, addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if !c.Path().IsForModule(addr.Module) {
// This indicates incorrect use of ConfigureProvider: it should be used
@@ -220,7 +220,7 @@ func (c *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, pro
panic(fmt.Sprintf("%s configured by wrong module %s", addr, c.Path()))
}
p := c.Provider(addr, providerKey)
p := c.Provider(ctx, addr, providerKey)
if p == nil {
diags = diags.Append(fmt.Errorf("%s not initialized", addr.InstanceString(providerKey)))
return diags
@@ -231,11 +231,11 @@ func (c *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, pro
Config: cfg,
}
resp := p.ConfigureProvider(context.TODO(), req)
resp := p.ConfigureProvider(ctx, req)
return resp.Diagnostics
}
func (c *BuiltinEvalContext) ProviderInput(pc addrs.AbsProviderConfig) map[string]cty.Value {
func (c *BuiltinEvalContext) ProviderInput(_ context.Context, pc addrs.AbsProviderConfig) map[string]cty.Value {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
@@ -253,7 +253,7 @@ func (c *BuiltinEvalContext) ProviderInput(pc addrs.AbsProviderConfig) map[strin
return c.ProviderInputConfig[pc.String()]
}
func (c *BuiltinEvalContext) SetProviderInput(pc addrs.AbsProviderConfig, vals map[string]cty.Value) {
func (c *BuiltinEvalContext) SetProviderInput(_ context.Context, pc addrs.AbsProviderConfig, vals map[string]cty.Value) {
absProvider := pc
if !pc.Module.IsRoot() {
// Only root module provider configurations can have input.
@@ -483,7 +483,7 @@ func (c *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, source ad
}
}
provider := c.Provider(providedBy.Provider, providerKey)
provider := c.Provider(context.TODO(), providedBy.Provider, providerKey)
if provider == nil {
// This should not be possible if references are tracked correctly

View File

@@ -39,13 +39,13 @@ func TestBuiltinEvalContextProviderInput(t *testing.T) {
}
expected1 := map[string]cty.Value{"value": cty.StringVal("foo")}
ctx1.SetProviderInput(providerAddr1, expected1)
ctx1.SetProviderInput(t.Context(), providerAddr1, expected1)
try2 := map[string]cty.Value{"value": cty.StringVal("bar")}
ctx2.SetProviderInput(providerAddr2, try2) // ignored because not a root module
ctx2.SetProviderInput(t.Context(), providerAddr2, try2) // ignored because not a root module
actual1 := ctx1.ProviderInput(providerAddr1)
actual2 := ctx2.ProviderInput(providerAddr2)
actual1 := ctx1.ProviderInput(t.Context(), providerAddr1)
actual2 := ctx2.ProviderInput(t.Context(), providerAddr2)
if !reflect.DeepEqual(actual1, expected1) {
t.Errorf("wrong result 1\ngot: %#v\nwant: %#v", actual1, expected1)
@@ -78,11 +78,11 @@ func TestBuildingEvalContextInitProvider(t *testing.T) {
Alias: "foo",
}
_, err := ctx.InitProvider(providerAddrDefault, addrs.NoKey)
_, err := ctx.InitProvider(t.Context(), providerAddrDefault, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test: %s", err)
}
_, err = ctx.InitProvider(providerAddrAlias, addrs.NoKey)
_, err = ctx.InitProvider(t.Context(), providerAddrAlias, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test.foo: %s", err)
}

View File

@@ -186,14 +186,14 @@ func (c *MockEvalContext) Input() UIInput {
return c.InputInput
}
func (c *MockEvalContext) InitProvider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey) (providers.Interface, error) {
func (c *MockEvalContext) InitProvider(_ context.Context, addr addrs.AbsProviderConfig, _ addrs.InstanceKey) (providers.Interface, error) {
c.InitProviderCalled = true
c.InitProviderType = addr.String()
c.InitProviderAddr = addr
return c.InitProviderProvider, c.InitProviderError
}
func (c *MockEvalContext) Provider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey) providers.Interface {
func (c *MockEvalContext) Provider(_ context.Context, addr addrs.AbsProviderConfig, _ addrs.InstanceKey) providers.Interface {
c.ProviderCalled = true
c.ProviderAddr = addr
return c.ProviderProvider
@@ -205,13 +205,13 @@ func (c *MockEvalContext) ProviderSchema(_ context.Context, addr addrs.AbsProvid
return c.ProviderSchemaSchema, c.ProviderSchemaError
}
func (c *MockEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
func (c *MockEvalContext) CloseProvider(_ context.Context, addr addrs.AbsProviderConfig) error {
c.CloseProviderCalled = true
c.CloseProviderAddr = addr
return nil
}
func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
func (c *MockEvalContext) ConfigureProvider(_ context.Context, addr addrs.AbsProviderConfig, _ addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
c.ConfigureProviderCalled = true
c.ConfigureProviderAddr = addr
c.ConfigureProviderConfig = cfg
@@ -221,13 +221,13 @@ func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, _ addr
return c.ConfigureProviderDiags
}
func (c *MockEvalContext) ProviderInput(addr addrs.AbsProviderConfig) map[string]cty.Value {
func (c *MockEvalContext) ProviderInput(_ context.Context, addr addrs.AbsProviderConfig) map[string]cty.Value {
c.ProviderInputCalled = true
c.ProviderInputAddr = addr
return c.ProviderInputValues
}
func (c *MockEvalContext) SetProviderInput(addr addrs.AbsProviderConfig, vals map[string]cty.Value) {
func (c *MockEvalContext) SetProviderInput(_ context.Context, addr addrs.AbsProviderConfig, vals map[string]cty.Value) {
c.SetProviderInputCalled = true
c.SetProviderInputAddr = addr
c.SetProviderInputValues = vals

View File

@@ -24,14 +24,14 @@ import (
"github.com/opentofu/opentofu/internal/tfdiags"
)
func buildProviderConfig(ctx EvalContext, addr addrs.AbsProviderConfig, config *configs.Provider) hcl.Body {
func buildProviderConfig(ctx context.Context, evalCtx EvalContext, addr addrs.AbsProviderConfig, config *configs.Provider) hcl.Body {
var configBody hcl.Body
if config != nil {
configBody = config.Config
}
var inputBody hcl.Body
inputConfig := ctx.ProviderInput(addr)
inputConfig := evalCtx.ProviderInput(ctx, addr)
if len(inputConfig) > 0 {
inputBody = configs.SynthBody("<input-prompt>", inputConfig)
}
@@ -135,7 +135,7 @@ func getProvider(ctx context.Context, evalCtx EvalContext, addr addrs.AbsProvide
// Should never happen
panic("GetProvider used with uninitialized provider configuration address")
}
provider := evalCtx.Provider(addr, providerKey)
provider := evalCtx.Provider(ctx, addr, providerKey)
if provider == nil {
return nil, providers.ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr.InstanceString(providerKey))
}

View File

@@ -28,7 +28,7 @@ func TestBuildProviderConfig(t *testing.T) {
Provider: addrs.NewDefaultProvider("foo"),
}
ctx := &MockEvalContext{
evalCtx := &MockEvalContext{
// The input values map is expected to contain only keys that aren't
// already present in the config, since we skip prompting for
// attributes that are already set.
@@ -36,7 +36,7 @@ func TestBuildProviderConfig(t *testing.T) {
"set_by_input": cty.StringVal("input"),
},
}
gotBody := buildProviderConfig(ctx, providerAddr, &configs.Provider{
gotBody := buildProviderConfig(t.Context(), evalCtx, providerAddr, &configs.Provider{
Name: "foo",
Config: configBody,
})

View File

@@ -90,7 +90,7 @@ func (n *NodeApplyableProvider) initInstances(ctx context.Context, evalCtx EvalC
}
for _, key := range initKeys {
_, err := evalCtx.InitProvider(n.Addr, key)
_, err := evalCtx.InitProvider(ctx, n.Addr, key)
diags = diags.Append(err)
}
if diags.HasErrors() {
@@ -135,7 +135,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx Ev
)
defer span.End()
configBody := buildProviderConfig(evalCtx, n.Addr, n.ProviderConfig())
configBody := buildProviderConfig(ctx, evalCtx, n.Addr, n.ProviderConfig())
// if a provider config is empty (only an alias), return early and don't continue
// validation. validate doesn't need to fully configure the provider itself, so
@@ -203,7 +203,7 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx E
config := n.ProviderConfig()
configBody := buildProviderConfig(evalCtx, n.Addr, config)
configBody := buildProviderConfig(ctx, evalCtx, n.Addr, config)
resp := provider.GetProviderSchema(ctx)
diags := resp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
@@ -273,7 +273,7 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx E
log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr)
}
configDiags := evalCtx.ConfigureProvider(n.Addr, providerKey, unmarkedConfigVal)
configDiags := evalCtx.ConfigureProvider(ctx, n.Addr, providerKey, unmarkedConfigVal)
diags = diags.Append(configDiags.InConfigBody(configBody, n.Addr.InstanceString(providerKey)))
if diags.HasErrors() && config == nil {
// If there isn't an explicit "provider" block in the configuration,

View File

@@ -23,7 +23,7 @@ type NodeEvalableProvider struct {
var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)
// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(_ context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
_, err := evalCtx.InitProvider(n.Addr, addrs.NoKey)
func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
_, err := evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
return diags.Append(err)
}

View File

@@ -139,7 +139,7 @@ func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
return nil
}
func (n *NodeAbstractResourceInstance) resolveProvider(evalCtx EvalContext, hasExpansionData bool, deposedKey states.DeposedKey) tfdiags.Diagnostics {
func (n *NodeAbstractResourceInstance) resolveProvider(ctx context.Context, evalCtx EvalContext, hasExpansionData bool, deposedKey states.DeposedKey) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
log.Printf("[TRACE] Resolving provider key for %s", n.Addr)
@@ -230,7 +230,7 @@ func (n *NodeAbstractResourceInstance) resolveProvider(evalCtx EvalContext, hasE
panic("EnsureProvider used with uninitialized provider configuration address")
}
provider := evalCtx.Provider(n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
provider := evalCtx.Provider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if provider != nil {
// All good
return nil

View File

@@ -155,7 +155,7 @@ func (n *NodeApplyableResourceInstance) Execute(ctx context.Context, evalCtx Eva
return diags
}
diags = n.resolveProvider(evalCtx, true, states.NotDeposed)
diags = n.resolveProvider(ctx, evalCtx, true, states.NotDeposed)
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags

View File

@@ -103,7 +103,7 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx context.Context, eva
)
defer span.End()
diags = n.resolveProvider(evalCtx, false, n.DeposedKey)
diags = n.resolveProvider(ctx, evalCtx, false, n.DeposedKey)
if diags.HasErrors() {
return diags
}
@@ -287,7 +287,7 @@ func (n *NodeDestroyDeposedResourceInstanceObject) ModifyCreateBeforeDestroy(v b
func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
var change *plans.ResourceInstanceChange
diags = n.resolveProvider(evalCtx, false, n.DeposedKey)
diags = n.resolveProvider(ctx, evalCtx, false, n.DeposedKey)
if diags.HasErrors() {
return diags
}
@@ -439,7 +439,7 @@ func (n *NodeForgetDeposedResourceInstanceObject) References() []*addrs.Referenc
// GraphNodeExecutable impl.
func (n *NodeForgetDeposedResourceInstanceObject) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
diags = n.resolveProvider(evalCtx, false, n.DeposedKey)
diags = n.resolveProvider(ctx, evalCtx, false, n.DeposedKey)
if diags.HasErrors() {
return diags
}

View File

@@ -155,7 +155,7 @@ func (n *NodeDestroyResourceInstance) Execute(ctx context.Context, evalCtx EvalC
// Eval info is different depending on what kind of resource this is
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
diags = n.resolveProvider(evalCtx, false, states.NotDeposed)
diags = n.resolveProvider(ctx, evalCtx, false, states.NotDeposed)
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags

View File

@@ -54,7 +54,7 @@ func (n *NodeForgetResourceInstance) Execute(ctx context.Context, evalCtx EvalCo
log.Printf("[WARN] NodeForgetResourceInstance for %s with no state", addr)
}
diags = n.resolveProvider(evalCtx, false, states.NotDeposed)
diags = n.resolveProvider(ctx, evalCtx, false, states.NotDeposed)
if diags.HasErrors() {
return diags
}

View File

@@ -93,7 +93,7 @@ func (n *graphNodeImportState) Execute(ctx context.Context, evalCtx EvalContext,
ResolvedProvider: n.ResolvedProvider,
},
}
diags = diags.Append(asAbsNode.resolveProvider(evalCtx, true, states.NotDeposed))
diags = diags.Append(asAbsNode.resolveProvider(ctx, evalCtx, true, states.NotDeposed))
if diags.HasErrors() {
return diags
}

View File

@@ -61,7 +61,7 @@ func (n *NodePlanDestroyableResourceInstance) Execute(ctx context.Context, evalC
)
defer span.End()
diags = diags.Append(n.resolveProvider(evalCtx, false, states.NotDeposed))
diags = diags.Append(n.resolveProvider(ctx, evalCtx, false, states.NotDeposed))
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags

View File

@@ -100,7 +100,7 @@ func (n *NodePlannableResourceInstance) Execute(ctx context.Context, evalCtx Eva
)
defer span.End()
diags := n.resolveProvider(evalCtx, true, states.NotDeposed)
diags := n.resolveProvider(ctx, evalCtx, true, states.NotDeposed)
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags

View File

@@ -75,7 +75,7 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx context.Context, evalC
var diags tfdiags.Diagnostics
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
resolveDiags := n.resolveProvider(evalCtx, true, states.NotDeposed)
resolveDiags := n.resolveProvider(ctx, evalCtx, true, states.NotDeposed)
diags = diags.Append(resolveDiags)
if resolveDiags.HasErrors() {
tracing.SetSpanError(span, diags)

View File

@@ -595,8 +595,8 @@ func (n *graphNodeCloseProvider) ModulePath() addrs.Module {
}
// GraphNodeExecutable impl.
func (n *graphNodeCloseProvider) Execute(_ context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
return diags.Append(evalCtx.CloseProvider(n.Addr))
func (n *graphNodeCloseProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
return diags.Append(evalCtx.CloseProvider(ctx, n.Addr))
}
func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig {