告警信息发送脚本- Lambda 2

本节创建lambda 2,用于输出监控的告警信息。

image-20220301180533210

创建Lambda的IAM Role

进入IAM页面,创建Role:

image-20220228231408383

信任主体选择Lambda

image-20220228231442257

搜索以下Policy,并全部赋予给这个Role:

CloudWatchFullAccess  # Describe / Create / Drop CloudWatch alarms
AWSLambdaRole         # Invoke Lambda Function
AmazonSNSFullAccess   #  Publish SNS messages
AWSLambdaExecute      # Put Logs in S3
AmazonRDSFullAccess   # Describe / Alter RDS Attributes, Add Tags to RDS

image-20220228232004589

角色名称:lambdaExecRole-autoCreateCxCwAlarms_RDS

image-20220228232045068

点击Create Role创建Role

创建Lambda

进入Lambda页面,创建Lambda:

image-20220301202631172

为Lambda命名为alarm-sender, runtime选择Python3.9

image-20220301202729311

选择使用上一步创建的Role:

image-20220301202833978

将以下内容粘帖到函数体,第89行,替换成上一节创建的SNS ARN

并点击Deploy进行部署:

image-20220301203200922

import json
import urllib
import datetime
import dateutil.tz
import re
import boto3
import os

def changeAlarmToLocalTimeZone(event, timezoneCode, localTimezoneInitial, platform_endpoint):
    tz = dateutil.tz.gettz(timezoneCode)
    # exclude the Alarm event from the SNS records
    AlarmEvent = json.loads(event['Records'][0]['Sns']['Message'])

    # extract event data like alarm name, region, state, timestamp
    alarmName = AlarmEvent['AlarmName']
    descriptionexist = 0
    if "AlarmDescription" in AlarmEvent:
        description = AlarmEvent['AlarmDescription']
        descriptionexist = 1
    reason = AlarmEvent['NewStateReason']
    region = AlarmEvent['Region']
    state = AlarmEvent['NewStateValue']
    previousState = AlarmEvent['OldStateValue']
    timestamp = AlarmEvent['StateChangeTime']
    Subject = event['Records'][0]['Sns']['Subject']
    alarmARN = AlarmEvent['AlarmArn']
    RegionID = alarmARN.split(":")[3]
    AccountID = AlarmEvent['AWSAccountId']

    # get the datapoints substring
    pattern = re.compile('\[(.*?)\]')

    # test if pattern match and there is datapoints
    if pattern.search(reason):
        Tempstr = pattern.findall(reason)[0]

        # get in the message all datapoints timestamps and convert to localTimezone using same format
        pattern = re.compile('\(.*?\)')
        m = pattern.finditer(Tempstr)
        for match in m:
            Tempstr = match.group()
            tempStamp = datetime.datetime.strptime(Tempstr, "(%d/%m/%y %H:%M:%S)")
            tempStamp = tempStamp.astimezone(tz)
            tempStamp = tempStamp.strftime('%d/%m/%y %H:%M:%S')
            reason = reason.replace(Tempstr, '(' + tempStamp + ')')

    # convert timestamp to localTimezone time
    timestamp = timestamp.split(".")[0]
    timestamp = datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
    localTimeStamp = timestamp.astimezone(tz)
    localTimeStamp = localTimeStamp.strftime("%A %B, %Y %H:%M:%S")

    # create Custom message and change timestamps

    customMessage = 'You are receiving this email because your Amazon CloudWatch Alarm "' + alarmName + '" in the ' + region + ' region has entered the ' + state + ' state, because "' + reason + '" at "' + localTimeStamp + ' ' + localTimezoneInitial + '.'

    # Add Console link
    customMessage = customMessage + '\n\n View this alarm in the AWS Management Console: \n' + 'https://' + RegionID + '.console.aws.amazon.com/cloudwatch/home?region=' + RegionID + '#s=Alarms&alarm=' + urllib.parse.quote(
        alarmName)

    # Add Alarm Name
    customMessage = customMessage + '\n\n Alarm Details:\n- Name:\t\t\t\t\t\t' + alarmName

    # Add alarm description if exist
    if (descriptionexist == 1): customMessage = customMessage + '\n- Description:\t\t\t\t\t' + description
    customMessage = customMessage + '\n- State Change:\t\t\t\t' + previousState + ' -> ' + state

    # Add alarm reason for changes
    customMessage = customMessage + '\n- Reason for State Change:\t\t' + reason

    # Add alarm evaluation timeStamp
    customMessage = customMessage + '\n- Timestamp:\t\t\t\t\t' + localTimeStamp + ' ' + localTimezoneInitial

    # Add AccountID
    customMessage = customMessage + '\n- AWS Account: \t\t\t\t' + AccountID

    # Add Alarm ARN
    customMessage = customMessage + '\n- Alarm Arn:\t\t\t\t\t' + alarmARN

    # push message to SNS topic
    response = platform_endpoint.publish(
        Message=customMessage,
        Subject=Subject,
        MessageStructure='string'
    )


