# 帳票設計書 19-PersistentVolume一覧

## 概要

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

### 本帳票の処理概要

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

**業務上の目的・背景**：PersistentVolume（PV）はクラスタ内のストレージリソースを表す。管理者がプロビジョニングしたストレージの状態（Available/Bound/Released/Failed）、容量、アクセスモード、リクレームポリシーを一覧で把握することは、ストレージ管理において不可欠である。PVのライフサイクル管理、ストレージキャパシティプランニング、PVC（PersistentVolumeClaim）との紐付け状況の確認に利用される。

**帳票の利用シーン**：クラスタ内のストレージリソースの状況を確認する場合、PVとPVCの紐付け状態を確認する場合、ストレージクラスごとのPV配分を確認する場合、Released状態のPVの棚卸しに利用される。

**主要な出力内容**：
1. PV名
2. 容量（Capacity）
3. アクセスモード（Access Modes）
4. リクレームポリシー（Reclaim Policy）
5. ステータス（Status）
6. バインドされたClaim（Claim）
7. StorageClass
8. VolumeAttributesClass
9. 理由（Reason）
10. 作成からの経過時間（Age）
11. VolumeMode（Wide出力時）

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

**帳票の利用者**：Kubernetesクラスタ管理者、ストレージエンジニア、SREエンジニア

## 帳票種別

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

## 利用画面

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

## 出力形式

### 基本仕様

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

## 帳票レイアウト

### レイアウト概要

タブ区切りのテーブル形式で、通常モードとWideモードの2パターンが存在する。カラム数が多い帳票である。

```
[通常モード]
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-01   10Gi       RWO            Retain           Bound    default/my-claim   standard       <unset>                          30d
pv-02   20Gi       RWX            Delete           Available                   fast           <unset>                          5d

[Wideモード (-o wide)]
（上記カラム + VOLUMEMODE）
NAME    ... AGE   VOLUMEMODE
pv-01   ... 30d   Filesystem
pv-02   ... 5d    Block
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | NAME | PV名 | `obj.Name` | 文字列 |
| 2 | CAPACITY | ストレージ容量 | `obj.Spec.Capacity[ResourceStorage]` | Quantity文字列（例: 10Gi） |
| 3 | ACCESS MODES | アクセスモード | `obj.Spec.AccessModes` | 略称文字列（例: RWO, ROX, RWX） |
| 4 | RECLAIM POLICY | リクレームポリシー | `obj.Spec.PersistentVolumeReclaimPolicy` | Retain/Delete/Recycle |
| 5 | STATUS | PVのフェーズ | `obj.Status.Phase` | Available/Bound/Released/Failed/Terminating |
| 6 | CLAIM | バインドされたPVC | `obj.Spec.ClaimRef` | "namespace/name"形式 |
| 7 | STORAGECLASS | ストレージクラス名 | `helper.GetPersistentVolumeClass(obj)` | 文字列 |
| 8 | VOLUMEATTRIBUTESCLASS | ボリューム属性クラス名 | `obj.Spec.VolumeAttributesClassName` | 文字列、未設定時`<unset>` |
| 9 | REASON | ステータスの理由 | `obj.Status.Reason` | 文字列 |
| 10 | AGE | 作成からの経過時間 | `obj.CreationTimestamp` | 相対時間（例: 30d, 5h） |
| 11 | VOLUMEMODE | ボリュームモード（Wide時のみ） | `obj.Spec.VolumeMode` | Filesystem/Block、未設定時`<unset>` |

### 明細部

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

### フッター部

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

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| リソースタイプ | PersistentVolumeリソースを対象とする | Yes |
| ラベルセレクタ | `-l` オプションで指定されたラベルによるフィルタリング | No |
| フィールドセレクタ | `--field-selector` オプションで指定されたフィールドによるフィルタリング | No |

### ソート順

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

### 改ページ条件

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| etcd: /registry/persistentvolumes/{name} | PersistentVolumeリソースの保存先 | リソース名で直接参照 |

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

#### PersistentVolume リソース

| 参照項目（フィールド名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| `metadata.name` | NAME | 全件取得 | そのまま文字列出力 |
| `metadata.creationTimestamp` | AGE | 全件取得 | 相対時間に変換 |
| `metadata.deletionTimestamp` | STATUS | 全件取得 | 非nilの場合「Terminating」に上書き |
| `spec.capacity[storage]` | CAPACITY | 全件取得 | Quantity.String()で文字列化 |
| `spec.accessModes` | ACCESS MODES | 全件取得 | helper.GetAccessModesAsStringで変換 |
| `spec.persistentVolumeReclaimPolicy` | RECLAIM POLICY | 全件取得 | string変換 |
| `spec.claimRef.namespace` | CLAIM | 全件取得 | namespace/name形式で結合 |
| `spec.claimRef.name` | CLAIM | 全件取得 | namespace/name形式で結合 |
| `spec.volumeMode` | VOLUMEMODE | Wide時 | nilの場合`<unset>` |
| `spec.volumeAttributesClassName` | VOLUMEATTRIBUTESCLASS | 全件取得 | nilの場合`<unset>` |
| `status.phase` | STATUS | 全件取得 | PersistentVolumePhase型をstring変換 |
| `status.reason` | REASON | 全件取得 | そのまま文字列出力 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| AGE | 現在時刻 - CreationTimestamp | N/A | `translateTimestampSince`関数で変換 |
| CAPACITY | obj.Spec.Capacity[ResourceStorage].String() | N/A | Quantity型の文字列表現 |
| ACCESS MODES | helper.GetAccessModesAsString(obj.Spec.AccessModes) | N/A | RWO/ROX/RWX/RWOP形式 |
| STATUS | DeletionTimestampが非nilなら"Terminating"、それ以外はStatus.Phase | N/A | DeletionTimestamp優先 |
| CLAIM | ClaimRef.Namespace + "/" + ClaimRef.Name | N/A | ClaimRefがnilなら空文字 |
| STORAGECLASS | helper.GetPersistentVolumeClass(obj) | N/A | StorageClassName取得 |
| VOLUMEATTRIBUTESCLASS | VolumeAttributesClassNameがnilなら`<unset>` | N/A | ポインタ型 |
| VOLUMEMODE | VolumeModeがnilなら`<unset>` | N/A | ポインタ型 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[kubectl get pv 実行] --> B[コマンドパラメータ解析]
    B --> C[API Server へ LIST リクエスト]
    C --> D[PersistentVolume リソース一覧取得]
    D --> E[printPersistentVolume 関数で各行生成]
    E --> F[ClaimRef解析]
    F --> G[AccessModes文字列変換]
    G --> H[Status判定（Terminating含む）]
    H --> I[HumanReadablePrinter でテーブル整形]
    I --> J[標準出力へ出力]
```

