terraform: more eval stuff

This commit is contained in:
Mitchell Hashimoto 2015-02-03 20:46:11 -05:00
parent 3f0eb528de
commit a8364dd0fc
6 changed files with 159 additions and 60 deletions

View File

@ -1,24 +1,5 @@
package terraform 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 // EvalNode is the interface that must be implemented by graph nodes to
// evaluate/execute. // evaluate/execute.
type EvalNode interface { type EvalNode interface {
@ -41,40 +22,3 @@ type EvalNode interface {
type GraphNodeEvalable interface { type GraphNodeEvalable interface {
EvalTree() EvalNode 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
}

59
terraform/eval_context.go Normal file
View File

@ -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
}

View File

@ -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)
}

25
terraform/eval_filter.go Normal file
View File

@ -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)
}

View File

@ -13,7 +13,7 @@ type EvalType uint32
const ( const (
EvalTypeInvalid EvalType = 0 EvalTypeInvalid EvalType = 0
EvalTypeNull EvalType = 1 << iota EvalTypeNull EvalType = 1 << iota // nil
EvalTypeConfig EvalTypeConfig // *ResourceConfig
EvalTypeResourceProvider EvalTypeResourceProvider // ResourceProvider
) )

View File

@ -118,6 +118,22 @@ func (n *graphNodeOrphanResource) ProvidedBy() string {
return resourceProvider(n.ResourceName) 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 { func (n *graphNodeOrphanResource) dependableName() string {
return n.ResourceName return n.ResourceName
} }