3
votes

I have 20 EC2 Windows instances and trying to create alarms if threshold is met. If I have to create alarms for CPU metric of every instance from the Cloud Watch console, I have to create 20 alarms. Instead of doing that, I decided to write a Lambda function. It looks like the following :

import boto3
import collections
from datetime import datetime
import calendar

def lambda_handler(event, context):

    client = boto3.client('cloudwatch')

    alarm = client.put_metric_alarm(
    AlarmName='CPU Alarm',
    MetricName='CPUUtilization',
    Namespace='AWS/EC2',
    Statistic='Average',
    ComparisonOperator='GreaterThanOrEqualToThreshold',
    Threshold=70.0,
    Period=300,
    EvaluationPeriods=1,
    Dimensions=[
        {
            'Name': 'InstanceId',
            'Value': '{instance_id}'
        }
    ],
    Unit='Percent',
    ActionsEnabled=True,
    AlarmActions=['arn:aws:sns:us-east-1:380431751678:CloudWatch'])

    print alarm

According to the above script, it will find the AWS/EC2 namespace and monitors all the metrics with name CPUUtilization. I have 20 metrics with the name . The above script has created the alarm but the state is in INSUFFICIENT_DATA. I have waited for 30 minutes and my server's CPU Utilization is more than the threshold specified(70%).To verify, I have created an alarm from CloudWatch console which is exactly the same but it does only for one instance. This has automatically been put to ALARM State and SNS notification has been sent.

Why is it so? Am I doing something wrong?

1

1 Answers

7
votes

First, I would remove your account ID from the code posted above for security!

You're not gathering data for the alarm because the dimensions are being set to {instance_id}, but you're not providing any values to that variable.

You need to loop through your instances and create an alarm for each, like this:

import boto3
import collections
from datetime import datetime
import calendar

client = boto3.client('cloudwatch')
ec = boto3.client('ec2')

def lambda_handler(event, context):
    reservations = ec.describe_instances()
        for r in reservations['Reservations']:
            for i in r['Instances']:
                instance_id = i['InstanceId']
                for t in i['Tags']:
                    if t['Key'] == 'Name':
                        iname = t['Value']
                        alarm = client.put_metric_alarm(
                        AlarmName='CPU Alarm ' + iname ,
                        MetricName='CPUUtilization',
                        Namespace='AWS/EC2',
                        Statistic='Average',
                        ComparisonOperator='GreaterThanOrEqualToThreshold',
                        Threshold=70.0,
                        Period=300,
                        EvaluationPeriods=1,
                        Dimensions=[
                            {
                                'Name': 'InstanceId',
                                'Value': instance_id
                            }
                        ],
                        Unit='Percent',
                        ActionsEnabled=True,
                        AlarmActions=['arn:aws:sns:us-east-1:012345678912:CloudWatch'])

You'll need to filter your describe_instances to just your desired instances and you'll need to change the account ID at the bottom, but that should create an alarm for each of the 20 instances with an alarm name of 'CPU Alarm i-whatevertheinstanceIDis'