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