From a8364dd0fc028ab55e07017c01840b5641363cf8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Feb 2015 20:46:11 -0500 Subject: [PATCH] terraform: more eval stuff --- terraform/eval.go | 56 ----------------------------- terraform/eval_context.go | 59 +++++++++++++++++++++++++++++++ terraform/eval_context_builtin.go | 55 ++++++++++++++++++++++++++++ terraform/eval_filter.go | 25 +++++++++++++ terraform/eval_type.go | 8 ++--- terraform/transform_orphan.go | 16 +++++++++ 6 files changed, 159 insertions(+), 60 deletions(-) create mode 100644 terraform/eval_context.go create mode 100644 terraform/eval_context_builtin.go create mode 100644 terraform/eval_filter.go diff --git a/terraform/eval.go b/terraform/eval.go index 5878a369c..eb1fe5a60 100644 --- a/terraform/eval.go +++ b/terraform/eval.go @@ -1,24 +1,5 @@ package terraform -import ( - "github.com/hashicorp/terraform/config" -) - -// EvalContext is the interface that is given to eval nodes to execute. -type EvalContext interface { - // InitProvider initializes the provider with the given name and - // returns the implementation of the resource provider or an error. - InitProvider(string) (ResourceProvider, error) - - // Provider gets the provider instance with the given name (already - // initialized) or returns nil if the provider isn't initialized. - Provider(string) ResourceProvider - - // Interpolate takes the given raw configuration and completes - // the interpolations, returning the processed ResourceConfig. - Interpolate(*config.RawConfig) (*ResourceConfig, error) -} - // EvalNode is the interface that must be implemented by graph nodes to // evaluate/execute. type EvalNode interface { @@ -41,40 +22,3 @@ type EvalNode interface { type GraphNodeEvalable interface { EvalTree() EvalNode } - -// MockEvalContext is a mock version of EvalContext that can be used -// for tests. -type MockEvalContext struct { - InitProviderCalled bool - InitProviderName string - InitProviderProvider ResourceProvider - InitProviderError error - - ProviderCalled bool - ProviderName string - ProviderProvider ResourceProvider - - InterpolateCalled bool - InterpolateConfig *config.RawConfig - InterpolateConfigResult *ResourceConfig - InterpolateError error -} - -func (c *MockEvalContext) InitProvider(n string) (ResourceProvider, error) { - c.InitProviderCalled = true - c.InitProviderName = n - return c.InitProviderProvider, c.InitProviderError -} - -func (c *MockEvalContext) Provider(n string) ResourceProvider { - c.ProviderCalled = true - c.ProviderName = n - return c.ProviderProvider -} - -func (c *MockEvalContext) Interpolate( - config *config.RawConfig) (*ResourceConfig, error) { - c.InterpolateCalled = true - c.InterpolateConfig = config - return c.InterpolateConfigResult, c.InterpolateError -} diff --git a/terraform/eval_context.go b/terraform/eval_context.go new file mode 100644 index 000000000..a41941eea --- /dev/null +++ b/terraform/eval_context.go @@ -0,0 +1,59 @@ +package terraform + +import ( + "github.com/hashicorp/terraform/config" +) + +// EvalContext is the interface that is given to eval nodes to execute. +type EvalContext interface { + // InitProvider initializes the provider with the given name and + // returns the implementation of the resource provider or an error. + // + // It is an error to initialize the same provider more than once. + InitProvider(string) (ResourceProvider, error) + + // Provider gets the provider instance with the given name (already + // initialized) or returns nil if the provider isn't initialized. + Provider(string) ResourceProvider + + // Interpolate takes the given raw configuration and completes + // the interpolations, returning the processed ResourceConfig. + Interpolate(*config.RawConfig) (*ResourceConfig, error) +} + +// MockEvalContext is a mock version of EvalContext that can be used +// for tests. +type MockEvalContext struct { + InitProviderCalled bool + InitProviderName string + InitProviderProvider ResourceProvider + InitProviderError error + + ProviderCalled bool + ProviderName string + ProviderProvider ResourceProvider + + InterpolateCalled bool + InterpolateConfig *config.RawConfig + InterpolateConfigResult *ResourceConfig + InterpolateError error +} + +func (c *MockEvalContext) InitProvider(n string) (ResourceProvider, error) { + c.InitProviderCalled = true + c.InitProviderName = n + return c.InitProviderProvider, c.InitProviderError +} + +func (c *MockEvalContext) Provider(n string) ResourceProvider { + c.ProviderCalled = true + c.ProviderName = n + return c.ProviderProvider +} + +func (c *MockEvalContext) Interpolate( + config *config.RawConfig) (*ResourceConfig, error) { + c.InterpolateCalled = true + c.InterpolateConfig = config + return c.InterpolateConfigResult, c.InterpolateError +} diff --git a/terraform/eval_context_builtin.go b/terraform/eval_context_builtin.go new file mode 100644 index 000000000..05b77c08d --- /dev/null +++ b/terraform/eval_context_builtin.go @@ -0,0 +1,55 @@ +package terraform + +import ( + "fmt" + "sync" + + "github.com/hashicorp/terraform/config" +) + +// BuiltinEvalContext is an EvalContext implementation that is used by +// Terraform by default. +type BuiltinEvalContext struct { + Providers map[string]ResourceProviderFactory + + providers map[string]ResourceProvider + once sync.Once +} + +func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) { + ctx.once.Do(ctx.init) + + if p := ctx.Provider(n); p != nil { + return nil, fmt.Errorf("Provider '%s' already initialized", n) + } + + f, ok := ctx.Providers[n] + if !ok { + return nil, fmt.Errorf("Provider '%s' not found", n) + } + + return f() +} + +func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider { + ctx.once.Do(ctx.init) + return ctx.providers[n] +} + +func (ctx *BuiltinEvalContext) Interpolate( + config *config.RawConfig) (*ResourceConfig, error) { + // TODO: Actual interpolation, for now we just return it as-is + return NewResourceConfig(config), nil +} + +func (ctx *BuiltinEvalContext) init() { + // We nil-check the things below because they're meant to be configured, + // and we just default them to non-nil. + if ctx.Providers == nil { + ctx.Providers = make(map[string]ResourceProviderFactory) + } + + // We always reset the things below since we only call this once and + // they can't be initialized externally. + ctx.providers = make(map[string]ResourceProvider) +} diff --git a/terraform/eval_filter.go b/terraform/eval_filter.go new file mode 100644 index 000000000..711c625c8 --- /dev/null +++ b/terraform/eval_filter.go @@ -0,0 +1,25 @@ +package terraform + +// EvalNodeFilterFunc is the callback used to replace a node with +// another to node. To not do the replacement, just return the input node. +type EvalNodeFilterFunc func(EvalNode) EvalNode + +// EvalNodeFilterable is an interface that can be implemented by +// EvalNodes to allow filtering of sub-elements. Note that this isn't +// a common thing to implement and you probably don't need it. +type EvalNodeFilterable interface { + EvalNode + Filter(EvalNodeFilterFunc) +} + +// EvalFilter runs the filter on the given node and returns the +// final filtered value. This should be called rather than checking +// the EvalNode directly since this will properly handle EvalNodeFilterables. +func EvalFilter(node EvalNode, fn EvalNodeFilterFunc) EvalNode { + if f, ok := node.(EvalNodeFilterable); ok { + f.Filter(fn) + return node + } + + return fn(node) +} diff --git a/terraform/eval_type.go b/terraform/eval_type.go index cf25cfc12..ee232939e 100644 --- a/terraform/eval_type.go +++ b/terraform/eval_type.go @@ -12,8 +12,8 @@ package terraform type EvalType uint32 const ( - EvalTypeInvalid EvalType = 0 - EvalTypeNull EvalType = 1 << iota - EvalTypeConfig - EvalTypeResourceProvider + EvalTypeInvalid EvalType = 0 + EvalTypeNull EvalType = 1 << iota // nil + EvalTypeConfig // *ResourceConfig + EvalTypeResourceProvider // ResourceProvider ) diff --git a/terraform/transform_orphan.go b/terraform/transform_orphan.go index 205f00204..5ce5a81fe 100644 --- a/terraform/transform_orphan.go +++ b/terraform/transform_orphan.go @@ -118,6 +118,22 @@ func (n *graphNodeOrphanResource) ProvidedBy() string { return resourceProvider(n.ResourceName) } +// GraphNodeEvalable impl. +func (n *graphNodeOrphanResource) EvalTree() EvalNode { + return nil + /* + TODO + return &EvalSequence{ + Nodes: []EvalNode{ + &EvalRefresh{}, + &EvalDiff{}, + &EvalApply{}, + &EvalCommitState{}, + }, + } + */ +} + func (n *graphNodeOrphanResource) dependableName() string { return n.ResourceName }