読者です 読者をやめる 読者になる 読者になる

tech.guitarrapc.cóm

C#, PowerShell, Unity, Cloud, Serverless Technical Update and Features

.NET Core on Lambda で Github 連携をSlack に飛ばしてみよう

AWS AWSLambda C# Serverless .NETCore

私の中で Serverless ななんとかネタで鉄板なのが、Github の PRやIssue などの通知連携です。日々使っているものなのでついつい。

もちろん過去にも Lambda + Node.js や Azure Functions で作っています。

tech.guitarrapc.com

では .NET Core でもやってみましょう。

目次

連携の流れ

Azure Functions では、Azure Functions の Secret と URL を直接 Github Webhook に入力して連携しました。ただ入力するだけ、簡単ですね。

f:id:guitarrapc_tech:20161212030030p:plain

AWS Lambda の場合は、Webhook を API Gateway で受けるようなことはせず、Amazon SNS を使って連携することが定番になっているように思います。Amazon SNS にするとAPI Gatewayと違ってレスポンスの受け口を作ったり管理する必要がほぼないのである意味ではとても楽です。*1

f:id:guitarrapc_tech:20161212025753p:plain

ということで今回もこの構成で行ってみましょう。Amazon SNS ではなく API Gateway で作っていたこともあったのですが余り楽しくないので推奨しません。

参考

Node.js で行われていますが、構成は同じです。

qiita.com

下準備

いきなりコードに行きたいところですが、まずは下準備からです。

Slack で Incoming Webhook を作成

Lambda の受け口となる Webhookの口を Slack に作成します。通知先の Channel を選んで適当にどうぞ。

slack.com

f:id:guitarrapc_tech:20161212030659p:plain

これで Lambda が送る先の Incoming Webhook URL が確定しました。URL は後ほどLambda の環境変数に仕込んでおくことになります。*2

SNS の Topic 作成

次にGithub が投げる先となる SNS の受け口 Topic を作成しておきます。作成する AWS Lambda と同一Region で作っておくといいでしょう。今回は ap-northeast-1 で作ります。

SNS から Create Topic を選んで

f:id:guitarrapc_tech:20161212031401p:plain

他の Topic と区別が付くようにつけておきましょう。

f:id:guitarrapc_tech:20161212031427p:plain

これで Topic を一意に示す Topic ARN が定まります。Github で入力するので把握しておきましょう。

f:id:guitarrapc_tech:20161212031718p:plain

今回は仮に arn:aws:sns:ap-northeast-1:123456789012:githublambdawebhook だったとします。

Github から SNS に投げる限定権限の IAM 作成

Github の Application Integrations を使った Amazon SNS では IAM の access key / secret key を直接入れることになります。

f:id:guitarrapc_tech:20161212031857p:plain

ということで指示に従って SNS を投げることができるsns:Publish権限だけの IAM ユーザーを作成しておきます。

ポリシーの Resource には、先ほどの Sns ARN arn:aws:sns:ap-northeast-1:123456789012:githublambdawebhook を指定します。

f:id:guitarrapc_tech:20161212032019p:plain

あとはIAM User作成時、あるいは後ほどでも Access Key / Secret Key を取得します。Secret Key は作成時の画面でしか確認できないのでお気をつけて。

f:id:guitarrapc_tech:20161212032358p:plain

仮に、Access Key を accesskey12345、Secret Key を secretkey12345 と表現します。

Github に Amazon SNS との連携を組む

では、Github の連携させたいリポジトリの Settings 画面に行きましょう。

メニューから Integrations & services を選択します。

f:id:guitarrapc_tech:20161212032628p:plain

サービス一覧から Amazon SNS を選びます。

f:id:guitarrapc_tech:20161212032759p:plain

あとは、AWS で作成した SNS Topic の情報、SNS送信専用 IAM Userの Access Key、Secret Key を入れます。

項目 入力する内容 入力値の例
Aws Key SNS 専用 IAM User の Access Key accesskey12345
Sns topic 作成した Sns の TOPIC Arn arn:aws:sns:ap-northeast-1:123456789012:githublambdawebhook
Sns region 作成した Sns の Region。SNS Topicに書いてありますが入れます ap-northeast-1
Aws secret SNS 専用 IAM User の Secret Key secretkey12345

f:id:guitarrapc_tech:20161212032921p:plain

Integrations の Event を指定する

Github の Webhook を使わない Integrations & services で連携する場合の最大のめんどくさいポイントはこれです。

Github API の hook.json にあるとおり、Amazon SNS の デフォルト Event は Push のみです。

