github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/transform_config.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  	"sync"
     6  
     7  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
     8  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/dag"
    10  )
    11  
    12  // ConfigTransformer is a GraphTransformer that adds all the resources
    13  // from the configuration to the graph.
    14  //
    15  // The module used to configure this transformer must be the root module.
    16  //
    17  // Only resources are added to the graph. Variables, outputs, and
    18  // providers must be added via other transforms.
    19  //
    20  // Unlike ConfigTransformerOld, this transformer creates a graph with
    21  // all resources including module resources, rather than creating module
    22  // nodes that are then "flattened".
    23  type ConfigTransformer struct {
    24  	Concrete ConcreteResourceNodeFunc
    25  
    26  	// Module is the module to add resources from.
    27  	Config *configs.Config
    28  
    29  	// Unique will only add resources that aren't already present in the graph.
    30  	Unique bool
    31  
    32  	// Mode will only add resources that match the given mode
    33  	ModeFilter bool
    34  	Mode       addrs.ResourceMode
    35  
    36  	l         sync.Mutex
    37  	uniqueMap map[string]struct{}
    38  }
    39  
    40  func (t *ConfigTransformer) Transform(g *Graph) error {
    41  	// Lock since we use some internal state
    42  	t.l.Lock()
    43  	defer t.l.Unlock()
    44  
    45  	// If no configuration is available, we don't do anything
    46  	if t.Config == nil {
    47  		return nil
    48  	}
    49  
    50  	// Reset the uniqueness map. If we're tracking uniques, then populate
    51  	// it with addresses.
    52  	t.uniqueMap = make(map[string]struct{})
    53  	defer func() { t.uniqueMap = nil }()
    54  	if t.Unique {
    55  		for _, v := range g.Vertices() {
    56  			if rn, ok := v.(GraphNodeResource); ok {
    57  				t.uniqueMap[rn.ResourceAddr().String()] = struct{}{}
    58  			}
    59  		}
    60  	}
    61  
    62  	// Start the transformation process
    63  	return t.transform(g, t.Config)
    64  }
    65  
    66  func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
    67  	// If no config, do nothing
    68  	if config == nil {
    69  		return nil
    70  	}
    71  
    72  	// Add our resources
    73  	if err := t.transformSingle(g, config); err != nil {
    74  		return err
    75  	}
    76  
    77  	// Transform all the children.
    78  	for _, c := range config.Children {
    79  		if err := t.transform(g, c); err != nil {
    80  			return err
    81  		}
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error {
    88  	path := config.Path
    89  	module := config.Module
    90  	log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
    91  
    92  	// For now we assume that each module call produces only one module
    93  	// instance with no key, since we don't yet support "count" and "for_each"
    94  	// on modules.
    95  	// FIXME: As part of supporting "count" and "for_each" on modules, rework
    96  	// this so that we'll "expand" the module call first and then create graph
    97  	// nodes for each module instance separately.
    98  	instPath := path.UnkeyedInstanceShim()
    99  
   100  	allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources))
   101  	for _, r := range module.ManagedResources {
   102  		allResources = append(allResources, r)
   103  	}
   104  	for _, r := range module.DataResources {
   105  		allResources = append(allResources, r)
   106  	}
   107  
   108  	for _, r := range allResources {
   109  		relAddr := r.Addr()
   110  
   111  		if t.ModeFilter && relAddr.Mode != t.Mode {
   112  			// Skip non-matching modes
   113  			continue
   114  		}
   115  
   116  		addr := relAddr.Absolute(instPath)
   117  		if _, ok := t.uniqueMap[addr.String()]; ok {
   118  			// We've already seen a resource with this address. This should
   119  			// never happen, because we enforce uniqueness in the config loader.
   120  			continue
   121  		}
   122  
   123  		abstract := &NodeAbstractResource{Addr: addr}
   124  		var node dag.Vertex = abstract
   125  		if f := t.Concrete; f != nil {
   126  			node = f(abstract)
   127  		}
   128  
   129  		g.Add(node)
   130  	}
   131  
   132  	return nil
   133  }