terraform: refresh hooks
This commit is contained in:
parent
5ba52ceac4
commit
379c37dd06
|
@ -26,6 +26,7 @@ type ContextOpts struct {
|
|||
// perform operations on infrastructure. This structure is built using
|
||||
// NewContext. See the documentation for that.
|
||||
type Context2 struct {
|
||||
hooks []Hook
|
||||
module *module.Tree
|
||||
providers map[string]ResourceProviderFactory
|
||||
provisioners map[string]ResourceProvisionerFactory
|
||||
|
@ -41,6 +42,7 @@ type Context2 struct {
|
|||
// the values themselves.
|
||||
func NewContext2(opts *ContextOpts) *Context2 {
|
||||
return &Context2{
|
||||
hooks: opts.Hooks,
|
||||
module: opts.Module,
|
||||
providers: opts.Providers,
|
||||
provisioners: opts.Provisioners,
|
||||
|
|
|
@ -123,12 +123,11 @@ func TestContext2Refresh_ignoreUncreated(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextRefresh_hook(t *testing.T) {
|
||||
func TestContext2Refresh_hook(t *testing.T) {
|
||||
h := new(MockHook)
|
||||
p := testProvider("aws")
|
||||
m := testModule(t, "refresh-basic")
|
||||
ctx := testContext(t, &ContextOpts{
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
Hooks: []Hook{h},
|
||||
Providers: map[string]ResourceProviderFactory{
|
||||
|
@ -162,6 +161,7 @@ func TestContextRefresh_hook(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextRefresh_modules(t *testing.T) {
|
||||
p := testProvider("aws")
|
||||
m := testModule(t, "refresh-modules")
|
||||
|
|
|
@ -27,6 +27,12 @@ type GraphNodeEvalable interface {
|
|||
EvalTree() EvalNode
|
||||
}
|
||||
|
||||
// EvalEarlyExitError is a special error return value that can be returned
|
||||
// by eval nodes that does an early exit.
|
||||
type EvalEarlyExitError struct{}
|
||||
|
||||
func (EvalEarlyExitError) Error() string { return "early exit" }
|
||||
|
||||
// Eval evaluates the given EvalNode with the given context, properly
|
||||
// evaluating all args in the correct order.
|
||||
func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||
|
|
|
@ -11,6 +11,10 @@ type EvalContext interface {
|
|||
// Path is the current module path.
|
||||
Path() []string
|
||||
|
||||
// Hook is used to call hook methods. The callback is called for each
|
||||
// hook and should return the hook action to take and the error.
|
||||
Hook(func(Hook) (HookAction, error)) error
|
||||
|
||||
// InitProvider initializes the provider with the given name and
|
||||
// returns the implementation of the resource provider or an error.
|
||||
//
|
||||
|
@ -53,6 +57,9 @@ type EvalContext interface {
|
|||
// MockEvalContext is a mock version of EvalContext that can be used
|
||||
// for tests.
|
||||
type MockEvalContext struct {
|
||||
HookCalled bool
|
||||
HookError error
|
||||
|
||||
InitProviderCalled bool
|
||||
InitProviderName string
|
||||
InitProviderProvider ResourceProvider
|
||||
|
@ -94,6 +101,11 @@ type MockEvalContext struct {
|
|||
StateLock *sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
||||
c.HookCalled = true
|
||||
return c.HookError
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
||||
c.InitProviderCalled = true
|
||||
c.InitProviderName = n
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
type BuiltinEvalContext struct {
|
||||
PathValue []string
|
||||
Interpolater *Interpolater
|
||||
Hooks []Hook
|
||||
Providers map[string]ResourceProviderFactory
|
||||
ProviderCache map[string]ResourceProvider
|
||||
ProviderConfigCache map[string]*ResourceConfig
|
||||
|
@ -27,6 +28,25 @@ type BuiltinEvalContext struct {
|
|||
once sync.Once
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
||||
for _, h := range ctx.Hooks {
|
||||
action, err := fn(h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch action {
|
||||
case HookActionContinue:
|
||||
continue
|
||||
case HookActionHalt:
|
||||
// Return an early exit error to trigger an early exit
|
||||
return EvalEarlyExitError{}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
||||
ctx.once.Do(ctx.init)
|
||||
|
||||
|
|
|
@ -27,8 +27,29 @@ func (n *EvalRefresh) Eval(
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
n.Info.ModulePath = ctx.Path()
|
||||
return provider.Refresh(n.Info, state)
|
||||
// Call pre-refresh hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreRefresh(n.Info, state)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Refresh!
|
||||
state, err = provider.Refresh(n.Info, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Call post-refresh hook
|
||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostRefresh(n.Info, state)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (n *EvalRefresh) Type() EvalType {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package terraform
|
||||
|
||||
// EvalInstanceInfo is an EvalNode implementation that fills in the
|
||||
// InstanceInfo as much as it can.
|
||||
type EvalInstanceInfo struct {
|
||||
Info *InstanceInfo
|
||||
}
|
||||
|
||||
func (n *EvalInstanceInfo) Args() ([]EvalNode, []EvalType) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalInstanceInfo) Eval(
|
||||
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||
n.Info.ModulePath = ctx.Path()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *EvalInstanceInfo) Type() EvalType {
|
||||
return EvalTypeNull
|
||||
}
|
|
@ -36,6 +36,7 @@ func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
|
|||
|
||||
return &BuiltinEvalContext{
|
||||
PathValue: g.Path,
|
||||
Hooks: w.Context.hooks,
|
||||
Providers: w.Context.providers,
|
||||
ProviderCache: w.providerCache,
|
||||
ProviderConfigCache: w.providerConfigCache,
|
||||
|
|
|
@ -96,6 +96,10 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
})
|
||||
}
|
||||
|
||||
// Build instance info
|
||||
info := &InstanceInfo{Id: n.stateId(), Type: n.Resource.Type}
|
||||
seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
|
||||
|
||||
// Refresh the resource
|
||||
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
||||
Ops: []walkOperation{walkRefresh},
|
||||
|
@ -104,9 +108,9 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
ResourceType: n.Resource.Type,
|
||||
Dependencies: n.DependentOn(),
|
||||
State: &EvalRefresh{
|
||||
Info: info,
|
||||
Provider: &EvalGetProvider{Name: n.ProvidedBy()},
|
||||
State: &EvalReadState{Name: n.stateId()},
|
||||
Info: &InstanceInfo{Id: n.stateId(), Type: n.Resource.Type},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue