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

builder/amazonebs: extract multistep, use that

parent 2dd5a982
......@@ -9,6 +9,7 @@ import (
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/mapstructure"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
......@@ -87,7 +88,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
state["ui"] = ui
// Build the steps
steps := []Step{
steps := []multistep.Step{
&stepKeyPair{},
&stepRunSourceInstance{},
&stepConnectSSH{},
......@@ -97,7 +98,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
}
// Run!
RunSteps(state, steps)
runner := &multistep.BasicRunner{Steps: steps}
runner.Run(state)
// Build the artifact and return it
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 (
gossh "code.google.com/p/go.crypto/ssh"
"fmt"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
"github.com/mitchellh/packer/packer"
"log"
......@@ -15,7 +16,7 @@ type stepConnectSSH struct {
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)
instance := state["instance"].(*ec2.Instance)
privateKey := state["privateKey"].(string)
......@@ -27,7 +28,7 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction {
err := keyring.AddPEMKey(privateKey)
if err != nil {
ui.Say(fmt.Sprintf("Error setting up SSH config: %s", err))
return StepHalt
return multistep.ActionHalt
}
// Build the actual SSH client configuration
......@@ -59,13 +60,13 @@ func (s *stepConnectSSH) Run(state map[string]interface{}) StepAction {
if err != nil {
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
state["communicator"] = comm
return StepContinue
return multistep.ActionContinue
}
func (s *stepConnectSSH) Cleanup(map[string]interface{}) {
......
......@@ -3,12 +3,13 @@ package amazonebs
import (
"fmt"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
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)
ec2conn := state["ec2"].(*ec2.EC2)
instance := state["instance"].(*ec2.Instance)
......@@ -24,7 +25,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction {
createResp, err := ec2conn.CreateImage(createOpts)
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
// Set the AMI ID in the state
......@@ -39,7 +40,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) StepAction {
imageResp, err := ec2conn.Images([]string{createResp.ImageId}, ec2.NewFilter())
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
if imageResp.Images[0].State == "available" {
......@@ -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{}) {
......
......@@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
......@@ -13,7 +14,7 @@ type stepKeyPair struct {
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)
ui := state["ui"].(packer.Ui)
......@@ -23,7 +24,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction {
keyResp, err := ec2conn.CreateKeyPair(keyName)
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
// Set the keyname so we know to delete it later
......@@ -33,7 +34,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) StepAction {
state["keyPair"] = keyName
state["privateKey"] = keyResp.KeyMaterial
return StepContinue
return multistep.ActionContinue
}
func (s *stepKeyPair) Cleanup(state map[string]interface{}) {
......
package amazonebs
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
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)
hook := state["hook"].(packer.Hook)
ui := state["ui"].(packer.Ui)
......@@ -15,7 +16,7 @@ func (*stepProvision) Run(state map[string]interface{}) StepAction {
log.Println("Running the provision hook")
hook.Run(packer.HookProvision, ui, comm, nil)
return StepContinue
return multistep.ActionContinue
}
func (*stepProvision) Cleanup(map[string]interface{}) {}
......@@ -2,6 +2,7 @@ package amazonebs
import (
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
......@@ -10,7 +11,7 @@ type stepRunSourceInstance struct {
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)
ec2conn := state["ec2"].(*ec2.EC2)
keyName := state["keyPair"].(string)
......@@ -28,7 +29,7 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction {
runResp, err := ec2conn.RunInstances(runOpts)
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
s.instance = &runResp.Instances[0]
......@@ -38,12 +39,12 @@ func (s *stepRunSourceInstance) Run(state map[string]interface{}) StepAction {
s.instance, err = waitForState(ec2conn, s.instance, "running")
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
state["instance"] = s.instance
return StepContinue
return multistep.ActionContinue
}
func (s *stepRunSourceInstance) Cleanup(state map[string]interface{}) {
......
......@@ -2,12 +2,13 @@ package amazonebs
import (
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
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)
instance := state["instance"].(*ec2.Instance)
ui := state["ui"].(packer.Ui)
......@@ -17,7 +18,7 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction {
_, err := ec2conn.StopInstances(instance.InstanceId)
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
// Wait for the instance to actual stop
......@@ -27,10 +28,10 @@ func (s *stepStopInstance) Run(state map[string]interface{}) StepAction {
instance, err = waitForState(ec2conn, instance, "stopped")
if err != nil {
ui.Error(err.Error())
return StepHalt
return multistep.ActionHalt
}
return StepContinue
return multistep.ActionContinue
}
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