

Azure Event Hubs に REST API でログを送りつける話
こんにちは、ソリューション開発部の柴崎です。
とある人型ロボのログを送りつける先として Azure Event Hubs を調査しました。色々とハマりどころがありましたのでここでご紹介します。
結論
Event Hubs の メッセージング プラン をよく確認すること。Standard がお勧め (ステマじゃないよ!)
Event Hubs には2種類 (Basic, Standard) のプランがあります。公式のドキュメントを含め Standard が基準に書かれていることも多く、そのまま試してみると使えなくて悲しい思いをします。特に パブリッシャー ポリシー が使えないなんて試してみるまで気づきませんでした。
SAS Token の生成
とある人型ロボからデータ送信するためには Python を使う必要があり .NET を利用できないため REST API による Event Hubs へのメッセージ送信が必要になります。利用する API は以下の通りです。
- Send event
- Send event with publisher ID (Standard のみ)
どうやら認証のために SAS Token が必要になるようです。調べてみると、C# で書かれたサンプルやサードパーティの生成ツールが出てきました。Basic, Standard それぞれで生成しなければいけない SAS が異なるにもかかわらず、某サードパーティのツールでは Standard 用にしか生成でないなど中々のハマりどころです。
安心してください、仕様ありますよ!
Basic 用 SAS Token 生成 PowerShell スクリプトを書きましたので参考にしてください。
$policyName = "POLICY_NAME"
$sharedAccessKey = "SHARED_ACCESS_KEY"
$servicebusNamespace = "SERVICEBUS_NAMESPACE"
$eventHubPath = "EVENT_HUB_PATH"
# 有効期限10年
$expiry = ([DateTimeOffset]::Now.ToUnixTimeSeconds()) + (60 * 60 * 24 * 365 * 10)
$resource = ("https://{0}.servicebus.windows.net/{1}/messages" -f $servicebusNamespace, $eventHubPath)
[void][Reflection.Assembly]::LoadWithPartialName("System.Web")
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.key = [Text.Encoding]::UTF8.GetBytes($sharedAccessKey)
$stringToSign = [System.Web.HttpUtility]::UrlEncode($resource)+ "`n" + [string]$expiry
$signature = [Convert]::ToBase64String($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign)))
$token = ("SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}" -f [System.Web.HttpUtility]::UrlEncode($resource), [System.Web.HttpUtility]::UrlEncode($signature), $expiry, $policyName)
$token
メッセージ送信
では早速送りつけてみましょう。ひとまず curl で試してみます。
以下は パブリッシャー ポリシー が無いものです。
要求
curl -v -X POST \
-H 'Authorization: SharedAccessSignature sr=https%3a%2f%2fSERVICEBUS_NAMESPACE.servicebus.windows.net%2fEVENT_HUB_PATH%2fmessages&sig=...&se=1782476450&skn=POLICY_NAME' \
-d 'test' \
'https://SERVICEBUS_NAMESPACE.servicebus.windows.net/EVENT_HUB_PATH/messages'
応答
HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-Type: application/xml; charset=utf-8
* Server Microsoft-HTTPAPI/2.0 is not blacklisted
Server: Microsoft-HTTPAPI/2.0
Strict-Transport-Security: max-age=31536000
Date: Tue, 28 Jun 2016 12:22:50 GMT
勝ったッ! 201 Created 完! なかなか長い道のりでした。
最後に Python のコードで締めくくります。
メッセージを送りつける Python コード
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib2
import base64
import hmac,hashlib
import time
data = "test"
servicebusNamespace = "SERVICEBUS_NAMESPACE"
eventHubPath = "EVENT_HUB_PATH"
resource = "https://%s.servicebus.windows.net/%s/messages" % (servicebusNamespace, eventHubPath)
token = "SharedAccessSignature sr=https%3a%2f%2fSERVICEBUS_NAMESPACE.servicebus.windows.net%2fEVENT_HUB_PATH%2fmessages&sig=...&se=1782476450&skn=POLICY_NAME"
req = urllib2.Request(resource, data)
req.add_header("Authorization", token)
res = urllib2.urlopen(req)
print res.code, res.msg
応答
201 Created
まとめ
MSDN あるあるの日本語ドキュメントが信用できない、サンプルがサンプルじゃないこともありましたが、実際に送信できれば簡単でした。Azure Event Hubs はログを送りつける候補の1つとして調査しましたが、なかなかよさそうです。今後、他の候補の調査内容も追ってご紹介できればと思います。