github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/eval_context_builtin.go (about)

     1  package terraform
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/terraform/config"
    10  )
    11  
    12  // BuiltinEvalContext is an EvalContext implementation that is used by
    13  // Terraform by default.
    14  type BuiltinEvalContext struct {
    15  	// StopContext is the context used to track whether we're complete
    16  	StopContext context.Context
    17  
    18  	// PathValue is the Path that this context is operating within.
    19  	PathValue []string
    20  
    21  	// Interpolater setting below affect the interpolation of variables.
    22  	//
    23  	// The InterpolaterVars are the exact value for ${var.foo} values.
    24  	// The map is shared between all contexts and is a mapping of
    25  	// PATH to KEY to VALUE. Because it is shared by all contexts as well
    26  	// as the Interpolater itself, it is protected by InterpolaterVarLock
    27  	// which must be locked during any access to the map.
    28  	Interpolater        *Interpolater
    29  	InterpolaterVars    map[string]map[string]interface{}
    30  	InterpolaterVarLock *sync.Mutex
    31  
    32  	Components          contextComponentFactory
    33  	Hooks               []Hook
    34  	InputValue          UIInput
    35  	ProviderCache       map[string]ResourceProvider
    36  	ProviderInputConfig map[string]map[string]interface{}
    37  	ProviderLock        *sync.Mutex
    38  	ProvisionerCache    map[string]ResourceProvisioner
    39  	ProvisionerLock     *sync.Mutex
    40  	DiffValue           *Diff
    41  	DiffLock            *sync.RWMutex
    42  	StateValue          *State
    43  	StateLock           *sync.RWMutex
    44  
    45  	once sync.Once
    46  }
    47  
    48  func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} {
    49  	// This can happen during tests. During tests, we just block forever.
    50  	if ctx.StopContext == nil {
    51  		return nil
    52  	}
    53  
    54  	return ctx.StopContext.Done()
    55  }
    56  
    57  func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
    58  	for _, h := range ctx.Hooks {
    59  		action, err := fn(h)
    60  		if err != nil {
    61  			return err
    62  		}
    63  
    64  		switch action {
    65  		case HookActionContinue:
    66  			continue
    67  		case HookActionHalt:
    68  			// Return an early exit error to trigger an early exit
    69  			log.Printf("[WARN] Early exit triggered by hook: %T", h)
    70  			return EvalEarlyExitError{}
    71  		}
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  func (ctx *BuiltinEvalContext) Input() UIInput {
    78  	return ctx.InputValue
    79  }
    80  
    81  func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProvider, error) {
    82  	ctx.once.Do(ctx.init)
    83  
    84  	// If we already initialized, it is an error
    85  	if p := ctx.Provider(name); p != nil {
    86  		return nil, fmt.Errorf("Provider '%s' already initialized", name)
    87  	}
    88  
    89  	// Warning: make sure to acquire these locks AFTER the call to Provider
    90  	// above, since it also acquires locks.
    91  	ctx.ProviderLock.Lock()
    92  	defer ctx.ProviderLock.Unlock()
    93  
    94  	p, err := ctx.Components.ResourceProvider(typeName, name)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	ctx.ProviderCache[name] = p
   100  	return p, nil
   101  }
   102  
   103  func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
   104  	ctx.once.Do(ctx.init)
   105  
   106  	ctx.ProviderLock.Lock()
   107  	defer ctx.ProviderLock.Unlock()
   108  
   109  	return ctx.ProviderCache[n]
   110  }
   111  
   112  func (ctx *BuiltinEvalContext) CloseProvider(n string) error {
   113  	ctx.once.Do(ctx.init)
   114  
   115  	ctx.ProviderLock.Lock()
   116  	defer ctx.ProviderLock.Unlock()
   117  
   118  	var provider interface{}
   119  	provider = ctx.ProviderCache[n]
   120  	if provider != nil {
   121  		if p, ok := provider.(ResourceProviderCloser); ok {
   122  			delete(ctx.ProviderCache, n)
   123  			return p.Close()
   124  		}
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  func (ctx *BuiltinEvalContext) ConfigureProvider(
   131  	n string, cfg *ResourceConfig) error {
   132  	p := ctx.Provider(n)
   133  	if p == nil {
   134  		return fmt.Errorf("Provider '%s' not initialized", n)
   135  	}
   136  	return p.Configure(cfg)
   137  }
   138  
   139  func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {
   140  	ctx.ProviderLock.Lock()
   141  	defer ctx.ProviderLock.Unlock()
   142  
   143  	// Make a copy of the path so we can safely edit it
   144  	path := ctx.Path()
   145  	pathCopy := make([]string, len(path)+1)
   146  	copy(pathCopy, path)
   147  
   148  	// Go up the tree.
   149  	for i := len(path) - 1; i >= 0; i-- {
   150  		pathCopy[i+1] = n
   151  		k := PathCacheKey(pathCopy[:i+2])
   152  		if v, ok := ctx.ProviderInputConfig[k]; ok {
   153  			return v
   154  		}
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) {
   161  	providerPath := make([]string, len(ctx.Path())+1)
   162  	copy(providerPath, ctx.Path())
   163  	providerPath[len(providerPath)-1] = n
   164  
   165  	// Save the configuration
   166  	ctx.ProviderLock.Lock()
   167  	ctx.ProviderInputConfig[PathCacheKey(providerPath)] = c
   168  	ctx.ProviderLock.Unlock()
   169  }
   170  
   171  func (ctx *BuiltinEvalContext) InitProvisioner(
   172  	n string) (ResourceProvisioner, error) {
   173  	ctx.once.Do(ctx.init)
   174  
   175  	// If we already initialized, it is an error
   176  	if p := ctx.Provisioner(n); p != nil {
   177  		return nil, fmt.Errorf("Provisioner '%s' already initialized", n)
   178  	}
   179  
   180  	// Warning: make sure to acquire these locks AFTER the call to Provisioner
   181  	// above, since it also acquires locks.
   182  	ctx.ProvisionerLock.Lock()
   183  	defer ctx.ProvisionerLock.Unlock()
   184  
   185  	provPath := make([]string, len(ctx.Path())+1)
   186  	copy(provPath, ctx.Path())
   187  	provPath[len(provPath)-1] = n
   188  	key := PathCacheKey(provPath)
   189  
   190  	p, err := ctx.Components.ResourceProvisioner(n, key)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	ctx.ProvisionerCache[key] = p
   196  	return p, nil
   197  }
   198  
   199  func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner {
   200  	ctx.once.Do(ctx.init)
   201  
   202  	ctx.ProvisionerLock.Lock()
   203  	defer ctx.ProvisionerLock.Unlock()
   204  
   205  	provPath := make([]string, len(ctx.Path())+1)
   206  	copy(provPath, ctx.Path())
   207  	provPath[len(provPath)-1] = n
   208  
   209  	return ctx.ProvisionerCache[PathCacheKey(provPath)]
   210  }
   211  
   212  func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error {
   213  	ctx.once.Do(ctx.init)
   214  
   215  	ctx.ProvisionerLock.Lock()
   216  	defer ctx.ProvisionerLock.Unlock()
   217  
   218  	provPath := make([]string, len(ctx.Path())+1)
   219  	copy(provPath, ctx.Path())
   220  	provPath[len(provPath)-1] = n
   221  
   222  	var prov interface{}
   223  	prov = ctx.ProvisionerCache[PathCacheKey(provPath)]
   224  	if prov != nil {
   225  		if p, ok := prov.(ResourceProvisionerCloser); ok {
   226  			delete(ctx.ProvisionerCache, PathCacheKey(provPath))
   227  			return p.Close()
   228  		}
   229  	}
   230  
   231  	return nil
   232  }
   233  
   234  func (ctx *BuiltinEvalContext) Interpolate(
   235  	cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) {
   236  
   237  	if cfg != nil {
   238  		scope := &InterpolationScope{
   239  			Path:     ctx.Path(),
   240  			Resource: r,
   241  		}
   242  
   243  		vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
   244  		if err != nil {
   245  			return nil, err
   246  		}
   247  
   248  		// Do the interpolation
   249  		if err := cfg.Interpolate(vs); err != nil {
   250  			return nil, err
   251  		}
   252  	}
   253  
   254  	result := NewResourceConfig(cfg)
   255  	result.interpolateForce()
   256  	return result, nil
   257  }
   258  
   259  func (ctx *BuiltinEvalContext) InterpolateProvider(
   260  	pc *config.ProviderConfig, r *Resource) (*ResourceConfig, error) {
   261  
   262  	var cfg *config.RawConfig
   263  
   264  	if pc != nil && pc.RawConfig != nil {
   265  		path := pc.Path
   266  		if len(path) == 0 {
   267  			path = ctx.Path()
   268  		}
   269  
   270  		scope := &InterpolationScope{
   271  			Path:     path,
   272  			Resource: r,
   273  		}
   274  
   275  		cfg = pc.RawConfig
   276  
   277  		vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
   278  		if err != nil {
   279  			return nil, err
   280  		}
   281  
   282  		// Do the interpolation
   283  		if err := cfg.Interpolate(vs); err != nil {
   284  			return nil, err
   285  		}
   286  	}
   287  
   288  	result := NewResourceConfig(cfg)
   289  	result.interpolateForce()
   290  	return result, nil
   291  }
   292  
   293  func (ctx *BuiltinEvalContext) Path() []string {
   294  	return ctx.PathValue
   295  }
   296  
   297  func (ctx *BuiltinEvalContext) SetVariables(n string, vs map[string]interface{}) {
   298  	ctx.InterpolaterVarLock.Lock()
   299  	defer ctx.InterpolaterVarLock.Unlock()
   300  
   301  	path := make([]string, len(ctx.Path())+1)
   302  	copy(path, ctx.Path())
   303  	path[len(path)-1] = n
   304  	key := PathCacheKey(path)
   305  
   306  	vars := ctx.InterpolaterVars[key]
   307  	if vars == nil {
   308  		vars = make(map[string]interface{})
   309  		ctx.InterpolaterVars[key] = vars
   310  	}
   311  
   312  	for k, v := range vs {
   313  		vars[k] = v
   314  	}
   315  }
   316  
   317  func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) {
   318  	return ctx.DiffValue, ctx.DiffLock
   319  }
   320  
   321  func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) {
   322  	return ctx.StateValue, ctx.StateLock
   323  }
   324  
   325  func (ctx *BuiltinEvalContext) init() {
   326  }