はじめに
aws上でCI環境を構築するため、aws CodeBuildを使って単体テストを実行し、テスト結果がエラーの場合メールを送信します。
※本記事は以下記事の続きとして書いていますが、aws CodeBuildを使ったことがあればなるべく理解できるように書いています
aws CodeBuildを使ってlambda(node.js)環境をテスト→デプロイする
CodeBuildでやりたい処理
CodeBuildで以下処理を行ないます。
- リポジトリからソースを取得
- 単体テストを実行する
- 単体テスト結果がエラーだった場合、amazon SNSを使ってメールを送信する
システムの全体図は以下のようになります。
作業の流れは以下になります。
- Amazon SNSの設定
- CodeBuild用のIAM Roleを作成
- CodeBuildのbuildspec.ymlを作成
- CodeBuildプロジェクトの実行
Amazon SNSの設定
公式サイトにある通り、Amazon SNSとはサブスクライブしているエンドポイントまたはクライアントへのメッセージの配信または送信を調整し、管理するウェブサービスです。例えば事前にサブスクライブ(登録)している人達に対して、一斉にメールを送信することができます。それをメールサーバとか建てることなしに、amazonのフルマネージドサービスとしてやってくれます。
今回はAmazon SNSを使って、単体テストエラー時にメールを送信するようにします。
イメージとしてはトピックを作成して、そのトピックに色々な人のメアドをサブスクライブ(登録)してもらいます。そうすると、そのトピックにメッセージを投稿するたびに、登録されたメアドに一斉送信されます。
ではSNSの設定手順について説明します。
Amazon SNSコンソールを開いて、
トピック→新しいトピックの作成を選択。
トピックが作成されました。ここに表示されているトピックのARNは、メッセージを投稿する時に必要になります。
作成したトピックにチェックを入れて、アクション→トピックへのサブスクリプションを選択。
プロトコルでEmailを選択、エンドポイントにテスト結果を送信したいメアドを入力。
サブスクリプションの項目を開くと、PendingConfirmationとなっているのが分かる。これはメールの承認をまだ行なっていないためなので、受信しているはずの承認メールを開いて「Confirm subscription」をクリックする。
さきほどPendingConfirmationとなっていた所が、サブスクリプションARNが設定されていてサブスクライブできたことが確認できます。
以上で、Amazon SNS側の設定は終わりです。
CodeBuild用のIAM Roleを作成
次にCodeBuild用のIAM Roleを作成します。これはCodeBuildで単体テストを実行し、CodeBuildからAmazon SNSのトピックに対してアクセスできるようにアクセス権を付与するためです。
IAMコンソールを開きます。
新規に(あるいは既にCodeBuild用のRoleを作成済みの場合はその)Roleを用意し、そのRoleに権限を追加します。今回は既にあるRoleForCodeBuildというRoleに新たに権限を追加するためポリシーを作成します。
サービスはSNS、アクションはPublish、リソースはすべてのリソースを選択します。
ポリシーの名前はSnsPublishPolicyとでもしておきます。
以上で、SNSにpublishできるポシリーを追加したCodeBuild用のIAM Roleが作成できました。
これでCodeBuildからAmazon SNSトピックに対して投稿(publish)するための準備が整いました。
※コンソールでのIAMロール(ポリシーの追加)の作成はこのような手順でできます。CodeBuildを使って色々なサービスと新たに連携したり、デプロイするたびに同様に必要なポリシーを追加していくことになります。
CodeBuildのbuildspec.ymlを作成
始めに簡単な例で説明し、次により実用的な例を示します。
CodeBuild実行時にテスト結果がエラーならメールを送信する
CodeBuildのプロジェクト作成の流れは以下記事を参照してください。
aws CodeBuildを使ってlambda(node.js)環境をテスト→デプロイする
CodeBuildのbuildspec.ymlは以下の通りになります。
version: 0.2
phases:
install:
commands:
- npm install
pre_build:
commands:
- sh prj_test.sh
prj_test.shは、テストを実行し、その結果に応じてamazon SNSにpublishするシェルスクリプトです。
npm test
if [ $? = 0 ]; then
echo "npm test ok."
else
echo "npm test failed. sending email."
aws sns publish --topic-arn arn:aws:sns:ap-northeast-1:1234567890:helloworld_topic --subject "単体テスト結果エラー" --message "ただちにエラーを修正するか、エラー発生前のコミットに戻してください"
exit 1
fi
テストが正常に終われば、"npm test ok."とechoして正常終了。テスト結果がエラーだった場合、aws cliを使ってamazon snsにpublishしています。この時に上記amazon SNSコンソールで作成したトピックのtopic ARNを指定します。
aws cli snsのリファレンスは以下参照
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-sqs-queue-sns-topic.html
以上でとりあえずテストエラー時にメールが飛ぶようにすることができました。しかし、まだこれではどの(誰の)コミットでエラーになったのか分かりません。またCodeBuld単体だと手動で実行する必要があり、CIを実現するためにはリポジトリへコミット(push)される度に毎回必ず自動的にテストが実行されてほしいです。
では、どうやってやるか?
以下の方法で実現します。
- pushされる度にCodeBuld実行 → CodePipelineの使用
- メール内容にコミットに関する情報を追加 → CodeCommitにaws cliでアクセスして情報を取得
CodePipelineとCodeBuildを組み合わせ、コミット時にテストを自動実行し、エラーになったコミット情報をメールで送信する
まずはCodePipelineを設定します。
CodePipelineの設定
CodePipelineコンソールを開き、パイプラインを作成。
パイプライン名を入力して、あとはデフォルトの設定のまま次へ。
ソースプロバイダはCodeCommitを選択し、使用しているリポジトリ名とブランチを指定。変更検出オプションはCloudWatch Events。このように設定することで、指定したブランチに変更が検出されると本パイプラインが発動することになる。変更の検出は当然プルリクエストを承認してマージした場合も該当する。
そのため、例えば運用上1つ1つのコミットでcodepipelineを走らせたくない場合は、ここで指定したブランチとは異なるブランチで作業をして、codepipelineを走らせたくなったら、指定したブランチにマージするといったやり方もできる。
ビルドステージはCodeBuildを選択し、CodeBuildで作成したプロジェクトを選択する。
デプロイステージはスキップする。なおデプロイステージ自体をスキップしたとしても、デプロイしたい場合はCodeBuildのプロジェクト内でaws cli経由でcloudformationを使ってデプロイ可能。
以上でCodePipelineは作成できました。これでCodeCommitに変更をプッシュする度に、自動的にCodeBuildのビルドが走ります。
テストエラー時のコミット情報を取得する
次に、テストがエラーになった際のコミット情報を取得します。
CodeBuildで行ないます。CodeBuildでは環境変数が設定されていて、そこからコミットIDを取得できます。CODEBUILD_RESOLVED_SOURCE_VERSIONという変数です。
CodeBuildの環境変数
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-env-vars.html
$CODEBUILD_RESOLVED_SOURCE_VERSIONを参照すればコミットIDが分かります。コミットIDが分かればaws cliのaws codecommitコマンドを使って指定したコミットIDのコミット情報を取得することができます。またコミットIDが分かれば、codecommitの当該コミットのURLも一意に生成することができます。
aws cli codecommitで可能な操作は以下参照
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-view-commit-details.html#how-to-view-commit-details-cli-commit
上記を踏まえ、以下の手順で実施します。
- CodeBuildがCodeCommitからコミット情報を取得できるようにCodeBuild用のRoleにアクセス権を付与
- CodeBuildが実行するスクリプトにaws cli(aws codecommit)でコミットIDを指定してコミット情報を引っ張ってくる記述を追加
- 取得したコミット情報から必要な情報をjqコマンドで抽出してメール本文に含める
RoleForCodeBuildに以下ポリシーを追加します。
AWSCodeCommitReadOnly
続いて上述したスクリプトファイルを以下のように変更します。
npm test
if [ $? = 0 ]; then
echo "npm test ok."
else
echo "npm test failed. sending email."
echo $CODEBUILD_RESOLVED_SOURCE_VERSION
RES=$(aws codecommit get-commit --repository-name helloworld-repo --commit-id $CODEBUILD_RESOLVED_SOURCE_VERSION)
echo $RES
dpkg -l jq
if [ $? = 1 ]; then
apt-get update
apt-get install -y jq
fi
COMMITTER_NAME=$(echo $RES | jq '.commit.committer.name')
COMMITTER_EMAIL=$(echo $RES | jq '.commit.committer.email')
COMMITTER_MESSAGE=$(echo $RES | jq '.commit.message')
aws sns publish --topic-arn arn:aws:sns:ap-northeast-1:1234567890:helloworld_topic --subject "単体テスト結果エラー:${COMMITTER_NAME}, ${COMMITTER_MESSAGE}" --message "以下のコミットでエラーが発生しています。修正お願いします。
コミットID:${CODEBUILD_RESOLVED_SOURCE_VERSION}
リンク:https://ap-northeast-1.console.aws.amazon.com/codesuite/codecommit/repositories/helloworld-repo/commit/${CODEBUILD_RESOLVED_SOURCE_VERSION}?region=ap-northeast-1
コミットメッセージ:${COMMITTER_MESSAGE}
コミット者:${COMMITTER_NAME}
連絡先:${COMMITTER_EMAIL}"
exit 1
fi
aws cliのcodecommit get-commitで取得されるコミット情報はjson形式で返ってきます。jsonを処理するためにjqコマンドを使うことにします。
デフォルトのCodeBuildのdocker imageだとjqコマンドが入っていなかったので、jqコマンドをインストールしています(2018/11/28時点)。ただしこれだとビルドの度にinstallが走ってしまうので、自分でデフォルトのdocker imageにjqコマンドをインストールしたカスタムdocker imageを作成して使用するか、jqコマンドを使わずに別のコマンドでjsonを処理する方がよいと思います。
codecommit get-commitで返ってくる値の仕様詳細については以下参照。
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-view-commit-details.html#how-to-view-commit-details-cli-commit
今回はコミットした人の名前、メアド、コミットメッセージをjqコマンドで抽出しています。
抽出した情報をsns publishコマンド内のsubjectとmessageに埋め込めば、当該コミットに関する情報を含んだメールを送信することができます。当該コミットへのリンクも含めておけば、エラーとなったコミットをブラウザ上ですぐに確認できます。
送信されるメール本文は以下のようになります。
以下のコミットでエラーが発生しています。修正お願いします。
コミットID:b8642a5d23avgb5875d446eb31cf94341f2621a0
リンク:https://ap-northeast-1.console.aws.amazon.com/codesuite/codecommit/repositories/helloworld-repo/commit/b8642a5d23da5b5875d446eb31cf94341f2621a0?region=ap-northeast-1
コミットメッセージ:"fixed bug"
コミット者:"Tarou"
連絡先:"user@example.com"
以上で完了です。
まとめ
コミットの度に自動的に単体テストが実行され、mochaの実行結果にエラーがあれば、当該コミット情報に関するメールが飛ぶ、という仕組みを構築する手段について記述しました。
awsで開発作業を自動化するのまとめ記事
本記事はawsで開発作業を自動化するシリーズの1つです。その他の記事については以下を参照ください。
aws環境でnode.js、lambda、CodeCommit、CodeBuild、CloudFormation、CodePipelineを使って開発作業を自動化する