# 機能設計書 12-コンピューター管理

## 概要

本ドキュメントは、Jenkinsにおけるコンピューター（Computer）管理機能の設計について記述する。この機能は、ビルドを実行するノードの実行時状態を管理し、接続・切断・オフライン制御・エグゼキューター管理等を提供する。

### 本機能の処理概要

コンピューター管理機能は、Jenkins上で設定されたNode（ノード）の実行時インスタンスであるComputer（コンピューター）を管理する。NodeがJenkinsの設定上の概念であるのに対し、ComputerはExecutor（エグゼキューター）を保持し、実際にビルドを実行する実行時オブジェクトである。

**業務上の目的・背景**：CI/CD環境では、複数のビルドエージェントを効率的に管理する必要がある。コンピューター管理機能により、管理者はエージェントの接続状態の監視、メンテナンス時のオフライン切り替え、トラブル発生時の切断・再接続、エグゼキューター数の調整などを行える。これにより、ビルド基盤の安定運用と柔軟なリソース管理が実現される。

**機能の利用シーン**：
- 新規エージェントノードの追加・設定変更後の接続確認
- メンテナンス作業のためのノードの一時オフライン化
- 接続トラブル発生時のエージェント再接続
- ノードの負荷状況監視とリソース配分の最適化
- 不要になったエージェントノードの削除

**主要な処理内容**：
1. Nodeオブジェクトに対応するComputerオブジェクトの生成・管理
2. エージェントとの通信チャネル（VirtualChannel）の確立と維持
3. Executor（エグゼキューター）スレッドの生成・管理・破棄
4. オンライン/オフライン状態の制御とOfflineCause（オフライン理由）の記録
5. NodeMonitorと連携したヘルスチェック情報の収集・表示
6. ノード設定の更新処理（config.xml の読み書き）

**関連システム・外部連携**：エージェントノードとのRemoting通信、NodeMonitorによるシステム情報収集（ディスク容量、メモリ、JVMスレッドダンプ等）。

**権限による制御**：
- Computer.CONFIGURE: ノード設定の変更
- Computer.CONNECT: ノードへの接続開始
- Computer.DISCONNECT: ノードからの切断
- Computer.DELETE: ノードの削除
- Computer.CREATE: 新規ノードの作成
- Computer.BUILD: ノード上でのビルド実行

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | ノード一覧 | 主画面 | ノード一覧の表示と状態確認 |
| 22 | ノード詳細 | 主画面 | ノードの詳細情報表示 |
| 23 | ノード設定 | 主画面 | ノード設定の編集 |
| 24 | ノード負荷統計 | 結果表示画面 | ノードの負荷統計グラフ表示 |
| 25 | ノードオフライン設定 | 主画面 | ノードのオフライン切り替え |

## 機能種別

CRUD操作 / データ連携 / 計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ノード名（Computer識別子） | 空文字不可、重複不可 |
| numExecutors | int | Yes | エグゼキューター数 | 1以上の整数 |
| offlineMessage | String | No | オフライン理由メッセージ | - |
| forceReconnect | boolean | No | 再接続時に既存接続を強制キャンセル | - |

### 入力データソース

- Jenkins.nodes: 設定済みノードのリスト
- StaplerRequest: Web UIからのフォーム入力
- config.xml: ノード設定ファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Computer | Computer | ノードの実行時状態オブジェクト |
| Executor[] | List<Executor> | エグゼキュータースレッドのリスト |
| monitorData | Map<String, Object> | NodeMonitorから収集した監視データ |
| offlineCause | OfflineCause | オフライン状態の場合、その理由 |

### 出力先

- Web UI: ノード一覧・詳細画面への表示
- REST API: /computer/ 配下のJSONレスポンス
- ログファイル: $JENKINS_HOME/logs/slaves/{nodeName}/slave.log

## 処理フロー

### 処理シーケンス

