1package main 2 3import ( 4 "fmt" 5 "log" 6 "sort" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/aws/session" 10 "github.com/aws/aws-sdk-go/service/ec2" 11) 12 13func clientForRegion(region string) (*ec2.EC2, error) { 14 sess, err := session.NewSession(&aws.Config{ 15 Region: ®ion, 16 }) 17 if err != nil { 18 return nil, err 19 } 20 return ec2.New(sess), nil 21} 22 23func getRegions(client *ec2.EC2) ([]*ec2.Region, error) { 24 all := false // beyond account access 25 regions, err := client.DescribeRegions(&ec2.DescribeRegionsInput{ 26 AllRegions: &all, 27 }) 28 if err != nil { 29 return nil, err 30 } 31 return regions.Regions, nil 32} 33 34type specs struct { 35 Cores int 36 Speed float64 37} 38 39func (s specs) String() string { 40 return fmt.Sprintf("(%d %.2f)", s.Cores, s.Speed) 41} 42 43func getData(regions []*ec2.Region, verbose bool) (map[string]map[string]specs, error) { 44 data := make(map[string]map[string]specs) 45 46 for _, region := range regions { 47 rData, rProblems, err := getDataForRegion(*region.RegionName) 48 if err != nil { 49 return nil, err 50 } 51 data[*region.RegionName] = rData 52 53 if verbose { 54 log.Println("region", *region.RegionName, "got data for", len(rData), "instance types", len(rProblems), "incomplete") 55 instanceProblems(rProblems) 56 } 57 } 58 59 return data, nil 60} 61 62func instanceProblems(problems map[string]string) { 63 types := make([]string, 0, len(problems)) 64 for k := range problems { 65 types = append(types, k) 66 } 67 sort.Strings(types) 68 for _, iType := range types { 69 log.Println(" ->", iType, problems[iType]) 70 } 71} 72 73func getDataForRegion(region string) (map[string]specs, map[string]string, error) { 74 client, err := clientForRegion(region) 75 if err != nil { 76 return nil, nil, err 77 } 78 79 data := make(map[string]specs) 80 problems := make(map[string]string) 81 regionInfoPage(client, true, region, nil, data, problems) 82 return data, problems, nil 83} 84 85func regionInfoPage(client *ec2.EC2, first bool, region string, token *string, data map[string]specs, problems map[string]string) { 86 if first || token != nil { 87 output, err := client.DescribeInstanceTypes(&ec2.DescribeInstanceTypesInput{ 88 NextToken: token, 89 }) 90 if err != nil { 91 log.Fatal(err) 92 } 93 94 // recursively accumulate each page of data 95 regionInfoAccumulate(output, data, problems) 96 regionInfoPage(client, false, region, output.NextToken, data, problems) 97 } 98} 99 100func regionInfoAccumulate(output *ec2.DescribeInstanceTypesOutput, data map[string]specs, problems map[string]string) { 101 for _, iType := range output.InstanceTypes { 102 switch { 103 104 case iType.ProcessorInfo == nil: 105 fallthrough 106 case iType.ProcessorInfo.SustainedClockSpeedInGhz == nil: 107 problems[*iType.InstanceType] = "missing clock Speed" 108 continue 109 110 case iType.VCpuInfo == nil: 111 fallthrough 112 case iType.VCpuInfo.DefaultVCpus == nil: 113 problems[*iType.InstanceType] = "missing virtual cpu Cores" 114 continue 115 116 default: 117 data[*iType.InstanceType] = specs{ 118 Speed: *iType.ProcessorInfo.SustainedClockSpeedInGhz, 119 Cores: int(*iType.VCpuInfo.DefaultVCpus), 120 } 121 continue 122 } 123 } 124} 125