# Get SNS Topic ARN from Environment variables
NotificationSNSTopic = os.environ['NotificationSNSTopic']
# Get timezone corresponding to your localTimezone from Environment variables
timezoneCode = os.environ['TimeZoneCode']
# Get Your local timezone Initials, E.g UTC+2, IST, AEST...etc from Environment variables
localTimezoneInitial = os.environ['TimezoneInitial']
# Get SNS resource using boto3
SNS = boto3.resource('sns')
# Specify the SNS topic to push message to by ARN
platform_endpoint = SNS.PlatformEndpoint(NotificationSNSTopic)


def lambda_handler(event, context):
    # Call Main function
    changeAlarmToLocalTimeZone(event, timezoneCode, localTimezoneInitial, platform_endpoint)

可以使用以下JSON作为测试事件:

{
    "Records": [
        {
            "EventSource": "aws:sns",
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:lambda:us-west-2:532134256174:function:CustomizeCloudWatchAlarmsNotifications-RDS_DatabaseConnections",
            "Sns": {
                "Type": "Notification",
                "MessageId": "f9f5ed56-3d38-57c8-b4ea-b51588f5f871",
                "TopicArn": "arn:aws:sns:us-west-2:532134256174:customizedAlarmAction-RDS_DatabaseConnections",
                "Subject": "ALARM: \"Test LocalTime\" in China, Asia (Hong Kong)",
                "Message": "{\"AlarmName\":\"RDS_DatabaseConnections\",\"AlarmDescription\":\"Auto-created customized CloudWatch Alarm <RDS_DatabaseConnections>\",\"AWSAccountId\":\"532134256174\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 out of the last 1 datapoints [0.0 (04/12/20 03:56:00)] was greater than or equal to the threshold (0.0) (minimum 1 datapoint for OK -> ALARM transition).\",\"StateChangeTime\":\"2020-12-04T03:57:01.659+0000\",\"Region\":\"US West (Oregon)\",\"AlarmArn\":\"arn:aws:cloudwatch:us-west:532134256174:alarm:RDS_DatabaseConnections LocalTime\",\"OldStateValue\":\"OK\",\"Trigger\":{\"Period\":60,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"GreaterThanOrEqualToThreshold\",\"Threshold\":0.0,\"TreatMissingData\":\"- TreatMissingData: missing\",\"EvaluateLowSampleCountPercentile\":\"\",\"Metrics\":[{\"Expression\":\"FILL(m1, 0)\",\"Id\":\"e1\",\"Label\":\"Expression1\",\"ReturnData\":true},{\"Id\":\"m1\",\"MetricStat\":{\"Metric\":{\"Dimensions\":[{\"value\":\"API\",\"name\":\"Type\"},{\"value\":\"DescribeAlarms\",\"name\":\"Resource\"},{\"value\":\"CloudWatch\",\"name\":\"Service\"},{\"value\":\"None\",\"name\":\"Class\"}],\"MetricName\":\"CallCount\",\"Namespace\":\"AWS/Usage\"},\"Period\":60,\"Stat\":\"Average\"},\"ReturnData\":false}]}}",
                "Timestamp": "2020-12-04T03:57:01.702Z",
                "SignatureVersion": "1",
                "Signature": "WcgVMPrlQsJY3yqbds968tqKPC6KKDWHSjIwEmzKVHZYg6foN9F5sm2Tp5IWPgaM9wMmYg8dpQjkxSm4q9V9iP1PbLp81RgJS2NghdeHNVnyxyzywXFMDztYZpgB2pjzfT101RVGpUwVPntOpBeBq2KAs/NrFX1nS2aTK/OX+gyOxwYZxRftzd+ttHA+PCh0kKlym7nnxaWuO9hgSrnupH2YttuvsdTSAOZ4MGhBON/sMmmlcxzfiFD+jJaqlHFmQ0DncjSe1NNwceOpwNsue6//sMYU1QzV6bO34I343KmQdXYw/KISDz7qH70Odm7nRLN3ExSOhtC/FS0/dXGl4Q==",
                "SigningCertUrl": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-010a507c1833636cd94bdb98bd93083a.pem",
                "UnsubscribeUrl": "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:532134256174:customizedAlarmAction-RDS_DatabaseConnections",
                "MessageAttributes": {}
            }
        }
    ]
}

创建测试:

image-20220301203307225

将上面的json粘帖进来,并为event命名:

image-20220301203331939

创建完成后,再次点击Test

image-20220301203348633

在邮箱中收到对应的告警邮件:

image-20220301203940686