2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PagerDutyAdvent Calendar 2023

Day 23

PagerDutyのAPIの使い方

Posted at

この記事はPagerDuty Advent Calendar 2023の23日目の記事です。


どうも、manji0です。 今年は所属してる会社が合併したり、交際0日婚約 & 出会って2ヶ月で入籍したりと中々激動の一年でした。

今日はPagerDutyのAPIの使い方について、いくつか例を上げたいと思います。PDのAPIを使いこなすための導入記事として読んでいただければ嬉しいです。

PagerDuty API

まずはお手元にPagerDuty APIのドキュメントを用意しておいてください。

Service, Escalation PolicyやScheduleなど、かなり広い対象にAPIが用意されていることが見てとれると思います。ただ、ほとんどのユーザはEvent API v2(=Incidentを作成するためのAPI)以外のAPIを使ったことがないのではないでしょうか?

個人的には、PDのAPIは少し使い方に癖があるように思えます。やりたいことを実現する方法をすぐに思いつけるようになるのに多少の慣れが必要だな、という感覚です。

例えば、Get a scheduleをQuery param無しでコールしてみます。

ドキュメントのResponse sampleでは以下のように final_schedule が返ってきますね。

{
  "schedule": {
    "id": "PI7DH85",
    "type": "schedule",
    "省略": "",
    "final_schedule": {
      "name": "Final Schedule",
      "rendered_schedule_entries": [
        {
          "start": "2015-11-10T08:00:00-05:00",
          "end": "2015-11-10T17:00:00-05:00",
          "user": {
            "id": "PXPGF42",
            "type": "user_reference",
            "summary": "Regina Phalange",
            "self": "https://api.pagerduty.com/users/PXPGF42",
            "html_url": "https://subdomain.pagerduty.com/users/PXPGF42"
          }
        }
      ],
      "rendered_coverage_percentage": 37.5
    }
  }
}

ところが実際に叩いてみると、final_scheduleは空だったりします。

    "overrides_subschedule": {
      "name": "Overrides",
      "rendered_schedule_entries": [],
      "rendered_coverage_percentage": null
    },
    "final_schedule": {
      "name": "Final Schedule",
      "rendered_schedule_entries": [],
      "rendered_coverage_percentage": null
    },

これが何故か分かる方は、正直この記事を読まなくてもOKです。

そうでない方がPDのAPIを便利に使えるようになるために、「あると少し便利だな」というユースケースを例に挙げ、仕様を交えながらAPIの呼び出しフローを説明していきます。

ユースケース

任意のEscalation Policyから現在の担当者のリストを取得する

用途: Slackにその週の担当者を通知する、など

まとめ:

  1. Get an escalation policyを使ってescalation_rules.0.targetsを取得
  2. targetsにtype:schedule_referenceが含まれる場合はGet a scheduleを使ってfinal_scheduleを取得し、担当者を特定する

目的に沿ってそうな名前のAPIはGet an escalation policyですね。response exampleを見てみましょう。

{
  "escalation_policy": {
    "id": "PT20YPA",
    "type": "escalation_policy",
    "summary": "Another Escalation Policy",
    "on_call_handoff_notifications": "if_has_services",
    "self": "https://api.pagerduty.com/escalation_policies/PT20YPA",
    "html_url": "https://subdomain.pagerduty.com/escalation_policies/PT20YPA",
    "name": "Another Escalation Policy",
    "escalation_rules": [
      {
        "id": "PGHDV41",
        "escalation_delay_in_minutes": 30,
        "targets": [
          {
            "id": "PAM4FGS",
            "summary": "Kyler Kuhn",
            "type": "user_reference",
            "self": "https://api.pagerduty.com/users/PAM4FGS",
            "html_url": "https://subdomain.pagerduty.com/users/PAM4FGS"
          },
          {
            "id": "PI7DH85",
            "summary": "Daily Engineering Rotation",
            "type": "schedule_reference",
            "self": "https://api.pagerduty.com/schedules/PI7DH85",
            "html_url": "https://subdomain.pagerduty.com/schedules/PI7DH85"
          }
        ]
      }
    ],
    "services": [
      {
        "id": "PIJ90N7",
        "type": "service_reference",
        "summary": "My Mail Service",
        "self": "https://api.pagerduty.com/services/PIJ90N7",
        "html_url": "https://subdomain.pagerduty.com/service-directory/PIJ90N7"
      }
    ],
    "num_loops": 2,
    "teams": [
      {
        "id": "PQ9K7I8",
        "type": "team_reference",
        "summary": "Engineering",
        "self": "https://api.pagerduty.com/teams/PQ9K7I8",
        "html_url": "https://subdomain.pagerduty.com/teams/PQ9K7I8"
      }
    ],
    "description": "This is yet another escalation policy"
  }
}

escalation_rules が目的の情報のようですが、このままでは使えませんね。Kylerさんが担当者なのは判明していますが...

          {
            "id": "PI7DH85",
            "summary": "Daily Engineering Rotation",
            "type": "schedule_reference",
            "self": "https://api.pagerduty.com/schedules/PI7DH85",
            "html_url": "https://subdomain.pagerduty.com/schedules/PI7DH85"
          }

このAPIから得られる情報では、sheduleの担当者は明らかになっていません。

Scheduleで定義された担当者を含めた完全なリストを生成するには、Scheduleの情報も取得する必要があります。

Get a scheduleについて

Get a scheduleを使ってみましょう。担当者はfinal_scheduleに記載されるはずです。

...しかし、(恐らく)ほとんどの方はここが空になって返ってくるのではないでしょうか。僕の試した限り、final_scheduleを得るためにはsinceuntilを指定する必要があります

そして、ドキュメントにある通りsinceかuntilの片方だけを指定した場合にはそこを起点とした2週間分の情報が出力されます。

