👀

Postmanを使ってREST APIで物理サーバーを操作する(入門編)

2022/08/21に公開

はじめに

最近(といってももはやここ10年弱くらい)の物理サーバーがREST APIで操作できるようなっているのご存知でしたか?メーカー側も世の中のトレンドにあわせて便利に使ってもらえるように製品開発を進めているわけです。なのでサーバーの電源オン・オフなどの操作も昔からあるIPMIやSSH経由のSM-CLP(SMASH)だけでなく、CurlコマンドやPostmanで実行したりPythonなどで通常のWeb APIを扱うのと同じ感覚でスクリプトを書いたりもできたりします。

今後数回の投稿でサーバーのリモート管理の話を情報共有していこうかなと思います。

投稿一覧

第1回: BMC(Basebord Management Controller)全般について
第2回: サーバー管理用REST API (DMTF Redfish)の基本的な使い方と、Redfishを使うときに便利なPostmanの変数・スクリプトの使い方(本投稿です)
第3回: PostmanとREST API(Redfish)を使ったサーバーの具体的な操作やスキーマの見方など
第4回(予定): ファームウェア更新やBIOS設定変更、イベントやテレメトリーなど

Redfish APIについて

サーバー管理用のREST APIですが、メーカー各社や製品ごとにAPIがバラバラだとユーザーの皆様にとって不便なので業界の標準団体DMTF (Distributed Management Task Force)Redfish APIとして標準化しており、各社ともそれに準拠した実装をしています。

IPMIが標準でできることが限られていて、結果的に各社独自のOEM拡張がかなり多くなってしまったことや、OEM拡張は16進数のオプションと戻り値を使うrawコマンド形式で非常に使いづらかったことを反省し、Redfish標準にも各社が自由にできるOEM拡張の仕組みはあるものの、標準部分を充実させて各社にOEM拡張を使う動機を与えないようにすることがデザイン目標の一つとなっています。

Redfishの主な特徴は

  • RESTfulなインターフェースとデータモデル表現を用いた管理標準
  • モデル指向なのでコンポーネント間の関係やセマンティクスを表現可能
  • データモデルは相互運用可能なスキーマで定義。OpenAPI YAML、OData CSDL、JSONスキーマの各フォーマットで公開中
  • JSONを使うのでプログラミング環境との統合が簡単、かつ人間にも読みやすい

Redfishは/redfish/v1がサービスルートで、ざっくり以下の図のようなリソースマップで表されます。普通に使う場合に重要なのは以下の6つくらいですね。

  • /redfish/v1/Chassis: サーバーの物理構成
  • /redfish/v1/Systems: サーバーの論理構成
  • /redfish/v1/Managers: Redfishサービスを提供するBMC設定(BMCのIPアドレスなど)
  • /redfish/v1/SessionService: Redfish含めたセッション管理
  • /redfish/v1/Task: すぐに終わらない処理を管理(ファームウェア更新など)
  • /redfish/v1/Event: イベントのサブスクリプション

図1: Redfishのリソースマップ

実際にRedfishを使ってみる

サービスルート

まずPostmanでサービスルート(/redfish/v1)にアクセスしてみます。サービスルートはRedfishサービスで唯一認証が必要なく、サービスルート直下にどんなリソースが実装されているか確認できます。基本的には先ほどの図のリソースが返ってくるはずです。また、各リソースはリンクで辿れるようになっているので便利です。
ちなみにURIの{{baseUrl}}というのはPostmanの変数で管理対象のサーバーIPアドレスを設定しています。サーバーが複数台あるときに管理対象を切り替えるのに便利です。
図2: サービスルート

ユーザー認証

サービスルート(/redfish/v1)は認証が必要ありませんが、それ以外のURIにアクセスするにはユーザー認証が必要です。認証に失敗すると401 UnauthorizedのHTTPステータスコードが返ってきます。

ユーザー認証にはベーシック認証(Basic Auth)またはセッションを確立する方法があります。

単発の操作はベーシック認証でも構いませんが、続けて色々と操作する場合にはセッションを確立します。ベーシック認証で連続操作を行うと、ログが認証で埋め尽くされ、他の重要なイベント(たとえばハードウェアの故障など)が埋もれて見落とすことになってしまったりします🤭

ベーシック認証

ベーシック認証は単純明快ですね。Authorizationタブで認証タイプにBasic Authを選び、ユーザー名とパスワードを設定すればOKです。
図3: ベーシック認証

セッション作成

セッションを作成するには/redfish/v1/SessionsにユーザーとパスワードをJSONのペイロードとしてPOSTします。成功すると201 Createdのステータスコードが返ってきます。なお、以下のスクリーンショットは緑の点線より上がリクエストで、点線より下がレスポンスです。
図4: セッション作成

