3

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 Answer 1

8
+50

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'

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much AppleBaggins. This solved my problem. You have used instance_id = i['InstanceId'] to retreive the instance id. I want to get the name of the instance. I have used this instance_id = i['InstanceName'] and instance_id = i['InstanceTag'] to get it. But both of them returned me an error saying KeyError: 'InstanceTag' What should I use there?
That gets to be a little more in-depth! I'll edit my answer for the new code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.