# 通知設計書 79-AmbiguousSelector

## 概要

本ドキュメントは、HPAのセレクタが曖昧な場合（同一のPodが複数のHPAによって選択される状態）に発行されるAmbiguousSelector通知の設計を定義する。

### 本通知の処理概要

AmbiguousSelector通知は、HPAコントローラがセレクタのバリデーション時に、同一のPod群が複数のHPAオブジェクトによって管理対象となっていることを検出した場合にWarningイベントとして発行される。この状態ではスケーリングの競合が発生し、予期しない動作につながる可能性がある。

**業務上の目的・背景**：同一のPodが複数のHPAによって管理されると、各HPAが独立にスケーリング判断を行い、互いに矛盾するスケール操作が実行される可能性がある。この通知により、HPA設定の競合を管理者が認識し、セレクタの重複を解消できるようにする。

**通知の送信タイミング**：HPAコントローラのreconcileAutoscaler()内でvalidateAndParseSelector()が呼ばれ、対象Podを選択しているHPAが複数存在することがhpasControllingPodsUnderSelector()で検出された場合に発行される。

**通知の受信者**：Kubernetes Event APIを通じてHPAオブジェクトに紐付くイベントとして記録される。kubectl describe hpaやイベント監視ツールを通じてHPA所有者やクラスタ管理者が受信する。

**通知内容の概要**：「pods by selector {selector} are controlled by multiple HPAs: {HPA一覧}」というメッセージで、競合するHPAの一覧が通知される。

**期待されるアクション**：HPA所有者はHPAのセレクタ設定を見直し、各HPAが一意のPod群を管理するようにセレクタを修正するか、不要なHPAを削除する。

## 通知種別

Kubernetes Event（Warning）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（reconcileAutoscaler処理内で発行） |
| 優先度 | 高（スケーリング競合のリスク） |
| リトライ | なし（次回のreconcile周期で再チェック） |

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

対象のHPAオブジェクトを送信先として使用する。

## 通知テンプレート

### Kubernetes Eventの場合

| 項目 | 内容 |
|-----|------|
| 送信元コンポーネント | horizontal-pod-autoscaler |
| EventType | Warning |
| Reason | AmbiguousSelector |
| 対象オブジェクト | HorizontalPodAutoscaler |

### 本文テンプレート

```
pods by selector {selector} are controlled by multiple HPAs: {selectingHpas}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| selector | HPAのPodセレクタ | scale.Status.Selector | Yes |
| selectingHpas | 競合するHPAの一覧 | hpasControllingPodsUnderSelector()の返却値 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| HPA reconcile | reconcileAutoscaler()実行 | len(selectingHpas) > 1 | 同一Podを選択するHPAが複数存在 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 単一HPA | selectingHpasの長さが1以下の場合 |
| セレクタが空/無効 | 先にSelectorRequired/InvalidSelectorが発行される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[validateAndParseSelector] --> B{selector空?}
    B -->|Yes| C[SelectorRequired]
    B -->|No| D[labels.Parse実行]
    D --> E{パース成功?}
    E -->|No| F[InvalidSelector]
    E -->|Yes| G[hpasControllingPodsUnderSelector]
    G --> H{len > 1?}
    H -->|Yes| I[AmbiguousSelector Event発行]
    I --> J[ScalingActive=False条件設定]
    J --> K[エラー返却]
    H -->|No| L[セレクタ有効・続行]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| Pods (informer cache) | セレクタに一致するPodの一覧取得 | podLister.Pods().List() |
| HPA Selectors (インメモリ) | 登録済みHPAセレクタの管理 | hpaSelectors構造体 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Events (etcd) | INSERT | Kubernetes Eventオブジェクトが作成される |
| HPA (etcd) | UPDATE | HPA StatusにScalingActive=False条件が設定される |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| セレクタ曖昧 | 複数HPAが同一Podを選択 | AmbiguousSelectorイベント発行、ScalingActive=False設定 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | HPAの同期間隔で自動再チェック |
| リトライ間隔 | デフォルト15秒 |
| リトライ対象エラー | 全てのreconcileエラー |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- セレクタ文字列とHPA名が通知に含まれるが、機密性は低い

## 備考

- AmbiguousSelectorイベントとともにHPAのScalingActive条件がFalse, Reason="AmbiguousSelector"に設定される
- validateAndParseSelector()の第3段階（最終チェック）に該当する
- hpasControllingPodsUnderSelector()はhpaSelectorsインメモリキャッシュを使用してHPAの競合を検出する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | 行87-99: HorizontalController構造体（hpaSelectors, hpaSelectorsMux） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | 行421-434: Podリスト取得とHPA競合チェック |

**主要処理フロー**:
1. **行421**: podLister.Pods(hpa.Namespace).List(parsedSelector) でPod取得
2. **行426**: hpasControllingPodsUnderSelector(pods) で競合HPA検出
3. **行427**: len(selectingHpas) > 1 チェック
4. **行428**: errMsg構築（セレクタとHPA一覧を含む）
5. **行429**: AmbiguousSelectorイベント発行
6. **行430**: setCondition(ScalingActive=False, Reason="AmbiguousSelector")
7. **行431**: エラー返却

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

```
HorizontalController
    |
    +-- reconcileAutoscaler()
           |
           +-- validateAndParseSelector(selector)  [行397]
                  |
                  +-- selector == "" (SelectorRequired)
                  +-- labels.Parse() (InvalidSelector)
                  |
                  +-- podLister.Pods().List(parsedSelector)  [行421]
                  +-- hpasControllingPodsUnderSelector(pods)  [行426]
                         |
                         +-- len(selectingHpas) > 1:
                                +-- eventRecorder.Event("AmbiguousSelector")  [行429]
                                +-- setCondition(ScalingActive=False)  [行430]
```

### データフロー図

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

Pod Informer Cache         validateAndParseSelector()
(Pods by selector) ------> hpasControllingPodsUnderSelector()
                           |
HPA Selectors Cache        |
(登録済みHPA) -----------> 競合検出
                           |
                           +-- 競合あり --> AmbiguousSelector Event
                           |               (Warning, HPA)
                           |               + ScalingActive=False
                           |
                           +-- 競合なし --> parsedSelector返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | ソース | HPAコントローラの実装（通知発行元） |
| horizontal_test.go | `pkg/controller/podautoscaler/horizontal_test.go` | テスト | HPAコントローラのテスト |
| selectors/ | `pkg/controller/util/selectors/` | ソース | HPAセレクタ管理ユーティリティ |
