How to Stop and Start EC2 Instance using boto3 and lambda Function

Question:

I want to start and stop EC2 instances using Lambda Function

I am able to start and stop EC2 instances using the Instance ID but How can I do the same for Instance name, I am trying to do this because my end-user doesn’t know what is instance-id they are only aware of Instance name

below is my code which is working fine for instance ID

import json
import boto3

region = 'us-east-1'
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    instances = event["instances"].split(',')
    action = event["action"]
    
    if action == 'Start':
        print("STARTing your instances: " + str(instances))
        ec2.start_instances(InstanceIds=instances)
        response = "Successfully started instances: " + str(instances)
    elif action == 'Stop':
        print("STOPping your instances: " + str(instances))
        ec2.stop_instances(InstanceIds=instances)
        response = "Successfully stopped instances: " + str(instances)
    
    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }

Events I am passing for stopping

{
  "instances": "i-0edb625f45fd4ae5e,i-0818263a2152a23bd,i-0cd2e17ba6f62f651",
  "action": "Stop"
}

Events I am passing for starting

{
  "instances": "i-0edb625f45fd4ae5e,i-0818263a2152a23bd,i-0cd2e17ba6f62f651",
  "action": "Start"
}
Asked By: Aviral Bhardwaj

||

Answers:

Instance name is based on tag called Name. So to get instance ids based on name you have to filter instances by tags. Below is one possible way of doing that:

import json
import boto3

region = 'us-east-1'

ec2 = boto3.client('ec2', region_name=region)

def get_instance_ids(instance_names):

    all_instances = ec2.describe_instances()
    
    instance_ids = []
    
    # find instance-id based on instance name
    # many for loops but should work
    for instance_name in instance_names:
        for reservation in all_instances['Reservations']:
            for instance in reservation['Instances']:
                if 'Tags' in instance:
                    for tag in instance['Tags']:
                        if tag['Key'] == 'Name' 
                            and tag['Value'] == instance_name:
                            instance_ids.append(instance['InstanceId'])
                            
    return instance_ids

def lambda_handler(event, context):
    
    instance_names = event["instances"].split(',')
    action = event["action"]

    instance_ids = get_instance_ids(instance_names)

    print(instance_ids)

    if action == 'Start':
        print("STARTing your instances: " + str(instance_ids))
        ec2.start_instances(InstanceIds=instance_ids)
        response = "Successfully started instances: " + str(instance_ids)
    elif action == 'Stop':
        print("STOPping your instances: " + str(instance_ids))
        ec2.stop_instances(InstanceIds=instance_ids)
        response = "Successfully stopped instances: " + str(instance_ids)
    
    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }
Answered By: Marcin

There is a highly scalable and cost-effective solution developed by AWS. Check it at https://aws.amazon.com/es/solutions/implementations/instance-scheduler-on-aws/.

It is easily deployed using CloudFront templates and managed by a cli. Last but not least, it operate over multiple accounts, and that way you can have a lot of ec2 instances (and RDS instances too) spread over multiple accounts and this solution will save you a lot of effort.