Commit 0df18df4 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/amazonebs: extract multistep, use that

parent 2dd5a982
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/mitchellh/goamz/aws" "github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
) )
...@@ -87,7 +88,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact { ...@@ -87,7 +88,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
state["ui"] = ui state["ui"] = ui
// Build the steps // Build the steps
steps := []Step{ steps := []multistep.Step{
&stepKeyPair{}, &stepKeyPair{},
&stepRunSourceInstance{}, &stepRunSourceInstance{},
&stepConnectSSH{}, &stepConnectSSH{},
...@@ -97,7 +98,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact { ...@@ -97,7 +98,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
} }
// Run! // Run!
RunSteps(state, steps) runner := &multistep.BasicRunner{Steps: steps}
runner.Run(state)
// Build the artifact and return it // Build the artifact and return it
return &artifact{state["amis"].(map[string]string)} return &artifact{state["amis"].(map[string]string)}
......
package amazonebs
// A StepAction determines the next step to take regarding multi-step actions.
type StepAction uint
const (
StepContinue StepAction = iota
StepHalt
)
// Step is a single step that is part of a potentially large sequence
// of other steps, responsible for performing some specific action.
type Step interface {
// Run is called to perform the action. The parameter is a "state bag"
// of untyped things. Please be very careful about type-checking the
// items in this bag.
//
// The return value determines whether multi-step sequences continue
// or should halt.
Run(map[string]interface{}) StepAction
// Cleanup is called in reverse order of the steps that have run
// and allow steps to clean up after themselves.
//
// The parameter is the same "state bag" as Run.
Cleanup(map[string]interface{})
}
// RunSteps runs a sequence of steps.
func RunSteps(state map[string]interface{}, steps []Step) {
for _, step := range steps {
action := step.Run(state)
defer step.Cleanup(state)
if action == StepHalt {
break
}
}
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
gossh "code.google.com/p/go.crypto/ssh" gossh "code.google.com/p/go.crypto/ssh"
"fmt" "fmt"
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh" "github.com/mitchellh/packer/communicator/ssh"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
...@@ -15,7 +16,7 @@ type stepConnectSSH struct { ...@@ -15,7 +16,7 @@ type stepConnectSSH struct {
conn net.Conn conn net.Conn
} }
func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction { func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(config) config := state["config"].(config)
instance := state["instance"].(*ec2.Instance) instance := state["instance"].(*ec2.Instance)
privateKey := state["privateKey"].(string) privateKey := state["privateKey"].(string)
...@@ -27,7 +28,7 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction { ...@@ -27,7 +28,7 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction {
err := keyring.AddPEMKey(privateKey) err := keyring.AddPEMKey(privateKey)
if err != nil { if err != nil {
ui.Say(fmt.Sprintf("Error setting up SSH config: %s", err)) ui.Say(fmt.Sprintf("Error setting up SSH config: %s", err))
return StepHalt return multistep.ActionHalt
} }
// Build the actual SSH client configuration // Build the actual SSH client configuration
...@@ -59,13 +60,13 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction { ...@@ -59,13 +60,13 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction {
if err != nil { if err != nil {
ui.Error(fmt.Sprintf("Error connecting to SSH: %s", err)) ui.Error(fmt.Sprintf("Error connecting to SSH: %s", err))
return StepHalt return multistep.ActionHalt
} }
// Set the communicator on the state bag so it can be used later // Set the communicator on the state bag so it can be used later
state["communicator"] = comm state["communicator"] = comm
return StepContinue return multistep.ActionContinue
} }
func (s *stepConnectSSH) Cleanup(map[string]interface{}) { func (s *stepConnectSSH) Cleanup(map[string]interface{}) {
......
...@@ -3,12 +3,13 @@ package amazonebs ...@@ -3,12 +3,13 @@ package amazonebs
import ( import (
"fmt" "fmt"
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
) )
type stepCreateAMI struct{} type stepCreateAMI struct{}
func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction { func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(config) config := state["config"].(config)
ec2conn := state["ec2"].(*ec2.EC2) ec2conn := state["ec2"].(*ec2.EC2)
instance := state["instance"].(*ec2.Instance) instance := state["instance"].(*ec2.Instance)
...@@ -24,7 +25,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction { ...@@ -24,7 +25,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction {
createResp, err := ec2conn.CreateImage(createOpts) createResp, err := ec2conn.CreateImage(createOpts)
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
// Set the AMI ID in the state // Set the AMI ID in the state
...@@ -39,7 +40,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction { ...@@ -39,7 +40,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction {
imageResp, err := ec2conn.Images([]string{createResp.ImageId}, ec2.NewFilter()) imageResp, err := ec2conn.Images([]string{createResp.ImageId}, ec2.NewFilter())
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
if imageResp.Images[0].State == "available" { if imageResp.Images[0].State == "available" {
...@@ -47,7 +48,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction { ...@@ -47,7 +48,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction {
} }
} }
return StepContinue return multistep.ActionContinue
} }
func (s *stepCreateAMI) Cleanup(map[string]interface{}) { func (s *stepCreateAMI) Cleanup(map[string]interface{}) {
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
) )
...@@ -13,7 +14,7 @@ type stepKeyPair struct { ...@@ -13,7 +14,7 @@ type stepKeyPair struct {
keyName string keyName string
} }
func (s *stepKeyPair) Run(state map[string]interface{}) StepAction { func (s *stepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
ec2conn := state["ec2"].(*ec2.EC2) ec2conn := state["ec2"].(*ec2.EC2)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
...@@ -23,7 +24,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction { ...@@ -23,7 +24,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction {
keyResp, err := ec2conn.CreateKeyPair(keyName) keyResp, err := ec2conn.CreateKeyPair(keyName)
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
// Set the keyname so we know to delete it later // Set the keyname so we know to delete it later
...@@ -33,7 +34,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction { ...@@ -33,7 +34,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction {
state["keyPair"] = keyName state["keyPair"] = keyName
state["privateKey"] = keyResp.KeyMaterial state["privateKey"] = keyResp.KeyMaterial
return StepContinue return multistep.ActionContinue
} }
func (s *stepKeyPair) Cleanup(state map[string]interface{}) { func (s *stepKeyPair) Cleanup(state map[string]interface{}) {
......
package amazonebs package amazonebs
import ( import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
) )
type stepProvision struct{} type stepProvision struct{}
func (*stepProvision) Run(state map[string]interface{}) StepAction { func (*stepProvision) Run(state map[string]interface{}) multistep.StepAction {
comm := state["communicator"].(packer.Communicator) comm := state["communicator"].(packer.Communicator)
hook := state["hook"].(packer.Hook) hook := state["hook"].(packer.Hook)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
...@@ -15,7 +16,7 @@ func (*stepProvision) Run(state map[string]interface{}) StepAction { ...@@ -15,7 +16,7 @@ func (*stepProvision) Run(state map[string]interface{}) StepAction {
log.Println("Running the provision hook") log.Println("Running the provision hook")
hook.Run(packer.HookProvision, ui, comm, nil) hook.Run(packer.HookProvision, ui, comm, nil)
return StepContinue return multistep.ActionContinue
} }
func (*stepProvision) Cleanup(map[string]interface{}) {} func (*stepProvision) Cleanup(map[string]interface{}) {}
...@@ -2,6 +2,7 @@ package amazonebs ...@@ -2,6 +2,7 @@ package amazonebs
import ( import (
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
) )
...@@ -10,7 +11,7 @@ type stepRunSourceInstance struct { ...@@ -10,7 +11,7 @@ type stepRunSourceInstance struct {
instance *ec2.Instance instance *ec2.Instance
} }
func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction { func (s *stepRunSourceInstance) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(config) config := state["config"].(config)
ec2conn := state["ec2"].(*ec2.EC2) ec2conn := state["ec2"].(*ec2.EC2)
keyName := state["keyPair"].(string) keyName := state["keyPair"].(string)
...@@ -28,7 +29,7 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction { ...@@ -28,7 +29,7 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction {
runResp, err := ec2conn.RunInstances(runOpts) runResp, err := ec2conn.RunInstances(runOpts)
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
s.instance = &runResp.Instances[0] s.instance = &runResp.Instances[0]
...@@ -38,12 +39,12 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction { ...@@ -38,12 +39,12 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction {
s.instance, err = waitForState(ec2conn, s.instance, "running") s.instance, err = waitForState(ec2conn, s.instance, "running")
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
state["instance"] = s.instance state["instance"] = s.instance
return StepContinue return multistep.ActionContinue
} }
func (s *stepRunSourceInstance) Cleanup(state map[string]interface{}) { func (s *stepRunSourceInstance) Cleanup(state map[string]interface{}) {
......
...@@ -2,12 +2,13 @@ package amazonebs ...@@ -2,12 +2,13 @@ package amazonebs
import ( import (
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
) )
type stepStopInstance struct{} type stepStopInstance struct{}
func (s *stepStopInstance) Run(state map[string]interface{}) StepAction { func (s *stepStopInstance) Run(state map[string]interface{}) multistep.StepAction {
ec2conn := state["ec2"].(*ec2.EC2) ec2conn := state["ec2"].(*ec2.EC2)
instance := state["instance"].(*ec2.Instance) instance := state["instance"].(*ec2.Instance)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
...@@ -17,7 +18,7 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction { ...@@ -17,7 +18,7 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction {
_, err := ec2conn.StopInstances(instance.InstanceId) _, err := ec2conn.StopInstances(instance.InstanceId)
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
// Wait for the instance to actual stop // Wait for the instance to actual stop
...@@ -27,10 +28,10 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction { ...@@ -27,10 +28,10 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction {
instance, err = waitForState(ec2conn, instance, "stopped") instance, err = waitForState(ec2conn, instance, "stopped")
if err != nil { if err != nil {
ui.Error(err.Error()) ui.Error(err.Error())
return StepHalt return multistep.ActionHalt
} }
return StepContinue return multistep.ActionContinue
} }
func (s *stepStopInstance) Cleanup(map[string]interface{}) { func (s *stepStopInstance) Cleanup(map[string]interface{}) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment