コンテンツにスキップ

xoa-proxy

XOA のイメージを XAPI へ流し込む、Rust 製の HTTP/HTTPS プロキシです。

リポジトリ: Vagrantin/xoa-proxy · 言語:Rust · ライセンス:AGPL-3.0

目的

XO Lite で手を入れた「Deploy XOA」ボタンを押すと、XAPI は .xva という VM のアーカイブを取り込む必要があります。XAPI は URL を指定して VM.import を呼びますが、その URL のサーバーには HTTP でのみファイルを配信することを 求め、ファイルは XVA 形式でなければなりません。

この制約は私にとって物足りないもので、当初は行き詰まりの原因でもありました。 Ronivay 氏のイメージを使っていたのですが、これは gz 形式で、HTTPS でしか 取得できなかったからです。

そのため xoa-proxy は、XAPI の手前に立つ窓口として、HTTP と HTTPS (自己署名証明書を含む)に対応し、さらに XVA に加えて gz 形式にも対応 します。

このプロキシがあることで、ローカルを含むさまざまな場所からイメージを取り込む 柔軟性が生まれ、HTTPS への対応によって安全性も高まります。


設計

技術の選択

選択理由
Rustメモリー安全性が高く、Dom0 で長時間動き続けるサーバープロセスに向いています

リクエストの流れ

XO Lite(ブラウザー)
    │  HTTP GET /image.xva
    ▼
xoa-proxy
    │
    │ XAPI 向けの HTTP/HTTPS の窓口
    │ gzip 形式をその場で展開
    │
    ▼
XAPI VM.import
    │  ローカルの SR に VDI を書き込む
    ▼
XOA の VM が作成される

HTTP と HTTPS

xoa-proxy は、上流の XOA イメージを取得するときに HTTP と HTTPS の両方 (自己署名証明書を含む)に対応します。ダウンロード中、gzip で圧縮された イメージはその場で展開されるため、XAPI が受け取るのは常に圧縮されていない 生の XVA のストリームです。

XAPI への VM.import による受け渡しは、意図的に HTTP/1.0 で行っています。 XAPI はチャンク転送エンコーディング(HTTP/1.1 の機能)に対応していないため、 HTTP/1.1 の形式を使うと取り込みが壊れてしまいます。プロキシがこの制約を 内部で処理するので、呼び出す側で設定することはありません。


コードの構成

xoa-proxy/
├── src/
│   └── main.rs        ← HTTP サーバー、リクエストの処理、ストリームの制御
├── tests/             ← 結合テスト
├── .cargo/            ← Cargo の設定(クロスコンパイルの設定)
├── Cargo.toml         ← 依存:hyper、tokio、tokio-util など
└── Cargo.lock

ストリーム処理の中心となる書き方

このプロキシの中心は、tokio::fs::File を、ファイル全体をメモリーに 読み込むことなく hyper のレスポンスボディに変換する部分です。

use tokio_util::io::ReaderStream;
use hyper::Body;

let file = tokio::fs::File::open("image.xva").await?;
let stream = ReaderStream::new(file);
let body = Body::wrap_stream(stream);

let response = Response::builder()
    .header("Content-Type", "application/octet-stream")
    .header("Content-Encoding", "gzip")
    .body(body)?;

ビルド

事前に必要なもの

  • Rust のツールチェーン(stable):rustup で導入します
  • Dom0 向けのクロスコンパイルには x86_64-unknown-linux-musl ターゲット
# ネイティブのビルド(テスト用)
cargo build

# Dom0 向けのクロスコンパイル(musl の静的バイナリー)
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

できあがる target/x86_64-unknown-linux-musl/release/xoa-proxy は、共有ライブラリーに 依存しない完全な静的実行ファイルで、XCP-ng の DOM0 環境に組み込むのに 適しています。

開発やテストのためにローカルで動かす

# テスト用の XVA を所定のパスに置く
cp /path/to/test.xva image.xva

# プロキシを起動する
./target/release/xoa-proxy

# ストリーム配信を試す
curl -v http://127.0.0.1:3000/image.xva -o /dev/null

設定

現在のリリースでは、待ち受けアドレスとイメージのパスはコードに直接書かれて います。

項目現在の値
待ち受けアドレス127.0.0.1:3000
プロキシのエンドポイントimage.xva

GPG 署名

xoa-proxy の RPM は、XCP-hl の鍵ペアの RPM 署名用サブキーで署名しています。このサブキーは xolite-ce と 共通で、2 つの RPM に対してサブキーは 1 つだけです。

プロジェクトの共通の公開鍵は 本番サイトのルートで配布しています。インポート前にマスター鍵のフィンガープリントを 確認してください。以下のコマンドには署名サブキーに対応した RPM が必要です。 XCP-ng 8.3 の Dom0 は古い RPM 4.11 を使用するため、ホストでは repo_gpgcheck=1 で署名付きリポジトリメタデータを検証します。 アップデートに記載のリポジトリ設定を維持してください。

ローカルで RPM を検証するには次のようにします。

curl -fLO https://vagrantin.github.io/xcp-hl/xcp-ng-ce-public.asc
gpg --show-keys --with-fingerprint xcp-ng-ce-public.asc
# 2F59 1DB9 D2C1 28C4 C3D9 63F4 6DA0 0DCA 5BBA 215A
rpm --import xcp-ng-ce-public.asc
rpm --checksig xoa-proxy-*.rpm

XO Lite CE との連携

xolite-ce の XO Lite パッチは、展開先の URL を http://127.0.0.1:3000/image.xva に設定します。これは、XCP-hl のホストで 起動したときに xoa-proxy が待ち受けるアドレスです。


テスト

# ユニットテストと結合テストを実行する
cargo test

# 結合テストは tests/ にあります
# プロキシを起動して、ストリーム配信の動作を確認します

開発に参加する

問題の報告や変更の提案は、Vagrantin/xcp-hlで issue を作ってください。