LoginSignup
1
1

More than 3 years have passed since last update.

CodeBuildのSlack通知をTerraformでサクッと設定する

Last updated at Posted at 2019-05-26

最近CodeBuildを利用し始めたのですが、CircleCI等のようにはサクッとSlack通知ができないのを少しもどかしく感じました。ビルドの状態がSlack上で楽に把握できないと、コンソールを見に行ってしまったり思考リソースを奪われてしまいますよね。

そこでよし通知をしようと思っても、まさにこれというTerraform Moduleがなかったのでmoduleを作ってみました。

en30/codebuild-to-slack/aws | Terraform Module Registry

これを利用するとCodeBuild上での以下のイベントを簡単にSlack通知できます。

  • IN_PROGRESS: 開始
  • SUCCEEDED: 成功
  • FAILED: 失敗
  • FAULT: AWS側が原因での失敗?
  • TIMED_OUT: タイムアウト
  • STOPPED: 中止

実際の通知例
通知例

使い方

main.tf
variable "encrypted_slack_webhook_url" {}

resource "aws_kms_key" "slack_webhook_url" {
  description = "Key for Slack Webhook URL"
}

module "codebuild_notification" {
  source = "en30/codebuild-to-slack/aws"

  version                     = "0.0.1"
  encrypted_slack_webhook_url = "${var.encrypted_slack_webhook_url}"
  slack_channel               = "#app"
  kms_key_arn                 = "${aws_kms_key.slack_webhook_url.arn}"
}

encrypted_slack_webhook_urlは以下のようにAWS CLIを使うことで得ることができます。

$ aws kms encrypt --key-id $AWS_KMS_KEY_ID --plaintext $SLACK_WEBHOOK_URL --query CiphertextBlob --output text

$AWS_KMS_KEY_IDはmoduleへkms_key_arnとして渡しているkeyのid、$SLACK_WEBHOOK_URLはSlackのIncoming WebhookのURLです。

上の例のようにキーもTerraformで作ろうとすると

  1. aws_kms_keyの作成(terraofmr apply①)
  2. キーを利用してwebhook urlを暗号化
  3. moduleを利用した通知設置(terraofrm apply②)

terraform applyで一発でいけないのが気持ち悪いところですが、よろしければ使ってみてください!

中身の簡単な説明

やっていることとしては

  • CodeBuildのビルド状態が変化に関するCloudWatch EventでLambdaを起動
  • Lambdaでイベント情報を整形してSlack通知

です。LambdaにRuby Runtimeも入ったことですし、僕はRubyが好きなのでLambdaはRubyで書きました。

それほど面白いところがあるわけではないですが、Lambdaのデプロイをシンプルに済ますために、標準ライブラリ、Lambdaの環境に元々入っているaws-sdkだけで済ますようにしています。

notify_slack.rb
require "uri"
require "net/http"
require "json"
require "base64"
require "aws-sdk"

COLORS = {
  "SUCCEEDED" => "good",
  "FAILED" => "danger",
  "FAULT" => "danger",
  "TIMED_OUT" => "danger",
  "STOPPED" => "warning",
}.freeze

def decrypt(encrypted_url)
  client = Aws::KMS::Client.new
  client.decrypt(ciphertext_blob: Base64.decode64(encrypted_url)).plaintext
end

def build_url(region, project, slug)
  region, project, slug = [region, project, slug].map(&URI.method(:encode_www_form_component))
  "https://#{region}.console.aws.amazon.com/codesuite/codebuild/projects/#{project}/build/#{slug}/log"
end

def format(event) # rubocop:disable Metrics/MethodLength
  project = event["detail"]["project-name"]
  status = event["detail"]["build-status"]
  slug = event["detail"]["build-id"].split("/").last

  {
    attachments: [
      {
        color: COLORS[status],
        title: slug,
        title_link: build_url(event["region"], project, slug),
        fallback: status,
        fields: [
          {
            title: "Status",
            value: status,
            short: true,
          },
          {
            title: "Initiator",
            value: event["detail"]["additional-information"]["initiator"],
            short: true,
          },
        ],
      },
    ],
  }
end

def notify_slack(slack_url, payload)
  Net::HTTP.post_form(URI.parse(slack_url), payload: JSON.dump(payload))
end

def lambda_handler(event:, context:)
  slack_url = decrypt(ENV["ENCRYPTED_SLACK_WEBHOOK_URL"])

  payload = {
    channel: ENV["SLACK_CHANNEL"],
    username: ENV["SLACK_USERNAME"],
    icon_emoji: ENV["SLACK_EMOJI"],
  }.merge(format(event))

  notify_slack(slack_url, payload)
end

以上です。

AWSもTerraformも使い始めて日が浅いので、何か少しでも気になる部分があれば気軽にコメントやIssue作成をお願いします。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1