## エラー処理

### エラーケース一覧

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

## パフォーマンス要件

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

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

PersistentVolumeリソースにはストレージバックエンドの情報（NFS サーバアドレス、AWS EBS ボリュームIDなど）が含まれる場合がある。一覧表示ではこれらの詳細情報は表示されないが、PV名やStorageClass名からインフラ構成が推測される可能性がある。PVはクラスタスコープリソースであり、閲覧にはRBACによる `get` / `list` 権限が必要。

## 備考

- PVはクラスタスコープリソースであり、Namespace指定は不要
- `kubectl get pv` は `kubectl get persistentvolumes` の省略形
- DeletionTimestampが設定されている場合、Status.Phaseに関係なく「Terminating」と表示される
- Wide出力（`-o wide`）ではVOLUMEMODEカラムが追加表示される
- 通常モードでも10カラムあり、ターミナル幅が狭い場合は表示が見づらくなる

---

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

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

### 推奨読解順序

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

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

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

**読解のコツ**: PVSpecにはCapacity, AccessModes, PersistentVolumeReclaimPolicy, ClaimRef, VolumeMode等の重要フィールドが多い。

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

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

**主要処理フロー**:
1. **行305-316**: persistentVolumeColumnDefinitionsでカラム定義（Name, Capacity, Access Modes, Reclaim Policy, Status, Claim, StorageClass, VolumeAttributesClass, Reason, Age, VolumeMode[Priority:1]）
2. **行318-319**: TableHandlerにprintPersistentVolumeとprintPersistentVolumeListを登録

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

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

**主要処理フロー**:
- **行2066-2071**: ClaimRefからnamespace/name形式のクレーム参照文字列を生成
- **行2073**: `helper.GetAccessModesAsString`でアクセスモード文字列を生成
- **行2074**: `PersistentVolumeReclaimPolicy`を文字列に変換
- **行2076-2077**: Capacity[ResourceStorage]のQuantity文字列を取得
- **行2079-2082**: DeletionTimestampが非nilなら"Terminating"にフェーズを上書き
- **行2083-2086**: VolumeModeがnilなら`<unset>`
- **行2088-2091**: VolumeAttributesClassNameがnilなら`<unset>`
- **行2093-2095**: 全11カラムをrow.Cellsに追加

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

```
kubectl get pv
    |
    +-- NewCmdGet (pkg/cmd/get/get.go)
    |      +-- RunGet
    |             +-- API Server LIST /api/v1/persistentvolumes
    |
    +-- AddHandlers (pkg/printers/internalversion/printers.go:93)
    |      +-- TableHandler(persistentVolumeColumnDefinitions, printPersistentVolume) (行318)
    |
    +-- printPersistentVolume (pkg/printers/internalversion/printers.go:2061)
    |      +-- helper.GetAccessModesAsString
    |      +-- helper.GetPersistentVolumeClass
    |      +-- translateTimestampSince
    |
    +-- HumanReadablePrinter.PrintObj (cli-runtime/pkg/printers/tableprinter.go)
           +-- tabwriter による整形出力
```

### データフロー図

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

API Server               printPersistentVolume()          標準出力(stdout)
(PersistentVolume        行2061-2097                      テーブル形式
 リソース一覧)   -------> - ClaimRef解析             -------> NAME | CAPACITY | ACCESS MODES |
                         - AccessModes変換                    RECLAIM POLICY | STATUS | CLAIM |
                         - Status判定                         STORAGECLASS | VOLUMEATTRIBUTESCLASS |
                         - Capacity取得                       REASON | AGE
                         - VolumeMode取得                     (Wide時: + VOLUMEMODE)
```

### 関連ファイル一覧

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