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 }