# 通知設計書 100-UnknownTimeZone

## 概要

本ドキュメントは、CronJobに無効なタイムゾーンが指定された際に発行されるKubernetesイベント通知「UnknownTimeZone」の設計を記述する。

### 本通知の処理概要

CronJobのSpec.TimeZoneフィールドに指定されたタイムゾーン名が、Goの`time.LoadLocation`関数で読み込み不能な場合にWarningイベントとして発行される通知である。

**業務上の目的・背景**：CronJobのSpec.TimeZoneはIANAタイムゾーンデータベース（例：「Asia/Tokyo」「America/New_York」）の名前を受け付ける。無効なタイムゾーン名が指定された場合、CronJobはJobを作成できなくなるため、この通知により設定ミスを即座に検知し修正を促す。

**通知の送信タイミング**：`syncCronJob`メソッド内で、Spec.TimeZoneがnilでない場合に`time.LoadLocation`でタイムゾーンの検証が行われ、エラーが発生した場合に発行される（行509）。

**通知の受信者**：Kubernetesイベントとして該当CronJobオブジェクトに記録される。

**通知内容の概要**：EventTypeはWarning、Reasonは「UnknownTimeZone」、メッセージには無効なタイムゾーン名とエラー詳細が含まれる。フォーマットは「invalid timeZone: "{タイムゾーン名}": {エラー内容}」である。

**期待されるアクション**：受信者はCronJobのSpec.TimeZoneをIANAタイムゾーンデータベースの有効な名前に修正する。有効なタイムゾーン名はGoの`time.LoadLocation`関数で受け付けられる名前（例：「UTC」「Asia/Tokyo」「America/New_York」等）である。

## 通知種別

Kubernetesイベント（Event API リソース）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（syncCronJob処理内で即座に発行） |
| 優先度 | 高（CronJobが一切動作しない） |
| リトライ | CronJobのSpec.TimeZoneが更新されるまで、毎回の同期で発行される |

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

CronJobコントローラの`recorder.Eventf`メソッドにより、対象のCronJobオブジェクトに対してイベントが記録される。

## 通知テンプレート

### メール通知の場合

本通知はKubernetesイベントであり、メール送信は行わない。

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | N/A（Kubernetesイベント） |
| 送信元名称 | cronjob-controller |
| 件名 | N/A |
| 形式 | Kubernetesイベントリソース |

### 本文テンプレート

```
invalid timeZone: %q: %s
```

第1変数`%q`には無効なタイムゾーン名（ダブルクォート付き）、第2変数`%s`にはLoadLocationのエラー内容が挿入される。

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | N/A | N/A | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| timeZone | 無効なタイムゾーン名 | ptr.Deref(cronJob.Spec.TimeZone, "") | Yes |
| err | LoadLocationのエラー内容 | time.LoadLocation戻り値 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コントローラ同期 | CronJob同期処理 | Spec.TimeZoneが非nilかつtime.LoadLocationがエラーを返した場合 | syncCronJob内のタイムゾーン検証 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| TimeZone未設定 | Spec.TimeZoneがnilの場合はタイムゾーン検証自体が行われない |
| 有効なタイムゾーン | time.LoadLocationが成功した場合 |
| CronJob削除中 | DeletionTimestampが設定されている場合はタイムゾーン検証に到達しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[syncCronJob] --> B{DeletionTimestamp?}
    B -->|削除中| C[ステータス更新のみ]
    B -->|通常| D{Spec.TimeZone設定?}
    D -->|未設定| E[Suspendチェックへ]
    D -->|設定済み| F[time.LoadLocation]
    F --> G{ロード結果}
    G -->|成功| E
    G -->|失敗| H[UnknownTimeZoneイベント発行]
    H --> I[nil返却（Job作成スキップ）]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| CronJob | TimeZone設定取得 | Informerキャッシュ経由 |

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

