エンジニャーリング

技術ときどきネコ

codepipelineの承認をslack上で行う(その2)

その1ではSlackアプリのベースを作った。その2ではそのtokenを使ってLambdaとそれを呼び出すSNSを作っていく。

2. SNSとpauseのLambdaを作る

今回のLambdaはpythonで書いた。 こんな感じ

import logging
import json
import os
import boto3
import traceback

from slack import WebClient
from slack.errors import SlackApiError


def lambda_handler(event, context):
    token = os.environ["SLACK_API_TOKEN"]
    channel_id = os.environ["channel_id"]

    client = WebClient(token=token)

    message = event["Records"][0]["Sns"]["Message"]
    data = json.loads(message)
    token = data["approval"]["token"]
    codepipeline_name = data["approval"]["pipelineName"]

    if codepipeline_name == "test-codepipeline-dev":
        msg_text = "``` 承認してもよろしいでしょうか?```"

    attachments_json = [
        {
            "fallback": "Upgrade your Slack client to use messages like these.",
            "color": "#258ab5",
            "attachment_type": "default",
            "callback_id": "the_greatest_war",
            "actions": [
                {
                    "name": "ok",
                    "text": "承認",
                    "value": token + ',' + codepipeline_name,
                    "style": "primary",
                    "type": "button",
                    "confirm": {
                        "title": "承認しますか?",
                        "text": "本当によろしいですか?",
                        "ok_text": "OK",
                        "dismiss_text": "Cancel"
                    }
                },
                {
                    "name": "cancel",
                    "text": "キャンセル",
                    "style": "danger",
                    "value": token + ',' + codepipeline_name,
                    "type": "button"
                }
            ]
        }
    ]

    try:
        response = client.chat_postMessage(
            channel=channel_id,
            text=msg_text,
            attachments=attachments_json
        )

        assert response["ok"]
    except Exception:
        print(traceback.format_exc())

SNSとLambdaのAWSへの作成はterraformにて実施

Lambdaを設置するところの例 Lambdaの環境変数にSlackアプリのtokenやチャンネルIDをセットする

# Function
resource "aws_lambda_function" "handler" {
  function_name = "lambda-handler"

  handler          = "lambda_handler.lambda_handler"
  filename         = data.archive_file.function_zip.output_path
  runtime          = "python3.8"
  role             = aws_iam_role.lambda_iam_role.arn
  source_code_hash = data.archive_file.function_zip.output_base64sha256
  layers           = ["${aws_lambda_layer_version.lambda_layer.arn}"]
  timeout          = 30
  memory_size      = 512

  environment {
    variables = {
      ENVIRONMENT = "dev"
      SLACK_API_TOKEN = [OAuth & Permissions の token]
      VERIFICATION_TOKEN = [verification の token]
      channel_id = [通知する slack の チャンネルID]
    }
  }
}

SNSトピックの作成とLambdaと繋ぐところの例

# SNS
resource "aws_sns_topic" "user_approval" {
  name = "user_approval"
}

resource "aws_sns_topic_subscription" "user_approval_lambda_target" {
  topic_arn = aws_sns_topic.user_approval.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.handler.arn
}

resource "aws_lambda_permission" "default" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.handler.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.user_approval.arn
}

実行するとこのように設置できる f:id:taiyakikuroann:20211019234909p:plain

あとはこれをCodePipeline側で呼び出すだけ。

3. CodePipelineのApprovalの設定にSNSをセットする

f:id:taiyakikuroann:20211020085128p:plain

これでslackへ通知が届くようになる。

(その3へ続く)