Commit 1e17e90a authored by Jack Pearkes's avatar Jack Pearkes

builder/digitalocean: add configurable "event_delay" for sleeps

parent c12e9ff9
...@@ -31,10 +31,12 @@ type config struct { ...@@ -31,10 +31,12 @@ type config struct {
SSHUsername string `mapstructure:"ssh_username"` SSHUsername string `mapstructure:"ssh_username"`
SSHPort uint `mapstructure:"ssh_port"` SSHPort uint `mapstructure:"ssh_port"`
SSHTimeout time.Duration SSHTimeout time.Duration
EventDelay time.Duration
PackerDebug bool `mapstructure:"packer_debug"` PackerDebug bool `mapstructure:"packer_debug"`
RawSSHTimeout string `mapstructure:"ssh_timeout"` RawSSHTimeout string `mapstructure:"ssh_timeout"`
RawEventDelay string `mapstructure:"event_delay"`
} }
type Builder struct { type Builder struct {
...@@ -88,6 +90,12 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -88,6 +90,12 @@ func (b *Builder) Prepare(raws ...interface{}) error {
b.config.RawSSHTimeout = "1m" b.config.RawSSHTimeout = "1m"
} }
if b.config.RawEventDelay == "" {
// Default to 5 second delays after creating events
// to allow DO to process
b.config.RawEventDelay = "5s"
}
// A list of errors on the configuration // A list of errors on the configuration
errs := make([]error, 0) errs := make([]error, 0)
...@@ -100,12 +108,19 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -100,12 +108,19 @@ func (b *Builder) Prepare(raws ...interface{}) error {
if b.config.APIKey == "" { if b.config.APIKey == "" {
errs = append(errs, errors.New("an api_key must be specified")) errs = append(errs, errors.New("an api_key must be specified"))
} }
timeout, err := time.ParseDuration(b.config.RawSSHTimeout) timeout, err := time.ParseDuration(b.config.RawSSHTimeout)
if err != nil { if err != nil {
errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
} }
b.config.SSHTimeout = timeout b.config.SSHTimeout = timeout
delay, err := time.ParseDuration(b.config.RawEventDelay)
if err != nil {
errs = append(errs, fmt.Errorf("Failed parsing event_delay: %s", err))
}
b.config.EventDelay = delay
if len(errs) > 0 { if len(errs) > 0 {
return &packer.MultiError{errs} return &packer.MultiError{errs}
} }
......
...@@ -220,6 +220,38 @@ func TestBuilderPrepare_SSHTimeout(t *testing.T) { ...@@ -220,6 +220,38 @@ func TestBuilderPrepare_SSHTimeout(t *testing.T) {
} }
func TestBuilderPrepare_EventDelay(t *testing.T) {
var b Builder
config := testConfig()
// Test default
err := b.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.RawEventDelay != "5s" {
t.Errorf("invalid: %d", b.config.RawEventDelay)
}
// Test set
config["event_delay"] = "10s"
b = Builder{}
err = b.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
// Test bad
config["event_delay"] = "tubes"
b = Builder{}
err = b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_SnapshotName(t *testing.T) { func TestBuilderPrepare_SnapshotName(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
"time" "time"
) )
...@@ -49,6 +50,7 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) { ...@@ -49,6 +50,7 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
client := state["client"].(*DigitalOceanClient) client := state["client"].(*DigitalOceanClient)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
c := state["config"].(config)
// Destroy the droplet we just created // Destroy the droplet we just created
ui.Say("Destroying droplet...") ui.Say("Destroying droplet...")
...@@ -56,7 +58,8 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) { ...@@ -56,7 +58,8 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
// Sleep arbitrarily before sending destroy request // Sleep arbitrarily before sending destroy request
// Otherwise we get "pending event" errors, even though there isn't // Otherwise we get "pending event" errors, even though there isn't
// one. // one.
time.Sleep(5 * time.Second) log.Printf("Sleeping for %v, event_delay", c.RawEventDelay)
time.Sleep(c.EventDelay)
err := client.DestroyDroplet(s.dropletId) err := client.DestroyDroplet(s.dropletId)
......
...@@ -3,6 +3,7 @@ package digitalocean ...@@ -3,6 +3,7 @@ package digitalocean
import ( import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
"time" "time"
) )
...@@ -10,13 +11,15 @@ type stepPowerOff struct{} ...@@ -10,13 +11,15 @@ type stepPowerOff struct{}
func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction { func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
client := state["client"].(*DigitalOceanClient) client := state["client"].(*DigitalOceanClient)
c := state["config"].(config)
ui := state["ui"].(packer.Ui) ui := state["ui"].(packer.Ui)
dropletId := state["droplet_id"].(uint) dropletId := state["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
// one. // one.
time.Sleep(3 * time.Second) log.Printf("Sleeping for %v, event_delay", c.RawEventDelay)
time.Sleep(c.EventDelay)
// Poweroff the droplet so it can be snapshot // Poweroff the droplet so it can be snapshot
err := client.PowerOffDroplet(dropletId) err := client.PowerOffDroplet(dropletId)
......
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