GCEの自動起動・自動停止をスケジューリングする

## 今回やりたいこと
GCEインスタンスの自動起動と自動停止をスケジューリングしたい。
例えば日中しか使わないから夜とかは停止しておいて朝になったら起動させることでコスト節約したいなどなど。。。
AWSでいう[LambdaのScheduleイベントでEC2を自動起動＆自動停止してみた#reinvent](http://dev.classmethod.jp/cloud/aws/lambda-scheduled-event-updown/)

GCPにはAWSのLambdaのような[Google Cloud Functions](https://cloud.google.com/functions/docs)があるが
まだ出たばかりでLamdaのようなスケジューリングの機能はない。
※2016/04/25 現在

GCPでは今のところスケジューリングなどはGoogle App Engineのcronサービスを使うらしい。
https://cloud.google.com/appengine/docs/python/config/cron#Python_app_yaml_The_schedule_format

## 検証環境
* 今回はGAEはpythonのDjangoを使用します。
* gceを起動、再起動するためにはcompute apiを使用するので認証周りなど[ここらへん](https://developers.google.com/identity/protocols/application-default-credentials#howtheywork)を参考にします。ここで取得したものを`credentials.json`とする

## インスタンスリストを取得してみる
まずはインスタンスリストを取得して認証が正しく通っているかなどを確認する

```py
#!/usr/bin/python
import os
from oauth2client.client import GoogleCredentials
from googleapiclient.discovery import build

root_path = os.path.dirname(os.path.realpath(__file__))

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '【credentials.jsonへのpath】'
credentials = GoogleCredentials.get_application_default()

compute = build('compute', 'v1', credentials=credentials)
project = '【プロジェクト名】'
zone = '【gceのインスタンスがあるゾーン】'
result_exec = compute.instances().list(project=project, zone=zone).execute()
items = result_exec['items']

for item in items:
  print '''
  id is %s
  name is %s
  zone is %s
  status is %s
  ''' %(item['id'], item['name'], item['zone'], item['status'])
```

## cronの設定や実行スクリプトなど

### **cron.yaml**
GAEのスケジュールはURLを指定して、そのスクリプトを実行する。
このファイルではいつどのURLにアクセスするかを指定する。
scheduleのformatに関しては[ここ](https://cloud.google.com/appengine/docs/python/config/cron#Python_app_yaml_The_schedule_format)をみる
urlは任意でよい。
今回は/instance/startと/instance/stopを作成したとしておく

```yaml
cron:
- description: instance start
  url: /instance/start
  schedule: every day 09:00
  timezone: Asia/Tokyo
- description: instance stop
  url: /instance/stop
  schedule: every day 22:00
  timezone: Asia/Tokyo
```

### **app.yaml**
上記で設定したurlがアクセスした時に実行するscriptを定義する。
`login: admin`と設定しているのは仮にURLをたたかれた時に認証をさせるため

```yaml
 -----

handlers:
- url: /instance/start
  script: instance.app
  login: admin
- url: /instance/stop
  script: instance.app
  login: admin
```

### **instance.py**
起動したり停止したりするスクリプトがかかれたスクリプト

```py

#!/usr/bin/python
import os
import sys
import webapp2 as webapp
from google.appengine.ext import vendor
vendor.add('lib')
from oauth2client.client import GoogleCredentials
from googleapiclient.discovery import build

root_path = os.path.dirname(os.path.realpath(__file__))
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '【credentials.jsonへのpath】'

project = '【プロジェクト名】'
zone = '【gceのインスタンスがあるゾーン】'
instance_names = [インスタンス名の配列]

credentials = GoogleCredentials.get_application_default()
compute = build('compute', 'v1', credentials=credentials)

# 開始用のHandler class
class InstanceStartHandler(webapp.RequestHandler):
  def get(self):
    print 'instance start process start'

    for instance_name in instance_names:
      # project, zone, instance名からインスタンスの情報を取得
      instance = compute.instances().get(project=project, zone=zone, instance=instance_name).execute()
      print '%s is %s' %(instance['name'], instance['status'])
      # インスタンスが停止している場合は開始処理を行う
      if instance['status'] == 'TERMINATED':
        print 'instance %s start......' %(instance['name'])
        compute.instances().start(project=project, zone=zone, instance=instance['name']).execute()
    
    print 'instance start process end'

# 停止用のHandler class
class InstanceStopHandler(webapp.RequestHandler):
  def get(self):
    print 'instance stop process start'

    for instance_name in instance_names:
      # project, zone, instance名からインスタンスの情報を取得
      instance = compute.instances().get(project=project, zone=zone, instance=instance_name).execute()
      print '%s is %s' %(instance['name'], instance['status'])
      # インスタンスが動いている場合は止める処理を行う
      if instance['status'] == 'RUNNING':
        print 'instance %s stop......' %(instance['name'])
        compute.instances().stop(project=project, zone=zone, instance=instance['name']).execute()

    print 'instance stop process end'

# app.yamlで設定したURLと実行するclassのセットを配列で定義する
app = webapp.WSGIApplication(
  [
    ('/instance/start', InstanceStartHandler),
    ('/instance/stop', InstanceStopHandler)
  ],
  debug=True
)
```

## フォルダ構成
今回は3つファイルをいじったけどフォルダ構成は下記
※ GAEはDjangoを使用している想定です

今回作成・編集したファイルはroot_dirにおく

```
root_dir
├─ polls
|   └─ ....
├─ lib
|   └─ ....
├─ mysite
|   └─ ....
└─ instance.py
└─ cron.yaml
└─ app.yaml
```

## タスクのuploadと確認
* GAEのコードをデプロイするには`appcfg.py -A stellar-mercury-734 update app.yaml`
* cron情報を更新するには`appcfg.py -A stellar-mercury-734 update_cron .`

ここまでくるとGAEのタスクキューのcronジョブから下記のように設定したものが確認できる
<img width="1117" alt="スクリーンショット 2016-04-26 1.08.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/44247/a77f8596-f606-8221-58ab-f79736a4ac7d.png">

後は画面上から「今すぐ実行」するなり時間になるまでまつと指定したインスタンスが自動起動、自動停止するはず

## Tips
3rd party製のツールを使用する際には下記のようにコマンドをうってDjangoのlib内にインストールする
[公式ドキュメント](https://cloud.google.com/appengine/docs/python/tools/libraries27?hl=ja#vendoring)

```
pip install -t lib oauth2client 
```