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)