【事象】
AWSのサービスを利用し、デプロイメントパイプラインを作ろうとしていた際、Git Hub Enterprise(以後、GHE)とAWS CodeBuildのwebhook連携ができなくて辛かった。
【解決】
GHEのwebhookの設定で、「Content-Type」を、[application/json]にすることで、webhook連携が有効になった。
ヾ(ΦωΦ)/
【詳細】
Git Hub/Labを使っていると、ビルド以外にもチケットと連携させたりで、
webhook/service hookを多用することになると思います。
今回、AWSのデプロイメントパイプラインを作成していましたが、
ビルド → デプロイのうち、ビルドの部分で躓きました。
GHEのmasterブランチにソースがpush → pushを検知してwebhook連携
→ AWS CodeBuildがビルドをする。
ここのwebhookがそもそもsucessしない!!GHEのコンソールで叱られる!!
GHEがおこな時のメッセージ
Invalid HTTP Response: 400
GHEとAWS CodeBuildによるビルド自動化の流れ
AWS CodeBuildのビルドの流れとしては、下記のような感じになります。
1.ビルド対象のソースコードがGHEのとmasterブランチにpushされる
2.pushを検知し、GHEがwebhookを飛ばしてAWSCodeBuildに知らせる
3.AWS CodeBuildが、ビルド仕様ファイル(build spec.yml)を元にビルドを実行
4.ビルドで生成されたjarなりzipなりをS3バケットに放り込む
AWS CodeBuildは、ビルド仕様ファイル(build spec.yml)の書き方次第で
色々いじれるみたいですね。今度また学んだらQiita書きます。
どうやら、ビルドテストを、自前のコンテナ内で動作させたりとかもできる模様...。
さてさて、AWS CodeBuildのビルドの流れを大きく4つに分けました。僕はこの中で、
2.pushを検知し、GHEがwebhookを飛ばしてAWSCodeBuildに知らせる
で上手くいきませんでした。
webhook連携失敗の詳細
今回はほぼGHEの話になります。
今一度AWS CodeBuild - GHE間のwebhook設定の流れをさらっと見てみましょう。
1.AWS CodeBuildでビルドプロジェクトを作成し、webhookのPOST先となる
「Payload URL」と、AWSへアクセスする「Secretキー」を受け取る。
2.GHEプロジェクトの[Settings]-[Webhooks]から色々設定します。
設定内容
項目 | 値 |
---|---|
Payload URL | AWSから受けったペイロードURL |
Content type | Content-Typeヘッダー |
Secret | シークレットキー |
Which events | トリガーイベント |
3.設定を反映
[Add webhook]で反映すると、GHEのコンソール画面にて疎通確認ができます。
Creating Webhooks
https://developer.github.com/webhooks/creating/
Testing Webhooks
https://developer.github.com/webhooks/testing/
↑設定がおかしいと、ここで真っ赤っかになって叱られます。
僕は、ここでfailed (red x) になってしまいました。
Content typeを application/x-www-form-urlencoded
から
application/json
へ変更することで無事SUCCESSしました。
payloadといえば、json payloadだと誰もがわかるそうなのですが、
僕は知識足りず、普通に調べるまでわかりませんでした...。
オンプレの古いところだと、jsonのapiダメだったりするしなぁ〜。
さてさて
僕が今回失敗していたのは、Coontent-Typeヘッダーの設定でした。
では何故、 application/json
だとうまくいって、
x-www-form-urlencoded
では失敗したのか。
そもそも
今回疎通ができていなかったwebhookは、 イベントが発生したのをきっかけにして、
HTTP通信でターゲットにデータを通知する仕組みのことを言います。
何かしらイベントが発生にあたるイベントは、「masterブランチへのpush」でしたね。
そして、「HTTP通信でターゲットにデータを通知」 これが、今回問題となった
Coontent-Typeヘッダー
の設定に関係があります。
ターゲットとなるのは、PayloadURLで、データはPayloadURLへ JSON形式でPOST
されていました。
(この画力でマスターヨーダを見抜いた人も居ました...。)
webhookが使うHTTP通信のやりとり
masterブランチへのpushというイベントを受け取ったGHEは、
webhookを動かしHTTP通信でデータを送ります。
この際、送られるデータの中身は下記のような感じになっています。
○HTTPリクエストの中身
・リクエストライン
・HTTPヘッダー
・メッセージボディ
それでは一つずつちょろっと見てみましょう〜。
リクエストラインは、「HTTP通信で何をどうしたいか。」を記述します。
例えばデータを投入(POST)したいのか参照(GET)したいのかとかにあたりますね。
今回の場合、データは、「PayloadURL(CodeBuildのビルドプロジェクト)へ向けて
JSON形式でPOST(投入)
」されていました。
HTTPヘッダー、今回はここで躓きましたね。
HTTPヘッダーは、読み込むリソースや、リクエスト送信者の情報のことを言います。
Cookie持つ持たない、どこのプロキシを通った通ってないとかも書かれています。
Content-Typeヘッダー
というのは、データの形式を指定する記載でした。
ターゲットのAWS CodeBuildは、 json形式
でデータを欲しがっていました。
そのため、webhookを定義する際、
GHEのコンソールで application/json
を選択せねばなりませんでした。
どうやらAWSのwebhookでは、デフォルトではJson形式で情報を受け取る模様です。
AWSの公式にも載ってました〜!
CreateWebhook
Request Parameters
https://docs.aws.amazon.com/ja_jp/codebuild/latest/APIReference/API_CreateWebhook.html
The request accepts the following data in JSON format.
メッセージボディ
実際のデータ内容
今回の場合は、データ形式が間違っていたんだということがわかりました〜。
application/json と x-www-form-urlencoded
今回の事象の原因となるHTTPヘッダーについても触りが理解できましたが、
application/json
と x-www-form-urlencoded
二つの違い知りたくないですか?
application/json
JSON形式を指定していますね。
JSON形式では、値(バリュー)と、値の名前のキーのペアをコロン「:」で対にして、
それらをコンマ「,」で区切り、全体を波かっこ「{...}」で括って表現する形式です。
こんな感じになりますね。江戸川乱歩めっちゃ好きなので、本の宣伝もしちゃう。
"book1":{ "title": "Phantom twenty face","year": 2005 ,"page": 350}
application/x-www-form-urlencoded
この形式だと、キーバリューはキーとバリューを「=」で結合することで記述されます。
また、キーバリューセットがが複数ある場合は、「&」で区切られるそうです。
そして、dataはURLエンコードされるとありました。
URLエンコードというのは、表記できない文字の文字コードを16進数で表し、
「%」に続けて表記し、その文字を置き換える表記のことを言います。
そのため、パーセントエンコードとも呼ばれています。
例えば、KINTAN表参道店だとこうかなぁ〜
データ形式の例:(Restaurant=KINTAN&where=Omotesando)
URLエンコードの例:焼肉 → %E7%84%BC%E8%82%89
atwata developer blog
http://blog.atwata.com/web/2017/04/20/http-request-content-type.html
HTTPリクエストのContent-typeについては、この方のブログが一番綺麗にまとまっていました。
最後におまけ
HTTP通信を生で見ようかなと思って、curlして生で見てみました。
AbemaTVの「田端信太郎VS藤田孝典」面白かったですね〜。
田端さんがお話していた「全員気持ちよく金を使いたくなる社会」がいいと思いました。
そんなわけで、WEARにcurl (GETリクエスト) してHTTP通信を生で見てみました。
オプションが豊富で、いろんなプロトコルにも対応してくれてありがたいです。
HTTPメソッド のGET リクエストが送られていたり、TSL通信が始まったりするところも見れちゃいますね〜。
[root@cbbb33c66501 work]# curl --verbos https://wear.jp/ -o ./wear.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* About to connect() to wear.jp port 443 (#0)
* Trying 175.111.83.51...
* Connected to wear.jp (175.111.83.51) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=wear.jp,O="START TODAY CO., LTD.",OU=System,L=CHIBA-SHI,ST=CHIBA,C=JP
* start date: Apr 26 03:11:04 2018 GMT
* expire date: Jul 01 23:59:59 2020 GMT
* common name: wear.jp
* issuer: CN=GlobalSign Organization Validation CA - SHA256 - G2,O=GlobalSign nv-sa,C=BE
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: wear.jp
> Accept: */*
>
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Length: 141665
< Content-Type: text/html; Charset=UTF-8
< Set-Cookie: PreObjectID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: AF%5FPreObjectID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: AF%5FPreScreenID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: ObjectID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: PreScreenID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: ScreenID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: AF%5FScreenID=12; expires=Sun, 18-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: AF%5FObjectID=; expires=Sat, 10-Nov-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: LocaleID=MQ%3D%3D%2D%2D46be9f2f8609755b62badaba4488e04c3da0adf1237bddab7d78accebcadc3c8; expires=Tue, 18-Dec-2018 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: ZOZO%5FUID=%3A65177467%3A595854930; expires=Thu, 30-Jul-2020 15:00:00 GMT; domain=.wear.jp; path=/
< Set-Cookie: ASPSESSIONIDQQRDQBRB=JGFICODAMLDKKLJENAKKCJFC; path=/
< Date: Sun, 18 Nov 2018 02:15:31 GMT
< Set-Cookie: BIGipServerIN51_wear.jp_Pool=1649482250.20480.0000; path=/; Httponly
< Set-Cookie: TS01145b15=0182a260475cac19114f0c5a22225c7a08322e320179019429bc3095c2da4cb67d9623533dc2dfd8f7a73be26886dd07b3e755506a; Path=/
< Set-Cookie: TS0148206c=0182a260475cac19114f0c5a22225c7a08322e320179019429bc3095c2da4cb67d9623533dc2dfd8f7a73be26886dd07b3e755506a; path=/; domain=.wear.jp
<
{ [data not shown]
100 138k 100 138k 0 0 146k 0 --:--:-- --:--:-- --:--:-- 146k
* Connection #0 to host wear.jp left intact
<参考>
Webhookって何?を子どもでもわかるように描いてみた | kintone hive online
https://kintone-blog.cybozu.co.jp/developer/000283.html
サイボウズめっちゃ好きだ〜。
くま、可愛いかよ。
Using application/x-www-form-urlencoded format
https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
Github Webhook Tutorial.md
https://gist.github.com/jagrosh/5b1761213e33fc5b54ec7f6379034a22
Web-hooks
https://developer.github.com/enterprise/2.10/webhooks/
https://developer.github.com/webhooks/
URLエンコード・デコード 日本語URLを扱う場合にどうぞ
https://tech-unlimited.com/urlencode.html
FormData オブジェクトの利用
https://developer.mozilla.org/ja/docs/Web/Guide/Using_FormData_Objects
MIME タイプ
https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types