My Note

自己理解のためのブログ

CodeBuildの実行結果をLambda(Go)でSlackに通知する

目的

AWS CodeBuildの実行結果をLambdaを使ってSlackに通知するようにしました。

前回のブログで、CodeBuildでMackerelの監視設定の最新を取得し、GitHubにpushする処理を行いました。

yhidetoshi.hatenablog.com

今回はそのCodeBuildの処理結果をSlackに通知するように CloudWatch Eventの設定 と Lambda Functionの実装について〜。

アーキテクチャについて

f:id:yhidetoshi:20190825074447p:plain

  1. CodeBuildで処理が実行されるとCloudWatchにログが出力される
  2. CloudWatch Eventルールに定義したログが出力されたらLambda関数を起動する
  3. Lambda関数でSlackにCodeBuildのプロジェクト名と実行ステータスを通知する

実装について

Lambda関数とCloudWatchEventの作成

今回はServerlessFrameworkでリソース作成・デプロイを行いました。

serverless.com

■ serverless.yml

service: slack-notice
frameworkVersion: ">=1.48.0"

provider:
  name: aws
  runtime: go1.x
  stage: dev
  region: ap-northeast-1


functions:
  codebuild:
    handler: main
    role: codebuildSlack
    timeout: 30
    description: codebuild status slack
    memorySize: 128
    environment:
      SLACKURL: ${opt:slackurl}
    events:
      - cloudwatchEvent:
          event:
            source:
              - 'aws.codebuild'
            detail-type:
              - 'CodeBuild Build State Change'
            detail:
              build-status:
                - FAILED
                - STOPPED
                - SUCCEEDED
                - IN_PROGRESS


resources:
  Resources:
    codebuildSlack:
      Type: AWS::IAM::Role
      Properties:
        RoleName: codebuildSlack
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: sts:AssumeRole
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/ReadOnlyAccess
        Policies:
          - PolicyName: codebuildSlackLogs
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action:
                    - "logs:CreateLogGroup"
                    - "logs:CreateLogStream"
                    - "logs:PutLogEvents"
                  Resource: "*"

Lambda関数の実装

CloudwatchのログからCodeBuildのプロジェクト名と実行ステータスを取得してSlackに通知する処理を実装。

GoでSlackに通知する方法は、以前のブログに記載しています。

yhidetoshi.hatenablog.com

  • 実行環境について

    • Lambdaのランタイムは go1.x
    • Goのバージョンは: 1.12.4
  • CodeBuildの情報 ( プロジェクト名とステータス ) を取得するために構造体を確認

github.com

■ main.go

package main

import (
    "encoding/json"
    "fmt"
    "os"

    "github.com/ashwanthkumar/slack-go-webhook"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
)

const version = "0.0.1"

var (
    // CHANNEL slack channel name
    CHANNEL  = "dev"

    // USERNAME slack username
    USERNAME = "CodeBuild"

    // SLACKURL slack webhook
    SLACKURL = os.Getenv("SLACKURL")
)

// CodeBuildPhaseStatus set status
type CodeBuildPhaseStatus string

// CodeBuildEventDetail set event detail
type CodeBuildEventDetail struct {
    BuildStatus CodeBuildPhaseStatus `json:"build-status"`
    ProjectName string               `json:"project-name"`
}

func main() {
    lambda.Start(Handler)
}

// Handler Lambda
func Handler(event events.CloudWatchEvent) {
    resInfo := &CodeBuildEventDetail{}

    err := json.Unmarshal(event.Detail, &resInfo)
    if err != nil {
        fmt.Println(err)
    }

    PostSlack(resInfo.ProjectName, string(resInfo.BuildStatus))
}

func checkStatus(status string) string {
    var color string

    if status == "SUCCEEDED" {
        color = "#00ff00"
    } else if status == "IN_PROGRESS" {
        color = "#0000ff"
    } else {
        color = "#dc143c"
    }
    return color
}

// PostSlack post slack result
func PostSlack(pjtName string, status string) {

    statusColor := checkStatus(status)

    field1 := slack.Field{Title: "ProjectName", Value: pjtName}
    field2 := slack.Field{Title: "BuildStatus", Value: status}

    attachment := slack.Attachment{}
    attachment.AddField(field1).AddField(field2)
    color := statusColor
    attachment.Color = &color
    payload := slack.Payload{
        Username:    USERNAME,
        Channel:     CHANNEL,
        Attachments: []slack.Attachment{attachment},
    }
    err := slack.Send(SLACKURL, "", payload)
    if err != nil {
        os.Exit(1)
    }
}

Slackの通知結果

f:id:yhidetoshi:20190825093423p:plain

デプロイ方法

ソースコードはこちら github.com

■ デプロイ方法

$ make build
$ sls deploy --aws-profile <PROFILE> --slackurl <SLACKURL>

MakefileGitHubにあげています。

<SLACKURL> はSlackに通知したいチャンネルのwebhookをセットします。 今回はこの設定方法は省略しています。

まとめ

今回は、CodeBuildの実行結果をSlack通知するために、CloudwatchEventとLambda(Go)を利用して実装しました。 デプロイについてはServerlessFrameworkを利用しています。 イベント駆動でLambdaでごにょっと処理ができると便利なことが多いと思うので他の場合もLambda(Go)で書いていきたいと思います。