diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index 228ad52f6..ac128e899 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -9,10 +9,10 @@ import ( "os" "regexp" "strings" - "time" "github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -371,7 +371,7 @@ type RunConfig struct { // The timeout for waiting for a Windows // password for Windows instances. Defaults to 20 minutes. Example value: // 10m - WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"` + WindowsPasswordTimeout config.DurationString `mapstructure:"windows_password_timeout" required:"false"` // Communicator settings Comm communicator.Config `mapstructure:",squash"` @@ -389,8 +389,8 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { c.Comm.SSHTemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()) } - if c.WindowsPasswordTimeout == 0 { - c.WindowsPasswordTimeout = 20 * time.Minute + if c.WindowsPasswordTimeout == "" { + c.WindowsPasswordTimeout = "20m" } if c.RunTags == nil { diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index d2638d806..e312241b3 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -229,7 +229,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &awscommon.StepGetPassword{ Debug: b.config.PackerDebug, Comm: &b.config.RunConfig.Comm, - Timeout: b.config.WindowsPasswordTimeout, + Timeout: b.config.WindowsPasswordTimeout.Duration(), BuildName: b.config.PackerBuildName, }, &communicator.StepConnect{ diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index ce31e0d1d..5c45eef93 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -8,9 +8,9 @@ import ( "context" "errors" "fmt" - "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/iam" awscommon "github.com/hashicorp/packer/builder/amazon/common" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -271,7 +271,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &awscommon.StepGetPassword{ Debug: b.config.PackerDebug, Comm: &b.config.RunConfig.Comm, - Timeout: b.config.WindowsPasswordTimeout, + Timeout: b.config.WindowsPasswordTimeout.Duration(), BuildName: b.config.PackerBuildName, }, &communicator.StepConnect{ diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index 5ed61279e..4640b8836 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -237,7 +237,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &awscommon.StepGetPassword{ Debug: b.config.PackerDebug, Comm: &b.config.RunConfig.Comm, - Timeout: b.config.WindowsPasswordTimeout, + Timeout: b.config.WindowsPasswordTimeout.Duration(), BuildName: b.config.PackerBuildName, }, &communicator.StepConnect{ diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index ac3296196..481052727 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -8,11 +8,11 @@ import ( "context" "errors" "fmt" - "github.com/aws/aws-sdk-go/service/iam" "os" "strings" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/iam" awscommon "github.com/hashicorp/packer/builder/amazon/common" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -322,7 +322,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &awscommon.StepGetPassword{ Debug: b.config.PackerDebug, Comm: &b.config.RunConfig.Comm, - Timeout: b.config.WindowsPasswordTimeout, + Timeout: b.config.WindowsPasswordTimeout.Duration(), BuildName: b.config.PackerBuildName, }, &communicator.StepConnect{ diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index 2a06f1b84..fd1f9b196 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -80,8 +80,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack b.config.ResourceGroupName, b.config.StorageAccount, b.config.ClientConfig.CloudEnvironment(), - b.config.SharedGalleryTimeout, - b.config.PollingDurationTimeout, + b.config.SharedGalleryTimeout.Duration(), + b.config.PollingDurationTimeout.Duration(), spnCloud, spnKeyVault) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 552a2389d..f1d5cfcb9 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -139,7 +139,7 @@ type Config struct { // Azure dashboard, then you probably need to increase this timeout from // its default of "60m" (valid time units include `s` for seconds, `m` for // minutes, and `h` for hours.) - SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"` + SharedGalleryTimeout config.DurationString `mapstructure:"shared_image_gallery_timeout"` // PublisherName for your base image. See // [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/) // for details. @@ -320,7 +320,7 @@ type Config struct { // context deadline exceeded`, then you probably need to increase this timeout from // its default of "15m" (valid time units include `s` for seconds, `m` for // minutes, and `h` for hours.) - PollingDurationTimeout time.Duration `mapstructure:"polling_duration_timeout" required:"false"` + PollingDurationTimeout config.DurationString `mapstructure:"polling_duration_timeout" required:"false"` // If either Linux or Windows is specified Packer will // automatically configure authentication credentials for the provisioned // machine. For Linux this configures an SSH authorized key. For Windows @@ -550,8 +550,8 @@ func newConfig(raws ...interface{}) (*Config, []string, error) { } func setSshValues(c *Config) error { - if c.Comm.SSHTimeout == 0 { - c.Comm.SSHTimeout = 20 * time.Minute + if c.Comm.SSHTimeout == "" { + c.Comm.SSHTimeout = "20m" } if c.Comm.SSHPrivateKeyFile != "" { @@ -867,9 +867,9 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("A list of replication_regions must be specified for shared_image_gallery_destination")) } } - if c.SharedGalleryTimeout == 0 { + if c.SharedGalleryTimeout == "" { // default to a one-hour timeout. In the sdk, the default is 15 m. - c.SharedGalleryTimeout = 60 * time.Minute + c.SharedGalleryTimeout = "60m" } if c.ManagedImageOSDiskSnapshotName != "" { @@ -920,9 +920,9 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { ///////////////////////////////////////////// // Polling Duration Timeout - if c.PollingDurationTimeout == 0 { + if c.PollingDurationTimeout == "" { // In the sdk, the default is 15 m. - c.PollingDurationTimeout = 15 * time.Minute + c.PollingDurationTimeout = "15m" } ///////////////////////////////////////////// diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index 52ad4814e..b229fbdb9 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -539,11 +539,11 @@ func TestConfigShouldSupportPackersConfigElements(t *testing.T) { t.Fatal(err) } - if c.Comm.SSHTimeout != 1*time.Hour { + if c.Comm.SSHTimeout.Duration() != 1*time.Hour { t.Errorf("Expected Comm.SSHTimeout to be a duration of an hour, but got '%s' instead.", c.Comm.SSHTimeout) } - if c.Comm.WinRMTimeout != 2*time.Hour { + if c.Comm.WinRMTimeout.Duration() != 2*time.Hour { t.Errorf("Expected Comm.WinRMTimeout to be a durationof two hours, but got '%s' instead.", c.Comm.WinRMTimeout) } } diff --git a/builder/cloudstack/builder.go b/builder/cloudstack/builder.go index dc1dace69..dedc70e83 100644 --- a/builder/cloudstack/builder.go +++ b/builder/cloudstack/builder.go @@ -44,7 +44,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack ) // Set the time to wait before timing out - client.AsyncTimeout(int64(b.config.AsyncTimeout.Seconds())) + client.AsyncTimeout(int64(b.config.AsyncTimeout.Duration().Seconds())) // Some CloudStack service providers only allow HTTP GET calls. client.HTTPGETOnly = b.config.HTTPGetOnly diff --git a/builder/cloudstack/config.go b/builder/cloudstack/config.go index cff9e2472..0831b8f4c 100644 --- a/builder/cloudstack/config.go +++ b/builder/cloudstack/config.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "os" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/uuid" @@ -35,7 +34,7 @@ type Config struct { SecretKey string `mapstructure:"secret_key" required:"true"` // The time duration to wait for async calls to // finish. Defaults to 30m. - AsyncTimeout time.Duration `mapstructure:"async_timeout" required:"false"` + AsyncTimeout config.DurationString `mapstructure:"async_timeout" required:"false"` // Some cloud providers only allow HTTP GET calls // to their CloudStack API. If using such a provider, you need to set this to // true in order for the provider to only make GET calls and no POST calls. @@ -68,7 +67,7 @@ type Config struct { // Configure the duration time to wait, making sure virtual machine is able // to finish installing OS before it ejects safely. Requires `eject_iso` // set to `true` and this option is only available when using `source_iso`. - EjectISODelay time.Duration `mapstructure:"eject_iso_delay"` + EjectISODelay config.DurationString `mapstructure:"eject_iso_delay"` // Set to true to expunge the instance when it is // destroyed. Defaults to false. Expunge bool `mapstructure:"expunge" required:"false"` @@ -200,8 +199,8 @@ func NewConfig(raws ...interface{}) (*Config, error) { c.SecretKey = os.Getenv("CLOUDSTACK_SECRET_KEY") } - if c.AsyncTimeout == 0 { - c.AsyncTimeout = 30 * time.Minute + if c.AsyncTimeout == "" { + c.AsyncTimeout = "30m" } if len(c.CIDRList) == 0 { diff --git a/builder/cloudstack/step_detach_iso.go b/builder/cloudstack/step_detach_iso.go index 444293c2c..748f139a8 100644 --- a/builder/cloudstack/step_detach_iso.go +++ b/builder/cloudstack/step_detach_iso.go @@ -25,9 +25,9 @@ func (s *stepDetachIso) Run(ctx context.Context, state multistep.StateBag) multi ui.Say("Checking attached iso...") // Wait to make call detachIso - if config.EjectISODelay > 0 { + if config.EjectISODelay.Duration() > 0 { ui.Message(fmt.Sprintf("Waiting for %v before detaching ISO from virtual machine...", config.EjectISODelay)) - time.Sleep(config.EjectISODelay) + time.Sleep(config.EjectISODelay.Duration()) } client := state.Get("client").(*cloudstack.CloudStackClient) diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index 661e2c2a4..1b3cdb23d 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -96,7 +96,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack new(stepShutdown), new(stepPowerOff), &stepSnapshot{ - snapshotTimeout: b.config.SnapshotTimeout, + snapshotTimeout: b.config.SnapshotTimeout.Duration(), }, } diff --git a/builder/digitalocean/builder_test.go b/builder/digitalocean/builder_test.go index 70ec6fea9..02db72d25 100644 --- a/builder/digitalocean/builder_test.go +++ b/builder/digitalocean/builder_test.go @@ -165,7 +165,7 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) { t.Fatalf("should not have error: %s", err) } - if b.config.StateTimeout != 6*time.Minute { + if b.config.StateTimeout.Duration() != 6*time.Minute { t.Errorf("invalid: %s", b.config.StateTimeout) } @@ -205,7 +205,7 @@ func TestBuilderPrepare_SnapshotTimeout(t *testing.T) { t.Fatalf("should not have error: %s", err) } - if b.config.SnapshotTimeout != 60*time.Minute { + if b.config.SnapshotTimeout.Duration() != 60*time.Minute { t.Errorf("invalid: %s", b.config.SnapshotTimeout) } diff --git a/builder/digitalocean/config.go b/builder/digitalocean/config.go index eef4e5e13..832818a7e 100644 --- a/builder/digitalocean/config.go +++ b/builder/digitalocean/config.go @@ -8,7 +8,6 @@ import ( "fmt" "os" "regexp" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/uuid" @@ -64,7 +63,7 @@ type Config struct { // 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 "6m". - StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"` + StateTimeout config.DurationString `mapstructure:"state_timeout" required:"false"` // How long to wait for an image to be published to the shared image // gallery before timing out. If your Packer build is failing on the // Publishing to Shared Image Gallery step with the error `Original Error: @@ -72,7 +71,7 @@ type Config struct { // Azure dashboard, then you probably need to increase this timeout from // its default of "60m" (valid time units include `s` for seconds, `m` for // minutes, and `h` for hours.) - SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout" required:"false"` + SnapshotTimeout config.DurationString `mapstructure:"snapshot_timeout" required:"false"` // The name assigned to the droplet. DigitalOcean // sets the hostname of the machine to this value. DropletName string `mapstructure:"droplet_name" required:"false"` @@ -130,18 +129,27 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } - if c.StateTimeout == 0 { + if c.StateTimeout == "" { // Default to 6 minute timeouts waiting for // desired state. i.e waiting for droplet to become active - c.StateTimeout = 6 * time.Minute + c.StateTimeout = "6m" } - if c.SnapshotTimeout == 0 { + if c.SnapshotTimeout == "" { // Default to 60 minutes timeout, waiting for snapshot action to finish - c.SnapshotTimeout = 60 * time.Minute + c.SnapshotTimeout = "60m" } var errs *packer.MultiError + + if err := c.StateTimeout.Validate(); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + + if err := c.SnapshotTimeout.Validate(); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } diff --git a/builder/digitalocean/step_droplet_info.go b/builder/digitalocean/step_droplet_info.go index dc7a9ed8a..b7ff1d19f 100644 --- a/builder/digitalocean/step_droplet_info.go +++ b/builder/digitalocean/step_droplet_info.go @@ -19,7 +19,7 @@ func (s *stepDropletInfo) Run(ctx context.Context, state multistep.StateBag) mul ui.Say("Waiting for droplet to become active...") - err := waitForDropletState("active", dropletID, client, c.StateTimeout) + err := waitForDropletState("active", dropletID, client, c.StateTimeout.Duration()) if err != nil { err := fmt.Errorf("Error waiting for droplet to become active: %s", err) state.Put("error", err) diff --git a/builder/digitalocean/step_power_off.go b/builder/digitalocean/step_power_off.go index fab35569a..a9248efbb 100644 --- a/builder/digitalocean/step_power_off.go +++ b/builder/digitalocean/step_power_off.go @@ -42,7 +42,7 @@ func (s *stepPowerOff) Run(ctx context.Context, state multistep.StateBag) multis } log.Println("Waiting for poweroff event to complete...") - err = waitForDropletState("off", dropletId, client, c.StateTimeout) + err = waitForDropletState("off", dropletId, client, c.StateTimeout.Duration()) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -50,7 +50,7 @@ func (s *stepPowerOff) Run(ctx context.Context, state multistep.StateBag) multis } // Wait for the droplet to become unlocked for future steps - if err := waitForDropletUnlocked(client, dropletId, c.StateTimeout); err != nil { + if err := waitForDropletUnlocked(client, dropletId, c.StateTimeout.Duration()); err != nil { // If we get an error the first time, actually report it err := fmt.Errorf("Error powering off droplet: %s", err) state.Put("error", err) diff --git a/builder/digitalocean/step_shutdown.go b/builder/digitalocean/step_shutdown.go index 339e034b7..120d90a0c 100644 --- a/builder/digitalocean/step_shutdown.go +++ b/builder/digitalocean/step_shutdown.go @@ -65,7 +65,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis } }() - err = waitForDropletState("off", dropletId, client, c.StateTimeout) + err = waitForDropletState("off", dropletId, client, c.StateTimeout.Duration()) if err != nil { // If we get an error the first time, actually report it err := fmt.Errorf("Error shutting down droplet: %s", err) @@ -74,7 +74,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis return multistep.ActionHalt } - if err := waitForDropletUnlocked(client, dropletId, c.StateTimeout); err != nil { + if err := waitForDropletUnlocked(client, dropletId, c.StateTimeout.Duration()); err != nil { // If we get an error the first time, actually report it err := fmt.Errorf("Error shutting down droplet: %s", err) state.Put("error", err) diff --git a/builder/googlecompute/config.go b/builder/googlecompute/config.go index bb7cd21b1..b1b85563f 100644 --- a/builder/googlecompute/config.go +++ b/builder/googlecompute/config.go @@ -8,7 +8,6 @@ import ( "fmt" "os" "regexp" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/uuid" @@ -121,7 +120,7 @@ type Config struct { // If true, launch a preemptible instance. Preemptible bool `mapstructure:"preemptible" required:"false"` // The time to wait for instance state changes. Defaults to "5m". - RawStateTimeout string `mapstructure:"state_timeout" required:"false"` + StateTimeout config.DurationString `mapstructure:"state_timeout" required:"false"` // The region in which to launch the instance. Defaults to the region // hosting the specified zone. Region string `mapstructure:"region" required:"false"` @@ -183,7 +182,6 @@ type Config struct { Zone string `mapstructure:"zone" required:"true"` account *jwt.Config - stateTimeout time.Duration imageAlreadyExists bool ctx interpolate.Context } @@ -293,8 +291,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.MachineType = "n1-standard-1" } - if c.RawStateTimeout == "" { - c.RawStateTimeout = "5m" + if c.StateTimeout == "" { + c.StateTimeout = "5m" + } + + if err := c.StateTimeout.Validate(); err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) } if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { @@ -330,11 +332,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.Region = region } - err = c.CalcTimeout() - if err != nil { - errs = packer.MultiErrorAppend(errs, err) - } - // Authenticating via an account file if c.AccountFile != "" { if c.VaultGCPOauthEngine != "" { @@ -384,15 +381,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { return c, nil, nil } -func (c *Config) CalcTimeout() error { - stateTimeout, err := time.ParseDuration(c.RawStateTimeout) - if err != nil { - return fmt.Errorf("Failed parsing state_timeout: %s", err) - } - c.stateTimeout = stateTimeout - return nil -} - type CustomerEncryptionKey struct { // KmsKeyName: The name of the encryption key that is stored in Google // Cloud KMS. diff --git a/builder/googlecompute/config.hcl2spec.go b/builder/googlecompute/config.hcl2spec.go index 3f2e62d09..cfa169a02 100644 --- a/builder/googlecompute/config.hcl2spec.go +++ b/builder/googlecompute/config.hcl2spec.go @@ -82,7 +82,7 @@ type FlatConfig struct { OmitExternalIP *bool `mapstructure:"omit_external_ip" required:"false" cty:"omit_external_ip"` OnHostMaintenance *string `mapstructure:"on_host_maintenance" required:"false" cty:"on_host_maintenance"` Preemptible *bool `mapstructure:"preemptible" required:"false" cty:"preemptible"` - RawStateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout"` + StateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout"` Region *string `mapstructure:"region" required:"false" cty:"region"` Scopes []string `mapstructure:"scopes" required:"false" cty:"scopes"` ServiceAccountEmail *string `mapstructure:"service_account_email" required:"false" cty:"service_account_email"` diff --git a/builder/googlecompute/step_create_image.go b/builder/googlecompute/step_create_image.go index 389338c43..51aeb9264 100644 --- a/builder/googlecompute/step_create_image.go +++ b/builder/googlecompute/step_create_image.go @@ -44,7 +44,7 @@ func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul var err error select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for image to register") } diff --git a/builder/googlecompute/step_create_instance.go b/builder/googlecompute/step_create_instance.go index 6004c2fab..a0bd48d3a 100644 --- a/builder/googlecompute/step_create_instance.go +++ b/builder/googlecompute/step_create_instance.go @@ -154,7 +154,7 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag) ui.Message("Waiting for creation operation to complete...") select { case err = <-errCh: - case <-time.After(c.stateTimeout): + case <-time.After(c.StateTimeout.Duration()): err = errors.New("time out while waiting for instance to create") } } @@ -200,7 +200,7 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) { if err == nil { select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for instance to delete") } } @@ -222,7 +222,7 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) { if err == nil { select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for disk to delete") } } diff --git a/builder/googlecompute/step_create_instance_test.go b/builder/googlecompute/step_create_instance_test.go index 33f0371fb..0065255dc 100644 --- a/builder/googlecompute/step_create_instance_test.go +++ b/builder/googlecompute/step_create_instance_test.go @@ -5,7 +5,6 @@ import ( "errors" "strings" "testing" - "time" "github.com/hashicorp/packer/helper/multistep" "github.com/stretchr/testify/assert" @@ -232,7 +231,7 @@ func TestStepCreateInstance_errorTimeout(t *testing.T) { errCh := make(chan error, 1) config := state.Get("config").(*Config) - config.stateTimeout = 1 * time.Microsecond + config.StateTimeout = "1ms" d := state.Get("driver").(*DriverMock) d.RunInstanceErrCh = errCh diff --git a/builder/googlecompute/step_create_windows_password.go b/builder/googlecompute/step_create_windows_password.go index a5ddb5950..60a0d2fa0 100644 --- a/builder/googlecompute/step_create_windows_password.go +++ b/builder/googlecompute/step_create_windows_password.go @@ -99,7 +99,7 @@ func (s *StepCreateWindowsPassword) Run(ctx context.Context, state multistep.Sta ui.Message("Waiting for windows password to complete...") select { case err = <-errCh: - case <-time.After(c.stateTimeout): + case <-time.After(c.StateTimeout.Duration()): err = errors.New("time out while waiting for the password to be created") } } diff --git a/builder/googlecompute/step_instance_info.go b/builder/googlecompute/step_instance_info.go index 1809fbb84..d419b8cfd 100644 --- a/builder/googlecompute/step_instance_info.go +++ b/builder/googlecompute/step_instance_info.go @@ -29,7 +29,7 @@ func (s *StepInstanceInfo) Run(ctx context.Context, state multistep.StateBag) mu var err error select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for instance to become running") } diff --git a/builder/googlecompute/step_instance_info_test.go b/builder/googlecompute/step_instance_info_test.go index e3d0febaf..6cad9a06d 100644 --- a/builder/googlecompute/step_instance_info_test.go +++ b/builder/googlecompute/step_instance_info_test.go @@ -156,7 +156,7 @@ func TestStepInstanceInfo_errorTimeout(t *testing.T) { state.Put("instance_name", "foo") config := state.Get("config").(*Config) - config.stateTimeout = 1 * time.Microsecond + config.StateTimeout = "1ms" driver := state.Get("driver").(*DriverMock) driver.WaitForInstanceErrCh = errCh diff --git a/builder/googlecompute/step_teardown_instance.go b/builder/googlecompute/step_teardown_instance.go index c992dead3..ae3c13ec2 100644 --- a/builder/googlecompute/step_teardown_instance.go +++ b/builder/googlecompute/step_teardown_instance.go @@ -34,7 +34,7 @@ func (s *StepTeardownInstance) Run(ctx context.Context, state multistep.StateBag if err == nil { select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for instance to delete") } } @@ -64,7 +64,7 @@ func (s *StepTeardownInstance) Cleanup(state multistep.StateBag) { if err == nil { select { case err = <-errCh: - case <-time.After(config.stateTimeout): + case <-time.After(config.StateTimeout.Duration()): err = errors.New("time out while waiting for disk to delete") } } diff --git a/builder/hcloud/builder.go b/builder/hcloud/builder.go index 92f9f474b..28b7e3489 100644 --- a/builder/hcloud/builder.go +++ b/builder/hcloud/builder.go @@ -35,7 +35,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack opts := []hcloud.ClientOption{ hcloud.WithToken(b.config.HCloudToken), hcloud.WithEndpoint(b.config.Endpoint), - hcloud.WithPollInterval(b.config.PollInterval), + hcloud.WithPollInterval(b.config.PollInterval.Duration()), hcloud.WithApplication("hcloud-packer", pluginVersion), } b.hcloudClient = hcloud.NewClient(opts...) diff --git a/builder/hcloud/config.go b/builder/hcloud/config.go index 73687ba5e..1fe711079 100644 --- a/builder/hcloud/config.go +++ b/builder/hcloud/config.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "os" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/uuid" @@ -23,9 +22,10 @@ type Config struct { common.PackerConfig `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"` - HCloudToken string `mapstructure:"token"` - Endpoint string `mapstructure:"endpoint"` - PollInterval time.Duration `mapstructure:"poll_interval"` + HCloudToken string `mapstructure:"token"` + Endpoint string `mapstructure:"endpoint"` + + PollInterval config.DurationString `mapstructure:"poll_interval"` ServerName string `mapstructure:"server_name"` Location string `mapstructure:"location"` @@ -78,8 +78,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.Endpoint = hcloud.Endpoint } } - if c.PollInterval == 0 { - c.PollInterval = 500 * time.Millisecond + if c.PollInterval == "" { + c.PollInterval = "500ms" } if c.SnapshotName == "" { diff --git a/builder/hyperone/builder.go b/builder/hyperone/builder.go index d9e85e5f0..e2e0c27b5 100644 --- a/builder/hyperone/builder.go +++ b/builder/hyperone/builder.go @@ -38,7 +38,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { cfg.BasePath = b.config.APIURL } - prefer := fmt.Sprintf("respond-async,wait=%d", int(b.config.StateTimeout.Seconds())) + prefer := fmt.Sprintf("respond-async,wait=%d", int(b.config.StateTimeout.Duration().Seconds())) cfg.AddDefaultHeader("Prefer", prefer) b.client = openapi.NewAPIClient(cfg) diff --git a/builder/hyperone/config.go b/builder/hyperone/config.go index f9173f7ce..7833007fc 100644 --- a/builder/hyperone/config.go +++ b/builder/hyperone/config.go @@ -8,7 +8,6 @@ import ( "fmt" "io/ioutil" "os" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/json" @@ -28,7 +27,7 @@ const ( defaultDiskType = "ssd" defaultImageService = "564639bc052c084e2f2e3266" - defaultStateTimeout = 5 * time.Minute + defaultStateTimeout = "5m" defaultUserName = "guru" ) @@ -51,7 +50,7 @@ type Config struct { TokenLogin string `mapstructure:"token_login" required:"false"` // Timeout for waiting on the API to complete // a request. Defaults to 5m. - StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"` + StateTimeout config.DurationString `mapstructure:"state_timeout" required:"false"` // ID or name of the image to launch server from. SourceImage string `mapstructure:"source_image" required:"true"` // The name of the resulting image. Defaults to @@ -146,8 +145,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.Comm.SSHUsername = defaultUserName } - if c.Comm.SSHTimeout == 0 { - c.Comm.SSHTimeout = 10 * time.Minute + if c.Comm.SSHTimeout == "" { + c.Comm.SSHTimeout = "10m" } if c.APIURL == "" { @@ -174,7 +173,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.Project = cliConfig.Profile.Project.ID } - if c.StateTimeout == 0 { + if c.StateTimeout == "" { c.StateTimeout = defaultStateTimeout } diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go index 1b40fac84..c8754fc01 100644 --- a/builder/hyperv/iso/builder.go +++ b/builder/hyperv/iso/builder.go @@ -270,10 +270,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &hypervcommon.StepTypeBootCommand{ BootCommand: b.config.FlatBootCommand(), - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), SwitchName: b.config.SwitchName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), }, // configure the communicator ssh, winrm @@ -293,7 +293,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &hypervcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, // wait for the vm to be powered off diff --git a/builder/hyperv/iso/builder.hcl2spec.go b/builder/hyperv/iso/builder.hcl2spec.go index e16785646..09f3fa0d3 100644 --- a/builder/hyperv/iso/builder.hcl2spec.go +++ b/builder/hyperv/iso/builder.hcl2spec.go @@ -26,10 +26,9 @@ type FlatConfig struct { ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls"` TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path"` TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` @@ -99,7 +98,7 @@ type FlatConfig struct { SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export"` Headless *bool `mapstructure:"headless" required:"false" cty:"headless"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` DiskSize *uint `mapstructure:"disk_size" required:"false" cty:"disk_size"` UseLegacyNetworkAdapter *bool `mapstructure:"use_legacy_network_adapter" required:"false" cty:"use_legacy_network_adapter"` DifferencingDisk *bool `mapstructure:"differencing_disk" required:"false" cty:"differencing_disk"` @@ -135,7 +134,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, diff --git a/builder/hyperv/vmcx/builder.go b/builder/hyperv/vmcx/builder.go index af93007e5..07123b072 100644 --- a/builder/hyperv/vmcx/builder.go +++ b/builder/hyperv/vmcx/builder.go @@ -318,10 +318,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &hypervcommon.StepTypeBootCommand{ BootCommand: b.config.FlatBootCommand(), - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), SwitchName: b.config.SwitchName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), }, // configure the communicator ssh, winrm @@ -341,7 +341,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &hypervcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, // wait for the vm to be powered off diff --git a/builder/hyperv/vmcx/builder.hcl2spec.go b/builder/hyperv/vmcx/builder.hcl2spec.go index 44971c8cb..1ba1e83ee 100644 --- a/builder/hyperv/vmcx/builder.hcl2spec.go +++ b/builder/hyperv/vmcx/builder.hcl2spec.go @@ -26,10 +26,9 @@ type FlatConfig struct { ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls"` TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path"` TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` @@ -99,7 +98,7 @@ type FlatConfig struct { SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export"` Headless *bool `mapstructure:"headless" required:"false" cty:"headless"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` CloneFromVMCXPath *string `mapstructure:"clone_from_vmcx_path" cty:"clone_from_vmcx_path"` CloneFromVMName *string `mapstructure:"clone_from_vm_name" cty:"clone_from_vm_name"` CloneFromSnapshotName *string `mapstructure:"clone_from_snapshot_name" required:"false" cty:"clone_from_snapshot_name"` @@ -137,7 +136,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, diff --git a/builder/oracle/classic/config.go b/builder/oracle/classic/config.go index 4fc1ddb15..7b56e2ecb 100644 --- a/builder/oracle/classic/config.go +++ b/builder/oracle/classic/config.go @@ -9,7 +9,6 @@ import ( "net/url" "os" "regexp" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -32,12 +31,12 @@ type Config struct { apiEndpointURL *url.URL // Image - ImageName string `mapstructure:"image_name"` - Shape string `mapstructure:"shape"` - SourceImageList string `mapstructure:"source_image_list"` - SourceImageListEntry int `mapstructure:"source_image_list_entry"` - SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout"` - DestImageList string `mapstructure:"dest_image_list"` + ImageName string `mapstructure:"image_name"` + Shape string `mapstructure:"shape"` + SourceImageList string `mapstructure:"source_image_list"` + SourceImageListEntry int `mapstructure:"source_image_list_entry"` + SnapshotTimeout config.DurationString `mapstructure:"snapshot_timeout"` + DestImageList string `mapstructure:"dest_image_list"` // Attributes and Attributes file are both optional and mutually exclusive. Attributes string `mapstructure:"attributes"` AttributesFile string `mapstructure:"attributes_file"` @@ -78,8 +77,8 @@ func NewConfig(raws ...interface{}) (*Config, error) { c.SSHSourceList = "seciplist:/oracle/public/public-internet" } - if c.SnapshotTimeout == 0 { - c.SnapshotTimeout = 20 * time.Minute + if c.SnapshotTimeout == "" { + c.SnapshotTimeout = "20m" } // Validate that all required fields are present diff --git a/builder/oracle/classic/step_snapshot.go b/builder/oracle/classic/step_snapshot.go index f11f718e0..c5912e0c7 100644 --- a/builder/oracle/classic/step_snapshot.go +++ b/builder/oracle/classic/step_snapshot.go @@ -28,7 +28,7 @@ func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multis snapshotInput := &compute.CreateSnapshotInput{ Instance: fmt.Sprintf("%s/%s", config.ImageName, instanceID), MachineImage: config.ImageName, - Timeout: config.SnapshotTimeout, + Timeout: config.SnapshotTimeout.Duration(), } snap, err := snapshotClient.CreateSnapshot(snapshotInput) diff --git a/builder/parallels/common/ssh_config.go b/builder/parallels/common/ssh_config.go index 10fdb30cc..df0125ce0 100644 --- a/builder/parallels/common/ssh_config.go +++ b/builder/parallels/common/ssh_config.go @@ -1,9 +1,8 @@ package common import ( - "time" - "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -13,13 +12,13 @@ type SSHConfig struct { // These are deprecated, but we keep them around for BC // TODO(@mitchellh): remove - SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"` + SSHWaitTimeout config.DurationString `mapstructure:"ssh_wait_timeout"` } // Prepare sets the default values for SSH communicator properties. func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { // TODO: backwards compatibility, write fixer instead - if c.SSHWaitTimeout != 0 { + if c.SSHWaitTimeout != "" { c.Comm.SSHTimeout = c.SSHWaitTimeout } diff --git a/builder/parallels/iso/builder.go b/builder/parallels/iso/builder.go index b7ea4788f..b2355aef5 100644 --- a/builder/parallels/iso/builder.go +++ b/builder/parallels/iso/builder.go @@ -224,12 +224,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, ¶llelscommon.StepRun{}, ¶llelscommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), BootCommand: b.config.FlatBootCommand(), HostInterfaces: b.config.HostInterfaces, VMName: b.config.VMName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), }, &communicator.StepConnect{ Config: &b.config.SSHConfig.Comm, @@ -251,7 +251,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, ¶llelscommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, ¶llelscommon.StepPrlctl{ Commands: b.config.PrlctlPost, diff --git a/builder/parallels/iso/builder.hcl2spec.go b/builder/parallels/iso/builder.hcl2spec.go index 73f4aefe5..e8e6e506c 100644 --- a/builder/parallels/iso/builder.hcl2spec.go +++ b/builder/parallels/iso/builder.hcl2spec.go @@ -29,10 +29,9 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` CpuCount *int `mapstructure:"cpus" required:"false" cty:"cpus"` MemorySize *int `mapstructure:"memory" required:"false" cty:"memory"` @@ -42,7 +41,7 @@ type FlatConfig struct { PrlctlPost [][]string `mapstructure:"prlctl_post" required:"false" cty:"prlctl_post"` PrlctlVersionFile *string `mapstructure:"prlctl_version_file" required:"false" cty:"prlctl_version_file"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -128,7 +127,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, "cpus": &hcldec.AttrSpec{Name: "cpus", Type: cty.Number, Required: false}, "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, diff --git a/builder/parallels/pvm/builder.go b/builder/parallels/pvm/builder.go index a199650d1..79e282e4b 100644 --- a/builder/parallels/pvm/builder.go +++ b/builder/parallels/pvm/builder.go @@ -78,11 +78,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack ¶llelscommon.StepRun{}, ¶llelscommon.StepTypeBootCommand{ BootCommand: b.config.FlatBootCommand(), - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), HostInterfaces: []string{}, VMName: b.config.VMName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), }, &communicator.StepConnect{ Config: &b.config.SSHConfig.Comm, @@ -101,7 +101,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack new(common.StepProvision), ¶llelscommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, &common.StepCleanupTempKeys{ Comm: &b.config.SSHConfig.Comm, diff --git a/builder/parallels/pvm/config.hcl2spec.go b/builder/parallels/pvm/config.hcl2spec.go index b0a1f90a4..77d76625f 100644 --- a/builder/parallels/pvm/config.hcl2spec.go +++ b/builder/parallels/pvm/config.hcl2spec.go @@ -65,11 +65,10 @@ type FlatConfig struct { WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" cty:"ssh_wait_timeout"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` ParallelsToolsFlavor *string `mapstructure:"parallels_tools_flavor" required:"true" cty:"parallels_tools_flavor"` ParallelsToolsGuestPath *string `mapstructure:"parallels_tools_guest_path" required:"false" cty:"parallels_tools_guest_path"` ParallelsToolsMode *string `mapstructure:"parallels_tools_mode" required:"false" cty:"parallels_tools_mode"` @@ -148,7 +147,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "parallels_tools_flavor": &hcldec.AttrSpec{Name: "parallels_tools_flavor", Type: cty.String, Required: false}, "parallels_tools_guest_path": &hcldec.AttrSpec{Name: "parallels_tools_guest_path", Type: cty.String, Required: false}, "parallels_tools_mode": &hcldec.AttrSpec{Name: "parallels_tools_mode", Type: cty.String, Required: false}, diff --git a/builder/proxmox/config.hcl2spec.go b/builder/proxmox/config.hcl2spec.go index a8cc2c0f0..abfee583c 100644 --- a/builder/proxmox/config.hcl2spec.go +++ b/builder/proxmox/config.hcl2spec.go @@ -19,10 +19,9 @@ type FlatConfig struct { HTTPDir *string `mapstructure:"http_directory" cty:"http_directory"` HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min"` HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` RawBootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` @@ -109,7 +108,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, diff --git a/builder/proxmox/step_type_boot_command.go b/builder/proxmox/step_type_boot_command.go index 97cb70c54..170096aa3 100644 --- a/builder/proxmox/step_type_boot_command.go +++ b/builder/proxmox/step_type_boot_command.go @@ -46,10 +46,10 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) return multistep.ActionContinue } - if int64(s.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot", s.BootWait.String())) + if int64(s.BootWait.Duration()) > 0 { + ui.Say(fmt.Sprintf("Waiting %s for boot", s.BootWait)) select { - case <-time.After(s.BootWait): + case <-time.After(s.BootWait.Duration()): break case <-ctx.Done(): return multistep.ActionHalt diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 989e4e277..e568940f2 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -12,7 +12,6 @@ import ( "os/exec" "path/filepath" "runtime" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/bootcommand" @@ -320,7 +319,7 @@ type Config struct { // These are deprecated, but we keep them around for BC // TODO(@mitchellh): remove - SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout" required:"false"` + SSHWaitTimeout config.DurationString `mapstructure:"ssh_wait_timeout" required:"false"` // TODO(mitchellh): deprecate RunOnce bool `mapstructure:"run_once"` @@ -446,7 +445,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } // TODO: backwards compatibility, write fixer instead - if b.config.SSHWaitTimeout != 0 { + if b.config.SSHWaitTimeout != "" { b.config.Comm.SSHTimeout = b.config.SSHWaitTimeout } @@ -463,6 +462,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, es...) } + if err := b.config.SSHWaitTimeout.Validate(); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + if !(b.config.Format == "qcow2" || b.config.Format == "raw") { errs = packer.MultiErrorAppend( errs, errors.New("invalid format, only 'qcow2' or 'raw' are allowed")) diff --git a/builder/qemu/builder.hcl2spec.go b/builder/qemu/builder.hcl2spec.go index 4675ba834..84697974b 100644 --- a/builder/qemu/builder.hcl2spec.go +++ b/builder/qemu/builder.hcl2spec.go @@ -26,14 +26,13 @@ type FlatConfig struct { ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls"` TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path"` TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` DisableVNC *bool `mapstructure:"disable_vnc" cty:"disable_vnc"` - RawBootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -141,7 +140,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "disable_vnc": &hcldec.AttrSpec{Name: "disable_vnc", Type: cty.Bool, Required: false}, "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, diff --git a/builder/qemu/step_shutdown.go b/builder/qemu/step_shutdown.go index b883e97e1..86919cc35 100644 --- a/builder/qemu/step_shutdown.go +++ b/builder/qemu/step_shutdown.go @@ -33,7 +33,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis cancelCh := make(chan struct{}, 1) go func() { defer close(cancelCh) - <-time.After(config.ShutdownTimeout) + <-time.After(config.ShutdownTimeout.Duration()) }() ui.Say("Waiting for shutdown...") if ok := driver.WaitForShutdown(cancelCh); ok { @@ -63,7 +63,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis cancelCh := make(chan struct{}, 1) go func() { defer close(cancelCh) - <-time.After(config.ShutdownTimeout) + <-time.After(config.ShutdownTimeout.Duration()) }() log.Printf("Waiting max %s for shutdown to complete", config.ShutdownTimeout) diff --git a/builder/qemu/step_type_boot_command.go b/builder/qemu/step_type_boot_command.go index 4bce10d0c..cbeb5c7a3 100644 --- a/builder/qemu/step_type_boot_command.go +++ b/builder/qemu/step_type_boot_command.go @@ -50,10 +50,10 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) } // Wait the for the vm to boot. - if int64(config.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot...", config.BootWait.String())) + if int64(config.BootWait.Duration()) > 0 { + ui.Say(fmt.Sprintf("Waiting %s for boot...", config.BootWait)) select { - case <-time.After(config.BootWait): + case <-time.After(config.BootWait.Duration()): break case <-ctx.Done(): return multistep.ActionHalt @@ -105,7 +105,7 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) config.VMName, } - d := bootcommand.NewVNCDriver(c, config.VNCConfig.BootKeyInterval) + d := bootcommand.NewVNCDriver(c, config.VNCConfig.BootKeyInterval.Duration()) ui.Say("Typing the boot command over VNC...") command, err := interpolate.Render(config.VNCConfig.FlatBootCommand(), &configCtx) diff --git a/builder/vagrant/builder.go b/builder/vagrant/builder.go index a922ed017..e763418a0 100644 --- a/builder/vagrant/builder.go +++ b/builder/vagrant/builder.go @@ -10,7 +10,6 @@ import ( "os" "path/filepath" "strings" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/bootcommand" @@ -155,8 +154,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName) } - if b.config.Comm.SSHTimeout == 0 { - b.config.Comm.SSHTimeout = 10 * time.Minute + if b.config.Comm.SSHTimeout == "" { + b.config.Comm.SSHTimeout = "10m" } if b.config.Comm.Type != "ssh" { diff --git a/builder/vagrant/builder.hcl2spec.go b/builder/vagrant/builder.hcl2spec.go index 710a6ad3b..1a9dece69 100644 --- a/builder/vagrant/builder.hcl2spec.go +++ b/builder/vagrant/builder.hcl2spec.go @@ -29,10 +29,9 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -130,7 +129,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/common/shutdown_config.go b/builder/virtualbox/common/shutdown_config.go index 63b58d8a5..80ecae3b4 100644 --- a/builder/virtualbox/common/shutdown_config.go +++ b/builder/virtualbox/common/shutdown_config.go @@ -4,8 +4,8 @@ package common import ( "fmt" - "time" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -22,35 +22,29 @@ type ShutdownConfig struct { // shutdown_command for the virtual machine to actually shut down. If it // doesn't shut down in this time, it is an error. By default, the timeout is // 5m or five minutes. - RawShutdownTimeout string `mapstructure:"shutdown_timeout" required:"false"` + ShutdownTimeout config.DurationString `mapstructure:"shutdown_timeout" required:"false"` // The amount of time to wait after shutting // down the virtual machine. If you get the error // Error removing floppy controller, you might need to set this to 5m // or so. By default, the delay is 0s or disabled. - RawPostShutdownDelay string `mapstructure:"post_shutdown_delay" required:"false"` - - ShutdownTimeout time.Duration `` - PostShutdownDelay time.Duration `` + PostShutdownDelay config.DurationString `mapstructure:"post_shutdown_delay" required:"false"` } func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error { - if c.RawShutdownTimeout == "" { - c.RawShutdownTimeout = "5m" + if c.ShutdownTimeout == "" { + c.ShutdownTimeout = "5m" } - if c.RawPostShutdownDelay == "" { - c.RawPostShutdownDelay = "0s" + if c.PostShutdownDelay == "" { + c.PostShutdownDelay = "0s" } var errs []error - var err error - c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout) - if err != nil { + if err := c.ShutdownTimeout.Validate(); err != nil { errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err)) } - c.PostShutdownDelay, err = time.ParseDuration(c.RawPostShutdownDelay) - if err != nil { + if err := c.PostShutdownDelay.Validate(); err != nil { errs = append(errs, fmt.Errorf("Failed parsing post_shutdown_delay: %s", err)) } diff --git a/builder/virtualbox/common/shutdown_config_test.go b/builder/virtualbox/common/shutdown_config_test.go index 897e673bc..1a67f69ba 100644 --- a/builder/virtualbox/common/shutdown_config_test.go +++ b/builder/virtualbox/common/shutdown_config_test.go @@ -28,7 +28,7 @@ func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) { // Test with a bad value c = testShutdownConfig() - c.RawShutdownTimeout = "this is not good" + c.ShutdownTimeout = "this is not good" errs = c.Prepare(interpolate.NewContext()) if len(errs) == 0 { t.Fatalf("should have error") @@ -36,12 +36,12 @@ func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) { // Test with a good one c = testShutdownConfig() - c.RawShutdownTimeout = "5s" + c.ShutdownTimeout = "5s" errs = c.Prepare(interpolate.NewContext()) if len(errs) > 0 { t.Fatalf("err: %#v", errs) } - if c.ShutdownTimeout != 5*time.Second { + if c.ShutdownTimeout.Duration() != 5*time.Second { t.Fatalf("bad: %s", c.ShutdownTimeout) } } @@ -52,7 +52,7 @@ func TestShutdownConfigPrepare_PostShutdownDelay(t *testing.T) { // Test with a bad value c = testShutdownConfig() - c.RawPostShutdownDelay = "this is not good" + c.PostShutdownDelay = "this is not good" errs = c.Prepare(interpolate.NewContext()) if len(errs) == 0 { t.Fatalf("should have error") @@ -60,23 +60,23 @@ func TestShutdownConfigPrepare_PostShutdownDelay(t *testing.T) { // Test with default value c = testShutdownConfig() - c.RawPostShutdownDelay = "" + c.PostShutdownDelay = "" errs = c.Prepare(interpolate.NewContext()) if len(errs) > 0 { t.Fatalf("err: %#v", errs) } - if c.PostShutdownDelay.Nanoseconds() != 0 { + if c.PostShutdownDelay.Duration().Nanoseconds() != 0 { t.Fatalf("bad: %s", c.PostShutdownDelay) } // Test with a good one c = testShutdownConfig() - c.RawPostShutdownDelay = "5s" + c.PostShutdownDelay = "5s" errs = c.Prepare(interpolate.NewContext()) if len(errs) > 0 { t.Fatalf("err: %#v", errs) } - if c.PostShutdownDelay != 5*time.Second { + if c.PostShutdownDelay.Duration() != 5*time.Second { t.Fatalf("bad: %s", c.PostShutdownDelay) } } diff --git a/builder/virtualbox/common/ssh_config.go b/builder/virtualbox/common/ssh_config.go index 074415535..12d7284c4 100644 --- a/builder/virtualbox/common/ssh_config.go +++ b/builder/virtualbox/common/ssh_config.go @@ -4,9 +4,9 @@ package common import ( "errors" - "time" "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -26,7 +26,7 @@ type SSHConfig struct { // These are deprecated, but we keep them around for BC // TODO(@mitchellh): remove - SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"` + SSHWaitTimeout config.DurationString `mapstructure:"ssh_wait_timeout"` } func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { @@ -43,7 +43,7 @@ func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { } // TODO: backwards compatibility, write fixer instead - if c.SSHWaitTimeout != 0 { + if c.SSHWaitTimeout != "" { c.Comm.SSHTimeout = c.SSHWaitTimeout } diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index 5ff62c54e..36a5eaca0 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -319,11 +319,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Headless: b.config.Headless, }, &vboxcommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), BootCommand: b.config.FlatBootCommand(), VMName: b.config.VMName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), Comm: &b.config.Comm, }, &communicator.StepConnect{ @@ -347,8 +347,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &vboxcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, - Delay: b.config.PostShutdownDelay, + Timeout: b.config.ShutdownTimeout.Duration(), + Delay: b.config.PostShutdownDelay.Duration(), }, &vboxcommon.StepRemoveDevices{ Bundling: b.config.VBoxBundleConfig, diff --git a/builder/virtualbox/iso/builder.hcl2spec.go b/builder/virtualbox/iso/builder.hcl2spec.go index af6d5027f..2eb36629e 100644 --- a/builder/virtualbox/iso/builder.hcl2spec.go +++ b/builder/virtualbox/iso/builder.hcl2spec.go @@ -29,10 +29,9 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` Format *string `mapstructure:"format" required:"false" cty:"format"` ExportOpts []string `mapstructure:"export_opts" required:"false" cty:"export_opts"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` @@ -41,8 +40,8 @@ type FlatConfig struct { VRDPPortMin *int `mapstructure:"vrdp_port_min" required:"false" cty:"vrdp_port_min"` VRDPPortMax *int `mapstructure:"vrdp_port_max" cty:"vrdp_port_max"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` - RawPostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -144,7 +143,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, "export_opts": &hcldec.AttrSpec{Name: "export_opts", Type: cty.List(cty.String), Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/ovf/builder.go b/builder/virtualbox/ovf/builder.go index 260a4ce64..7abf36b64 100644 --- a/builder/virtualbox/ovf/builder.go +++ b/builder/virtualbox/ovf/builder.go @@ -112,11 +112,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Headless: b.config.Headless, }, &vboxcommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), BootCommand: b.config.FlatBootCommand(), VMName: b.config.VMName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), Comm: &b.config.Comm, }, &communicator.StepConnect{ @@ -140,8 +140,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &vboxcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, - Delay: b.config.PostShutdownDelay, + Timeout: b.config.ShutdownTimeout.Duration(), + Delay: b.config.PostShutdownDelay.Duration(), }, &vboxcommon.StepRemoveDevices{ GuestAdditionsInterface: b.config.GuestAdditionsInterface, diff --git a/builder/virtualbox/ovf/config.hcl2spec.go b/builder/virtualbox/ovf/config.hcl2spec.go index ba709eba1..789b147a1 100644 --- a/builder/virtualbox/ovf/config.hcl2spec.go +++ b/builder/virtualbox/ovf/config.hcl2spec.go @@ -22,10 +22,9 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` Format *string `mapstructure:"format" required:"false" cty:"format"` ExportOpts []string `mapstructure:"export_opts" required:"false" cty:"export_opts"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` @@ -78,8 +77,8 @@ type FlatConfig struct { SSHSkipNatMapping *bool `mapstructure:"ssh_skip_nat_mapping" required:"false" cty:"ssh_skip_nat_mapping"` SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" cty:"ssh_wait_timeout"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` - RawPostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` VBoxManage [][]string `mapstructure:"vboxmanage" required:"false" cty:"vboxmanage"` VBoxManagePost [][]string `mapstructure:"vboxmanage_post" required:"false" cty:"vboxmanage_post"` VBoxVersionFile *string `mapstructure:"virtualbox_version_file" required:"false" cty:"virtualbox_version_file"` @@ -124,7 +123,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, "export_opts": &hcldec.AttrSpec{Name: "export_opts", Type: cty.List(cty.String), Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/vm/builder.go b/builder/virtualbox/vm/builder.go index 25f825622..c76535954 100644 --- a/builder/virtualbox/vm/builder.go +++ b/builder/virtualbox/vm/builder.go @@ -96,11 +96,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Headless: b.config.Headless, }, &vboxcommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), BootCommand: b.config.FlatBootCommand(), VMName: b.config.VMName, Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, + GroupInterval: b.config.BootConfig.BootGroupInterval.Duration(), Comm: &b.config.Comm, }, &communicator.StepConnect{ @@ -124,8 +124,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &vboxcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, - Delay: b.config.PostShutdownDelay, + Timeout: b.config.ShutdownTimeout.Duration(), + Delay: b.config.PostShutdownDelay.Duration(), }, &vboxcommon.StepVBoxManage{ Commands: b.config.VBoxManagePost, diff --git a/builder/virtualbox/vm/config.go b/builder/virtualbox/vm/config.go index e43d44283..24ad2535b 100644 --- a/builder/virtualbox/vm/config.go +++ b/builder/virtualbox/vm/config.go @@ -71,8 +71,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.GuestAdditionsPath = "VBoxGuestAdditions.iso" } - if c.RawPostShutdownDelay == "" { - c.RawPostShutdownDelay = "2s" + if c.PostShutdownDelay == "" { + c.PostShutdownDelay = "2s" } // Prepare the errors @@ -88,7 +88,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, c.VBoxVersionConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...) - log.Printf("PostShutdownDelay: %f", c.PostShutdownDelay.Seconds()) + log.Printf("PostShutdownDelay: %s", c.PostShutdownDelay) if c.VMName == "" { errs = packer.MultiErrorAppend(errs, diff --git a/builder/virtualbox/vm/config.hcl2spec.go b/builder/virtualbox/vm/config.hcl2spec.go index 0214aac6a..da231ce2c 100644 --- a/builder/virtualbox/vm/config.hcl2spec.go +++ b/builder/virtualbox/vm/config.hcl2spec.go @@ -22,10 +22,9 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` Format *string `mapstructure:"format" required:"false" cty:"format"` ExportOpts []string `mapstructure:"export_opts" required:"false" cty:"export_opts"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` @@ -78,8 +77,8 @@ type FlatConfig struct { SSHSkipNatMapping *bool `mapstructure:"ssh_skip_nat_mapping" required:"false" cty:"ssh_skip_nat_mapping"` SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" cty:"ssh_wait_timeout"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` - RawPostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"` VBoxManage [][]string `mapstructure:"vboxmanage" required:"false" cty:"vboxmanage"` VBoxManagePost [][]string `mapstructure:"vboxmanage_post" required:"false" cty:"vboxmanage_post"` VBoxVersionFile *string `mapstructure:"virtualbox_version_file" required:"false" cty:"virtualbox_version_file"` @@ -120,7 +119,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, "export_opts": &hcldec.AttrSpec{Name: "export_opts", Type: cty.List(cty.String), Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, diff --git a/builder/vmware/common/ssh_config.go b/builder/vmware/common/ssh_config.go index 8c59cdedc..c93344e77 100644 --- a/builder/vmware/common/ssh_config.go +++ b/builder/vmware/common/ssh_config.go @@ -3,9 +3,8 @@ package common import ( - "time" - "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -17,12 +16,12 @@ type SSHConfig struct { SSHSkipRequestPty bool `mapstructure:"ssh_skip_request_pty"` // These are deprecated, but we keep them around for BC // TODO(@mitchellh): remove - SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"` + SSHWaitTimeout config.DurationString `mapstructure:"ssh_wait_timeout"` } func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { // TODO: backwards compatibility, write fixer instead - if c.SSHWaitTimeout != 0 { + if c.SSHWaitTimeout != "" { c.Comm.SSHTimeout = c.SSHWaitTimeout } if c.SSHSkipRequestPty { diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 7e94d9663..81e56818d 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -131,12 +131,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Headless: b.config.Headless, }, &vmwcommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), VNCEnabled: !b.config.DisableVNC, BootCommand: b.config.FlatBootCommand(), VMName: b.config.VMName, Ctx: b.config.ctx, - KeyInterval: b.config.VNCConfig.BootKeyInterval, + KeyInterval: b.config.VNCConfig.BootKeyInterval.Duration(), }, &communicator.StepConnect{ Config: &b.config.SSHConfig.Comm, @@ -155,7 +155,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &vmwcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, &vmwcommon.StepCleanFiles{}, &vmwcommon.StepCompactDisk{ diff --git a/builder/vmware/iso/config.hcl2spec.go b/builder/vmware/iso/config.hcl2spec.go index 9a5da2aae..6dce149ae 100644 --- a/builder/vmware/iso/config.hcl2spec.go +++ b/builder/vmware/iso/config.hcl2spec.go @@ -29,12 +29,11 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` DisableVNC *bool `mapstructure:"disable_vnc" cty:"disable_vnc"` - RawBootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` FusionAppPath *string `mapstructure:"fusion_app_path" required:"false" cty:"fusion_app_path"` RemoteType *string `mapstructure:"remote_type" required:"false" cty:"remote_type"` RemoteDatastore *string `mapstructure:"remote_datastore" required:"false" cty:"remote_datastore"` @@ -62,7 +61,7 @@ type FlatConfig struct { VNCPortMax *int `mapstructure:"vnc_port_max" cty:"vnc_port_max"` VNCDisablePassword *bool `mapstructure:"vnc_disable_password" required:"false" cty:"vnc_disable_password"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -161,7 +160,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "disable_vnc": &hcldec.AttrSpec{Name: "disable_vnc", Type: cty.Bool, Required: false}, "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, "fusion_app_path": &hcldec.AttrSpec{Name: "fusion_app_path", Type: cty.String, Required: false}, diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index e1e33dd7c..03a201828 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -128,12 +128,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Headless: b.config.Headless, }, &vmwcommon.StepTypeBootCommand{ - BootWait: b.config.BootWait, + BootWait: b.config.BootWait.Duration(), VNCEnabled: !b.config.DisableVNC, BootCommand: b.config.FlatBootCommand(), VMName: b.config.VMName, Ctx: b.config.ctx, - KeyInterval: b.config.VNCConfig.BootKeyInterval, + KeyInterval: b.config.VNCConfig.BootKeyInterval.Duration(), }, &communicator.StepConnect{ Config: &b.config.SSHConfig.Comm, @@ -152,7 +152,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &vmwcommon.StepShutdown{ Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, + Timeout: b.config.ShutdownTimeout.Duration(), }, &vmwcommon.StepCleanFiles{}, &vmwcommon.StepCompactDisk{ diff --git a/builder/vmware/vmx/config.hcl2spec.go b/builder/vmware/vmx/config.hcl2spec.go index 432837e07..15fc44b5e 100644 --- a/builder/vmware/vmx/config.hcl2spec.go +++ b/builder/vmware/vmx/config.hcl2spec.go @@ -22,12 +22,11 @@ type FlatConfig struct { FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label"` - RawBootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` - RawBootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootGroupInterval *string `cty:"boot_group_interval"` DisableVNC *bool `mapstructure:"disable_vnc" cty:"disable_vnc"` - RawBootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval"` FusionAppPath *string `mapstructure:"fusion_app_path" required:"false" cty:"fusion_app_path"` RemoteType *string `mapstructure:"remote_type" required:"false" cty:"remote_type"` RemoteDatastore *string `mapstructure:"remote_datastore" required:"false" cty:"remote_datastore"` @@ -46,7 +45,7 @@ type FlatConfig struct { VNCPortMax *int `mapstructure:"vnc_port_max" cty:"vnc_port_max"` VNCDisablePassword *bool `mapstructure:"vnc_disable_password" required:"false" cty:"vnc_disable_password"` ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"` - RawShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` + ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"` Type *string `mapstructure:"communicator" cty:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` @@ -130,7 +129,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "boot_group_interval": &hcldec.AttrSpec{Name: "boot_group_interval", Type: cty.String, Required: false}, "disable_vnc": &hcldec.AttrSpec{Name: "disable_vnc", Type: cty.Bool, Required: false}, "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, "fusion_app_path": &hcldec.AttrSpec{Name: "fusion_app_path", Type: cty.String, Required: false}, diff --git a/builder/yandex/config.go b/builder/yandex/config.go index 2319203e1..248b1ffe0 100644 --- a/builder/yandex/config.go +++ b/builder/yandex/config.go @@ -8,7 +8,6 @@ import ( "fmt" "os" "regexp" - "time" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common/uuid" @@ -119,7 +118,7 @@ type Config struct { ctx interpolate.Context // The time to wait for instance state changes. // Defaults to `5m`. - StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"` + StateTimeout config.DurationString `mapstructure:"state_timeout" required:"false"` } func NewConfig(raws ...interface{}) (*Config, []string, error) { @@ -280,8 +279,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { } } - if c.StateTimeout == 0 { - c.StateTimeout = 5 * time.Minute + if c.StateTimeout == "" { + c.StateTimeout = "5m" + } + + if err := c.StateTimeout.Validate(); err != nil { + errs = packer.MultiErrorAppend(errs, err) } // Check for any errors. diff --git a/builder/yandex/step_create_image.go b/builder/yandex/step_create_image.go index 4e40f188c..08842906c 100644 --- a/builder/yandex/step_create_image.go +++ b/builder/yandex/step_create_image.go @@ -22,7 +22,7 @@ func (stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multis diskID := state.Get("disk_id").(string) ui.Say(fmt.Sprintf("Creating image: %v", c.ImageName)) - ctx, cancel := context.WithTimeout(ctx, c.StateTimeout) + ctx, cancel := context.WithTimeout(ctx, c.StateTimeout.Duration()) defer cancel() op, err := sdk.WrapOperation(sdk.Compute().Image().Create(ctx, &compute.CreateImageRequest{ diff --git a/builder/yandex/step_create_instance.go b/builder/yandex/step_create_instance.go index 5d7b28f10..5e7341cad 100644 --- a/builder/yandex/step_create_instance.go +++ b/builder/yandex/step_create_instance.go @@ -112,7 +112,7 @@ func (s *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) - ctx, cancel := context.WithTimeout(ctx, config.StateTimeout) + ctx, cancel := context.WithTimeout(ctx, config.StateTimeout.Duration()) defer cancel() sourceImage, err := getImage(ctx, config, driver) @@ -263,7 +263,7 @@ func (s *stepCreateInstance) Cleanup(state multistep.StateBag) { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) - ctx, cancel := context.WithTimeout(context.Background(), config.StateTimeout) + ctx, cancel := context.WithTimeout(context.Background(), config.StateTimeout.Duration()) defer cancel() if s.SerialLogFile != "" { diff --git a/builder/yandex/step_instance_info.go b/builder/yandex/step_instance_info.go index fa85c052d..a194e5ae5 100644 --- a/builder/yandex/step_instance_info.go +++ b/builder/yandex/step_instance_info.go @@ -22,7 +22,7 @@ func (s *stepInstanceInfo) Run(ctx context.Context, state multistep.StateBag) mu ui.Say(fmt.Sprintf("Waiting for instance with id %s to become active...", instanceID)) - ctx, cancel := context.WithTimeout(ctx, c.StateTimeout) + ctx, cancel := context.WithTimeout(ctx, c.StateTimeout.Duration()) defer cancel() instance, err := sdk.Compute().Instance().Get(ctx, &compute.GetInstanceRequest{ diff --git a/builder/yandex/step_teardown_instance.go b/builder/yandex/step_teardown_instance.go index ee3d0dbd3..0af11c29a 100644 --- a/builder/yandex/step_teardown_instance.go +++ b/builder/yandex/step_teardown_instance.go @@ -21,7 +21,7 @@ func (s *stepTeardownInstance) Run(ctx context.Context, state multistep.StateBag instanceID := state.Get("instance_id").(string) ui.Say("Stopping instance...") - ctx, cancel := context.WithTimeout(ctx, c.StateTimeout) + ctx, cancel := context.WithTimeout(ctx, c.StateTimeout.Duration()) defer cancel() op, err := sdk.WrapOperation(sdk.Compute().Instance().Stop(ctx, &compute.StopInstanceRequest{ InstanceId: instanceID, diff --git a/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go b/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go index da3a507bf..eb8d35a76 100644 --- a/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go +++ b/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go @@ -431,7 +431,7 @@ func getMapstructureSquashedStruct(topPkg *types.Package, utStruct *types.Struct switch f := field.Type().(type) { case *types.Named: switch f.String() { - case "time.Duration": + case "time.Duration", "github.com/hashicorp/packer/helper/config.DurationString": field = types.NewField(field.Pos(), field.Pkg(), field.Name(), types.NewPointer(types.Typ[types.String]), field.Embedded()) case "github.com/hashicorp/packer/helper/config.Trilean": // TODO(azr): unhack this situation field = types.NewField(field.Pos(), field.Pkg(), field.Name(), types.NewPointer(types.Typ[types.Bool]), field.Embedded()) diff --git a/cmd/struct-markdown/main.go b/cmd/struct-markdown/main.go index ccf80b47c..487704bef 100644 --- a/cmd/struct-markdown/main.go +++ b/cmd/struct-markdown/main.go @@ -111,6 +111,10 @@ func main() { } fieldType := string(b[field.Type.Pos()-1 : field.Type.End()-1]) fieldType = strings.ReplaceAll(fieldType, "*", `\*`) + switch fieldType { + case "config.DurationString": + fieldType = "duration string. ex: \"1h5m2s\"" + } field := Field{ Name: name, diff --git a/common/bootcommand/config.go b/common/bootcommand/config.go index ddef4132f..d32798c1f 100644 --- a/common/bootcommand/config.go +++ b/common/bootcommand/config.go @@ -5,8 +5,8 @@ package bootcommand import ( "fmt" "strings" - "time" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -112,21 +112,19 @@ type BootConfig struct { // Packer to wait five seconds and one minute 30 seconds, respectively. If // this isn't specified, a sensible default value is picked depending on // the builder type. - RawBootGroupInterval string `mapstructure:"boot_keygroup_interval"` + BootGroupInterval config.DurationString `mapstructure:"boot_keygroup_interval"` // The time to wait after booting the initial virtual machine before typing // the `boot_command`. The value of this should be a duration. Examples are // `5s` and `1m30s` which will cause Packer to wait five seconds and one // minute 30 seconds, respectively. If this isn't specified, the default is // `10s` or 10 seconds. - RawBootWait string `mapstructure:"boot_wait"` + BootWait config.DurationString `mapstructure:"boot_wait"` // This is an array of commands to type when the virtual machine is first // booted. The goal of these commands should be to type just enough to // initialize the operating system installer. Special keys can be typed as // well, and are covered in the section below on the boot command. If this // is not specified, it is assumed the installer will start itself. - BootCommand []string `mapstructure:"boot_command"` - BootGroupInterval time.Duration `` - BootWait time.Duration `` + BootCommand []string `mapstructure:"boot_command"` } // The boot command "typed" character for character over a VNC connection to @@ -142,37 +140,26 @@ type VNCConfig struct { // when this is true. Defaults to false. DisableVNC bool `mapstructure:"disable_vnc"` // Time in ms to wait between each key press - RawBootKeyInterval string `mapstructure:"boot_key_interval"` - BootKeyInterval time.Duration `` + BootKeyInterval config.DurationString `mapstructure:"boot_key_interval"` } func (c *BootConfig) Prepare(ctx *interpolate.Context) (errs []error) { - if c.RawBootWait == "" { - c.RawBootWait = "10s" + if c.BootWait == "" { + c.BootWait = "10s" } - if c.RawBootWait != "" { - bw, err := time.ParseDuration(c.RawBootWait) - if err != nil { - errs = append( - errs, fmt.Errorf("Failed parsing boot_wait: %s", err)) - } else { - c.BootWait = bw - } + if err := c.BootWait.Validate(); err != nil { + errs = append( + errs, fmt.Errorf("Failed parsing boot_wait: %s", err)) } - if c.RawBootGroupInterval == "" { - c.RawBootGroupInterval = "0ms" + if c.BootGroupInterval == "" { + c.BootGroupInterval = "0ms" } - if c.RawBootGroupInterval != "" { - bgi, err := time.ParseDuration(c.RawBootGroupInterval) - if err != nil { - errs = append( - errs, fmt.Errorf("Failed parsing boot_keygroup_interval: %s", err)) - } else { - c.BootGroupInterval = bgi - } + if err := c.BootGroupInterval.Validate(); err != nil { + errs = append( + errs, fmt.Errorf("Failed parsing boot_keygroup_interval: %s", err)) } if c.BootCommand != nil { @@ -197,18 +184,13 @@ func (c *VNCConfig) Prepare(ctx *interpolate.Context) (errs []error) { fmt.Errorf("A boot command cannot be used when vnc is disabled.")) } - if c.RawBootKeyInterval == "" { - c.RawBootKeyInterval = "0ms" + if c.BootKeyInterval == "" { + c.BootKeyInterval = "0ms" } - if c.RawBootKeyInterval != "" { - bki, err := time.ParseDuration(c.RawBootKeyInterval) - if err != nil { - errs = append( - errs, fmt.Errorf("Failed parsing boot_key_interval: %s", err)) - } else { - c.BootKeyInterval = bki - } + if err := c.BootKeyInterval.Validate(); err != nil { + errs = append( + errs, fmt.Errorf("Failed parsing boot_key_interval: %s", err)) } errs = append(errs, c.BootConfig.Prepare(ctx)...) diff --git a/common/bootcommand/config_test.go b/common/bootcommand/config_test.go index 551f2c785..9254a108e 100644 --- a/common/bootcommand/config_test.go +++ b/common/bootcommand/config_test.go @@ -11,18 +11,18 @@ func TestConfigPrepare(t *testing.T) { // Test a default boot_wait c = new(BootConfig) - c.RawBootWait = "" + c.BootWait = "" errs := c.Prepare(&interpolate.Context{}) if len(errs) > 0 { t.Fatalf("bad: %#v", errs) } - if c.RawBootWait != "10s" { - t.Fatalf("bad value: %s", c.RawBootWait) + if c.BootWait != "10s" { + t.Fatalf("bad value: %s", c.BootWait) } // Test with a bad boot_wait c = new(BootConfig) - c.RawBootWait = "this is not good" + c.BootWait = "this is not good" errs = c.Prepare(&interpolate.Context{}) if len(errs) == 0 { t.Fatal("should error") @@ -30,7 +30,7 @@ func TestConfigPrepare(t *testing.T) { // Test with a good one c = new(BootConfig) - c.RawBootWait = "5s" + c.BootWait = "5s" errs = c.Prepare(&interpolate.Context{}) if len(errs) > 0 { t.Fatalf("bad: %#v", errs) diff --git a/common/shutdowncommand/config.go b/common/shutdowncommand/config.go index a5198318e..36ce8bb5e 100644 --- a/common/shutdowncommand/config.go +++ b/common/shutdowncommand/config.go @@ -3,9 +3,7 @@ package shutdowncommand import ( - "fmt" - "time" - + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/template/interpolate" ) @@ -23,22 +21,17 @@ type ShutdownConfig struct { // virtual machine to actually shut down. If the machine doesn't shut down // in this time it is considered an error. By default, the time out is "5m" // (five minutes). - RawShutdownTimeout string `mapstructure:"shutdown_timeout" required:"false"` - - ShutdownTimeout time.Duration `` + ShutdownTimeout config.DurationString `mapstructure:"shutdown_timeout" required:"false"` } func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error { - if c.RawShutdownTimeout == "" { - c.RawShutdownTimeout = "5m" + if c.ShutdownTimeout == "" { + c.ShutdownTimeout = "5m" } - var errs []error - var err error - c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout) - if err != nil { - errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err)) + if err := c.ShutdownTimeout.Validate(); err != nil { + return []error{err} } - return errs + return nil } diff --git a/common/shutdowncommand/config_test.go b/common/shutdowncommand/config_test.go index 44ab632cb..3f63f599c 100644 --- a/common/shutdowncommand/config_test.go +++ b/common/shutdowncommand/config_test.go @@ -28,7 +28,7 @@ func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) { // Test with a bad value c = testShutdownConfig() - c.RawShutdownTimeout = "this is not good" + c.ShutdownTimeout = "this is not good" errs = c.Prepare(interpolate.NewContext()) if len(errs) == 0 { t.Fatalf("should have error") @@ -36,12 +36,12 @@ func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) { // Test with a good one c = testShutdownConfig() - c.RawShutdownTimeout = "5s" + c.ShutdownTimeout = "5s" errs = c.Prepare(interpolate.NewContext()) if len(errs) > 0 { t.Fatalf("err: %#v", errs) } - if c.ShutdownTimeout != 5*time.Second { + if c.ShutdownTimeout.Duration() != 5*time.Second { t.Fatalf("bad: %s", c.ShutdownTimeout) } } diff --git a/hcl2template/load_test.go b/hcl2template/load_test.go index c91893c8e..0f4d6f91d 100644 --- a/hcl2template/load_test.go +++ b/hcl2template/load_test.go @@ -80,7 +80,7 @@ func TestParser_ParseFile(t *testing.T) { RawSingleISOUrl: strPtr("http://releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso"), BootCommand: []string{"..."}, ShutdownCommand: strPtr("echo 'vagrant' | sudo -S shutdown -P now"), - RawBootWait: strPtr("10s"), + BootWait: strPtr("10s"), VBoxManage: [][]string{}, VBoxManagePost: [][]string{}, }, diff --git a/hcl2template/parser_test.go b/hcl2template/parser_test.go index c62bf6bdb..1056153d6 100644 --- a/hcl2template/parser_test.go +++ b/hcl2template/parser_test.go @@ -52,7 +52,7 @@ func TestParser_Parse(t *testing.T) { RawSingleISOUrl: strPtr("http://releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso"), BootCommand: []string{"..."}, ShutdownCommand: strPtr("echo 'vagrant' | sudo -S shutdown -P now"), - RawBootWait: strPtr("10s"), + BootWait: strPtr("10s"), VBoxManage: [][]string{}, VBoxManagePost: [][]string{}, }, diff --git a/helper/communicator/config.go b/helper/communicator/config.go index 20207d1c6..ced93494e 100644 --- a/helper/communicator/config.go +++ b/helper/communicator/config.go @@ -9,9 +9,9 @@ import ( "io/ioutil" "net" "os" - "time" packerssh "github.com/hashicorp/packer/communicator/ssh" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/multistep" helperssh "github.com/hashicorp/packer/helper/ssh" "github.com/hashicorp/packer/packer" @@ -58,7 +58,7 @@ type Config struct { // In this example, Packer will check whether it can connect, as normal. But once // a connection attempt is successful, it will disconnect and then wait 10 minutes // before connecting to the guest and beginning provisioning. - PauseBeforeConnect time.Duration `mapstructure:"pause_before_connecting"` + PauseBeforeConnect config.DurationString `mapstructure:"pause_before_connecting"` SSH `mapstructure:",squash"` WinRM `mapstructure:",squash"` @@ -104,7 +104,7 @@ type SSH struct { // The time to wait for SSH to become available. Packer uses this to // determine when the machine has booted so this is usually quite long. // Example value: `10m`. - SSHTimeout time.Duration `mapstructure:"ssh_timeout"` + SSHTimeout config.DurationString `mapstructure:"ssh_timeout"` // If true, the local SSH agent will be used to authenticate connections to // the source instance. No temporary keypair will be created, and the // values of `ssh_password` and `ssh_private_key_file` will be ignored. To @@ -146,11 +146,11 @@ type SSH struct { SSHProxyPassword string `mapstructure:"ssh_proxy_password"` // How often to send "keep alive" messages to the server. Set to a negative // value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. - SSHKeepAliveInterval time.Duration `mapstructure:"ssh_keep_alive_interval"` + SSHKeepAliveInterval config.DurationString `mapstructure:"ssh_keep_alive_interval"` // The amount of time to wait for a remote command to end. This might be // useful if, for example, packer hangs on a connection after a reboot. // Example: `5m`. Disabled by default. - SSHReadWriteTimeout time.Duration `mapstructure:"ssh_read_write_timeout"` + SSHReadWriteTimeout config.DurationString `mapstructure:"ssh_read_write_timeout"` // Tunneling @@ -201,7 +201,7 @@ type WinRM struct { WinRMPort int `mapstructure:"winrm_port"` // The amount of time to wait for WinRM to become available. This defaults // to `30m` since setting up a Windows machine generally takes a long time. - WinRMTimeout time.Duration `mapstructure:"winrm_timeout"` + WinRMTimeout config.DurationString `mapstructure:"winrm_timeout"` // If `true`, use HTTPS for WinRM. WinRMUseSSL bool `mapstructure:"winrm_use_ssl"` // If `true`, do not check server certificate chain and host name. @@ -370,12 +370,12 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error { c.SSHPort = 22 } - if c.SSHTimeout == 0 { - c.SSHTimeout = 5 * time.Minute + if c.SSHTimeout == "" { + c.SSHTimeout = "5m" } - if c.SSHKeepAliveInterval == 0 { - c.SSHKeepAliveInterval = 5 * time.Second + if c.SSHKeepAliveInterval == "" { + c.SSHKeepAliveInterval = "5s" } if c.SSHHandshakeAttempts == 0 { @@ -404,6 +404,13 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error { // Validation var errs []error + + for _, d := range []config.DurationString{c.SSHTimeout, c.SSHKeepAliveInterval} { + if err := d.Validate(); err != nil { + errs = append(errs, err) + } + } + if c.SSHUsername == "" { errs = append(errs, errors.New("An ssh_username must be specified\n Note: some builders used to default ssh_username to \"root\".")) } @@ -470,22 +477,25 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error { return errs } -func (c *Config) prepareWinRM(ctx *interpolate.Context) []error { +func (c *Config) prepareWinRM(ctx *interpolate.Context) (errs []error) { if c.WinRMPort == 0 && c.WinRMUseSSL { c.WinRMPort = 5986 } else if c.WinRMPort == 0 { c.WinRMPort = 5985 } - if c.WinRMTimeout == 0 { - c.WinRMTimeout = 30 * time.Minute + if c.WinRMTimeout == "" { + c.WinRMTimeout = "30m" + } + + if err := c.WinRMTimeout.Validate(); err != nil { + errs = append(errs, err) } if c.WinRMUseNTLM == true { c.WinRMTransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} } } - var errs []error if c.WinRMUser == "" { errs = append(errs, errors.New("winrm_username must be specified.")) } diff --git a/helper/communicator/step_connect.go b/helper/communicator/step_connect.go index 6bb062f80..6a05a030d 100644 --- a/helper/communicator/step_connect.go +++ b/helper/communicator/step_connect.go @@ -112,8 +112,8 @@ func (s *StepConnect) Run(ctx context.Context, state multistep.StateBag) multist return action } - if s.Config.PauseBeforeConnect > 0 { - cancelled := s.pause(s.Config.PauseBeforeConnect, ctx) + if s.Config.PauseBeforeConnect.Duration() > 0 { + cancelled := s.pause(s.Config.PauseBeforeConnect.Duration(), ctx) if cancelled { return multistep.ActionHalt } diff --git a/helper/communicator/step_connect_ssh.go b/helper/communicator/step_connect_ssh.go index 07763e335..a816f6c13 100644 --- a/helper/communicator/step_connect_ssh.go +++ b/helper/communicator/step_connect_ssh.go @@ -46,7 +46,7 @@ func (s *StepConnectSSH) Run(ctx context.Context, state multistep.StateBag) mult }() log.Printf("[INFO] Waiting for SSH, up to timeout: %s", s.Config.SSHTimeout) - timeout := time.After(s.Config.SSHTimeout) + timeout := time.After(s.Config.SSHTimeout.Duration()) for { // Wait for either SSH to become available, a timeout to occur, // or an interrupt to come through. @@ -198,8 +198,8 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, ctx context.Contex Pty: s.Config.SSHPty, DisableAgentForwarding: s.Config.SSHDisableAgentForwarding, UseSftp: s.Config.SSHFileTransferMethod == "sftp", - KeepAliveInterval: s.Config.SSHKeepAliveInterval, - Timeout: s.Config.SSHReadWriteTimeout, + KeepAliveInterval: s.Config.SSHKeepAliveInterval.Duration(), + Timeout: s.Config.SSHReadWriteTimeout.Duration(), Tunnels: tunnels, } diff --git a/helper/communicator/step_connect_winrm.go b/helper/communicator/step_connect_winrm.go index 275468bc1..62ddaa13a 100644 --- a/helper/communicator/step_connect_winrm.go +++ b/helper/communicator/step_connect_winrm.go @@ -49,7 +49,7 @@ func (s *StepConnectWinRM) Run(ctx context.Context, state multistep.StateBag) mu }() log.Printf("Waiting for WinRM, up to timeout: %s", s.Config.WinRMTimeout) - timeout := time.After(s.Config.WinRMTimeout) + timeout := time.After(s.Config.WinRMTimeout.Duration()) for { // Wait for either WinRM to become available, a timeout to occur, // or an interrupt to come through. @@ -136,7 +136,7 @@ func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, ctx context.Co Port: port, Username: user, Password: password, - Timeout: s.Config.WinRMTimeout, + Timeout: s.Config.WinRMTimeout.Duration(), Https: s.Config.WinRMUseSSL, Insecure: s.Config.WinRMInsecure, TransportDecorator: s.Config.WinRMTransportDecorator, diff --git a/helper/config/decode.go b/helper/config/decode.go index 43673e1dc..3b7d10c45 100644 --- a/helper/config/decode.go +++ b/helper/config/decode.go @@ -31,7 +31,6 @@ var DefaultDecodeHookFuncs = []mapstructure.DecodeHookFunc{ uint8ToStringHook, stringToTrilean, mapstructure.StringToSliceHookFunc(","), - mapstructure.StringToTimeDurationHookFunc(), } // Decode decodes the configuration into the target and optionally diff --git a/helper/config/decode_test.go b/helper/config/decode_test.go index b08fb2af1..dd34f0bb4 100644 --- a/helper/config/decode_test.go +++ b/helper/config/decode_test.go @@ -3,7 +3,6 @@ package config import ( "reflect" "testing" - "time" "github.com/hashicorp/packer/template/interpolate" ) @@ -12,7 +11,7 @@ func TestDecode(t *testing.T) { type Target struct { Name string Address string - Time time.Duration + Time DurationString Trilean Trilean } @@ -31,7 +30,7 @@ func TestDecode(t *testing.T) { }, &Target{ Name: "bar", - Time: 5 * time.Second, + Time: "5s", Trilean: TriTrue, }, nil, diff --git a/helper/config/duration.go b/helper/config/duration.go new file mode 100644 index 000000000..c9b939ff6 --- /dev/null +++ b/helper/config/duration.go @@ -0,0 +1,36 @@ +package config + +import ( + "fmt" + "time" +) + +// DurationString is a string that represents a time duration. +// +// A DurationString is validated using time.ParseDuration. +// +// An empty string ("") is a valid (0) DurationString. A time.Sleep(0) returns +// immediately. +type DurationString string + +// Duration returns the parsed duration. +// Duration panics if d is invalid. +func (d DurationString) Duration() time.Duration { + if d == "" { + return 0 + } + du, err := time.ParseDuration(string(d)) + if err != nil { + s := fmt.Sprintf("DurationString: Could not parse '%s' : %v", d, err) + panic(s) + } + return du +} + +func (d DurationString) Validate() error { + if d == "" { + return nil + } + _, err := time.ParseDuration(string(d)) + return err +} diff --git a/packer/core.go b/packer/core.go index bcdd91b30..d00713e48 100644 --- a/packer/core.go +++ b/packer/core.go @@ -135,14 +135,14 @@ func (c *Core) generateCoreBuildProvisioner(rawP *template.Provisioner, rawName } } // If we're pausing, we wrap the provisioner in a special pauser. - if rawP.PauseBefore > 0 { + if rawP.PauseBefore != "" { provisioner = &PausedProvisioner{ - PauseBefore: rawP.PauseBefore, + PauseBefore: rawP.PauseBefore.Duration(), Provisioner: provisioner, } - } else if rawP.Timeout > 0 { + } else if rawP.Timeout != "" { provisioner = &TimeoutProvisioner{ - Timeout: rawP.Timeout, + Timeout: rawP.Timeout.Duration(), Provisioner: provisioner, } } diff --git a/post-processor/digitalocean-import/post-processor.go b/post-processor/digitalocean-import/post-processor.go index 0588a3566..43eb77343 100644 --- a/post-processor/digitalocean-import/post-processor.go +++ b/post-processor/digitalocean-import/post-processor.go @@ -35,16 +35,17 @@ type Config struct { SpacesKey string `mapstructure:"spaces_key"` SpacesSecret string `mapstructure:"spaces_secret"` - SpacesRegion string `mapstructure:"spaces_region"` - SpaceName string `mapstructure:"space_name"` - ObjectName string `mapstructure:"space_object_name"` - SkipClean bool `mapstructure:"skip_clean"` - Tags []string `mapstructure:"image_tags"` - Name string `mapstructure:"image_name"` - Description string `mapstructure:"image_description"` - Distribution string `mapstructure:"image_distribution"` - ImageRegions []string `mapstructure:"image_regions"` - Timeout time.Duration `mapstructure:"timeout"` + SpacesRegion string `mapstructure:"spaces_region"` + SpaceName string `mapstructure:"space_name"` + ObjectName string `mapstructure:"space_object_name"` + SkipClean bool `mapstructure:"skip_clean"` + Tags []string `mapstructure:"image_tags"` + Name string `mapstructure:"image_name"` + Description string `mapstructure:"image_description"` + Distribution string `mapstructure:"image_distribution"` + ImageRegions []string `mapstructure:"image_regions"` + + Timeout config.DurationString `mapstructure:"timeout"` ctx interpolate.Context } @@ -103,8 +104,8 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { p.config.Distribution = "Unkown" } - if p.config.Timeout == 0 { - p.config.Timeout = 20 * time.Minute + if p.config.Timeout == "" { + p.config.Timeout = "20m" } errs := new(packer.MultiError) @@ -207,7 +208,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact } ui.Message(fmt.Sprintf("Waiting for import of image %s to complete (may take a while)", p.config.Name)) - err = waitUntilImageAvailable(client, image.ID, p.config.Timeout) + err = waitUntilImageAvailable(client, image.ID, p.config.Timeout.Duration()) if err != nil { return nil, false, false, fmt.Errorf("Import of image %s failed with error: %s", p.config.Name, err) } @@ -221,7 +222,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact regions = regions[:len(regions)-1] ui.Message(fmt.Sprintf("Distributing image %s to additional regions: %v", p.config.Name, regions)) - err = distributeImageToRegions(client, image.ID, regions, p.config.Timeout) + err = distributeImageToRegions(client, image.ID, regions, p.config.Timeout.Duration()) if err != nil { return nil, false, false, err } diff --git a/post-processor/googlecompute-export/post-processor.go b/post-processor/googlecompute-export/post-processor.go index eff848bdf..4bfdd0817 100644 --- a/post-processor/googlecompute-export/post-processor.go +++ b/post-processor/googlecompute-export/post-processor.go @@ -138,7 +138,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact Metadata: exporterMetadata, Network: p.config.Network, NetworkProjectId: builderProjectId, - RawStateTimeout: "5m", + StateTimeout: "5m", SourceImageFamily: "debian-9-worker", SourceImageProjectId: "compute-image-tools", Subnetwork: p.config.Subnetwork, @@ -149,7 +149,6 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact "https://www.googleapis.com/auth/userinfo.email", }, } - exporterConfig.CalcTimeout() driver, err := googlecompute.NewDriverGCE(ui, builderProjectId, p.config.account, p.config.VaultGCPOauthEngine) diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index e541a782b..5c8d028e8 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -53,7 +53,7 @@ type Config struct { // The timeout for retrying to start the process. Until this timeout is // reached, if the provisioner can't start a process, it retries. This // can be set high to allow for reboots. - StartRetryTimeout time.Duration `mapstructure:"start_retry_timeout"` + StartRetryTimeout config.DurationString `mapstructure:"start_retry_timeout"` // This is used in the template generation to format environment variables // inside the `ExecuteCommand` template. @@ -143,8 +143,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.Inline = nil } - if p.config.StartRetryTimeout == 0 { - p.config.StartRetryTimeout = 5 * time.Minute + if p.config.StartRetryTimeout == "" { + p.config.StartRetryTimeout = "5m" } if p.config.RemotePath == "" { @@ -279,7 +279,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C // that the upload succeeded, a restart is initiated, and then the // command is executed but the file doesn't exist any longer. var cmd *packer.RemoteCmd - err = retry.Config{StartTimeout: p.config.StartRetryTimeout}.Run(ctx, func(ctx context.Context) error { + err = retry.Config{StartTimeout: p.config.StartRetryTimeout.Duration()}.Run(ctx, func(ctx context.Context) error { if _, err := f.Seek(0, 0); err != nil { return err } @@ -391,7 +391,7 @@ func (p *Provisioner) uploadEnvVars(flattenedEnvVars string) (err error) { // a system restart envVarReader := strings.NewReader(flattenedEnvVars) log.Printf("Uploading env vars to %s", p.config.RemoteEnvVarPath) - err = retry.Config{StartTimeout: p.config.StartRetryTimeout}.Run(ctx, func(context.Context) error { + err = retry.Config{StartTimeout: p.config.StartRetryTimeout.Duration()}.Run(ctx, func(context.Context) error { if err := p.communicator.Upload(p.config.RemoteEnvVarPath, envVarReader, nil); err != nil { return fmt.Errorf("Error uploading ps script containing env vars: %s", err) } diff --git a/provisioner/powershell/provisioner_test.go b/provisioner/powershell/provisioner_test.go index c90d90f2e..e43a3ccc1 100644 --- a/provisioner/powershell/provisioner_test.go +++ b/provisioner/powershell/provisioner_test.go @@ -8,7 +8,6 @@ import ( "regexp" "strings" "testing" - "time" "github.com/hashicorp/packer/packer" ) @@ -510,7 +509,7 @@ func TestProvisionerProvision_UploadFails(t *testing.T) { p := new(Provisioner) comm := new(packer.ScriptUploadErrorMockCommunicator) p.Prepare(config) - p.config.StartRetryTimeout = time.Second + p.config.StartRetryTimeout = "1s" err := p.Provision(context.Background(), ui, comm) if !strings.Contains(err.Error(), packer.ScriptUploadErrorMockCommunicatorError.Error()) { t.Fatalf("expected Provision() error %q to contain %q", diff --git a/provisioner/sleep/provisioner.go b/provisioner/sleep/provisioner.go index 646f1c4dd..0ed9468ec 100644 --- a/provisioner/sleep/provisioner.go +++ b/provisioner/sleep/provisioner.go @@ -11,7 +11,7 @@ import ( ) type Provisioner struct { - Duration time.Duration + Duration config.DurationString } var _ packer.Provisioner = new(Provisioner) @@ -24,7 +24,7 @@ func (p *Provisioner) Provision(ctx context.Context, _ packer.Ui, _ packer.Commu select { case <-ctx.Done(): return ctx.Err() - case <-time.After(p.Duration): + case <-time.After(p.Duration.Duration()): return nil } } diff --git a/provisioner/sleep/provisioner_test.go b/provisioner/sleep/provisioner_test.go index afc0d162c..d6f047b7a 100644 --- a/provisioner/sleep/provisioner_test.go +++ b/provisioner/sleep/provisioner_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" "time" + + "github.com/hashicorp/packer/helper/config" ) func test1sConfig() map[string]interface{} { @@ -20,7 +22,7 @@ func TestConfigPrepare_1s(t *testing.T) { t.Fatalf("prerare failed: %v", err) } - if p.Duration != time.Second { + if p.Duration.Duration() != time.Second { t.Fatal("wrong duration") } } @@ -29,7 +31,7 @@ func TestProvisioner_Provision(t *testing.T) { ctxCancelled, cancel := context.WithCancel(context.Background()) cancel() type fields struct { - Duration time.Duration + Duration config.DurationString } type args struct { ctx context.Context @@ -40,8 +42,8 @@ func TestProvisioner_Provision(t *testing.T) { args args wantErr bool }{ - {"valid sleep", fields{time.Millisecond}, args{context.Background()}, false}, - {"timeout", fields{time.Millisecond}, args{ctxCancelled}, true}, + {"valid sleep", fields{"1ms"}, args{context.Background()}, false}, + {"timeout", fields{"1ms"}, args{ctxCancelled}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/provisioner/windows-restart/provisioner.go b/provisioner/windows-restart/provisioner.go index 4f019c94b..528b4eb37 100644 --- a/provisioner/windows-restart/provisioner.go +++ b/provisioner/windows-restart/provisioner.go @@ -44,7 +44,7 @@ type Config struct { RestartCheckCommand string `mapstructure:"restart_check_command"` // The timeout for waiting for the machine to restart - RestartTimeout time.Duration `mapstructure:"restart_timeout"` + RestartTimeout config.DurationString `mapstructure:"restart_timeout"` // Whether to check the registry (see RegistryKeys) for pending reboots CheckKey bool `mapstructure:"check_registry"` @@ -85,8 +85,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.RestartCheckCommand = DefaultRestartCheckCommand } - if p.config.RestartTimeout == 0 { - p.config.RestartTimeout = 5 * time.Minute + if p.config.RestartTimeout == "" { + p.config.RestartTimeout = "5m" + } + if err := p.config.RestartTimeout.Validate(); err != nil { + return err } if len(p.config.RegistryKeys) == 0 { @@ -107,7 +110,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C var cmd *packer.RemoteCmd command := p.config.RestartCommand - err := retry.Config{StartTimeout: p.config.RestartTimeout}.Run(ctx, func(context.Context) error { + err := retry.Config{StartTimeout: p.config.RestartTimeout.Duration()}.Run(ctx, func(context.Context) error { cmd = &packer.RemoteCmd{Command: command} return cmd.RunWithUi(ctx, comm, ui) }) @@ -127,7 +130,7 @@ var waitForRestart = func(ctx context.Context, p *Provisioner, comm packer.Commu ui := p.ui ui.Say("Waiting for machine to restart...") waitDone := make(chan bool, 1) - timeout := time.After(p.config.RestartTimeout) + timeout := time.After(p.config.RestartTimeout.Duration()) var err error p.comm = comm diff --git a/provisioner/windows-restart/provisioner_test.go b/provisioner/windows-restart/provisioner_test.go index ffe9c48a2..f72608032 100644 --- a/provisioner/windows-restart/provisioner_test.go +++ b/provisioner/windows-restart/provisioner_test.go @@ -31,7 +31,7 @@ func TestProvisionerPrepare_Defaults(t *testing.T) { t.Fatalf("err: %s", err) } - if p.config.RestartTimeout != 5*time.Minute { + if p.config.RestartTimeout.Duration() != 5*time.Minute { t.Errorf("unexpected restart timeout: %s", p.config.RestartTimeout) } @@ -50,7 +50,7 @@ func TestProvisionerPrepare_ConfigRetryTimeout(t *testing.T) { t.Fatalf("err: %s", err) } - if p.config.RestartTimeout != 1*time.Minute { + if p.config.RestartTimeout.Duration() != 1*time.Minute { t.Errorf("unexpected restart timeout: %s", p.config.RestartTimeout) } } diff --git a/provisioner/windows-shell/provisioner.go b/provisioner/windows-shell/provisioner.go index a2927017c..927d4f5a9 100644 --- a/provisioner/windows-shell/provisioner.go +++ b/provisioner/windows-shell/provisioner.go @@ -35,7 +35,7 @@ type Config struct { // The timeout for retrying to start the process. Until this timeout // is reached, if the provisioner can't start a process, it retries. // This can be set high to allow for reboots. - StartRetryTimeout time.Duration `mapstructure:"start_retry_timeout"` + StartRetryTimeout config.DurationString `mapstructure:"start_retry_timeout"` // This is used in the template generation to format environment variables // inside the `ExecuteCommand` template. @@ -79,8 +79,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.Inline = nil } - if p.config.StartRetryTimeout == 0 { - p.config.StartRetryTimeout = 5 * time.Minute + if p.config.StartRetryTimeout == "" { + p.config.StartRetryTimeout = "5m" } if p.config.RemotePath == "" { @@ -202,7 +202,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C // and then the command is executed but the file doesn't exist // any longer. var cmd *packer.RemoteCmd - err = retry.Config{StartTimeout: p.config.StartRetryTimeout}.Run(ctx, func(ctx context.Context) error { + err = retry.Config{StartTimeout: p.config.StartRetryTimeout.Duration()}.Run(ctx, func(ctx context.Context) error { if _, err := f.Seek(0, 0); err != nil { return err } diff --git a/template/parse.go b/template/parse.go index ff5c60988..3088903e9 100644 --- a/template/parse.go +++ b/template/parse.go @@ -273,7 +273,7 @@ func (r *rawTemplate) decoder( result interface{}, md *mapstructure.Metadata) *mapstructure.Decoder { d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - DecodeHook: mapstructure.StringToTimeDurationHookFunc(), + DecodeHook: nil, Metadata: md, Result: result, }) diff --git a/template/parse_test.go b/template/parse_test.go index 77b63616d..04e41604d 100644 --- a/template/parse_test.go +++ b/template/parse_test.go @@ -9,7 +9,6 @@ import ( "reflect" "strings" "testing" - "time" "github.com/google/go-cmp/cmp" ) @@ -99,7 +98,7 @@ func TestParse(t *testing.T) { Provisioners: []*Provisioner{ { Type: "something", - PauseBefore: 1 * time.Second, + PauseBefore: "1s", }, }, }, @@ -112,7 +111,7 @@ func TestParse(t *testing.T) { Provisioners: []*Provisioner{ { Type: "something", - Timeout: 5 * time.Minute, + Timeout: "5m", }, }, }, @@ -358,6 +357,12 @@ func TestParse(t *testing.T) { false, }, + { + "parse-bad-prov-timeout.json", + nil, + true, + }, + { "parse-comment.json", &Template{ diff --git a/template/template.go b/template/template.go index 6bab8d4c2..dd382b3c9 100644 --- a/template/template.go +++ b/template/template.go @@ -6,9 +6,9 @@ import ( "encoding/json" "errors" "fmt" - "time" multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/packer/helper/config" ) // Template represents the parsed template that is used to configure @@ -140,8 +140,8 @@ type Provisioner struct { Type string `json:"type"` Config map[string]interface{} `json:"config,omitempty"` Override map[string]interface{} `json:"override,omitempty"` - PauseBefore time.Duration `mapstructure:"pause_before" json:"pause_before,omitempty"` - Timeout time.Duration `mapstructure:"timeout" json:"timeout,omitempty"` + PauseBefore config.DurationString `mapstructure:"pause_before" json:"pause_before,omitempty"` + Timeout config.DurationString `mapstructure:"timeout" json:"timeout,omitempty"` } // MarshalJSON conducts the necessary flattening of the Provisioner struct diff --git a/template/test-fixtures/parse-bad-prov-timeout.json b/template/test-fixtures/parse-bad-prov-timeout.json new file mode 100644 index 000000000..8a147bb6c --- /dev/null +++ b/template/test-fixtures/parse-bad-prov-timeout.json @@ -0,0 +1,11 @@ +{ + "builders": [{ + "type": "foo" + }], + + "provisioners": [{ + "timeout": 555, + "type": "bar", + "only": ["foo"] + }] +} diff --git a/website/source/partials/builder/amazon/common/_RunConfig-not-required.html.md b/website/source/partials/builder/amazon/common/_RunConfig-not-required.html.md index 588f63fa5..1f625a64b 100644 --- a/website/source/partials/builder/amazon/common/_RunConfig-not-required.html.md +++ b/website/source/partials/builder/amazon/common/_RunConfig-not-required.html.md @@ -279,7 +279,7 @@ subnet_id to be set. If this field is left blank, Packer will try to get the VPC ID from the subnet_id. -- `windows_password_timeout` (time.Duration) - The timeout for waiting for a Windows +- `windows_password_timeout` (duration string. ex: "1h5m2s") - The timeout for waiting for a Windows password for Windows instances. Defaults to 20 minutes. Example value: 10m diff --git a/website/source/partials/builder/azure/arm/_Config-not-required.html.md b/website/source/partials/builder/azure/arm/_Config-not-required.html.md index efeb01932..8601cee01 100644 --- a/website/source/partials/builder/azure/arm/_Config-not-required.html.md +++ b/website/source/partials/builder/azure/arm/_Config-not-required.html.md @@ -34,7 +34,7 @@ "managed_image_name": "TargetImageName", "managed_image_resource_group_name": "TargetResourceGroup" -- `shared_image_gallery_timeout` (time.Duration) - How long to wait for an image to be published to the shared image +- `shared_image_gallery_timeout` (duration string. ex: "1h5m2s") - How long to wait for an image to be published to the shared image gallery before timing out. If your Packer build is failing on the Publishing to Shared Image Gallery step with the error `Original Error: context deadline exceeded`, but the image is present when you check your @@ -187,7 +187,7 @@ 3. PlanPublisher 4. PlanPromotionCode -- `polling_duration_timeout` (time.Duration) - The default PollingDuration for azure is 15mins, this property will override +- `polling_duration_timeout` (duration string. ex: "1h5m2s") - The default PollingDuration for azure is 15mins, this property will override that value. See [Azure DefaultPollingDuration](https://godoc.org/github.com/Azure/go-autorest/autorest#pkg-constants) If your Packer build is failing on the ARM deployment step with the error `Original Error: diff --git a/website/source/partials/builder/cloudstack/_Config-not-required.html.md b/website/source/partials/builder/cloudstack/_Config-not-required.html.md index 2769d20f1..e99070514 100644 --- a/website/source/partials/builder/cloudstack/_Config-not-required.html.md +++ b/website/source/partials/builder/cloudstack/_Config-not-required.html.md @@ -1,6 +1,6 @@ -- `async_timeout` (time.Duration) - The time duration to wait for async calls to +- `async_timeout` (duration string. ex: "1h5m2s") - The time duration to wait for async calls to finish. Defaults to 30m. - `http_get_only` (bool) - Some cloud providers only allow HTTP GET calls @@ -32,7 +32,7 @@ attached to a virtual machine. Defaults to `false`. This option is only available when using `source_iso`. -- `eject_iso_delay` (time.Duration) - Configure the duration time to wait, making sure virtual machine is able +- `eject_iso_delay` (duration string. ex: "1h5m2s") - Configure the duration time to wait, making sure virtual machine is able to finish installing OS before it ejects safely. Requires `eject_iso` set to `true` and this option is only available when using `source_iso`. diff --git a/website/source/partials/builder/digitalocean/_Config-not-required.html.md b/website/source/partials/builder/digitalocean/_Config-not-required.html.md index fe4917ba9..9b994957f 100644 --- a/website/source/partials/builder/digitalocean/_Config-not-required.html.md +++ b/website/source/partials/builder/digitalocean/_Config-not-required.html.md @@ -20,11 +20,11 @@ - `snapshot_regions` ([]string) - The regions of the resulting snapshot that will appear in your account. -- `state_timeout` (time.Duration) - The time to wait, as a duration string, for a +- `state_timeout` (duration string. ex: "1h5m2s") - 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 "6m". -- `snapshot_timeout` (time.Duration) - How long to wait for an image to be published to the shared image +- `snapshot_timeout` (duration string. ex: "1h5m2s") - How long to wait for an image to be published to the shared image gallery before timing out. If your Packer build is failing on the Publishing to Shared Image Gallery step with the error `Original Error: context deadline exceeded`, but the image is present when you check your diff --git a/website/source/partials/builder/googlecompute/_Config-not-required.html.md b/website/source/partials/builder/googlecompute/_Config-not-required.html.md index 0f137015b..4ffb9840e 100644 --- a/website/source/partials/builder/googlecompute/_Config-not-required.html.md +++ b/website/source/partials/builder/googlecompute/_Config-not-required.html.md @@ -88,7 +88,7 @@ - `preemptible` (bool) - If true, launch a preemptible instance. -- `state_timeout` (string) - The time to wait for instance state changes. Defaults to "5m". +- `state_timeout` (duration string. ex: "1h5m2s") - The time to wait for instance state changes. Defaults to "5m". - `region` (string) - The region in which to launch the instance. Defaults to the region hosting the specified zone. diff --git a/website/source/partials/builder/hyperone/_Config-not-required.html.md b/website/source/partials/builder/hyperone/_Config-not-required.html.md index a392fed18..743777cc5 100644 --- a/website/source/partials/builder/hyperone/_Config-not-required.html.md +++ b/website/source/partials/builder/hyperone/_Config-not-required.html.md @@ -6,7 +6,7 @@ - `token_login` (string) - Login (an e-mail) on HyperOne platform. Set this if you want to fetch the token by SSH authentication. -- `state_timeout` (time.Duration) - Timeout for waiting on the API to complete +- `state_timeout` (duration string. ex: "1h5m2s") - Timeout for waiting on the API to complete a request. Defaults to 5m. - `image_name` (string) - The name of the resulting image. Defaults to diff --git a/website/source/partials/builder/virtualbox/common/_ShutdownConfig-not-required.html.md b/website/source/partials/builder/virtualbox/common/_ShutdownConfig-not-required.html.md index aba3347fe..e734ac3e1 100644 --- a/website/source/partials/builder/virtualbox/common/_ShutdownConfig-not-required.html.md +++ b/website/source/partials/builder/virtualbox/common/_ShutdownConfig-not-required.html.md @@ -8,12 +8,12 @@ since reboots may fail and specify the final shutdown command in your last script. -- `shutdown_timeout` (string) - The amount of time to wait after executing the +- `shutdown_timeout` (duration string. ex: "1h5m2s") - The amount of time to wait after executing the shutdown_command for the virtual machine to actually shut down. If it doesn't shut down in this time, it is an error. By default, the timeout is 5m or five minutes. -- `post_shutdown_delay` (string) - The amount of time to wait after shutting +- `post_shutdown_delay` (duration string. ex: "1h5m2s") - The amount of time to wait after shutting down the virtual machine. If you get the error Error removing floppy controller, you might need to set this to 5m or so. By default, the delay is 0s or disabled. diff --git a/website/source/partials/builder/yandex/_Config-not-required.html.md b/website/source/partials/builder/yandex/_Config-not-required.html.md index 18c4e4ff6..80d43eb27 100644 --- a/website/source/partials/builder/yandex/_Config-not-required.html.md +++ b/website/source/partials/builder/yandex/_Config-not-required.html.md @@ -73,6 +73,6 @@ - `zone` (string) - The name of the zone to launch the instance. This defaults to `ru-central1-a`. -- `state_timeout` (time.Duration) - The time to wait for instance state changes. +- `state_timeout` (duration string. ex: "1h5m2s") - The time to wait for instance state changes. Defaults to `5m`. \ No newline at end of file diff --git a/website/source/partials/common/bootcommand/_BootConfig-not-required.html.md b/website/source/partials/common/bootcommand/_BootConfig-not-required.html.md index 69791b48a..526a29c98 100644 --- a/website/source/partials/common/bootcommand/_BootConfig-not-required.html.md +++ b/website/source/partials/common/bootcommand/_BootConfig-not-required.html.md @@ -1,12 +1,12 @@ -- `boot_keygroup_interval` (string) - Time to wait after sending a group of key pressses. The value of this +- `boot_keygroup_interval` (duration string. ex: "1h5m2s") - Time to wait after sending a group of key pressses. The value of this should be a duration. Examples are `5s` and `1m30s` which will cause Packer to wait five seconds and one minute 30 seconds, respectively. If this isn't specified, a sensible default value is picked depending on the builder type. -- `boot_wait` (string) - The time to wait after booting the initial virtual machine before typing +- `boot_wait` (duration string. ex: "1h5m2s") - The time to wait after booting the initial virtual machine before typing the `boot_command`. The value of this should be a duration. Examples are `5s` and `1m30s` which will cause Packer to wait five seconds and one minute 30 seconds, respectively. If this isn't specified, the default is diff --git a/website/source/partials/common/bootcommand/_VNCConfig-not-required.html.md b/website/source/partials/common/bootcommand/_VNCConfig-not-required.html.md index d7081e407..937b0b467 100644 --- a/website/source/partials/common/bootcommand/_VNCConfig-not-required.html.md +++ b/website/source/partials/common/bootcommand/_VNCConfig-not-required.html.md @@ -3,5 +3,5 @@ - `disable_vnc` (bool) - Whether to create a VNC connection or not. A boot_command cannot be used when this is true. Defaults to false. -- `boot_key_interval` (string) - Time in ms to wait between each key press +- `boot_key_interval` (duration string. ex: "1h5m2s") - Time in ms to wait between each key press \ No newline at end of file diff --git a/website/source/partials/common/shutdowncommand/_ShutdownConfig-not-required.html.md b/website/source/partials/common/shutdowncommand/_ShutdownConfig-not-required.html.md index 6094b9154..8d72081d7 100644 --- a/website/source/partials/common/shutdowncommand/_ShutdownConfig-not-required.html.md +++ b/website/source/partials/common/shutdowncommand/_ShutdownConfig-not-required.html.md @@ -9,7 +9,7 @@ reboots may fail) and instead specify the final shutdown command in your last script. -- `shutdown_timeout` (string) - The amount of time to wait after executing the shutdown_command for the +- `shutdown_timeout` (duration string. ex: "1h5m2s") - The amount of time to wait after executing the shutdown_command for the virtual machine to actually shut down. If the machine doesn't shut down in this time it is considered an error. By default, the time out is "5m" (five minutes). diff --git a/website/source/partials/helper/communicator/_Config-not-required.html.md b/website/source/partials/helper/communicator/_Config-not-required.html.md index e994c8fe1..ec02abbc7 100644 --- a/website/source/partials/helper/communicator/_Config-not-required.html.md +++ b/website/source/partials/helper/communicator/_Config-not-required.html.md @@ -15,7 +15,7 @@ that uses `docker exec` and `docker cp` to execute scripts and copy files. -- `pause_before_connecting` (time.Duration) - We recommend that you enable SSH or WinRM as the very last step in your +- `pause_before_connecting` (duration string. ex: "1h5m2s") - We recommend that you enable SSH or WinRM as the very last step in your guest's bootstrap script, but sometimes you may have a race condition where you need Packer to wait before attempting to connect to your guest. diff --git a/website/source/partials/helper/communicator/_SSH-not-required.html.md b/website/source/partials/helper/communicator/_SSH-not-required.html.md index 9aff6f74e..1eca3bcd7 100644 --- a/website/source/partials/helper/communicator/_SSH-not-required.html.md +++ b/website/source/partials/helper/communicator/_SSH-not-required.html.md @@ -36,7 +36,7 @@ - `ssh_pty` (bool) - If `true`, a PTY will be requested for the SSH connection. This defaults to `false`. -- `ssh_timeout` (time.Duration) - The time to wait for SSH to become available. Packer uses this to +- `ssh_timeout` (duration string. ex: "1h5m2s") - The time to wait for SSH to become available. Packer uses this to determine when the machine has booted so this is usually quite long. Example value: `10m`. @@ -79,10 +79,10 @@ - `ssh_proxy_password` (string) - The optional password to use to authenticate with the proxy server. -- `ssh_keep_alive_interval` (time.Duration) - How often to send "keep alive" messages to the server. Set to a negative +- `ssh_keep_alive_interval` (duration string. ex: "1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. -- `ssh_read_write_timeout` (time.Duration) - The amount of time to wait for a remote command to end. This might be +- `ssh_read_write_timeout` (duration string. ex: "1h5m2s") - The amount of time to wait for a remote command to end. This might be useful if, for example, packer hangs on a connection after a reboot. Example: `5m`. Disabled by default. diff --git a/website/source/partials/helper/communicator/_WinRM-not-required.html.md b/website/source/partials/helper/communicator/_WinRM-not-required.html.md index aac408a0b..dbbd58107 100644 --- a/website/source/partials/helper/communicator/_WinRM-not-required.html.md +++ b/website/source/partials/helper/communicator/_WinRM-not-required.html.md @@ -14,7 +14,7 @@ unencrypted connection and `5986` for SSL when `winrm_use_ssl` is set to true. -- `winrm_timeout` (time.Duration) - The amount of time to wait for WinRM to become available. This defaults +- `winrm_timeout` (duration string. ex: "1h5m2s") - The amount of time to wait for WinRM to become available. This defaults to `30m` since setting up a Windows machine generally takes a long time. - `winrm_use_ssl` (bool) - If `true`, use HTTPS for WinRM.