github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/terraform/transform_config.go (about)

     1  package terraform
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/terraform/config"
    10  	"github.com/hashicorp/terraform/config/module"
    11  	"github.com/hashicorp/terraform/dag"
    12  )
    13  
    14  // ConfigTransformer is a GraphTransformer that adds all the resources
    15  // from the configuration to the graph.
    16  //
    17  // The module used to configure this transformer must be the root module.
    18  //
    19  // Only resources are added to the graph. Variables, outputs, and
    20  // providers must be added via other transforms.
    21  //
    22  // Unlike ConfigTransformerOld, this transformer creates a graph with
    23  // all resources including module resources, rather than creating module
    24  // nodes that are then "flattened".
    25  type ConfigTransformer struct {
    26  	Concrete ConcreteResourceNodeFunc
    27  
    28  	// Module is the module to add resources from.
    29  	Module *module.Tree
    30  
    31  	// Unique will only add resources that aren't already present in the graph.
    32  	Unique bool
    33  
    34  	// Mode will only add resources that match the given mode
    35  	ModeFilter bool
    36  	Mode       config.ResourceMode
    37  
    38  	l         sync.Mutex
    39  	uniqueMap map[string]struct{}
    40  }
    41  
    42  func (t *ConfigTransformer) Transform(g *Graph) error {
    43  	// Lock since we use some internal state
    44  	t.l.Lock()
    45  	defer t.l.Unlock()
    46  
    47  	// If no module is given, we don't do anything
    48  	if t.Module == nil {
    49  		return nil
    50  	}
    51  
    52  	// If the module isn't loaded, that is simply an error
    53  	if !t.Module.Loaded() {
    54  		return errors.New("module must be loaded for ConfigTransformer")
    55  	}
    56  
    57  	// Reset the uniqueness map. If we're tracking uniques, then populate
    58  	// it with addresses.
    59  	t.uniqueMap = make(map[string]struct{})
    60  	defer func() { t.uniqueMap = nil }()
    61  	if t.Unique {
    62  		for _, v := range g.Vertices() {
    63  			if rn, ok := v.(GraphNodeResource); ok {
    64  				t.uniqueMap[rn.ResourceAddr().String()] = struct{}{}
    65  			}
    66  		}
    67  	}
    68  
    69  	// Start the transformation process
    70  	return t.transform(g, t.Module)
    71  }
    72  
    73  func (t *ConfigTransformer) transform(g *Graph, m *module.Tree) error {
    74  	// If no config, do nothing
    75  	if m == nil {
    76  		return nil
    77  	}
    78  
    79  	// Add our resources
    80  	if err := t.transformSingle(g, m); err != nil {
    81  		return err
    82  	}
    83  
    84  	// Transform all the children.
    85  	for _, c := range m.Children() {
    86  		if err := t.transform(g, c); err != nil {
    87  			return err
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func (t *ConfigTransformer) transformSingle(g *Graph, m *module.Tree) error {
    95  	log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", m.Path())
    96  
    97  	// Get the configuration for this module
    98  	conf := m.Config()
    99  
   100  	// Build the path we're at
   101  	path := m.Path()
   102  
   103  	// Write all the resources out
   104  	for _, r := range conf.Resources {
   105  		// Build the resource address
   106  		addr, err := parseResourceAddressConfig(r)
   107  		if err != nil {
   108  			panic(fmt.Sprintf(
   109  				"Error parsing config address, this is a bug: %#v", r))
   110  		}
   111  		addr.Path = path
   112  
   113  		// If this is already in our uniqueness map, don't add it again
   114  		if _, ok := t.uniqueMap[addr.String()]; ok {
   115  			continue
   116  		}
   117  
   118  		// Remove non-matching modes
   119  		if t.ModeFilter && addr.Mode != t.Mode {
   120  			continue
   121  		}
   122  
   123  		// Build the abstract node and the concrete one
   124  		abstract := &NodeAbstractResource{Addr: addr}
   125  		var node dag.Vertex = abstract
   126  		if f := t.Concrete; f != nil {
   127  			node = f(abstract)
   128  		}
   129  
   130  		// Add it to the graph
   131  		g.Add(node)
   132  	}
   133  
   134  	return nil
   135  }