AWS SDK for Go でEC2インスタンス情報取得


Go言語がちょっと流行りだしてるのでやってみた。


## Go環境整備

まずGo言語を入れる。環境はMac(Yosemite 10.10.2)でbrewを使用。

```
$ brew install go
$ echo 'export GOPATH=${HOME}/.golang' >> ~/.bash_profile
$ echo 'export PATH=${PATH}:${GOROOT}/bin:${GOPATH}/bin' >> ~/.bash_profile
$ source ~/.bash_profile
$ go version
go version go1.4.1 darwin/amd64
```

恒例のやつも試しておく。

```
$ vi Hello.go
package main

import "fmt"

func main() {
    fmt.Println("Hello World!")
}

$ go build Hello.go
$ ./Hello
Hello World!

buildしなくてもいける
$ go run Hello.go
Hello World!
```

## AWS SDK fo Go インストール

[GitHub](https://github.com/awslabs/aws-sdk-go)にあるので取ってくる。
全部取ってみたらなんかエラーっぽいのが出たが、とりえあず行ってみる。(buildするソースがないってことだからOKっぽい?)

```
$ go get github.com/awslabs/aws-sdk-go
package github.com/awslabs/aws-sdk-go
	imports github.com/awslabs/aws-sdk-go
	imports github.com/awslabs/aws-sdk-go: no buildable Go source files in /Users/USERNAME/.golang/src/github.com/awslabs/aws-sdk-go
```


## インスタンス情報取得
まずは恒例のアクセスキー関連の情報を仕込んでおく。

```
$ vi ~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXX
```


そして、見慣れたdescribe-instancesを実行してみる。


```
$ vi ec2.go

package main

import (
    "fmt"

    "github.com/awslabs/aws-sdk-go/aws"
    "github.com/awslabs/aws-sdk-go/service/ec2"
)

func main() {
    svc := ec2.New(&aws.Config{Region: "ap-northeast-1"})
    res, err := svc.DescribeInstances(nil)
    if err != nil {
        panic(err)
    }

    for _, r := range res.Reservations {
        for _, i := range r.Instances {
            var tag_name string
            for _, t := range i.Tags {
                if *t.Key == "Name" {
                    tag_name = *t.Value
                }
            }
            fmt.Println(
                tag_name,
                *i.InstanceID,
                *i.InstanceType,
                *i.Placement.AvailabilityZone,
                *i.PrivateIPAddress,
                *i.State.Name,
            )
        }
    }
}

$ go run ec2.go
TAGNAME-A i-XXXXXXXX c1.medium ap-northeast-1a X.X.X.X stopped
TAGNAME-B i-XXXXXXXX m1.medium ap-northeast-1b X.X.X.X stopped
TAGNAME-C i-XXXXXXXX t2.small ap-northeast-1c X.X.X.X running
TAGNAME-D i-XXXXXXXX m3.large ap-northeast-1a X.X.X.X stopped
   :
   :
```

そのまんま[DescribeInstances](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#EC2.DescribeInstances)というAPIを使う。
実行結果として[DescribeInstancesOutput](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#DescribeInstancesOutput)という型の構造体を返し、その中のメンバである[Reservation](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#Reservation)の配列を参照する感じ。
んで、その[Reservation](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#Reservation)に含まれるメンバの[Instance](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#Instance)も配列なので二重ループでインスタンスの情報にアクセスしている。
インタンスの持っているメンバはほとんど文字列か数字なのでそのまま参照出来るが、[Tag](http://godoc.org/github.com/awslabs/aws-sdk-go/service/ec2#Tag)は構造体の配列なので、同じようにループさせて取得する。

Goにはforeach的なものが存在しないらしく、for文の応用技で `for key, val := range Array` という書き方を使う。`_` は使わないので捨ててるという意味。



ただ、このままだと綺麗に出力されないので、テーブルレイアウト表示させてみる。
ググって発見した[tablewriter](https://github.com/olekukonko/tablewriter)というのを使わせて頂く。

```
$ go get github.com/olekukonko/tablewriter
```

最終形はこんな感じ。

```
package main

import (
    "os"
    "github.com/awslabs/aws-sdk-go/aws"
    "github.com/awslabs/aws-sdk-go/service/ec2"
    "github.com/olekukonko/tablewriter"
)

func main() {
    svc := ec2.New(&aws.Config{Region: "ap-northeast-1"})
    res, err := svc.DescribeInstances(nil)
    if err != nil {
        panic(err)
    }

    table := tablewriter.NewWriter(os.Stdout)
    table.SetHeader([]string{"Tag Name", "Instance Id", "Instance Type", "AZ", "IP", "Status"})


    for _, r := range res.Reservations {
        for _, i := range r.Instances {
            var tag_name string
            for _, t := range i.Tags {
                if *t.Key == "Name" {
                    tag_name = *t.Value
                }
            }
            table.Append([]string{
                tag_name,
                *i.InstanceID,
                *i.InstanceType,
                *i.Placement.AvailabilityZone,
                *i.PrivateIPAddress,
                *i.State.Name,
            })
        }
    }
    table.Render()
}
```

実行結果のイメージ。

```
+-----------+-------------+---------------+-----------------+---------+---------+
| TAG NAME  | INSTANCE ID | INSTANCE TYPE |       AZ        |   IP    | STATUS  |
+-----------+-------------+---------------+-----------------+---------+---------+
| TAGNAME-A | i-XXXXXXXX  | m1.small      | ap-northeast-1a | X.X.X.X | stopped |
| TAGNAME-B | i-XXXXXXXX  | r3.2xlarge    | ap-northeast-1b | X.X.X.X | stopped |
| TAGNAME-C | i-XXXXXXXX  | m1.medium     | ap-northeast-1c | X.X.X.X | stopped |
| TAGNAME-D | i-XXXXXXXX  | c3.large      | ap-northeast-1b | X.X.X.X | running |
```


以上。今度はTag名で絞ったりインスタンス起動停止とかやってみよう。