Oracle Cloud Infrastructure SDK for .NETが公開されました

皆さんこんにちは。部屋が暑すぎるid:k-furusawa--gです。室内であっても熱中症には十分気を付けましょう。

本日は公式よりついに公開となった「Oracle Cloud Infrastructure SDK for .NET」をご紹介したいと思います。実際に使ってみてわかった突っ込みどころも書いていこうかと思います。

ドキュメントはこちら

.Net向けSDKの入手方法

本SDKはGitHubにて公開されています。URLは以下です。

GitHub - oracle/oci-dotnet-sdk: Oracle Cloud Infrastructure SDK for .NET

一応、全サービスが利用できる状態のようです。

Nugetでも公開されています。NuGetの検索は超使いにくいのでDeveloperで検索するとよいです。

NuGet Gallery | oci-dotnet-sdk

軽く使ってみる

使い方は公式のGitHubに書かれたサンプル通りにやれば、とりあえず動きます。

var provider = new ConfigFileAuthenticationDetailsProvider("DEFAULT");
var client = new AuditClient(provider, new ClientConfiguration());

API認証を行い接続に利用するProvider設定とクライアント作成です。

初めて見る人にはなんのこっちゃですが、サンプルの説明をよく読めばわかります。CLI用の接続設定ファイルを用意して、DEFAULTとタグ付けすればその接続設定を参照するという意味ですね。

Providerの設定は他にも、以下のように直接指定して作成することもできます。

Provider = new SimpleAuthenticationDetailsProvider
{
    TenantId = <テナントOCID>,
    UserId = <接続ユーザーOCID>,
    Fingerprint = <接続ユーザーフィンガープリント>,
    Region = <ホームリージョンID>
};

Provider.PrivateKeySupplier = new FilePrivateKeySupplier(<キーのパス>, <パスフレーズ>);

こちらのほうが多く使われるかもしれませんね。ちなみに構造からわかると思いますが、作成したクライアントは Dispose して切断を明記する必要があります。using を利用するなりしましょう。

また、作成したクライアントのエンドポイントを途中で違うリージョンのものに切り替えるなどもできません。その場合はクライアントを作り直しましょう。

キー内容を直接読み出すProviderは未実装

ただ、これだとサーバー内にキーを配置しないといけないので、環境によっては許容できないかもしれません。例えば、セキュリティ担保の都合でキーをAPサーバーに置きたくない! とかですね。接続設定ファイルも、アプリケーションが読めるような場所に直で配置するのは危ないので嫌だってこともあるでしょう。セキュリティ意識が高くていいと思います。

ただその場合、キー内容を直接読んでAPI認証を行うためのProviderがSDKに含まれていませんので、SDK利用できなくなります。その場合は自分で作っちゃいましょう。

自分で実装する

無いなら実装せよですね。

public class PrivateKeyPairSupplier : ISupplier<RsaKeyParameters>
{
    private string privateKeyContent;
    private string privateKeyPassphrase;

    public PrivateKeyPairSupplier(string keyContent, string keyPassphrase = "")
    {
        this.privateKeyContent = keyContent;
        this.privateKeyPassphrase = keyPassphrase;
        if (string.IsNullOrEmpty(privateKeyPassphrase))
        {
            privateKeyPassphrase = "";
        }
    }

    /// <summary>Retrieves the private key from a key string.</summary>
    public RsaKeyParameters GetKey()
    {
        AsymmetricCipherKeyPair keyPair;

        using (var privateKeyStream = new MemoryStream(Encoding.UTF8.GetBytes(privateKeyContent)))
        using (var privateKey = new StreamReader(privateKeyStream))
        {
            try
            {
                keyPair = (AsymmetricCipherKeyPair)new PemReader(privateKey, new Password(privateKeyPassphrase.ToCharArray())).ReadObject();
            }
            catch (InvalidCipherTextException e)
            {
                throw new ArgumentException("Incorrect passphrase for private key", e);
            }
            catch (PasswordException e)
            {
                throw new ArgumentException("Private key is encrypted with a pass phrase. Please provide passphrase in the config", e);
            }
            catch (InvalidKeyException e)
            {
                throw new ArgumentException("Invalid Key has been provided", e);
            }
        }

        return (RsaKeyParameters)keyPair.Private;
    }

    /// <summary>
    /// Implements Bouncy Castle's IPasswordFinder interface to allow opening password protected private keys.
    /// </summary>
    public class Password : IPasswordFinder
    {
        private readonly char[] password;

        /// <summary>
        /// key password
        /// </summary>
        /// <param name="password"></param>
        public Password(char[] password) { this.password = password; }

        /// <summary>
        /// password getter
        /// </summary>
        /// <returns></returns>
        public char[] GetPassword() { return (char[])password.Clone(); }
    }
}

こんな感じでしょうか。FilePrivateKeySupplierとほぼ同じ構造で、API認証サンプルコードをそのまま移植したような形になります。試したらこれでもSDKが利用できました!

とりあえずインスタンスを取得する

SDK使ったらとりあえずインスタンスを取得したいですよね(偏見)。以下のようなコードで取得できます。

