早くエンジニアになりたい

masatany's memorandum

SNSトピックへのメッセージをGoランタイムのLambdaでSlack通知する

前置き

AWSのリソースに関するイベントをSlackに通知したい欲があり 少し前にLamdaのGo言語サポートが実装されたことを思い出したので Goランタイムで動くLambda関数を作成しました。

実装コード

package main

import (
    "bytes"
    "context"
    "fmt"
    "net/http"
    "os"

    "github.com/antonholmquist/jason"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
)

type Slack struct {
    WebhookURL string
    Channel    string
    Name       string
    Emoji      string
    Message    string
}

func send(s Slack) {
    jsonStr := `{"channel":"` + s.Channel +
        `","username":"` + s.Name +
        `","icon_emoji":"` + s.Emoji +
        `","text":"` + s.Message + `"}`

    req, err := http.NewRequest(
        "POST",
        s.WebhookURL,
        bytes.NewBuffer([]byte(jsonStr)),
    )

    if err != nil {
        fmt.Print(err)
    }

    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Print(err)
    }

    fmt.Print(resp)
    defer resp.Body.Close()
}

func createMessage(message string) string {
    json, err := jason.NewObjectFromBytes([]byte(message))
    if err != nil {
        panic(err)
    }

    text := "<!channel>\n```\n"
    for k, v := range json.Map() {
        s, sErr := v.String()
        if sErr == nil {
            text += fmt.Sprintf("%s\t:%s\n", k, s)
        } else {
            text += fmt.Sprintf("%s\t:%s\n", k, sErr)
        }
    }
    text += "```"

    return text
}

func slackNotice(ctx context.Context, snsEvent events.SNSEvent) {
    for _, record := range snsEvent.Records {
        snsRecord := record.SNS
        var s = Slack{os.Getenv("WEBHOOK_URL"),
            os.Getenv("SLACK_CHANNEL"),
            os.Getenv("SLACK_NAME"),
            os.Getenv("SLACK_EMOJI"),
            createMessage(snsRecord.Message)}

        send(s)
    }
}

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

Slackに通知するためのPost処理の部分は、

crossbridge-lab.hatenablog.com

こちらの記事を参考にさせていただきました。

SNSのイベント情報を取得する

今回の本命処理は、以下の部分です。 (本命と言うほどでもない)

func slackNotice(ctx context.Context, snsEvent events.SNSEvent) {
    for _, record := range snsEvent.Records {
        snsRecord := record.SNS
        var s = Slack{os.Getenv("WEBHOOK_URL"),
            os.Getenv("SLACK_CHANNEL"),
            os.Getenv("SLACK_NAME"),
            os.Getenv("SLACK_EMOJI"),
            createMessage(snsRecord.Message)}

        send(s)
    }
}

  今回は、SNSトピックに色々なイベントを集約して同一のSlackチャンネルに通知する方針です。 そのため、snsEvent events.SNSEventでトリガーとなったSNSのイベント情報を取得しています。

また、Slack通知関係の定数(WebhookURLなど)は、Lambda関数の環境変数os.Getenvで取ってくるようにしているため、別のアカウントでも流用できる形となっています。

まとめ

Go言語は初学者中の初学者なのですが、割と直感的に書けていい感じの言語だと思いました。 また、フォーマッティングまで言語がサポートしてくれるのはとても嬉しいですね。

もっと複雑な処理もサーバーレスに処理できるようにLambdaGoの知見を貯めて行きたいと思います。