# 機能設計書 2-Add-DbaAgListener

## 概要

本ドキュメントは、dbatools PowerShellモジュールのAdd-DbaAgListener機能の設計仕様を定義する。本機能は、SQL Server Always On可用性グループに対してネットワークリスナーエンドポイントを作成し、クライアント接続の仮想ネットワーク名とIPアドレスを提供する。

### 本機能の処理概要

Add-DbaAgListenerは、可用性グループ（AG）に対してネットワークリスナーを作成するPowerShellコマンドである。リスナーは、クライアントアプリケーションが現在のプライマリレプリカに自動的に接続できるようにする仮想ネットワーク名（VNN）を提供する。これにより、フェイルオーバー時にもアプリケーションの接続文字列を変更する必要がなくなる。

**業務上の目的・背景**：可用性グループを構成しても、リスナーがなければクライアントアプリケーションは個々のレプリカサーバー名に直接接続する必要がある。フェイルオーバーが発生すると、プライマリレプリカが変更されるため、アプリケーションの接続先を手動で変更する必要がある。リスナーを作成することで、クライアントは常に同じ仮想ネットワーク名を使用してプライマリレプリカに接続でき、フェイルオーバー時の透過的な接続切り替えが実現される。

**機能の利用シーン**：
- 新規可用性グループ作成後のリスナー設定
- 既存AGへのクライアント接続ポイント追加
- マルチサブネット環境での複数IPアドレスリスナー構成
- DHCP環境での動的IPリスナー作成

**主要な処理内容**：
1. 入力パラメータの検証（IPアドレス、サブネット、ポート）
2. AvailabilityGroupListenerオブジェクトの生成
3. IPアドレス設定（静的IP/DHCP）の構成
4. リスナーの作成またはオブジェクト返却（Passthru時）

**関連システム・外部連携**：
- SQL Server SMO (Server Management Objects)
- Windows Server Failover Cluster (WSFC)
- DNS（リスナー名の名前解決）
- ネットワークインフラ（IPアドレス管理、DHCP）

**権限による制御**：
- 可用性グループに対するALTER ANY AVAILABILITY GROUP権限
- WSFCクラスタに対するクラスタオブジェクト作成権限
- DNSレコード作成権限（Active Directory環境）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | AGリスナー管理 | 主機能 | 可用性グループリスナーの作成 |

## 機能種別

インフラストラクチャ管理 / ネットワーク構成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | No | 対象SQL Serverインスタンス | SQL Server 2012以上 |
| SqlCredential | PSCredential | No | SQL Server接続用認証情報 | - |
| AvailabilityGroup | string[] | No | 可用性グループ名 | SqlInstance指定時は必須 |
| Name | string | No | リスナー名（デフォルト: AG名） | 複数AG処理時は使用不可 |
| IPAddress | ipaddress[] | No | 静的IPアドレス | Dhcpと排他 |
| SubnetIP | ipaddress[] | No | サブネットIPアドレス | 自動計算可能 |
| SubnetMask | ipaddress[] | No | サブネットマスク（デフォルト: 255.255.255.0） | - |
| Port | int | No | TCPポート番号（デフォルト: 1433） | - |
| Dhcp | switch | No | DHCP使用 | IPAddressと排他 |
| Passthru | switch | No | 作成前にオブジェクト返却 | - |
| InputObject | AvailabilityGroup[] | No | パイプライン入力 | - |
| EnableException | switch | No | 例外有効化 | - |

### 入力データソース

- SQL Serverインスタンスへの直接接続
- Get-DbaAvailabilityGroupからのパイプライン入力
- ネットワーク管理者からのIPアドレス情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverのコンピュータ名 |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlInstance | string | 完全なSQL Serverインスタンス名 |
| AvailabilityGroup | string | 可用性グループ名 |
| Name | string | リスナーのネットワーク名 |
| PortNumber | int | TCPポート番号 |
| ClusterIPConfiguration | string | クラスタIP構成情報 |

### 出力先

- PowerShellパイプライン（Microsoft.SqlServer.Management.Smo.AvailabilityGroupListener型）
- Passthru指定時は作成前のオブジェクトを返却

## 処理フロー

### 処理シーケンス

