Azure Event Hubs に REST API でログを送りつける話

Azure Event Hubs, Microsoft Azure, Pepper, PowerShell, Python

こんにちは、ソリューション開発部の柴崎です。

とある人型ロボのログを送りつける先として Azure Event Hubs を調査しました。色々とハマりどころがありましたのでここでご紹介します。

結論

Event Hubs の メッセージング プラン をよく確認すること。Standard がお勧め (ステマじゃないよ!)

Event Hubs には2種類 (Basic, Standard) のプランがあります。公式のドキュメントを含め Standard が基準に書かれていることも多く、そのまま試してみると使えなくて悲しい思いをします。特に パブリッシャー ポリシー が使えないなんて試してみるまで気づきませんでした。

SAS Token の生成

とある人型ロボからデータ送信するためには Python を使う必要があり .NET を利用できないため REST API による Event Hubs へのメッセージ送信が必要になります。利用する API は以下の通りです。

どうやら認証のために 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つとして調査しましたが、なかなかよさそうです。今後、他の候補の調査内容も追ってご紹介できればと思います。

  • 株式会社アークシステムの来訪管理・会議室予約システム BRoomHubs
  • 低コスト・短納期で提供するまるごとおまかせZabbix