Force durations to be passed a strings

Before this commit it was possible to set a duration using an integer or a float. Go's time.Duration is an int64 internally an mapstructure will take advantage of this and load the number as a int64 but `1` means one ns which is unexpected/confusing. To avoid confusion and enforce readability this forces users to pass a string with a unit for a duration; ex "56s".
This commit is contained in:
Adrien Delorme 2019-10-31 11:31:17 +01:00
parent ada9821897
commit bf3d9841c6
112 changed files with 423 additions and 415 deletions

View File

@ -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 {

View File

@ -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{

View File

@ -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{

View File

@ -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{

View File

@ -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{

View File

@ -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)

View File

@ -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"
}
/////////////////////////////////////////////

View File

@ -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)
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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(),
},
}

View File

@ -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)
}

View File

@ -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...)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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"`

View File

@ -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")
}

View File

@ -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")
}
}

View File

@ -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

View File

@ -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")
}
}

View File

@ -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")
}

View File

@ -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

View File

@ -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")
}
}

View File

@ -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...)

View File

@ -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 == "" {

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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},

View File

@ -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

View File

@ -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},

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -224,12 +224,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
},
&parallelscommon.StepRun{},
&parallelscommon.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
},
&parallelscommon.StepShutdown{
Command: b.config.ShutdownCommand,
Timeout: b.config.ShutdownTimeout,
Timeout: b.config.ShutdownTimeout.Duration(),
},
&parallelscommon.StepPrlctl{
Commands: b.config.PrlctlPost,

View File

@ -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},

View File

@ -78,11 +78,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
&parallelscommon.StepRun{},
&parallelscommon.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),
&parallelscommon.StepShutdown{
Command: b.config.ShutdownCommand,
Timeout: b.config.ShutdownTimeout,
Timeout: b.config.ShutdownTimeout.Duration(),
},
&common.StepCleanupTempKeys{
Comm: &b.config.SSHConfig.Comm,

View File

@ -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},

View File

@ -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},

View File

@ -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

View File

@ -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"))

View File

@ -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},

View File

@ -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)

View File

@ -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)

View File

@ -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" {

View File

@ -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},

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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,

View File

@ -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},

View File

@ -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,

View File

@ -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},

View File

@ -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,

View File

@ -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,

View File

@ -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},

View File

@ -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 {

View File

@ -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{

View File

@ -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},

View File

@ -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{

View File

@ -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},

View File

@ -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.

View File

@ -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{

View File

@ -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 != "" {

View File

@ -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{

View File

@ -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,

View File

@ -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())

View File

@ -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,

View File

@ -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)...)

View File

@ -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)

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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{},
},

View File

@ -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{},
},

View File

@ -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."))
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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,

View File

@ -31,7 +31,6 @@ var DefaultDecodeHookFuncs = []mapstructure.DecodeHookFunc{
uint8ToStringHook,
stringToTrilean,
mapstructure.StringToSliceHookFunc(","),
mapstructure.StringToTimeDurationHookFunc(),
}
// Decode decodes the configuration into the target and optionally

View File

@ -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,

36
helper/config/duration.go Normal file
View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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",

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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,
})

View File

@ -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{

View File

@ -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

View File

@ -0,0 +1,11 @@
{
"builders": [{
"type": "foo"
}],
"provisioners": [{
"timeout": 555,
"type": "bar",
"only": ["foo"]
}]
}

View File

@ -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

View File

@ -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:

Some files were not shown because too many files have changed in this diff Show More