github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/terraform/eval_context_builtin.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sync"
     7  
     8  	"github.com/hashicorp/terraform/config"
     9  )
    10  
    11  // BuiltinEvalContext is an EvalContext implementation that is used by
    12  // Terraform by default.
    13  type BuiltinEvalContext struct {
    14  	PathValue           []string
    15  	Interpolater        *Interpolater
    16  	Hooks               []Hook
    17  	InputValue          UIInput
    18  	Providers           map[string]ResourceProviderFactory
    19  	ProviderCache       map[string]ResourceProvider
    20  	ProviderConfigCache map[string]*ResourceConfig
    21  	ProviderInputConfig map[string]map[string]interface{}
    22  	ProviderLock        *sync.Mutex
    23  	Provisioners        map[string]ResourceProvisionerFactory
    24  	ProvisionerCache    map[string]ResourceProvisioner
    25  	ProvisionerLock     *sync.Mutex
    26  	DiffValue           *Diff
    27  	DiffLock            *sync.RWMutex
    28  	StateValue          *State
    29  	StateLock           *sync.RWMutex
    30  
    31  	once sync.Once
    32  }
    33  
    34  func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
    35  	for _, h := range ctx.Hooks {
    36  		action, err := fn(h)
    37  		if err != nil {
    38  			return err
    39  		}
    40  
    41  		switch action {
    42  		case HookActionContinue:
    43  			continue
    44  		case HookActionHalt:
    45  			// Return an early exit error to trigger an early exit
    46  			log.Printf("[WARN] Early exit triggered by hook: %T", h)
    47  			return EvalEarlyExitError{}
    48  		}
    49  	}
    50  
    51  	return nil
    52  }
    53  
    54  func (ctx *BuiltinEvalContext) Input() UIInput {
    55  	return ctx.InputValue
    56  }
    57  
    58  func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) {
    59  	ctx.once.Do(ctx.init)
    60  
    61  	// If we already initialized, it is an error
    62  	if p := ctx.Provider(n); p != nil {
    63  		return nil, fmt.Errorf("Provider '%s' already initialized", n)
    64  	}
    65  
    66  	// Warning: make sure to acquire these locks AFTER the call to Provider
    67  	// above, since it also acquires locks.
    68  	ctx.ProviderLock.Lock()
    69  	defer ctx.ProviderLock.Unlock()
    70  
    71  	f, ok := ctx.Providers[n]
    72  	if !ok {
    73  		return nil, fmt.Errorf("Provider '%s' not found", n)
    74  	}
    75  
    76  	p, err := f()
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	providerPath := make([]string, len(ctx.Path())+1)
    82  	copy(providerPath, ctx.Path())
    83  	providerPath[len(providerPath)-1] = n
    84  
    85  	ctx.ProviderCache[PathCacheKey(providerPath)] = p
    86  	return p, nil
    87  }
    88  
    89  func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
    90  	ctx.once.Do(ctx.init)
    91  
    92  	ctx.ProviderLock.Lock()
    93  	defer ctx.ProviderLock.Unlock()
    94  
    95  	providerPath := make([]string, len(ctx.Path())+1)
    96  	copy(providerPath, ctx.Path())
    97  	providerPath[len(providerPath)-1] = n
    98  
    99  	return ctx.ProviderCache[PathCacheKey(providerPath)]
   100  }
   101  
   102  func (ctx *BuiltinEvalContext) ConfigureProvider(
   103  	n string, cfg *ResourceConfig) error {
   104  	p := ctx.Provider(n)
   105  	if p == nil {
   106  		return fmt.Errorf("Provider '%s' not initialized", n)
   107  	}
   108  
   109  	providerPath := make([]string, len(ctx.Path())+1)
   110  	copy(providerPath, ctx.Path())
   111  	providerPath[len(providerPath)-1] = n
   112  
   113  	// Save the configuration
   114  	ctx.ProviderLock.Lock()
   115  	ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg
   116  	ctx.ProviderLock.Unlock()
   117  
   118  	return p.Configure(cfg)
   119  }
   120  
   121  func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {
   122  	ctx.ProviderLock.Lock()
   123  	defer ctx.ProviderLock.Unlock()
   124  
   125  	return ctx.ProviderInputConfig[n]
   126  }
   127  
   128  func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) {
   129  	ctx.ProviderLock.Lock()
   130  	defer ctx.ProviderLock.Unlock()
   131  
   132  	ctx.ProviderInputConfig[n] = c
   133  }
   134  
   135  func (ctx *BuiltinEvalContext) ParentProviderConfig(n string) *ResourceConfig {
   136  	ctx.ProviderLock.Lock()
   137  	defer ctx.ProviderLock.Unlock()
   138  
   139  	// Make a copy of the path so we can safely edit it
   140  	path := ctx.Path()
   141  	pathCopy := make([]string, len(path)+1)
   142  	copy(pathCopy, path)
   143  
   144  	// Go up the tree.
   145  	for i := len(path) - 1; i >= 0; i-- {
   146  		pathCopy[i+1] = n
   147  		k := PathCacheKey(pathCopy[:i+2])
   148  		if v, ok := ctx.ProviderConfigCache[k]; ok {
   149  			return v
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func (ctx *BuiltinEvalContext) InitProvisioner(
   157  	n string) (ResourceProvisioner, error) {
   158  	ctx.once.Do(ctx.init)
   159  
   160  	// If we already initialized, it is an error
   161  	if p := ctx.Provisioner(n); p != nil {
   162  		return nil, fmt.Errorf("Provisioner '%s' already initialized", n)
   163  	}
   164  
   165  	// Warning: make sure to acquire these locks AFTER the call to Provisioner
   166  	// above, since it also acquires locks.
   167  	ctx.ProvisionerLock.Lock()
   168  	defer ctx.ProvisionerLock.Unlock()
   169  
   170  	f, ok := ctx.Provisioners[n]
   171  	if !ok {
   172  		return nil, fmt.Errorf("Provisioner '%s' not found", n)
   173  	}
   174  
   175  	p, err := f()
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	provPath := make([]string, len(ctx.Path())+1)
   181  	copy(provPath, ctx.Path())
   182  	provPath[len(provPath)-1] = n
   183  
   184  	ctx.ProvisionerCache[PathCacheKey(provPath)] = p
   185  	return p, nil
   186  }
   187  
   188  func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner {
   189  	ctx.once.Do(ctx.init)
   190  
   191  	ctx.ProvisionerLock.Lock()
   192  	defer ctx.ProvisionerLock.Unlock()
   193  
   194  	provPath := make([]string, len(ctx.Path())+1)
   195  	copy(provPath, ctx.Path())
   196  	provPath[len(provPath)-1] = n
   197  
   198  	return ctx.ProvisionerCache[PathCacheKey(provPath)]
   199  }
   200  
   201  func (ctx *BuiltinEvalContext) Interpolate(
   202  	cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) {
   203  	if cfg != nil {
   204  		scope := &InterpolationScope{
   205  			Path:     ctx.Path(),
   206  			Resource: r,
   207  		}
   208  		vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
   209  		if err != nil {
   210  			return nil, err
   211  		}
   212  
   213  		// Do the interpolation
   214  		if err := cfg.Interpolate(vs); err != nil {
   215  			return nil, err
   216  		}
   217  	}
   218  
   219  	result := NewResourceConfig(cfg)
   220  	result.interpolateForce()
   221  	return result, nil
   222  }
   223  
   224  func (ctx *BuiltinEvalContext) Path() []string {
   225  	return ctx.PathValue
   226  }
   227  
   228  func (ctx *BuiltinEvalContext) SetVariables(vs map[string]string) {
   229  	for k, v := range vs {
   230  		ctx.Interpolater.Variables[k] = v
   231  	}
   232  }
   233  
   234  func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) {
   235  	return ctx.DiffValue, ctx.DiffLock
   236  }
   237  
   238  func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) {
   239  	return ctx.StateValue, ctx.StateLock
   240  }
   241  
   242  func (ctx *BuiltinEvalContext) init() {
   243  	// We nil-check the things below because they're meant to be configured,
   244  	// and we just default them to non-nil.
   245  	if ctx.Providers == nil {
   246  		ctx.Providers = make(map[string]ResourceProviderFactory)
   247  	}
   248  }