```
1. パラメータ検証
   └─ SqlInstanceまたはInputObjectの指定確認
   └─ SqlInstance時はAvailabilityGroupの指定確認
   └─ DhcpとIPAddressの排他チェック
   └─ Dhcp時は単一サブネット制限確認

2. 可用性グループオブジェクト取得
   └─ SqlInstance指定時: Get-DbaAvailabilityGroup呼び出し
   └─ InputObject指定時: パイプラインから受信

3. IPアドレス/サブネット計算
   └─ SubnetMask数とIPAddress数の整合チェック
   └─ SubnetIP未指定時は自動計算

4. 各可用性グループに対してリスナー作成
   └─ AvailabilityGroupListenerオブジェクト生成
   └─ ポート番号設定
   └─ IPアドレス設定ループ（静的IP/DHCP）
   └─ Passthru時: オブジェクト返却して終了
   └─ 通常時: Invoke-Create実行

5. 結果取得と出力
   └─ Get-DbaAgListener呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{SqlInstance/InputObject?}
    B -->|なし| Z1[エラー: 入力必須]
    B -->|SqlInstance| C{AvailabilityGroup指定?}
    B -->|InputObject| E[パイプラインから取得]
    C -->|No| Z2[エラー: AG必須]
    C -->|Yes| D[Get-DbaAvailabilityGroup]
    D --> E
    E --> F{Dhcp指定?}
    F -->|Yes| G{IPAddress指定?}
    G -->|Yes| Z3[エラー: 排他]
    G -->|No| H{複数サブネット?}
    H -->|Yes| Z4[エラー: 単一のみ]
    H -->|No| I[IPアドレス設定]
    F -->|No| J{IPAddress指定?}
    J -->|Yes| K[SubnetMask数チェック]
    J -->|No| I
    K --> L{数一致?}
    L -->|No| M{SubnetMask=1?}
    M -->|Yes| N[全IPに同一マスク適用]
    M -->|No| Z5[エラー: 数不一致]
    N --> O{SubnetIP指定?}
    L -->|Yes| O
    O -->|No| P[自動計算]
    O -->|Yes| Q{数一致?}
    P --> I
    Q -->|No| R{SubnetIP=1?}
    R -->|Yes| S[全IPに同一適用]
    R -->|No| Z6[エラー: 数不一致]
    S --> I
    Q -->|Yes| I
    I --> T[Listenerオブジェクト生成]
    T --> U[ポート設定]
    U --> V[IPアドレスループ]
    V --> W{Passthru?}
    W -->|Yes| X[オブジェクト返却]
    W -->|No| Y[Invoke-Create]
    Y --> AA[Get-DbaAgListener]
    X --> AB[終了]
    AA --> AB
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | SQLバージョン要件 | SQL Server 2012以上が必要 | 常時 |
| BR-02 | DHCP排他 | DHCPとIPAddressは同時指定不可 | Dhcpスイッチ使用時 |
| BR-03 | DHCPサブネット制限 | DHCPは単一サブネットのみ対応 | Dhcpスイッチ使用時 |
| BR-04 | デフォルトリスナー名 | 未指定時はAvailabilityGroup名を使用 | Name未指定時 |
| BR-05 | デフォルトポート | 未指定時は1433 | Port未指定時 |
| BR-06 | デフォルトサブネットマスク | 未指定時は255.255.255.0 (/24) | SubnetMask未指定時 |

### 計算ロジック

- サブネットIP自動計算: `IPAddress.Address -band SubnetMask.Address`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リスナー作成 | master.sys.availability_group_listeners | INSERT | リスナー情報登録 |
| リスナー取得 | master.sys.availability_group_listeners | SELECT | 作成後の確認 |

### テーブル別操作詳細

#### master.sys.availability_group_listeners

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | dns_name | リスナー名 | SMO経由 |
| INSERT | port | ポート番号 | SMO経由 |
| INSERT | ip_configuration_string_from_cluster | IP構成 | WSFC経由 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ParameterError | SqlInstanceとInputObject両方なし | いずれかを指定 |
| - | ParameterError | SqlInstance指定時にAvailabilityGroupなし | AG名を指定 |
| - | ParameterError | DhcpとIPAddress同時指定 | いずれかを選択 |
| - | ParameterError | Dhcp時に複数サブネット | 単一サブネットのみ |
| - | ParameterError | IPAddressとSubnetMask数不一致 | 数を合わせるか単一指定 |
| - | ParameterError | IPAddressとSubnetIP数不一致 | 数を合わせるか単一指定 |
| - | CreateError | リスナー作成失敗 | WSFC/DNS設定確認 |

### リトライ仕様

- 本機能にリトライロジックは実装されていない
- 失敗時はStop-Functionでエラー出力

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

- SMOのCreate()メソッドはWSFCと連携してアトミックに実行
- 作成失敗時はロールバックされる
- Passthru使用時はオブジェクト返却のみで変更なし

## パフォーマンス要件

- リスナー作成はWSFCとの通信を伴うため数秒を要する
- DNS伝播には追加時間が必要な場合がある
- 複数IPアドレス設定でも同一処理内で完了

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

- SQL Server認証またはWindows認証対応
- WSFCクラスタオブジェクト作成権限が必要
- DNSレコード作成権限が必要（AD環境）
- ファイアウォールでリスナーポートの開放が必要

## 備考

- Invoke-Createは内部ヘルパー関数（SMO Create()呼び出しのラッパー）
- マルチサブネット構成では各サブネットに1つのIPアドレスを指定
- リスナー名はDNS名として機能するため、NetBIOS命名規則に従う

---

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

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

### 推奨読解順序

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

SMOのAvailabilityGroupListenerとAvailabilityGroupListenerIPAddressの関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | param()ブロックでパラメータ構造を把握（119-134行目） |

**読解のコツ**: ipaddress[]型のパラメータは.NET Frameworkのipaddressクラスを使用。サブネット計算でAddress プロパティ（32ビット整数）が使われる。

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

パラメータ検証とオブジェクト取得のロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | process開始部でTest-Boundによる検証（136-156行目） |
| 2-2 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | SqlInstance時のGet-DbaAvailabilityGroup呼び出し（158-159行目） |

**主要処理フロー**:
1. **136-139行目**: SqlInstance/InputObject必須チェック
2. **141-144行目**: SqlInstance時のAvailabilityGroup必須チェック
3. **146-156行目**: Dhcp使用時のバリデーション

#### Step 3: IPアドレス/サブネット計算を理解する

SubnetMask/SubnetIPの数の整合と自動計算ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | SubnetMask数の整合チェック（162-171行目） |
| 3-2 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | SubnetIP自動計算（173-189行目） |

**主要処理フロー**:
- **163-167行目**: SubnetMask数がIPAddress数と異なる場合の処理
- **175-176行目**: ビット演算によるサブネットIP自動計算

#### Step 4: リスナー作成処理を理解する

AvailabilityGroupListenerオブジェクトの生成と作成を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | foreach AGループとオブジェクト生成（191-229行目） |

**主要処理フロー**:
- **192-194行目**: Nameのデフォルト設定（AG名を使用）
- **197-198行目**: AvailabilityGroupListenerオブジェクト生成
- **203-216行目**: IPアドレス設定ループ（do-while）
- **218-223行目**: Passthru判定とInvoke-Create
- **227行目**: Get-DbaAgListenerで結果取得

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

```
Add-DbaAgListener
    │
    ├─ Test-Bound (パラメータ検証)
    │
    ├─ Get-DbaAvailabilityGroup (SqlInstance時)
    │
    ├─ SMO AvailabilityGroupListener.New()
    │      └─ ポート番号設定
    │      └─ AvailabilityGroupListenerIPAddress追加
    │
    ├─ Invoke-Create (通常時)
    │      └─ SMO Create()ラッパー
    │
    └─ Get-DbaAgListener (結果取得)
