AWS LambdaとSlack incoming webhookでサイトの生存確認チェッカーを作る

主要サービスにはいろいろ監視ソフト入れて、トラフィックの異常増大や、生存確認、リソースの利用状況なんかを可視化しているケースが多いと思います。ですが、例えば自社サイト(wordpressとかが多い)はじめ、管理コストをあまりかけられないサービスなりサイトって有りますよね。そんなサイトたちをAWS LambdaとSlackのincoming webhookを使って落ちているときに通知してくれるスクリプトを書いてみました。

## Slackのincoming webhookのURLを発行する

ワークスペースの設定　→　APP管理　→　カスタムインテグレーションへ移動
直リンクだと以下のページ
https://##yourdomain##.slack.com/apps/manage/custom-integrations

![Screenshot from 2020-05-22 22-53-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/7df5c62f-5da4-c7c6-a5d1-985003cec9dd.png)

Incoming Webhookの項目を選択　→　Slackに追加を選択　→　通知を送りたいSlackチャネルを選択　→　発行されたURLをコピーしておく
![Screenshot from 2020-05-22 22-54-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/7e213bf4-2b7f-0fc3-bda4-ea594fbe6c2e.png)

`https://hooks.slack.com/services/xxxxxxxx/xxxxxxx/xxxxxxxxxxxx`こんな感じのURLが発行されるはずである。これをメモって置きましょう。

## Lambdaのクローリングコードを作成

AWS Lambdaから関数の作成を行い、python3.7で以下のコードを書く

```python
from __future__ import print_function

import datetime
import urllib.request
import json


SITES = [
    'https://www.example.com/',
    'https://ここにチェックしたいサイトを入れてね'
    ]
DESCRIPTION = "サイトの生存確認用チェッカーからの連絡"
SLACK_WEBHOOK = 'ここにSlackのincoming webhookのURLをコピペ'
DIFF_JST_FROM_UTC = 9

def lambda_handler(event, context):
    for site in SITES:
        request = urllib.request.Request(site)
        now = datetime.datetime.now() + datetime.timedelta(hours=DIFF_JST_FROM_UTC)
        nowstr = now.strftime("%Y/%m/%d %H:%M:%S")
        try:
            with urllib.request.urlopen(request) as res:
                url = res.geturl()
                print(url)
                if not url == site :
                    raise ValueError("error!")
        except urllib.error.HTTPError as e:
            print('Check failed!')
            post_slack("<!here>\n{0}\n{1}\n※※※※※※※※\n{2}\nHTTP通信エラー\n※※※※※※※※".format(nowstr,site,DESCRIPTION))
            raise
        except urllib.error.URLError as e:
            print('Check failed!')
            post_slack("<!here>\n{0}\n{1}\n※※※※※※※※\n{2}\n URLエラー\n※※※※※※※※".format(nowstr,DESCRIPTION))
            raise
        except ValueError as e:
            print('Check failed!')
            post_slack("<!here>\n{0}\n※※※※※※※※\n{1}\n ルーティングエラー：リダイレクトされている\n※※※※※※※※".format(nowstr,DESCRIPTION))
            raise
        else:
            print('Check passed!')
            # post_slack("{0}\n{1} 成功".format(nowstr,DESCRIPTION))
            return
        finally:
            print('Check complete at {}'.format(str(datetime.datetime.now())))

def post_slack(message):

    send_data = {
        "username": "AWS Lambda",
        "text": message,
    }
    send_text = "payload=" + json.dumps(send_data)
    request = urllib.request.Request(
        SLACK_WEBHOOK, 
        data=send_text.encode("utf-8"), 
        method="POST"
    )
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")
```

## 上記のスクリプトをクローリングさせる

関数作成ページの上の方にあるトリガーの追加をクリック

![Screenshot from 2020-05-22 23-21-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/6a475515-3a00-9c7b-3669-65843f131042.png)

CloudWatch Events/EventBridgeを選択して、いい具合にルールを作る。
今回は15分に1回テスト通知させる。もし、時間間隔を変更したいときにはスケジュール式をよしなに書いてみてください。
書き方の公式ドキュメントは[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/services-cloudwatchevents-expressions.html)

![Screenshot from 2020-05-22 23-22-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/9c257f1f-59ce-714c-dc70-246825ed9e78.png)

## 実際に試してみる

SITESの配列のURLに存在しないページやドメインを記載してみてください。
incoming webhookを設定したSlackチャネルにエラーメッセージが飛んできたら成功です。
なお、このスクリプト、問題ないときには何も発生しません。