0
votes

I created a AWS Lambda function to send alert mails(SNS) whenever a EC2 instance changes state, which works perfectly fine. I did this by creating a rule in cloudWatch to trigger my lambda function & it captures all the instance details and publishes SNS to send out mails.

Current Feature: 1. Triggering point - A change in instance state 2. Lambda triggered - Captures instance state (running/stopped) 3. Lambda publishes the SNS mail - Mail has instance state details (running/stopped) about all EC2 instances even the instance which state is not changed.

Required Feature: 1. Triggering point - A change in instance state 2. Lambda triggered - Captures instance state (running/stopped) 3. Lambda publishes the SNS mail - Mail should send instance state details (running/stopped) only about the ec2 instances which got changed.

Thanks in advance!

Lambda Code:

import boto3
import json
import logging
import datetime 
import os
from botocore.exceptions import ClientError
from datetime import timedelta

region ='us-east-1'
ec2 = boto3.resource('ec2',region)
client = boto3.client('ec2',region)
snsClient = boto3.client('sns',region)


def lambda_handler(event, context):
    global stop
    global start
    stop = ec2.instances.filter(Filters=[{'Name': 'instance-state-name', 'Values': ['stopped']}])
    start = ec2.instances.filter(Filters=[{'Name': 'instance-state-name', 'Values': ['running']}])
    for instance1 in stop:
        print('Ec2 Instances which are stopped: ', 'Instance ID: ', instance1.id, 'Instance state: ', instance1.state, 'Instance type: ',instance1.instance_type)
    for instance2 in start:
        print('Ec2 Instances which are running: ', 'Instance ID: ', instance2.id, 'Instance state: ', instance2.state, 'Instance type: ',instance2.instance_type)
    publish_sns()   


def publish_sns():
    print('Publish Messsage to SNS Topic')
    subject_str = 'Alert! EC2 Instances Started / Stopped'
    affected_instances1 = [instance1.id for instance1 in stop]
    affected_instances2 = [instance2.id for instance2 in start]
    DT = datetime.datetime.now() + timedelta(hours = 5.5)

    Waqt = DT.strftime("%Y-%m-%d %H:%M:%S")
    msg = '^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nHello Team, \n\nFollowing EC2 instances have been started / stopped: \n\nStopped instances: \n'+ str(affected_instances1)+ '\n\nStarted instances: \n'+str(affected_instances2)+'\n\nInstance state changed time IST: '+str(Waqt)+'\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'
    response = snsClient.publish(TopicArn=os.environ['SNSARN'],Message=msg,Subject=subject_str)
1
What is your question exactly? Is something not working, do you want different functionality?Exelian
Current script: Sends out mail with all instances status My requirement: It should send instance state details only for the instances which state got changed.Abdul Salam
@Exelian I have edited my question for better understanding.. hope this helpsAbdul Salam

1 Answers

2
votes

Your lambda is invoked with two parameters - event & context - you should use event since it contains the information regarding the EC2 instance change instead of querying ec2.instance which will always return all the instances regardless to their state change.

Regardless to your implementation - What you are describing is to have the ability to know the previous state of all the instances and filtering the unchanged instances before emailing. You can save the entire array to a db and compare it back when your lambda is invoked by a state change.