github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/graph_walk_context.go (about)

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