mirror of
https://github.com/opentofu/opentofu.git
synced 2026-06-11 09:31:23 -04:00
Previously ManagedPerformDeposed just allocated a fresh deposed key dynamically at apply time, but to allow it to compose with the recently-added ManagePrepareDeposed it will now take a "delete" plan as an argument and expect it to already be annotated with a unique deposed key to use. This means that we will now preselect all of the new deposed keys during the planning phase, making it easier to relate the generated execution graph to the results of running it during the apply phase. This commit also includes changes to the planning engine to now generate a correct execution subgraph for create-then-destroy replace operations, where the final step of destroying the old object now correctly destroys the deposed object instead of getting confused and overwriting the current object with the result of the destroy. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
77 lines
3.2 KiB
Go
77 lines
3.2 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 (
|
|
"sync"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/engine/internal/execgraph"
|
|
)
|
|
|
|
// execGraphBuilder is a higher-level wrapper around [execgraph.Builder] that
|
|
// is tailored to the needs of the planning engine.
|
|
//
|
|
// Specifically:
|
|
// - Its exported methods that add to or modify the graph are all
|
|
// concurrency-safe, for convenient use during the concurrent planning work
|
|
// driven by the evaluator.
|
|
// - It keeps track of certain "singleton" collections of graph nodes that
|
|
// different parts of the planning engine all need to agree on for the
|
|
// execution graph to be correct, such as ensuring there's only one open
|
|
// and one close operation per distinct provider instance address.
|
|
// - Many of its methods can potentially add multiple operations to the graph
|
|
// at once, to let the planning engine work at a higher level of abstraction
|
|
// than just the individual raw operation types. The lower-level
|
|
// [execgraph.Builder] instead directly matches the abstraction level of
|
|
// [execgraph.Operations].
|
|
type execGraphBuilder struct {
|
|
// mu must be locked while accessing any of the other fields.
|
|
mu sync.Mutex
|
|
|
|
// lower is the lower-level graph builder that this utility is built in
|
|
// terms of.
|
|
lower *execgraph.Builder
|
|
|
|
// During construction we treat certain items as singletons so that
|
|
// we can do the associated work only once while providing it to
|
|
// multiple callers, and so these maps track those singletons but
|
|
// we throw these away after building is complete because the graph
|
|
// becomes immutable at that point.
|
|
resourceInstAddrRefs addrs.Map[addrs.AbsResourceInstance, execgraph.ResultRef[addrs.AbsResourceInstance]]
|
|
|
|
// makeDeposedKey is a function provided by the caller for allocating the
|
|
// tracking keys for objects that will become newly-deposed during the
|
|
// apply phase.
|
|
//
|
|
// The implementer is required to make sure that the returned key does not
|
|
// overlap with any already-deposed object for the given resource instance
|
|
// or with any other keys previously returned for the same resource instance
|
|
// address during the same graph-build.
|
|
makeDeposedKey func(addrs.AbsResourceInstance) addrs.DeposedKey
|
|
}
|
|
|
|
// NOTE: There are additional methods for [execGraphBuilder] declared in
|
|
// the other files named execgraph_*.go , grouped by what kinds of objects they
|
|
// primarily work with.
|
|
|
|
func newExecGraphBuilder(makeDeposedKey func(addrs.AbsResourceInstance) addrs.DeposedKey) *execGraphBuilder {
|
|
return &execGraphBuilder{
|
|
lower: execgraph.NewBuilder(),
|
|
resourceInstAddrRefs: addrs.MakeMap[addrs.AbsResourceInstance, execgraph.ResultRef[addrs.AbsResourceInstance]](),
|
|
makeDeposedKey: makeDeposedKey,
|
|
}
|
|
}
|
|
|
|
// Finish returns the graph that has been built, which is then immutable.
|
|
//
|
|
// After calling this function the execGraphBuilder is invalid and must not be
|
|
// used anymore.
|
|
func (b *execGraphBuilder) Finish() *execgraph.Graph {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.lower.Finish()
|
|
}
|