Merge pull request #7841 from hbdgr/digitalocean_timeout

builder/digitalocean: increase timeout for Digital Ocean snapshot creation.
This commit is contained in:
Megan Marsh 2019-07-08 09:40:14 -07:00 committed by GitHub
commit 7d48eab11e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 3 deletions

View File

@ -95,7 +95,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}, },
new(stepShutdown), new(stepShutdown),
new(stepPowerOff), new(stepPowerOff),
new(stepSnapshot), &stepSnapshot{
snapshotTimeout: b.config.SnapshotTimeout,
},
} }
// Run the steps // Run the steps

View File

@ -190,7 +190,46 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("should have error") t.Fatal("should have error")
} }
}
func TestBuilderPrepare_SnapshotTimeout(t *testing.T) {
var b Builder
config := testConfig()
// Test default
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.SnapshotTimeout != 60*time.Minute {
t.Errorf("invalid: %s", b.config.SnapshotTimeout)
}
// Test set
config["snapshot_timeout"] = "15m"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
// Test bad
config["snapshot_timeout"] = "badstring"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatal("should have error")
}
} }
func TestBuilderPrepare_PrivateNetworking(t *testing.T) { func TestBuilderPrepare_PrivateNetworking(t *testing.T) {

View File

@ -33,6 +33,7 @@ type Config struct {
SnapshotName string `mapstructure:"snapshot_name"` SnapshotName string `mapstructure:"snapshot_name"`
SnapshotRegions []string `mapstructure:"snapshot_regions"` SnapshotRegions []string `mapstructure:"snapshot_regions"`
StateTimeout time.Duration `mapstructure:"state_timeout"` StateTimeout time.Duration `mapstructure:"state_timeout"`
SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout"`
DropletName string `mapstructure:"droplet_name"` DropletName string `mapstructure:"droplet_name"`
UserData string `mapstructure:"user_data"` UserData string `mapstructure:"user_data"`
UserDataFile string `mapstructure:"user_data_file"` UserDataFile string `mapstructure:"user_data_file"`
@ -88,6 +89,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
c.StateTimeout = 6 * time.Minute c.StateTimeout = 6 * time.Minute
} }
if c.SnapshotTimeout == 0 {
// Default to 60 minutes timeout, waiting for snapshot action to finish
c.SnapshotTimeout = 60 * time.Minute
}
var errs *packer.MultiError var errs *packer.MultiError
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packer.MultiErrorAppend(errs, es...) errs = packer.MultiErrorAppend(errs, es...)

View File

@ -12,7 +12,9 @@ import (
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
type stepSnapshot struct{} type stepSnapshot struct {
snapshotTimeout time.Duration
}
func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*godo.Client) client := state.Get("client").(*godo.Client)
@ -31,9 +33,11 @@ func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multis
} }
// With the pending state over, verify that we're in the active state // With the pending state over, verify that we're in the active state
// because action can take a long time and may depend on the size of the final snapshot,
// the timeout is parameterized
ui.Say("Waiting for snapshot to complete...") ui.Say("Waiting for snapshot to complete...")
if err := waitForActionState(godo.ActionCompleted, dropletId, action.ID, if err := waitForActionState(godo.ActionCompleted, dropletId, action.ID,
client, 20*time.Minute); err != nil { client, s.snapshotTimeout); err != nil {
// If we get an error the first time, actually report it // If we get an error the first time, actually report it
err := fmt.Errorf("Error waiting for snapshot: %s", err) err := fmt.Errorf("Error waiting for snapshot: %s", err)
state.Put("error", err) state.Put("error", err)

View File

@ -83,6 +83,10 @@ builder.
droplet to enter a desired state (such as "active") before timing out. The droplet to enter a desired state (such as "active") before timing out. The
default state timeout is "6m". default state timeout is "6m".
- `snapshot_timeout` (string) - The time to wait, as a duration string, for a
snapshot action to complete (e.g snapshot creation) before timing out. The
default snapshot timeout is "60m".
- `user_data` (string) - User data to launch with the Droplet. Packer will - `user_data` (string) - User data to launch with the Droplet. Packer will
not automatically wait for a user script to finish before shutting down the not automatically wait for a user script to finish before shutting down the
instance this must be handled in a provisioner. instance this must be handled in a provisioner.