AWS Lambda – clean unused EC2 instances V2.0

Posted: February 5, 2019 in Amazon Web Services (AWS), Scripts

Changes compared with previous version:

  • Script will search all regions
  • added time when instance is launched
  • added option to terminate all EBS volumes associated with instance
  • uses Simple email service
  • uses Lambda environmental variables

6-1.png

import smtplib
import boto3
import collections
import datetime
import time
import sys
import os
from datetime import datetime
from dateutil.relativedelta import relativedelta
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

AWSAccountID = boto3.client('sts').get_caller_identity()['Account']
AWSUser = boto3.client('sts').get_caller_identity()['UserId']
AWSAccount = os.environ["AWS_Account_Name"]
# create date variables
date_after_month = datetime.now() + relativedelta(days = 7)
# date_after_month.strftime('%d/%m/%Y')
today = datetime.now().strftime('%d/%m/%Y')

# AWS SES variables
EMAIL_HOST = os.environ["EMAIL_HOST"]
EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"] # Replace with your SMTP username
EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"] # Replace with your SMTP password
SENT_TO = os.environ["SENT_TO"]
EMAIL_PORT = 587

def lambda_handler(event, context):

    instance_ids = []
    launch_date = ""
    launched = ""
    launched1 = ""
    ec = boto3.client('ec2')
    ec2_regions = [region['RegionName'] for region in ec.describe_regions()['Regions']]
    for region in ec2_regions:
     ec = boto3.client('ec2', region_name = region)
     ec2 = boto3.resource('ec2',region_name = region)
     reservations = ec.describe_instances().get('Reservations', []) 

     for reservation in reservations:
      for instance in reservation['Instances']:
         tags = {}
         for tag in instance['Tags']:
             tags[tag['Key']] = tag['Value']
             if tag['Key'] == 'Name':
               name = tag['Value']
         if not 'Owner' in tags or tags['Owner'] == 'unknown' or tags['Owner'] == 'Unknown':
              instance_ids.append(instance['InstanceId'])  

                # Check if "TerminateOn" tag exists:

              if 'TerminateOn' in tags:
                  # compare TerminteOn value with current date
                    if tags["TerminateOn"] == today:

                    # Check if termination protection is enabled
                     terminate_protection = ec.describe_instance_attribute(InstanceId = instance['InstanceId'] ,Attribute = 'disableApiTermination')
                     protection_value = (terminate_protection['DisableApiTermination']['Value'])
                     #if enabled disable it
                     if protection_value == True:
                        ec.modify_instance_attribute(InstanceId = instance['InstanceId'],Attribute = "disableApiTermination",Value = "False" )

                     volumes_to_delete = ec.describe_instance_attribute(InstanceId=instance['InstanceId'],Attribute='blockDeviceMapping')

                     for v in volumes_to_delete['BlockDeviceMappings']:

                       if volumes_to_delete['InstanceId']:
                        launch_date = str(v['Ebs']['AttachTime'])
                        device_name = v['DeviceName'] 

                        ec.modify_instance_attribute(InstanceId = instance['InstanceId'],Attribute = 'blockDeviceMapping',BlockDeviceMappings = [{'DeviceName': device_name,'Ebs': {'DeleteOnTermination':True}}])

                     # send email that instance is terminated
                     body = "<b>AWS Account:</b>" + AWSAccount + "<b>AWSAccountNumber:</b>" + AWSAccountID + "<b>Instance Name:</b>" + name + "<b>Instance ID:</b>" + instance['InstanceId'] + "<b>Created At:</b>" + launch_date + "<b>To be terminated at</b>:Now <b>Note:</b>er tag is missing from this instance, hence,instance is removed."
                     msg = MIMEMultipart('alternative')
                     msg['Subject'] = "Notification of terminated instances in " + region + " AWS region"
                     msg['From'] = "ses@amazon.com"
                     msg['To'] = SENT_TO
                     html = body
                     mime_text = MIMEText(html, 'html')
                     msg.attach(mime_text)
                     s = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
                     s.starttls()
                     s.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                     s.sendmail("ses@amazon.com", SENT_TO, msg.as_string())
                     s.quit()
                     # Terminate instance
                     ec.terminate_instances(InstanceIds = [instance['InstanceId']])

                    else:

                      now = datetime.now()
                      future = tags["TerminateOn"]
                      TerminateOn = datetime.strptime(future, "%d/%m/%Y")
                      days = (TerminateOn-now).days
                      volume1 = ec.describe_instance_attribute(InstanceId = instance['InstanceId'],Attribute = 'blockDeviceMapping')
                      for a in volume1['BlockDeviceMappings']:
                        if volume1['InstanceId']:
                         launched1  = str(a['Ebs']['AttachTime'])
                      body = "<b>AWS Account:</b>" + AWSAccount + "<b>AWSAccountNumber:</b>" + AWSAccountID + "<b>Instance Name:</b>" + name + "b&gt;Instance ID:" + instance['InstanceId'] + "<b>Created At:</b>" + launched1 + "Owner tag is mising from this instance, hence,instance will be removed."
                      msg = MIMEMultipart('alternative')
                      msg['Subject'] = "Notification of shutting down instances in " + region + " AWS region"
                      msg['From'] = "ses@amazon.com"
                      msg['To'] = SENT_TO
                      html = body
                      mime_text = MIMEText(html, 'html')
                      msg.attach(mime_text)
                      s = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
                      s.starttls()
                      s.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                      s.sendmail("ses@amazon.com, SENT_TO, msg.as_string())
                      s.quit()
					  # stop instance
                      ec.stop_instances(InstanceIds=[instance['InstanceId']])

              else:
                 if not 'TerminateOn' in tags:#, create it
                  ec2.create_tags(Resources=[instance['InstanceId']],Tags=[{'Key':'TerminateOn','Value':date_after_month.strftime('%d/%m/%Y')}])
                  volume = ec.describe_instance_attribute(InstanceId = instance['InstanceId'],Attribute = 'blockDeviceMapping')

                  for s in volume['BlockDeviceMappings']:
                     if volume['InstanceId']:
                      launched  = str(s['Ebs']['AttachTime'])

                  body = "<b>AWS Account:</b>" + AWSAccount + "<b>AWS Account Number:</b>"AWSAccountID + "<b>Instance Name:</b>" + name + "<b>Instance ID:</b>" + instance['InstanceId'] + Created<b> At:</b>" + launched + "<b>To be terminated at</b>: (6 days from now) <b>Note:</b>Owner tag is missing from this instance.If you do not wish this instance to be removed, please update the Owner tag."
                  msg = MIMEMultipart('alternative')
                  msg['Subject'] = "Notification of shutting down instances in " + region + " AWS region"
                  msg['From'] = "ses@amazon.com"
                  msg['To'] = SENT_TO
                  html = body
                  mime_text = MIMEText(html, 'html')
                  msg.attach(mime_text)
                  s = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
                  s.starttls()
                  s.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                  s.sendmail("ses@amazon.com", SENT_TO, msg.as_string())
                  s.quit()
				  # stop instance
                  ec.stop_instances(InstanceIds=[instance['InstanceId']])
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s