# 通知設計書 45-VolumePermissionChangeInProgress

## 概要

本ドキュメントは、Kubernetesにおけるボリュームの権限変更が進行中の際に発行されるイベント通知「VolumePermissionChangeInProgress」の設計を記述する。ボリュームのfsGroup権限変更処理が長時間かかっている場合に、Warningイベントとして記録される。

### 本通知の処理概要

本通知は、ボリュームマウント時のfsGroup所有権変更処理が一定時間（初回30秒、以後60秒間隔）以上かかっている場合に発行されるKubernetesイベントである。大量のファイルを持つボリュームでは再帰的な所有権変更に長時間を要するため、この通知によりユーザーに進捗状況を通知する。

**業務上の目的・背景**：ボリュームのfsGroup設定に基づく再帰的な所有権変更は、ファイル数が多い場合にPodの起動を大幅に遅延させる。この通知により、Podの起動遅延の原因がボリューム権限変更であることをユーザーに通知し、OnRootMismatch FSGroupChangePolicyの使用を推奨する。

**通知の送信タイミング**：ChangePermissions()実行開始から30秒後に初回イベントが発行され、その後60秒間隔で進捗状況が継続的に通知される。

**通知の受信者**：Podオブジェクトに対するイベントとして記録されるため、Pod所有者、Namespace管理者がkubectl describe podやイベント監視ツールを通じて確認できる。

**通知内容の概要**：「Setting volume ownership for {dir} is taking longer than expected, consider using OnRootMismatch」という初回メッセージと、「Setting volume ownership for {dir}, processed {N} files.」という進捗メッセージが含まれる。

**期待されるアクション**：管理者はPodのSecurityContext設定でfsGroupChangePolicyをOnRootMismatchに変更することを検討すべきである。これによりルートディレクトリのみの権限チェックで済むようになる。

## 通知種別

Kubernetesイベント（Event API リソース）- EventType: Warning

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（goroutineによる定期通知） |
| 優先度 | 中（Warning） |
| リトライ | EventRecorderの内部リトライ機構に依存 |

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

Podオブジェクトに対してイベントが記録される。vo.recorder.Event(vo.pod, v1.EventTypeWarning, events.VolumePermissionChangeInProgress, msg)により発行される。

## 通知テンプレート

### メール通知の場合

該当なし（Kubernetesネイティブイベント）

### 本文テンプレート