この変更は Web request でしかできないのでしかたいので cURL でやります。*3

対象とするイベントは、Webhooks で適当に決めます。

f:id:guitarrapc_tech:20161212033709p:plain

今回はIssue 処理時Issue コメント時Pull Request 処理時Pull Request レビューサブミット時Pull Request レビューコメント時 とします。

gist.github.com

API経由で変更をかける際に利用する Application Token は、Github ユーザー プロファイルから作成できます。admin:repo_hookadmin:org_hook を有効にしておけばいいでしょう。

f:id:guitarrapc_tech:20161212034045p:plain

qiita.com

Webhook の ID は、URLに表示されています。

f:id:guitarrapc_tech:20161212044547p:plain

events が期待通りに設定されましたか? cURL の設定時のレスポンスで確認できます。

f:id:guitarrapc_tech:20161212034425p:plain

残りは Amazon SNS と Lambda のつなぎこみですが、Visual Studioから Lambda コード反映時にまとめて設定できるので後述します。

お疲れさまでした、長い下準備もおしまいです!

C# で Github Webhook を受ける

Azure Functions で書いていたコードを使って書いてみましょう。

サンプルJSON

今回サンプルで利用した、SNS から送ってくるJSON は次のフォーマットです。これは Issue のサンプルなので、コードもIssue を想定したものとします。

gist.github.com

C# コード例

Issue が書かれたらSlack に飛ばすサンプルです。ほぼ Azure Functions のコードと違いはありません。

違いは2点のみです。

  • フィールドに AWS Lambdaの環境変数から SlackWebhookUrl というキーを探して URL をstringとして取得するようにします。パスワードとかそういうのは Lambda の環境変数で KMS 使って暗号化がいいですね。
  • SNS Response のデシリアライズ処理が入っています。

当たり前の注意点だけ

  • X-Github-Event がプロパティ名に利用できないので JSONPropertyとして指定しておきます。
  • ただし、github のイベントJSONは issue だったり PR だったりでフォーマットが変わるので、そこは AzureFunctiosn 同様に dynamic で受けておきます。

gist.github.com

今回は Issue に限定しましたが、適当に他のイベント対応も switch に達せばいいでしょう。*4

xUnit テスト

ごく単純な実行テストです。様々なイベントに応じた JSON パターンをここでテストするといいでしょう。

gist.github.com

ローカル実行

ローカル実行する場合は、buildOptions に emitEntryPointを true と設定してProgram.cs を適当に書きましょう。

  "buildOptions": {
    "emitEntryPoint": true
  },

gist.github.com

これで普通のコンソールアプリケーションとして検証できます。

アップロード と 環境変数 と イベントソース設定

そろそろ CI ほしいですが、まだいったんVisual Studio でやります。適当にアップロード先 Function を作成します。

f:id:guitarrapc_tech:20161212041329p:plain

冒頭で作成した Slack Incoming Webhook のURL を環境変数に入れるのもここでできます。便利。

f:id:guitarrapc_tech:20161212041442p:plain

ついでに、Amazon SNS を起点に Lambda を実行するので、Event Sources も設定してしまいます。

f:id:guitarrapc_tech:20161212044036p:plain

もちろん Web Console 画面からやってもok です。

f:id:guitarrapc_tech:20161212044215p:plain

f:id:guitarrapc_tech:20161212044145p:plain

テスト実行

ローカル実行やテストする場合は、OSの環境変数に Lambda に設定する環境変数と同じものを仕込んでおきます。

Isssue を適当に立ててコメントしてみます。

f:id:guitarrapc_tech:20161212042125p:plain

うまく Slack に通知されましたね。

f:id:guitarrapc_tech:20161212042142p:plain

テスト中の実行グラフも出ています。

f:id:guitarrapc_tech:20161212042214p:plain

失敗や成功のログも Cloud Watch Logs に出力されています。

f:id:guitarrapc_tech:20161212042253p:plain

まとめ

Azure Functions と比べると SNS が増えてるだけなのに手間が大きく違いますね!シカタナイとは言え、Github とのつなぎこみに特化対応している Azure Functions はこの面で圧倒的に便利です。ただ、.csx でやり続けるのとどっちがいいかというと、どうでしょうかねぇ。

さて、今回のサンプルも挙げておきます。参考になれば幸いです。

github.com

*1:最高とは思いません。IAM作るのいやぽよ

*2:Azure Functions の AppSettings と同様です

*3:別に PowerShell でも C# でもいいです

*4:大半のケースはたいした処理しないでしょう。