# 通知設計書 57-ExternalProvisioning

## 概要

本ドキュメントは、外部プロビジョナーによるPersistentVolumeのプロビジョニングが開始された際に発行されるイベント通知「ExternalProvisioning」の設計について記述する。

### 本通知の処理概要

**業務上の目的・背景**：KubernetesのStorageClassで外部プロビジョナー（CSIドライバー等）が指定されている場合、PVCの動的プロビジョニングはKubernetes内蔵のプロビジョナーではなく外部プロビジョナーに委任される。この通知は、PVCに対する外部プロビジョニングが開始されたことをクラスタ管理者に通知し、ボリューム作成が外部プロビジョナーに委任された状態であることを可視化する。プロビジョニングが遅延している場合、この通知によりプロビジョナーの稼働状態を確認するきっかけを提供する。

**通知の送信タイミング**：PV Controllerの `provisionClaimOperationExternal` 内で、外部プロビジョナーのアノテーションをPVCに設定した後に発行される。CSI移行（CSI Migration）が有効な場合は、in-treeプラグイン名からCSIプラグイン名への変換後に設定される。

**通知の受信者**：PVCオブジェクトに対するKubernetes Eventとして発行される。`kubectl describe pvc` や `kubectl get events` で監視しているクラスタ管理者、ストレージ管理者が受信者となる。

**通知内容の概要**：外部プロビジョナー名とボリューム作成を待機している旨、およびプロビジョナーが稼働しているか確認するようガイダンスが含まれる。

**期待されるアクション**：通常は対応不要だが、プロビジョニングが長時間完了しない場合は、外部プロビジョナー（CSIドライバー等）のログと稼働状態を確認する。

## 通知種別

Kubernetes Event（EventType: Normal）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（provisionClaimOperationExternalはgoroutineで実行） |
| 優先度 | 低（情報通知） |
| リトライ | 不要（通知のみ。プロビジョニング自体の再試行は外部プロビジョナーが担当） |

### 送信先決定ロジック

PVCオブジェクトに対してEventを発行する。

## 通知テンプレート

### Kubernetes Event

| 項目 | 内容 |
|-----|------|
| 送信元コンポーネント | pv controller |
| EventType | Normal |
| Reason | ExternalProvisioning |
| 関連オブジェクト | PersistentVolumeClaim |

### 本文テンプレート

```
Waiting for a volume to be created either by the external provisioner '%s' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| provisionerName | 外部プロビジョナー名 | StorageClass.Provisioner（またはCSI移行後の名前） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| PV Controller同期 | provisionClaimOperationExternal | 外部プロビジョナーアノテーションの設定成功後 | pv_controller.go 1857行目 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| in-treeプラグイン存在 | in-treeプロビジョナーが見つかった場合はprovisionClaimOperationが呼ばれる |
| CSI名変換失敗 | CSI移行時の名前変換が失敗した場合はProvisioningFailedが発行される |
| PVCアノテーション設定失敗 | setClaimProvisionerが失敗した場合はProvisioningFailedが発行される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[provisionClaim開始] --> B{in-treeプラグイン存在?}
    B -->|Yes| C[provisionClaimOperation内部プロビジョニング]
    B -->|No| D[provisionClaimOperationExternal]
    D --> E{CSI移行有効?}
    E -->|Yes| F[CSI名変換]
    F --> G{変換成功?}
    G -->|No| H[Event: ProvisioningFailed]
    G -->|Yes| I[setClaimProvisioner]
    E -->|No| I
    I --> J{アノテーション設定成功?}
    J -->|No| K[Event: ProvisioningFailed]
    J -->|Yes| L[Event: ExternalProvisioning<br/>Waiting for a volume to be created...]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| PersistentVolumeClaims | PVCの情報取得 | コントローラキャッシュ経由 |
| StorageClasses | プロビジョナー名の取得 | Lister経由 |

### テーブル別参照項目詳細

#### StorageClasses

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| Provisioner | 外部プロビジョナー名の取得 | PVC.Spec.StorageClassName で参照 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| PersistentVolumeClaims | UPDATE | プロビジョナーアノテーションの設定 |
| Events | INSERT | ExternalProvisioningイベントの記録 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| CSI名変換失敗 | CSI移行有効でin-treeプラグイン名の変換に失敗 | CSI移行設定の確認 |
| アノテーション設定失敗 | PVC更新のAPIエラー | 次回同期で再試行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | エラー時はPV Controller同期ループで再試行 |
| リトライ間隔 | PV Controller同期ループの間隔に依存 |
| リトライ対象エラー | setClaimProvisionerのAPIエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Event APIのレート制限に準拠 |
| 1日あたり上限 | 同一理由のイベントは集約される |

### 配信時間帯

制限なし

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

- イベントメッセージにはプロビジョナー名が含まれるが、認証情報やシークレットは含まれない
- Kubernetes RBACによりEventの読み取り権限が制御される

## 備考

- ExternalProvisioningは情報通知であり、問題発生時はProvisioningFailedが別途発行される
- 外部プロビジョナー（CSIドライバー等）はこのアノテーションを監視してプロビジョニングを開始する
- CSI移行（CSI Migration）が有効な場合、in-treeプラグイン名がCSIプラグイン名に変換される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.go | `pkg/controller/volume/events/event.go` | 28行目: `ExternalProvisioning` 定数定義 |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | 1820-1861行目: provisionClaimOperationExternal全体の処理フロー |

**主要処理フロー**:
1. **1831行目**: StorageClass.Provisionerからプロビジョナー名を取得
2. **1832行目**: CSI移行有効チェック
3. **1834行目**: CSI名変換（移行有効時）
4. **1843行目**: `setClaimProvisioner` でPVCにアノテーション設定
5. **1852-1854行目**: 待機メッセージの構築
6. **1857行目**: `eventRecorder.Event(claim, Normal, ExternalProvisioning, msg)`

#### Step 3: provisionClaimの分岐を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | 1574-1612行目: provisionClaimでin-tree/externalの分岐 |

**主要処理フロー**:
- **1583行目**: `findProvisionablePlugin(claim)` でプラグイン検索
- **1599行目**: plugin == nil の場合 `provisionClaimOperationExternal` を呼び出し
- **1602行目**: plugin != nil の場合 `provisionClaimOperation` を呼び出し

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

```
PersistentVolumeController.syncUnboundClaim()
    |
    +-- provisionClaim(claim)
            |
            +-- findProvisionablePlugin(claim)
            |       |
            |       +-- (plugin == nil) -> external provisioner
            |
            +-- scheduleOperation("provision-...", func)
                    |
                    +-- provisionClaimOperationExternal(claim, storageClass)
                            |
                            +-- csiMigratedPluginManager.IsMigrationEnabledForPlugin()
                            +-- translator.GetCSINameFromInTreeName()
                            +-- setClaimProvisioner(claim, provisionerName)
                            +-- eventRecorder.Event(claim, Normal, ExternalProvisioning, msg)
```

### データフロー図

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

PVC Spec               ---->  provisionClaimOperationExternal  ---->  Kubernetes Event
(StorageClassName)             |                                      (ExternalProvisioning)
                               +-> StorageClass.Provisioner           |
StorageClass            ---->  +-> CSI名変換（必要時）                PVC更新
(Provisioner)                  +-> setClaimProvisioner()              (アノテーション追加)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/controller/volume/events/event.go` | ソース | ExternalProvisioning定数定義（28行目） |
| pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | ソース | provisionClaimOperationExternal（1820-1861行目） |
| provision_test.go | `pkg/controller/volume/persistentvolume/provision_test.go` | テスト | プロビジョニングロジックのユニットテスト |
