Run a Lambda function for RDS using the DBInstanceIdentifier

0

Hello,

I have been trying to automate stopping RDS instance using a Lambda Function when the number of connections made to the instances are low than 1. I have used an EventBridge that triggers the Lambda function when the Alarm created goes into In Alarm.

From this, it stops all the RDS instances even those with connections. I understand that the issue is in the Lambda function since it loops through all instances and turns them off.

I was inquiring if there is a way to pass the DBInstanceIdentifier of the instance in alarm state only to the lambda function for it to only shut down the instance in which the alarm is on.

Below is the lambda code used.

import boto3 import os

target_db = None region = os.environ['AWS_REGION'] rds = boto3.client('rds', region_name=region)

def get_tags_for_db(db): instance_arn = db['DBInstanceArn'] instance_tags = rds.list_tags_for_resource(ResourceName=instance_arn) return instance_tags['TagList']

def get_tags_for_db_cluster(db): instance_arn = db['DBClusterArn'] instance_tags = rds.list_tags_for_resource(ResourceName=instance_arn) return instance_tags['TagList']

def lambda_handler(event, context):

dbs = rds.describe_db_instances()
readReplica = []
for db in dbs['DBInstances']:
    readReplicaDB = db['ReadReplicaDBInstanceIdentifiers']
    readReplica.extend(readReplicaDB)
print("readReplica : " + str(readReplica))

for db in dbs['DBInstances']:
    db_id = db['DBInstanceIdentifier']
    db_engine = db['Engine']
    print('DB ID : ' + str(db_id))
    db_tags = get_tags_for_db(db)
    print("All Tags : " + str(db_tags))
    tag = next(iter(filter(lambda tag: tag['Key'] == 'AutoStop' and tag['Value'].lower() == 'true', db_tags)), None)
    print("AutoStop Tag : " + str(tag))

    if db_engine not in ['aurora-mysql','aurora-postgresql']:
        if db_id not in readReplica and len(readReplica) == 0:
            if tag:
                target_db = db
                print("DB Details : " + str(target_db))
                db_id = target_db['DBInstanceIdentifier']
                db_status = target_db['DBInstanceStatus']
                print("DB ID : " + str(db_id))
                print("DB Status : " + str(db_status))
                if db_status == "available":
                    AutoStopping = rds.stop_db_instance(DBInstanceIdentifier=db_id)
                    print("Stopping DB : " + str(db_id))
                else:
                    print("Database already stopped : " + str(db_id))
            else:
                print("AutoStop Tag Key not set for Database to Stop...")
        else:
            print("Cannot stop or start a Read-Replica Database...")

dbs = rds.describe_db_clusters()
readReplica = []
for db in dbs['DBClusters']:
    readReplicaDB = db['ReadReplicaIdentifiers']
    readReplica.extend(readReplicaDB)
print("readReplica : " + str(readReplica))

for db in dbs['DBClusters']:
    db_id = db['DBClusterIdentifier']
    db_engine = db['Engine']
    print('DB ID : ' + str(db_id))
    db_tags = get_tags_for_db_cluster(db)
    print("All Tags : " + str(db_tags))
    tag = next(iter(filter(lambda tag: tag['Key'] == 'AutoStop' and tag['Value'].lower() == 'true', db_tags)), None)
    print("AutoStop Tag : " + str(tag))

    if db_engine in ['aurora-mysql','aurora-postgresql']:
        if db_id not in readReplica and len(readReplica) == 0:
            if tag:
                target_db = db
                db_id = target_db['DBClusterIdentifier']
                db_status = target_db['Status']
                print("Cluster DB ID : " + str(db_id))
                print("Cluster DB Status : " + str(db_status))
                if db_status == "available":
                    AutoStopping = rds.stop_db_cluster(DBClusterIdentifier=db_id)
                    print("Stopping Cluster DB : " + str(db_id))
                else:
                    print("Cluster Database already stopped : " + str(db_id))
            else:
                print("AutoStop Tag Key not set for Cluster Database to Stop...")
        else:
            print("Cannot stop or start a Read-Replica Cluster Database...")
2 Answers
0

Note that lambda_handler() accepts an "event" argument which, as described at https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html is a document that wraps the source event. You can dig a bit deeper into the docs to find the event format that applies for your alarm, or trigger the alarm, capture the event and view it. I'd expect the DB identifier would be in there.

EXPERT
answered 2 years ago
0

Hello guys,

I did some research and was able to get a break through. Using SNS as a trigger to the lambda function after the Cloud Watch alarm changes to IN ALARM. CloudWatch provides a message that is sent to a SNS Topic. When the SNS triggers the Lambda Function, the message event can be obtained by a Lambda code. From that you can tap into the message dictionary and get the value of the DBIdentifier.

The below link shows how you can get the message from the SNS topic

https://docs.aws.amazon.com/lambda/latest/dg/with-sns-create-package.html#with-sns-example-deployment-pkg-python

answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions