# 帳票設計書 20-PersistentVolumeClaim一覧

## 概要

本ドキュメントは、Kubernetes PersistentVolumeClaimリソースの一覧をテーブル形式で出力する帳票の設計書である。`kubectl get pvc` コマンド実行時にPersistentVolumeClaimリソースの情報を人間が読みやすいテーブル形式で標準出力に表示する。

### 本帳票の処理概要

PersistentVolumeClaimリソースの一覧情報を取得し、テーブル形式で出力する処理を行う。

**業務上の目的・背景**：PersistentVolumeClaim（PVC）はユーザがストレージリソースを要求するためのリソースである。アプリケーションが必要とするストレージの状態（Pending/Bound/Lost）、バインドされたPV、要求した容量とアクセスモードを一覧で確認することは、アプリケーション運用とストレージ管理において不可欠である。PVCがBound状態にならない問題のトラブルシューティングや、ストレージ使用量の把握に利用される。

**帳票の利用シーン**：Namespace内のPVC一覧と状態を確認する場合、PVCとPVのバインド状態を確認する場合、ストレージ容量の確認、Pending状態のPVCの調査に利用される。

**主要な出力内容**：
1. PVC名
2. ステータス（Status）
3. バインドされたVolume名
4. 容量（Capacity）
5. アクセスモード（Access Modes）
6. StorageClass
7. VolumeAttributesClass
8. 作成からの経過時間（Age）
9. VolumeMode（Wide出力時）

**帳票の出力タイミング**：ユーザが `kubectl get pvc` コマンドを実行した際に出力される。

**帳票の利用者**：Kubernetesクラスタ管理者、アプリケーション開発者、SREエンジニア

## 帳票種別

一覧表（リソース一覧出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLIターミナル | - | `kubectl get pvc` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力） |
| 用紙サイズ | N/A（ターミナル出力） |
| 向き | N/A |
| ファイル名 | N/A（標準出力）|
| 出力方法 | 標準出力（stdout） |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

タブ区切りのテーブル形式で、通常モードとWideモードの2パターンが存在する。

