# 機能設計書 134-FlexVolumeプラグイン

## 概要

本ドキュメントは、Kubernetes における FlexVolume プラグインの機能設計を記述する。FlexVolume は外部ボリュームドライバーを exec ベースのインターフェースで Kubernetes に統合するフレームワークである。

### 本機能の処理概要

**業務上の目的・背景**：CSI (Container Storage Interface) 登場以前に、サードパーティストレージベンダーが Kubernetes にストレージドライバーを統合するための拡張メカニズムとして設計された。ノード上に配置された実行可能ファイルを呼び出すことで、カスタムストレージの Attach/Mount/Unmount/Detach を実現する。

**機能の利用シーン**：CSI ドライバーが利用できない環境や、レガシーストレージシステムとの統合が必要な場合に使用される。ただし、CSI が推奨される現在では新規利用は推奨されていない。

**主要な処理内容**：
1. ドライバー実行ファイルの検出と初期化（init コマンド）
2. ドライバーの capabilities 検出（Attach サポート、メトリクス対応等）
3. ドライバー実行ファイルへの各種コマンドの exec 呼び出し
4. Attach/Detach サポートの有無に応じたプラグインタイプの切り替え
5. ボリュームの Mount/Unmount、Expand のドライバー委譲

**関連システム・外部連携**：外部 FlexVolume ドライバー実行ファイル（ノード上の指定ディレクトリに配置）

**権限による制御**：PV/PVC の RBAC によるアクセス制御。ドライバー実行ファイルはノード上の権限で実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は PV/PVC 定義を通じて Kubelet が自動的に実行する |

## 機能種別

ボリュームライフサイクル管理（Attach/Mount/Unmount/Detach/Expand） - 外部ドライバー委譲型

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| driver | string | Yes | FlexVolume ドライバー名 | vendor/driver 形式 |
| fsType | string | No | ファイルシステムタイプ | ext4, xfs 等 |
| secretRef | LocalObjectReference | No | Secret 参照 | 有効な Secret 名 |
| readOnly | bool | No | 読み取り専用フラグ | true/false |
| options | map[string]string | No | ドライバー固有のオプション | キーバリューペア |

### 入力データソース

- PersistentVolume の `.spec.flexVolume` フィールド
- Volume の `.flexVolume` フィールド

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| mountPath | string | Pod 内のマウントポイントパス |
| devicePath | string | ドライバーが返すデバイスパス（Attach サポート時） |

### 出力先

- Pod のボリュームマウントパス

## 処理フロー

### 処理シーケンス

