Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
AshanFernando committed Jun 10, 2016
0 parents commit bca7fb8
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dynamodb/bin
/node_modules
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Serverless plugin
84 changes: 84 additions & 0 deletions dynamodb/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"use strict";

var spawn = require('child_process').spawn
, fs = require('fs')
, Q = require('q')
, installer = require('./installer');

const DOWNLOAD_PATH = 'http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.tar.gz'
, JAR = 'DynamoDBLocal.jar'
, DB_PATH = './bin';

var runningProcesses = {}
, dynamodb = {
/**
*
* @param port
* @param dbPath if omitted will use in memory
* @param additionalArgs
* @returns {Promise.<ChildProcess>}
*/
launch: function (port, dbPath, additionalArgs) {
if (runningProcesses[port]) {
return Q.fcall(function () {
return runningProcesses[port];
});
}

if (!additionalArgs) {
additionalArgs = [];
} else if (Array.isArray(additionalArgs)) {
additionalArgs = [additionalArgs];
}

if (!dbPath) {
additionalArgs.push('-inMemory');
} else {
additionalArgs.push('-dbPath', dbPath);
}

return installer.install(DB_PATH, DOWNLOAD_PATH, JAR)
.then(function () {
var args = [
'-Djava.library.path=./DynamoDBLocal_lib', '-jar', JAR, '-port', port
];
args = args.concat(additionalArgs);

var child = spawn('java', args, {
cwd: DB_PATH
, env: process.env
, stdio: ['pipe', 'pipe', process.stderr]
});

if (!child.pid) throw new Error("Unable to launch DynamoDBLocal process");

child
.on('error', function (err) {
console.log("local DynamoDB start error", err);
throw new Error("Local DynamoDB failed to start. ");
})
.on('close', function (code) {
if (code !== null && code !== 0) {
console.log('Local DynamoDB failed to start with code', code);
}
});

runningProcesses[port] = child;

console.log("DynamoDbLocal(" + child.pid + ") started on port", port, "via java", args.join(' '), "from CWD", DB_PATH);

return child;
});
}
, stop: function (port) {
if (runningProcesses[port]) {
runningProcesses[port].kill('SIGKILL');
delete runningProcesses[port];
}
}
, relaunch: function (port, db) {
this.stop(port);
this.launch(port, db);
}
};
module.exports = dynamodb;
59 changes: 59 additions & 0 deletions dynamodb/installer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use strict';

/* TODO: Replace Q with 'bluebird' promise */
var Q = require('q')
, tar = require('tar')
, zlib = require('zlib')
, path = require('path')
, http = require('http')
, fs = require('fs');

var install = function (dbPath, downloadPath, jar) {
console.log("Checking for ", dbPath);
var deferred = Q.defer();

try {
if (fs.existsSync(path.join(dbPath, jar))) {
return Q.fcall(function () {
return true;
});
}
} catch (e) {}

console.log("DynamoDb Local not installed. Installing...");

if (!fs.existsSync(dbPath))
fs.mkdirSync(dbPath);

http.get(downloadPath, function (response) {
if (302 != response.statusCode) {
deferred.reject(new Error("Error getting DynamoDb local latest tar.gz location: " + response.statusCode));
}

http.get(response.headers['location'], function (redirectResponse) {
if (200 != redirectResponse.statusCode) {
deferred.reject(new Error("Error getting DynamoDb local latest tar.gz location " + response.headers['location'] + ": " + redirectResponse.statusCode));
}
redirectResponse
.pipe(zlib.Unzip())
.pipe(tar.Extract({
path: dbPath
}))
.on('end', function () {
deferred.resolve();
})
.on('error', function (err) {
deferred.reject(err);
});
})
.on('error', function (e) {
deferred.reject(e);
});
})
.on('error', function (e) {
deferred.reject(e);
});

return deferred.promise;
}
module.exports.install = install;
181 changes: 181 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
'use strict';

/**
* Serverless Plugin Boilerplate
* - Useful example/starter code for writing a plugin for the Serverless Framework.
* - In a plugin, you can:
* - Manipulate Serverless classes
* - Create a Custom Action that can be called via the CLI or programmatically via a function handler.
* - Overwrite a Core Action that is included by default in the Serverless Framework.
* - Add a hook that fires before or after a Core Action or a Custom Action
* - All of the above at the same time :)
*
* - Setup:
* - Make a Serverless Project dedicated for plugin development, or use an existing Serverless Project
* - Make a "plugins" folder in the root of your Project and copy this codebase into it. Title it your custom plugin name with the suffix "-dev", like "myplugin-dev"
*
*/

const path = require('path'),
fs = require('fs'),
BbPromise = require('bluebird'); // Serverless uses Bluebird Promises and we recommend you do to because they provide more than your average Promise :)

