Lambda Python script to stop/start instances based on tag values
Intro
I run into this a lot – finding a good way to automate startup/shutdown of EC2 instances.
AWS has a very robust solution here, but I’m keeping this simple.
Here’s a Python script that looks for instances tagged with the key shutmedown
and value true
:
import boto3
ec2 = boto3.resource("ec2")
SHUTDOWN_TAG = "shutmedown"
ACTIONS = {
"stop": {"filter_values": ["running"]},
"start": {"filter_values": ["stopped"]},
}
def change_ec2_instance_state(action, tag):
try:
filters = [
{
"Name": "instance-state-name",
"Values": ACTIONS[action]["filter_values"],
},
{
"Name": f"tag:{tag}",
"Values": ["true"],
},
]
except KeyError:
raise KeyError(f"Invalid action: {action}. Expected one of: {ACTIONS.keys()}")
instances = ec2.instances.filter(Filters=filters)
instance_ids = [instance.id for instance in instances]
print(f"Instances to {action}: {instance_ids}")
if instance_ids:
filtered_instances = ec2.instances.filter(InstanceIds=instance_ids)
if action == "stop":
response = filtered_instances.stop()
elif action == "start":
response = filtered_instances.start()
print(response)
else:
print(f"No instances to {action}")
def lambda_handler(event, context):
change_ec2_instance_state(event["action"], SHUTDOWN_TAG)
I then created 2 EventBridge triggers on a cron schedule (2AM and 11AM) that provide the following inputs to the Lambda target:
// For the stop event that runs in the evening
{
"action": "stop"
}
// For the start event that runs in the morning
{
"action": "start"
}
If you’ve got large deployments or users in multiple regions, you might need different tags, more events, additional logic, but the foundation is there.
You’ll need to add the some additional permissions to the IAM role that the Lambda function uses. I just added a new inline policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StartAndStopBasedOnTags",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*"
}
]
}
Might mash this into Terraform and post it here later. Thanks for reading.