```
1. Jenkins起動時のComputer初期化
   └─ Jenkins.updateComputerList()で全Nodeに対応するComputerを生成
2. ノード接続処理（Computer.connect()）
   └─ ComputerLauncherを通じてエージェントプロセスを起動
   └─ VirtualChannel（Remoting接続）の確立
3. Executor生成（Computer.setNumExecutors()）
   └─ 設定数に応じてExecutorスレッドを生成
4. オンライン/オフライン状態管理
   └─ setTemporaryOfflineCause()でオフライン状態を設定
   └─ disconnect()で接続を切断
5. 設定変更処理（Computer.doConfigSubmit()）
   └─ フォーム入力を検証し、Node.reconfigure()を呼び出し
   └─ Jenkins.getNodesObject().replaceNode()でノードを更新
6. Computer削除処理（Computer.doDoDelete()）
   └─ Jenkins.removeNode()またはremoveComputer()を呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[Jenkins起動] --> B[updateComputerList]
    B --> C{各Nodeに対して}
    C --> D[Computer生成]
    D --> E{接続タイプ?}
    E -->|自動接続| F[ComputerLauncher.launch]
    E -->|インバウンド| G[接続待機]
    F --> H{接続成功?}
    G --> H
    H -->|Yes| I[setNumExecutors]
    H -->|No| J[オフライン状態]
    I --> K[Executor生成]
    K --> L[オンライン状態]
    L --> M{操作}
    M -->|オフライン| N[setTemporaryOfflineCause]
    M -->|切断| O[disconnect]
    M -->|設定変更| P[doConfigSubmit]
    M -->|削除| Q[doDoDelete]
    N --> L
    O --> J
    P --> C
    Q --> R[Computer破棄]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-12-01 | ビルトインノード保護 | マスターノード（ビルトインノード）は削除・切断不可 | マスターノード操作時 |
| BR-12-02 | エグゼキューター数変更 | 設定数を減らしても、実行中のビルドは完了まで継続 | numExecutors変更時 |
| BR-12-03 | 一時オフライン | 一時オフライン状態でもVirtualChannel接続は維持 | setTemporaryOfflineCause時 |
| BR-12-04 | ノード名重複禁止 | 同一名のノードは存在できない | ノード作成・名称変更時 |
| BR-12-05 | 削除前ビルド完了待機 | Executorが全てアイドルになるまでComputer削除を待機 | Computer.kill()時 |

### 計算ロジック

- アイドルエグゼキューター数: `countIdle() = executors.stream().filter(Executor::isIdle).count()`
- ビジーエグゼキューター数: `countBusy() = countExecutors() - countIdle()`
- アイドル開始時刻: 全Executorのうち最も遅いアイドル開始時刻

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

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

本機能はデータベースではなく、XMLファイルベースの設定永続化を使用。

| 操作 | 対象ファイル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ノード設定保存 | nodes/{nodeName}/config.xml | INSERT/UPDATE | ノード設定の永続化 |
| モニター設定保存 | nodeMonitors.xml | UPDATE | NodeMonitor設定の永続化 |
| ログ出力 | logs/slaves/{nodeName}/slave.log | INSERT | エージェントログの記録 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FormException | ノード名重複 | エラーメッセージ表示、再入力促進 |
| - | ServletException | ノード未存在 | 404エラー、一覧画面へリダイレクト |
| - | AccessDeniedException | 権限不足 | 403エラー、ログイン促進 |
| - | IOException | 接続失敗 | オフライン状態に移行、リトライ可能 |

### リトライ仕様

- RetentionStrategyによる自動再接続制御
- Computer.connect(true)で強制再接続（既存接続をキャンセル）

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

- Queue.lockによるExecutor操作の排他制御
- statusChangeLockによるオンライン/オフライン状態変更の同期
- BulkChangeによる設定変更時の一括保存

## パフォーマンス要件

- threadPoolForRemoting: エージェント通信用のキャッシュスレッドプール
- waitUntilOnline/Offline: 1秒間隔でのポーリング待機

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

- Computer.PERMISSIONS グループによる細粒度アクセス制御
- Jenkins.ADMINISTER権限によるスクリプトコンソール実行制限
- EXTENDED_READ権限によるconfig.xml閲覧時の機密情報マスキング
- ACL.SYSTEM2によるシステム権限でのリモーティング処理

## 備考

- ComputerはNodeと1対1で対応するが、ライフサイクルは異なる
- Nodeを削除してもビルド実行中のComputerは即座には削除されない
- OneOffExecutorはFlyweightTask（軽量タスク）用の一時的なエグゼキューター

---

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

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

### 推奨読解順序

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

ComputerとNodeの関係、Executorの役割を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Computer.java | `core/src/main/java/hudson/model/Computer.java` | 実行時状態管理クラス、Executor保持 |
| 1-2 | Node.java | `core/src/main/java/hudson/model/Node.java` | 設定情報を持つ抽象クラス |
| 1-3 | Executor.java | `core/src/main/java/hudson/model/Executor.java` | ビルド実行スレッド |

**読解のコツ**: ComputerはActionable, AccessControlledを実装しており、Web UIとの連携およびセキュリティ制御が組み込まれている。

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

ComputerSetからのアクセスとComputer個別操作の起点を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ComputerSet.java | `core/src/main/java/hudson/model/ComputerSet.java` | Computer一覧管理、/computer/ URLのルート |

**主要処理フロー**:
1. **133-135行目**: getComputers()で全Computer取得（ソート済み）
2. **246-254行目**: do_launchAll()で全ノード接続開始
3. **279-356行目**: doCreateItem()で新規ノード作成

#### Step 3: 接続・切断処理を理解する

Computer.connect()とdisconnect()の処理フローを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Computer.connect() | `core/src/main/java/hudson/model/Computer.java` | 接続開始処理（440-443行目） |
| 3-2 | Computer.disconnect() | `core/src/main/java/hudson/model/Computer.java` | 切断処理（502-527行目） |

**主要処理フロー**:
- **440-443行目**: connect()でconnectTimeを記録し、_connect()を呼び出し
- **502-510行目**: disconnect(OfflineCause)でオフライン理由を設定

#### Step 4: Executor管理を理解する

エグゼキューターの生成・削除ロジックを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Computer.setNumExecutors() | `core/src/main/java/hudson/model/Computer.java` | エグゼキューター数変更（861-882行目） |
| 4-2 | Computer.removeExecutor() | `core/src/main/java/hudson/model/Computer.java` | エグゼキューター削除（1063-1083行目） |

**主要処理フロー**:
- **861-882行目**: setNumExecutors()で必要に応じてExecutorを追加・削除
- **869-875行目**: Queue.withLock()内でアイドルExecutorにinterrupt送信
- **884-906行目**: addNewExecutorIfNecessary()で不足分のExecutor追加

#### Step 5: 設定変更・削除処理を理解する

Web UIからの設定操作の処理フローを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Computer.doConfigSubmit() | `core/src/main/java/hudson/model/Computer.java` | 設定保存処理（1484-1519行目） |
| 5-2 | Computer.doDoDelete() | `core/src/main/java/hudson/model/Computer.java` | 削除処理（1580-1591行目） |

**主要処理フロー**:
- **1484-1519行目**: doConfigSubmit()でフォーム検証、Node.reconfigure()、replaceNode()
- **1580-1591行目**: doDoDelete()でJenkins.removeNode()呼び出し

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

```
ComputerSet (URL: /computer/)
    │
    ├─ getComputers()
    │      └─ Jenkins.getComputersCollection()
    │
    ├─ doCreateItem()
    │      └─ Jenkins.addNode()
    │             └─ updateComputerList()
    │
    └─ Computer (URL: /computer/{name}/)
           │
           ├─ connect()
           │      └─ _connect() [サブクラス実装]
           │             └─ ComputerLauncher.launch()
           │
           ├─ disconnect()
           │      └─ recordTermination()
           │
           ├─ setNumExecutors()
           │      ├─ Queue.withLock()
           │      └─ addNewExecutorIfNecessary()
           │             └─ new Executor(this, number)
           │
           ├─ doConfigSubmit()
           │      ├─ Node.reconfigure()
           │      └─ Nodes.replaceNode()
           │
           └─ doDoDelete()
                  └─ Jenkins.removeNode()
