mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-02-15 13:00:32 -05:00
The previous commit split the handling of provider instance items into separate dependency-analysis and execgraph construction steps, with the intention of avoiding the need for the execGraphBuilder to directly interact with the planning oracle and thus indirectly with the evaluator. Overall the hope is that execGraphBuilder will be a self-contained object that doesn't depend on anything else in the planning engine so that it's easier to write unit tests for it that don't require creating an entire fake planning context. However, on reflection that change introduced a completely unnecessary extra handoff from the execGraphBuilder to _another part of itself_, which is obviously unnecessary complexity because it doesn't serve to separate any concerns. This is therefore a further simplification that returns to just doing the entire handling of a provider instance's presence in the execution graph only once we've decided that at least one resource instance will definitely use the provider instance during the apply phase. There is still a separation of concerns where the planGlue type is responsible for calculating the provider dependencies and then the execGraphBuilder is only responsible for adding items to the execution graph based on that information. That separation makes sense because planGlue's job is to bridge between the planning engine and the evaluator, and it's the evaluator's job to calculate the dependencies for a provider instance, whereas execGraphBuilder is the component responsible for deciding exactly which low-level execgraph operations we'll use to describe the situation to the apply engine. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
58 lines
2.6 KiB
Go
58 lines
2.6 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package planning
|
|
|
|
import (
|
|
"github.com/opentofu/opentofu/internal/engine/internal/exec"
|
|
"github.com/opentofu/opentofu/internal/engine/internal/execgraph"
|
|
"github.com/opentofu/opentofu/internal/lang/eval"
|
|
)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This file contains methods of [execGraphBuilder] that are related to the
|
|
// parts of an execution graph that deal with provider instances.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ProviderInstanceSubgraph generates the execution graph operations needed to
|
|
// obtain a configured client for a provider instance and ensure that the client
|
|
// stays open long enough to handle one or more other operations registered
|
|
// afterwards.
|
|
//
|
|
// This should be called ONLY by [planGlue.ensureProviderInstanceExecgraph],
|
|
// which therefore ensures that all calls will consistently pass the same config
|
|
// for each distinct provider instance address.
|
|
//
|
|
// Each distinct provider instance address gets only one set of operations
|
|
// added, so future calls with the same provider instance recieve references to
|
|
// the same operations. This means that the resource instance planning code must
|
|
// call this only once it's definitely intending to add side-effects to the
|
|
// execution graph then the resulting graph will refer to only the subset of
|
|
// provider instances needed to perform planned changes.
|
|
func (b *execGraphBuilder) ProviderInstanceSubgraph(config *eval.ProviderInstanceConfig) (execgraph.ResultRef[*exec.ProviderClient], registerExecCloseBlockerFunc) {
|
|
// We only register one index for each distinct provider instance address.
|
|
if existing, ok := b.openProviderRefs.GetOk(config.Addr); ok {
|
|
return existing.Result, existing.CloseBlockerFunc
|
|
}
|
|
|
|
resourceInstDeps := config.RequiredResourceInstances
|
|
dependencyWaiter, closeDependencyAfter := b.waiterForResourceInstances(resourceInstDeps.All())
|
|
|
|
addrResult := b.lower.ConstantProviderInstAddr(config.Addr)
|
|
configResult := b.lower.ProviderInstanceConfig(addrResult, dependencyWaiter)
|
|
openResult := b.lower.ProviderInstanceOpen(configResult)
|
|
closeWait, registerCloseBlocker := b.makeCloseBlocker()
|
|
|
|
closeRef := b.lower.ProviderInstanceClose(openResult, closeWait)
|
|
closeDependencyAfter(closeRef)
|
|
|
|
b.openProviderRefs.Put(config.Addr, execResultWithCloseBlockers[*exec.ProviderClient]{
|
|
Result: openResult,
|
|
CloseBlockerResult: closeWait,
|
|
CloseBlockerFunc: registerCloseBlocker,
|
|
})
|
|
return openResult, registerCloseBlocker
|
|
}
|