github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/terraform/graph_walk_context.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/hashicorp/errwrap"
     8  	"github.com/hashicorp/terraform/dag"
     9  )
    10  
    11  // ContextGraphWalker is the GraphWalker implementation used with the
    12  // Context struct to walk and evaluate the graph.
    13  type ContextGraphWalker struct {
    14  	NullGraphWalker
    15  
    16  	// Configurable values
    17  	Context   *Context
    18  	Operation walkOperation
    19  
    20  	// Outputs, do not set these. Do not read these while the graph
    21  	// is being walked.
    22  	ValidationWarnings []string
    23  	ValidationErrors   []error
    24  
    25  	errorLock           sync.Mutex
    26  	once                sync.Once
    27  	contexts            map[string]*BuiltinEvalContext
    28  	contextLock         sync.Mutex
    29  	providerCache       map[string]ResourceProvider
    30  	providerConfigCache map[string]*ResourceConfig
    31  	providerLock        sync.Mutex
    32  	provisionerCache    map[string]ResourceProvisioner
    33  	provisionerLock     sync.Mutex
    34  }
    35  
    36  func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
    37  	w.once.Do(w.init)
    38  
    39  	w.contextLock.Lock()
    40  	defer w.contextLock.Unlock()
    41  
    42  	// If we already have a context for this path cached, use that
    43  	key := PathCacheKey(g.Path)
    44  	if ctx, ok := w.contexts[key]; ok {
    45  		return ctx
    46  	}
    47  
    48  	// Variables should be our context variables, but these only apply
    49  	// to the root module. As we enter subgraphs, we don't want to set
    50  	// variables, which is set by the SetVariables EvalContext function.
    51  	variables := w.Context.variables
    52  	if len(g.Path) > 1 {
    53  		// We're in a submodule, the variables should be empty
    54  		variables = make(map[string]string)
    55  	}
    56  
    57  	ctx := &BuiltinEvalContext{
    58  		PathValue:           g.Path,
    59  		Hooks:               w.Context.hooks,
    60  		InputValue:          w.Context.uiInput,
    61  		Providers:           w.Context.providers,
    62  		ProviderCache:       w.providerCache,
    63  		ProviderConfigCache: w.providerConfigCache,
    64  		ProviderInputConfig: w.Context.providerInputConfig,
    65  		ProviderLock:        &w.providerLock,
    66  		Provisioners:        w.Context.provisioners,
    67  		ProvisionerCache:    w.provisionerCache,
    68  		ProvisionerLock:     &w.provisionerLock,
    69  		DiffValue:           w.Context.diff,
    70  		DiffLock:            &w.Context.diffLock,
    71  		StateValue:          w.Context.state,
    72  		StateLock:           &w.Context.stateLock,
    73  		Interpolater: &Interpolater{
    74  			Operation: w.Operation,
    75  			Module:    w.Context.module,
    76  			State:     w.Context.state,
    77  			StateLock: &w.Context.stateLock,
    78  			Variables: variables,
    79  		},
    80  	}
    81  
    82  	w.contexts[key] = ctx
    83  	return ctx
    84  }
    85  
    86  func (w *ContextGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode {
    87  	// Acquire a lock on the semaphore
    88  	w.Context.parallelSem.Acquire()
    89  
    90  	// We want to filter the evaluation tree to only include operations
    91  	// that belong in this operation.
    92  	return EvalFilter(n, EvalNodeFilterOp(w.Operation))
    93  }
    94  
    95  func (w *ContextGraphWalker) ExitEvalTree(
    96  	v dag.Vertex, output interface{}, err error) error {
    97  	// Release the semaphore
    98  	w.Context.parallelSem.Release()
    99  
   100  	if err == nil {
   101  		return nil
   102  	}
   103  
   104  	// Acquire the lock because anything is going to require a lock.
   105  	w.errorLock.Lock()
   106  	defer w.errorLock.Unlock()
   107  
   108  	// Try to get a validation error out of it. If its not a validation
   109  	// error, then just record the normal error.
   110  	verr, ok := err.(*EvalValidateError)
   111  	if !ok {
   112  		return err
   113  	}
   114  
   115  	for _, msg := range verr.Warnings {
   116  		w.ValidationWarnings = append(
   117  			w.ValidationWarnings,
   118  			fmt.Sprintf("%s: %s", dag.VertexName(v), msg))
   119  	}
   120  	for _, e := range verr.Errors {
   121  		w.ValidationErrors = append(
   122  			w.ValidationErrors,
   123  			errwrap.Wrapf(fmt.Sprintf("%s: {{err}}", dag.VertexName(v)), e))
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  func (w *ContextGraphWalker) init() {
   130  	w.contexts = make(map[string]*BuiltinEvalContext, 5)
   131  	w.providerCache = make(map[string]ResourceProvider, 5)
   132  	w.providerConfigCache = make(map[string]*ResourceConfig, 5)
   133  	w.provisionerCache = make(map[string]ResourceProvisioner, 5)
   134  }