Slack slash command で GCP Compute Engine を起動・停止する

# はじめに
GCPで一時的にCompute Engineを利用したいユーザから都度依頼を受けるたびに起動・停止を手動で行うのが大変であるため、Slackから起動・停止ができるようにしたいと思ったのがはじまり。
想定外の Instance の起動・停止をされると困るので、設定ファイルに記載された Instance のみを対象とするようにした。
この記事ではSlackとGCPの設定を行い、実際に利用できるまでについて記載します。
コードの解説については別記事(作成中)に記載します。

本記事は [Google Cloud Platform Advent Calendar 2020](https://qiita.com/advent-calendar/2020/gcp) の 14日目の記事です。

# この記事でできること

slack で slash command を実行したら、GCP のcompute Engine Instance の起動・停止ができる

実行方法とレスポンスの例は[使い方](#使い方)まで



# 全体概要
![全体概要図.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/b7c9e739-07ff-d164-344f-cf64226bc749.png)

1. slack から slash command で Cloud Functions #1 をキックする
2. Cloud Functions #2 をキックするため Cloud Pub/Sub に必要な情報を渡す
3. slack に 初回通知を行う
4. Cloud Pub/Sub が Cloud Functions #2 をキックする
5. Cloud Functions #2 で Compute Engine のAPIで起動・停止を行う
6. Compute Engine からの応答を確認する
7. slackにスレッド返信で通知する

※2~3の処理はslack slash command が3秒以内に応答がないとエラーとなるため、起動・停止処理を行う前にレスポンスを返す。

# 設定方法

下記の順で説明していきます。
1. slack apps
2. Cloud Functions #2
3. Cloud Functions #1
4. slack slash command

### slack apps を設定する

**1. Slack App 作成**

Slack の Your Apps ページに行く
https://api.slack.com/apps

"Create New App" ボタンを押し、任意のアプリ名と Workspase を入力し、"Create App" を選択
![your_apps.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/9fb7c932-fcd3-d46a-431b-86ed15ada232.png)

**2. 権限追加**

OAuth & Permissions の Scopes で Bot Token Scopes に 下記の Scope を追加する

* chat:write
* chat:write.customize

追加後、Workspace にアプリをインストールする
インストールするとTokenが発行されるのでメモしておく
![slack_token.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/37503c60-b114-072b-fcea-ece94996e902.png)

**3. 設定値メモ**

また、Basic Information の App Credntials にある下記の情報をメモしておく

* Siging Secret

---

### Cloud Functions #2 を設定する

**設定値メモ**

GCP の プロジェクト情報から下記情報をメモしておく

* プロジェクトID

**Function作成**

GCP の Cloud Functions で "関数の作成"を押す

下記の設定を行う

|項目名|値|今回の設定値|
|:--|:--|:--|
|関数名|任意の名前|operate_instace|
|リージョン|任意のリージョン|asia-northeast1|
|トリガー タイプ|Cloud Pub/Sub|左同|
|トリガー トピック|任意の名前|ope-instance-test(新規作成)|
|詳細設定　詳細タブ　サービスアカウント|任意のアカウント|opeInstanceFromSlack(新規作成)|
|詳細設定　変数タブ|下記の通り|左同|
|詳細設定　上記以外|デフォルト|左同|

ランタイム環境変数設定

|名前|値|
|:--|:--|
|PROJECT_ID|メモした "GCP Project ID"|
|SLACK_TOKEN|メモした "Bot User OAuth Access Token"|
|SLACK_CHANNEL|投稿先のSlack Channel名|

トリガーを保存して、"次へ"を押す

コード設定

|名前|値|
|:--|:--|
|ランタイム|Python 3.8|
|エントリポイント|from_pubsub|

ソースコードに下記gitのリンク先のファイルを配置
[slack-command-to-gcp/operate_instance](https://github.com/kohei-kuwata/slack-command-to-gcp/tree/main/operate_instance)

ファイル構成などはこんな感じ
![ope_instace.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/74988150-7913-f395-ee37-5c6224f03352.png)

設定が完了したら、"デプロイ"を押す

---

### Cloud Functions #1 を設定する
GCP の Cloud Functions で "関数の作成"を押す

下記の設定を行う

|項目名|値|今回の設定値|
|:--|:--|:--|
|関数名|任意の名前|from_slack|
|リージョン|任意のリージョン|asia-northeast1|
|トリガー タイプ|HTTP|左同|
|トリガー 認証|未承認の呼び出しを許可|左同|
|詳細設定　詳細タブ　サービスアカウント|任意のアカウント|opeInstanceFromSlack|
|詳細設定　変数タブ|下記の通り|左同|
|詳細設定　上記以外|デフォルト|左同|

ランタイム環境変数設定

|名前|値|
|:--|:--|
|PROJECT_ID|メモした "GCP Project ID"|
|PUBSUB_TOPIC|作成したpub/sub Topic名|
|SLACK_TOKEN|メモした "Bot User OAuth Access Token"|
|SLACK_SECRET|メモした "Siging Secret"|
|SLACK_CHANNEL|投稿先のSlack Channel名|

トリガーを保存して、"次へ"を押す

コード設定

|名前|値|
|:--|:--|
|ランタイム|Python 3.8|
|エントリポイント|from_slack|

ソースコードに下記gitのリンク先のファイルを配置 ※instances.json は下記に従い変更する必要あり
[slack-command-to-gcp/from_slack](https://github.com/kohei-kuwata/slack-command-to-gcp/tree/main/from_slack)

対象のインスタンス情報をJsonファイル(instances.json)に記入する。
記載方法は下記の通り。

```json:instances.json
{
    "Instance名":{
        "zone":"zone名",
        "type":"compute"
    },
    //下記は例
    "test-server":{
        "zone":"asia-northeast1-a",
        "type":"compute"
    }
}
```

ファイル構成などはこんな感じ
![from_slack.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/c6eeeb2c-1185-f5f0-91ab-82ff7e1485d5.png)

設定が完了したら、"デプロイ"を押す

**GCPの権限設定**

IAM と管理ページを開く
サービスアカウントを開き、"Cloud Functions #2"で追加したサービスアカウントを検索する
検索結果のメールアドレスをコピーする

IAM ページを開き、追加を選択
下記の設定を行い、"保存"を押す

|項目名|値|今回の設定値|
|:--|:--|:--|
|新しいメンバー|コピーしたメールアドレス|opeInstanceFromSlack@~|
|ロール|Compute 管理者<br>Pub/Sub パブリッシャー|左同|

---

### slack slash command を設定する

slack app のページに戻る

Basic Information の Add features and functionality から "Slash Commands" を選択し、"Create New Command" を選択
![slack_features.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/3554bdcc-f236-8ea3-6f7a-afeb1e34713a.png)

下記の設定を行い、"Save"を押す

|項目名|値|今回の設定値|
|:--|:--|:--|
|Command|任意の名前|/gcp-test|
|Request URL|Cloud Functions #1 のトリガーURL|https://<リージョン>-< ProjectID >.cloudfunctions.net/<関数名>|
|Short Description|任意の説明|operate gcp|
|Usage Hint|任意の説明 ※省略可|-|

アプリの再インストールを求められるので、実施する

**Slack Channel に アプリをインストール**

コマンドを実行したいチャンネルの詳細を開く
"その他"を押し、"アプリの追加"を選択
作成したアプリ(今回であれば"gcp-test")の"追加"ボタンを押し、追加する

# 使い方

アプリをインストールしたチャンネルで下記のように入力し、コマンドを実行する
/slackアプリ名 [status/start/stop] インスタンス名
ex) /gcp-test status test-server

■Status レスポンス例
![gcp-test_status.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/b12291eb-7111-aeff-406d-f2bdc79a13c1.png)

■Stop レスポンス例
![gcp-test_stop.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/3905284e-796f-3d0a-05bf-cdb97ad10156.png)


**注意事項**

たまにSlackbotが timeout エラーになることがあるが、アプリ名でメッセージが送られていれば、動作している。
![err_skackbot.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405298/327f1852-de05-d52a-f177-1388978ef5b9.png)

# 最後に

Pub/Sub 経由で Function をキックする部分が特にWebに資料がほとんどなくて結構苦労しました。
基本となる仕組みはできたので、他の操作や Compute Engine 以外にも応用していこうと思います。