builder/openstack: new multistep API
This commit is contained in:
parent
94b76036fc
commit
77f7f24990
|
@ -72,11 +72,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the state bag and initial state for the steps
|
// Setup the state bag and initial state for the steps
|
||||||
state := make(map[string]interface{})
|
state := new(multistep.BasicStateBag)
|
||||||
state["config"] = b.config
|
state.Put("config", b.config)
|
||||||
state["csp"] = csp
|
state.Put("csp", csp)
|
||||||
state["hook"] = hook
|
state.Put("hook", hook)
|
||||||
state["ui"] = ui
|
state.Put("ui", ui)
|
||||||
|
|
||||||
// Build the steps
|
// Build the steps
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
|
@ -108,13 +108,13 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
b.runner.Run(state)
|
b.runner.Run(state)
|
||||||
|
|
||||||
// If there was an error, return that
|
// If there was an error, return that
|
||||||
if rawErr, ok := state["error"]; ok {
|
if rawErr, ok := state.GetOk("error"); ok {
|
||||||
return nil, rawErr.(error)
|
return nil, rawErr.(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the artifact and return it
|
// Build the artifact and return it
|
||||||
artifact := &Artifact{
|
artifact := &Artifact{
|
||||||
ImageId: state["image"].(string),
|
ImageId: state.Get("image").(string),
|
||||||
BuilderIdValue: BuilderId,
|
BuilderIdValue: BuilderId,
|
||||||
Conn: csp,
|
Conn: csp,
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ type StateRefreshFunc func() (result interface{}, state string, progress int, er
|
||||||
type StateChangeConf struct {
|
type StateChangeConf struct {
|
||||||
Pending []string
|
Pending []string
|
||||||
Refresh StateRefreshFunc
|
Refresh StateRefreshFunc
|
||||||
StepState map[string]interface{}
|
StepState multistep.StateBag
|
||||||
Target string
|
Target string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.StepState != nil {
|
if conf.StepState != nil {
|
||||||
if _, ok := conf.StepState[multistep.StateCancelled]; ok {
|
if _, ok := conf.StepState.GetOk(multistep.StateCancelled); ok {
|
||||||
return nil, errors.New("interrupted")
|
return nil, errors.New("interrupted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
gossh "code.google.com/p/go.crypto/ssh"
|
gossh "code.google.com/p/go.crypto/ssh"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/communicator/ssh"
|
"github.com/mitchellh/packer/communicator/ssh"
|
||||||
"github.com/rackspace/gophercloud"
|
"github.com/rackspace/gophercloud"
|
||||||
"time"
|
"time"
|
||||||
|
@ -11,10 +12,10 @@ import (
|
||||||
|
|
||||||
// SSHAddress returns a function that can be given to the SSH communicator
|
// SSHAddress returns a function that can be given to the SSH communicator
|
||||||
// for determining the SSH address based on the server AccessIPv4 setting..
|
// for determining the SSH address based on the server AccessIPv4 setting..
|
||||||
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(map[string]interface{}) (string, error) {
|
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.StateBag) (string, error) {
|
||||||
return func(state map[string]interface{}) (string, error) {
|
return func(state multistep.StateBag) (string, error) {
|
||||||
for j := 0; j < 2; j++ {
|
for j := 0; j < 2; j++ {
|
||||||
s := state["server"].(*gophercloud.Server)
|
s := state.Get("server").(*gophercloud.Server)
|
||||||
if s.AccessIPv4 != "" {
|
if s.AccessIPv4 != "" {
|
||||||
return fmt.Sprintf("%s:%d", s.AccessIPv4, port), nil
|
return fmt.Sprintf("%s:%d", s.AccessIPv4, port), nil
|
||||||
}
|
}
|
||||||
|
@ -24,7 +25,7 @@ func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(map[string]
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
state["server"] = serverState
|
state.Put("server", serverState)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +36,9 @@ func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(map[string]
|
||||||
// SSHConfig returns a function that can be used for the SSH communicator
|
// SSHConfig returns a function that can be used for the SSH communicator
|
||||||
// config for connecting to the instance created over SSH using the generated
|
// config for connecting to the instance created over SSH using the generated
|
||||||
// private key.
|
// private key.
|
||||||
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
|
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||||
return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||||
privateKey := state["privateKey"].(string)
|
privateKey := state.Get("privateKey").(string)
|
||||||
|
|
||||||
keyring := new(ssh.SimpleKeychain)
|
keyring := new(ssh.SimpleKeychain)
|
||||||
if err := keyring.AddPEMKey(privateKey); err != nil {
|
if err := keyring.AddPEMKey(privateKey); err != nil {
|
||||||
|
|
|
@ -11,11 +11,11 @@ import (
|
||||||
|
|
||||||
type stepCreateImage struct{}
|
type stepCreateImage struct{}
|
||||||
|
|
||||||
func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
config := state["config"].(config)
|
config := state.Get("config").(config)
|
||||||
server := state["server"].(*gophercloud.Server)
|
server := state.Get("server").(*gophercloud.Server)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
// Create the image
|
// Create the image
|
||||||
ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
|
ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
|
||||||
|
@ -25,20 +25,20 @@ func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction
|
||||||
imageId, err := csp.CreateImage(server.Id, createOpts)
|
imageId, err := csp.CreateImage(server.Id, createOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error creating image: %s", err)
|
err := fmt.Errorf("Error creating image: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the Image ID in the state
|
// Set the Image ID in the state
|
||||||
ui.Say(fmt.Sprintf("Image: %s", imageId))
|
ui.Say(fmt.Sprintf("Image: %s", imageId))
|
||||||
state["image"] = imageId
|
state.Put("image", imageId)
|
||||||
|
|
||||||
// Wait for the image to become ready
|
// Wait for the image to become ready
|
||||||
ui.Say("Waiting for image to become ready...")
|
ui.Say("Waiting for image to become ready...")
|
||||||
if err := WaitForImage(csp, imageId); err != nil {
|
if err := WaitForImage(csp, imageId); err != nil {
|
||||||
err := fmt.Errorf("Error waiting for image: %s", err)
|
err := fmt.Errorf("Error waiting for image: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateImage) Cleanup(map[string]interface{}) {
|
func (s *stepCreateImage) Cleanup(multistep.StateBag) {
|
||||||
// No cleanup...
|
// No cleanup...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,16 +14,16 @@ type StepKeyPair struct {
|
||||||
keyName string
|
keyName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Creating temporary keypair for this instance...")
|
ui.Say("Creating temporary keypair for this instance...")
|
||||||
keyName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
keyName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||||
log.Printf("temporary keypair name: %s", keyName)
|
log.Printf("temporary keypair name: %s", keyName)
|
||||||
keyResp, err := csp.CreateKeyPair(gophercloud.NewKeyPair{Name: keyName})
|
keyResp, err := csp.CreateKeyPair(gophercloud.NewKeyPair{Name: keyName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state["error"] = fmt.Errorf("Error creating temporary keypair: %s", err)
|
state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err))
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,20 +31,20 @@ func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
s.keyName = keyName
|
s.keyName = keyName
|
||||||
|
|
||||||
// Set some state data for use in future steps
|
// Set some state data for use in future steps
|
||||||
state["keyPair"] = keyName
|
state.Put("keyPair", keyName)
|
||||||
state["privateKey"] = keyResp.PrivateKey
|
state.Put("privateKey", keyResp.PrivateKey)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepKeyPair) Cleanup(state map[string]interface{}) {
|
func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
|
||||||
// If no key name is set, then we never created it, so just return
|
// If no key name is set, then we never created it, so just return
|
||||||
if s.keyName == "" {
|
if s.keyName == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Deleting temporary keypair...")
|
ui.Say("Deleting temporary keypair...")
|
||||||
err := csp.DeleteKeyPair(s.keyName)
|
err := csp.DeleteKeyPair(s.keyName)
|
||||||
|
|
|
@ -16,10 +16,10 @@ type StepRunSourceServer struct {
|
||||||
server *gophercloud.Server
|
server *gophercloud.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *StepRunSourceServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
keyName := state["keyPair"].(string)
|
keyName := state.Get("keyPair").(string)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
// XXX - validate image and flavor is available
|
// XXX - validate image and flavor is available
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAc
|
||||||
serverResp, err := csp.CreateServer(server)
|
serverResp, err := csp.CreateServer(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error launching source server: %s", err)
|
err := fmt.Errorf("Error launching source server: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -51,24 +51,24 @@ func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAc
|
||||||
latestServer, err := WaitForState(&stateChange)
|
latestServer, err := WaitForState(&stateChange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.Id, err)
|
err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.Id, err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
s.server = latestServer.(*gophercloud.Server)
|
s.server = latestServer.(*gophercloud.Server)
|
||||||
state["server"] = s.server
|
state.Put("server", s.server)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRunSourceServer) Cleanup(state map[string]interface{}) {
|
func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) {
|
||||||
if s.server == nil {
|
if s.server == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Terminating the source server...")
|
ui.Say("Terminating the source server...")
|
||||||
if err := csp.DeleteServerById(s.server.Id); err != nil {
|
if err := csp.DeleteServerById(s.server.Id); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue