mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-21 02:37:43 -05:00
Based on discussion so far it seems that we have consensus about merging the lang/eval and engine-related commits that precede this one as a starting point for ongoing work in future (hopefully smaller) PRs. This commit therefore mostly just acknowledges a small amount of unused code in a way that it won't cause linter noise, since the future work is likely to make these be used and so it'll be helpful to have them around as examples to build on. (Which is, after all, the whole point of merging this as dead code in the first place!) This does _actually_ remove an old, now-redundant declaration of the "compiled module instance" interface though, since that eventually ended up in a different place and I just forgot to clean up this initial form of it in later refactoring. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
120 lines
5.8 KiB
Go
120 lines
5.8 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 eval
|
|
|
|
import (
|
|
"context"
|
|
|
|
_ "github.com/apparentlymart/go-workgraph/workgraph" // for documentation links only
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/lang/grapheval"
|
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
|
)
|
|
|
|
// ApplyGlue is used with [DriveApplying] to allow the evaluation system to
|
|
// communicate with the applying engine that called it.
|
|
//
|
|
// Methods of this type can be called concurrently with each other and with
|
|
// themselves, so implementations must use appropriate synchronization
|
|
// primitives to avoid race conditions.
|
|
type ApplyGlue interface {
|
|
// ResourceInstanceFinalState blocks until the apply phase has completed
|
|
// enough work to decide the final state value for the resource instance
|
|
// with the given address and then returns that value.
|
|
//
|
|
// If operations that would contribute to that final value fail then this
|
|
// function returns a suitable placeholder for the final state that can
|
|
// would allow valid dependent expressions to evaluate successfully though
|
|
// potentially to an unknown value. Returning the "planned state" that
|
|
// was predicted during the planning phase is acceptable, and returning
|
|
// [cty.DynamicVal] is also acceptable as a last resort when absolutely
|
|
// no information is available.
|
|
//
|
|
// Diagnostics from apply-time actions must be reported through some other
|
|
// channel controlled by the apply engine itself.
|
|
ResourceInstanceFinalState(ctx context.Context, addr addrs.AbsResourceInstance) cty.Value
|
|
}
|
|
|
|
// DriveApplying uses this configuration instance to support an "apply"
|
|
// process being managed by some other part of the system.
|
|
//
|
|
// Applying is driven primarily by an execution graph that was built during
|
|
// the planning phase and so during apply the eval engine's only role is to
|
|
// provide information about the final configuration of different configuration
|
|
// objects and propagate the final state returned by the apply engine through
|
|
// dependent expressions. We achieve that by calling the given callback with
|
|
// an [ApplyOracle] object that the apply engine can use to pull the needed
|
|
// information at an appropriate time.
|
|
//
|
|
// The given callback is provided a [context.Context] that is associated
|
|
// with a [workgraph.Worker], and is required to use the facilities in
|
|
// [grapheval] and [workgraph] to track its work so that it can collaborate
|
|
// properly with the evaluation system's detection of self-references, to
|
|
// avoid deadlocks, but the apply phase is free to construct its own workers
|
|
// rather than using the one provided to the callback function.
|
|
func (c *ConfigInstance) DriveApplying(ctx context.Context, glue ApplyGlue, run func(ctx context.Context, oracle *ApplyOracle)) tfdiags.Diagnostics {
|
|
// All of our work will be associated with a workgraph worker that serves
|
|
// as the initial worker node in the work graph.
|
|
ctx = grapheval.ContextWithNewWorker(ctx)
|
|
_ = ctx // just so we can keep the above as a reminder of the need to have a grapheval worker in future work
|
|
|
|
// TODO: This should take an implementation of an interface that integrates
|
|
// with the main applying engine.
|
|
panic("unimplemented")
|
|
}
|
|
|
|
// An ApplyOracle is passed to the callback given to
|
|
// [ConfigInstance.DriveApplying] to give the main apply engine access to
|
|
// various information from the configuration that it will need during
|
|
// the apply process.
|
|
//
|
|
// The methods of an [ApplyOracle] must be called with a [context.Context]
|
|
// derived from one produced by [grapheval.ContextWithWorker].
|
|
//
|
|
// Whereas the planning process is driven primarily by the dependencies
|
|
// discovered dynamically during evaluation, the apply process is instead
|
|
// driven primarily by an execution graph that was built during the planning
|
|
// process. The apply-time execution steps therefore need to be able to
|
|
// pull the information they need from the evaluation engine on request
|
|
// instead of the evaluation engine pushing the information out, and an
|
|
// object of this type provides that information.
|
|
//
|
|
// It's the responsibilty of the planning engine to construct an execution
|
|
// graph that ensures that the apply phase will request information from
|
|
// the oracle only once it has already been made available by earlier work.
|
|
type ApplyOracle struct {
|
|
}
|
|
|
|
// DesiredResourceInstance returns the [DesiredResourceInstance] object
|
|
// associated with the given resource instance address, or nil if the given
|
|
// address does not match a desired resource instance.
|
|
//
|
|
// This API assumes that the apply phase is working from an execution graph
|
|
// built during the planning phase and is therefore relying on the plan phase
|
|
// to correctly describe a subset of the desired resource instances so that
|
|
// this should never return nil. If this _does_ return nil then that suggests
|
|
// a bug in the planning engine, which caused it to create an incorrect
|
|
// execution graph.
|
|
func (o *ApplyOracle) DesiredResourceInstance(ctx context.Context, addr addrs.AbsResourceInstance) *DesiredResourceInstance {
|
|
// TODO: Implement
|
|
panic("unimplemented")
|
|
}
|
|
|
|
// ProviderInstanceConfig returns the configuration value for the given
|
|
// provider instance, or [cty.NilVal] if there is no such provider instance.
|
|
//
|
|
// This API assumes that the apply phase is working from an execution graph
|
|
// built during the planning phase and is therefore relyingo n the plan phase
|
|
// to refer only to provider instances that are present ni the configuration.
|
|
// If this _does_ return cty.NilVal then that suggests a bug in the planning
|
|
// engine, causing it to create an incorrect execution graph.
|
|
func (o *ApplyOracle) ProviderInstanceConfig(ctx context.Context, addr addrs.AbsProviderInstanceCorrect) cty.Value {
|
|
// TODO: Implement
|
|
panic("unimplemented")
|
|
}
|