例えば、1週間で担当者が切り替わるスケジュールである場合は最大3週分の情報が出力されます。

curl -H "Authorization: Token token=xxx" https://api.pagerduty.com/schedules/yyy\?since\=2023-12-23T00:00:00 | jq
# 省略
"final_schedule": {
      "name": "Final Schedule",
      "rendered_schedule_entries": [
        {
          "start": "2023-12-23T00:00:00+09:00",
          "end": "2023-12-29T20:00:00+09:00",
          "user": {
            "id": "YYY",
            "type": "user_reference",
            "summary": "Alice Carrol",
            "self": "https://api.pagerduty.com/users/YYY",
            "html_url": "https://verda.pagerduty.com/users/YYY"
          },
          "id": "Q114LVW901RIEH"
        },
        {
          "start": "2023-12-29T20:00:00+09:00",
          "end": "2024-01-05T20:00:00+09:00",
          "user": {
            "id": "XXX",
            "type": "user_reference",
            "summary": "Bob Iris",
            "self": "https://api.pagerduty.com/users/XXX",
            "html_url": "https://verda.pagerduty.com/users/XXX"
          },
          "id": "Q0BY6F774SDSHE"
        },
        {
          "start": "2024-01-05T20:00:00+09:00",
          "end": "2024-01-06T00:00:00+09:00",
          "user": {
            "id": "ZZZ",
            "type": "user_reference",
            "summary": "Adam Smith",
            "self": "https://api.pagerduty.com/users/ZZZ",
            "html_url": "https://verda.pagerduty.com/users/ZZZ"
          },
          "id": "HOGEHOGE"
        }
      ],
      "rendered_coverage_percentage": 100.0
    }

こうして何個も出力されてしまったら、「現在の日付とrendered_schedule_entriesのそれぞれの要素の.startや.endを比較して適切なユーザを抽出する」みたいなとても面倒な手順が必要になってしまいます。

これを避けるには、sinceuntilに同じように現在のtimestampを指定してください。

curl -H "Authorization: Token token=xxx" https://api.pagerduty.com/schedules/yyy\?since\=2023-12-23T00:00:00\&until\=2023-12-23T00:00:00 | jq
    "final_schedule": {
      "name": "Final Schedule",
      "rendered_schedule_entries": [
        {
          "start": "2023-12-22T20:00:00+09:00",
          "end": "2023-12-29T20:00:00+09:00",
          "user": {
            "id": "YYY",
            "type": "user_reference",
            "summary": "Alice Carrol",
            "self": "https://api.pagerduty.com/users/YYY",
            "html_url": "https://verda.pagerduty.com/users/YYY"
          },
          "id": "HOGEHOGE"
        }
      ],
      "rendered_coverage_percentage": 100.0
    }

これで担当者が全員明らかになりました。使い方が少し分かってきましたでしょうか。

一定期間内に発生したアラートを全て取得する

用途: インシデントをローカルのpandasなどでより詳細に分析するなど

まとめ:

  1. List incidentsから指定期間内のIncident一覧を取得
  2. Incident毎にList alerts for an incidentでAlert一覧を取得してマージ
  3. (resolved_atはAlertではなくIncidentにしか定義されてないので注意)

PagerDutyではIncidentとAlertは別の概念です。具体的には、1つのIncidentには複数のAlertが含まれる場合があります。

通常は1Incident=1Alertですが、上位プランでIncident Alert Groupingを使っていたり、PDのEvent API v2を叩くモジュール(Alertmanagerなど)でdedup keyを制御したりしていると、この関係が崩れることがあります。

(ちなみに、Event API v2でPOSTしたときに作成されるのは(僕の認識が正しければ)Alertです。Incidentが作成されるか、既存のIncidentにマージされるかはPOST後に判断されます。)

ということで、手元のシステムから発行されるアラートなどについて件数などを正確に分析したい場合は、すべてのIncidentからAlertの一覧を抽出する必要があります

List incidentsから仕様を確認していきましょう。

  • Query parameterにはGet a scheduleと同じくsinceuntilがあるので、期間はここで指定します。
  • 対象のサービスを絞りたい場合には、servicesにサービスIDのリストを指定します。チーム管理をきっちりしてる場合にはteamsで絞ってもよいです。
  • more:trueの場合にはoffsetを使って追加でincident listを取得しましょう。

Response Exampleを見る限り、incidents[].id以外の情報は無視していいですね。

次に、List alerts for an incidentを使ってAlertのリストを取得します。最後にそれをマージしていけばAlertのリストの完成です。

さて、List alerts for an incidentやGet an alertのResponse Exampleを見てみると、created_atはありますがresolved_atがないことが分かります。

実は、PagerDutyではresolved_atはIncidentにしか定義されていません。まあIncidentがオンコールイベントなので自然ですね。

とはいえ、このように「PDに投げたアラートをすべて管理したい」とか「PDのAnalysis機能以上の分析をしたい」という場合には引っかかりやすい仕様だと思います。このあたり、自分たちの要望は発生次第しっかり担当の営業さんに伝えて実現方法を一緒に考えてもらいましょうね。


結構長くなったのでこの辺で。直前に書いたことにも繋がりますが、一般論として、APIやドキュメントが整備されてるからといって自分たちで何でも考えようとすると後から詰まったりするものです。PagerDutyは契約してたらきちんと担当営業さんがついてくれるので、逐一相談してより快適なオンコール生活を送りましょう。 Merry Xmas and Have a happy new year!


余談: 実はIncidentのリストはWebUIからならCSVで落とせたりします。

スクリーンショット 2023-12-23 0.05.18.png

分析のためにPandasにかけるならCSVで落とした方が圧倒的に楽なので、このAPIを開放してください! クリスマスプレゼントってことで!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?