LoginSignup
0
0

CloudWatch アラームを Redmine のチケットに起票する

Posted at

やりたいこと

CloudWatch アラームが ALARM 状態になったら Redmine のチケットに起票したい。

なお、Redmine チケットは次のようにしたい。

  • プロジェクト: test_project
  • トラッカー: Alarm
  • チケットの優先度
    • CloudWatch アラーム名に Critical が含まれる場合は、優先度 Urgent とする
    • CloudWatch アラーム名に Error が含まれる場合は、優先度 High とする

どうやるか?

Redmine API が提供されているので、これを参考に行う。

構成図

実際は、CloudWatch metrics のアクションとして、Lambda を指定しますが、今回は Lamda からテストイベントを作成し実行させるので、CloudWatch metrics の作成は手順から省いています。
redmine.png

手順

Lightsail で Redmine を作成する

本題は CloudWatch アラームが ALARM 状態になったら Redmine のチケットに起票するという点ですので、Redmine の作成において今回は簡易的に Lightsail で作成しておきます。

スクリーンショット 2024-05-09 13.11.25.png

ドキュメントを参考に「ステップ 1 〜 4」を行う

繰り返しになりますが、本題は CloudWatch アラームが ALARM 状態になったら Redmine のチケットに起票するという点ですので、「ステップ 5 〜 8」は今回は飛ばします。

プロジェクト,トラッカーの作成、チケットの優先度の確認

プロジェクト: test_project を追加します。
スクリーンショット 2024-05-09 13.25.42.png

トラッカー: Alarm を追加します。
スクリーンショット 2024-05-09 13.25.57.png

チケットの優先度: UrgentHigh は既に存在することだけを確認します。
スクリーンショット 2024-05-09 13.26.16.png

ユーザーと API キーの作成

Redmine の REST API を有効にするため、「RESTによるWebサービスを有効にする」にチェックを入れ、「保存」します。
スクリーンショット 2024-05-09 13.49.46.png

ユーザーを作成します。ここでは、aws としています。
スクリーンショット 2024-05-09 13.46.41.png

新しく作成した aws のアカウントでログインし、「個人設定」から API アクセスキーを確認し控えます。
スクリーンショット 2024-05-08 13.52.21.png

プロジェクト,トラッカー,チケットの優先度の id の確認

プロジェクトの test_project の id: 1 を確認。

projects.xml
<projects total_count="1" offset="0" limit="25" type="array">
  <project>
    <id>1</id>
    <name>test_project</name>
    <identifier>test_project</identifier>
    <description/>
    <homepage/>
    <status>1</status>
    <is_public>true</is_public>
    <inherit_members>false</inherit_members>
    <created_on>2024-05-08T02:40:49Z</created_on>
    <updated_on>2024-05-08T02:40:49Z</updated_on>
  </project>
</projects>

トラッカーの Alarm の id: 6 を確認。

trackers.xml
<trackers type="array">
  <tracker>
    <id>1</id>
    <name>Bug</name>
    <default_status id="1" name="New"/>
    <description/>
    <enabled_standard_fields type="array">
      <field>assigned_to_id</field>
      <field>category_id</field>
      <field>fixed_version_id</field>
      <field>parent_issue_id</field>
      <field>start_date</field>
      <field>due_date</field>
      <field>estimated_hours</field>
      <field>done_ratio</field>
      <field>description</field>
      <field>priority_id</field>
    </enabled_standard_fields>
  </tracker>
  <tracker>
    <id>2</id>
    <name>Feature</name>
    <default_status id="1" name="New"/>
    <description/>
    <enabled_standard_fields type="array">
      <field>assigned_to_id</field>
      <field>category_id</field>
      <field>fixed_version_id</field>
      <field>parent_issue_id</field>
      <field>start_date</field>
      <field>due_date</field>
      <field>estimated_hours</field>
      <field>done_ratio</field>
      <field>description</field>
      <field>priority_id</field>
    </enabled_standard_fields>
  </tracker>
  <tracker>
    <id>3</id>
    <name>Support</name>
    <default_status id="1" name="New"/>
    <description/>
    <enabled_standard_fields type="array">
      <field>assigned_to_id</field>
      <field>category_id</field>
      <field>fixed_version_id</field>
      <field>parent_issue_id</field>
      <field>start_date</field>
      <field>due_date</field>
      <field>estimated_hours</field>
      <field>done_ratio</field>
      <field>description</field>
      <field>priority_id</field>
    </enabled_standard_fields>
  </tracker>
  <tracker>
    <id>6</id>
    <name>Alarm</name>
    <default_status id="1" name="New"/>
    <description/>
    <enabled_standard_fields type="array">
      <field>assigned_to_id</field>
      <field>category_id</field>
      <field>fixed_version_id</field>
      <field>parent_issue_id</field>
      <field>start_date</field>
      <field>due_date</field>
      <field>estimated_hours</field>
      <field>done_ratio</field>
      <field>description</field>
      <field>priority_id</field>
    </enabled_standard_fields>
  </tracker>
