StackStormからLineに通知してみよう

# はじめに
弊社エンジニアがちょくちょく記事を投稿していますが、StackStormは自動化の仕組みを作るのに非常に有用なツールです。しかし、日本で使うのに「この機能があったらなー」というものがあります。

そうLineへの通知です。

StackStormを紹介した際に、「StackStormの通知ってLineに飛ばせないの？」と問い合わせを受けたことがありますが、Line Packはまだありません。

そこで楽してLine通知を作ってみようと考えました。

# 背景と目的
## 背景
- StackStormで自動化をするにあたり、Packだけでなくもっと広い範囲でのサービス連携の要望がある
- 楽して機能拡張したいって要望は多い＜重要

ごりごりとAPIを叩くものを開発すれば、もちろん色々なサービスとの連携は可能です。
しかし、現実には開発のリソースを割けないところもあるので、楽して連携していきます。

## 目的
IFTTTのWebhook TriggerとLineのActionを使って、StackStormと連携させます。
その上で、StackStormで処理を行う際の通知をLineへ飛ばします。

# 手順
1. IFTTTの設定
IFTTTで新規のAppletを作っていきます。
まずはTriggerにWebhooksを指定します。Webhooksでの設定はEvent名だけなので、StackStormの通知用であることを明示します。

![05-event-name.png](https://qiita-image-store.s3.amazonaws.com/0/181557/05f6fb99-55fb-b847-0091-f498ec97888c.png)

Action部分にはLineのSend Messageを利用します。LineのSend Message Actionでは、通知先に自分自身宛か、自分が所属するグループが指定できます。通知内容はHTTPのBodyヘッダに含まれるValue1～Value3の3つの内容を指定できます。

Appletが出来上がったら、Webhook用のURLを確認します。

作成したAppletのWebhookアイコンをクリックします。
![11-applet.png](https://qiita-image-store.s3.amazonaws.com/0/181557/722a18b6-e459-d663-88ff-f6a5da5ac989.png)

Webhookの詳細が表示されるので、Documentationをクリックします。
![12-webhook-doc.png](https://qiita-image-store.s3.amazonaws.com/0/181557/ae8e66f2-1a9e-e615-e1a1-3aa45befdda1.png)

個人用のWebhook KeyとWebhook用のURLが表示されます。
URLの中に個人のKeyと先ほど作成したAppletで利用しているWebhook Event名をいれることで、Webhookが使えるようになります。
![13-webhook-url.png](https://qiita-image-store.s3.amazonaws.com/0/181557/8bdf3a6a-6a58-6547-4283-6a58fc9c37b9.png)

2.　APIのテスト
IFTTTの設定ができたら、動作するかテストします。
IFTTTのテストページにあるCurlコマンドをStackStormのホストから実行します。

```curl:IFTTTのWebhookをキック
# curl -X POST -H "Content-Type: application/json" -d '{"value1":"test"}' https://maker.ifttt.com/trigger/st2_notify/with/key/xxxxxxxxxxxxxxxxxxxxxx
Congratulations! You've fired the st2_notify event
```

実際にLineを見てみると画像のような通知が来ました。
これでIFTTTの設定は完了です。

3.　StackStormの設定
続いてStackStormの設定をしていきます。
今回はStackStormのCLIを覚えたい気持ちがあるのでCLIで設定を進めていきます。

まずはStackStormへログインします。
```stackstorm:StackStormへのログイン
# st2 login st2admin
Password:
Logged in as st2admin

Note: You didn't use --write-password option so the password hasn't been stored in the client config and you will need to login again in 24 hours when the auth token expires.
As an alternative, you can run st2 login command with the "--write-password" flag, but keep it mind this will cause it to store the password in plain-text in the client config file (~/.st2/config).
```

IFTTTのWebhookをキックするため、core.httpの仕様を確認します。
Parametersを確認しすると、IFTTTのキックに必要なmethodとbodyはそのまま使えますが、content-typeはありません。headerのParameterはあるので、それを使って自前で指定していきます。

```stackstorm:core.httpの確認
# st2 action get core.http
+-------------+--------------------------------------------------------------+
| Property    | Value                                                        |
+-------------+--------------------------------------------------------------+
| id          | 5aa74d5b760efb2bdb690815                                     |
| uid         | action:core:http                                             |
| ref         | core.http                                                    |
| pack        | core                                                         |
| name        | http                                                         |
| description | Action that performs an http request.                        |
| enabled     | True                                                         |
| entry_point |                                                              |
| runner_type | http-request                                                 |
| parameters  | {                                                            |
|             |     "body": {                                                |
|             |         "type": "string",                                    |
|             |         "description": "Body to send with the request"       |
|             |     },                                                       |
|             |     "file_content": {                                        |
|             |         "type": "string",                                    |
|             |         "description": "Magic attribute which is             |
|             | automatically populated when file_path is specified"         |
|             |     },                                                       |
|             |     "file_name": {                                           |
|             |         "type": "string",                                    |
|             |         "description": "Magic attribute which is             |
|             | automatically populated when file_path is specified"         |
|             |     },                                                       |
|             |     "file_content_type": {                                   |
|             |         "type": "string",                                    |
|             |         "description": "Optional content type for the        |
|             | uploaded file"                                               |
|             |     },                                                       |
|             |     "auth": {                                                |
|             |         "type": "string",                                    |
|             |         "description": "Auth string to be used. This can be  |
|             | like 'x-auth-token=XYZ'."                                    |
|             |     },                                                       |
|             |     "method": {                                              |
|             |         "enum": [                                            |
|             |             "HEAD",                                          |
|             |             "GET",                                           |
|             |             "POST",                                          |
|             |             "PUT",                                           |
|             |             "DELETE"                                         |
|             |         ],                                                   |
|             |         "type": "string",                                    |
|             |         "description": "HTTP method to use."                 |
|             |     },                                                       |
|             |     "headers": {                                             |
|             |         "type": "object",                                    |
|             |         "description": "HTTP headers to use with the         |
|             | request."                                                    |
|             |     },                                                       |
|             |     "params": {                                              |
|             |         "type": "object",                                    |
|             |         "description": "Query params to be used with the     |
|             | HTTP request."                                               |
|             |     },                                                       |
|             |     "timeout": {                                             |
|             |         "default": 60,                                       |
|             |         "type": "number",                                    |
|             |         "description": "Timeout for the HTTP request."       |
|             |     },                                                       |
|             |     "file_path": {                                           |
|             |         "type": "string",                                    |
|             |         "description": "Path to the file to upload"          |
|             |     }                                                        |
|             | }                                                            |
| notify      |                                                              |
| tags        |                                                              |
+-------------+--------------------------------------------------------------+
```

実際にcore.httpを使ってIFTTTをキックします。
先程のCurlコマンドを参考にParametersを指定します。
statusはsucceeded、HTTPのステータスコードは200が返ってきているので成功です。

```stackstorm:core.httpを使ったAPIアクセス（IFTTT編）
# st2 run core.http method=POST body='{"value1":"This is TEST!"}' url=https://maker.ifttt.com/trigger/event_notified/with/key/xxxxxxxxxxxxxxxxxxxxxx headers='content-type=application/json'
.
id: 5ab84fa5760efb2fd452a28b
status: succeeded
parameters:
  body: '{"value1":"This is TEST!"}'
  headers:
    content-type: application/json
  method: POST
  url: https://maker.ifttt.com/trigger/event_notified/with/key/xxxxxxxxxxxxxxxxxxxxxx
result:
  body: Congratulations! You've fired the event_notified event
  headers:
    Connection: keep-alive
    Content-Length: '54'
    Content-Type: text/html; charset=utf-8
    Date: Mon, 26 Mar 2018 01:40:55 GMT
    Server: web_server
    X-Top-SecreTTT: VG9vIGVhc3k/IElmIHlvdSBjYW4gcmVhZCB0aGlzLCBFbWFpbCB1cyBhdCBqb2JzK3NlY3JldEBpZnR0dC5jb20uIFdlIHdhbnQgTWFrZXJzLg==
  parsed: false
  status_code: 200
```

Lineを見ると、ちゃんと通知されています。

![16-notify-by-st2-1.png](https://qiita-image-store.s3.amazonaws.com/0/181557/3ac1abe4-c17e-0c1e-b3f9-e32e1f7ea603.png)

次にルールを作ります。
StackStormのルールはYAMLファイルを読ませて登録します。
まずはルールとしての動作をみるため、特定ファイルに新規の行が追加されたことをTriggerとします。このルールはログ監視に応用できます。ログ監視として利用する場合にはCriteriaを設定し、特定セベリティに一致した場合に通知するようにしないと大変なことになります。
また、Lineへ通知する内容も決め打ちで書いていますので、実際に使う場合にはログファイルから読み取った内容を整形し、通知するような仕組みも入れると利便性が上がります。

```stackstorm:watch_logfile.yaml
---
   name: "watch_logfile"
   pack: "Kanno"
   description: "Watch logfile"
   enabled: true

   trigger:
      type: "linux.file_watch.line"
      parameters:
         file_path: "/var/log/testlog"

   action:
      ref: "core.http"
      parameters:
         body: '{"value1":"This is TEST!"}'
         headers: '{"content-type":"application/json"}'
         method: "POST"
         url: "https://maker.ifttt.com/trigger/event_notified/with/key/xxxxxxxxxxxxxxxxxxxxxx"
```

YAMLファイルが書き上がったら、ルールを登録します。
ルール登録に成功すると詳細が表示されます。

```stackstorm:ルールの作成
# st2 rule create /home/administrator/st2_rule/watch_logfile.yaml
+-------------+--------------------------------------------------------------+
| Property    | Value                                                        |
+-------------+--------------------------------------------------------------+
| id          | 5abc3798760efb05dd55681f                                     |
| name        | watch_logfile                                                |
| pack        | Kanno                                                        |
| description | Watch logfile                                                |
| action      | {                                                            |
|             |     "ref": "core.http",                                      |
|             |     "parameters": {                                          |
|             |         "body": "{"value1":"This is TEST!"}",                |
|             |         "headers": "{"content-type":"application/json"}",    |
|             |         "url": "https://maker.ifttt.com/trigger/event_notifi |
|             | ed/with/key/xxxxxxxxxxxxxxxxxxxxxx",                         |
|             |         "method": "POST"                                     |
|             |     }                                                        |
|             | }                                                            |
| criteria    |                                                              |
| enabled     | True                                                         |
| ref         | Kanno.watch_logfile                                          |
| tags        |                                                              |
| trigger     | {                                                            |
|             |     "type": "linux.file_watch.line",                         |
|             |     "ref": "linux.d6945bf7-a2cd-4635-8153-c160dc3ad265",     |
|             |     "parameters": {                                          |
|             |         "file_path": "/var/log/testlog"                      |
|             |     }                                                        |
|             | }                                                            |
| type        | {                                                            |
|             |     "ref": "standard",                                       |
|             |     "parameters": {}                                         |
|             | }                                                            |
| uid         | rule:Kanno:watch_logfile                                     |
+-------------+--------------------------------------------------------------+
```

実際にファイルへ書き込んでみると、Lineの方にも通知がきました。

![17-notify-by-st2-2.png](https://qiita-image-store.s3.amazonaws.com/0/181557/04ae25c4-6aa9-7c85-4065-5dc66b49b761.png)

念の為、履歴も確認すると正常に実行出来ているようです。

```stackstorm:ルールの動作履歴確認
# st2 execution list
+----------------------------+---------------+--------------+-------------------------+-------------------------------+-------------------------------+
| id                         | action.ref    | context.user | status                  | start_timestamp               | end_timestamp                 |
+----------------------------+---------------+--------------+-------------------------+-------------------------------+-------------------------------+
|   5abc38ed760efb041529fbc6 | core.http     | stanley      | succeeded (2s elapsed)  | Thu, 29 Mar 2018 00:53:00 UTC | Thu, 29 Mar 2018 00:53:02 UTC |
+----------------------------+---------------+--------------+-------------------------+-------------------------------+-------------------------------+
```

# まとめ/さいごに
StackStormからLineへ通知ができるようになりました。
Lineのような普段使いのアプリケーションへ通知できるようにすることで、通知があった際にもすぐに気付くことができるようになります。一方で、あまりやりすぎるとプライベートのときにも通知が大量に来て大変なことになります。
程々になるよう、本当に申告なものだけを通知するなど工夫も必要となります。そこはCriteriaなどでフィルタリングするようにしましょう。