PagerDuty APIを叩いてみる

## はじめに

PagerDuty の各種リソース（インシデント、ユーザー、サービスなど）を API 経由でまとめて取得し、ローカルに JSON ファイルとして保存するスクリプトを紹介します。
APIで取得したデータを眺めてみるとデータ構造についての理解が深まるかもしれないと思い作成しました。

## 前提

* Ruby 2.6 以上
* 以下の gem がインストール済み

```bash
gem install faraday
```
* PagerDuty の API トークンを取得済み（権限は「READ only」以上で OK）

## スクリプトの実行方法

1. **環境変数の設定**

   ```bash
   export PAGERDUTY_API_TOKEN=your_token_here
   ```
2. **スクリプト実行**

   ```bash
   chmod +x fetch_pagerduty_resources.rb
   ./fetch_pagerduty_resources.rb
   ```
3. 実行後、以下のディレクトリが生成されます。

   * `output/`…各リソースの JSON ファイル
   * `logs/`…失敗時のログファイル

## コード構成

```ruby
#!/usr/bin/env ruby
# coding: utf-8

require 'faraday'
require 'json'
require 'fileutils'
require 'time'

API_TOKEN = ENV.fetch('PAGERDUTY_API_TOKEN') { abort "環境変数 PAGERDUTY_API_TOKEN をセットしてください" }

# 取得対象リソース一覧（apps, automation_actions は除外）
RESOURCES = %w[
  abilities
  addons
  alert_grouping_settings
  audit/records
  business_services
  change_events
  escalation_policies
  event_orchestrations
  extension_schemas
  extensions
  incidents
  incident_workflows      # response_plays の代替
  licenses
  log_entries
  maintenance_windows
  notifications
  oncalls
  priorities
  response_plays          # 実体は incident_workflows
  rulesets
  schedules
  service_dependencies
  services
  webhooks
  standards
  status_dashboards
  tags
  teams
  templates
  users
  vendors
]

OUTPUT_DIR = 'output'
LOG_DIR    = 'logs'
FileUtils.mkdir_p OUTPUT_DIR
FileUtils.mkdir_p LOG_DIR

def connection
  @conn ||= Faraday.new(url: 'https://api.pagerduty.com') do |f|
    f.request  :url_encoded
    f.adapter  Faraday.default_adapter
    f.headers['Content-Type'] = 'application/json'
    f.headers['Accept']       = 'application/vnd.pagerduty+json;version=2'
    f.headers['Authorization'] = "Token token=#{API_TOKEN}"
  end
end

def write_log(resource, message, response_body=nil)
  path = File.join(LOG_DIR, "#{resource.tr('/', '_')}.log")
  File.open(path, 'a') do |f|
    f.puts "[#{Time.now.utc.iso8601}] #{message}"
    if response_body
      f.puts "----- response body start -----"
      f.puts response_body
      f.puts "----- response body end   -----"
    end
  end
end

def fetch_page(resource)
  endpoint = resource == 'response_plays' ? 'incident_workflows' : resource
  key      = endpoint.include?('/') ? endpoint.tr('/', '_') : endpoint

  params = { limit: 10, offset: 0 }
  if resource == 'notifications'
    now_utc        = Time.now.utc
    params[:since] = (now_utc - 7*24*60*60).iso8601
    params[:until] = now_utc.iso8601
  end

  resp = connection.get("/#{endpoint}", params)
  unless resp.success?
    write_log(resource, "HTTP #{resp.status} error", resp.body)
    warn "[#{resource}] HTTP #{resp.status} → logs/#{resource.tr('/', '_')}.log を参照"
    return []
  end

  data = JSON.parse(resp.body) rescue (write_log(resource, "JSON parse error", resp.body); return [])
  data[key] || []
end

RESOURCES.each do |res|
  puts "=== Fetching #{res} (limit=10) ==="
  items = fetch_page(res)
  next if items.empty?
  fname = res.tr('/', '_')
  File.write(File.join(OUTPUT_DIR, "#{fname}.json"), JSON.pretty_generate(items))
  puts "→ Saved #{items.size} items to #{OUTPUT_DIR}/#{fname}.json"
end
```

## 各リソースの概要

| リソース名                     | 概要                                              |
| ------------------------- | ----------------------------------------------- |
| `abilities`               | API キーやユーザーが持つ権限（何ができるか）情報                      |
| `addons`                  | PagerDuty Marketplace での拡張機能（Slack 連携など）の情報     |
| `alert_grouping_settings` | アラートを自動グルーピングする設定                               |
| `audit/records`           | Audit Log（操作履歴）のレコード                            |
| `business_services`       | ビジネスサービス（基幹サービス）の情報                             |
| `change_events`           | Change Management のトリガーイベント                     |
| `escalation_policies`     | エスカレーションポリシー（インシデント通知のルール）                      |
| `event_orchestrations`    | イベントオーケストレーション（複数サービス横断処理）                      |
| `extension_schemas`       | カスタム拡張データのスキーマ定義                                |
| `extensions`              | 上記スキーマに基づいた拡張データ                                |
| `incidents`               | インシデント（障害）の一覧                                   |
| `incident_workflows`      | ワークフロー機能（response\_plays の代替）                   |
| `licenses`                | ライセンス契約情報                                       |
| `log_entries`             | システムログ（Events API 経由のログなど）                      |
| `maintenance_windows`     | メンテナンスウィンドウ（停止期間）の設定                            |
| `notifications`           | 通知履歴（直近 7 日分を取得）                                |
| `oncalls`                 | ローテーション中の担当者                                    |
| `priorities`              | インシデント優先度                                       |
| `response_plays`          | 旧称 response\_plays（現在は incident\_workflows で代替） |
| `rulesets`                | 自動化ルール（Event Rules）                             |
| `schedules`               | シフトスケジュール（勤務表）の設定                               |
| `service_dependencies`    | サービス間の依存関係                                      |
| `services`                | PagerDuty 上のサービス（監視対象とか）                        |
| `webhooks`                | Webhook 通知の設定                                   |
| `standards`               | コンプライアンス／ベストプラクティス設定                            |
| `status_dashboards`       | ステータスページ（公開ダッシュボード）                             |
| `tags`                    | タグ                                              |
| `teams`                   | チーム設定                                           |
| `templates`               | インシデントや通知テンプレート                                 |
| `users`                   | ユーザーアカウント                                       |
| `vendors`                 | サードパーティベンダー情報                                   |

## 実行例

```console
$ export PAGERDUTY_API_TOKEN=abcdefghijklmnopqrstuvwxyz
$ ./fetch_pagerduty_resources.rb
=== Fetching abilities (limit=10) ===
→ Saved 3 items to output/abilities.json
=== Fetching addons (limit=10) ===
→ Saved 2 items to output/addons.json
…
```

* **出力ディレクトリ**

  * `output/*.json` に各リソースの配列データを整形済み JSON で保存
* **ログ**

  * `logs/<resource>.log` に HTTP エラーや JSON パースエラーを追記