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) {}