# 通知設計書 62-WaitForPodScheduled

## 概要

本ドキュメントは、KubernetesにおけるPersistentVolumeClaim（PVC）の遅延バインディングモード時に、参照するPodのスケジュールを待機していることをユーザーに通知する「WaitForPodScheduled」イベントの設計を記述する。

### 本通知の処理概要

PVCが`WaitForFirstConsumer`モードのStorageClassを使用し、かつPVCを参照するPodが存在するがまだノードにスケジュールされていない場合に、ボリュームバインディングがPodスケジュール待ちであることを通知する。

**業務上の目的・背景**：遅延バインディングモードでは、PVCはPodがノードにスケジュールされるまでPVにバインドされない。PVCを参照するPodが作成されたが、まだスケジューラによりノードに割り当てられていない場合、ユーザーにはPVCがPending状態に見える。この通知はPodのスケジュール待ちという正常な遷移状態であることを伝え、ユーザーの不安を解消する。

**通知の送信タイミング**：PVコントローラがunbound状態のPVCを同期（syncUnboundClaim）する際、遅延バインディングモードのPVCに対して、参照するPod（未スケジュール）が存在する場合に発行される。

**通知の受信者**：PVCオブジェクトに対するKubernetes Eventとして記録され、kubectl describe pvc等で確認可能。クラスタ管理者およびPVCを作成した開発者が対象。

**通知内容の概要**：「waiting for pod <Pod名> to be scheduled」または複数Podの場合「waiting for pods <Pod名一覧> to be scheduled」というメッセージが、PVCオブジェクトに対するNormalイベントとして記録される。

**期待されるアクション**：ユーザーはPodがスケジュール可能な状態であることを確認する（リソース不足、アフィニティ制約等の確認）。Podが正常にスケジュールされればPVCのバインディングが自動的に進行する。

## 通知種別

Kubernetes Event（EventType: Normal）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（PVコントローラの同期ループ内で発行） |
| 優先度 | 低（情報通知） |
| リトライ | なし（同期ループで繰り返し発行される） |

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

PVCオブジェクトに対するEventとして記録される。eventRecorder.Event()のターゲットとしてclaim（PVC）が指定される。

## 通知テンプレート

### メール通知の場合

本通知はKubernetes Eventとして発行されるため、メール送信は行わない。

### 本文テンプレート

```
# Pod が1つの場合
waiting for pod {podName} to be scheduled

# Pod が複数の場合
waiting for pods {podName1},{podName2},... to be scheduled
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| podNames | PVCを参照する未スケジュールPod名のリスト | findNonScheduledPodsByPVC | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コントローラ同期 | PVコントローラによるPVC同期処理 | PVCが遅延バインディングモードかつ未スケジュールPodが存在する | emitEventForUnboundDelayBindingClaimメソッド内で判定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| PVCを参照するPodが存在しない | Podが存在しない場合はWaitForFirstConsumerイベントが発行される |
| PVCが既にバインド済み | バインド済みのPVCに対してはこのパスに到達しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[PVコントローラ同期ループ] --> B[syncUnboundClaim]
    B --> C{遅延バインディングモード?}
    C -->|No| D[通常バインディング処理]
    C -->|Yes| E[emitEventForUnboundDelayBindingClaim]
    E --> F[findNonScheduledPodsByPVC]
    F --> G{参照するPodが存在?}
    G -->|No| H[WaitForFirstConsumer イベント]
    G -->|Yes| I{Pod数 > 1?}
    I -->|No| J[waiting for pod X to be scheduled]
    I -->|Yes| K[waiting for pods X,Y to be scheduled]
    J --> L[WaitForPodScheduled イベント発行]
    K --> L
    L --> M[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| PersistentVolumeClaim | 対象PVCの状態確認 | API Server経由 |
| StorageClass | volumeBindingModeの確認 | classLister経由 |
| Pod | PVCを参照する未スケジュールPodの検索 | findNonScheduledPodsByPVC |

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

#### PersistentVolumeClaim

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| spec.volumeName | バインド状態の確認 | 空文字列であること |
| spec.storageClassName | StorageClassの参照 | 遅延バインディングモードの判定 |

#### Pod

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| metadata.name | メッセージに含めるPod名 | PVCを参照かつ未スケジュール |
| spec.volumes | PVC参照の確認 | PVCを参照するPodの特定 |
| spec.nodeName | スケジュール状態の確認 | 空文字列（未スケジュール） |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event | INSERT | Kubernetes Eventオブジェクトの作成 |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | reason | WaitForPodScheduled | イベント理由 |
| INSERT | message | waiting for pod(s) ... to be scheduled | Pod名を含む動的メッセージ |
| INSERT | type | Normal | イベントタイプ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Pod検索失敗 | findNonScheduledPodsByPVCがエラーを返した場合 | エラーを返し、次の同期ループで再試行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | PVコントローラの同期ループにより自動的に再試行 |
| リトライ間隔 | PVコントローラの同期間隔に依存 |
| リトライ対象エラー | Pod検索エラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Eventのデフォルトレート制限に従う |
| 1日あたり上限 | 制限なし（Eventの自動集約による） |

### 配信時間帯

制限なし（コントローラの動作タイミングに依存）

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

通知メッセージにPod名が含まれるが、これはKubernetesの標準的な動作であり、RBACにより閲覧が制限される。機密情報は含まない。

## 備考

- WaitForPodScheduledはWaitForFirstConsumer（No.61）と同一メソッド（emitEventForUnboundDelayBindingClaim）内で条件分岐により選択される
- 複数のPodが同一PVCを参照可能であり、その場合は全Pod名がカンマ区切りでメッセージに含まれる
- スケジューラのvolumebindingプラグインがPodスケジュール時にPVCのバインドを実行する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.go | `pkg/controller/volume/events/event.go` | WaitForPodScheduled定数の定義（行33） |

**読解のコツ**: WaitForFirstConsumerと同一ファイルで定義されており、セットで理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | syncUnboundClaimメソッド（行329付近） |

**主要処理フロー**:
1. **行335-340**: 遅延バインディングモード判定
2. **行306-327**: emitEventForUnboundDelayBindingClaim呼び出し

#### Step 3: イベント発行ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | emitEventForUnboundDelayBindingClaimメソッド（行304-327） |

**主要処理フロー**:
- **行309**: findNonScheduledPodsByPVCでPod検索
- **行313**: Pod存在時にWaitForPodScheduledに切り替え
- **行315-320**: 複数Pod時のメッセージ構築（strings.Join）
- **行321-322**: 単一Pod時のメッセージ構築
- **行325**: eventRecorder.Eventでイベント発行

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

```
PersistentVolumeController.syncUnboundClaim
    |
    +-- storagehelpers.IsDelayBindingMode
    |
    +-- emitEventForUnboundDelayBindingClaim
           |
           +-- findNonScheduledPodsByPVC
           |      (Pod名リスト取得)
           |
           +-- strings.Join (複数Pod時)
           |
           +-- eventRecorder.Event (WaitForPodScheduled)
```

### データフロー図

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

PVC (Pending状態)  ───> PVコントローラ同期ループ          ───> Kubernetes Event
StorageClass       ───> IsDelayBindingMode判定           (WaitForPodScheduled)
Pod一覧            ───> findNonScheduledPodsByPVC         + Pod名入りメッセージ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/controller/volume/events/event.go` | ソース | イベント理由定数の定義 |
| pv_controller.go | `pkg/controller/volume/persistentvolume/pv_controller.go` | ソース | PVコントローラ本体、イベント発行ロジック |
| pv_helpers.go | `staging/src/k8s.io/component-helpers/storage/volume/pv_helpers.go` | ソース | IsDelayBindingMode関数 |
