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