Files
opentf/internal/lang/eval/resource_instance.go
Martin Atkins 635b444c8e lang/eval: Some deeper stubbing out of the DrivePlanning design
This is a little too busy/complicated for my liking but it's a place to
start and hopefully we'll be able to cut this down a little after we see
how the planning engine implementation turns out.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-27 10:15:41 -07:00

169 lines
7.7 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 (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
)
// DesiredResourceInstance describes a resource instance that is part of
// the desired state (i.e. declared in the configuration).
//
// In situations where unknown values mean that we cannot yet determine exactly
// which instances exist for a given resource an object of this type can
// potentially instead represent a placeholder for zero or more instances
// of the same resource, in which case we can still produce a "speculative"
// planned new state but will not be able to actually apply changes to those
// resource instances until a subsequent plan/apply round.
// [DesiredResourceInstance.IsPlaceholder] returns true for these placeholder
// objects.
//
// Prior state resouce instances are not represented in this package at all.
// The plan and apply mechanisms implemented elsewhere are responsible for
// comparing desired resource instances with prior state resource instances
// to determine what actions are needed, if any.
type DesiredResourceInstance struct {
// Addr is the absolute address of the resource instance, suitable for
// correlation with resource instances in the prior state and (during the
// apply phase) in the plan.
//
// For objects that represent placeholders for zero or more instances whose
// instance expansion is not yet known,
// [addrs.AbsResourceInstance.IsPlaceholder] returns true.
Addr addrs.AbsResourceInstance
// ConfigVal is an object-typed value representing the configuration, which
// has already been validated against the schema for the corresponding
// resource type.
//
// This will contain unknown values if the configuration for this resource
// instance is derived from the results of other resource instances which
// have pending actions in this same plan.
ConfigVal cty.Value
// Provider is the source address of the provider that the resource type
// of this resource instance belongs to.
//
// ProviderInstance is guaranteed to refer to an instance of this provider.
Provider addrs.Provider
// ProviderInstance is the absolute address of the provider instance that
// this resource instance currently belongs to. All configured-provider
// operations related to this resource instance must be performed through
// this provider instance.
//
// This can be nil in situations where the decision about which provider
// instance to use depends on an unknown value. In that case the planning
// phase should return a canned placeholder object based only on the
// configuration value and the schema for this resource type, such as
// by using [objchange.ProposedNew], and should otherwise defer any
// actions for this resource instance until a future plan/apply round.
ProviderInstance *addrs.AbsProviderInstanceCorrect
// RequiredResourceInstances are the addresses of zero or more resource
// instances that must exist and must be fully converged before the
// final plan for this resource instance could be calculated.
//
// These addresses can potentially contain unknown instance keys if the
// configuration for this resource instance was derived from placeholders
// for upstream resource instances that had unknown keys in their own
// addresses.
RequiredResourceInstances addrs.Set[addrs.AbsResourceInstance]
// IgnoreChangesPaths are paths for which the module author requested
// that we "ignore changes".
//
// To "ignore changes" means to disregard what is configured for anything
// under a matching path in ConfigVal and to instead treat the corresponding
// value from the prior state as the effective desired state. This is
// meaningful only when planning in-place updates to an object that is
// already tracked in the prior state; it should be ignored when planning
// to create or delete the object associated with a resource instance.
//
// Index steps within the path can potentially have unknown keys if the
// decision about what to ignore is based on a value that won't be known
// until the apply phase.
//
// This is meaningful only for resource modes that support the "update"
// change action, and so is always empty for other modes.
IgnoreChangesPaths []cty.Path
// CreateBeforeDestroy is true when the module author specified that
// a "replace" action for this resource instance should be decomposed into
// "create replacement and then destroy", instead of the default
// decomposition of "destroy and then create replacement".
//
// How exactly that request is honored is outside the scope of this package,
// and is instead the responsibility of the planning engine as it builds
// the execution graph for the apply phase.
//
// This is meaningful only for resource modes that support the "update"
// change action, and so is always false for other modes.
//
// FIXME: Probably also need an "unknown" representation for this, so
// that we can eventually do https://github.com/opentofu/opentofu/issues/2523 .
CreateBeforeDestroy bool
// If RejectDeleteAction is true then the planning phase should return an
// error if it would otherwise have planned to destroy any existing object
// associated with this resource instance.
//
// This is meaningful only for resource modes that support the "update"
// change action, and so is always false for other modes.
//
// FIXME: Probably also need an "unknown" representation for this, so
// that we can eventually do https://github.com/opentofu/opentofu/issues/2522 .
RejectDeleteAction bool
// ReplaceTriggeredBy describes zero ore more attribute prefixes within
// other resource instances for which the planning engine should force
// replacement of this resource instance if any value beneath one of
// the nominated paths has a change already planned for the current
// plan/apply round.
//
// Index steps within the paths and instance keys within the resource
// instance addresses can both potentially have unknown keys if the
// decision about what to refer to is based on a value that won't be known
// until the apply phase.
//
// This is meaningful only for resource modes that support the "update"
// change action, and so is always false for other modes.
//
// Any resource instance mentioned in this collection will always also
// appear in RequiredResourceInstances.
ReplaceTriggeredBy []ResourceInstanceAttributePath
}
// IsPlaceholder returns true if this object is acting as a placeholder for
// zero or more resource instances whose full expansion is not yet known.
//
// In that case the other fields of [DesiredResourceInstance] describe
// characteristics that all of those instances would have in common, so that
// it's hopefully still possible to perform some speculative planning and
// transfer partial results downstream to other resource instances so we can
// present as complete as possible an overview of how the system is likely
// to be configured after subsequent plan/apply rounds once everything is fully
// converged.
//
// This is not the only reason why a particular resource instance might need
// to have its actions deferred to a future plan/apply round. Refer to the
// documentation for other fields of [DesiredResourceInstance] for some other
// situations where this is true. The planning engine might also have additional
// reasons for deferring particular resource instances that are outside the
// scope of the configuration.
func (ri *DesiredResourceInstance) IsPlaceholder() bool {
return ri.Addr.IsPlaceholder()
}
// ResourceInstanceAttributePath describes a (possibly empty) attribute path
// within a resource instance.
type ResourceInstanceAttributePath struct {
ResourceInstance addrs.AbsResourceInstance
Path cty.Path
}