var listInstancesRequest = new ListInstancesRequest()
{
    CompartmentId = <コンパートメントID>,
    Limit = 100(最大取得数)
};

var listInstance = await OciComputeClient.ListInstances(listInstancesRequest);

基本async実装です。並列実行想定のようですが、OCIのAPIは頻繁に呼び出すとすぐに429や502エラーが返るので、実行数は制御したほうがいいでしょう。せめて1分間にどれだけリクエストを送っていいかなどの記載があればいいのですが、APIドキュメントには記載があったりなかったりで正確なリクエスト数は私にもわかりませんでした。

全体的にはAWSのSDKとよく似ている

ここまで読んでいただければわかった方もいらっしゃると思いますが、全体的にAWSのSDKに似ています。サービスごとにプロジェクトが分かれている点なんてそのまんまですね。

後述する欠点は多くありますが、公式なのでAPIの変更などにも一定の保証があるはずですのでid:k-furusawa--gという人物が出しているOCISDKとかいう野良SDKは使わず、こちらを利用しましょう!

欠点、難点、突っ込みどころ

基本的な使い方をご紹介したので、続いて突っ込みどころを書こうかと思います。

なぜかインターフェースは未実装

本SDK最大の謎なのですが、なぜかインターフェースが実装されていません。インターフェースがないとDIなどで困ってしまうのですが、そういったユースケースは想定していないようです。この量だとフォークしてインターフェースだけ自力で実装するのも骨なので、公式で対応してほしいですね。

API認証に不要なはずのホームリージョンを強要される

SDKのコードを読んでいくと分かるのですが、構造の問題でAPI認証時には不要なホームリージョンの提供を強制されます。

本来であれば

  1. API認証してIdentityクライアントを用意する
  2. サブスクリプションしたリージョン一覧を得て保持
  3. 各リージョンでクライアントを作成してリソース取得

といった流れを組めばホームリージョンの確認なんてしなくてもいいのですが、ホームリージョンがないといけないのでコンソールから確認しないといけません。面倒くさいです。ただでさえOCIのAPI認証は必要となる項目が多いので、せっかく公式なのですから減らす努力をしてもらいたいです。

どこまで対応されているのか不明

これは公式だからこそやってほしいという意見なのですが、SDKがどこまで対応されているのか不明です。ドキュメントの最新版とパラメータの不一致などが起きているので、もとになっているAPIの定義から必ずしも最新版を引っ張って作成しているわけではなさそうなのですが(コードはおそらく自動生成と思われるので)、それなら対応している範囲をどこかに書き出してほしいですね。

summaryがない

JavaのJavadocって便利ですよね。ドキュメント化できるだけでなく、SDKについていると利用時に必須項目なのかどうか、どういったメソッドなのか、返り値はどうなのか、Exceptionは何が発生するのか、そういった情報が出てくるので、実装も楽です。ドキュメントの参照回数も少なくて済みますね。

C#にも一応、summaryで記載しておけばそれっぽいコメントを出せるようになるのですが、本SDKにはないです。なのでいちいちドキュメントを参照しないといけなくてスムーズに実装できません。コード上には記載されているようですので、パッケージ化の際にオプションを付けていないようです。公式なのですからそれくらいは気を付けてもらいたいですね。

サンプルが少なすぎる

正直、あまり取っつき易いとは言えないOCIのAPI類なのですが、SDKもその影響なのか使いづらい面がかなりたくさんあります。だからこそ前述したsummaryが重要なのですが、無いものは仕方がありません。

せめてサンプルが充実していればと思うのですが、こちらもかなり不足しています。正直、このサンプルだけで充分だと思ったのならオラクルのエンジニアはユースケースを見れていないのだと思います。私の個人開発のSDKでさえ一通りサービスが触れるようにサンプルは用意してあります。

AWSのSDKなどはテストもサンプルも業務利用レベルを想定して提供しているので、開発利用時に非常に有効です。

補助クラス類の実装はない

これはほしい! という要望に近いのですが、AWSのSDKのように実装時に使えるオプションクラスが欲しいです。

例えばObjectStorage。ぶっちゃけこのままの実装でちゃんと扱おうとすると相当に頑張らないといけません。AWSのS3はIO実装があって便利ですね。ユーザーがSDKをどう利用するのかを踏まえている実装だと思います。

ちなみに私が個人的に作ったIOはコードを公開してますので、興味ある方はどうぞ。AWSのDirectoryInfoとFileInfoをそのまま移植した感じです。バグありますけどご愛敬。

oci-sdk-net/OCISDK.Core/ObjectStorage/IO at master · KoutaFurusawa/oci-sdk-net · GitHub

さいごに

いろいろ突っ込みどころを書きはしましたが、ようやく公式でdotnet向けのSDKが出たのは喜ばしいことですね。ありがたいです。先にも書きましたが、公式なので野良SDKとは違って変更時のトラブルや、問題発生時の対応も報告場所がわかっていますし、一定の水準が設けられているはずですので対応も早いと思われます。

これからdotnetでOCI利用の開発を想定している場合は、利用してみるといいと思います。