# 通知設計書 43-コントローラーエグゼキュータ警告（ControllerExecutorsNoAgents）

## 概要

本ドキュメントは、JenkinsのControllerExecutorsNoAgents（コントローラーエグゼキュータ警告：エージェント非存在時）に関する通知設計書である。エージェントもクラウドも設定されていない状態で、ビルトインノード（コントローラー）にエグゼキュータが設定されている場合にセキュリティ警告を表示し、分散ビルド環境の構築を推奨するAdministrativeMonitor機能について記述する。

### 本通知の処理概要

ControllerExecutorsNoAgentsは、Jenkinsコントローラー上でのみビルドを実行している環境に対して、分散ビルド環境（エージェント設定）の構築を推奨するAdministrativeMonitorである。

**業務上の目的・背景**：Jenkinsコントローラー（ビルトインノード）上でビルドを実行することは、セキュリティ上の重大なリスクを伴う。ビルドスクリプトは任意のコードを実行できるため、悪意のあるビルドがコントローラーのファイルシステムやJenkinsの内部状態にアクセスする可能性がある。エージェントが存在しない環境では、まずエージェントまたはクラウドを設定し、ビルドをエージェント上で実行する分散ビルド環境を構築すべきである。

**通知の送信タイミング**：Jenkinsの管理画面（/manage）にアクセスした際に、isActivated()メソッドで条件がチェックされ、条件を満たす場合に警告が表示される。具体的には、(1) 開発モードでない、(2) コントローラーのエグゼキュータ数が1以上、(3) クラウドも静的エージェントも存在しない、という3条件すべてを満たす場合に警告が有効化される。

**通知の受信者**：Jenkins管理者権限（Jenkins.ADMINISTER）を持つユーザーが対象。管理画面でセキュリティ関連の警告として表示される。

**通知内容の概要**：「ビルトインノードでのビルド実行はセキュリティ上の問題となる可能性がある。分散ビルド環境を設定すべき」という警告メッセージと、Jenkins公式ドキュメントへのリンクが表示される。

**期待されるアクション**：管理者は警告を確認し、「Set up agent」ボタンで静的エージェントの追加画面、「Set up cloud」ボタンでクラウド設定画面に遷移し、分散ビルド環境を構築する。または、「Dismiss」ボタンで警告を無視する（非推奨）。

## 通知種別

管理者向けAdministrativeMonitor（Webダッシュボード警告表示）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | オンデマンド（管理画面アクセス時） |
| 優先度 | 高（セキュリティ関連警告） |
| リトライ | N/A（画面表示のため） |

### 送信先決定ロジック

Jenkins管理画面（/manage）にアクセスしたJenkins.ADMINISTER権限を持つユーザーに対して、isActivated()がtrueを返す場合に警告が表示される。

## 通知テンプレート

### 管理画面警告の場合

| 項目 | 内容 |
|-----|------|
| 表示位置 | Jenkins管理画面上部 |
| スタイル | jenkins-alert jenkins-alert-warning |
| カテゴリ | セキュリティ関連（isSecurity()=true） |

### 本文テンプレート

