Perform shutting and starting of instances during non-business hours to reduce operating cost.
Architecture Diagram
AWS Lambda function will be called using CloudWatch rule at regular intervals every hour. Lambda function will review tags of each instance and verify weather instance needed shutdown or startup depend upon local time. Lambda code can be placed on S3 for safekeeping to import from.
New Log stream and group created to keep track of shutdown and startup events. Amazon SNS topics can be used for event notification. A custom role is created to get EC2 instance information and write logs to the CloudWatch event.
Instance tagging will be used to determine the instance needed to shut down or startup.

Tagging format
Key name: “shutdown”
Values format :
weekday:<hours to shutdown separated by hours>;weekend: <hours to shutdown separated by hours>;
weekday: Monday to Friday
weekend: Saturday and Sunday
This format can be changed but code change needed for that.
PS. Keywords include colon(:) and semicolon(;)
Role Policy
Create Role policy with the following permissions.

Create a role and attach it to the newly created policy.

Lambda Function
Create a Lambda function with runtime python3.8. A select newly created role for the Lambda function.

Download Archive.zip file code from my GitHub below link –
https://github.com/yogeshagrawal11/cloud/tree/master/aws/EC2/instance_shutdown_script
To add function code. Click on Action and upload a zip file.

After uploading a zip file you would see “lambda_function.py” is an actual script for instance. I am using the default handler in the script. In case, handler information is changed please make appropriate changes either in function name or file name.
Filename: lambda_function.py
Python function name: lambda_handler

I am using “pytz” module to get the correct timezone conversion so needed to upload that module code.
For regions to timezone mapping, I have created a dictionary. In case your region is not part of the list feel free to add a new key with region name and respective timezone.

In our magical earth, sunset and sunrise are happening at the same time for different regions. So I am calling function to perform both activities simultaneously. “system_function” will generate a list of all instances that need to stop and start.

In the case of the large instance count, I am using a paginator.

Paginator will reduce the list by filtering tag value. If the “shutdown” tag is not set then the instance will not be part of the list. Using the same function for starting and shutting down instances. Hence, for shutting down instances I am also filtering for running instances. Or else to start instances I am filtering for stopped instances.

Set a timeout value of more than 3sec. Normally it takes me 10 to 15 sec. This value can vary with the environment and no of instances.
Please use the following handler or make any appropriate changes.
Lambda handler = lambda_function.lambda_handler

Lambda Permissions :
Lambda permission for creating log stream/log group and adding events in cloud watch.

Lambda function also has permission to get instance status, able to read instance tags. Start and stop instances.

Cloud watch Rule
Create a CloudWatch rule that will trigger the Lambda function every start of the hour every day.



Testing
Current time: Fri 4:18 pm PST
In the Oregon region, I have instance1 will be shut down and instance 2 will be started.

In North Virginia region, east 2 and east 3 should be shutdown(+3hr)

Manually run Lambda function

Logwatch events

Oregon instances Started and stopped as expected

North Virginia instances stopped

Mumbai region instance closed as well

Disclaimer :
SNS topic is not triggered but can be added for any stopping and starting instances.
Database can be used to track no of hours saved due to starting and stopping Ec2 instance script