From 750e4b0f315e08a7bce3b1575c7b0d09ad95aaef Mon Sep 17 00:00:00 2001 From: hbdgr Date: Wed, 3 Jul 2019 17:13:50 +0200 Subject: [PATCH 1/4] builder/digitalocean: increase timeout for waitForActionState --- builder/digitalocean/step_snapshot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/digitalocean/step_snapshot.go b/builder/digitalocean/step_snapshot.go index f3c9430f1..5468c002e 100644 --- a/builder/digitalocean/step_snapshot.go +++ b/builder/digitalocean/step_snapshot.go @@ -33,7 +33,7 @@ func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multis // With the pending state over, verify that we're in the active state ui.Say("Waiting for snapshot to complete...") if err := waitForActionState(godo.ActionCompleted, dropletId, action.ID, - client, 20*time.Minute); err != nil { + client, 60*time.Minute); err != nil { // If we get an error the first time, actually report it err := fmt.Errorf("Error waiting for snapshot: %s", err) state.Put("error", err) From 7d723b7c7b557933e2ddac56ef65f0a2844f8f9f Mon Sep 17 00:00:00 2001 From: hbdgr Date: Thu, 4 Jul 2019 16:25:42 +0200 Subject: [PATCH 2/4] builder/digitalocean: add snapshotTimeout option --- builder/digitalocean/builder.go | 4 +++- builder/digitalocean/config.go | 6 ++++++ builder/digitalocean/step_snapshot.go | 8 ++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index 6519d30f5..4c515b900 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -95,7 +95,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, new(stepShutdown), new(stepPowerOff), - new(stepSnapshot), + &stepSnapshot{ + snapshotTimeout: b.config.SnapshotTimeout, + }, } // Run the steps diff --git a/builder/digitalocean/config.go b/builder/digitalocean/config.go index 451852829..25b28a3bc 100644 --- a/builder/digitalocean/config.go +++ b/builder/digitalocean/config.go @@ -33,6 +33,7 @@ type Config struct { SnapshotName string `mapstructure:"snapshot_name"` SnapshotRegions []string `mapstructure:"snapshot_regions"` StateTimeout time.Duration `mapstructure:"state_timeout"` + SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout"` DropletName string `mapstructure:"droplet_name"` UserData string `mapstructure:"user_data"` UserDataFile string `mapstructure:"user_data_file"` @@ -88,6 +89,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { 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 if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) diff --git a/builder/digitalocean/step_snapshot.go b/builder/digitalocean/step_snapshot.go index 5468c002e..511c3a377 100644 --- a/builder/digitalocean/step_snapshot.go +++ b/builder/digitalocean/step_snapshot.go @@ -12,7 +12,9 @@ import ( "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 { 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 + // 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...") if err := waitForActionState(godo.ActionCompleted, dropletId, action.ID, - client, 60*time.Minute); err != nil { + client, s.snapshotTimeout); err != nil { // If we get an error the first time, actually report it err := fmt.Errorf("Error waiting for snapshot: %s", err) state.Put("error", err) From 6a8f45123a02ccd3231997eb57beb04edc2bda4c Mon Sep 17 00:00:00 2001 From: hbdgr Date: Thu, 4 Jul 2019 16:28:09 +0200 Subject: [PATCH 3/4] test for snapshotTimeout option --- builder/digitalocean/builder_test.go | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/builder/digitalocean/builder_test.go b/builder/digitalocean/builder_test.go index 9ef7c0ad7..70ec6fea9 100644 --- a/builder/digitalocean/builder_test.go +++ b/builder/digitalocean/builder_test.go @@ -190,7 +190,46 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) { if err == nil { 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) { From 7f5f9f0856ec99449dc0ea3fa149eed4e80ead18 Mon Sep 17 00:00:00 2001 From: hbdgr Date: Thu, 4 Jul 2019 16:29:05 +0200 Subject: [PATCH 4/4] digitalocean.html.md : snapshot_timeout --- website/source/docs/builders/digitalocean.html.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/source/docs/builders/digitalocean.html.md b/website/source/docs/builders/digitalocean.html.md index 1d382869d..8df5c9df0 100644 --- a/website/source/docs/builders/digitalocean.html.md +++ b/website/source/docs/builders/digitalocean.html.md @@ -83,6 +83,10 @@ builder. droplet to enter a desired state (such as "active") before timing out. The 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 not automatically wait for a user script to finish before shutting down the instance this must be handled in a provisioner.