```
Building on the built-in node can be a security issue.
You should set up distributed builds.
See the documentation.

[Set up agent] [Set up cloud] [Dismiss]
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | - | - | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| it.url | モニターのURL | AdministrativeMonitor.getUrl() | Yes |
| it.id | モニターのID | AdministrativeMonitor.id | Yes |
| rootURL | JenkinsルートURL | Staplerコンテキスト | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | 管理画面（/manage）アクセス | isActivated()=true | 条件を満たす場合に警告表示 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 開発モード | Main.isDevelopmentModeがtrueの場合は表示されない |
| エグゼキュータ0 | Jenkins.get().getNumExecutors()が0の場合は表示されない |
| エージェント・クラウドあり | cloudsまたはnodesが空でない場合は表示されない（No.42が代わりに表示） |
| 無効化済み | disable(true)で無効化された場合は表示されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[管理画面アクセス] --> B{権限チェック}
    B -->|ADMINISTER権限あり| C{isEnabled?}
    B -->|権限なし| Z[警告非表示]
    C -->|有効| D{isActivated?}
    C -->|無効化済み| Z
    D -->|有効化| E[message.jelly表示]
    D -->|非有効化| Z
    E --> F{ユーザーアクション}
    F -->|Set up agent| G[新規エージェント追加画面へ遷移]
    F -->|Set up cloud| H[クラウド設定画面へ遷移]
    F -->|Dismiss| I[disable実行・管理画面へリダイレクト]
    G --> J[エージェント設定]
    H --> K[クラウド設定]
    J --> L[警告解消（No.42に切り替わる可能性）]
    K --> L
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | データベースは使用しない | Jenkinsオブジェクトモデルを参照 |

### Jenkins設定参照

| 参照項目 | 用途 | 取得条件 |
|---------|------|---------|
| Jenkins.get().getNumExecutors() | コントローラーのエグゼキュータ数 | isActivated()判定で使用 |
| Jenkins.get().clouds | クラウド設定リスト | isActivated()判定で使用（空であること） |
| Jenkins.get().getNodes() | 静的エージェントリスト | isActivated()判定で使用（空であること） |
| Main.isDevelopmentMode | 開発モードフラグ | isActivated()判定で使用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Jenkins設定ファイル | UPDATE | disable()時にdisabledAdministrativeMonitorsに追加 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| IOエラー | disable()やJenkins.save()失敗時 | IOException伝播 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | N/A |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 表示頻度 | 管理画面アクセス毎 |
| 重複表示 | なし（1つの警告のみ） |

### 配信時間帯

常時（管理画面アクセス時に条件判定）

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

- isSecurity()がtrueを返すため、セキュリティ関連警告としてカウントされる（50-52行目）
- doAct()メソッドは@RequirePOSTアノテーションによりPOSTリクエストのみ許可（54行目）
- AdministrativeMonitorの基底クラスでJenkins.ADMINISTER権限が必要
- NoExternalUse制限により内部利用専用

## 備考

- Symbol名は`executorsOnBuiltInNodeWithoutAgents`および`controllerExecutorsWithoutAgents`（40行目）
- 警告メッセージ内のドキュメントリンク: https://www.jenkins.io/redirect/building-on-controller/
- 2021年にCloudBees社により追加された機能
- No.42のControllerExecutorsAgentsとは排他的な関係（エージェント有無で切り替わる）
- エージェントまたはクラウドを追加すると、この警告は消えNo.42の警告に切り替わる

---

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

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

### 推奨読解順序

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

AdministrativeMonitorの基本構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AdministrativeMonitor.java | `core/src/main/java/hudson/model/AdministrativeMonitor.java` | 基底クラスの構造、id、isEnabled()、isActivated()、disable()の仕組み |

**読解のコツ**: AdministrativeMonitorは抽象クラスで、isActivated()が抽象メソッド。各実装クラスで条件を定義する。

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

ControllerExecutorsNoAgentsクラスの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ControllerExecutorsNoAgents.java | `core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java` | クラス定義、@Extension/@Symbolアノテーション（39-41行目） |

**主要処理フロー**:
1. **39-41行目**: @Extension, @Symbol, @Restricted定義
2. **44-47行目**: getDisplayName()でメッセージリソースから表示名取得
3. **49-52行目**: isSecurity()でセキュリティ警告フラグ設定

#### Step 3: 有効化条件を理解する

isActivated()メソッドの条件ロジックを追跡する。No.42との違いに注目。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControllerExecutorsNoAgents.java | `core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java` | isActivated()メソッド（67-70行目） |

**主要処理フロー**:
- **68-69行目**: 3つの条件をANDで評価
  - `!Main.isDevelopmentMode`: 開発モードでない
  - `Jenkins.get().getNumExecutors() > 0`: エグゼキュータが1以上
  - `Jenkins.get().clouds.isEmpty() && Jenkins.get().getNodes().isEmpty()`: クラウドもエージェントも存在しない

#### Step 4: アクション処理を理解する

ユーザーのボタンクリック時の処理フローを追跡する。No.42より選択肢が多い。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ControllerExecutorsNoAgents.java | `core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java` | doAct()メソッド（54-64行目） |

**主要処理フロー**:
- **54行目**: @RequirePOSTでPOSTリクエスト必須
- **56-58行目**: "no"パラメータ（Dismiss）の場合、disable(true)して/manageへリダイレクト
- **59-60行目**: "cloud"パラメータ（Set up cloud）の場合、/manage/cloud/へリダイレクト
- **61-63行目**: "agent"パラメータ（Set up agent）の場合、/computer/newへリダイレクト

#### Step 5: 表示テンプレートを理解する

警告メッセージの表示方法を理解する。No.42とボタン構成が異なる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | message.jelly | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.jelly` | 警告UIの構造、3つのボタン定義 |
| 5-2 | message.properties | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties` | 警告メッセージテキスト（分散ビルド推奨） |
| 5-3 | description.jelly | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/description.jelly` | モニターの説明文表示 |

