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

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