module.exports = function(S) { // Always pass in the ServerlessPlugin Class

/**
* Adding/Manipulating Serverless classes
* - You can add or manipulate Serverless classes like this
*/

S.classes.Project.newStaticMethod = function() { console.log("A new method!"); };
S.classes.Project.prototype.newMethod = function() { S.classes.Project.newStaticMethod(); };

/**
* Extending the Plugin Class
* - Here is how you can add custom Actions and Hooks to Serverless.
* - This class is only required if you want to add Actions and Hooks.
*/

class PluginBoilerplate extends S.classes.Plugin {

/**
* Constructor
* - Keep this and don't touch it unless you know what you're doing.
*/

constructor() {
super();
this.name = 'myPlugin'; // Define your plugin's name
}

/**
* Register Actions
* - If you would like to register a Custom Action or overwrite a Core Serverless Action, add this function.
* - If you would like your Action to be used programatically, include a "handler" which can be called in code.
* - If you would like your Action to be used via the CLI, include a "description", "context", "action" and any options you would like to offer.
* - Your custom Action can be called programatically and via CLI, as in the example provided below
*/

registerActions() {

S.addAction(this._customAction.bind(this), {
handler: 'customAction',
description: 'A custom action from a custom plugin',
context: 'custom',
contextAction: 'run',
options: [{ // These must be specified in the CLI like this "-option true" or "-o true"
option: 'option',
shortcut: 'o',
description: 'test option 1'
}],
parameters: [ // Use paths when you multiple values need to be input (like an array). Input looks like this: "serverless custom run module1/function1 module1/function2 module1/function3. Serverless will automatically turn this into an array and attach it to evt.options within your plugin
{
parameter: 'paths',
description: 'One or multiple paths to your function',
position: '0->' // Can be: 0, 0-2, 0-> This tells Serverless which params are which. 3-> Means that number and infinite values after it.
}
]
});

return BbPromise.resolve();
}

/**
* Register Hooks
* - If you would like to register hooks (i.e., functions) that fire before or after a core Serverless Action or your Custom Action, include this function.
* - Make sure to identify the Action you want to add a hook for and put either "pre" or "post" to describe when it should happen.
*/

registerHooks() {

S.addHook(this._hookPre.bind(this), {
action: 'functionRun',
event: 'pre'
});

S.addHook(this._hookPost.bind(this), {
action: 'functionRun',
event: 'post'
});

return BbPromise.resolve();
}

/**
* Custom Action Example
* - Here is an example of a Custom Action. Include this and modify it if you would like to write your own Custom Action for the Serverless Framework.
* - Be sure to ALWAYS accept and return the "evt" object, or you will break the entire flow.
* - The "evt" object contains Action-specific data. You can add custom data to it, but if you change any data it will affect subsequent Actions and Hooks.
* - You can also access other Project-specific data @ this.S Again, if you mess with data on this object, it could break everything, so make sure you know what you're doing ;)
*/

_customAction(evt) {

let _this = this;

return new BbPromise(function (resolve, reject) {

// console.log(evt) // Contains Action Specific data
// console.log(_this.S) // Contains Project Specific data
// console.log(_this.S.state) // Contains tons of useful methods for you to use in your plugin. It's the official API for plugin developers.

console.log('-------------------');
console.log('YOU JUST RAN YOUR CUSTOM ACTION, NICE!');
console.log('-------------------');

return resolve(evt);

});
}

/**
* Your Custom PRE Hook
* - Here is an example of a Custom PRE Hook. Include this and modify it if you would like to write your a hook that fires BEFORE an Action.
* - Be sure to ALWAYS accept and return the "evt" object, or you will break the entire flow.
* - The "evt" object contains Action-specific data. You can add custom data to it, but if you change any data it will affect subsequent Actions and Hooks.
* - You can also access other Project-specific data @ this.S Again, if you mess with data on this object, it could break everything, so make sure you know what you're doing ;)
*/

_hookPre(evt) {

let _this = this;

return new BbPromise(function (resolve, reject) {

console.log('-------------------');
console.log('YOUR SERVERLESS PLUGIN\'S CUSTOM "PRE" HOOK HAS RUN BEFORE "FunctionRun"');
console.log('-------------------');

return resolve(evt);

});
}

/**
* Your Custom POST Hook
* - Here is an example of a Custom POST Hook. Include this and modify it if you would like to write your a hook that fires AFTER an Action.
* - Be sure to ALWAYS accept and return the "evt" object, or you will break the entire flow.
* - The "evt" object contains Action-specific data. You can add custom data to it, but if you change any data it will affect subsequent Actions and Hooks.
* - You can also access other Project-specific data @ this.S Again, if you mess with data on this object, it could break everything, so make sure you know what you're doing ;)
*/

_hookPost(evt) {

let _this = this;

return new BbPromise(function (resolve, reject) {

console.log('-------------------');
console.log('YOUR SERVERLESS PLUGIN\'S CUSTOM "POST" HOOK HAS RUN AFTER "FunctionRun"');
console.log('-------------------');

return resolve(evt);

});
}
}

// Export Plugin Class
return PluginBoilerplate;

};
41 changes: 41 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "serverless-dynamodb-local",
"version": "0.1.0",
"engines": {
"node": ">=4.0"
},
"description": "Serverless plugin",
"author": "serverless.com",
"license": "MIT",
"repository": {
"type": "git",
"url": "http://github.com/"
},
"keywords": [
"serverless framework plugin",
"serverless applications",
"serverless plugins",
"api gateway",
"lambda",
"aws",
"aws lambda",
"amazon",
"amazon web services",
"serverless.com"
],
"main": "index.js",
"bin": {},
"scripts": {
"test": "mocha tests/all"
},
"devDependencies": {
"chai": "^3.2.0",
"mocha": "^2.2.5"
},
"dependencies": {
"bluebird": "^3.0.6",
"q": "^1.4.1",
"mkdirp": "^0.5.0",
"tar": "^2.0.0"
}
}

0 comments on commit bca7fb8

Please sign in to comment.