#### CronJob

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| Spec.TimeZone | タイムゾーン検証対象 | syncCronJob内 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event | INSERT | UnknownTimeZoneイベント作成 |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Event.Type | Warning | イベント種別 |
| INSERT | Event.Reason | UnknownTimeZone | イベント理由 |
| INSERT | Event.Message | invalid timeZone: "{timeZone}": {err} | タイムゾーンエラー |
| INSERT | Event.Source.Component | cronjob-controller | 発行元コンポーネント |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| タイムゾーン名不正 | IANAタイムゾーンデータベースに存在しない名前 | 有効なタイムゾーン名に修正 |
| タイムゾーンデータ不在 | ノード上にtzdata（zoneinfo）が存在しない | コンテナイメージまたはノードにtzdataをインストール |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 毎回の同期サイクルで再検証される |
| リトライ間隔 | ワークキューのリキュー間隔 |
| リトライ対象エラー | time.LoadLocationのエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetesイベントのデフォルト集約ルールに従う |
| 1日あたり上限 | 特に制限なし |

### 配信時間帯

制限なし。

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

タイムゾーン名がメッセージに含まれるが、機密情報は含まれない。

## 備考

- UnknownTimeZoneはsyncCronJob内で最も早い段階でチェックされる（DeletionTimestampチェックの直後、Suspendチェックの前）
- UnknownTimeZone検出後はnilが返され（行510）、updateStatus=falseのままとなるため、CronJobのステータスは変更されない
- formatSchedule関数（行775-777）でも同様のtime.LoadLocationチェックが行われるが、こちらはエラー時にスケジュール文字列をそのまま返す
- ptr.Deref関数でSpec.TimeZoneのnilデリファレンスを安全に処理している

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `staging/src/k8s.io/api/batch/v1/types.go` | CronJob.Spec.TimeZone（*string型）の仕様を理解する。nilは未設定（UTC使用）を意味する |

**読解のコツ**: TimeZoneはKubernetes 1.24でAlpha、1.25でBetaとして追加されたフィールド。IANA Time Zone Database名を受け付ける。

#### Step 2: タイムゾーン検証を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cronjob_controllerv2.go | `pkg/controller/cronjob/cronjob_controllerv2.go` | syncCronJob内のタイムゾーン検証（行505-512）を理解する |

**主要処理フロー**:
1. **行505**: Spec.TimeZoneがnilでないかチェック
2. **行506**: ptr.Deref(cronJob.Spec.TimeZone, "")でデリファレンス
3. **行507**: time.LoadLocation(timeZone)でタイムゾーンの有効性を検証
4. **行509**: エラー時にrecorder.Eventf "UnknownTimeZone"発行
5. **行510**: nil, updateStatus, nil返却（Job作成をスキップ）

#### Step 3: formatScheduleとの関連を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cronjob_controllerv2.go | `pkg/controller/cronjob/cronjob_controllerv2.go` | formatSchedule関数（行775-781）でもTimeZoneを使用してTZプレフィックスを付与する処理を理解する |

**主要処理フロー**:
- **行775-777**: TimeZone設定時にLoadLocationで検証し、エラー時はスケジュールをそのまま返す（イベント発行なし）
- **行780**: 成功時に"TZ={timezone} {schedule}"形式で返す

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

```
ControllerV2.syncCronJob (行426)
    |
    +-- [DeletionTimestampチェック] (行498-502)
    |
    +-- [TimeZoneチェック] (行505-512)
    |    |
    |    +-- ptr.Deref (行506)
    |    +-- time.LoadLocation (行507)
    |    |
    |    +-- [エラー]
    |         +-- recorder.Eventf "UnknownTimeZone" (行509) ★本通知
    |         +-- nil返却 (行510)
    |
    +-- [Suspendチェック] (行514-517)
    +-- [スケジュール解析] (行519-)
```

### データフロー図

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

CronJob.Spec.TimeZone    --> syncCronJob                  --> UnknownTimeZone Event
                              |                                (Warning)
                              +-- ptr.Deref
                              +-- time.LoadLocation
                              +-- recorder.Eventf
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cronjob_controllerv2.go | `pkg/controller/cronjob/cronjob_controllerv2.go` | ソース | UnknownTimeZoneイベント発行（行509）、タイムゾーン検証（行505-512） |
| cronjob_controllerv2.go | `pkg/controller/cronjob/cronjob_controllerv2.go` | ソース | formatSchedule関数（行775-781）でのTimeZone使用 |
