From f7bc33812eb0988c7765a79573ea3cc4f77f11ed Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 2 Jul 2014 16:27:06 -0700 Subject: [PATCH] terraform: use a panic mechanism for handling hooks --- terraform/hook.go | 16 ++++++++++++ terraform/terraform.go | 57 +++++++++++++----------------------------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/terraform/hook.go b/terraform/hook.go index 5aad18887..4c4c1a776 100644 --- a/terraform/hook.go +++ b/terraform/hook.go @@ -65,3 +65,19 @@ func (*NilHook) PreRefresh(string, *ResourceState) (HookAction, error) { func (*NilHook) PostRefresh(string, *ResourceState) (HookAction, error) { 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) + } +} diff --git a/terraform/terraform.go b/terraform/terraform.go index 9d97a0253..8822a0843 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -1,7 +1,6 @@ package terraform import ( - "errors" "fmt" "log" "sync" @@ -24,10 +23,6 @@ type Terraform struct { // tree internally on the Terraform structure. 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 // a Terraform structure. type Config struct { @@ -35,10 +30,6 @@ type Config struct { Providers map[string]ResourceProviderFactory } -func init() { - genericWalkStop = errors.New("genericWalkStop") -} - // New creates a new Terraform structure, initializes resource providers // 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) { for _, h := range t.hooks { - // TODO: return value - h.PreRefresh(r.Id, r.State) + handleHook(h.PreRefresh(r.Id, r.State)) } rs, err := r.Provider.Refresh(r.State) @@ -203,8 +193,7 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc { l.Unlock() for _, h := range t.hooks { - // TODO: return value - h.PostRefresh(r.Id, rs) + handleHook(h.PostRefresh(r.Id, rs)) } return nil, nil @@ -239,15 +228,7 @@ func (t *Terraform) applyWalkFn( // anything and that the diff has no computed values (pre-computed) for _, h := range t.hooks { - a, err := h.PreApply(r.Id, r.State, diff) - if err != nil { - return nil, err - } - - switch a { - case HookActionHalt: - return nil, genericWalkStop - } + handleHook(h.PreApply(r.Id, r.State, diff)) } // With the completed diff, apply! @@ -291,15 +272,7 @@ func (t *Terraform) applyWalkFn( r.State = rs for _, h := range t.hooks { - a, err := h.PostApply(r.Id, r.State) - if err != nil { - return nil, err - } - - switch a { - case HookActionHalt: - return nil, genericWalkStop - } + handleHook(h.PostApply(r.Id, r.State)) } // Determine the new state and update variables @@ -324,8 +297,7 @@ func (t *Terraform) planWalkFn(result *Plan, opts *PlanOpts) depgraph.WalkFunc { var diff *ResourceDiff for _, h := range t.hooks { - // TODO: return value - h.PreDiff(r.Id, r.State) + handleHook(h.PreDiff(r.Id, r.State)) } if opts.Destroy { @@ -358,8 +330,7 @@ func (t *Terraform) planWalkFn(result *Plan, opts *PlanOpts) depgraph.WalkFunc { l.Unlock() for _, h := range t.hooks { - // TODO: return value - h.PostDiff(r.Id, diff) + handleHook(h.PostDiff(r.Id, diff)) } // Determine the new state and update variables @@ -446,15 +417,21 @@ func (t *Terraform) genericWalkFn( 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 log.Printf("[INFO] Walking: %s", rn.Resource.Id) newVars, err := cb(rn.Resource) if err != nil { - if err == genericWalkStop { - atomic.StoreUint32(&stop, 1) - return nil - } - return err }