```
[通常モード]
NAME         STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
my-claim     Bound    pv-01    10Gi       RWO            standard       <unset>                 5d
data-claim   Pending                                     fast           <unset>                 1m

[Wideモード (-o wide)]
NAME         STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
my-claim     Bound    pv-01    10Gi       RWO            standard       <unset>                 5d    Filesystem
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | NAME | PVC名 | `obj.Name` | 文字列 |
| 2 | STATUS | PVCのフェーズ | `obj.Status.Phase` | Pending/Bound/Lost/Terminating |
| 3 | VOLUME | バインドされたPV名 | `obj.Spec.VolumeName` | 文字列 |
| 4 | CAPACITY | 実際に割り当てられた容量 | `obj.Status.Capacity[ResourceStorage]` | Quantity文字列（例: 10Gi） |
| 5 | ACCESS MODES | アクセスモード | `obj.Status.AccessModes` | 略称文字列（例: RWO, ROX, RWX） |
| 6 | STORAGECLASS | ストレージクラス名 | `helper.GetPersistentVolumeClaimClass(obj)` | 文字列 |
| 7 | VOLUMEATTRIBUTESCLASS | ボリューム属性クラス名 | `obj.Spec.VolumeAttributesClassName` | 文字列、未設定時`<unset>` |
| 8 | AGE | 作成からの経過時間 | `obj.CreationTimestamp` | 相対時間（例: 5d, 1m） |
| 9 | VOLUMEMODE | ボリュームモード（Wide時のみ） | `obj.Spec.VolumeMode` | Filesystem/Block、未設定時`<unset>` |

### 明細部

ヘッダーと同一カラムで各PersistentVolumeClaimリソースの情報を1行ずつ出力する。

### フッター部

フッター部は存在しない。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| リソースタイプ | PersistentVolumeClaimリソースを対象とする | Yes |
| Namespace | 指定されたNamespace内のリソースを対象とする | No（デフォルトは現在のNamespace） |
| ラベルセレクタ | `-l` オプションで指定されたラベルによるフィルタリング | No |
| フィールドセレクタ | `--field-selector` オプションで指定されたフィールドによるフィルタリング | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | APIサーバからの返却順（デフォルト） | 昇順 |

### 改ページ条件

改ページは発生しない（ターミナル出力のため）。

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| etcd: /registry/persistentvolumeclaims/{namespace}/{name} | PVCリソースの保存先 | Namespace + リソース名で参照 |

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

#### PersistentVolumeClaim リソース

| 参照項目（フィールド名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| `metadata.name` | NAME | 全件取得 | そのまま文字列出力 |
| `metadata.creationTimestamp` | AGE | 全件取得 | 相対時間に変換 |
| `metadata.deletionTimestamp` | STATUS | 全件取得 | 非nilの場合「Terminating」に上書き |
| `spec.volumeName` | VOLUME | 全件取得 | バインド先のPV名 |
| `spec.resources.requests[storage]` | （内部参照のみ） | 全件取得 | バインド前の要求容量参照 |
| `spec.volumeMode` | VOLUMEMODE | Wide時 | nilの場合`<unset>` |
| `spec.volumeAttributesClassName` | VOLUMEATTRIBUTESCLASS | 全件取得 | nilの場合`<unset>` |
| `status.phase` | STATUS | 全件取得 | PersistentVolumeClaimPhase型をstring変換 |
| `status.capacity[storage]` | CAPACITY | 全件取得 | VolumeNameが設定されている場合のみ |
| `status.accessModes` | ACCESS MODES | 全件取得 | VolumeNameが設定されている場合のみ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| AGE | 現在時刻 - CreationTimestamp | N/A | `translateTimestampSince`関数で変換 |
| STATUS | DeletionTimestampが非nilなら"Terminating"、それ以外はStatus.Phase | N/A | DeletionTimestamp優先 |
| CAPACITY | VolumeNameが空でなければStatus.Capacity[ResourceStorage].String() | N/A | バインド前は空文字 |
| ACCESS MODES | VolumeNameが空でなければhelper.GetAccessModesAsString(Status.AccessModes) | N/A | バインド前は空文字 |
| STORAGECLASS | helper.GetPersistentVolumeClaimClass(obj) | N/A | StorageClassName取得 |
| VOLUMEATTRIBUTESCLASS | VolumeAttributesClassNameがnilなら`<unset>` | N/A | ポインタ型 |
| VOLUMEMODE | VolumeModeがnilなら`<unset>` | N/A | ポインタ型 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[kubectl get pvc 実行] --> B[コマンドパラメータ解析]
    B --> C[API Server へ LIST リクエスト]
    C --> D[PersistentVolumeClaim リソース一覧取得]
    D --> E[printPersistentVolumeClaim 関数で各行生成]
    E --> F[Status判定（Terminating含む）]
    F --> G{VolumeNameが設定されているか?}
    G -->|Yes| H[Status.CapacityとStatus.AccessModesを取得]
    G -->|No| I[Capacity, AccessModesは空文字]
    H --> J[HumanReadablePrinter でテーブル整形]
    I --> J
    J --> K[標準出力へ出力]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| リソース未存在 | 指定した名前のPVCが存在しない | `Error from server (NotFound): persistentvolumeclaims "<名前>" not found` | 正しいリソース名を指定 |
| 権限不足 | PVCリソースへのアクセス権限がない | `Error from server (Forbidden): ...` | RBACで適切な権限を付与 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数件〜数百件 |
| 目標出力時間 | 1秒以内 |
| 同時出力数上限 | N/A（CLIコマンド） |

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

PersistentVolumeClaimリソースの閲覧にはRBACによる `get` / `list` 権限が必要。PVCにはバインド先のPV名やStorageClass名が含まれるが、機密データそのものは含まれない。PVCはNamespaceスコープリソースである。

## 備考

- `kubectl get pvc` は `kubectl get persistentvolumeclaims` の省略形
- PVCがバインドされていない（VolumeName が空の）場合、CAPACITY と ACCESS MODES は空文字になる
- DeletionTimestampが設定されている場合、Status.Phaseに関係なく「Terminating」と表示される
- Wide出力（`-o wide`）ではVOLUMEMODEカラムが追加表示される
- CAPACITY はSpec.Resources.Requests（要求容量）ではなく、Status.Capacity（実際に割り当てられた容量）が表示される

---

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

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

### 推奨読解順序

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

PersistentVolumeClaimリソースのAPI型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `staging/src/k8s.io/api/core/v1/types.go` | PersistentVolumeClaim, PersistentVolumeClaimSpec, PersistentVolumeClaimStatus, PersistentVolumeClaimPhase の定義 |

**読解のコツ**: PVCにはSpec（要求）とStatus（実際の割り当て）の両方にCapacityとAccessModesがある。テーブル出力ではStatus側の値が使用される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | printers.go | `pkg/printers/internalversion/printers.go` | AddHandlers関数内のpersistentVolumeClaimColumnDefinitions（行321-333） |

**主要処理フロー**:
1. **行321-330**: persistentVolumeClaimColumnDefinitionsでカラム定義（Name, Status, Volume, Capacity, Access Modes, StorageClass, VolumeAttributesClass, Age, VolumeMode[Priority:1]）
2. **行332-333**: TableHandlerにprintPersistentVolumeClaimとprintPersistentVolumeClaimListを登録

#### Step 3: 印刷関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | printers.go | `pkg/printers/internalversion/printers.go` | printPersistentVolumeClaim関数（行2111-2144） |

**主要処理フロー**:
- **行2116-2119**: DeletionTimestampが非nilなら"Terminating"にフェーズを上書き
- **行2121-2122**: VolumeAttributesClassNameの初期値設定（`<unset>`）
- **行2123-2125**: capacity, accessModes, volumeModeの初期値設定（空文字/`<unset>`）
- **行2127-2129**: VolumeAttributesClassNameがnilでなければ値を設定
- **行2131-2135**: VolumeNameが設定されている場合のみ、Status.AccessModesとStatus.Capacityを取得
- **行2137-2139**: VolumeModeがnilでなければ値を設定
- **行2141-2142**: 全9カラムをrow.Cellsに追加

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

```
kubectl get pvc
    |
    +-- NewCmdGet (pkg/cmd/get/get.go)
    |      +-- RunGet
    |             +-- API Server LIST /api/v1/namespaces/{ns}/persistentvolumeclaims
    |
    +-- AddHandlers (pkg/printers/internalversion/printers.go:93)
    |      +-- TableHandler(persistentVolumeClaimColumnDefinitions, printPersistentVolumeClaim) (行332)
    |
    +-- printPersistentVolumeClaim (pkg/printers/internalversion/printers.go:2111)
    |      +-- helper.GetAccessModesAsString
    |      +-- helper.GetPersistentVolumeClaimClass
    |      +-- translateTimestampSince
    |
    +-- HumanReadablePrinter.PrintObj (cli-runtime/pkg/printers/tableprinter.go)
           +-- tabwriter による整形出力
```

### データフロー図

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

API Server                  printPersistentVolumeClaim()        標準出力(stdout)
(PersistentVolumeClaim      行2111-2144                         テーブル形式
 リソース一覧)       -------> - Status判定(Terminating)    -------> NAME | STATUS | VOLUME | CAPACITY |
                             - VolumeName確認                       ACCESS MODES | STORAGECLASS |
                             - Capacity/AccessModes条件取得         VOLUMEATTRIBUTESCLASS | AGE
                             - VolumeMode取得                       (Wide時: + VOLUMEMODE)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| printers.go | `pkg/printers/internalversion/printers.go` | ソース | カラム定義とprintPersistentVolumeClaim関数 |
| tableprinter.go | `staging/src/k8s.io/cli-runtime/pkg/printers/tableprinter.go` | ソース | HumanReadablePrinterによるテーブル出力エンジン |
| types.go | `staging/src/k8s.io/api/core/v1/types.go` | ソース | PersistentVolumeClaim API型定義 |
| helpers.go | `pkg/apis/core/helper/helpers.go` | ソース | GetAccessModesAsString, GetPersistentVolumeClaimClass関数 |
| printers_test.go | `pkg/printers/internalversion/printers_test.go` | テスト | printPersistentVolumeClaimのテストケース |