</trackers>

チケットの優先度の
Urgent の id: 4
High の id: 3
Normal の id: 2
を確認。

enumerations/issue_priorities.xml
<issue_priorities type="array">
  <issue_priority>
    <id>5</id>
    <name>Immediate</name>
    <is_default>false</is_default>
    <active>true</active>
  </issue_priority>
  <issue_priority>
    <id>4</id>
    <name>Urgent</name>
    <is_default>false</is_default>
    <active>true</active>
  </issue_priority>
  <issue_priority>
    <id>3</id>
    <name>High</name>
    <is_default>false</is_default>
    <active>true</active>
  </issue_priority>
  <issue_priority>
    <id>1</id>
    <name>Low</name>
    <is_default>false</is_default>
    <active>true</active>
  </issue_priority>
  <issue_priority>
    <id>2</id>
    <name>Normal</name>
    <is_default>false</is_default>
    <active>true</active>
  </issue_priority>
</issue_priorities>

Lambda の実装

## になっている箇所を自身の環境に合わせて修正し、Lambda 関数を作成します。

redmine.py
import json
import urllib.request
import ssl

def lambda_handler(event, context):
    # CloudWatchからのイベント情報を取得
    alarm_name = event['detail']['alarmName']
    alarm_description = event['detail']['alarmDescription']
    new_state = event['detail']['newState']['stateValue']
    
    # new_stateがALARMの場合のみRedmineのチケットに登録
    if new_state != 'ALARM':
        print('CloudWatchアラームはALARM状態ではありません。Redmineチケットへの登録をスキップします。')
        return
    
    # 優先度のデフォルト設定
    priority_id = 2  ## enumerations/issue_priorities.xml で確認した Normal id
    
    # alarm_nameに応じて優先度を設定
    if 'Error' in alarm_name:
        priority_id = 3  ## enumerations/issue_priorities.xml で確認した High id
    elif 'Critical' in alarm_name:
        priority_id = 4  ## enumerations/issue_priorities.xml で確認した Urgent id
    # RedmineのAPIエンドポイントと認証情報
    redmine_url = 'https://X.X.X.X/issues.json'  ## redmine のip
    redmine_api_key = 'abcdefghi1234567' ## redmine aws ユーザーの API アクセスキー

    # SSL証明書の検証を無効にする
    ssl_context = ssl.create_default_context()
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_NONE
    
    # CloudWatchアラームの情報をRedmineチケットに記録するためのデータを準備
    ticket_data = {
        'issue': {
            'project_id': 1, ## projects.xml で確認した test_project id
            'tracker_id': 6, ## trackers.xml で確認した Alarm id
            'priority_id': priority_id,
            'subject': f'Alarm: {alarm_name} is now {new_state}',
            'description': f'{alarm_description}\n\nCloudWatch Alarm: {alarm_name} is now {new_state}'
        }
    }
    
    # RedmineにPOSTリクエストを送信してチケットを作成
    req = urllib.request.Request(
        redmine_url, 
        data=json.dumps(ticket_data).encode('utf-8'), 
        headers={'Content-Type': 'application/json', 'X-Redmine-API-Key': redmine_api_key})
    try:
        with urllib.request.urlopen(req, context=ssl_context) as response:
            response_data = response.read().decode('utf-8')
            print(response_data)
            print('Redmineチケットが正常に登録されました。')
    except urllib.error.HTTPError as e:
        print('Redmineチケットの作成中にエラーが発生しました。')
        print(e)

動作確認

Critical_test

CloudWatch アラーム名に Critical が含まれる場合は、優先度 Urgent とするを行いたいと思います。
次のようなテストイベントを作成し、Lambda を実行させます。

