Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

Windows Azure Pluginを作ってみる

こんばんは、statemachineです。書きかけの記事を吹き飛ばしてしまい、二回目の執筆ですがいかがお過ごしでしょうか。
前回は、Windows Azure におけるPluginの仕組みについて紹介しましたが、今回は実際Pluginを作成してみたいと思います。

海外では既に、Memcached pluginを作成されている方もいらっしゃるようですが、こちらは特に参考にしたりしていません。食い違っていることを言っていたらごめんなさい。例によって本記事の内容は、無担保、無保証でありPluginの作成方法も正式に公開されている訳ではないので、注意してください。

おさらい

前回のおさらいとして、Pluginの特徴をまとめると以下。特にPluginだからといって特殊な機能を備えているわけではなく、あくまでSDK 1.3で提供されている範囲内だと思われます。

  • 格納場所は、C:\Program Files\Windows Azure SDK\v1.3\bin\plugins
  • サービス定義、構成ファイル風のスキーマを持っている。
  • StartupTask/ConfigurationSettings/InputEndpointなどを定義できる。

Agentの作成

Pluginとして起動するAgent的な何かを作成します。Connect/RemoteDesktop/Diagnosticsなど、どれもAgent的なものなのでそれに倣ってみます。また以下の機能を持たせることで、Pluginの機能を検証します。

  • StartupTaskでAgent的な何かを常駐。
  • ConfigurationSettingsで値を利用
  • InputEndpointを定義し通信

ということで作成したのが以下のプログラム。

  • TcpListenerで常駐し、InputEndpointを利用。
  • クライアントからの接続で、構成ファイルに定義された値をランダムに返却

プログラム自体は、.NET 3.5 Console Applicationです。Microsoft.WindowsAzure.xxxなDLLの参設照定を追加を忘れずに。.NET 4だとデフォでClient Profileになるとか混合アセンブリが云々と言われるので。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Web;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace HogeAgent
{
    class Program
    {
        static void Main(string[] args)
        {
            new HogeAgent().Start();
        }
    }


    public class HogeAgent
    {
        private readonly TcpListener _listener;
        readonly string[] _response;
        private readonly Random _rnd = new Random();

        public HogeAgent()
        {
            IPEndPoint ip;
            if (RoleEnvironment.IsAvailable)
            {
                ip = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["statemachine.HogeInput"].IPEndpoint;
                // サービス構成ファイルは日本語化けるっぽいのでUrlEncode済
                _response = RoleEnvironment.GetConfigurationSettingValue("statemachine.ResponseStrings").
                            Split(',').Select(HttpUtility.UrlDecode).ToArray();

            }
            else
            {
                // test route
                ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4989);
                _response = new string[] { "あほ", "ばか", "とろ" };
            }
            _listener = new TcpListener(ip);
        }

        public void Start()
        {
            _listener.Start();

            while (true)
            {
                TcpClient client = _listener.AcceptTcpClient();
                var message = _response[_rnd.Next(_response.Length)];
                //  byte[] data = Encoding.GetEncoding(932).GetBytes(message + "\n");
                byte[] data = Encoding.UTF8.GetBytes(message + "\n");
                NetworkStream stream = client.GetStream();
                stream.Write(data, 0, data.Length);
                stream.Close();
                client.Close();
            }
        }
    }
}

Pluginの作成

Agentが完成したら、Pluginを作成します。作成手順としては以下。

  • Pluginフォルダを作成。C:\Program Files\Windows Azure SDK\v1.3\bin\plugins\Hogeなど。
  • Plugin定義ファイル Hoge.cspluginを作成。
  • Agent的な実行ファイルを配置

作成したHoge.cspluginが以下。Azureの定義ファイルをご存じの方なら説明不要かと思います。

  • RoleModuleのnamespace属性に、Pluginの名前空間を定義。Pluginで定義された情報へのアクセスは、この名前空間を付加する。
  • StartupTaskでHogeAgentを起動。特に管理者権限は必要ないので、権限はlimited。常駐して制御を返さないので、taskTaypeはbackgroundで。
  • ConfigurationSettings/InputEndpointは普通に定義。
  • ignoreRoleInstanceStatusは、RemoteForwarderについていたので,特にそのまま。
<?xml version="1.0" ?>
<RoleModule 
  xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"
  namespace="statemachine">
  <Startup>
    <Task commandLine="HogeAgent.exe" executionContext="limited" taskType="background" />
  </Startup>
  <ConfigurationSettings>
    <Setting name="ResponseStrings" />
  </ConfigurationSettings>
  <Endpoints>
    <InputEndpoint name="HogeInput" protocol="tcp" port="4989" localPort="4989" ignoreRoleInstanceStatus="true" />
  </Endpoints>
</RoleModule>

Pluginの組み込み

通常のWebRoleプロジェクトを作成し、サービス定義ファイルにImport文を追加します。

すると、サービス定義ファイルに、statemachine.ResponseSettingsが自動で追加されるのでレスポンスデータを定義します。日本語が化けるっぽいのですが、原因は追及せずUrlEncodeでごまかします。

実行

WebRoleをAzure上にデプロイします。Agent的な何かは、4989ポートでリクエスト待ちとなっているので、telnet等で4989ポートをつんつんしてみます。すると、以下のようなレスポンスデータがランダムに返ってくることになります。

まとめ

  • Pluginの作成自体は得に難しいものではないが、お作法が合っているのか不明。
  • サービス的なものにしたほうが良いのか? 起動、終了のシーケンスなどきちんとやらきゃいけないとか。
  • SDKのインストールフォルダに配置しなければいけないのか? 配布が面倒かもとか。

といらえず、実現可能性は分かったので、このあたりでサヨナラ、サヨナラ、サヨナラ。