```
# 初回メッセージ（30秒後）:
"Setting volume ownership for %s is taking longer than expected, consider using OnRootMismatch - https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods"

# 進捗メッセージ（60秒間隔）:
"Setting volume ownership for %s, processed %d files."
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| dir（ディレクトリパス） | ボリュームディレクトリ（Pod UID以降の部分） | getDirnameToReport(vo.dir, string(vo.pod.UID)) | Yes |
| 処理済みファイル数 | 権限変更済みファイル数 | vo.fileCounter.Load() | Yes（進捗メッセージのみ） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| タイマー | ChangePermissions開始後30秒 | Podオブジェクトが設定されている | 初回イベント発行とモニター開始 |
| タイマー | 60秒間隔のticker | 権限変更処理が継続中 | 進捗イベントの定期発行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| fsGroupがnil | ChangePermissions()が即座にreturnする |
| fsGroupChangePolicyがOnRootMismatch | skipPermissionChange()がtrueを返し、再帰変更をスキップ |
| 処理が30秒以内に完了 | タイマー発火前にcancel()が呼ばれる |
| vo.podがnil | monitorProgress goroutineが起動されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ChangePermissions呼び出し] --> B{fsGroup == nil?}
    B -->|Yes| C[return nil]
    B -->|No| D{skipPermissionChange?}
    D -->|Yes| C
    D -->|No| E[30秒タイマー開始]
    E --> F[changePermissionsRecursively開始]
    F -->|30秒未満で完了| G[タイマーキャンセル]
    F -->|30秒経過| H[initiateProgressMonitor]
    H --> I[初回イベント発行]
    I --> J[monitorProgress goroutine開始]
    J --> K{60秒ticker}
    K --> L[進捗イベント発行]
    L --> K
    K -->|context cancelled| M[goroutine終了]
    G --> N[終了]
    M --> N
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| Pod | イベント発行対象 | vo.pod |

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

#### Pod

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| UID | ディレクトリ名のフィルタリング | getDirnameToReport用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event | INSERT | VolumePermissionChangeInProgressイベント作成（初回+定期） |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Event.Reason | "VolumePermissionChangeInProgress" | Warningイベント |
| INSERT | Event.Message | 進捗メッセージ | 初回/定期で異なる内容 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 権限変更エラー | Lchown/Chmod失敗 | エラーログ出力。処理は継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 該当なし（通知自体は定期発行） |
| リトライ間隔 | 60秒（進捗通知の間隔） |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 最大1件（60秒間隔のticker） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（24時間365日）

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

イベントメッセージにはボリュームディレクトリパス（Pod UID以降の部分のみ）が含まれる。フルパスは公開されず、Pod UIDからの相対パスのみが表示される。

## 備考

- firstEventReportDuration（30秒）とprogressReportDuration（60秒）はパッケージレベルの変数として定義されており、テスト目的で変更可能
- VolumeOwnership構造体のfileCounterはatomic.Int64で実装されており、goroutine安全
- Kubernetes公式ドキュメントのOnRootMismatch設定ページへのリンクが初回メッセージに含まれる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.go | `pkg/kubelet/events/event.go` | 68行目: VolumePermissionChangeInProgress定数定義 |
| 1-2 | volume_linux.go | `pkg/volume/volume_linux.go` | 38-49行目: rwMask/roMask/execMask定数、progressReportDuration/firstEventReportDuration変数 |

**読解のコツ**: VolumeOwnership構造体はvolume_linux.goに定義される。Linux専用のビルドタグが付いている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | volume_linux.go | `pkg/volume/volume_linux.go` | 71-90行目: ChangePermissions()メソッド - fsGroupチェック、skipPermissionChangeチェック、タイマー設定 |

**主要処理フロー**:
1. **72行目**: fsGroup == nilチェック
2. **76行目**: skipPermissionChange()呼び出し
3. **84行目**: 30秒タイマー設定（AfterFunc）
4. **89行目**: changePermissionsRecursively()呼び出し

#### Step 3: 進捗モニタリング

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | volume_linux.go | `pkg/volume/volume_linux.go` | 92-97行目: initiateProgressMonitor() - 初回イベント発行 |
| 3-2 | volume_linux.go | `pkg/volume/volume_linux.go` | 116-130行目: monitorProgress() - 60秒間隔の進捗通知goroutine |
| 3-3 | volume_linux.go | `pkg/volume/volume_linux.go` | 141-146行目: logWarning() - 進捗ログとイベント発行 |

**主要処理フロー**:
- **119行目**: 初回Event発行（VolumePermissionChangeInProgress）
- **120行目**: 60秒tickerの作成
- **127行目**: ticker発火時にlogWarning()呼び出し
- **145行目**: logWarning()内でEvent発行

#### Step 4: 権限変更の実体処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | volume_linux.go | `pkg/volume/volume_linux.go` | 99-114行目: changePermissionsRecursively() - walkDeepによる再帰処理 |
| 4-2 | volume_linux.go | `pkg/volume/volume_linux.go` | 148-181行目: changeFilePermission() - 個別ファイルの権限変更 |
| 4-3 | volume_linux.go | `pkg/volume/volume_linux.go` | 183-232行目: skipPermissionChange()、requiresPermissionChange() |

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

```
VolumeOwnership.ChangePermissions()
    |
    +-- skipPermissionChange()
    |       +-- requiresPermissionChange()
    |
    +-- time.AfterFunc(30s, initiateProgressMonitor)
    |       +-- monitorProgress() [goroutine]
    |               +-- recorder.Event(pod, Warning, VolumePermissionChangeInProgress, ...)
    |               +-- time.NewTicker(60s)
    |               +-- logWarning()
    |                       +-- recorder.Event(pod, Warning, VolumePermissionChangeInProgress, ...)
    |
    +-- changePermissionsRecursively()
            +-- walkDeep()
                    +-- changeFilePermission()
                            +-- os.Lchown()
                            +-- os.Chmod()
```

### データフロー図

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

Pod.SecurityContext       VolumeOwnership                    Kubernetes Event API
  .fsGroup           --> .ChangePermissions()           --> Event(Warning,
  .fsGroupChangePolicy   .changePermissionsRecursively()    VolumePermissionChangeInProgress)
Volume dir path          .monitorProgress()                  [30秒後初回 + 60秒間隔]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/kubelet/events/event.go` | ソース | VolumePermissionChangeInProgress定数定義（68行目） |
| volume_linux.go | `pkg/volume/volume_linux.go` | ソース | VolumeOwnership構造体と権限変更処理の実装 |
| volume.go | `pkg/volume/volume.go` | ソース | VolumeOwnershipChanger インターフェース定義 |