Critical_test.json
{
  "version": "0",
  "id": "b80d68ad-1c0b-4b9e-8c1e-092fe533b4a5",
  "detail-type": "CloudWatch Alarm State Change",
  "source": "aws.cloudwatch",
  "account": "123456789012",
  "time": "2024-05-08T12:34:56Z",
  "region": "ap-northeast-1.",
  "resources": [
    "arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:Critical_test"
  ],
  "detail": {
    "alarmName": "Critical_test",
    "alarmDescription": "これは緊急テストです。",
    "oldState": {
      "stateValue": "OK",
      "stateReason": "Threshold Crossed: 1 out of the last 1 datapoints [1.0 (08/05/24 12:32:00)] was greater than the threshold (0.0)."
    },
    "newState": {
      "stateValue": "ALARM",
      "stateReason": "Threshold Crossed: 1 out of the last 1 datapoints [1.0 (08/05/24 12:32:00)] was greater than the threshold (0.0).",
      "stateReasonData": {
        "version": "1.0",
        "queryDate": "2024-05-08T12:34:56.005Z",
        "startDate": "2024-05-08T12:32:00.000Z",
        "statistic": "Sum",
        "period": 60,
        "recentDatapoints": [
          1
        ]
      }
    }
  }
}

実行結果は以下の通りです。

Critical_test_logs.json
{
    "issue": {
        "id": 32,
        "project": {
            "id": 1,
            "name": "test_project"
        },
        "tracker": {
            "id": 6,
            "name": "Alarm"
        },
        "status": {
            "id": 1,
            "name": "New",
            "is_closed": false
        },
        "priority": {
            "id": 4,
            "name": "Urgent"
        },
        "author": {
            "id": 6,
            "name": "aws aws"
        },
        "subject": "Alarm: Critical_test is now ALARM",
        "description": "これは緊急テストです。\r\n\r\nCloudWatch Alarm: Critical_test is now ALARM",
        "start_date": "2024-05-09",
        "due_date": null,
        "done_ratio": 0,
        "is_private": false,
        "estimated_hours": null,
        "total_estimated_hours": null,
        "created_on": "2024-05-09T05:39:31Z",
        "updated_on": "2024-05-09T05:39:31Z",
        "closed_on": null
    }
}

Error_test

CloudWatch アラーム名に Error が含まれる場合は、優先度 High とするを行いたいと思います。
次のようなテストイベントを作成し、Lambda を実行させます。

Error_test.json
{
  "version": "0",
  "id": "b80d68ad-1c0b-4b9e-8c1e-092fe533b4a5",
  "detail-type": "CloudWatch Alarm State Change",
  "source": "aws.cloudwatch",
  "account": "123456789012",
  "time": "2024-05-08T12:34:56Z",
  "region": "ap-northeast-1.",
  "resources": [
    "arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:Error_test"
  ],
  "detail": {
    "alarmName": "Error_test",
    "alarmDescription": "これはエラーテストです。",
    "oldState": {
      "stateValue": "OK",
      "stateReason": "Threshold Crossed: 1 out of the last 1 datapoints [1.0 (08/05/24 12:32:00)] was greater than the threshold (0.0)."
    },
    "newState": {
      "stateValue": "ALARM",
      "stateReason": "Threshold Crossed: 1 out of the last 1 datapoints [1.0 (08/05/24 12:32:00)] was greater than the threshold (0.0).",
      "stateReasonData": {
        "version": "1.0",
        "queryDate": "2024-05-08T12:34:56.005Z",
        "startDate": "2024-05-08T12:32:00.000Z",
        "statistic": "Sum",
        "period": 60,
        "recentDatapoints": [
          1
        ]
      }
    }
  }
}

実行結果は以下の通りです。

Error_test_logs.json
{
    "issue": {
        "id": 33,
        "project": {
            "id": 1,
            "name": "test_project"
        },
        "tracker": {
            "id": 6,
            "name": "Alarm"
        },
        "status": {
            "id": 1,
            "name": "New",
            "is_closed": false
        },
        "priority": {
            "id": 3,
            "name": "High"
        },
        "author": {
            "id": 6,
            "name": "aws aws"
        },
        "subject": "Alarm: Error_test is now ALARM",
        "description": "これはエラーテストです。\r\n\r\nCloudWatch Alarm: Error_test is now ALARM",
        "start_date": "2024-05-09",
        "due_date": null,
        "done_ratio": 0,
        "is_private": false,
        "estimated_hours": null,
        "total_estimated_hours": null,
        "created_on": "2024-05-09T05:40:02Z",
        "updated_on": "2024-05-09T05:40:02Z",
        "closed_on": null
    }
}

redmine で確認

redmine で想定通り登録されたことを確認できれば完了です。
スクリーンショット 2024-05-09 14.44.12.png

0
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
0
0