# 機能設計書 85-リソースパッチ（patch）

## 概要

本ドキュメントは、kubectlの`patch`コマンドによるKubernetesリソースの部分更新機能の設計を記述する。Strategic Merge Patch、JSON Merge Patch、JSON Patchの3種類のパッチタイプをサポートし、リソースのフィールドを選択的に更新する。

### 本機能の処理概要

**業務上の目的・背景**：リソース全体を置き換えることなく、特定のフィールドのみを更新する機能を提供する。CI/CDパイプラインやスクリプトからのプログラマティックなリソース更新に適しており、`edit`のような対話的操作を必要としない。

**機能の利用シーン**：Deploymentのイメージ変更、Nodeのunschedulable設定変更、Podのラベル更新、DeploymentのReplicasスケール変更（--subresource=scale）、スクリプトベースの自動化など。

**主要な処理内容**：
1. コマンドライン引数とフラグの解析（Complete）
2. 入力バリデーション（Validate）
3. パッチタイプの決定と、パッチデータの読み込み
4. パッチの適用（resource.Helper.Patchまたはローカルパッチ）
5. 結果の出力

**関連システム・外部連携**：API Serverに対してPATCHリクエストを送信する。

**権限による制御**：対象リソースに対するpatch権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | kubectl patch | 主機能 | リソースの部分更新を行う主処理 |

## 機能種別

CRUD操作（Update）/ 部分更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| TYPE NAME / -f | string | Yes | リソースタイプと名前またはファイル | いずれか必須 |
| -p / --patch | string | 条件付き | パッチ内容（JSON/YAML） | --patch-fileと排他 |
| --patch-file | string | 条件付き | パッチファイル | --patchと排他 |
| --type | string | No | パッチタイプ | json/merge/strategic（デフォルト: strategic） |
| --local | bool | No | ローカルパッチ（API呼び出しなし） | サーバーリソースと排他 |
| --dry-run | string | No | DryRun戦略 | none/client/server |
| -o / --output | string | No | 出力形式 | json/yaml/name等 |
| --field-manager | string | No | フィールドマネージャー名 | デフォルト: kubectl-patch |
| --subresource | string | No | サブリソースを指定 | scale、status等 |
| --record | bool | No | 変更理由を記録（deprecated） | - |

### 入力データソース

- コマンドライン引数（-p）
- パッチファイル（--patch-file）
- マニフェストファイル（-f、ローカルパッチ時のベース）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| パッチ結果 | string | 例: node/k8s-node-1 patched |
| 変更なし | string | 例: node/k8s-node-1 patched (no change) |

### 出力先

- 標準出力（stdout）：パッチ結果メッセージまたはリソースオブジェクト
- API Server：PATCHリクエスト

## 処理フロー

### 処理シーケンス

```
1. NewCmdPatch: コマンド定義
2. Complete: オプション補完
   ├─ DryRun戦略の取得
   ├─ Namespace解決
   └─ ResourceBuilder初期化
3. Validate: バリデーション
   ├─ --patchと--patch-fileの排他チェック
   ├─ --patchまたは--patch-fileの必須チェック
   └─ --typeの有効値チェック
4. RunPatch: パッチ実行
   ├─ パッチタイプの決定
   ├─ パッチデータ読み込み（ファイルまたは引数）
   ├─ YAML→JSON変換
   ├─ ResourceBuilder構築
   └─ r.Visit: 各リソースの処理
       ├─ [サーバーパッチ] helper.Patch
       │   └─ RecordMergePatch（--record時）
       └─ [ローカルパッチ] getPatchedJSON
```

### フローチャート

