builder/digitalocean: completed initial pass at all steps.
This commit is contained in:
parent
dd6e4e4933
commit
a774e2b444
|
@ -17,7 +17,6 @@ type stepConnectSSH struct {
|
|||
|
||||
func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(config)
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
privateKey := state["privateKey"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ipAddress := state["droplet_ip"]
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
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
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type stepDropletInfo struct{}
|
||||
|
@ -12,59 +10,15 @@ type stepDropletInfo struct{}
|
|||
func (s *stepDropletInfo) 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("Waiting for droplet to become active...")
|
||||
|
||||
// Wait for the droplet to become active
|
||||
active := make(chan bool, 1)
|
||||
err := waitForDropletState("active", dropletId, client)
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Set the IP on the state for later
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
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{}) {}
|
|
@ -0,0 +1,39 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
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
|
||||
}
|
Loading…
Reference in New Issue