Table of Content
In the first part of articles we prepare Terraform configuration for deploy, run and log our Lambda function by schedule. Here I will show how to interact with AWS API through Node.js.
Structure of code
├── package
├── index.js
├── rds-scheduler.js
Implementation
The code is scaffolding which help me create schedulers for another type of instances on AWS:
// index.js
/**
* Main function entrypoint for lambda.
*
* Stop and start AWS resources:
* - rds instances
* - rds aurora clusters
* - instance ec2
*
* Suspend and resume AWS resources:
* - ec2 autoscaling groups
*
* Terminate spot instances (spot instance cannot be stopped by a user).
*
* @param event
* @param context
* @param callback
*/
exports.handler = (event, context, callback) => {
const strategy = {};
// Retrieve variables from aws lambda ENVIRONMENT
const scheduleAction = process.env.SCHEDULE_ACTION;
const awsRegions = process.env.AWS_REGIONS.replace(" ", "").split(",");
const resourceTags = JSON.parse(process.env.RESOURCES_TAGS);
//strategy['AutoscalingScheduler'] = process.env.AUTOSCALING_SCHEDULE;
//strategy['SpotScheduler'] = process.env.SPOT_SCHEDULE;
//strategy['InstanceScheduler'] = process.env.EC2_SCHEDULE;
strategy['rds-scheduler'] = process.env.RDS_SCHEDULE;
console.log(scheduleAction);
console.log(awsRegions);
console.log(resourceTags);
console.log(strategy);
for (const serviceName in strategy) {
let toSchedule = strategy[serviceName];
if (toSchedule === 'true') {
for (const awsRegion of awsRegions) {
let Service = require(serviceName);
let service = new Service(awsRegion);
service.run(scheduleAction, resourceTags, callback);
}
}
}
};
// rds-scheduler.js
const AWS = require('aws-sdk');
class RdsScheduler {
constructor(awsRegion) {
this.awsRegion = awsRegion;
this.rds = new AWS.RDS();
}
async run(action, resourceTags, callback) {
if (!resourceTags) {
throw new Error('Resource tags must be specified otherwise you will shoutdown all instances');
}
this.rds.describeDBInstances(async (rdsErr, rdsData) => {
for (let i = 0; i < rdsData.DBInstances.length; i++) {
let dbInstance = rdsData.DBInstances[i];
let rdsTagParams = {
ResourceName: dbInstance.DBInstanceArn
};
try {
let tagData = await this.rds.listTagsForResource(rdsTagParams).promise();
let tags = tagData.TagList || [];
if (this.allowDispatch(tags, resourceTags)) {
let data = await this[action](dbInstance.DBInstanceIdentifier);
callback(null, data);
console.log(`${action[0].toUpperCase()}${action.slice(1)} RDS instance ${dbInstance.DBInstanceIdentifier}`);
}
} catch (e) {
callback(e, null);
console.exception(e);
}
}
})
}
/**
* Stop RDS instance by identifier
*
* @param instanceIdentifier
* @returns {Promise<*>}
*/
async stop(instanceIdentifier) {
let shutdownParams = {
DBInstanceIdentifier: instanceIdentifier
};
return this.rds.stopDBInstance(shutdownParams).promise();
}
/**
* Start RDS instance by identifier
*
* @param instanceIdentifier
* @returns {Promise<*>}
*/
async start(instanceIdentifier) {
let startParams = {
DBInstanceIdentifier: instanceIdentifier
};
return await this.rds.startDBInstance(startParams).promise();
}
/**
* Filter and compare tags which we get from DBInstance (instanceTags)
* with tags with we pass from configuration (resourceTags).
*
* DBInstance must include all tags which were passed from configuration,
* otherwise action won't dispatch.
*
* @param instanceTags
* @param resourceTags
*/
allowDispatch(instanceTags, resourceTags) {
let toDispatch = true;
instanceTags.forEach((tag) => {
resourceTags.forEach((resourceTag) => {
if (tag.Key === resourceTag.Key) {
toDispatch = (tag.Value === resourceTag.Value) ? (toDispatch && true) : (toDispatch && false)
}
});
});
return toDispatch;
}
}
module.exports = RdsScheduler;
Future improvements:
- Implement
autoscaling-scheduler
,spot-scheduler
,instance-scheduler
; - Allow create snapshot for RDS instance before stopping. How it do you can find in this article;
- Allow stop/start RDS aurora clusters (mark)
Further reading
- Start/Stop RDS instances on schedule
- Implementing DB Instance Stop and Start in Amazon RDS
- Terraform module with Python on the board
- Auto Shutdown AWS EC2s with Lambda, CloudWatch (and Terraform)
- EC2 Scheduler. AWS Implementation Guide
- AWS.RDS SDK (Node.js)
- How to get RDS tags?
- How do I stop and start Amazon EC2 instances at regular intervals using Lambda?