【AWS Lambda for Ruby】eventパラメータの取り出し方

Cloudwatch AlarmSNSトピックをLambdaの起動トリガとした際に、eventパラメータの取り出し方に手間取ってしまったのでここに残しておこうと筆をとりました。

やりたかったこと

以下の構成で、SNSトピックのイベントデータから、アラート対象のロードバランサおよびターゲットグループを特定したい。

前提のeventパラメータ

以下のテストイベントを利用します。実際のSNSトピックから渡されるeventパラメータと構成は同じです。伏せたいところを伏せただけです。

{
  "Records": [
    {
      "EventSource": "aws:sns",
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:ap-northeast-1:123456789012:event-test:abcdefghijklmnopqrstuvwxyz",
      "Sns": {
        "Type": "Notification",
        "MessageId": "abcdefghijklmnopqrstuvwxyz",
        "TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:event-test",
        "Subject": "ALARM: \"alarm-event-test\" in Asia Pacific (Tokyo)",
        "Message": "{\"AlarmName\":\"alarm-event-test\",\"AlarmDescription\":null,\"AWSAccountId\":\"123456789012\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 out of the last 1 datapoints [0.0 (06/06/20 14:04:00)] was less than the threshold (1.0) (minimum 1 datapoint for OK -> ALARM transition).\",\"StateChangeTime\":\"2020-06-06T14:05:17.378+0000\",\"Region\":\"Asia Pacific (Tokyo)\",\"AlarmArn\":\"arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:alarm-event-test\",\"OldStateValue\":\"OK\",\"Trigger\":{\"MetricName\":\"HealthyHostCount\",\"Namespace\":\"AWS/ApplicationELB\",\"StatisticType\":\"Statistic\",\"Statistic\":\"MINIMUM\",\"Unit\":null,\"Dimensions\":[{\"value\":\"targetgroup/tg-event-test/abcdefghijklmnopqrstuvwxyz\",\"name\":\"TargetGroup\"},{\"value\":\"ap-northeast-1c\",\"name\":\"AvailabilityZone\"},{\"value\":\"app/lb-test-event/abcdefghijklmnopqrstuvwxyz\",\"name\":\"LoadBalancer\"}],\"Period\":60,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"LessThanThreshold\",\"Threshold\":1.0,\"TreatMissingData\":\"- TreatMissingData:                    missing\",\"EvaluateLowSampleCountPercentile\":\"\"}}",
        "Timestamp": "2020-06-06T14:05:17.430Z",
        "SignatureVersion": "1",
        "Signature": "abcdefghijklmnopqrstuvwxyz",
        "SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-abcdefghijklmnopqrstuvwxyz.pem",
        "UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:123456789012:event-test:abcdefghijklmnopqrstuvwxyz",
        "MessageAttributes": {}
      }
    }
  ]
}

eventパラメータの型の確認

目的のパラメータは、eventパラメータ内のMessageの中に含まれています。まずは、Messageまでの型を確認してみます。 型の確認 MessageはString扱いです。

def event_test(event:, context:)
  p event.class
  p event['Records'].class
  p event['Records'][0].class
  p event['Records'][0]['Sns'].class
  p event['Records'][0]['Sns']['Message'].class
end

=> Hash
=> Array
=> Hash
=> Hash
=> String

MessageをHashへ変換して出力

def event_test(event:, context:)
  p JSON.parse(event['Records'][0]['Sns']['Message'])
end

Messageの出力結果 大分スッキリMessageの中身が確認できます。

{
  "AlarmName": "alarm-event-test",
  "AlarmDescription": null,
  "AWSAccountId": "123456789012",
  "NewStateValue": "ALARM",
  "NewStateReason": "Threshold Crossed: 1 out of the last 1 datapoints [0.0 (06/06/20 14:04:00)] was less than the threshold (1.0) (minimum 1 datapoint for OK -> ALARM transition).",
  "StateChangeTime": "2020-06-06T14:05:17.378+0000",
  "Region": "Asia Pacific (Tokyo)",
  "AlarmArn": "arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:alarm-event-test",
  "OldStateValue": "OK",
  "Trigger": {
    "MetricName": "HealthyHostCount",
    "Namespace": "AWS/ApplicationELB",
    "StatisticType": "Statistic",
    "Statistic": "MINIMUM",
    "Unit": null,
    "Dimensions": [
      {
        "value": "targetgroup/tg-event-test/abcdefghijklmnopqrstuvwxyz",
        "name": "TargetGroup"
      },
      {
        "value": "ap-northeast-1c",
        "name": "AvailabilityZone"
      },
      {
        "value": "app/lb-test-event/abcdefghijklmnopqrstuvwxyz",
        "name": "LoadBalancer"
      }
    ],
    "Period": 60,
    "EvaluationPeriods": 1,
    "ComparisonOperator": "LessThanThreshold",
    "Threshold": 1,
    "TreatMissingData": "- TreatMissingData:                    missing",
    "EvaluateLowSampleCountPercentile": ""
  }
}

ロードバランサとターゲットグループ名の取り出し

def event_test(event:, context:)
  message = JSON.parse(event['Records'][0]['Sns']['Message'])
  p message['Trigger']['Dimensions'].select { |k| k['name'] == 'LoadBalancer' }[0]['value']
  p message['Trigger']['Dimensions'].select { |k| k['name'] == 'TargetGroup' }[0]['value']
end

=> "app/lb-test-event/abcdefghijklmnopqrstuvwxyz"
=> "targetgroup/tg-event-test/abcdefghijklmnopqrstuvwxyz"

最後に

eventパラメータの取り出しでno implicit conversion of String into Integerが発生した際に、ご参考いただければ幸いです。