Files
opentf/internal/tofu/node_resource_apply.go
2025-09-04 20:19:20 +04:00

69 lines
2.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 tofu
import (
"context"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/tfdiags"
)
// nodeExpandApplyableResource handles the first layer of resource
// expansion during apply. Even though the resource instances themselves are already expanded from the plan,
// we still need to register resource nodes in instances.Expander with their absolute addresses
// based on the expanded module instances.
//
// "Expand" in the name refers to instances.Expander usage. This node doesn't generate a dynamic subgraph.
type nodeExpandApplyableResource struct {
*NodeAbstractResource
}
var (
_ GraphNodeExecutable = (*nodeExpandApplyableResource)(nil)
_ GraphNodeReferenceable = (*nodeExpandApplyableResource)(nil)
_ GraphNodeReferencer = (*nodeExpandApplyableResource)(nil)
_ GraphNodeConfigResource = (*nodeExpandApplyableResource)(nil)
_ GraphNodeAttachResourceConfig = (*nodeExpandApplyableResource)(nil)
// nodeExpandApplyableResource needs to be retained during unused nodes pruning
// to register the resource for expanded module instances in `instances.Expander`
_ graphNodeRetainedByPruneUnusedNodesTransformer = (*nodeExpandApplyableResource)(nil)
_ GraphNodeTargetable = (*nodeExpandApplyableResource)(nil)
)
func (n *nodeExpandApplyableResource) retainDuringUnusedPruning() {
}
func (n *nodeExpandApplyableResource) References() []*addrs.Reference {
refs := n.NodeAbstractResource.References()
// The expand node needs to connect to the individual resource instances it
// references, but cannot refer to it's own instances without causing
// cycles. It would be preferable to entirely disallow self references
// without the `self` identifier, but those were allowed in provisioners
// for compatibility with legacy configuration. We also can't always just
// filter them out for all resource node types, because the only method we
// have for catching certain invalid configurations are the cycles that
// result from these inter-instance references.
return filterSelfRefs(n.Addr.Resource, refs)
}
func (n *nodeExpandApplyableResource) Name() string {
return n.NodeAbstractResource.Name() + " (expand)"
}
func (n *nodeExpandApplyableResource) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
expander := evalCtx.InstanceExpander()
moduleInstances := expander.ExpandModule(n.Addr.Module)
for _, module := range moduleInstances {
evalCtx = evalCtx.WithPath(module)
diags = diags.Append(n.writeResourceState(ctx, evalCtx, n.Addr.Resource.Absolute(module)))
}
return diags
}