Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Create an AWS Lambda Function to Stop and Start an RDS Instance

DZone's Guide to

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.

· Cloud Zone ·
Free Resource

Site24x7 - Full stack It Infrastructure Monitoring from the cloud. Sign up for free trial.

It’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.

Image title

  • 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.


Create Role

  • Provide a descriptive role name (for example), lambda-start-stop-rds, and click Create Role.

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

Image title

  • A Lambda function will be created and will appear as below:

Image title

  • 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.

Image title

  • 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.

Image title

  • Now go back to the Lambda function and the AWS Lambda added should appear as a Resource.


Image title

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 function RDSInstanceStop .
  •  DBInstance variable holds the environment variable DBInstanceName  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.

Image title

  • Select the execution role to  lambda-start-stop-rds  and save the function.

Image title

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 policy

  • Go 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.


Image title

  • The Role now has access to start and stop the functions specifically defined along with any RDS instances.


Image title

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='RDSInstancetStart'
        )
        #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.


Site24x7 - Full stack It Infrastructure Monitoring from the cloud. Sign up for free trial.

Topics:
rds ,python 2.7 ,aws lambda ,cloud

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}