terraform: use a panic mechanism for handling hooks

This commit is contained in:
Mitchell Hashimoto 2014-07-02 16:27:06 -07:00
parent 733752122a
commit f7bc33812e
2 changed files with 33 additions and 40 deletions

View File

@ -65,3 +65,19 @@ func (*NilHook) PreRefresh(string, *ResourceState) (HookAction, error) {
func (*NilHook) PostRefresh(string, *ResourceState) (HookAction, error) { func (*NilHook) PostRefresh(string, *ResourceState) (HookAction, error) {
return HookActionContinue, nil return HookActionContinue, nil
} }
// handleHook turns hook actions into panics. This lets you use the
// panic/recover mechanism in Go as a flow control mechanism for hook
// actions.
func handleHook(a HookAction, err error) {
if err != nil {
// TODO: handle errors
}
switch a {
case HookActionContinue:
return
case HookActionHalt:
panic(HookActionHalt)
}
}

View File

@ -1,7 +1,6 @@
package terraform package terraform
import ( import (
"errors"
"fmt" "fmt"
"log" "log"
"sync" "sync"
@ -24,10 +23,6 @@ type Terraform struct {
// tree internally on the Terraform structure. // tree internally on the Terraform structure.
type genericWalkFunc func(*Resource) (map[string]string, error) type genericWalkFunc func(*Resource) (map[string]string, error)
// genericWalkStop is a special return value that can be returned from a
// genericWalkFunc that causes the walk to cease immediately.
var genericWalkStop error
// Config is the configuration that must be given to instantiate // Config is the configuration that must be given to instantiate
// a Terraform structure. // a Terraform structure.
type Config struct { type Config struct {
@ -35,10 +30,6 @@ type Config struct {
Providers map[string]ResourceProviderFactory Providers map[string]ResourceProviderFactory
} }
func init() {
genericWalkStop = errors.New("genericWalkStop")
}
// New creates a new Terraform structure, initializes resource providers // New creates a new Terraform structure, initializes resource providers
// for the given configuration, etc. // for the given configuration, etc.
// //
@ -183,8 +174,7 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
cb := func(r *Resource) (map[string]string, error) { cb := func(r *Resource) (map[string]string, error) {
for _, h := range t.hooks { for _, h := range t.hooks {
// TODO: return value handleHook(h.PreRefresh(r.Id, r.State))
h.PreRefresh(r.Id, r.State)
} }
rs, err := r.Provider.Refresh(r.State) rs, err := r.Provider.Refresh(r.State)
@ -203,8 +193,7 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
l.Unlock() l.Unlock()
for _, h := range t.hooks { for _, h := range t.hooks {
// TODO: return value handleHook(h.PostRefresh(r.Id, rs))
h.PostRefresh(r.Id, rs)
} }
return nil, nil return nil, nil
@ -239,15 +228,7 @@ func (t *Terraform) applyWalkFn(
// anything and that the diff has no computed values (pre-computed) // anything and that the diff has no computed values (pre-computed)
for _, h := range t.hooks { for _, h := range t.hooks {
a, err := h.PreApply(r.Id, r.State, diff) handleHook(h.PreApply(r.Id, r.State, diff))
if err != nil {
return nil, err
}
switch a {
case HookActionHalt:
return nil, genericWalkStop
}
} }
// With the completed diff, apply! // With the completed diff, apply!
@ -291,15 +272,7 @@ func (t *Terraform) applyWalkFn(
r.State = rs r.State = rs
for _, h := range t.hooks { for _, h := range t.hooks {
a, err := h.PostApply(r.Id, r.State) handleHook(h.PostApply(r.Id, r.State))
if err != nil {
return nil, err
}
switch a {
case HookActionHalt:
return nil, genericWalkStop
}
} }
// Determine the new state and update variables // Determine the new state and update variables
@ -324,8 +297,7 @@ func (t *Terraform) planWalkFn(result *Plan, opts *PlanOpts) depgraph.WalkFunc {
var diff *ResourceDiff var diff *ResourceDiff
for _, h := range t.hooks { for _, h := range t.hooks {
// TODO: return value handleHook(h.PreDiff(r.Id, r.State))
h.PreDiff(r.Id, r.State)
} }
if opts.Destroy { if opts.Destroy {
@ -358,8 +330,7 @@ func (t *Terraform) planWalkFn(result *Plan, opts *PlanOpts) depgraph.WalkFunc {
l.Unlock() l.Unlock()
for _, h := range t.hooks { for _, h := range t.hooks {
// TODO: return value handleHook(h.PostDiff(r.Id, diff))
h.PostDiff(r.Id, diff)
} }
// Determine the new state and update variables // Determine the new state and update variables
@ -446,15 +417,21 @@ func (t *Terraform) genericWalkFn(
rn.Resource.Config = nil rn.Resource.Config = nil
} }
// Handle recovery of special panic scenarios
defer func() {
if v := recover(); v != nil {
if v == HookActionHalt {
atomic.StoreUint32(&stop, 1)
} else {
panic(v)
}
}
}()
// Call the callack // Call the callack
log.Printf("[INFO] Walking: %s", rn.Resource.Id) log.Printf("[INFO] Walking: %s", rn.Resource.Id)
newVars, err := cb(rn.Resource) newVars, err := cb(rn.Resource)
if err != nil { if err != nil {
if err == genericWalkStop {
atomic.StoreUint32(&stop, 1)
return nil
}
return err return err
} }