github.com/angdraug/packer@v1.3.2/builder/amazon/common/step_source_ami_info.go (about)

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