```

### データフロー図

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

StaplerRequest ─────────▶ ComputerSet.doCreateItem() ──▶ Node (config.xml)
  (フォーム入力)                   │
                                 ▼
                         Jenkins.addNode()
                                 │
                                 ▼
                         updateComputerList() ─────────▶ Computer (インスタンス)
                                 │
                                 ▼
                         Computer.connect() ───────────▶ VirtualChannel
                                 │                      (エージェント接続)
                                 ▼
                         setNumExecutors() ────────────▶ Executor[] (スレッド)
                                 │
                                 ▼
NodeMonitor ────────────▶ getMonitorData() ────────────▶ monitorData (JSON)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Computer.java | `core/src/main/java/hudson/model/Computer.java` | ソース | 実行時状態管理クラス |
| ComputerSet.java | `core/src/main/java/hudson/model/ComputerSet.java` | ソース | Computer一覧管理 |
| Node.java | `core/src/main/java/hudson/model/Node.java` | ソース | ノード設定抽象クラス |
| Slave.java | `core/src/main/java/hudson/model/Slave.java` | ソース | エージェントノード実装 |
| Executor.java | `core/src/main/java/hudson/model/Executor.java` | ソース | ビルド実行スレッド |
| OneOffExecutor.java | `core/src/main/java/hudson/model/OneOffExecutor.java` | ソース | 軽量タスク用一時エグゼキューター |
| ComputerLauncher.java | `core/src/main/java/hudson/slaves/ComputerLauncher.java` | ソース | エージェント起動抽象クラス |
| RetentionStrategy.java | `core/src/main/java/hudson/slaves/RetentionStrategy.java` | ソース | エージェント保持戦略 |
| OfflineCause.java | `core/src/main/java/hudson/slaves/OfflineCause.java` | ソース | オフライン理由クラス |
| NodeMonitor.java | `core/src/main/java/hudson/node_monitors/NodeMonitor.java` | ソース | ノード監視基底クラス |
