github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/amazon/common/step_source_ami_info.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sort"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/service/ec2"
    10  	"github.com/mitchellh/multistep"
    11  	"github.com/mitchellh/packer/packer"
    12  )
    13  
    14  // StepSourceAMIInfo extracts critical information from the source AMI
    15  // that is used throughout the AMI creation process.
    16  //
    17  // Produces:
    18  //   source_image *ec2.Image - the source AMI info
    19  type StepSourceAMIInfo struct {
    20  	SourceAmi          string
    21  	EnhancedNetworking bool
    22  	AmiFilters         AmiFilterOptions
    23  }
    24  
    25  // Build a slice of AMI filter options from the filters provided.
    26  func buildAmiFilters(input map[*string]*string) []*ec2.Filter {
    27  	var filters []*ec2.Filter
    28  	for k, v := range input {
    29  		filters = append(filters, &ec2.Filter{
    30  			Name:   k,
    31  			Values: []*string{v},
    32  		})
    33  	}
    34  	return filters
    35  }
    36  
    37  type imageSort []*ec2.Image
    38  
    39  func (a imageSort) Len() int      { return len(a) }
    40  func (a imageSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
    41  func (a imageSort) Less(i, j int) bool {
    42  	itime, _ := time.Parse(time.RFC3339, *a[i].CreationDate)
    43  	jtime, _ := time.Parse(time.RFC3339, *a[j].CreationDate)
    44  	return itime.Unix() < jtime.Unix()
    45  }
    46  
    47  // Returns the most recent AMI out of a slice of images.
    48  func mostRecentAmi(images []*ec2.Image) *ec2.Image {
    49  	sortedImages := images
    50  	sort.Sort(imageSort(sortedImages))
    51  	return sortedImages[len(sortedImages)-1]
    52  }
    53  
    54  func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction {
    55  	ec2conn := state.Get("ec2").(*ec2.EC2)
    56  	ui := state.Get("ui").(packer.Ui)
    57  
    58  	params := &ec2.DescribeImagesInput{}
    59  
    60  	if s.SourceAmi != "" {
    61  		params.ImageIds = []*string{&s.SourceAmi}
    62  	}
    63  
    64  	// We have filters to apply
    65  	if len(s.AmiFilters.Filters) > 0 {
    66  		params.Filters = buildAmiFilters(s.AmiFilters.Filters)
    67  	}
    68  	if len(s.AmiFilters.Owners) > 0 {
    69  		params.Owners = s.AmiFilters.Owners
    70  	}
    71  
    72  	log.Printf("Using AMI Filters %v", params)
    73  	imageResp, err := ec2conn.DescribeImages(params)
    74  	if err != nil {
    75  		err := fmt.Errorf("Error querying AMI: %s", err)
    76  		state.Put("error", err)
    77  		ui.Error(err.Error())
    78  		return multistep.ActionHalt
    79  	}
    80  
    81  	if len(imageResp.Images) == 0 {
    82  		err := fmt.Errorf("No AMI was found matching filters: %v", params)
    83  		state.Put("error", err)
    84  		ui.Error(err.Error())
    85  		return multistep.ActionHalt
    86  	}
    87  
    88  	if len(imageResp.Images) > 1 && s.AmiFilters.MostRecent == false {
    89  		err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
    90  		state.Put("error", err)
    91  		ui.Error(err.Error())
    92  		return multistep.ActionHalt
    93  	}
    94  
    95  	var image *ec2.Image
    96  	if s.AmiFilters.MostRecent {
    97  		image = mostRecentAmi(imageResp.Images)
    98  	} else {
    99  		image = imageResp.Images[0]
   100  	}
   101  
   102  	ui.Message(fmt.Sprintf("Found Image ID: %s", *image.ImageId))
   103  
   104  	// Enhanced Networking (SriovNetSupport) can only be enabled on HVM AMIs.
   105  	// See http://goo.gl/icuXh5
   106  	if s.EnhancedNetworking && *image.VirtualizationType != "hvm" {
   107  		err := fmt.Errorf("Cannot enable enhanced networking, source AMI '%s' is not HVM", s.SourceAmi)
   108  		state.Put("error", err)
   109  		ui.Error(err.Error())
   110  		return multistep.ActionHalt
   111  	}
   112  
   113  	state.Put("source_image", image)
   114  	return multistep.ActionContinue
   115  }
   116  
   117  func (s *StepSourceAMIInfo) Cleanup(multistep.StateBag) {}