セッションを作成するとレスポンスヘッダーで認証トークンとロケーションURIが返ってくるので確認しましょう。

  • X-Auth-Token: これ以降のAPIリクエストのヘッダーで指定します
  • Location: このURIにDELETEをリクエストすることでRedfishのセッションを終了します。

なお、ここではX-Auth-Tokenは隠していませんが、本番環境では不正なユーザーに知られないようにご注意ください。

セッション終了

作成したばかりですが、練習ということでセッションを終了してみます。リクエストヘッダーにX-Auth-Tokenを指定して、Locationに対してDELETEをリクエストします。セッション終了が成功すると200 OKのステータスコードが返ってきます。
図5: セッション終了

Postmanの変数とスクリプト

以上、サービスルートを眺めてセッションを作成・終了してみましたが、X-Auth-TokenLocationを毎度コピペするのは面倒ですね。

Postmanでは変数が使えるので、レスポンスで返され値を自動で変数に設定し、リクエストのヘッダーやURIにあらかじめ変数を設定しておけばコピペなしで使えて便利ですね。

Postmanの変数には何種類かのスコープがありますが、Redfishのレスポンスボディーで渡されたURIをクリックして新しいリクエストを投げるような使い方をする場合はグローバル変数を使うのが楽です。(環境変数やコレクション変数だと、いちいちコレクションに保存しないといけないので面倒です。)
ただし、リクエストを保存していって他の人とコレクションをシェアするような場合はコレクション変数を使った方が変数がなくて動かないというエラーがなくて親切ですね。

Postmanにはリクエストの前処理として実行できるPre-request Scriptタブと後処理として実行できるTestsタブがあります。

今やりたいことは、セッションを作成したときのレスポンスヘッダーで渡されるX-Auth-TokenLocationの値を変数に設定したいので、セッションを作成するリクエストのTestsタブに以下のようなスクリプトを記述します。

let ok = responseCode.code === 201

if(ok){
    pm.globals.set('iLO_X-Auth-Token', responseHeaders['X-Auth-Token']);
    pm.globals.set('iLO_Location', responseHeaders.Location);
}

また、グローバル変数にX-Auth-TokenLocationを用意しておきます。変数によってはベンダ間でフォーマットが微妙に違ったりすることがあったりするので、そういう差異を吸収できるよう私は2段構えにしています。

今回の場合は、X-Auth-Tokenは大丈夫なのですが、Locationはベンダ間で違いがあります。HPE iLOのLocationはIPアドレスを含めて返ってくるのですが(この記事で既出のセッション作成のスクリーンショットで確認できます)、Dell iDRACのLocationはサービスルート以下で返ってきます。
図6: Dellの戻り値

なので、LocationiLO_Locationを参照することにして、iLO_Locationという変数にレスポンスヘッダーで渡された値を設定しています。ちなみにiDRAC用にもidrac_Locationという変数を用意して、それを参照するLocationという変数をもう一つ用意しておき、使う際にグローバル変数の編集画面でどちらを使うか切り替えています。(画面には使用中の変数しか表示されていません)
図7: グローバル変数

そして今度は設定した変数を利用してセッションを終了してみたいと思います。

そのためには、セッションのDELETEリクエストのターゲットURIに変数Locationを指定し、ヘッダーにX-Auth-Tokenを指定します。

この状態でリクエストを投げると無事にセッションが終了できました。
図8: 変数を使ったセッション終了

おまけ - コレクション変数や環境変数を使う場合のスクリプト

Postmanの変数には何種類かのスコープがあって、Redfishのレスポンスボディーで渡されたURIをクリックして新しいリクエストを投げるような使い方をする場合はいちいちコレクションに保存しないくていいのでグローバル変数が楽ですよと前述しました。

ただし、リクエストを保存していって他の人とコレクションをシェアするような場合はコレクション変数を使った方が変数がなくて動かないというエラーがなくて親切ですね。

コレクション変数を使う場合は、コレクション変数を用意して以下のスクリプトをTestsタブに記述します。

let ok = responseCode.code === 201

if(ok){
    pm.collectionVariables.set('idrac_X-Auth-Token', responseHeaders['X-Auth-Token']);
    pm.collectionVariables.set('idrac_Location', responseHeaders.Location);
}

ついでで環境変数を使いたい場合も同様に、環境変数を用意して以下のスクリプトをTestsタブに記述すると大丈夫です。

let ok = responseCode.code === 201

if(ok){
    pm.environment.set('idrac_X-Auth-Token', responseHeaders['X-Auth-Token']);
    pm.environment.set('idrac_Location', responseHeaders.Location);
}

まとめ

以上、簡単ですがPostmanでRedfishを触ってみました。キリがいいので本投稿はここまでにします。

次回の投稿でもう少し実践的なサーバーの操作やRedfishをもう少し詳しく紹介したいと思います。

GitHubで編集を提案

Discussion