砂漠の旅人(たびと)|新天地:たびとの旅路

電脳砂漠を旅する、ある旅人の日記。フロッピーを頼りに歩いた日から、クラウドの地平を見つめる今日まで。見つけたオアシスも、迷い込んだ砂の迷宮も、全てこの羊皮紙に。

遺跡の魂を直接読み解け ~RestSharpで、Redfishの深淵を覗く~

旅の途中、興味深いオアシスを見つけた。忘れないうちに、この羊皮紙に記しておくとしよう。

前回の旅で、我々はRedfishのモックアップという名の「地図」から、その構造を読み解く魔法を編み出した。しかし、地図はあくまで地図。真の冒険者ならば、本物の遺跡(サーバ)へ赴き、その魂に直接触れたいと思うのが常だろう。

今回は、前回の魔法をさらに進化させ、RestSharpという名の翼を授ける。これにより、我々はファイルという名の書庫から飛び立ち、ネットワークという広大な空を経て、サーバ(BMC)という名の神殿に直接アクセスするのだ。自己署名証明書という結界を突破し、@odata.idという糸を辿って、遺跡の魂の全てを一枚の羊皮紙にマージする。さあ、真の探査の旅が始まる。

この羊皮紙のあらまし

この羊皮紙が導く者

  • サーバ(BMC)という名の神殿から、Redfishの情報を一気に引き出したいと願う者
  • RestSharpという翼を使い、REST APIという大空を自在に飛び回りたい探求者

翼を授ける儀式:RestSharpとの契約

今回の旅の鍵を握るのは、HTTPアクセスを驚くほど簡単にする魔法の道具「RestSharp」だ。

Hello from RestSharp | RestSharp

この翼を使いこなす作法は、極めてシンプルだ。

  1. RestClientという翼を広げる。この時、自己署名証明書という名の結界を無視するため、RemoteCertificateValidationCallbackで「全てを信じる」と誓いを立てる。
  2. RestRequestで行き先(URI)を定め、ExecuteAsyncの呪文で大空へ飛び立つ。
  3. 戻ってきたRestResponseという名の伝書バトから、お目当ての情報を受け取る。

秘儀の全貌:魂をマージする呪文

この秘儀の核心は、遺跡の魂(JSON)を読み解き、繋ぎ合わせるための、二つの設計図(クラス)と、それらを操る再帰の魔法(Readメソッド)」にある。

設計図その1:JsonElement

これは、遺跡から得られる魂の欠片、一つ一つの情報を記録するための、最小単位の器だ。

/// <summary>
/// JSONの要素
/// </summary>
class JsonElement
{
    public JsonToken TokenType { get; set; }
    public object? Value { get; set; }
}

設計図その2:Redfish

そしてこれが、旅の全てを司る、我々の分身だ。翼(RestClient)を持ち、魂の欠片(JsonElement)を集め、そして再帰の魔法を唱える。

/// <summary>
/// Redfishマージ用
/// </summary>
class Redfish
{
    public RestClient? Client { get; set; }
    public List<JsonElement> Elements { get; set; } = new List<JsonElement>();

    HashSet<JsonToken> JsonTags { get; } = new HashSet<JsonToken>() { JsonToken.StartObject, JsonToken.EndObject, JsonToken.StartArray, JsonToken.EndArray };
    HashSet<string> OdataItems { get; set; } = new HashSet<string>() { "/redfish/v1/" };

    /// <summary>
    /// 全ての魂を再帰的に読み込む
    /// </summary>
    public void Read(string path)
    {
        if (Client == null) return;

        // RestSharpの翼で、遺跡へ直接問いかける
        var request = new RestRequest(path);
        request.AddHeader("Content-Type", "application/json");
        var response = Client.ExecuteAsync(request, Method.Get).Result;
        if (response == null || response.Content == null || response.ResponseUri == null) return;
        Console.WriteLine($"{response.ResponseUri.AbsoluteUri}\n{response.Content}\n");

        // 遺跡からの応答(JSON)を解読し、
        // 新たな「@odata.id」という名の道を見つけたら、
        // 再びこのReadメソッド自身を呼び出し、旅を続ける(再帰)
        var reader = new JsonTextReader(new StringReader(response.Content));
        while (reader.Read())
        {
            var val1 = reader.Value;
            Elements.Add(new JsonElement() { TokenType = reader.TokenType, Value = val1 });

            if (reader.TokenType != JsonToken.PropertyName) continue;
            reader.Read();
            var val2 = reader.Value;
            Elements.Add(new JsonElement() { TokenType = reader.TokenType, Value = val2 });

            if (val1 == null || val2 == null) continue;
            if (JsonTags.Contains(reader.TokenType)) continue;
            if (!((string)val1).Equals("@odata.id")) continue;

            if (!OdataItems.Contains((string)val2))
            {
                OdataItems.Add((string)val2);
                Elements.Add(new JsonElement() { TokenType = JsonToken.PropertyName, Value = "/* @odata.child */" });
                Read((string)val2);
            }
        }
    }
    // ...(Writeメソッドは、集めたElementsをファイルに書き出すだけなので省略)...
}

この再帰の魔法により、最初に/redfish/v1/という入口から入るだけで、そこから繋がる全ての道を自動的に探査し、巨大な一枚の地図(JSONファイル)として描き出すことができるのだ。

羊皮紙を巻く前に

この進化版の魔法を使い、私はいくつかの本物の遺跡(サーバ)を探査してみた。中には、100MBを超えるほどの膨大な魂を持つ遺跡もあり、道半ばで力尽きることもあった。ここに掲載した呪文は、あくまで秘儀の骨子。実戦で使うには、エラー処理やリトライ処理という名の、さらなる鎧を纏わせる必要があるだろう。

しかし、これでついに、Redfishという広大な遺跡の、完全な地図を描き出すための基礎は、全て整った。 いずれ、この魔法を核として、誰もが直感的に遺跡を探査できる、GUI版の魔法の眼鏡(Redfishビューワ)を創り出してみたいものだ。

おっと、どうやら相棒が腹を空かせたようだ。今日はこのへんで筆を置くとしよう。

砂漠で見つけた魔法のランプ

  • 前回の冒険の記録(ファイル読み込み編)
  • RestSharp 公式の古文書

ラクダの独り言

ご主人が、羊皮紙を読むだけじゃ飽き足らず、今度は「れすとしょーぷ」とかいう、鳥の翼みたいなもので、遠くの神殿から直接情報を引っこ抜いてきている。便利かもしれんが、そんなことばっかりしてると、自分の足で歩くことを忘れちまうんじゃないのかね。まったく、横着なんだから。おっと、喉が渇いてきやがった。