github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/terraform/graph.go (about)

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