SMP の操作と相互作用
組み込みメソッドと管理インフラストラクチャ API
ストレージ管理プロバイダー (SMP) 開発者は、次の作業を行います。
- Convert-MofToProvider.exeによって生成される組み込みメソッド。
- SMP の実装を提供するために、 mi.h ファイルの管理インフラストラクチャ (MI) API。
次の箇条書きでは、いくつかの主要な組み込みメソッドと MI メソッドに注意してください。
EnumerateInstances と GetInstance
EnumerateInstances は、特定のクラスのインスタンスに対するクエリがある場合に呼び出されます。 たとえば、PowerShell コマンドレット Get-<Object> は、対応する WMI オブジェクトの EnumerateInstances メソッドにマップされます。 このメソッドは、<Object>_Post メソッドを使用してクラスのすべてのインスタンスを返す必要があります。 WMI は EnumerateInstances を頻繁に呼び出すので、すばやく実行する必要があります。 そのためには、適切なキャッシュ管理を使用します。
GetInstance は、次のようなクラスの特定のインスタンスが必要な場合に呼び出されます (ただし、これらに限定されません)。
- WMI インフラストラクチャがこのクラスの任意のメソッドを呼び出す場合
- WMI ベースのアプリケーションでこのメソッドを直接呼び出す場合
- クラスのインスタンスが Association クラスを通じて要求された場合
GetInstance メソッドは、<Object>_Post メソッドを使用して指定されたオブジェクトのみを返す必要があります。 クエリ対象のインスタンスの識別子 (通常は ObjectId である MOF で定義されている "キー") は、InstanceName パラメーターを使用して取得されます。 このメソッドは、WMI によって頻繁に呼び出され、迅速に完了する必要があります。
EnumerateInstances と GetInstance は、StorageProvider、StorageSubsystem、PhysicalDisk などの通常のクラスでは必須です。
Association クラスの場合、EnumerateInstances、AssociatorInstances、ReferenceInstances は必須ですが、GetInstance は必須ではありません。
<Object>_Post と MI_PostResult
MI API メソッド <Object>_Post と MI_PostResult の違いを理解するには:
- <Object>_Post は出力パラメーターへのポインターを返すものとして考えてください。
- MI_PostResultは、関数の実行状態を示す関数の戻り値と考えてください。
WMI メソッド "context" ごとに 1 回だけ MI_PostResult を呼び出す必要があります。これは、各 WMI メソッドの入力パラメーターにあります。 "Context" は、WMI コールバックへのポインターです。 MI_PostResult を呼び出すと、このポインターが破棄されます。 したがって、WMI メソッドを別の WMI メソッドの本体で呼び出すことはできません。
一方、<Object>_Post オブジェクトは、WMI メソッド コンテキストごとに複数回呼び出すことができます。 このメソッドは通常、複数のオブジェクトを返すために EnumerateInstances で使用されます。
Set<プロパティ> と ModifyInstance
組み込みメソッド ModifyInstance は、 Windows Storage Management API ではサポートされていません。 オブジェクトのプロパティを変更するには、extrinsic メソッド Set<Property> が使用されます。
組み込みメソッドと MI API の詳細については、Windows SDK の MI API サンプルを参照してください。
オブジェクトの識別
SMP インターフェイスは、オブジェクトの識別に次の 2 つのプロパティ グループを使用します。
スクリプトとプログラミングの場合: ObjectId と UniqueId
ObjectId は、SMP とそのクライアントを使用してオブジェクトのインスタンスを追跡するために作成され、メインに含まれる不透明な識別子です。 これは、グローバルに一意である必要がある必須のプロパティです。 つまり、2 つのオブジェクトが個別の SMP によって管理されている場合や、異なるストレージ サブシステム上にある場合でも、同じ ObjectId を持つ必要はありません。
オブジェクトが 2 つの異なるパス (たとえば、同じストレージ サブシステムを指す 2 つの個別の SMP がある) を介して表示される場合、同じオブジェクトが 2 つの異なる ObjectId で表示される可能性があります。 2 つのオブジェクト インスタンスが同じオブジェクトであるかどうかを判断するには、UniqueId プロパティを使用します。
UniqueId は、グローバル スコープ内のクラスのインスタンスを一意に識別するために使用される必須プロパティです。 この値は、異なる管理サーバーで実行されている 2 つの SMP インスタンス間で同じである必要があります。 ObjectId とは異なり、UniqueId は、ストレージ管理プロバイダー プロセスではなく、ストレージ サブシステムが保持する値である必要があります。
UniqueId には、特に明記されている場合を除き、任意の不透明な値を指定できます (例: MSFT_VirtualDisk)。
表示の場合: FriendlyName と Name
エンド ユーザーは、これら 2 つのプロパティを使用してオブジェクトを識別します。 FriendlyName は、SMP がこのような操作をサポートしている場合にエンド ユーザーが設定できるわかりやすい文字列です。 FriendlyName は一意である必要はありません。 1 つのストレージ サブシステムの 2 つのオブジェクトで同じ FriendlyName を共有できますが、この方法はお勧めしません。
SMP によって Name プロパティが設定され、エンド ユーザーはそれを変更できません。 SMP は、エンド ユーザーがオブジェクトを識別するのを支援するために、このプロパティに追加情報を提供します。 このような情報は、オブジェクトの技術的な側面をカバーする場合があります。 たとえば、記憶域サブシステムの名前には、サブシステムの IP または WWN を指定できます。 名前は通常、特定の範囲内で一意です。 たとえば、ストレージ プールの名前は、所有するストレージ サブシステム内で一意である必要があります。
エラー処理
SMP インターフェイス には、Windows Storage Management API (SM API) 戻りコード、"ソフト エラー"、"ハード エラー" の 3 種類のエラーがあります。
SM API 戻りコードは、SMP extrinsic メソッドごとに戻り値としてリストされているエラー コードを参照します。 たとえば、"5" は "無効なパラメーター" を表します。 これらのエラー コードは、Convert-MofToProvider.exe によって生成されたメソッド構造で定義された MIReturn 出力パラメーターを介して返されます。 MIReturn の値は、対応するオブジェクトのヘッダー ファイルで定義された <Object> _<Method>_Set_MIReturn を介して設定できます。
Extrinsic メソッドは、可能な場合は常に SM API エラー コードを使用するように既定値にする必要があります。 追加情報が必要な場合、SMP は MSFT_ExtendedStatus クラスを使用して、extrinsic メソッドの呼び出しに関する追加の状態情報を提供できます。 この方法は、Extrinsic メソッドにソフト エラーを使用する場合に適しています。
ソフト エラーとは、MSFT_SoftError クラスを介して返されるエラー メッセージを指します。 これらのエラーは、SM API エラー コードを返さない組み込みメソッド (EnumerateInstances、GetInstance など) 用に設計されています。 ソフト エラーを返すには、MSFT_SoftError から派生したソフト エラー クラスのインスタンスを構築し、mi.h で定義されている MI_WriteCimError メソッドの "MI_Instance error" パラメーターを介して返す必要があります。 たとえば、ストレージ アレイのログイン中に "正しい資格情報が必要です" と示すために、StorageSubsystem オブジェクトの EnumerateInstances 呼び出し中に "MSFT_SoftError_NotAuthenticated" のインスタンスを返すことができます。 ソフト エラーの場合、MI_RESULT_OKの結果は引き続きMI_PostResultを通じて投稿する必要があります。
ハード エラーは、mi.h ファイルから MI_Result 構造体で定義されているエラーを参照します。 MI API は、これらのエラーを返します。 SMP は、絶対に必要でない限り、記憶域管理アプリケーションにこれらのエラーが直接表示されないようにする必要があります。 たとえば、"無効なパラメーター" の場合、SMP は、ストレージ管理アプリケーションに依存してMI_RESULT_INVALID_PARAMETERを使用する代わりに、MIReturn を使用して SM API エラー コード "5" - "無効なパラメーター" を表示する必要があります。
初期プール
"使用可能ストレージ" プールとも呼ばれる初期プールでは、コンクリート ストレージ プールの作成と削除でストレージ容量が描画され、返されます。 初期プールは作成、削除、または変更できません。
SMP は、少なくとも 1 つの初期プールを提供する必要があります。 物理ディスクをコンクリート ストレージ プールに追加しても、物理ディスクは初期プールの一部と見なす必要があります。
サイズ レポート
記憶域プール オブジェクトのさまざまなサイズ フィールドについては、ホット スペア ドライブからの容量と異常なドライブからの容量の 2 つの特別なケースについて説明します。
ドライブがホットスペア ドライブとして指定されたら、対応する初期プールの AllocatedSize にその容量を含める必要があります。 ただし、記憶域アレイがホット スペア ドライブを特定のコンクリート プールに割り当てることができる場合でも、ドライブの容量を具象プールのサイズに含めることはできません。 ホット スペア ドライブが特定のコンクリート プールに割り当てられた後、実際に使用されているドライブを置き換えるまで、ドライブの容量をコンクリート プールの AllocatedSize に含めてはなりません。 コンクリート プールに追加する場合、CanPooled は、このホットスペア ドライブの物理ディスク オブジェクトに対して FALSE にする必要があります。 この物理ディスク オブジェクトとコンクリート プールのストレージ プール オブジェクトの間に関連付けを作成する必要があります。
HealthStatus が "Unhealthy" のドライブからの容量は、原始的なプールまたはコンクリート プールのサイズ フィールドには含めてはなりません。
Associations
SM API には、ストレージ オブジェクト間のリレーションシップを定義する関連付けクラスが含まれています。 これらの関連付けクラスを使用すると、ストレージ オブジェクト階層を簡単に走査して、特定のオブジェクトの関連オブジェクトを取得できます。 Storage PowerShell モジュールの場合、コマンドレットのパイプ処理は関連付けクラスによって実現されます。 たとえば、仮想ディスク オブジェクトを指定すると、ユーザーは次のコマンドレットを使用して、仮想ディスク オブジェクトを所有するストレージ プールを取得できます。
PS> Get-VirtualDisk –FriendlyName MyVirtualDisk | Get-StoragePool
このセクションの残りの部分では、関連付けクラスの実装について説明します。 ノート内のメソッドは、各関連付けクラスの Convert-MofToProvider.exe によって生成されます。 ノートでは、関連付けクラスの例として XToY を使用します。擬似コードでは、例として StoragePoolToVirtualDisk を使用します。
- EnumerateInstances と GetInstance
- XToY\_EnumerateInstances returns association objects (XToY objects) for ALL X objects
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_EnumerateInstances( ... )
{
...
/** This method should return association objects for ALL Storage Pools. **/
// for each storage pool
// for each virtual disk that's associated with this storage pool
// create the StoragePoolToVirtualDisk association object
// set the storage pool object and virtual disk object to this association object
// post the association object
// end for
// end for
...
}
- AssociatorInstances
- AssociatorInstances method returns regular objects instead of association objects
- XToY\_AssociatorInstancesX should return all associated Y object(s) for the X specified
- XToY\_AssociatorInstancesY should return all associated X object(s) for the Y specified
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_AssociatorInstancesStoragePool(...)
{
...
/** This method should return VIRTUAL DISK object(s) for the
STORAGE POOL specified. **/
// for each virtual disk that's associated with this storage pool
// create the virtual disk object
// post the virtual disk object
// end for
...
}
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_AssociatorInstancesVirtualDisk(...)
{
...
/** This method should return STORAGE POOL object(s) for the
VIRTUAL DISK specified. **/
// for each storage pool that's associated with this virtual disk
// create the storage pool object
// post the storage pool object
// end for
...
}
- ReferenceInstances
- ReferenceInstances is similar to AssociatorInstances except that these methods return association (XToY) objects instead of regular objects
- XToY\_ReferenceInstancesX should return XToY object(s) for X specified
- XToY\_ReferenceInstancesY should return YToX object(s) for Y specified
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_ReferenceInstancesStoragePool(...)
{
...
/** This method should return StoragePoolToVirtualDisk
ASSOCIATION object(s) for the STORAGE POOL specified. **/
// for each virtual disk that's associated with this storage pool
// create the StoragePoolToVirtualDisk association object
// set the storage pool and virtual disk to this association object
// post the association object
// end for
...
}
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_ReferenceInstancesVirtualDisk(...)
{
...
/** This method should return StoragePoolToVirtualDisk
ASSOCIATION object(s) for the VIRTUAL DISK specified. **/
// for each storage pool that's associated with this virtual disk
// create the StoragePoolToVirtualDisk association object
// set the storage pool and virtual disk to this association object
// post the association object
// end for
...
}
キャッシュ管理
SMP が読み込まれると、ストレージ オブジェクトのキャッシュを初期化する必要があります。 この初期化により、オブジェクトを SMP のキャッシュから直接取得できるため、API 呼び出しにサービスを提供する際の応答時間が短縮されます。 このキャッシュは、インバンド オブジェクトの変更や帯域外オブジェクトの変更との同期を維持する必要があります。
インバンド オブジェクトの変更には、現在の SMP インスタンスを通じて行われた変更が含まれます。 たとえば、仮想ディスクが現在の SMP インスタンスを介して作成された場合は、次のようになります。
- 新しい仮想ディスク オブジェクトをキャッシュに追加する必要があります。
- 所有している記憶域プールや関連するターゲット ポート オブジェクトなど、関連付けられているオブジェクトも更新する必要があります。
帯域外の変更には、ベンダー独自のツールや他のマシンでホストされている SMP を通じて行われた変更が含まれます。 たとえば、ベンダー独自のツールを使用して仮想ディスクを作成する場合は、キャッシュ更新をトリガーするために、ストレージ サブシステムから SMP にイベントを送信する必要があります。
また、ストレージ プロバイダー クラスから Discover メソッドが呼び出されたときに、SMP によってキャッシュが更新されます。 ストレージ管理アプリケーションは、このメソッドを呼び出して、サービスの再起動やシステムの再起動などのイベントでキャッシュをリセットおよび再構築します。
SMP が起動時にキャッシュ全体を初期化できない場合 (オブジェクトが多すぎるため、またはすばやく実行できないため)、ストレージ プロバイダーオブジェクトとストレージサブシステムオブジェクトのみをキャッシュに読み込む必要があります。 アプリケーションは、ストレージ サブシステム オブジェクトの CurrentCacheLevel プロパティを見て、キャッシュの深さを確認します。 エンド ユーザーまたはアプリケーションは、Discover メソッドを使用してキャッシュの残りの部分を明示的に読み込みます。
非同期操作
完了までに 30 秒を超える操作は、ストレージ ジョブ オブジェクトを返す必要があります。 CreatedStorageJob 出力パラメーターを含むメソッドは、この種類の操作である可能性が最も高くなります。 SMP は、これらすべてのメソッドを非同期操作として実装し、それらに対してストレージ ジョブ オブジェクトを返す必要があります。 ストレージ ジョブ オブジェクトは、30 秒以内に呼び出し元に返される必要があります。それ以外の場合、呼び出し元は、待機時間が長すぎてストレージ ジョブ オブジェクトをまだ受信していない場合にタイムアウトする可能性があります。
アプリケーション (または "WMI クライアント") には、メソッドを "RunAsJob" にするかどうかを指定するオプションがあります。 アプリケーションが使用する SM API には、この追加のブール値 RunAsJob パラメーターと CreatedStorageJob 出力パラメーターが含まれています。 一方、SMP インターフェイスの対応するメソッドには CreatedStorageJob パラメーターしかありません。 ただし、"RunAsJob" の値に関係なく、SMP は常にこれらのメソッドのストレージ ジョブ オブジェクトを返す必要があります。
次のシナリオは、非同期操作の呼び出しシーケンスを示しています。 CreateVirtualDisk は次のような場合に使用されます。
"RunAsJob" が TRUE に設定されている場合
CreateVirtualDisk が呼び出されると、SMP はメソッドの初期化を行い、ストレージ サブシステムでジョブを開始し、30 秒以内にストレージ ジョブ オブジェクトを呼び出し元に返す必要があります。 ただし、記憶域サブシステムは操作を完了するまでに任意の時間を要する場合があります。 呼び出し元は、この期間中にジョブの状態をポーリングします。
ワーカー スレッドを使用してジョブを実行する必要があります。 効率を高める目的で、SMP は、呼び出し元がそのジョブの状態をポーリングする場合にのみ、ジョブの状態に関連する属性 (PercentComplete など) を更新できます。
"RunAsJob" が FALSE に設定されている場合
呼び出し元は、メソッドが戻るまで CreateVirtualDisk メソッドでブロックされます。 SM API は、ブロックとポーリング自体を自動的に実行します。 通常、この種類の呼び出し元は、ブロック メカニズムを優先する非ユーザー対話型クライアント (スクリプト ツールなど) です。
新しく作成されたオブジェクトに関する情報を取得する唯一の方法は、このオブジェクトと対応するストレージ ジョブ オブジェクトの間の関連付けであるため、SMP は、キャッシュから削除する前に、ストレージ ジョブ オブジェクトを少なくとも 24 時間保持する必要があります。 新しく作成されたオブジェクトを返さないその他の操作 (DeleteObject 操作など) の場合、関連付けは必要ありません。ストレージ ジョブ オブジェクトは 15 分間だけ存続する必要があります。
管理コンソールで予期しないシステム再起動が発生した場合、SMP は StorageJob オブジェクトのキャッシュをストレージ アレイなどの物理的な場所に保持し、システムの再起動時にキャッシュを再読み込みする必要があります。
プロバイダーの有効期間の制御
SMP は、結合プロバイダーまたは分離プロバイダーとして実装できます。 これら 2 種類のプロバイダーの違いについては、WMI MSDN のドキュメントを参照してください。
分離されたプロバイダーは、ベンダー固有のプロセスで読み込まれ、ホストされます。 通常、このプロセスは常に実行されるサービスです。
プロバイダーの起動にはキャッシュの再読み込みが含まれるため、時間がかかる場合があります。 SMP スタートアップで読み込みに 1 秒以上必要な場合は、永続的キャッシュを介してストレージ オブジェクトを管理するために、分離されたプロバイダーを実装することをお勧めします。 このアプローチは、Windows SM API を使用して SMP を管理するアプリケーションの全体的なパフォーマンスと応答性を高めるのに役立ちます。
Windows SDK からの DecoupledHost サンプルでは、分離されたプロバイダーの詳細が提供されます。
表示
アプリケーション開発者は、オブジェクトの状態が変化したときにその変化について知りたいことがよくあります。 これを行うには、WMI の表示をサブスクライブします。 表示は別の種類のクラスです。これらは非同期的に公開され、管理操作から帯域外になることがあり、永続化されません。 使い慣れた組み込みメソッド (EnumerateInstances/GetInstance) を実装する代わりに、サポートする必要がある新しいメソッドがあります。
表示には 4 つの種類があります。
- 到着 – この表示は、デバイスまたはオブジェクト インスタンスがサブシステムに追加されるときに使用されます。 例: サブシステムへの新しい物理ディスクの追加、または仮想ディスクの作成。
- 出発 – この表示は、デバイスまたはオブジェクト インスタンスがサブシステムから削除されるときに使用されます。 例: サブシステムからの物理ディスクの削除、または疎ストレージ プールの削除。
- 変更 – この表示は、既存のオブジェクトで重要なプロパティが変更されたときに使用されます。 少なくとも、HealthStatus と OperationalStatus の変更によって Modify 表示がトリガーされる必要があります。 オブジェクトの動作状態に関連するその他のプロパティの変更を表示するよう強くお勧めします。
- アラート – この表示は、アプリケーションに潜在的な問題を警告するために使用されます。 現時点で定義されているアラートは、シン プロビジョニングのしきい値に達した場合の通知のみです。
表示を実装するには、各インジケーター クラスに実装する必要がある 2 つの新しい組み込みメソッドがあります。
- EnableIndication – 表示クラスをサブスクライブする要求が行われました。 indicationContext は、後の時点で通知で投稿できるように、保存する必要があります。
- DisableIndication – 表示クラスのサブスクライバーはこれ以上ありません。 クリーンアップを行う必要があり、このクラスの兆候をポストする必要はありません。 indicationContext は、この時点で破棄されます。
展開
選択した "管理サーバー" に SMP がインストールされます。 これらのサーバーは、冗長性を提供するためにクラスター化できます。 他のサーバーは、iSCSI またはファイバー チャネル経由で割り当てられたストレージにアクセスします。 これらのマシンはすべて、サーバー マネージャーからファイル サーバー ユーザー インターフェイスを実行するサーバーによって管理できます。
ただし、ストレージ ベンダーは、要件に最も適したデプロイ モデルを選択できます。
セキュリティ モデル
SMP インターフェイスでは、Windows セキュリティ資格情報を使用したシングル サインオン (SSO) モデルがサポートされています。
SSO モデルでは、ユーザーは Windows 資格情報を使用して "管理マシン" に 1 回ログインし、アクセス許可を持つすべてのストレージ資産に自動的にアクセスします。 ストレージ サブシステムのサインイン用に資格情報を追加する必要はありません。
このインターフェイスにより、ストレージ管理者は個々のストレージ アセットに対するアクセス制御を管理することもできます。 ストレージ資産ごとに、ストレージ管理者は GetSecurityDescriptor メソッドと SetSecurityDescriptor メソッドを使用して、任意の Windows ユーザーに異なるアクセス権を付与できます。 その結果、SMP は VDS モデルとは異なり、任意の種類のユーザー アカウントから要求を受信できるようになりました。
SSO モデルを実装するには、SMP がストレージ サブシステムに対して Windows クライアントを認証する必要があります。 ストレージ サブシステムは、各ストレージ アセットのセキュリティ記述子情報を保持する必要があります。 認証を実装するために、ストレージ ベンダーには次の 2 つの選択肢があります。
- サブシステムでの認証 (推奨)
- 各 SMP インスタンスでの認証。
どちらのオプションでも、セキュリティ記述子とユーザー ID 情報を安全に渡すことができるように、SMP とストレージ サブシステムの間に信頼関係を確立する必要があります。
ストレージ サブシステムにシームレスな認証と承認を実装するには、SMP とストレージ サブシステムの間のリンクを使用して、Kerberos、NTLM、または SPNego を実装することをお勧めします。 ストレージ サブシステムに Web サーバーが配置されている場合は、"NTLM over HTTP" プロトコル [MS-NLMP] の方が役立つ場合があります。 ストレージ ベンダーは、SSO モデルを実装するために独自のプロトコルを維持することを選択できます。 ただし、Windows でサポートされている認証プロトコルの 1 つを実装するよりも多くの作業やセットアップが行われることがあるため、この方法はお勧めしません。
Windows セキュリティ ポリシーをサポートするには、ストレージ サブシステムがユーザーの "トークン情報" を取得する必要があります。これには、ユーザーのセキュリティ識別子 (SID) と、ユーザーがメンバーになっているグループの SID が含まれます。 Kerberos、NTLM、または SPNego プロトコルが実装されている場合、ストレージ サブシステムは、プロトコルの一部としてユーザーのトークン情報を取得します。 SMP とストレージ サブシステムの間でベンダー独自のプロトコルが使用されている場合、ストレージ サブシステムは、ライトウェイト ディレクトリ アクセス プロトコル (LDAP) を使用して Active Directory からユーザーのトークン情報を照会し、ユーザーのアカウント オブジェクトの tokenGroupsGlobalAndUniversal 属性または Object-Sid 属性を確認できます。
ユーザーのトークン情報を使用して、Windows セキュリティ ポリシーを適用するには、[MS-DTYP] で説明されているアクセス チェック アルゴリズムをストレージ サブシステムに実装する必要があります。
ストレージ ベンダーがこの SSO モデルをサポートしないことを選択した場合は、SMP が VDS のセキュリティ モデルに従うことをお勧めします。管理者アカウントから開始された操作のみを許可します。 ただし、このチェックは、SMP 自体で実行する必要があります。