Commit a774e2b4 authored by Jack Pearkes's avatar Jack Pearkes

builder/digitalocean: completed initial pass at all steps.

parent dd6e4e49
...@@ -17,7 +17,6 @@ type stepConnectSSH struct { ...@@ -17,7 +17,6 @@ type stepConnectSSH struct {
func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction { func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(config) config := state["config"].(config)
client := state["client"].(*DigitalOceanClient)
privateKey := state["privateKey"].(string) privateKey := state["privateKey"].(string)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
ipAddress := state["droplet_ip"] ipAddress := state["droplet_ip"]
......
package digitalocean
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type stepDestroyDroplet struct{}
func (s *stepDestroyDroplet) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui)
dropletId := state["droplet_id"].(uint)
ui.Say("Destroying droplet...")
err := client.DestroyDroplet(dropletId)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepDestroyDroplet) Cleanup(state map[string]interface{}) {
// no cleanup
}
package digitalocean
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type stepDestroySSHKey struct{}
func (s *stepDestroySSHKey) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui)
sshKeyId := state["ssh_key_id"].(uint)
ui.Say("Destroying temporary ssh key...")
err := client.DestroyKey(sshKeyId)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepDestroySSHKey) Cleanup(state map[string]interface{}) {
// no cleanup
}
...@@ -3,8 +3,6 @@ package digitalocean ...@@ -3,8 +3,6 @@ package digitalocean
import ( import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
"time"
) )
type stepDropletInfo struct{} type stepDropletInfo struct{}
...@@ -12,59 +10,15 @@ type stepDropletInfo struct{} ...@@ -12,59 +10,15 @@ type stepDropletInfo struct{}
func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction { func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient) client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
c := state["config"].(config)
dropletId := state["droplet_id"].(uint) dropletId := state["droplet_id"].(uint)
ui.Say("Waiting for droplet to become active...") ui.Say("Waiting for droplet to become active...")
// Wait for the droplet to become active err := waitForDropletState("active", dropletId, client)
active := make(chan bool, 1)
go func() { if err != nil {
var err error ui.Error(err.Error())
return multistep.ActionHalt
attempts := 0
for {
select {
default:
}
attempts += 1
log.Printf("Checking droplet status... (attempt: %d)", attempts)
ip, status, err := client.DropletStatus(dropletId)
if status == "active" {
break
}
// Wait a second in between
time.Sleep(1 * time.Second)
}
active <- true
}()
log.Printf("Waiting for up to 3 minutes for droplet to become active")
duration, _ := time.ParseDuration("3m")
timeout := time.After(duration)
ActiveWaitLoop:
for {
select {
case <-active:
// We connected. Just break the loop.
break ActiveWaitLoop
case <-timeout:
ui.Error("Timeout while waiting to for droplet to become active")
return multistep.ActionHalt
case <-time.After(1 * time.Second):
if _, ok := state[multistep.StateCancelled]; ok {
log.Println("Interrupt detected, quitting waiting droplet to become active")
return multistep.ActionHalt
}
}
} }
// Set the IP on the state for later // Set the IP on the state for later
......
package digitalocean
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type stepPowerOff struct{}
func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui)
dropletId := state["droplet_id"].(uint)
// Poweroff the droplet so it can be snapshot
err := client.PowerOffDroplet(dropletId)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say("Waiting for droplet to power off...")
err = waitForDropletState("off", dropletId, client)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepPowerOff) Cleanup(state map[string]interface{}) {
// no cleanup
}
package digitalocean
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
type stepProvision struct{}
func (*stepProvision) Run(state map[string]interface{}) multistep.StepAction {
comm := state["communicator"].(packer.Communicator)
hook := state["hook"].(packer.Hook)
ui := state["ui"].(packer.Ui)
log.Println("Running the provision hook")
hook.Run(packer.HookProvision, ui, comm, nil)
return multistep.ActionContinue
}
func (*stepProvision) Cleanup(map[string]interface{}) {}
package digitalocean
import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type stepSnapshot struct{}
func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui)
c := state["config"].(config)
dropletId := state["droplet_id"].(uint)
ui.Say("Creating snapshot...")
err := client.CreateSnapshot(dropletId, c.SnapshotName)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say("Waiting for snapshot to complete...")
err = waitForDropletState("active", dropletId, client)
if err != nil {
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepSnapshot) Cleanup(state map[string]interface{}) {
// no cleanup
}
package digitalocean
import (
"errors"
"log"
"time"
)
// waitForState simply blocks until the droplet is in
// a state we expect, while eventually timing out.
func waitForDropletState(desiredState string, dropletId uint, client *DigitalOceanClient) error {
active := make(chan bool, 1)
go func() {
attempts := 0
for {
select {
default:
}
attempts += 1
log.Printf("Checking droplet status... (attempt: %d)", attempts)
_, status, err := client.DropletStatus(dropletId)
if err != nil {
log.Println(err)
break
}
if status == desiredState {
break
}
// Wait a second in between
time.Sleep(1 * time.Second)
}
active <- true
}()
log.Printf("Waiting for up to 3 minutes for droplet to become %s", desiredState)
duration, _ := time.ParseDuration("3m")
timeout := time.After(duration)
ActiveWaitLoop:
for {
select {
case <-active:
// We connected. Just break the loop.
break ActiveWaitLoop
case <-timeout:
err := errors.New("Timeout while waiting to for droplet to become active")
return err
case <-time.After(1 * time.Second):
err := errors.New("Interrupt detected, quitting waiting for droplet")
return err
}
}
// If we got this far, there were no errors
return nil
}
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