github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/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  
    69  	log.Printf("Using AMI Filters %v", params)
    70  	imageResp, err := ec2conn.DescribeImages(params)
    71  	if err != nil {
    72  		err := fmt.Errorf("Error querying AMI: %s", err)
    73  		state.Put("error", err)
    74  		ui.Error(err.Error())
    75  		return multistep.ActionHalt
    76  	}
    77  
    78  	if len(imageResp.Images) == 0 {
    79  		err := fmt.Errorf("No AMI was found matching filters: %v", params)
    80  		state.Put("error", err)
    81  		ui.Error(err.Error())
    82  		return multistep.ActionHalt
    83  	}
    84  
    85  	if len(imageResp.Images) > 1 && s.AmiFilters.MostRecent == false {
    86  		err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
    87  		state.Put("error", err)
    88  		ui.Error(err.Error())
    89  		return multistep.ActionHalt
    90  	}
    91  
    92  	var image *ec2.Image
    93  	if s.AmiFilters.MostRecent {
    94  		image = mostRecentAmi(imageResp.Images)
    95  	} else {
    96  		image = imageResp.Images[0]
    97  	}
    98  
    99  	ui.Message(fmt.Sprintf("Found Image ID: %s", *image.ImageId))
   100  
   101  	// Enhanced Networking (SriovNetSupport) can only be enabled on HVM AMIs.
   102  	// See http://goo.gl/icuXh5
   103  	if s.EnhancedNetworking && *image.VirtualizationType != "hvm" {
   104  		err := fmt.Errorf("Cannot enable enhanced networking, source AMI '%s' is not HVM", s.SourceAmi)
   105  		state.Put("error", err)
   106  		ui.Error(err.Error())
   107  		return multistep.ActionHalt
   108  	}
   109  
   110  	state.Put("source_image", image)
   111  	return multistep.ActionContinue
   112  }
   113  
   114  func (s *StepSourceAMIInfo) Cleanup(multistep.StateBag) {}