Cloudwatch Alarmをchatworkで受け取りたい


Alarmをメールで受けるのイヤなんじゃ・・・

slack だと、Lambdaで便利なブループリントが提供されてるんですけどね・・・
chatwork使わざるをえない環境なんで・・・


Cloudwatch Alarm
SNS
Lambda
Chatwork

って良くあるパータンの。

手順

1. Lambda Function作成

python3で。

import boto3
import json
import logging
import os
import pprint

from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode

APIKEY = os.environ['APIToken']
ROOMID = os.environ['RoomID']
ENDPOINT = 'https://api.chatwork.com/v2/'
post_message_url = '{}/rooms/{}/messages'.format(ENDPOINT, ROOMID)

logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.info("post_message_url: " + str(post_message_url))

def lambda_handler(event, context):
    logger.info("Event: " + str(event))
    message = json.loads(event['Records'][0]['Sns']['Message'])
    logger.info("Message: " + str(message))

    alarm_name = message['AlarmName']
    #old_state = message['OldStateValue']
    new_state = message['NewStateValue']
    reason = message['NewStateReason']

    chatwork_message = {
        'body': "[info][title]{0} state is now {1}[/title][code]{2}[/code][/info]" .format(alarm_name, new_state, reason)
    }
    chatwork_message = urlencode(chatwork_message).encode("utf-8")

    try:
        headers = {"X-ChatWorkToken": APIKEY}
        request = Request(post_message_url, data=chatwork_message, method="POST", headers=headers)

        with urlopen(request) as response:
            result = json.loads(response.read().decode("utf-8"))
            logger.info("TEST %s", result)
            info = dict(response.info())
            logger.info("TEST2 %s", info)

        logger.info("Message posted to %s", ROOMID)
        #logger.info("Message: %s", resp.content)
    except HTTPError as e:
        logger.error("Request failed: %d %s", e.code, e.reason)
    except URLError as e:

テストケース

どこぞで拾ったテストケース、使わせて頂きました。
他にも探したけど、良さそうなの見つからなかった。

{
  "Records": [
    {
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:EXAMPLE",
      "EventSource": "aws:sns",
      "Sns": {
        "SignatureVersion": "1",
        "Timestamp": "1970-01-01T00:00:00.000Z",
        "Signature": "EXAMPLE",
        "SigningCertUrl": "EXAMPLE",
        "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
        "Message": "{\"AlarmName\":\"awsrds-app-High-DB-Connections\",\"AlarmDescription\":\"Alarm when CPU exceeds 50 percent\",\"AWSAccountId\":\"123456789123\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 datapoint (10.0) was greater than or equal to the threshold (10.0).\",\"StateChangeTime\":\"2016-07-24T22:05:19.737+0000\",\"Region\":\"US West - Oregon\",\"OldStateValue\":\"OK\",\"Trigger\":{\"MetricName\":\"DatabaseConnections\",\"Namespace\":\"AWS/RDS\",\"Statistic\":\"AVERAGE\",\"Unit\":null,\"Dimensions\":[{\"name\":\"DBInstanceIdentifier\",\"value\":\"app\"}],\"Period\":300,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"GreaterThanOrEqualToThreshold\",\"Threshold\":10.0}}",
        "MessageAttributes": {
          "Test": {
            "Type": "String",
            "Value": "TestString"
          },
          "TestBinary": {
            "Type": "Binary",
            "Value": "TestBinary"
          }
        },
        "Type": "Notification",
        "UnsubscribeUrl": "EXAMPLE",
        "TopicArn": "arn:aws:sns:EXAMPLE",
        "Subject": "TestInvoke"
      }
    }
  ]
}

この後の手順

SNSトピックを作って、サブスクリプションを定義して
Cloudwatch Alarmのアクションで指定して、
って感じになると思うけど、探せば色々資料出てくるので割愛。

課題

  • RDSのAlarmとか、多分適宜捕まえてもうちょっと見やすく改変する必要がある。
  • 厳密にテストしてない。alarm頻発してる場合とか。