// 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 }