2014-06-04 17:58:11 -04:00
|
|
|
package common
|
2013-07-29 20:37:22 -04:00
|
|
|
|
|
|
|
import (
|
2018-01-22 18:32:33 -05:00
|
|
|
"context"
|
2013-07-29 20:37:22 -04:00
|
|
|
"fmt"
|
2016-08-20 19:08:45 -04:00
|
|
|
"log"
|
|
|
|
"sort"
|
|
|
|
"time"
|
2014-06-04 17:58:11 -04:00
|
|
|
|
2015-06-03 17:13:52 -04:00
|
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
2018-01-19 19:18:44 -05:00
|
|
|
"github.com/hashicorp/packer/helper/multistep"
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/packer"
|
2013-07-29 20:37:22 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// StepSourceAMIInfo extracts critical information from the source AMI
|
|
|
|
// that is used throughout the AMI creation process.
|
|
|
|
//
|
|
|
|
// Produces:
|
|
|
|
// source_image *ec2.Image - the source AMI info
|
2014-06-04 17:58:11 -04:00
|
|
|
type StepSourceAMIInfo struct {
|
2017-08-28 12:18:23 -04:00
|
|
|
SourceAmi string
|
|
|
|
EnableAMISriovNetSupport bool
|
|
|
|
EnableAMIENASupport bool
|
2018-09-04 21:13:18 -04:00
|
|
|
AMIVirtType string
|
2017-08-28 12:18:23 -04:00
|
|
|
AmiFilters AmiFilterOptions
|
2016-08-20 14:58:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build a slice of AMI filter options from the filters provided.
|
|
|
|
func buildAmiFilters(input map[*string]*string) []*ec2.Filter {
|
|
|
|
var filters []*ec2.Filter
|
|
|
|
for k, v := range input {
|
|
|
|
filters = append(filters, &ec2.Filter{
|
|
|
|
Name: k,
|
|
|
|
Values: []*string{v},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return filters
|
2014-06-04 17:58:11 -04:00
|
|
|
}
|
2013-07-29 20:37:22 -04:00
|
|
|
|
2016-08-20 19:08:45 -04:00
|
|
|
type imageSort []*ec2.Image
|
|
|
|
|
|
|
|
func (a imageSort) Len() int { return len(a) }
|
|
|
|
func (a imageSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
func (a imageSort) Less(i, j int) bool {
|
|
|
|
itime, _ := time.Parse(time.RFC3339, *a[i].CreationDate)
|
|
|
|
jtime, _ := time.Parse(time.RFC3339, *a[j].CreationDate)
|
|
|
|
return itime.Unix() < jtime.Unix()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the most recent AMI out of a slice of images.
|
|
|
|
func mostRecentAmi(images []*ec2.Image) *ec2.Image {
|
|
|
|
sortedImages := images
|
|
|
|
sort.Sort(imageSort(sortedImages))
|
|
|
|
return sortedImages[len(sortedImages)-1]
|
|
|
|
}
|
|
|
|
|
2018-01-22 18:31:41 -05:00
|
|
|
func (s *StepSourceAMIInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
2013-08-31 15:58:55 -04:00
|
|
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
|
|
|
ui := state.Get("ui").(packer.Ui)
|
2013-07-29 20:37:22 -04:00
|
|
|
|
2016-08-20 14:58:36 -04:00
|
|
|
params := &ec2.DescribeImagesInput{}
|
2016-08-20 19:08:45 -04:00
|
|
|
|
|
|
|
if s.SourceAmi != "" {
|
|
|
|
params.ImageIds = []*string{&s.SourceAmi}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have filters to apply
|
|
|
|
if len(s.AmiFilters.Filters) > 0 {
|
|
|
|
params.Filters = buildAmiFilters(s.AmiFilters.Filters)
|
|
|
|
}
|
2016-12-01 08:29:31 -05:00
|
|
|
if len(s.AmiFilters.Owners) > 0 {
|
|
|
|
params.Owners = s.AmiFilters.Owners
|
|
|
|
}
|
2016-08-20 19:08:45 -04:00
|
|
|
|
|
|
|
log.Printf("Using AMI Filters %v", params)
|
2016-08-20 14:58:36 -04:00
|
|
|
imageResp, err := ec2conn.DescribeImages(params)
|
2013-07-29 20:37:22 -04:00
|
|
|
if err != nil {
|
|
|
|
err := fmt.Errorf("Error querying AMI: %s", err)
|
2013-08-31 15:58:55 -04:00
|
|
|
state.Put("error", err)
|
2013-07-29 20:37:22 -04:00
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(imageResp.Images) == 0 {
|
2016-08-20 19:08:45 -04:00
|
|
|
err := fmt.Errorf("No AMI was found matching filters: %v", params)
|
|
|
|
state.Put("error", err)
|
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
2017-03-28 21:29:55 -04:00
|
|
|
if len(imageResp.Images) > 1 && !s.AmiFilters.MostRecent {
|
2016-08-20 19:08:45 -04:00
|
|
|
err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
|
2013-08-31 15:58:55 -04:00
|
|
|
state.Put("error", err)
|
2013-07-29 20:37:22 -04:00
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
2016-08-20 19:08:45 -04:00
|
|
|
var image *ec2.Image
|
|
|
|
if s.AmiFilters.MostRecent {
|
|
|
|
image = mostRecentAmi(imageResp.Images)
|
|
|
|
} else {
|
|
|
|
image = imageResp.Images[0]
|
|
|
|
}
|
|
|
|
|
2016-11-01 18:26:43 -04:00
|
|
|
ui.Message(fmt.Sprintf("Found Image ID: %s", *image.ImageId))
|
2013-07-29 20:37:22 -04:00
|
|
|
|
Always set both SRIOV and ENA when Enhanced Networking is enabled
Set SriovNetSupport to "simple". As of February 2017, this applies to C3, C4,
D2, I2, R3, and M4 (excluding m4.16xlarge).
Set EnaSupport to true. As of February 2017, this applies to C5, I3, P2, R4,
X1, and m4.16xlarge.
2017-02-21 20:46:16 -05:00
|
|
|
// Enhanced Networking can only be enabled on HVM AMIs.
|
2014-06-04 17:58:11 -04:00
|
|
|
// See http://goo.gl/icuXh5
|
2018-09-04 21:13:18 -04:00
|
|
|
if s.EnableAMIENASupport || s.EnableAMISriovNetSupport {
|
|
|
|
err = s.canEnableEnhancedNetworking(image)
|
|
|
|
if err != nil {
|
|
|
|
state.Put("error", err)
|
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
2013-07-29 20:37:22 -04:00
|
|
|
}
|
|
|
|
|
2013-08-31 15:58:55 -04:00
|
|
|
state.Put("source_image", image)
|
2013-07-29 20:37:22 -04:00
|
|
|
return multistep.ActionContinue
|
|
|
|
}
|
|
|
|
|
2013-08-31 15:58:55 -04:00
|
|
|
func (s *StepSourceAMIInfo) Cleanup(multistep.StateBag) {}
|
2018-09-04 21:13:18 -04:00
|
|
|
|
|
|
|
func (s *StepSourceAMIInfo) canEnableEnhancedNetworking(image *ec2.Image) error {
|
|
|
|
if s.AMIVirtType == "hvm" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if s.AMIVirtType != "" {
|
|
|
|
return fmt.Errorf("Cannot enable enhanced networking, AMIVirtType '%s' is not HVM", s.AMIVirtType)
|
|
|
|
}
|
|
|
|
if *image.VirtualizationType != "hvm" {
|
|
|
|
return fmt.Errorf("Cannot enable enhanced networking, source AMI '%s' is not HVM", s.SourceAmi)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|