```mermaid
flowchart TD
    A[開始: RunPatch] --> B[パッチタイプ決定]
    B --> C{--patch-file?}
    C -->|Yes| D[ファイル読み込み]
    C -->|No| E[引数からパッチ取得]
    D --> F[YAML → JSON変換]
    E --> F
    F --> G[ResourceBuilder構築]
    G --> H[r.Visit]
    H --> I{ローカル && DryRunClient以外?}
    I -->|No - サーバーパッチ| J[helper.Patch]
    I -->|Yes - ローカルパッチ| K[getPatchedJSON]
    J --> L[didPatch判定]
    K --> L
    L --> M[PrintObj]
    M --> N{次のリソース?}
    N -->|Yes| H
    N -->|No| O{count == 0?}
    O -->|Yes| P[エラー: no objects passed]
    O -->|No| Q[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | patch/patch-file排他 | --patchと--patch-fileは同時指定不可 | 常時 |
| BR-02 | patch/patch-file必須 | いずれか一方は必須 | 常時 |
| BR-03 | local/args排他 | --localとサーバーリソース引数は同時指定不可 | --local時 |
| BR-04 | local/server-dry-run排他 | --localと--dry-run=serverは同時指定不可 | --local時 |
| BR-05 | パッチタイプ有効値 | json/merge/strategicのいずれか | --type指定時 |
| BR-06 | カスタムリソース制約 | Strategic merge patchはカスタムリソースにはサポートされない | CRD対象時 |
| BR-07 | 変更検出 | パッチ前後のオブジェクトをDeepEqualで比較し、変更有無を判定 | 常時 |

### 計算ロジック

- **getPatchedJSON関数（318-350行目）**: パッチタイプに応じた適用ロジック
  - JSONPatchType: jsonpatch.DecodePatch → Apply
  - MergePatchType: jsonpatch.MergePatch
  - StrategicMergePatchType: strategicpatch.StrategicMergePatch（スキーマ必要）

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リソース更新 | etcd（API Server経由） | UPDATE | PATCHによる部分更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 415 | UnsupportedMediaType | パッチタイプがリソースで未サポート | 別のパッチタイプを使用 |
| 422 | Unprocessable Entity | パッチ内容が無効 | パッチ内容を修正 |
| - | バリデーションエラー | --patchと--patch-fileの同時指定 | いずれか一方を使用 |
| - | パースエラー | パッチデータのYAML/JSONが不正 | パッチ内容を修正 |
| - | フィールド不足エラー | JSON Patchで対象フィールドが存在しない | パスを確認 |

### リトライ仕様

クライアント側でのリトライは行わない。

## トランザクション仕様

各リソースは個別にパッチが適用される。

## パフォーマンス要件

- パッチの計算はクライアントローカルで実行（ローカルパッチ時）
- API Server側のPATCH処理はサーバーパフォーマンスに依存

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

- patch権限が必要（RBAC）
- --patch-fileにより機密情報をコマンドライン引数に含めずに済む

## 備考

- patchTypesマップ（50行目）: {"json": JSONPatchType, "merge": MergePatchType, "strategic": StrategicMergePatchType}
- YAML入力はJSON変換後にパッチとして適用される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | PatchOptions構造体（54-78行目）でオプション全体を把握 |
| 1-2 | patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | patchTypesマップ（50行目）で対応パッチタイプを把握 |

#### Step 2: バリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | Validate関数（181-199行目）で排他制約を理解 |

**主要処理フロー**:
- **182-183行目**: --patchと--patch-fileの排他チェック
- **185-186行目**: いずれか必須チェック
- **188-189行目**: --localとサーバーリソース引数の排他チェック

#### Step 3: パッチ実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | RunPatch関数（202-316行目）でパッチ処理を理解 |
| 3-2 | patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | getPatchedJSON関数（318-350行目）でローカルパッチ処理を理解 |

**主要処理フロー**:
- **203-206行目**: パッチタイプ決定
- **208-217行目**: パッチデータ読み込み（ファイルまたは引数）
- **219-221行目**: YAML→JSON変換
- **247-284行目**: サーバーパッチ処理（helper.Patch → RecordMergePatch → PrintObj）
- **287-307行目**: ローカルパッチ処理（getPatchedJSON）
- **267行目**: reflect.DeepEqualによる変更検出

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

```
NewCmdPatch (patch.go:117)
    │
    ├─ Complete (patch.go:149)
    ├─ Validate (patch.go:181)
    └─ RunPatch (patch.go:202)
           ├─ yaml.ToJSON（パッチデータ変換）
           ├─ builder.Do()（リソース構築）
           └─ r.Visit
                  ├─ [サーバーパッチ]
                  │      ├─ resource.NewHelper.Patch
                  │      └─ Recorder.MakeRecordMergePatch
                  └─ [ローカルパッチ]
                         └─ getPatchedJSON (patch.go:318)
                                ├─ [JSON] jsonpatch.DecodePatch → Apply
                                ├─ [Merge] jsonpatch.MergePatch
                                └─ [Strategic] strategicpatch.StrategicMergePatch
```

### データフロー図

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

-p/--patch-file ──▶ パッチデータ ──▶ yaml.ToJSON
                                        │
リソース指定 ──▶ ResourceBuilder ──▶ r.Visit
                                        │
                                        ├─ [Server] helper.Patch ──▶ API Server
                                        │
                                        └─ [Local] getPatchedJSON ──▶ stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| patch.go | `staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go` | ソース | メインコマンド定義・パッチ処理 |
