124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
package common
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
"github.com/hashicorp/packer/helper/multistep"
|
|
"github.com/hashicorp/packer/packer"
|
|
)
|
|
|
|
// 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
|
|
type StepSourceAMIInfo struct {
|
|
SourceAmi string
|
|
EnableAMISriovNetSupport bool
|
|
EnableAMIENASupport *bool
|
|
AMIVirtType string
|
|
AmiFilters AmiFilterOptions
|
|
}
|
|
|
|
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]
|
|
}
|
|
|
|
func (s *StepSourceAMIInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
params := &ec2.DescribeImagesInput{}
|
|
|
|
if s.SourceAmi != "" {
|
|
params.ImageIds = []*string{&s.SourceAmi}
|
|
}
|
|
|
|
// We have filters to apply
|
|
if len(s.AmiFilters.Filters) > 0 {
|
|
params.Filters = buildEc2Filters(s.AmiFilters.Filters)
|
|
}
|
|
if len(s.AmiFilters.Owners) > 0 {
|
|
params.Owners = s.AmiFilters.Owners
|
|
}
|
|
|
|
log.Printf("Using AMI Filters %v", params)
|
|
imageResp, err := ec2conn.DescribeImages(params)
|
|
if err != nil {
|
|
err := fmt.Errorf("Error querying AMI: %s", err)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
if len(imageResp.Images) == 0 {
|
|
err := fmt.Errorf("No AMI was found matching filters: %v", params)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
if len(imageResp.Images) > 1 && !s.AmiFilters.MostRecent {
|
|
err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
var image *ec2.Image
|
|
if s.AmiFilters.MostRecent {
|
|
image = mostRecentAmi(imageResp.Images)
|
|
} else {
|
|
image = imageResp.Images[0]
|
|
}
|
|
|
|
ui.Message(fmt.Sprintf("Found Image ID: %s", *image.ImageId))
|
|
|
|
// Enhanced Networking can only be enabled on HVM AMIs.
|
|
// See http://goo.gl/icuXh5
|
|
if (s.EnableAMIENASupport != nil && *s.EnableAMIENASupport) || s.EnableAMISriovNetSupport {
|
|
err = s.canEnableEnhancedNetworking(image)
|
|
if err != nil {
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
}
|
|
|
|
state.Put("source_image", image)
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
func (s *StepSourceAMIInfo) Cleanup(multistep.StateBag) {}
|
|
|
|
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
|
|
}
|