CodeBuildの開始と終了をSlackに通知する

2018/01/03 | 所要時間 約4分

開発合宿でhugo + github + CodeBuildを使ってブログ環境を構築したわけですが、 CodeBuildで処理が本当に始まっているのか、ちゃんと処理が完了したのかわからないとちょっと不安です。

そこでCodeBuildの処理の開始と終了を個人Slackに通知するようにしてみました。

最終構成はこんな感じです

最終構成

SlackでIncoming WebHookのURLを取得する

まずSlackの設定から”Add an app”でIncoming WebHooksを追加します。 こいつは特定のURLを叩くと任意の内容の通知をしてくれる便利なやつです。

webhook追加

ここでは#awsチャンネルに通知されるように設定しています。

webhookのURLを取得

設定したらwebhook用のURLが取得できるのでこれを後ほど使用します。

Lambda関数を作成する

次にAWS Lambda関数を作成します。

実はSlackに通知するテンプレートが用意されているのでこれを使用します。
nodejsでもいいのですが今回はpython3のcloudwatch-alarm-to-slack-python3テンプレートを選択します。

lambdaのテンプレートを選択

基本情報は適当に入力します。 その下にSNSの設定がありますが今回は使用しないので削除してOKです。

lambdaの基本情報入力

次に環境変数を設定するのですが、その前に暗号化の設定をします。 暗号化の設定をすると環境変数に設定する値も暗号化されるので悪用されるのを防げます。

伝送中の暗号化のためのヘルパーの有効化にチェックを入れてください。 キーがない場合以下のようにエラーがでるのでリンクのキーを作成からKMSキーを作成して設定してください。

lambdaの暗号化にチェック

暗号化キーを設定できたら、環境変数を設定します。

  • slackChannelに通知するチャンネル名
  • kmsEncryptedHookUrlにIncoming WebHookのURL (https:// の部分は除いてください)

を設定して、kmsEncryptedHookUrlを暗号化ボタンを押して暗号化してください。

hookURLの暗号化

暗号化したらこんな感じになります。

暗号化された状態

できたら関数を作成して、一旦CloudWatchの設定に移ります。

CouldWatchのイベントルールを作成する

CloudWatchを開いて、イベント→ルールの作成

イベントソースは

  1. サービス名: CodeBuild を選択
  2. イベントタイプ: CodeBuild Build State Change を選択
  3. 通知したいステートを選択

ターゲットは

  1. Lambda関数を選択
  2. 先程作成した関数名を選択

できたらこんな感じになります。この時、下に表示されるサンプルイベントのjsonをコピーしておいてください。

CloudWatchイベントルールの作成

Lambdaコードを実装する

CloudWatchが設定できたら、先程作成したLambda関数に戻ります。 こんな感じでCloudWatch Eventsが設定されていたらOKです。

CloudWatchトリガー

肝心のコードは、テンプレートをほんのちょっと変えるだけでOKです。 CodeBuildのプロジェクト名と状態をSlackに通知するには以下のようにすれば大丈夫です。

import boto3
import json
import logging
import os

from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError

ENCRYPTED_HOOK_URL = os.environ['kmsEncryptedHookUrl']
SLACK_CHANNEL = os.environ['slackChannel']
HOOK_URL = "https://" + boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_HOOK_URL))['Plaintext'].decode('utf-8')

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    logger.info("Event: " + str(event))

    project = event["detail"]["project-name"]
    state = event["detail"]["build-status"]

    slack_message = {
        'channel': SLACK_CHANNEL,
        'text': "CodeBuild: %s - %s" % (project, state)
    }

    req = Request(HOOK_URL, json.dumps(slack_message).encode('utf-8'))
    try:
        response = urlopen(req)
        response.read()
        logger.info("Message posted to %s", slack_message['channel'])
    except HTTPError as e:
        logger.error("Request failed: %d %s", e.code, e.reason)
    except URLError as e:
        logger.error("Server connection failed: %s", e.reason)

コードが書けたらテストしてみます。メニューからテストが実行できるのですが、そのときに先程コピーしておいたサンプルイベントのjsonを貼り付けます。

Lambdaテスト

こんな感じでテスト用にjsonを貼り付けて、実際にSlackに通知されたらOKです 🆗

実際にブログを更新して、githubにpushすると…

通知結果

できました 🎉

ごちゃごちゃと設定しないといけないように見えますが設定してみれば意外と簡単でした。 他のCIにも使えそうですね。

2018/01/03

プロフィールアイコン

ton

何でもやりたいエンジニア

趣味でFlash作って遊んでいたらプログラマーになってしまいました。

仕事ではSNSの運用したり、ゲーム作ったり、webサービス作ったり、アプリ作ったり、色々してます。