diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index eef56cf4c..1b50b4842 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -152,3 +152,7 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { return errs } + +func (c *RunConfig) IsSpotInstance() bool { + return c.SpotPrice != "" && c.SpotPrice != "0" +} diff --git a/builder/amazon/common/step_run_spot_instance.go b/builder/amazon/common/step_run_spot_instance.go index b34d09bcb..323032de0 100644 --- a/builder/amazon/common/step_run_spot_instance.go +++ b/builder/amazon/common/step_run_spot_instance.go @@ -231,21 +231,26 @@ func (s *StepRunSpotInstance) Run(state multistep.StateBag) multistep.StepAction ui.Message(fmt.Sprintf("Instance ID: %s", instanceId)) ui.Say(fmt.Sprintf("Waiting for instance (%v) to become ready...", instanceId)) - stateChangeSpot := StateChangeConf{ - Pending: []string{"pending"}, - Target: "running", - Refresh: InstanceStateRefreshFunc(ec2conn, instanceId), - StepState: state, + describeInstanceStatus := &ec2.DescribeInstanceStatusInput{ + InstanceIds: []*string{aws.String(instanceId)}, } - latestInstance, err := WaitForState(&stateChangeSpot) - if err != nil { + if err := ec2conn.WaitUntilInstanceStatusOk(describeInstanceStatus); err != nil { err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - instance := latestInstance.(*ec2.Instance) + r, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{aws.String(instanceId)}, + }) + if err != nil || len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 { + err := fmt.Errorf("Error finding source instance.") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + instance := r.Reservations[0].Instances[0] // Retry creating tags for about 2.5 minutes err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) { diff --git a/builder/amazon/common/step_stop_ebs_instance.go b/builder/amazon/common/step_stop_ebs_instance.go index 852626811..7d6b2e943 100644 --- a/builder/amazon/common/step_stop_ebs_instance.go +++ b/builder/amazon/common/step_stop_ebs_instance.go @@ -75,15 +75,12 @@ func (s *StepStopEBSBackedInstance) Run(state multistep.StateBag) multistep.Step ui.Say("Automatic instance stop disabled. Please stop instance manually.") } - // Wait for the instance to actual stop + // Wait for the instance to actually stop ui.Say("Waiting for the instance to stop...") - stateChange := StateChangeConf{ - Pending: []string{"running", "pending", "stopping"}, - Target: "stopped", - Refresh: InstanceStateRefreshFunc(ec2conn, *instance.InstanceId), - StepState: state, - } - _, err = WaitForState(&stateChange) + err = ec2conn.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{instance.InstanceId}, + }) + if err != nil { err := fmt.Errorf("Error waiting for instance to stop: %s", err) state.Put("error", err) diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 56757b826..255506ccc 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -69,6 +69,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) + if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Spot instances do not support modification, which is required "+ + "when either `ena_support` or `sriov_support` are set. Please ensure "+ + "you use an AMI that already has either SR-IOV or ENA enabled.")) + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } @@ -110,47 +117,46 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) var instanceStep multistep.Step - isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0" - if isSpotInstance { + if b.config.IsSpotInstance() { instanceStep = &awscommon.StepRunSpotInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - SpotPrice: b.config.SpotPrice, - SpotPriceProduct: b.config.SpotPriceAutoProduct, - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, - VolumeTags: b.config.VolumeRunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.BlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SpotPrice: b.config.SpotPrice, + SpotPriceProduct: b.config.SpotPriceAutoProduct, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, + VolumeTags: b.config.VolumeRunTags, } } else { instanceStep = &awscommon.StepRunSourceInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, - VolumeTags: b.config.VolumeRunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.BlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, + VolumeTags: b.config.VolumeRunTags, } } @@ -201,7 +207,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &awscommon.StepStopEBSBackedInstance{ - Skip: isSpotInstance, + Skip: b.config.IsSpotInstance(), DisableStopInstance: b.config.DisableStopInstance, }, &awscommon.StepModifyEBSBackedInstance{ diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index fec997816..8cf1fff12 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -84,6 +84,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("no volume with name '%s' is found", b.config.RootDevice.SourceDeviceName)) } + if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Spot instances do not support modification, which is required "+ + "when either `ena_support` or `sriov_support` are set. Please ensure "+ + "you use an AMI that already has either SR-IOV or ENA enabled.")) + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } @@ -124,47 +131,46 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) var instanceStep multistep.Step - isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0" - if isSpotInstance { + if b.config.IsSpotInstance() { instanceStep = &awscommon.StepRunSpotInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - SpotPrice: b.config.SpotPrice, - SpotPriceProduct: b.config.SpotPriceAutoProduct, - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, - VolumeTags: b.config.VolumeRunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.BlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SpotPrice: b.config.SpotPrice, + SpotPriceProduct: b.config.SpotPriceAutoProduct, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, + VolumeTags: b.config.VolumeRunTags, } } else { instanceStep = &awscommon.StepRunSourceInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, - VolumeTags: b.config.VolumeRunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.BlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, + VolumeTags: b.config.VolumeRunTags, } } @@ -212,7 +218,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &awscommon.StepStopEBSBackedInstance{ - Skip: isSpotInstance, + Skip: b.config.IsSpotInstance(), DisableStopInstance: b.config.DisableStopInstance, }, &awscommon.StepModifyEBSBackedInstance{ diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index 6bd8927ee..e7384784b 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -62,6 +62,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, err) } + if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Spot instances do not support modification, which is required "+ + "when either `ena_support` or `sriov_support` are set. Please ensure "+ + "you use an AMI that already has either SR-IOV or ENA enabled.")) + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } @@ -103,45 +110,43 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe var instanceStep multistep.Step - isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0" - - if isSpotInstance { + if b.config.IsSpotInstance() { instanceStep = &awscommon.StepRunSpotInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - SpotPrice: b.config.SpotPrice, - SpotPriceProduct: b.config.SpotPriceAutoProduct, - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.launchBlockDevices, - Tags: b.config.RunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.launchBlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SpotPrice: b.config.SpotPrice, + SpotPriceProduct: b.config.SpotPriceAutoProduct, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, } } else { instanceStep = &awscommon.StepRunSourceInstance{ - Debug: b.config.PackerDebug, - ExpectedRootDevice: "ebs", - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, - AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, - AvailabilityZone: b.config.AvailabilityZone, - BlockDevices: b.config.launchBlockDevices, - Tags: b.config.RunTags, - Ctx: b.config.ctx, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + AvailabilityZone: b.config.AvailabilityZone, + BlockDevices: b.config.launchBlockDevices, + Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + ExpectedRootDevice: "ebs", + IamInstanceProfile: b.config.IamInstanceProfile, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, } } @@ -189,7 +194,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &awscommon.StepStopEBSBackedInstance{ - Skip: isSpotInstance, + Skip: b.config.IsSpotInstance(), DisableStopInstance: b.config.DisableStopInstance, }, &awscommon.StepModifyEBSBackedInstance{ diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 220ee7b10..ccef52d1a 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -155,6 +155,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs, fmt.Errorf("x509_key_path points to bad file: %s", err)) } + if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Spot instances do not support modification, which is required "+ + "when either `ena_support` or `sriov_support` are set. Please ensure "+ + "you use an AMI that already has either SR-IOV or ENA enabled.")) + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } @@ -196,39 +203,39 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe var instanceStep multistep.Step - if b.config.SpotPrice == "" || b.config.SpotPrice == "0" { - instanceStep = &awscommon.StepRunSourceInstance{ - Debug: b.config.PackerDebug, - InstanceType: b.config.InstanceType, - UserData: b.config.UserData, - UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, + if b.config.IsSpotInstance() { + instanceStep = &awscommon.StepRunSpotInstance{ AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, AvailabilityZone: b.config.AvailabilityZone, BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, Ctx: b.config.ctx, - } - } else { - instanceStep = &awscommon.StepRunSpotInstance{ Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + IamInstanceProfile: b.config.IamInstanceProfile, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, SpotPrice: b.config.SpotPrice, SpotPriceProduct: b.config.SpotPriceAutoProduct, - InstanceType: b.config.InstanceType, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, UserData: b.config.UserData, UserDataFile: b.config.UserDataFile, - SourceAMI: b.config.SourceAmi, - IamInstanceProfile: b.config.IamInstanceProfile, - SubnetId: b.config.SubnetId, + } + } else { + instanceStep = &awscommon.StepRunSourceInstance{ AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, - EbsOptimized: b.config.EbsOptimized, AvailabilityZone: b.config.AvailabilityZone, BlockDevices: b.config.BlockDevices, - Tags: b.config.RunTags, Ctx: b.config.ctx, + Debug: b.config.PackerDebug, + EbsOptimized: b.config.EbsOptimized, + IamInstanceProfile: b.config.IamInstanceProfile, + InstanceType: b.config.InstanceType, + SourceAMI: b.config.SourceAmi, + SubnetId: b.config.SubnetId, + Tags: b.config.RunTags, + UserData: b.config.UserData, + UserDataFile: b.config.UserDataFile, } }