From ca5b1ca6500a0f6382b7e3784f298b82f16e8649 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Tue, 6 Jan 2026 10:07:44 -0500 Subject: [PATCH] Rewire closing providers directly instead of in EvalContext Signed-off-by: Christian Mesh --- internal/tofu/eval_context.go | 6 ------ internal/tofu/eval_context_builtin.go | 24 ------------------------ internal/tofu/eval_context_mock.go | 10 ---------- internal/tofu/node_provider.go | 10 ++++++++++ internal/tofu/node_provider_eval.go | 5 +++++ internal/tofu/transform_provider.go | 18 ++++++++++++------ 6 files changed, 27 insertions(+), 46 deletions(-) diff --git a/internal/tofu/eval_context.go b/internal/tofu/eval_context.go index 8af13eb4e7..bd2fd6d019 100644 --- a/internal/tofu/eval_context.go +++ b/internal/tofu/eval_context.go @@ -56,12 +56,6 @@ type EvalContext interface { // resources in one module are able to use providers from other modules. ProviderSchema(context.Context, addrs.AbsProviderConfig) (providers.ProviderSchema, error) - // CloseProvider closes provider connections that aren't needed anymore. - // - // This method will panic if the module instance address of the given - // provider configuration does not match the Path() of the EvalContext. - CloseProvider(context.Context, addrs.AbsProviderConfig) error - // ProviderInput and SetProviderInput are used to configure providers // from user input. // diff --git a/internal/tofu/eval_context_builtin.go b/internal/tofu/eval_context_builtin.go index cfdc08b971..6de9ea9425 100644 --- a/internal/tofu/eval_context_builtin.go +++ b/internal/tofu/eval_context_builtin.go @@ -157,30 +157,6 @@ func (c *BuiltinEvalContext) ProviderSchema(ctx context.Context, addr addrs.AbsP return c.Plugins.ProviderSchema(ctx, addr.Provider) } -func (c *BuiltinEvalContext) CloseProvider(ctx context.Context, addr addrs.AbsProviderConfig) error { - c.ProviderLock.Lock() - defer c.ProviderLock.Unlock() - - var diags tfdiags.Diagnostics - - providerAddrKey := addr.String() - providerMap := c.ProviderCache[providerAddrKey] - if providerMap != nil { - for _, provider := range providerMap { - err := provider.Close(ctx) - if err != nil { - diags = diags.Append(err) - } - } - delete(c.ProviderCache, providerAddrKey) - } - if diags.HasErrors() { - return diags.Err() - } - - return nil -} - func (c *BuiltinEvalContext) ProviderInput(_ context.Context, pc addrs.AbsProviderConfig) map[string]cty.Value { c.ProviderLock.Lock() defer c.ProviderLock.Unlock() diff --git a/internal/tofu/eval_context_mock.go b/internal/tofu/eval_context_mock.go index 7ad5fceb4e..0bd7e598a9 100644 --- a/internal/tofu/eval_context_mock.go +++ b/internal/tofu/eval_context_mock.go @@ -51,10 +51,6 @@ type MockEvalContext struct { ProviderSchemaSchema providers.ProviderSchema ProviderSchemaError error - CloseProviderCalled bool - CloseProviderAddr addrs.AbsProviderConfig - CloseProviderProvider providers.Interface - ProviderInputCalled bool ProviderInputAddr addrs.AbsProviderConfig ProviderInputValues map[string]cty.Value @@ -187,12 +183,6 @@ func (c *MockEvalContext) ProviderSchema(_ context.Context, addr addrs.AbsProvid return c.ProviderSchemaSchema, c.ProviderSchemaError } -func (c *MockEvalContext) CloseProvider(_ context.Context, addr addrs.AbsProviderConfig) error { - c.CloseProviderCalled = true - c.CloseProviderAddr = addr - return nil -} - func (c *MockEvalContext) ProviderInput(_ context.Context, addr addrs.AbsProviderConfig) map[string]cty.Value { c.ProviderInputCalled = true c.ProviderInputAddr = addr diff --git a/internal/tofu/node_provider.go b/internal/tofu/node_provider.go index a7bdfa0b12..46ae5b3710 100644 --- a/internal/tofu/node_provider.go +++ b/internal/tofu/node_provider.go @@ -7,6 +7,7 @@ package tofu import ( "context" + "errors" "fmt" "log" @@ -64,6 +65,15 @@ func (n *NodeApplyableProvider) Instance(key addrs.InstanceKey) providers.Config return n.instances[key] } +// GraphNodeProvider +func (n *NodeApplyableProvider) Close(ctx context.Context) error { + var errs []error + for _, instance := range n.instances { + errs = append(errs, instance.Close(ctx)) + } + return errors.Join(errs...) +} + // GraphNodeExecutable func (n *NodeApplyableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) tfdiags.Diagnostics { instances, diags := n.initInstances(ctx, evalCtx, op) diff --git a/internal/tofu/node_provider_eval.go b/internal/tofu/node_provider_eval.go index 4aa7aa40e4..85131a9a3a 100644 --- a/internal/tofu/node_provider_eval.go +++ b/internal/tofu/node_provider_eval.go @@ -31,6 +31,11 @@ func (n *NodeEvalableProvider) Instance(key addrs.InstanceKey) providers.Configu return n.instance } +// GraphNodeProvider +func (n *NodeEvalableProvider) Close(ctx context.Context) error { + return n.instance.Close(ctx) +} + // GraphNodeExecutable func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { var err error diff --git a/internal/tofu/transform_provider.go b/internal/tofu/transform_provider.go index 102f369252..3aa4f544c4 100644 --- a/internal/tofu/transform_provider.go +++ b/internal/tofu/transform_provider.go @@ -55,6 +55,7 @@ type GraphNodeProvider interface { ProviderAddr() addrs.AbsProviderConfig Name() string Instance(addrs.InstanceKey) providers.Configured + Close(ctx context.Context) error // For test framework MocksAndOverrides() (IsMocked bool, MockResources []*configs.MockResource, OverrideResources []*configs.OverrideResource) } @@ -497,7 +498,7 @@ func (t *CloseProviderTransformer) Transform(_ context.Context, g *Graph) error if closer == nil { // create a closer for this provider type - closer = &graphNodeCloseProvider{Addr: p.ProviderAddr()} + closer = &graphNodeCloseProvider{Provider: p} g.Add(closer) cpm[key] = closer } @@ -638,7 +639,7 @@ func providerVertexMap(g *Graph) map[string]GraphNodeProvider { } type graphNodeCloseProvider struct { - Addr addrs.AbsProviderConfig + Provider GraphNodeProvider } var ( @@ -647,21 +648,21 @@ var ( ) func (n *graphNodeCloseProvider) Name() string { - return n.Addr.String() + " (close)" + return n.Provider.ProviderAddr().String() + " (close)" } // GraphNodeModulePath func (n *graphNodeCloseProvider) ModulePath() addrs.Module { - return n.Addr.Module + return n.Provider.ProviderAddr().Module } // GraphNodeExecutable impl. func (n *graphNodeCloseProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - return diags.Append(evalCtx.CloseProvider(ctx, n.Addr)) + return diags.Append(n.Provider.Close(ctx)) } func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig { - return n.Addr + return n.Provider.ProviderAddr() } // GraphNodeDotter impl. @@ -724,6 +725,11 @@ func (n *graphNodeProxyProvider) Instance(key addrs.InstanceKey) providers.Confi return n.Target().Instance(key) } +func (n *graphNodeProxyProvider) Close(ctx context.Context) error { + // NOP, close handled by the proxied instance + return nil +} + // 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) {