diff --git a/instance.go b/instance.go index 5ebc577..f7bc065 100644 --- a/instance.go +++ b/instance.go @@ -1,32 +1,31 @@ package main import ( - "strconv" - "strings" + "net" + "github.com/aws/aws-sdk-go/service/ec2" ) type instance struct { *ec2.Instance - name *string + name string + privateIP net.IP } -type instanceSlice []*instance - -func newInstance(i *ec2.Instance) (ret *instance) { - ret = new(instance) +func newInstance(i *ec2.Instance) (ret instance) { ret.Instance = i + ret.privateIP = net.ParseIP(*i.PrivateIpAddress) for _, t := range i.Tags { if *t.Key == "Name" { - ret.name = t.Value + ret.name = *t.Value } } - return + return ret } func (i *instance) toRow() []string { return []string{ - *i.name, + i.name, *i.InstanceId, stringify(i.PublicIpAddress), *i.PrivateIpAddress, @@ -41,39 +40,26 @@ func stringify(s *string) string { return *s } -func (i *instance) privateIPOctets() []int { - stringOctets := strings.Split(*i.PrivateIpAddress, ".") - intOctets := make([]int, 4) - for n, o := range stringOctets { - x, _ := strconv.ParseInt(o, 10, 32) - intOctets[n] = int(x) - } - return intOctets -} - -func (s instanceSlice) Len() int { - return len(s) -} +// implement sort.Interface +type sortable []*instance +func (s sortable) Len() int { return len(s) } +func (s sortable) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s instanceSlice) Less(i, j int) bool { - octetsI, octetsJ := s[i].privateIPOctets(), s[j].privateIPOctets() - if *s[i].name < *s[j].name { +// Less sorts instances by name and then by private IP address +func (s sortable) Less(i, j int) bool { + if s[i].name < s[j].name { return true } - if *s[i].name > *s[j].name { + if s[i].name > s[j].name { return false } - for n := 0; n < 3; n++ { - if octetsI[n] < octetsJ[n] { + for n, v := range s[i].privateIP { + if v < s[j].privateIP[n] { return true } - if octetsI[n] > octetsJ[n] { + if v > s[j].privateIP[n] { return false } } - return true -} - -func (s instanceSlice) Swap(i, j int) { - s[i], s[j] = s[j], s[i] + return false } diff --git a/main.go b/main.go index 68adfb9..c0afbcb 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ func perror(err error) { } } -func getInstances(region string, instanceChan chan *instance) { +func getInstances(region string, c chan *instance) { ec2Svc := ec2.New(&aws.Config{Region: ®ion}) ec2instances, err := ec2Svc.DescribeInstances(&ec2.DescribeInstancesInput{ @@ -34,41 +34,47 @@ func getInstances(region string, instanceChan chan *instance) { for _, r := range ec2instances.Reservations { for _, i := range r.Instances { inst := newInstance(i) - instanceChan <- inst + c <- &inst } } } +func printTable(s []*instance) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Name", "Id", "PublicIP", "PrivateIP", "Key"}) + for _, i := range s { + table.Append(i.toRow()) + } + table.Render() +} + func main() { - var instances instanceSlice - instanceChan := make(chan *instance) + var instances []*instance + c := make(chan *instance) var wg sync.WaitGroup + // Query EC2 endpoints in each region in parallel for _, r := range REGIONS { wg.Add(1) go func(r string) { - getInstances(r, instanceChan) + getInstances(r, c) wg.Done() }(r) } + // Close channel after all EC2 queries have returned go func() { - for { - i, ok := <-instanceChan - if !ok { - return - } - instances = append(instances, i) - } + wg.Wait() + close(c) }() - wg.Wait() - close(instanceChan) - - sort.Sort(instances) - - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Name", "Id", "PublicIP", "PrivateIP", "Key"}) - for _, i := range instances { - table.Append(i.toRow()) + // Build up a slice of instances as they are returned to us + for { + i, ok := <-c + if !ok { + break + } + instances = append(instances, i) } - table.Render() + + sort.Sort(sortable(instances)) + printTable(instances) }