Go言語でGCEのインスタンス一覧を取得する

[google/google-api-go-client](https://github.com/google/google-api-go-client)を使う。

取得処理自体は以下のとおり。

```go
import (
  "google.golang.org/api/compute/v1"
  "net/http"
)

func listInstances(client *http.Client, project_id string, zone string) (*compute.InstanceList, error) {
	service, err := compute.New(client)  // Newを使うとServiecオブジェクトがつくれる。各サービスのインスタンスを初期化してくれる。
	if err != nil {
		return nil, err
	}
	
	t := services.instasces  //　compute.NewInstancesService(service) と等価
	list, err := t.List(project_id, zone).Do() // いろんなメソッドがある Listを使うと一覧を取得する命令を構築する。 Doで実際のアクセスが発生する。
	if err != nil {
		return nil, err
	}
	return list, err
}
```

http.ClientとProjectIDとZONEが必要になる。
http.ClientはGoogle APIにアクセスするための情報がセットされているという前提になる。後述する。

[GCEのインスタンスの一覧の取得のAPI](https://cloud.google.com/compute/docs/reference/latest/instances/list)を確認すると project と zone が必須なのがわかる。オプションになるパラメータはDoを呼ぶ際に指定することができる。


# http.Clintの取得

DefaultClientを使うと、`gcloud auth login`などが実行済みだったり、GCEをインスタンスを作成する際に権限を付与済みであれば、その情報をつかったhttp.Clientを作成することができる。
別途APIKeyを用意する必要がなく、CLIツールと同じ権限で実行させることができて便利。

参考コード。

```go
import (
  "golang.org/x/oauth2/google"
  "golang.org/x/net/context"
)

func client() *http.Client {
	ctx := context.Background()
	client, _ := google.DefaultClient(ctx)
	return client
}
```

google.DefaultClientを使うのに、Contextが必要になる。

## Google AppEngineの場合

Google App Engineで利用したい場合は少し修正が必要。


```go
import (
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v1"
	newurlfetch "google.golang.org/appengine/urlfetch"
	"net/http"
)

func client(c *context.Context) *http.Client {
	source, err := google.DefaultTokenSource(c, compute.ComputeScope)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: source,
			Base:   &newurlfetch.Transport{Context: c},
		},
	}
	return client
}
```

Google App EngineのSDKに付属しているものではなく、Managed VMsを利用する際のライブラリを使うようだ。

最後に、一つにまとめたソースの例をおいとく

```go
package main

import (
	"fmt"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v1"
	newurlfetch "google.golang.org/appengine/urlfetch"
	"net/http"
	"os"
)

const project = "XXXXXXXX"  // project id
const zone = "XXXXXXX"      // east-asia1-bとか

func listInstances(client *http.Client, project_id string, zone string) (*compute.InstanceList, error) {
	service, err := compute.New(client)
	if err != nil {
		return nil, err
	}
	t := compute.NewInstancesService(service)
	list, err := t.List(project_id, zone).Do()
	if err != nil {
		return nil, err
	}
	return list, err
}

// CLI
func main() {
	ctx := context.Background()
	client, err := google.DefaultClient(ctx)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	list, err := listInstances(client, project, zone)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	for _, v := range list.Items {
		fmt.Println(v.Name)
	}
}

// Google App Engine
func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	ctx := context.Background()
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: source,
			Base:   &newurlfetch.Transport{Context: c},
		},
	}
	list, _ := listInstances(client, project, zone)
	for _, v := range list.Items {
		fmt.Fprintln(w, v.Name)
	}
}
```

### 参考文献

* https://github.com/google/google-api-go-client
* https://github.com/golang/oauth2
* https://godoc.org/google.golang.org/api/compute/v1