github.com/nov1n/terraform@v0.7.9-0.20161103151050-bf6852f38e28/terraform/graph.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/terraform/dag"
    10  )
    11  
    12  // RootModuleName is the name given to the root module implicitly.
    13  const RootModuleName = "root"
    14  
    15  // RootModulePath is the path for the root module.
    16  var RootModulePath = []string{RootModuleName}
    17  
    18  // Graph represents the graph that Terraform uses to represent resources
    19  // and their dependencies. Each graph represents only one module, but it
    20  // can contain further modules, which themselves have their own graph.
    21  type Graph struct {
    22  	// Graph is the actual DAG. This is embedded so you can call the DAG
    23  	// methods directly.
    24  	dag.AcyclicGraph
    25  
    26  	// Path is the path in the module tree that this Graph represents.
    27  	// The root is represented by a single element list containing
    28  	// RootModuleName
    29  	Path []string
    30  
    31  	// annotations are the annotations that are added to vertices. Annotations
    32  	// are arbitrary metadata taht is used for various logic. Annotations
    33  	// should have unique keys that are referenced via constants.
    34  	annotations map[dag.Vertex]map[string]interface{}
    35  
    36  	// dependableMap is a lookaside table for fast lookups for connecting
    37  	// dependencies by their GraphNodeDependable value to avoid O(n^3)-like
    38  	// situations and turn them into O(1) with respect to the number of new
    39  	// edges.
    40  	dependableMap map[string]dag.Vertex
    41  
    42  	once sync.Once
    43  }
    44  
    45  // Annotations returns the annotations that are configured for the
    46  // given vertex. The map is guaranteed to be non-nil but may be empty.
    47  //
    48  // The returned map may be modified to modify the annotations of the
    49  // vertex.
    50  func (g *Graph) Annotations(v dag.Vertex) map[string]interface{} {
    51  	g.once.Do(g.init)
    52  
    53  	// If this vertex isn't in the graph, then just return an empty map
    54  	if !g.HasVertex(v) {
    55  		return map[string]interface{}{}
    56  	}
    57  
    58  	// Get the map, if it doesn't exist yet then initialize it
    59  	m, ok := g.annotations[v]
    60  	if !ok {
    61  		m = make(map[string]interface{})
    62  		g.annotations[v] = m
    63  	}
    64  
    65  	return m
    66  }
    67  
    68  // Add is the same as dag.Graph.Add.
    69  func (g *Graph) Add(v dag.Vertex) dag.Vertex {
    70  	g.once.Do(g.init)
    71  
    72  	// Call upwards to add it to the actual graph
    73  	g.Graph.Add(v)
    74  
    75  	// If this is a depend-able node, then store the lookaside info
    76  	if dv, ok := v.(GraphNodeDependable); ok {
    77  		for _, n := range dv.DependableName() {
    78  			g.dependableMap[n] = v
    79  		}
    80  	}
    81  
    82  	// If this initializes annotations, then do that
    83  	if av, ok := v.(GraphNodeAnnotationInit); ok {
    84  		as := g.Annotations(v)
    85  		for k, v := range av.AnnotationInit() {
    86  			as[k] = v
    87  		}
    88  	}
    89  
    90  	return v
    91  }
    92  
    93  // Remove is the same as dag.Graph.Remove
    94  func (g *Graph) Remove(v dag.Vertex) dag.Vertex {
    95  	g.once.Do(g.init)
    96  
    97  	// If this is a depend-able node, then remove the lookaside info
    98  	if dv, ok := v.(GraphNodeDependable); ok {
    99  		for _, n := range dv.DependableName() {
   100  			delete(g.dependableMap, n)
   101  		}
   102  	}
   103  
   104  	// Remove the annotations
   105  	delete(g.annotations, v)
   106  
   107  	// Call upwards to remove it from the actual graph
   108  	return g.Graph.Remove(v)
   109  }
   110  
   111  // Replace is the same as dag.Graph.Replace
   112  func (g *Graph) Replace(o, n dag.Vertex) bool {
   113  	g.once.Do(g.init)
   114  
   115  	// Go through and update our lookaside to point to the new vertex
   116  	for k, v := range g.dependableMap {
   117  		if v == o {
   118  			if _, ok := n.(GraphNodeDependable); ok {
   119  				g.dependableMap[k] = n
   120  			} else {
   121  				delete(g.dependableMap, k)
   122  			}
   123  		}
   124  	}
   125  
   126  	// Move the annotation if it exists
   127  	if m, ok := g.annotations[o]; ok {
   128  		g.annotations[n] = m
   129  		delete(g.annotations, o)
   130  	}
   131  
   132  	return g.Graph.Replace(o, n)
   133  }
   134  
   135  // ConnectDependent connects a GraphNodeDependent to all of its
   136  // GraphNodeDependables. It returns the list of dependents it was
   137  // unable to connect to.
   138  func (g *Graph) ConnectDependent(raw dag.Vertex) []string {
   139  	v, ok := raw.(GraphNodeDependent)
   140  	if !ok {
   141  		return nil
   142  	}
   143  
   144  	return g.ConnectTo(v, v.DependentOn())
   145  }
   146  
   147  // ConnectDependents goes through the graph, connecting all the
   148  // GraphNodeDependents to GraphNodeDependables. This is safe to call
   149  // multiple times.
   150  //
   151  // To get details on whether dependencies could be found/made, the more
   152  // specific ConnectDependent should be used.
   153  func (g *Graph) ConnectDependents() {
   154  	for _, v := range g.Vertices() {
   155  		if dv, ok := v.(GraphNodeDependent); ok {
   156  			g.ConnectDependent(dv)
   157  		}
   158  	}
   159  }
   160  
   161  // ConnectFrom creates an edge by finding the source from a DependableName
   162  // and connecting it to the specific vertex.
   163  func (g *Graph) ConnectFrom(source string, target dag.Vertex) {
   164  	g.once.Do(g.init)
   165  
   166  	if source := g.dependableMap[source]; source != nil {
   167  		g.Connect(dag.BasicEdge(source, target))
   168  	}
   169  }
   170  
   171  // ConnectTo connects a vertex to a raw string of targets that are the
   172  // result of DependableName, and returns the list of targets that are missing.
   173  func (g *Graph) ConnectTo(v dag.Vertex, targets []string) []string {
   174  	g.once.Do(g.init)
   175  
   176  	var missing []string
   177  	for _, t := range targets {
   178  		if dest := g.dependableMap[t]; dest != nil {
   179  			g.Connect(dag.BasicEdge(v, dest))
   180  		} else {
   181  			missing = append(missing, t)
   182  		}
   183  	}
   184  
   185  	return missing
   186  }
   187  
   188  // Dependable finds the vertices in the graph that have the given dependable
   189  // names and returns them.
   190  func (g *Graph) Dependable(n string) dag.Vertex {
   191  	// TODO: do we need this?
   192  	return nil
   193  }
   194  
   195  // Walk walks the graph with the given walker for callbacks. The graph
   196  // will be walked with full parallelism, so the walker should expect
   197  // to be called in concurrently.
   198  func (g *Graph) Walk(walker GraphWalker) error {
   199  	return g.walk(walker)
   200  }
   201  
   202  func (g *Graph) init() {
   203  	if g.annotations == nil {
   204  		g.annotations = make(map[dag.Vertex]map[string]interface{})
   205  	}
   206  
   207  	if g.dependableMap == nil {
   208  		g.dependableMap = make(map[string]dag.Vertex)
   209  	}
   210  }
   211  
   212  func (g *Graph) walk(walker GraphWalker) error {
   213  	// The callbacks for enter/exiting a graph
   214  	ctx := walker.EnterPath(g.Path)
   215  	defer walker.ExitPath(g.Path)
   216  
   217  	// Get the path for logs
   218  	path := strings.Join(ctx.Path(), ".")
   219  
   220  	// Walk the graph.
   221  	var walkFn dag.WalkFunc
   222  	walkFn = func(v dag.Vertex) (rerr error) {
   223  		log.Printf("[DEBUG] vertex '%s.%s': walking", path, dag.VertexName(v))
   224  
   225  		walker.EnterVertex(v)
   226  		defer func() { walker.ExitVertex(v, rerr) }()
   227  
   228  		// vertexCtx is the context that we use when evaluating. This
   229  		// is normally the context of our graph but can be overridden
   230  		// with a GraphNodeSubPath impl.
   231  		vertexCtx := ctx
   232  		if pn, ok := v.(GraphNodeSubPath); ok && len(pn.Path()) > 0 {
   233  			vertexCtx = walker.EnterPath(normalizeModulePath(pn.Path()))
   234  			defer walker.ExitPath(pn.Path())
   235  		}
   236  
   237  		// If the node is eval-able, then evaluate it.
   238  		if ev, ok := v.(GraphNodeEvalable); ok {
   239  			tree := ev.EvalTree()
   240  			if tree == nil {
   241  				panic(fmt.Sprintf(
   242  					"%s.%s (%T): nil eval tree", path, dag.VertexName(v), v))
   243  			}
   244  
   245  			// Allow the walker to change our tree if needed. Eval,
   246  			// then callback with the output.
   247  			log.Printf("[DEBUG] vertex '%s.%s': evaluating", path, dag.VertexName(v))
   248  			tree = walker.EnterEvalTree(v, tree)
   249  			output, err := Eval(tree, vertexCtx)
   250  			if rerr = walker.ExitEvalTree(v, output, err); rerr != nil {
   251  				return
   252  			}
   253  		}
   254  
   255  		// If the node is dynamically expanded, then expand it
   256  		if ev, ok := v.(GraphNodeDynamicExpandable); ok {
   257  			log.Printf(
   258  				"[DEBUG] vertex '%s.%s': expanding/walking dynamic subgraph",
   259  				path,
   260  				dag.VertexName(v))
   261  			g, err := ev.DynamicExpand(vertexCtx)
   262  			if err != nil {
   263  				rerr = err
   264  				return
   265  			}
   266  			if g != nil {
   267  				// Walk the subgraph
   268  				if rerr = g.walk(walker); rerr != nil {
   269  					return
   270  				}
   271  			}
   272  		}
   273  
   274  		// If the node has a subgraph, then walk the subgraph
   275  		if sn, ok := v.(GraphNodeSubgraph); ok {
   276  			log.Printf(
   277  				"[DEBUG] vertex '%s.%s': walking subgraph",
   278  				path,
   279  				dag.VertexName(v))
   280  
   281  			if rerr = sn.Subgraph().walk(walker); rerr != nil {
   282  				return
   283  			}
   284  		}
   285  
   286  		return nil
   287  	}
   288  
   289  	return g.AcyclicGraph.Walk(walkFn)
   290  }
   291  
   292  // GraphNodeAnnotationInit is an interface that allows a node to
   293  // initialize it's annotations.
   294  //
   295  // AnnotationInit will be called _once_ when the node is added to a
   296  // graph for the first time and is expected to return it's initial
   297  // annotations.
   298  type GraphNodeAnnotationInit interface {
   299  	AnnotationInit() map[string]interface{}
   300  }
   301  
   302  // GraphNodeDependable is an interface which says that a node can be
   303  // depended on (an edge can be placed between this node and another) according
   304  // to the well-known name returned by DependableName.
   305  //
   306  // DependableName can return multiple names it is known by.
   307  type GraphNodeDependable interface {
   308  	DependableName() []string
   309  }
   310  
   311  // GraphNodeDependent is an interface which says that a node depends
   312  // on another GraphNodeDependable by some name. By implementing this
   313  // interface, Graph.ConnectDependents() can be called multiple times
   314  // safely and efficiently.
   315  type GraphNodeDependent interface {
   316  	DependentOn() []string
   317  }