# 通知設計書 60-ProvisioningSucceeded

## 概要

本ドキュメントは、PersistentVolumeの動的プロビジョニングが正常に完了した際に発行されるイベント通知「ProvisioningSucceeded」の設計について記述する。

### 本通知の処理概要

**業務上の目的・背景**：動的プロビジョニングにおいて、ストレージバックエンド上にボリュームが作成され、対応するPVオブジェクトがKubernetes API Serverに正常に作成された場合にこの通知が発行される。この通知はPVCに対する動的プロビジョニングが完全に完了したことをクラスタ管理者に伝達し、ストレージリソースが正常にプロビジョニングされたことの確認を可能にする。運用監視において、プロビジョニングの成功件数や頻度を追跡するためにも有用である。

**通知の送信タイミング**：PV Controllerの `provisionClaimOperation` 内で、ストレージボリュームのプロビジョニングとPVオブジェクトの作成が共に成功した直後に発行される。

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

**通知内容の概要**：「Successfully provisioned volume {PV名} using {プラグイン名}」というメッセージで、作成されたPV名と使用されたプロビジョナープラグイン名が含まれる。

**期待されるアクション**：通常は対応不要。プロビジョニングが正常に完了したことを確認する情報通知。

## 通知種別

Kubernetes Event（EventType: Normal）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（provisionClaimOperationはgoroutineで実行） |
| 優先度 | 低（正常完了通知） |
| リトライ | 不要（成功通知のため） |

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

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

## 通知テンプレート

### Kubernetes Event

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

### 本文テンプレート

```
Successfully provisioned volume %s using %s
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| volume.Name | 作成されたPV名 | プロビジョナーが返したPVオブジェクトのName | Yes |
| pluginName | 使用されたプロビジョナープラグイン名 | plugin.GetPluginName() | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| PV Controller同期 | provisionClaimOperation | ストレージプロビジョニングとPVオブジェクト作成が共に成功 | pv_controller.go 1813-1815行目 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| プロビジョニング失敗 | provisioner.Provisionがエラーの場合はProvisioningFailedが発行される |
| PVオブジェクト作成失敗 | PV作成がリトライ後も失敗した場合はProvisioningFailedが発行される |
| 外部プロビジョニング | 外部プロビジョナー使用時はProvisioningSucceededは内部からは発行されない（外部プロビジョナーが発行） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[provisionClaimOperation] --> B[provisioner.Provision実行]
    B --> C{プロビジョニング成功?}
    C -->|No| D[Event: ProvisioningFailed]
    C -->|Yes| E[PVオブジェクト作成<br/>最大5回リトライ]
    E --> F{作成成功?}
    F -->|No| G[Event: ProvisioningFailed<br/>+ クリーンアップ試行]
    F -->|Yes| H[Event: ProvisioningSucceeded<br/>Successfully provisioned volume]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| PersistentVolumeClaims | PVCの情報取得 | provisionClaimOperationの引数 |
| StorageClasses | プロビジョナー設定の取得 | Lister経由 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Events | INSERT | ProvisioningSucceededイベントの記録 |
| PersistentVolumes | INSERT | プロビジョニングされたPVオブジェクトの作成（イベント発行前に完了） |

## エラー処理

### エラーケース一覧

該当なし（成功通知のため）

### リトライ仕様

該当なし（成功通知のため）

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- イベントメッセージにはPV名とプラグイン名が含まれるが、機密情報は含まれない
- Kubernetes RBACによりEventの読み取り権限が制御される

## 備考

- ProvisioningSucceededは内部プロビジョニング（in-treeプラグイン）の成功時にのみ発行される
- 外部プロビジョナー（CSIドライバー等）の場合、成功通知は外部プロビジョナー側で発行される
- このイベント発行後、PVはBound状態でPVCに関連付けられている
- metrics.RecordMetricによりプロビジョニング成功のメトリクスも記録される

---

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

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

### 推奨読解順序

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

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | 1812-1815行目: プロビジョニング成功時のイベント発行 |

**主要処理フロー**:
1. **1812行目**: `} else {` ブロック（PVオブジェクト作成成功の分岐）
2. **1813行目**: 成功ログ `"Volume provisioned for claim"`
3. **1814行目**: メッセージ構築 `"Successfully provisioned volume %s using %s"`
4. **1815行目**: `eventRecorder.Event(claim, Normal, ProvisioningSucceeded, msg)`

#### Step 3: PVオブジェクト作成の成功パスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | 1730-1773行目: PVオブジェクトの構築と作成 |

**主要処理フロー**:
- **1731-1737行目**: PVオブジェクトのフィールド設定（Name, ClaimRef, Phase, StorageClassName）
- **1740-1741行目**: アノテーション設定（BoundByController, DynamicallyProvisioned）
- **1743-1748行目**: HonorPVReclaimPolicyフィーチャーゲートによるFinalizer設定
- **1751-1773行目**: PVオブジェクト作成リトライ

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

```
PersistentVolumeController.provisionClaimOperation()
    |
    +-- provisioner.Provision(selectedNode, allowedTopologies)
    |       |
    |       +-- (success) -> PV object returned
    |
    +-- kubeClient.CoreV1().PersistentVolumes().Create(volume)  [リトライ x5]
    |       |
    |       +-- (success)
    |
    +-- storeVolumeUpdate(newVol)  // internal cache update
    |
    +-- eventRecorder.Event(claim, Normal, ProvisioningSucceeded,
            "Successfully provisioned volume %s using %s")
```

### データフロー図

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

PVC Spec               ---->  provisioner.Provision()        ---->  PV Object (API Server)
(StorageClassName,             |                                    |
 Resources,                    +-> PV属性設定                       Kubernetes Event
 DataSource)                   +-> kubeClient.PV.Create()          (ProvisioningSucceeded)
                               +-> storeVolumeUpdate()
StorageClass            ---->  +-> eventRecorder.Event()
(Provisioner,
 ReclaimPolicy,
 Parameters)
```

### 関連ファイル一覧

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