# 機能設計書 96-アノテーション管理（annotate）

## 概要

本ドキュメントは、kubectl annotateコマンドによるKubernetesリソースへのアノテーション追加・更新・削除機能の設計を記述する。

### 本機能の処理概要

kubectl annotateコマンドは、任意のKubernetesリソースに対してアノテーション（key/value ペア）を追加・更新・削除するCLI機能である。

**業務上の目的・背景**：アノテーションはラベルと異なり、セレクタには使用されないが、ツールやシステム拡張がメタデータを保存するための汎用的な仕組みである。構造化JSONなどの大きな値も保持可能。

**機能の利用シーン**：Ingressコントローラー設定（nginx.ingress.kubernetes.io/*）、CI/CDパイプライン情報の付与、変更記録（kubernetes.io/change-cause）、運用メモの付与、外部ツール連携用メタデータの管理。

**主要な処理内容**：
1. コマンドライン引数からリソースとアノテーション仕様を解析
2. 対象リソースの取得（Builder パターン）
3. アノテーションの追加・更新・削除をMerge Patchで適用
4. 結果の出力

**関連システム・外部連携**：Ingressコントローラー、cert-manager、Istio等の多くのツールがアノテーションを設定情報として使用する。

**権限による制御**：対象リソースのupdate/patch権限（RBAC）が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | kubectl annotate | 主機能 | リソースへのアノテーション追加・更新・削除 |

## 機能種別

CRUD操作（Update） / リソースメタデータ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| TYPE NAME | string | Yes(ファイル未指定時) | リソースタイプと名前 | 有効なリソースタイプ |
| ANNOTATION_SPEC | string[] | Yes(--list未指定時) | アノテーション仕様（key=value / key-） | 有効なアノテーション形式 |
| --overwrite | bool | No | 既存アノテーションの上書き許可 | - |
| --all | bool | No | 指定タイプの全リソースを選択 | - |
| --all-namespaces / -A | bool | No | 全Namespaceを対象 | - |
| --selector / -l | string | No | ラベルセレクタ | 有効なラベルセレクタ形式 |
| --field-selector | string | No | フィールドセレクタ | 有効なフィールドセレクタ形式 |
| --resource-version | string | No | リソースバージョン（楽観ロック） | 単一リソース時のみ |
| --list | bool | No | 現在のアノテーション一覧を表示 | - |
| --local | bool | No | ローカルモード（API呼び出しなし） | - |
| -f / --filename | string | No | リソース定義ファイル | 有効なファイルパス |
| --dry-run | string | No | dry-run戦略 | none/client/server |

### 入力データソース

CLI引数、ファイル（-fオプション）、kubeconfig

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| アノテーション操作結果 | string | "resource annotated" メッセージ |
| アノテーション一覧 | string | --list時のkey=value一覧 |

### 出力先

標準出力（stdout）

## 処理フロー

### 処理シーケンス

```
1. NewCmdAnnotate: cobraコマンド定義
2. AnnotateFlags.ToOptions: フラグからランタイムオプションへ変換
   ├─ GetResourcesAndPairs: リソースとアノテーション引数を分離
   ├─ parseAnnotations: アノテーション仕様のパース
   └─ validateAnnotations: 追加と削除の矛盾チェック
3. RunAnnotate: アノテーション操作実行
   ├─ resource.Builderでリソース取得
   ├─ 各リソースに対して:
   │   ├─ updateAnnotations: アノテーション追加・削除
   │   ├─ jsonpatch.CreateMergePatch生成
   │   └─ helper.Patch() / helper.Replace()
   └─ 結果出力（--list時はkey=value一覧）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ToOptions: フラグ→オプション変換]
    B --> C[parseAnnotations: 仕様パース]
    C --> D[validateAnnotations: 矛盾チェック]
    D --> E[RunAnnotate: リソース取得]
    E --> F{--list モード?}
    F -->|Yes| G[アノテーション一覧出力]
    F -->|No| H{dry-run client / local?}
    H -->|Yes| I[ローカル更新→出力]
    H -->|No| J[Merge Patch生成]
    J --> K{パッチ生成成功?}
    K -->|Yes| L[helper.Patch]
    K -->|No| M[helper.Replace]
    L --> N[結果出力]
    M --> N
    I --> N
    G --> O[終了]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-96-01 | 上書き保護 | 既存アノテーションの更新は--overwrite必須（change-causeアノテーションは例外） | デフォルト |
| BR-96-02 | 矛盾禁止 | 同一キーの追加と削除を同時指定不可 | 常時 |
| BR-96-03 | resource-version排他 | resource-versionは単一リソース時のみ使用可 | 複数リソース時 |
| BR-96-04 | listとoutput排他 | --listと--outputは同時指定不可 | - |
| BR-96-05 | allとselector排他 | --allと--selectorは同時指定不可 | - |
| BR-96-06 | allとfield-selector排他 | --allと--field-selectorは同時指定不可 | - |
| BR-96-07 | change-cause例外 | kubernetes.io/change-causeアノテーションは--overwriteなしでも更新可能 | 常時 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Annotate操作 | 任意のKubernetesリソース | PATCH | metadata.annotationsをMerge Patchで更新 |
| Replace | 任意のKubernetesリソース | PUT | パッチ生成失敗時のフォールバック |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 上書きエラー | 既存アノテーション更新時に--overwrite未指定 | --overwriteを指定 |
| - | 矛盾エラー | 同一キーの追加と削除を同時指定 | 矛盾を解消 |
| - | resource-versionエラー | 複数リソースにresource-version指定 | 単一リソースに限定 |
| - | listとoutputの競合 | --listと--outputの同時指定 | どちらか一方を選択 |
| - | ローカルモードエラー | --localと--dry-run=serverの同時指定 | --dry-run=clientに変更 |

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

Merge PatchまたはReplace（パッチ生成失敗時のフォールバック）で実行。resource-version指定時は楽観的並行制御。resource-versionは空文字列をクリアして送信することで常にパッチに含まれる。

## パフォーマンス要件

Merge Patchによる軽量操作。--all/--selector使用時はリソース数に比例。

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

- 対象リソースのupdate/patch権限が必要
- アノテーションの値にサイズ制限はKubernetesのetcdサイズ制限に依存
- セキュリティ関連アノテーション（cert-manager、NetworkPolicy等）の変更は慎重に実施

## 備考

- アノテーションはラベルと異なりセレクタに使用されない
- アノテーション値にはサイズの大きな構造化データも保持可能
- --listオプションで現在のアノテーションを一覧表示可能

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **52-70行目**: AnnotateFlags構造体でCLI入力フラグの全体を把握 |
| 1-2 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **82-111行目**: AnnotateOptions構造体でランタイムオプションを確認 |

**読解のコツ**: Flags→Optionsの2段階構造はkubectlの標準パターン。FlagsはCLI入力そのまま、OptionsはValidation後のランタイム情報。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **149-169行目**: NewCmdAnnotate関数。Run内で`flags.ToOptions()`→`o.RunAnnotate()`の2段階実行 |

#### Step 3: 入力変換（ToOptions）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **193-285行目**: ToOptions関数でフラグからオプションへの変換とバリデーションを確認 |
| 3-2 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **240行目**: GetResourcesAndPairsでリソースとアノテーション引数を分離 |
| 3-3 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **413-415行目**: parseAnnotationsはcmdutil.ParsePairsに委譲 |
| 3-4 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **418-433行目**: validateAnnotationsで追加と削除の矛盾チェック |

#### Step 4: 実行処理（RunAnnotate）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **288-410行目**: RunAnnotate関数が処理本体 |
| 4-2 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **329-333行目**: dry-run client / local / list時はローカル更新のみ |
| 4-3 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **338-344行目**: resource-version指定時はアクセッサからクリア（パッチに含めるため） |
| 4-4 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **361行目**: jsonpatch.CreateMergePatchでパッチ生成 |
| 4-5 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **376-380行目**: パッチ成功時はPatch、失敗時はReplaceにフォールバック |
| 4-6 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **457-485行目**: updateAnnotations関数で実際のアノテーション更新ロジック |
| 4-7 | annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | **436-454行目**: validateNoAnnotationOverwritesでchange-causeの例外処理（440-442行目） |

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

```
NewCmdAnnotate
    │
    ├─ AnnotateFlags.ToOptions
    │      ├─ RecordFlags.Complete / ToRecorder
    │      ├─ GetDryRunStrategy
    │      ├─ PrintFlags.ToPrinter
    │      ├─ GetResourcesAndPairs(args, "annotation")
    │      ├─ parseAnnotations → cmdutil.ParsePairs
    │      └─ validateAnnotations
    │
    └─ RunAnnotate
           ├─ builder.Unstructured().LocalParam().Do()
           │      └─ r.Visit() 各リソースに対して:
           │             ├─ updateAnnotations(obj)
           │             │      ├─ validateNoAnnotationOverwrites()
           │             │      ├─ annotations[key] = value (追加)
           │             │      ├─ delete(annotations, key) (削除)
           │             │      └─ accessor.SetAnnotations()
           │             ├─ jsonpatch.CreateMergePatch(oldData, newData)
           │             ├─ helper.Patch() / helper.Replace()
           │             └─ PrintObj() or list出力
           └─ (--list時) accessor.GetAnnotations() → 表示
```

### データフロー図

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

CLI引数                  ───▶ ToOptions
 (TYPE NAME key=value)         ├─ parseAnnotations
                               └─ validateAnnotations
                                     │
                                     ▼
kubeconfig              ───▶ RunAnnotate
                         ├─ Builder.Do()        ───▶ API Server (GET)
                         ├─ updateAnnotations()
                         ├─ CreateMergePatch()
                         ├─ helper.Patch()      ───▶ API Server (PATCH)
                         │   or Replace()       ───▶ API Server (PUT)
                         └─ PrintObj()          ───▶ stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| annotate.go | `staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go` | ソース | annotateコマンドのメイン実装（486行） |
| util.go | `staging/src/k8s.io/kubectl/pkg/cmd/util/helpers.go` | ソース | ParsePairs等の共通ユーティリティ |
| polymorphichelpers | `staging/src/k8s.io/kubectl/pkg/polymorphichelpers/` | ソース | ChangeCauseAnnotation定数の定義 |
