Create an AWS Lambda Function to Stop and Start an RDS Instance
Here we take a look at how you can trigger RDS instances to stop and start with a few simple lines of Python commands.
Join the DZone community and get the full member experience.
Join For FreeIt’s a fairly common practice in Amazon Web Services (AWS) world to have a Relational Database Service (RDS) instance running only during certain peak times and other times conveniently shut down. I wanted to use AWS Lambda using Python to be able to start and stop the RDS instance and want the DB Instance name parameterized as an environment variable. So when I move code from Dev to QA to Production I can change the DB name in the environment variable without having to change the code. I suppose one can use the same technique to start and stop different types of instances, like MySQL, MariaDB or PostgreSQL.
So let’s get started.
Lambda Function to Stop an RDS Instance
Step 1 – Create an IAM role
We will create an appropriate IAM role to enable access to CloudWatch logs, as well as to start and stop an RDS instance. AWS now has a convenient visual editor for policy selections should you elect its use.
I will first create a policy and attach then it to an IAM Role
- Log into the IAM console and click on
- Policy and Create Policy.
- Paste the following in the JSON editor.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:StopDBInstance",
"rds:StartDBInstance"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
Give a policy name: policy_start_stop_RDS, along with a description, then click on Create Policy.
- Now in the IAM console click on Roles and Create Roles
- Choose AWS Services, Lambda as your service.
- In the Search bar search for policy_ and the policy you created earlier should appear as below.
Provide a descriptive role name (for example), lambda-start-stop-rds, and click Create Role.
Step 2 – Author a Function
- Be sure you are in the correct region for creating Lambda functions and in the same region in which your DB instance was created. In my case, it is N.Virginia.
- Get the RDS Instance name and the Availability Zone from the Administrator.
- Open the Lambda console and click on Create Function and Author from Scratch
- Enter the following information in the window
- Name: RDSInstanceStop
- Runtime: Python 2.7
- Role: Choose an existing role
Role Name: Lambda-start-stop-rds and click on Create Function
- A Lambda function will be created and will appear as below:
At the top right hand corner there is now an ARN resource created for the Lambda function. This is used to grant permissions for the Lambda function to access Lambda API GetFunctionConfiguration plus access to the environment variables.
- Return to the Role: lambda-start-stop-rds and click on Add inline policy.
Next, go to the JSON tab and enter:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:GetFunctionConfiguration",
"Resource": "arn:aws:lambda:<region>:<Account_id>:function:RDSInstanceStop"
}
]
}
- Be sure to change the Resource to the Lambda ARN you just created.
- Assign the Lambda ARN a descriptive policy name such as policy_rds_stop and click Save.
- Now go back to the Lambda function and the AWS Lambda added should appear as a Resource.
Step 3 – Update Function Code
- In the Python function code section paste the following:
import sys
import botocore
import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
rds = boto3.client('rds')
lambdaFunc = boto3.client('lambda')
print 'Trying to get Environment variable'
try:
funcResponse = lambdaFunc.get_function_configuration(
FunctionName='RDSInstanceStop'
)
DBinstance = funcResponse['Environment']['Variables']['DBInstanceName']
print 'Stoping RDS service for DBInstance : ' + DBinstance
except ClientError as e:
print(e)
try:
response = rds.stop_db_instance(
DBInstanceIdentifier=DBinstance
)
print 'Success :: '
return response
except ClientError as e:
print(e)
return
{
'message' : "Script execution completed. See Cloudwatch logs for complete output"
}
- The primary piece of line that stops a DB instance is
rds.stop_db_instance
. -
lambdaFunc.get_function_configuration
returns a dictionary of the properties of the functionRDSInstanceStop
. -
DBInstance
variable holds the environment variableDBInstanceName
which is the key value pair that one can use to separate Dev, QA or Prod environments.
Step 4 – Configure the Lambda Function
- Scroll down to the Environment Variables and add two items:
- Key:
DBInstanceName
- Value: <
userDB instance name
>. In my example, I used a test database.
- Key:
- Select the execution role to
lambda-start-stop-rds
and save the function.
Step 5 – Time to Test
- On the top right corner of the screen select Test and Configure Test events.
- Select Create New Test Event and select the Hello World event template.
- When you click on save, the execution should succeed. If your DB is not started, there is nothing to actually stop and hence you will get a message similar to “Instance <> is not in available state.”
Congratulations, you just created a Lambda function to stop an RDS instance.
Now let’s create a function for starting an RDS instance. Since the steps are repetitive to those of the Stop Lambda Function, the instructions will only mention changes to the steps noted above.
Lambda Function to Start an RDS Instance
Step 1 – Create an IAM Role
NOTE: We have defined both start and stop actions in the earlier IAM role "policy_start_stop_RDS”, so for this example we will use the same role.
Step 2 – Author a Function
- Give the same settings as above except name the function as “RDSInstanceStart”.
Step 3 – Update the IAM Role
We will update the IAM Role
lambda_start_stop_RDS
to include another inline policyGo to IAM Roles and select lambda-start-stop-rds Role.
- Click on Add Inline Policy and edit JSON as below. Be sure to change the Account and Region id to the function's ARN.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:GetFunctionConfiguration",
"Resource": "arn:aws:lambda:<region>:<Account_id>:function:RDSInstanceStart"
}
]
}
- Save the policy as policy_rds_start.
- The Role now has access to start and stop the functions specifically defined along with any RDS instances.
Step 4 – Update the Function Code
Update the Lambda function as below:
import sys
import botocore
import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
# TODO implement
rds = boto3.client('rds')
lambdaFunc = boto3.client('lambda')
print 'Trying to get Environment variable'
try:
funcResponse = lambdaFunc.get_function_configuration(
FunctionName='RDSInstanceStart'
)
#print (funcResponse)
DBinstance = funcResponse['Environment']['Variables']['DBInstanceName']
print 'Starting RDS service for DBInstance : ' + DBinstance
except ClientError as e:
print(e)
try:
response = rds.start_db_instance(
DBInstanceIdentifier=DBinstance
)
print 'Success :: '
return response
except ClientError as e:
print(e)
return
{
'message' : "Script execution completed. See Cloudwatch logs for complete output"
}
- The important line of code to note is
rds.start_db_instance
, which starts the RDS.
Step 5 – Configure the Lambda function
Follow the same steps as above to configure the Lambda Function for the Environment variables and Execution Role.
Congratulations, you can now Start and Stop the RDS instance from a Lambda Function.
Opinions expressed by DZone contributors are their own.
Comments