```

### データフロー図

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

SqlInstance ─────────────▶ Get-DbaAvailabilityGroup ───┐
                                                        │
AvailabilityGroup ───────────────────────────────────▶ │
                                                        │
InputObject (Pipeline) ─────────────────────────────▶ AG Object
                                                        │
                                                        ▼
IPAddress[] ─────────────▶ ┌─────────────────────┐
                           │ SubnetIP計算        │
SubnetMask[] ────────────▶ │ (ビット演算)        │
                           └─────────────────────┘
SubnetIP[] ───────────────────────────│
                                      ▼
                           ┌─────────────────────┐
Port ─────────────────────▶│ Listener生成        │
                           │ IPAddress設定       │
Name ─────────────────────▶│                     │
                           └─────────────────────┘
                                      │
                    ┌─────────────────┴─────────────────┐
                    ▼                                   ▼
             [Passthru=True]                     [Passthru=False]
                    │                                   │
                    ▼                                   ▼
             Listenerオブジェクト              Invoke-Create
             (未作成)                                   │
                                                        ▼
                                               Get-DbaAgListener
                                                        │
                                                        ▼
                                               AvailabilityGroupListener
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Add-DbaAgListener.ps1 | `public/Add-DbaAgListener.ps1` | ソース | メインコマンド実装 |
| Get-DbaAvailabilityGroup.ps1 | `public/Get-DbaAvailabilityGroup.ps1` | ソース | AG取得 |
| Get-DbaAgListener.ps1 | `public/Get-DbaAgListener.ps1` | ソース | リスナー取得 |
| Invoke-Create.ps1 | `private/Invoke-Create.ps1` | ソース | SMO Create()ラッパー |