**主要処理フロー**:
- **message.jelly 27-32行目**: jenkins-alert-warningスタイルのdiv、Set up agent、Set up cloud、Dismissの3ボタン
- **message.properties 23-25行目**: ExecutorsWarningメッセージ（分散ビルド設定を推奨）

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

```
管理画面アクセス（/manage）
    │
    ├─ AdministrativeMonitor.all()
    │      └─ ExtensionList.lookup(AdministrativeMonitor.class)
    │
    └─ 各モニターに対して
           ├─ isEnabled()
           │      └─ disabledAdministrativeMonitors.contains(id)チェック
           │
           └─ isActivated()
                  └─ ControllerExecutorsNoAgents.isActivated()
                         ├─ Main.isDevelopmentMode チェック
                         ├─ Jenkins.get().getNumExecutors() チェック
                         └─ clouds.isEmpty() && nodes.isEmpty() チェック

ユーザーアクション
    │
    └─ doAct() [POST]
           ├─ "no" → disable(true) → /manage リダイレクト
           ├─ "cloud" → /manage/cloud/ リダイレクト
           └─ "agent" → /computer/new リダイレクト
```

### データフロー図

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

Jenkins設定状態 ───▶ isActivated()条件判定 ───▶ 警告表示可否
- numExecutors              │
- clouds (空判定)            │
- nodes (空判定)             │
- developmentMode           │
                           ▼
                    message.jelly
                           │
                           ▼
               [警告メッセージ表示]


ボタンクリック ───▶ doAct() ───▶ リダイレクト
- agent: Set up agent      │        - /computer/new
- cloud: Set up cloud      │        - /manage/cloud/
- no: Dismiss              │        - /manage + disable()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ControllerExecutorsNoAgents.java | `core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java` | ソース | メインクラス、条件判定とアクション処理 |
| AdministrativeMonitor.java | `core/src/main/java/hudson/model/AdministrativeMonitor.java` | ソース | 基底クラス、共通機能 |
| message.jelly | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.jelly` | テンプレート | 警告UI表示（3ボタン） |
| message.properties | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties` | 設定 | 警告メッセージテキスト |
| description.jelly | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/description.jelly` | テンプレート | モニター説明表示 |
| description.properties | `core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/description.properties` | 設定 | 説明テキスト |
| Messages.properties | `core/src/main/resources/jenkins/diagnostics/Messages.properties` | 設定 | DisplayName定義 |
| ControllerExecutorsNoAgentsTest.java | `test/src/test/java/jenkins/diagnostics/ControllerExecutorsNoAgentsTest.java` | テスト | ユニットテスト |
| ControllerExecutorsAgents.java | `core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java` | ソース | 関連クラス（排他的関係） |
