github.com/opentofu/opentofu@v1.7.1/internal/tofu/transform_attach_state.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofu
     7  
     8  import (
     9  	"log"
    10  
    11  	"github.com/opentofu/opentofu/internal/dag"
    12  	"github.com/opentofu/opentofu/internal/states"
    13  )
    14  
    15  // GraphNodeAttachResourceState is an interface that can be implemented
    16  // to request that a ResourceState is attached to the node.
    17  //
    18  // Due to a historical naming inconsistency, the type ResourceState actually
    19  // represents the state for a particular _instance_, while InstanceState
    20  // represents the values for that instance during a particular phase
    21  // (e.g. primary vs. deposed). Consequently, GraphNodeAttachResourceState
    22  // is supported only for nodes that represent resource instances, even though
    23  // the name might suggest it is for containing resources.
    24  type GraphNodeAttachResourceState interface {
    25  	GraphNodeResourceInstance
    26  
    27  	// Sets the state
    28  	AttachResourceState(*states.Resource)
    29  }
    30  
    31  // AttachStateTransformer goes through the graph and attaches
    32  // state to nodes that implement the interfaces above.
    33  type AttachStateTransformer struct {
    34  	State *states.State // State is the root state
    35  }
    36  
    37  func (t *AttachStateTransformer) Transform(g *Graph) error {
    38  	// If no state, then nothing to do
    39  	if t.State == nil {
    40  		log.Printf("[DEBUG] Not attaching any node states: overall state is nil")
    41  		return nil
    42  	}
    43  
    44  	for _, v := range g.Vertices() {
    45  		// Nodes implement this interface to request state attachment.
    46  		an, ok := v.(GraphNodeAttachResourceState)
    47  		if !ok {
    48  			continue
    49  		}
    50  		addr := an.ResourceInstanceAddr()
    51  
    52  		rs := t.State.Resource(addr.ContainingResource())
    53  		if rs == nil {
    54  			log.Printf("[DEBUG] Resource state not found for node %q, instance %s", dag.VertexName(v), addr)
    55  			continue
    56  		}
    57  
    58  		is := rs.Instance(addr.Resource.Key)
    59  		if is == nil {
    60  			// We don't actually need this here, since we'll attach the whole
    61  			// resource state, but we still check because it'd be weird
    62  			// for the specific instance we're attaching to not to exist.
    63  			log.Printf("[DEBUG] Resource instance state not found for node %q, instance %s", dag.VertexName(v), addr)
    64  			continue
    65  		}
    66  
    67  		// make sure to attach a copy of the state, so instances can modify the
    68  		// same ResourceState.
    69  		an.AttachResourceState(rs.DeepCopy())
    70  	}
    71  
    72  	return nil
    73  }