Merge pull request #26 from mitchellh/digital-ocean-state-timeout
DigitalOcean: Add configuration for state timeout
This commit is contained in:
commit
a93668bed3
|
@ -39,12 +39,14 @@ type config struct {
|
|||
SSHPort uint `mapstructure:"ssh_port"`
|
||||
SSHTimeout time.Duration
|
||||
EventDelay time.Duration
|
||||
StateTimeout time.Duration
|
||||
|
||||
PackerDebug bool `mapstructure:"packer_debug"`
|
||||
|
||||
RawSnapshotName string `mapstructure:"snapshot_name"`
|
||||
RawSSHTimeout string `mapstructure:"ssh_timeout"`
|
||||
RawEventDelay string `mapstructure:"event_delay"`
|
||||
RawStateTimeout string `mapstructure:"state_timeout"`
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
|
@ -104,6 +106,12 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
|||
b.config.RawEventDelay = "5s"
|
||||
}
|
||||
|
||||
if b.config.RawStateTimeout == "" {
|
||||
// Default to 3 minute timeouts waiting for
|
||||
// desired state. i.e waiting for droplet to become active
|
||||
b.config.RawStateTimeout = "3m"
|
||||
}
|
||||
|
||||
// A list of errors on the configuration
|
||||
errs := make([]error, 0)
|
||||
|
||||
|
@ -117,17 +125,23 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
|||
errs = append(errs, errors.New("an api_key must be specified"))
|
||||
}
|
||||
|
||||
timeout, err := time.ParseDuration(b.config.RawSSHTimeout)
|
||||
sshTimeout, err := time.ParseDuration(b.config.RawSSHTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
|
||||
}
|
||||
b.config.SSHTimeout = timeout
|
||||
b.config.SSHTimeout = sshTimeout
|
||||
|
||||
delay, err := time.ParseDuration(b.config.RawEventDelay)
|
||||
eventDelay, err := time.ParseDuration(b.config.RawEventDelay)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing event_delay: %s", err))
|
||||
}
|
||||
b.config.EventDelay = delay
|
||||
b.config.EventDelay = eventDelay
|
||||
|
||||
stateTimeout, err := time.ParseDuration(b.config.RawStateTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing state_timeout: %s", err))
|
||||
}
|
||||
b.config.StateTimeout = stateTimeout
|
||||
|
||||
// Parse the name of the snapshot
|
||||
snapNameBuf := new(bytes.Buffer)
|
||||
|
|
|
@ -253,6 +253,38 @@ func TestBuilderPrepare_EventDelay(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_StateTimeout(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.RawStateTimeout != "3m" {
|
||||
t.Errorf("invalid: %d", b.config.RawStateTimeout)
|
||||
}
|
||||
|
||||
// Test set
|
||||
config["state_timeout"] = "5m"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["state_timeout"] = "tubes"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_SnapshotName(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
|
|
@ -11,11 +11,12 @@ 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...")
|
||||
|
||||
err := waitForDropletState("active", dropletId, client)
|
||||
err := waitForDropletState("active", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for droplet to become active: %s", err)
|
||||
state["error"] = err
|
||||
|
|
|
@ -34,7 +34,7 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
|||
|
||||
ui.Say("Waiting for droplet to power off...")
|
||||
|
||||
err = waitForDropletState("off", dropletId, client)
|
||||
err = waitForDropletState("off", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for droplet to become 'off': %s", err)
|
||||
state["error"] = err
|
||||
|
|
|
@ -26,7 +26,7 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
|||
}
|
||||
|
||||
ui.Say("Waiting for snapshot to complete...")
|
||||
err = waitForDropletState("active", dropletId, client)
|
||||
err = waitForDropletState("active", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for snapshot to complete: %s", err)
|
||||
state["error"] = err
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
// 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 {
|
||||
func waitForDropletState(desiredState string, dropletId uint, client *DigitalOceanClient, c config) error {
|
||||
active := make(chan bool, 1)
|
||||
|
||||
go func() {
|
||||
|
@ -36,9 +36,8 @@ func waitForDropletState(desiredState string, dropletId uint, client *DigitalOce
|
|||
active <- true
|
||||
}()
|
||||
|
||||
log.Printf("Waiting for up to 3 minutes for droplet to become %s", desiredState)
|
||||
duration, _ := time.ParseDuration("3m")
|
||||
timeout := time.After(duration)
|
||||
log.Printf("Waiting for up to %s for droplet to become %s", c.RawStateTimeout, desiredState)
|
||||
timeout := time.After(c.StateTimeout)
|
||||
|
||||
ActiveWaitLoop:
|
||||
for {
|
||||
|
|
|
@ -64,6 +64,10 @@ Optional:
|
|||
* `ssh_username` (string) - The username to use in order to communicate
|
||||
over SSH to the running droplet. Default is "root".
|
||||
|
||||
* `state_timeout` (string) - The time to wait, as a duration string,
|
||||
for a droplet to enter a desired state (such as "active") before
|
||||
timing out. The default state timeout is "3m".
|
||||
|
||||
## Basic Example
|
||||
|
||||
Here is a basic example. It is completely valid as soon as you enter your
|
||||
|
|
Loading…
Reference in New Issue