builder/digitalocean: new multistep API
This commit is contained in:
parent
0b830c92ba
commit
94b76036fc
|
@ -189,11 +189,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
client := DigitalOceanClient{}.New(b.config.ClientID, b.config.APIKey)
|
client := DigitalOceanClient{}.New(b.config.ClientID, b.config.APIKey)
|
||||||
|
|
||||||
// Set up the state
|
// Set up the state
|
||||||
state := make(map[string]interface{})
|
state := new(multistep.BasicStateBag)
|
||||||
state["config"] = b.config
|
state.Put("config", b.config)
|
||||||
state["client"] = client
|
state.Put("client", client)
|
||||||
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{
|
||||||
|
@ -224,18 +224,18 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := state["snapshot_name"]; !ok {
|
if _, ok := state.GetOk("snapshot_name"); !ok {
|
||||||
log.Println("Failed to find snapshot_name in state. Bug?")
|
log.Println("Failed to find snapshot_name in state. Bug?")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
artifact := &Artifact{
|
artifact := &Artifact{
|
||||||
snapshotName: state["snapshot_name"].(string),
|
snapshotName: state.Get("snapshot_name").(string),
|
||||||
snapshotId: state["snapshot_image_id"].(uint),
|
snapshotId: state.Get("snapshot_image_id").(uint),
|
||||||
client: client,
|
client: client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,19 @@ package digitalocean
|
||||||
import (
|
import (
|
||||||
gossh "code.google.com/p/go.crypto/ssh"
|
gossh "code.google.com/p/go.crypto/ssh"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/communicator/ssh"
|
"github.com/mitchellh/packer/communicator/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sshAddress(state map[string]interface{}) (string, error) {
|
func sshAddress(state multistep.StateBag) (string, error) {
|
||||||
config := state["config"].(config)
|
config := state.Get("config").(config)
|
||||||
ipAddress := state["droplet_ip"].(string)
|
ipAddress := state.Get("droplet_ip").(string)
|
||||||
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
|
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||||
config := state["config"].(config)
|
config := state.Get("config").(config)
|
||||||
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 {
|
||||||
|
|
|
@ -14,11 +14,11 @@ type stepCreateDroplet struct {
|
||||||
dropletId uint
|
dropletId uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
sshKeyId := state["ssh_key_id"].(uint)
|
sshKeyId := state.Get("ssh_key_id").(uint)
|
||||||
|
|
||||||
ui.Say("Creating droplet...")
|
ui.Say("Creating droplet...")
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepActi
|
||||||
dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId)
|
dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error creating droplet: %s", err)
|
err := fmt.Errorf("Error creating droplet: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -38,20 +38,20 @@ func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepActi
|
||||||
s.dropletId = dropletId
|
s.dropletId = dropletId
|
||||||
|
|
||||||
// Store the droplet id for later
|
// Store the droplet id for later
|
||||||
state["droplet_id"] = dropletId
|
state.Put("droplet_id", dropletId)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
|
func (s *stepCreateDroplet) Cleanup(state multistep.StateBag) {
|
||||||
// If the dropletid isn't there, we probably never created it
|
// If the dropletid isn't there, we probably never created it
|
||||||
if s.dropletId == 0 {
|
if s.dropletId == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
|
|
||||||
// Destroy the droplet we just created
|
// Destroy the droplet we just created
|
||||||
ui.Say("Destroying droplet...")
|
ui.Say("Destroying droplet...")
|
||||||
|
|
|
@ -18,9 +18,9 @@ type stepCreateSSHKey struct {
|
||||||
keyId uint
|
keyId uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Creating temporary ssh key for droplet...")
|
ui.Say("Creating temporary ssh key for droplet...")
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the private key in the statebag for later
|
// Set the private key in the statebag for later
|
||||||
state["privateKey"] = string(pem.EncodeToMemory(&priv_blk))
|
state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk)))
|
||||||
|
|
||||||
// Marshal the public key into SSH compatible format
|
// Marshal the public key into SSH compatible format
|
||||||
pub := priv.PublicKey
|
pub := priv.PublicKey
|
||||||
|
@ -48,7 +48,7 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||||
keyId, err := client.CreateKey(name, pub_sshformat)
|
keyId, err := client.CreateKey(name, pub_sshformat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
|
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -59,20 +59,20 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||||
log.Printf("temporary ssh key name: %s", name)
|
log.Printf("temporary ssh key name: %s", name)
|
||||||
|
|
||||||
// Remember some state for the future
|
// Remember some state for the future
|
||||||
state["ssh_key_id"] = keyId
|
state.Put("ssh_key_id", keyId)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateSSHKey) Cleanup(state map[string]interface{}) {
|
func (s *stepCreateSSHKey) 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.keyId == 0 {
|
if s.keyId == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
|
|
||||||
ui.Say("Deleting temporary ssh key...")
|
ui.Say("Deleting temporary ssh key...")
|
||||||
err := client.DestroyKey(s.keyId)
|
err := client.DestroyKey(s.keyId)
|
||||||
|
|
|
@ -8,18 +8,18 @@ import (
|
||||||
|
|
||||||
type stepDropletInfo struct{}
|
type stepDropletInfo struct{}
|
||||||
|
|
||||||
func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepDropletInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
dropletId := state["droplet_id"].(uint)
|
dropletId := state.Get("droplet_id").(uint)
|
||||||
|
|
||||||
ui.Say("Waiting for droplet to become active...")
|
ui.Say("Waiting for droplet to become active...")
|
||||||
|
|
||||||
err := waitForDropletState("active", dropletId, client, c)
|
err := waitForDropletState("active", dropletId, client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error waiting for droplet to become active: %s", err)
|
err := fmt.Errorf("Error waiting for droplet to become active: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -28,16 +28,16 @@ func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction
|
||||||
ip, _, err := client.DropletStatus(dropletId)
|
ip, _, err := client.DropletStatus(dropletId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error retrieving droplet ID: %s", err)
|
err := fmt.Errorf("Error retrieving droplet ID: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
state["droplet_ip"] = ip
|
state.Put("droplet_ip", ip)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepDropletInfo) Cleanup(state map[string]interface{}) {
|
func (s *stepDropletInfo) Cleanup(state multistep.StateBag) {
|
||||||
// no cleanup
|
// no cleanup
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
|
|
||||||
type stepPowerOff struct{}
|
type stepPowerOff struct{}
|
||||||
|
|
||||||
func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepPowerOff) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
dropletId := state["droplet_id"].(uint)
|
dropletId := state.Get("droplet_id").(uint)
|
||||||
|
|
||||||
// Sleep arbitrarily before sending power off request
|
// Sleep arbitrarily before sending power off request
|
||||||
// Otherwise we get "pending event" errors, even though there isn't
|
// Otherwise we get "pending event" errors, even though there isn't
|
||||||
|
@ -27,7 +27,7 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error powering off droplet: %s", err)
|
err := fmt.Errorf("Error powering off droplet: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,6 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepPowerOff) Cleanup(state map[string]interface{}) {
|
func (s *stepPowerOff) Cleanup(state multistep.StateBag) {
|
||||||
// no cleanup
|
// no cleanup
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
|
|
||||||
type stepShutdown struct{}
|
type stepShutdown struct{}
|
||||||
|
|
||||||
func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
dropletId := state["droplet_id"].(uint)
|
dropletId := state.Get("droplet_id").(uint)
|
||||||
|
|
||||||
// Sleep arbitrarily before sending the request
|
// Sleep arbitrarily before sending the request
|
||||||
// Otherwise we get "pending event" errors, even though there isn't
|
// Otherwise we get "pending event" errors, even though there isn't
|
||||||
|
@ -26,7 +26,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error shutting down droplet: %s", err)
|
err := fmt.Errorf("Error shutting down droplet: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
err = waitForDropletState("off", dropletId, client, c)
|
err = waitForDropletState("off", dropletId, client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error waiting for droplet to become 'off': %s", err)
|
err := fmt.Errorf("Error waiting for droplet to become 'off': %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,6 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepShutdown) Cleanup(state map[string]interface{}) {
|
func (s *stepShutdown) Cleanup(state multistep.StateBag) {
|
||||||
// no cleanup
|
// no cleanup
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,17 @@ import (
|
||||||
|
|
||||||
type stepSnapshot struct{}
|
type stepSnapshot struct{}
|
||||||
|
|
||||||
func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
client := state["client"].(*DigitalOceanClient)
|
client := state.Get("client").(*DigitalOceanClient)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state["config"].(config)
|
c := state.Get("config").(config)
|
||||||
dropletId := state["droplet_id"].(uint)
|
dropletId := state.Get("droplet_id").(uint)
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
|
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
|
||||||
err := client.CreateSnapshot(dropletId, c.SnapshotName)
|
err := client.CreateSnapshot(dropletId, c.SnapshotName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error creating snapshot: %s", err)
|
err := fmt.Errorf("Error creating snapshot: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
err = waitForDropletState("active", dropletId, client, c)
|
err = waitForDropletState("active", dropletId, client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error waiting for snapshot to complete: %s", err)
|
err := fmt.Errorf("Error waiting for snapshot to complete: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
images, err := client.Images()
|
images, err := client.Images()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error looking up snapshot ID: %s", err)
|
err := fmt.Errorf("Error looking up snapshot ID: %s", err)
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
@ -53,19 +53,19 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
|
|
||||||
if imageId == 0 {
|
if imageId == 0 {
|
||||||
err := errors.New("Couldn't find snapshot to get the image ID. Bug?")
|
err := errors.New("Couldn't find snapshot to get the image ID. Bug?")
|
||||||
state["error"] = err
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Snapshot image ID: %d", imageId)
|
log.Printf("Snapshot image ID: %d", imageId)
|
||||||
|
|
||||||
state["snapshot_image_id"] = imageId
|
state.Put("snapshot_image_id", imageId)
|
||||||
state["snapshot_name"] = c.SnapshotName
|
state.Put("snapshot_name", c.SnapshotName)
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepSnapshot) Cleanup(state map[string]interface{}) {
|
func (s *stepSnapshot) Cleanup(state multistep.StateBag) {
|
||||||
// no cleanup
|
// no cleanup
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue