# 通知設計書 123-CalculateExpectedPodCountFailed

## 概要

本ドキュメントは、Kubernetes の disruption-controller が発行する `CalculateExpectedPodCountFailed` イベント通知の設計を記述する。PodDisruptionBudget（PDB）の期待されるPod数の計算に失敗した際に発行される警告イベントである。

### 本通知の処理概要

本通知は、disruption-controller が PDB の同期処理中に、期待されるPod数（expectedCount）の計算に失敗した場合に発行される。この計算はPDBの `maxUnavailable` や `minAvailable` の設定に基づいて行われ、対象Podのコントローラ（Deployment, ReplicaSet等）のスケール情報の取得失敗が主な原因となる。

**業務上の目的・背景**：PDBのステータスを正確に計算するには、Podを管理するコントローラのスケール情報が必要である。スケール情報が取得できない場合、PDBは正しく機能せず、Podのエビクション保護が不完全になるリスクがある。この状態を管理者に通知し、問題の原因調査を促す。

**通知の送信タイミング**：trySync関数内でgetExpectedPodCount関数を呼び出し、エラーが発生した時点で発行される。

**通知の受信者**：Kubernetes Event として PDB オブジェクトに対して記録される。クラスタ管理者が `kubectl describe pdb` や `kubectl get events` で確認する。

**通知内容の概要**：期待されるPod数の計算に失敗した旨とエラーメッセージが記録される。

**期待されるアクション**：クラスタ管理者は、PDBが参照するPodのコントローラ（Deployment, ReplicaSet, StatefulSet等）が正常に存在し、Scale サブリソースが取得可能な状態にあることを確認する。

## 通知種別

Kubernetes Event（Warning イベント）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（イベント記録） |
| 優先度 | 高（Warning - PDB機能障害） |
| リトライ | なし（イベント記録のため） |

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

PDBオブジェクトに対してイベントが記録される。

## 通知テンプレート

### メール通知の場合

本通知はKubernetes Eventであり、メール送信は行わない。

### 本文テンプレート

```
Failed to calculate the number of expected pods: <error message>
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| error | 計算失敗時のエラーメッセージ | getExpectedPodCount戻り値 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コントローラ処理 | PDB同期（trySync） | getExpectedPodCountがエラーを返す | 期待Pod数の計算失敗 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 計算成功 | エラーがない場合はイベントは発行されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[PDB同期トリガー] --> B[trySync開始]
    B --> C[getPodsForPdb]
    C --> D[getExpectedPodCount呼び出し]
    D --> E{結果}
    E -->|エラー| F[Warning Eventf CalculateExpectedPodCountFailed]
    E -->|成功| G[正常処理続行]
    F --> H[エラー返却]
    G --> I[updatePdbStatus]
    H --> J[終了]
    I --> J
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| PodDisruptionBudget（API リソース） | PDBのmaxUnavailable/minAvailable設定取得 | pdbLister経由 |
| Pod（API リソース） | PDBに一致するPodのコントローラ情報取得 | podLister経由 |
| Scale（API サブリソース） | コントローラのスケール情報取得 | scaleNamespacer経由 |

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

#### PodDisruptionBudget

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| spec.maxUnavailable | 最大不可用数の指定 | PDB同期時 |
| spec.minAvailable | 最小可用数の指定 | PDB同期時 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event（API リソース） | INSERT | Warning イベントの記録 |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Event | Warning / CalculateExpectedPodCountFailed | Kubernetes Event APIを通じて記録 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| スケール取得失敗 | コントローラのScaleサブリソースが取得できない | Warning イベント発行後、エラー返却 |
| IntOrPercent変換失敗 | maxUnavailable/minAvailableの値変換エラー | Warning イベント発行後、エラー返却 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | コントローラのワークキューによる再試行 |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | getExpectedPodCount失敗時 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Event APIのデフォルトレート制限に従う |
| 1日あたり上限 | 制限なし |

### 配信時間帯

特に制限なし。

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

本イベントにはPDB名とエラーメッセージが含まれるが、機密情報は含まれない。

## 備考

- getExpectedPodCount関数（818行目）はmaxUnavailableとminAvailableの両ケースで異なるロジックを使用する
- maxUnavailable指定時はgetExpectedScale経由でスケール情報を取得するため失敗しやすい

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | disruption.go | `pkg/controller/disruption/disruption.go` | controllerAndScale構造体（124-127行目）とpodControllerFinder型（131行目） |

**読解のコツ**: PDBのexpectedCount計算にはコントローラのスケール情報が必要な点を意識する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | disruption.go | `pkg/controller/disruption/disruption.go` | trySync関数（735-772行目）の746-750行目が本イベントの発行箇所 |

**主要処理フロー**:
1. **746行目**: getExpectedPodCount(ctx, pdb, pods) 呼び出し
2. **747行目**: err != nil チェック
3. **748行目**: recorder.Eventf で CalculateExpectedPodCountFailed イベント発行
4. **749行目**: エラーを返却

#### Step 3: 期待Pod数計算ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | disruption.go | `pkg/controller/disruption/disruption.go` | getExpectedPodCount関数（818行目以降）でmaxUnavailable/minAvailableの分岐 |

**主要処理フロー**:
- **825行目**: maxUnavailable != nil の場合、getExpectedScaleを呼び出し
- **831行目**: GetScaledValueFromIntOrPercent で値を変換
- **839行目**: minAvailable != nil の場合の処理分岐

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

```
DisruptionController.trySync (735行目)
    |
    +-- getPodsForPdb (737行目)
    |
    +-- getExpectedPodCount (746行目)
    |      +-- getExpectedScale
    |      |      +-- scaleNamespacer.Scales().Get()
    |      +-- intstr.GetScaledValueFromIntOrPercent
    |
    +-- recorder.Eventf("CalculateExpectedPodCountFailed") (748行目)
```

### データフロー図

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

PDB + Pods ───> getExpectedPodCount ───> Scale API照合 ───> Event記録
                                                             (CalculateExpectedPodCountFailed)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| disruption.go | `pkg/controller/disruption/disruption.go` | ソース | trySync, getExpectedPodCount のロジック |
| disruption_test.go | `pkg/controller/disruption/disruption_test.go` | テスト | CalculateExpectedPodCountFailed のテスト |
