terraform: subpath context setting

This commit is contained in:
Mitchell Hashimoto 2015-05-01 14:19:32 -07:00
parent 9a54dddc85
commit f2e7f505d4
5 changed files with 35 additions and 14 deletions

View File

@ -144,8 +144,8 @@ func (g *Graph) init() {
func (g *Graph) walk(walker GraphWalker) error { func (g *Graph) walk(walker GraphWalker) error {
// The callbacks for enter/exiting a graph // The callbacks for enter/exiting a graph
ctx := walker.EnterGraph(g) ctx := walker.EnterPath(g.Path)
defer walker.ExitGraph(g) defer walker.ExitPath(g.Path)
// Get the path for logs // Get the path for logs
path := strings.Join(ctx.Path(), ".") path := strings.Join(ctx.Path(), ".")
@ -158,6 +158,15 @@ func (g *Graph) walk(walker GraphWalker) error {
walker.EnterVertex(v) walker.EnterVertex(v)
defer func() { walker.ExitVertex(v, rerr) }() defer func() { walker.ExitVertex(v, rerr) }()
// vertexCtx is the context that we use when evaluating. This
// is normally the context of our graph but can be overridden
// with a GraphNodeSubPath impl.
vertexCtx := ctx
if pn, ok := v.(GraphNodeSubPath); ok {
vertexCtx = walker.EnterPath(pn.Path())
defer walker.ExitPath(pn.Path())
}
// If the node is eval-able, then evaluate it. // If the node is eval-able, then evaluate it.
if ev, ok := v.(GraphNodeEvalable); ok { if ev, ok := v.(GraphNodeEvalable); ok {
tree := ev.EvalTree() tree := ev.EvalTree()
@ -170,7 +179,7 @@ func (g *Graph) walk(walker GraphWalker) error {
// then callback with the output. // then callback with the output.
log.Printf("[DEBUG] vertex %s.%s: evaluating", path, dag.VertexName(v)) log.Printf("[DEBUG] vertex %s.%s: evaluating", path, dag.VertexName(v))
tree = walker.EnterEvalTree(v, tree) tree = walker.EnterEvalTree(v, tree)
output, err := Eval(tree, ctx) output, err := Eval(tree, vertexCtx)
if rerr = walker.ExitEvalTree(v, output, err); rerr != nil { if rerr = walker.ExitEvalTree(v, output, err); rerr != nil {
return return
} }
@ -182,7 +191,7 @@ func (g *Graph) walk(walker GraphWalker) error {
"[DEBUG] vertex %s.%s: expanding/walking dynamic subgraph", "[DEBUG] vertex %s.%s: expanding/walking dynamic subgraph",
path, path,
dag.VertexName(v)) dag.VertexName(v))
g, err := ev.DynamicExpand(ctx) g, err := ev.DynamicExpand(vertexCtx)
if err != nil { if err != nil {
rerr = err rerr = err
return return

View File

@ -227,7 +227,7 @@ func (n *graphNodeModuleExpanded) FlattenGraph() *Graph {
graph.Replace(v, &graphNodeModuleFlatWrap{ graph.Replace(v, &graphNodeModuleFlatWrap{
graphNodeModuleWrappable: wn, graphNodeModuleWrappable: wn,
Path: graph.Path, PathValue: graph.Path,
NamePrefix: pathStr, NamePrefix: pathStr,
DependentOnPrefix: depPrefix, DependentOnPrefix: depPrefix,
}) })
@ -259,7 +259,7 @@ type graphNodeModuleWrappable interface {
type graphNodeModuleFlatWrap struct { type graphNodeModuleFlatWrap struct {
graphNodeModuleWrappable graphNodeModuleWrappable
Path []string PathValue []string
NamePrefix string NamePrefix string
DependentOnPrefix string DependentOnPrefix string
} }
@ -268,6 +268,11 @@ func (n *graphNodeModuleFlatWrap) Name() string {
return fmt.Sprintf("%s.%s", n.NamePrefix, n.graphNodeModuleWrappable.Name()) return fmt.Sprintf("%s.%s", n.NamePrefix, n.graphNodeModuleWrappable.Name())
} }
// GraphNodeSubPath impl.
func (n *graphNodeModuleFlatWrap) Path() []string {
return n.PathValue
}
func (n *graphNodeModuleFlatWrap) DependableName() []string { func (n *graphNodeModuleFlatWrap) DependableName() []string {
result := n.graphNodeModuleWrappable.DependableName() result := n.graphNodeModuleWrappable.DependableName()
n.prefixList(result, n.NamePrefix) n.prefixList(result, n.NamePrefix)

View File

@ -0,0 +1,7 @@
package terraform
// GraphNodeSubPath says that a node is part of a graph with a
// different path, and the context should be adjusted accordingly.
type GraphNodeSubPath interface {
Path() []string
}

View File

@ -7,8 +7,8 @@ import (
// GraphWalker is an interface that can be implemented that when used // GraphWalker is an interface that can be implemented that when used
// with Graph.Walk will invoke the given callbacks under certain events. // with Graph.Walk will invoke the given callbacks under certain events.
type GraphWalker interface { type GraphWalker interface {
EnterGraph(*Graph) EvalContext EnterPath([]string) EvalContext
ExitGraph(*Graph) ExitPath([]string)
EnterVertex(dag.Vertex) EnterVertex(dag.Vertex)
ExitVertex(dag.Vertex, error) ExitVertex(dag.Vertex, error)
EnterEvalTree(dag.Vertex, EvalNode) EvalNode EnterEvalTree(dag.Vertex, EvalNode) EvalNode
@ -20,8 +20,8 @@ type GraphWalker interface {
// implementing all the required functions. // implementing all the required functions.
type NullGraphWalker struct{} type NullGraphWalker struct{}
func (NullGraphWalker) EnterGraph(*Graph) EvalContext { return nil } func (NullGraphWalker) EnterPath([]string) EvalContext { return nil }
func (NullGraphWalker) ExitGraph(*Graph) {} func (NullGraphWalker) ExitPath([]string) {}
func (NullGraphWalker) EnterVertex(dag.Vertex) {} func (NullGraphWalker) EnterVertex(dag.Vertex) {}
func (NullGraphWalker) ExitVertex(dag.Vertex, error) {} func (NullGraphWalker) ExitVertex(dag.Vertex, error) {}
func (NullGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode { return n } func (NullGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode { return n }

View File

@ -33,14 +33,14 @@ type ContextGraphWalker struct {
provisionerLock sync.Mutex provisionerLock sync.Mutex
} }
func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext { func (w *ContextGraphWalker) EnterPath(path []string) EvalContext {
w.once.Do(w.init) w.once.Do(w.init)
w.contextLock.Lock() w.contextLock.Lock()
defer w.contextLock.Unlock() defer w.contextLock.Unlock()
// If we already have a context for this path cached, use that // If we already have a context for this path cached, use that
key := PathCacheKey(g.Path) key := PathCacheKey(path)
if ctx, ok := w.contexts[key]; ok { if ctx, ok := w.contexts[key]; ok {
return ctx return ctx
} }
@ -49,13 +49,13 @@ func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
// to the root module. As we enter subgraphs, we don't want to set // to the root module. As we enter subgraphs, we don't want to set
// variables, which is set by the SetVariables EvalContext function. // variables, which is set by the SetVariables EvalContext function.
variables := w.Context.variables variables := w.Context.variables
if len(g.Path) > 1 { if len(path) > 1 {
// We're in a submodule, the variables should be empty // We're in a submodule, the variables should be empty
variables = make(map[string]string) variables = make(map[string]string)
} }
ctx := &BuiltinEvalContext{ ctx := &BuiltinEvalContext{
PathValue: g.Path, PathValue: path,
Hooks: w.Context.hooks, Hooks: w.Context.hooks,
InputValue: w.Context.uiInput, InputValue: w.Context.uiInput,
Providers: w.Context.providers, Providers: w.Context.providers,