```
1. プラグイン検出
   └─ pluginDir 内のドライバー実行ファイルを検索
2. ドライバー初期化
   └─ init コマンドを exec で実行し、capabilities を取得
3. プラグインタイプ決定
   └─ Attach をサポートする場合は flexVolumeAttachablePlugin、しない場合は flexVolumePlugin
4. Volume操作
   └─ 各操作（attach/detach/mount/unmount/expand等）をドライバーに exec で委譲
5. 結果解析
   └─ ドライバーの stdout から JSON レスポンスをパースし、結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[PluginFactory.NewFlexVolumePlugin] --> B[init コマンド実行]
    B --> C{init 成功?}
    C -->|No| D[エラー返却]
    C -->|Yes| E[capabilities 取得]
    E --> F{Attach サポート?}
    F -->|Yes| G[flexVolumeAttachablePlugin 返却]
    F -->|No| H[flexVolumePlugin 返却]
    G --> I[ボリューム操作]
    H --> I
    I --> J[DriverCall で exec 実行]
    J --> K[JSON レスポンス解析]
    K --> L[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-134-01 | ドライバーパス | ドライバー実行ファイルは `{pluginDir}/{driverName}/{execName}` に配置 | 常時 |
| BR-134-02 | capabilities による分岐 | Attach サポートの有無でプラグインタイプが変わる | プラグイン初期化時 |
| BR-134-03 | 未サポートコマンドの記録 | サポートされないコマンドはリストに記録し、以降の呼び出しをスキップ | コマンド実行時 |
| BR-134-04 | GetVolumeName フォールバック | ドライバーが GetVolumeName をサポートしない場合、PV名またはボリューム名をデフォルトとする | GetVolumeName 呼び出し時 |
| BR-134-05 | RequiresFSResize | ドライバーの capabilities.RequiresFSResize に従う | Expand 操作時 |

### 計算ロジック

- ドライバー実行パス: `{pluginDir}/{vendorName~driverName}/{driverName}`（Windowsの場合はパス変換あり）

## データベース操作仕様

本機能にはデータベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | init 失敗 | ドライバーの初期化コマンドが失敗 | プラグイン登録失敗としてエラー返却 |
| - | コマンド未サポート | ドライバーが特定コマンドをサポートしない | デフォルト動作にフォールバック |
| - | exec 失敗 | ドライバー実行ファイルの実行失敗 | エラー返却 |
| - | JSON パース失敗 | ドライバーの出力が不正な JSON | エラー返却 |

### リトライ仕様

FlexVolume プラグイン内部にリトライ機構はない。リトライは kubelet の sync loop に委ねる。

## トランザクション仕様

FlexVolume 操作にトランザクション管理は存在しない。各コマンドは独立した exec 呼び出しとして実行される。

## パフォーマンス要件

- 各コマンドの実行時間はドライバー実装に依存
- exec ベースのため、プロセス起動のオーバーヘッドが発生する

## セキュリティ考慮事項

- ドライバー実行ファイルはノード上で特権的に実行される可能性がある
- Secret は Pod の Namespace から取得し、ドライバーに渡される
- SupportsMountOption は false（ドライバーが独自にマウントオプションを管理）
- SELinux コンテキストマウントは非サポート

## 備考

- プラグイン名: `kubernetes.io/flexvolume`（ベース名。実際のプラグイン名はドライバー名）
- CSI が推奨される現在、FlexVolume は既存環境の互換性維持のために残されている
- サポートするアクセスモード: ReadWriteOnce, ReadOnlyMany

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | plugin.go | `pkg/volume/flexvolume/plugin.go` | flexVolumePlugin 構造体（41-50行目）: driverName, execPath, capabilities が中核 |
| 1-2 | volume.go | `pkg/volume/flexvolume/volume.go` | flexVolume 構造体: ドライバー情報と Pod 情報を保持 |
| 1-3 | driver-call.go | `pkg/volume/flexvolume/driver-call.go` | DriverCall 構造体: exec 呼び出しのパラメータとレスポンス管理 |

#### Step 2: プラグイン初期化

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | plugin.go | `pkg/volume/flexvolume/plugin.go` | NewFlexVolumePlugin()（70-95行目）: init コマンドで capabilities を取得し、Attach対応に応じてプラグインタイプを決定 |

**主要処理フロー**:
- **71行目**: execPath を pluginDir + name から構築
- **83-84行目**: init コマンドを exec で実行
- **88行目**: capabilities を保存
- **90-94行目**: Attach サポートに応じて返却するプラグインタイプを分岐

#### Step 3: Mounter/Unmounter 生成

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | plugin.go | `pkg/volume/flexvolume/plugin.go` | newMounterInternal()（173-209行目）: ドライバー名抽出、メトリクスプロバイダ設定 |
| 3-2 | mounter.go | `pkg/volume/flexvolume/mounter.go` | SetUpAt(): ドライバーの mount コマンドを exec で実行 |
| 3-3 | unmounter.go | `pkg/volume/flexvolume/unmounter.go` | TearDownAt(): ドライバーの unmount コマンドを exec で実行 |

### プログラム呼び出し階層図

```
PluginFactory.NewFlexVolumePlugin()
    │
    ├─ flexVolumePlugin / flexVolumeAttachablePlugin
    │
    ├─ NewMounter() → flexVolumeMounter
    │      └─ SetUpAt()
    │             └─ DriverCall(mountCmd).Run()
    │
    ├─ NewUnmounter() → flexVolumeUnmounter
    │      └─ TearDownAt()
    │             └─ DriverCall(unmountCmd).Run()
    │
    ├─ NewAttacher() → flexVolumeAttacher [Attach対応時のみ]
    │      ├─ Attach() → DriverCall(attachCmd).Run()
    │      └─ WaitForAttach() → DriverCall(waitForAttachCmd).Run()
    │
    ├─ NewDetacher() → flexVolumeDetacher [Attach対応時のみ]
    │      └─ Detach() → DriverCall(detachCmd).Run()
    │
    └─ NodeExpand() → DriverCall(expandVolumeCmd).Run()
```

### データフロー図

```
[入力]                    [処理]                       [出力]

PV/Volume Spec      ──▶ getDriver()              ──▶ driverName
  (driver, options)

driverName          ──▶ NewFlexVolumePlugin()     ──▶ plugin (with capabilities)
                         init コマンド exec

volume spec +       ──▶ DriverCall.Run()          ──▶ JSON response
pod info                  exec 実行                    (status, device, etc.)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| plugin.go | `pkg/volume/flexvolume/plugin.go` | ソース | プラグイン本体。初期化、Mounter/Unmounter 生成 |
| volume.go | `pkg/volume/flexvolume/volume.go` | ソース | flexVolume 構造体定義 |
| driver-call.go | `pkg/volume/flexvolume/driver-call.go` | ソース | exec 呼び出しの実装 |
| mounter.go | `pkg/volume/flexvolume/mounter.go` | ソース | Mounter 実装 |
| unmounter.go | `pkg/volume/flexvolume/unmounter.go` | ソース | Unmounter 実装 |
| attacher.go | `pkg/volume/flexvolume/attacher.go` | ソース | Attacher 実装 |
| detacher.go | `pkg/volume/flexvolume/detacher.go` | ソース | Detacher 実装 |
| expander.go | `pkg/volume/flexvolume/expander.go` | ソース | Expander 実装 |
| probe.go | `pkg/volume/flexvolume/probe.go` | ソース | ドライバーの自動検出 |
| util.go | `pkg/volume/flexvolume/util.go` | ソース | ユーティリティ関数 |
