Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgraded to ES6. Added AirBnb EsLint file. Added support for Flow. #26

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/node_modules/*
node_modules
test/node_modules
218 changes: 119 additions & 99 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,163 +1,183 @@
var fs = require('fs');
var AWS = require('aws-sdk');
var extend = require('util')._extend;
var async = require('async');
// @flow

import { stat } from 'fs';
import { AWS } from 'aws-sdk';
import { extend } from 'util-extend';
import { async } from 'async';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { loggerpro } from 'loggerpro';

exports.deploy = (codePackage: string, config: any, callback: any, logger: any, lambda: any) => {
let loggerImpl;
let lambdaNew = lambda;

exports.deploy = function(codePackage, config, callback, logger, lambda) {
if (!logger) {
logger = console.log;
loggerImpl = loggerpro;
}

if(!lambda) {
if("profile" in config) {
var credentials = new AWS.SharedIniFileCredentials({profile: config.profile});
if (!lambdaNew) {
if ('profile' in config) {
const credentials = new AWS.SharedIniFileCredentials({ profile: config.profile });
AWS.config.credentials = credentials;
}

if (process.env.HTTPS_PROXY) {
if (!AWS.config.httpOptions) {
AWS.config.httpOptions = {};
}
var HttpsProxyAgent = require('https-proxy-agent');
AWS.config.httpOptions.agent = new HttpsProxyAgent(process.env.HTTPS_PROXY);
}

lambda = new AWS.Lambda({
lambdaNew = new AWS.Lambda({
region: config.region,
accessKeyId: "accessKeyId" in config ? config.accessKeyId : "",
secretAccessKey: "secretAccessKey" in config ? config.secretAccessKey : "",
sessionToken: "sessionToken" in config ? config.sessionToken : ""
accessKeyId: 'accessKeyId' in config ? config.accessKeyId : '',
secretAccessKey: 'secretAccessKey' in config ? config.secretAccessKey : '',
sessionToken: 'sessionToken' in config ? config.sessionToken : '',
});
}

var params = {
const params = {
FunctionName: config.functionName,
Description: config.description,
Handler: config.handler,
Role: config.role,
Timeout: config.timeout,
MemorySize: config.memorySize
MemorySize: config.memorySize,
VpcConfig: null,
BatchSize: null,
Code: {},
Runtime: '',
Publish: false,
};
if (config.vpc) params.VpcConfig = config.vpc;
var isPublish = (config.publish === true);

var updateEventSource = function(eventSource, callback) {
var params = extend({
FunctionName: config.functionName
if (config.vpc) {
params.VpcConfig = config.vpc;
}

const isPublish = (config.publish === true);

const updateEventSource = (eventSource, updateEventSourceCallback) => {
const eventSourceParams = extend({
FunctionName: config.functionName,
}, eventSource);

lambda.listEventSourceMappings({
FunctionName: params.FunctionName,
EventSourceArn: params.EventSourceArn
}, function(err, data) {
if(err) {
logger("List event source mapping failed, please make sure you have permission");
callback(err);
lambdaNew.listEventSourceMappings({
FunctionName: eventSourceParams.FunctionName,
EventSourceArn: eventSourceParams.EventSourceArn,
}, (err, data) => {
if (err) {
loggerImpl('List event source mapping failed, please make sure you have permission');
updateEventSourceCallback(err);
}

if (data.EventSourceMappings.length === 0) {
lambdaNew.createEventSourceMapping(eventSourceParams,
(eventSourceError) => {
if (eventSourceError) {
loggerImpl('Failed to create event source mapping!');
updateEventSourceCallback(eventSourceError);
} else {
updateEventSourceCallback();
}
});
} else {
if (data.EventSourceMappings.length === 0) {
lambda.createEventSourceMapping(params, function(err, data) {
if(err) {
logger("Failed to create event source mapping!");
callback(err);
} else {
callback();
}
});
} else {
async.eachSeries(data.EventSourceMappings, function(mapping, iteratorCallback) {
lambda.updateEventSourceMapping({
UUID: mapping.UUID,
BatchSize: params.BatchSize
}, iteratorCallback);
}, function(err) {
if(err) {
logger("Update event source mapping failed");
callback(err);
} else {
callback();
}
});
}
async.eachSeries(data.EventSourceMappings, (mapping, iteratorCallback) => {
lambdaNew.updateEventSourceMapping({
UUID: mapping.UUID,
BatchSize: params.BatchSize,
}, iteratorCallback);
}, (eventSourceMappingsError) => {
if (eventSourceMappingsError) {
loggerImpl('Update event source mapping failed');
updateEventSourceCallback(eventSourceMappingsError);
} else {
updateEventSourceCallback();
}
});
}
});
};

var updateEventSources = function(callback) {
var eventSources;

if(!config.eventSource) {
callback();
const updateEventSources = (updateEventSourcesCallback) => {
if (!config.eventSource) {
updateEventSourcesCallback();
return;
}

eventSources = Array.isArray(config.eventSource) ? config.eventSource : [ config.eventSource ];

const eventSources = Array.isArray(config.eventSource)
? config.eventSource : [config.eventSource];
async.eachSeries(
eventSources,
updateEventSource,
function(err) {
callback(err);
}
(err) => {
callback(err);
},
);
};

var updateFunction = function(callback) {
fs.readFile(codePackage, function(err, data) {
if(err) {
return callback('Error reading specified package "'+ codePackage + '"');
const updateFunction = (updateFunctionCallback) => {
stat.readFile(codePackage, (err, data) => {
if (err) {
const returnMessage = `Error reading specified package, ${codePackage}`;
return callback(returnMessage);
}

lambda.updateFunctionCode({FunctionName: params.FunctionName, ZipFile: data, Publish: isPublish}, function(err, data) {
if (err) {
var warning = 'Package upload failed. '
warning += 'Check your iam:PassRole permissions.'
logger(warning);
callback(err)
} else {
lambda.updateFunctionConfiguration(params, function(err, data) {
if (err) {
var warning = 'Update function configuration failed. '
logger(warning);
callback(err);
} else {
updateEventSources(callback);
}
});
}
});
lambdaNew.updateFunctionCode({
FunctionName: params.FunctionName, ZipFile: data, Publish: isPublish },
(updateFunctionCodeError) => {
if (updateFunctionCodeError) {
let warning = 'Package upload failed. ';
warning += 'Check your iam:PassRole permissions.';
logger(warning);
updateFunctionCallback(updateFunctionCodeError);
} else {
lambdaNew.updateFunctionConfiguration(params, (updateFunctionConfigurationError) => {
if (updateFunctionConfigurationError) {
const warning = 'Update function configuration failed. ';
logger(warning);
updateFunctionCallback(updateFunctionConfigurationError);
} else {
updateEventSources(updateFunctionCallback);
}
});
}
});

return true;
});
};

var createFunction = function(callback) {
fs.readFile(codePackage, function(err, data) {
if(err) {
return callback('Error reading specified package "'+ codePackage + '"');
const createFunction = (createFunctionCallback) => {
stat.readFile(codePackage, (createFunctionError, createFunctionData) => {
if (createFunctionError) {
return callback(`Error reading specified package ${codePackage}`);
}

params['Code'] = { ZipFile: data };
params['Runtime'] = "runtime" in config ? config.runtime : "nodejs4.3";
params['Publish'] = isPublish;
lambda.createFunction(params, function(err, data) {
params.Code = { ZipFile: createFunctionData };
params.Runtime = 'runtime' in config ? config.runtime : 'nodejs4.3';
params.Publish = isPublish;
lambdaNew.createFunction(params, (err) => {
if (err) {
var warning = 'Create function failed. '
warning += 'Check your iam:PassRole permissions.'
let warning = 'Create function failed. ';
warning += 'Check your iam:PassRole permissions.';
logger(warning);
callback(err)
createFunctionCallback(err);
} else {
updateEventSources(callback);
}
});

return true;
});
};


lambda.getFunction({FunctionName: params.FunctionName}, function(err, data) {
lambdaNew.getFunction({ FunctionName: params.FunctionName }, (err) => {
if (err) {
if (err.statusCode === 404) {
createFunction(callback);
} else {
var warning = 'AWS API request failed. '
warning += 'Check your AWS credentials and permissions.'
let warning = 'AWS API request failed. ';
warning += 'Check your AWS credentials and permissions.';
logger(warning);
callback(err);
}
Expand Down
19 changes: 15 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"name": "node-aws-lambda",
"version": "0.1.8",
"version": "0.1.9",
"description": "A module help you automate AWS lambda function deployment.",
"scripts": {
"test": "./node_modules/mocha/bin/mocha test/all.js"
"test": "./node_modules/mocha/bin/mocha test/all.js",
"lint": "./node_modules/.bin/eslint **.js",
"flow": "flow; test $? -eq 0 -o $? -eq 2"
},
"repository": {
"type": "git",
Expand All @@ -22,11 +24,20 @@
"dependencies": {
"async": "^1.0.0",
"aws-sdk": "2.x.x",
"https-proxy-agent": "^1.0.0"
"babel-eslint": "^7.1.1",
"eslint-plugin-flowtype": "^2.25.0",
"fs": "0.0.1-security",
"https-proxy-agent": "^1.0.0",
"loggerpro": "^1.0.2",
"util-extend": "^1.0.3"
},
"devDependencies": {
"mocha": "^2.2.1",
"chai": "^2.1.1",
"eslint": "^3.10.2",
"eslint-config-airbnb-base": "^10.0.1",
"eslint-plugin-import": "^2.2.0",
"flow-bin": "^0.35.0",
"mocha": "^2.2.1",
"node-uuid": "^1.4.3"
}
}
40 changes: 40 additions & 0 deletions test/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
0.1.9
=====
* Converted to ES6 (by @blairg)
* Added AirBnb EsLint configuration (by @blairg)
* Support for Flow (by @blairg)

0.1.8
=====
* Support VPC (by @tilfin)
* Support authentication with sessionToken (by @JohnBloom)
* Support Publish flag (by @hiro-koba)

0.1.7
=====
* Support python and other runtime (by @kikusu)
* Support specifying multiple event sources (by @driadi)

0.1.6
=====
* Support specifying descriptions (by @dlhdesign)

0.1.5
=====
* HTTPS proxy support (by @dvonlehman)

0.1.4
=====
* Add "profile" option to enable load AWS credentials from custom profile (by @bryannaegele)

0.1.3
=====
* Add optional accessKeyId and secretAccessKey (by @ikait)

0.1.2
=====
* Add support for memorySize option (by @ikait)

0.1.1
=====
* Skip event source mapping if not specified.
Loading