diff --git a/builder/amazon/common/step_run_spot_instance.go b/builder/amazon/common/step_run_spot_instance.go index 210498eef..2f454b7c0 100644 --- a/builder/amazon/common/step_run_spot_instance.go +++ b/builder/amazon/common/step_run_spot_instance.go @@ -210,6 +210,15 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) // instance yet ec2Tags.Report(ui) + volumeTags, err := TagMap(s.VolumeTags).EC2Tags(s.Ctx, s.Region, state) + if err != nil { + err := fmt.Errorf("Error generating volume tags: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + volumeTags.Report(ui) + spotOptions := ec2.LaunchTemplateSpotMarketOptionsRequest{} // The default is to set the maximum price to the OnDemand price. if s.SpotPrice != "auto" { @@ -262,8 +271,28 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) } } + if len(ec2Tags) > 0 { + launchTemplate.LaunchTemplateData.TagSpecifications = append( + launchTemplate.LaunchTemplateData.TagSpecifications, + &ec2.LaunchTemplateTagSpecificationRequest{ + ResourceType: aws.String("instance"), + Tags: ec2Tags, + }, + ) + } + + if len(volumeTags) > 0 { + launchTemplate.LaunchTemplateData.TagSpecifications = append( + launchTemplate.LaunchTemplateData.TagSpecifications, + &ec2.LaunchTemplateTagSpecificationRequest{ + ResourceType: aws.String("volume"), + Tags: volumeTags, + }, + ) + } + // Tell EC2 to create the template - _, err = ec2conn.CreateLaunchTemplate(launchTemplate) + createLaunchTemplateOutput, err := ec2conn.CreateLaunchTemplate(launchTemplate) if err != nil { err := fmt.Errorf("Error creating launch template for spot instance: %s", err) state.Put("error", err) @@ -271,6 +300,9 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) return multistep.ActionHalt } + launchTemplateId := createLaunchTemplateOutput.LaunchTemplate.LaunchTemplateId + ui.Message(fmt.Sprintf("Created Spot Fleet launch template: %s", *launchTemplateId)) + // Add overrides for each user-provided instance type var overrides []*ec2.FleetLaunchTemplateOverridesRequest for _, instanceType := range s.SpotInstanceTypes { @@ -437,16 +469,6 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) if len(volumeIds) > 0 && len(s.VolumeTags) > 0 { ui.Say("Adding tags to source EBS Volumes") - - volumeTags, err := TagMap(s.VolumeTags).EC2Tags(s.Ctx, s.Region, state) - if err != nil { - err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - volumeTags.Report(ui) - _, err = ec2conn.CreateTags(&ec2.CreateTagsInput{ Resources: volumeIds, Tags: volumeTags, diff --git a/builder/amazon/common/step_run_spot_instance_test.go b/builder/amazon/common/step_run_spot_instance_test.go index a30bc4702..71caa4bd3 100644 --- a/builder/amazon/common/step_run_spot_instance_test.go +++ b/builder/amazon/common/step_run_spot_instance_test.go @@ -190,7 +190,7 @@ func (m *runSpotEC2ConnMock) CreateTags(req *ec2.CreateTagsInput) (*ec2.CreateTa } } -func defaultEc2Mock(instanceId, spotRequestId, volumeId *string) *runSpotEC2ConnMock { +func defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId *string) *runSpotEC2ConnMock { instance := &ec2.Instance{ InstanceId: instanceId, SpotInstanceRequestId: spotRequestId, @@ -205,8 +205,10 @@ func defaultEc2Mock(instanceId, spotRequestId, volumeId *string) *runSpotEC2Conn return &runSpotEC2ConnMock{ CreateLaunchTemplateFn: func(in *ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) { return &ec2.CreateLaunchTemplateOutput{ - LaunchTemplate: nil, - Warning: nil, + LaunchTemplate: &ec2.LaunchTemplate{ + LaunchTemplateId: launchTemplateId, + }, + Warning: nil, }, nil }, CreateFleetFn: func(*ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error) { @@ -237,7 +239,8 @@ func TestRun(t *testing.T) { instanceId := aws.String("test-instance-id") spotRequestId := aws.String("spot-id") volumeId := aws.String("volume-id") - ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId) + launchTemplateId := aws.String("launchTemplateId") + ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId) uiMock := packersdk.TestUi(t) @@ -329,7 +332,8 @@ func TestRun_NoSpotTags(t *testing.T) { instanceId := aws.String("test-instance-id") spotRequestId := aws.String("spot-id") volumeId := aws.String("volume-id") - ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId) + launchTemplateId := aws.String("lt-id") + ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId) uiMock := packersdk.TestUi(t)