Skip to content

Support functionName, functionVersion and invokedFunctionArn property on clientContext #94

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

Open
wants to merge 12 commits 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
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,32 @@ A list of one or more security groups IDs in your VPC.

If your Lambda function accesses resources in a VPC you must provide at least one security group and one subnet ID. These must belong to the same VPC

##### options.s3_bucket
Type: `String`
Default value: `undefined`

An optional S3 bucket that contains a pre uploaded package for deployment.

If this property is specified, the task will attempt to load the package from the specified S3 bucket, instead of uploading it from the file system.

The `package` property is used to determine the name of the file within the bucket.

##### options.s3_path
Type: `String`
Default value: `undefined`

An optional S3 path that points to the "directory" within S3 that contains the package. If omitted, the task assumes that the package has been deployed at the root of the S3 bucket.

The `package` property is used to determine the name of the file within the bucket.

##### options.s3_version
Type: `String`
Default value: `undefined`

An optional S3 version id string that can be used to specifiy a specific version of the package file on s3. If omitted, the latest version of the package will be used.

The `package` property is used to determine the name of the file within the bucket.

#### Usage Examples

##### Default Options
Expand Down Expand Up @@ -643,4 +669,4 @@ Adding more warnings for various failure cases

* Added support for Node 4.3 runtime callback function - [pull request by bobhigs](https://github.com/Tim-B/grunt-aws-lambda/pull/76)
* Added VPC support - [pull request by beeva-arturomartinez](https://github.com/Tim-B/grunt-aws-lambda/pull/71)
* Added local proxy support - [pull request by alekstr](https://github.com/Tim-B/grunt-aws-lambda/pull/66)
* Added local proxy support - [pull request by alekstr](https://github.com/Tim-B/grunt-aws-lambda/pull/66)
3 changes: 2 additions & 1 deletion test/unit/date_facade_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ dateFacadeTest.testGetFormattedTimestamp = function(test) {

dateFacadeTest.testGetHumanReadableTimestamp = function(test) {
var fixedDate = new Date(2016, 2, 13, 14, 38, 13);
test.ok(dateFacade.getHumanReadableTimestamp(fixedDate).indexOf('Sun Mar 13 2016 14:38:13') > -1);
var expectedValue = fixedDate.toLocaleString();
test.ok(dateFacade.getHumanReadableTimestamp(fixedDate)===expectedValue);
test.done();
};
module.exports = dateFacadeTest;
134 changes: 134 additions & 0 deletions test/unit/deploy_task_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,140 @@ deployTaskTest.testDeployWithoutProxy = function(test) {
gruntMock.execute(deployTask.getHandler, harnessParams);
};

deployTaskTest.testDeployS3 = function(test) {
test.expect(9);

var deployTask = require('../../utils/deploy_task');
var expectedPackage = 'my-package.zip';
var expectedS3Bucket = 'my-s3-bucket';
var expectedS3Path = 'my-s3-path';
var expectedS3Key = expectedS3Path + '/' + expectedPackage;
var progressMessage = [
'Using code deployed to S3 at [',
expectedS3Bucket, '/', expectedS3Key,
'] (version: LATEST)'
].join('');

var harnessParams = {
options: { },
config: {
'lambda_deploy.fake-target.function': 'some-function',
'lambda_deploy.fake-target.package': expectedPackage,
'lambda_deploy.fake-target.s3_bucket': expectedS3Bucket,
'lambda_deploy.fake-target.s3_path': expectedS3Path
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 3);
test.equal(harness.output[0], progressMessage);
test.equal(harness.output[1], 'Package deployed.');
test.equal(harness.output[2], 'No config updates to make.');

test.ok(awsSDKMock.config.update.calledWith({region: 'us-east-1'}));
test.ok(lambdaAPIMock.getFunction.calledWith({FunctionName: 'some-function'}));
test.ok(lambdaAPIMock.updateFunctionCode.calledWith({
FunctionName: 'some-function',
S3Bucket: expectedS3Bucket,
S3Key: expectedS3Key
}));
test.ok(!lambdaAPIMock.updateFunctionConfiguration.called);
test.done();
}
};
gruntMock.execute(deployTask.getHandler, harnessParams);
};

deployTaskTest.testDeployS3WithoutPath = function(test) {
test.expect(9);

var deployTask = require('../../utils/deploy_task');
var expectedPackage = 'my-package.zip';
var expectedS3Bucket = 'my-s3-bucket';
var expectedS3Path = '';
var expectedS3Key = expectedPackage;
var progressMessage = [
'Using code deployed to S3 at [',
expectedS3Bucket, '/', expectedPackage,
'] (version: LATEST)'
].join('');

var harnessParams = {
options: { },
config: {
'lambda_deploy.fake-target.function': 'some-function',
'lambda_deploy.fake-target.package': expectedPackage,
'lambda_deploy.fake-target.s3_bucket': expectedS3Bucket,
'lambda_deploy.fake-target.s3_path': expectedS3Path
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 3);
test.equal(harness.output[0], progressMessage);
test.equal(harness.output[1], 'Package deployed.');
test.equal(harness.output[2], 'No config updates to make.');

test.ok(awsSDKMock.config.update.calledWith({region: 'us-east-1'}));
test.ok(lambdaAPIMock.getFunction.calledWith({FunctionName: 'some-function'}));
test.ok(lambdaAPIMock.updateFunctionCode.calledWith({
FunctionName: 'some-function',
S3Bucket: expectedS3Bucket,
S3Key: expectedS3Key
}));
test.ok(!lambdaAPIMock.updateFunctionConfiguration.called);
test.done();
}
};
gruntMock.execute(deployTask.getHandler, harnessParams);
};

deployTaskTest.testDeployS3WithVersion = function(test) {
test.expect(9);

var deployTask = require('../../utils/deploy_task');
var expectedPackage = 'my-package.zip';
var expectedS3Bucket = 'my-s3-bucket';
var expectedS3Path = 'my-s3-path';
var expectedS3Version = 'my-version';
var expectedS3Key = expectedS3Path + '/' + expectedPackage;
var progressMessage = [
'Using code deployed to S3 at [',
expectedS3Bucket, '/', expectedS3Key,
'] (version: ',
expectedS3Version,
')'
].join('');

var harnessParams = {
options: { },
config: {
'lambda_deploy.fake-target.function': 'some-function',
'lambda_deploy.fake-target.package': expectedPackage,
'lambda_deploy.fake-target.s3_bucket': expectedS3Bucket,
'lambda_deploy.fake-target.s3_path': expectedS3Path,
'lambda_deploy.fake-target.s3_version': expectedS3Version
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 3);
test.equal(harness.output[0], progressMessage);
test.equal(harness.output[1], 'Package deployed.');
test.equal(harness.output[2], 'No config updates to make.');

test.ok(awsSDKMock.config.update.calledWith({region: 'us-east-1'}));
test.ok(lambdaAPIMock.getFunction.calledWith({FunctionName: 'some-function'}));
test.ok(lambdaAPIMock.updateFunctionCode.calledWith({
FunctionName: 'some-function',
S3Bucket: expectedS3Bucket,
S3Key: expectedS3Key,
S3ObjectVersion: expectedS3Version
}));
test.ok(!lambdaAPIMock.updateFunctionConfiguration.called);
test.done();
}
};
gruntMock.execute(deployTask.getHandler, harnessParams);
};

deployTaskTest.testProfile = function(test) {
test.expect(3);

Expand Down
77 changes: 76 additions & 1 deletion test/unit/invoke_task_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,81 @@ invokeTaskTests.testNoClientContext = function(test) {
gruntMock.execute(invokeTask.getHandler, harnessParams);
};

invokeTaskTests.testNoFunctionName = function(test) {
test.expect(5);

setLambdaFunction(function(event, context) {
var defaultFunctionName = '_function_name_';
test.equal(context.functionName, defaultFunctionName);
context.done(null, 'My Message');
});

var invokeTask = require('../../utils/invoke_task');

var harnessParams = {
options: {
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 5);
test.equal(harness.output[2], 'Success! Message:');
test.equal(harness.output[4], 'My Message');
test.done();
}
};
gruntMock.execute(invokeTask.getHandler, harnessParams);
};

invokeTaskTests.testNoFunctionVersion = function(test) {
test.expect(5);

setLambdaFunction(function(event, context) {
var defaultFunctionVersion = 1;
test.equal(context.functionVersion, defaultFunctionVersion);
context.done(null, 'My Message');
});

var invokeTask = require('../../utils/invoke_task');

var harnessParams = {
options: {
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 5);
test.equal(harness.output[2], 'Success! Message:');
test.equal(harness.output[4], 'My Message');
test.done();
}
};
gruntMock.execute(invokeTask.getHandler, harnessParams);
};

invokeTaskTests.testNoInvokedFunctionArn = function(test) {
test.expect(5);

setLambdaFunction(function(event, context) {
var defaultArn = 'arn:aws:lambda:_aws_region_:_aws_account_id_:function:_lambda_function_name_';
test.equal(context.invokedFunctionArn, defaultArn);
context.done(null, 'My Message');
});

var invokeTask = require('../../utils/invoke_task');

var harnessParams = {
options: {
},
callback: function(harness) {
test.equal(harness.status, true);
test.equal(harness.output.length, 5);
test.equal(harness.output[2], 'Success! Message:');
test.equal(harness.output[4], 'My Message');
test.done();
}
};
gruntMock.execute(invokeTask.getHandler, harnessParams);
};

invokeTaskTests.testNoIdentity = function(test) {
test.expect(5);

Expand Down Expand Up @@ -537,4 +612,4 @@ invokeTaskTests.testCallbackError = function(test) {
};


module.exports = invokeTaskTests;
module.exports = invokeTaskTests;
73 changes: 54 additions & 19 deletions utils/deploy_task.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ deployTask.getHandler = function (grunt) {
var deploy_function = grunt.config.get('lambda_deploy.' + this.target + '.function');
var deploy_arn = grunt.config.get('lambda_deploy.' + this.target + '.arn');
var deploy_package = grunt.config.get('lambda_deploy.' + this.target + '.package');
var s3_bucket = grunt.config.get('lambda_deploy.' + this.target + '.s3_bucket');
var s3_path = grunt.config.get('lambda_deploy.' + this.target + '.s3_path');
var s3_version = grunt.config.get('lambda_deploy.' + this.target + '.s3_version');
var package_version = grunt.config.get('lambda_deploy.' + this.target + '.version');
var package_name = grunt.config.get('lambda_deploy.' + this.target + '.package_name');
var archive_name = grunt.config.get('lambda_deploy.' + this.target + '.archive_name');
Expand Down Expand Up @@ -248,36 +251,68 @@ deployTask.getHandler = function (grunt) {
}
};

grunt.log.writeln('Uploading...');
fs.readFile(deploy_package, function (err, data) {
if (err) {
grunt.fail.warn('Could not read package file (' + deploy_package + '), verify the lambda package ' +
'location is correct, and that you have already created the package using lambda_package.');
}
var updateLambdaConfig = function(functionName, configParams) {
updateConfig(functionName, configParams)
.then(function () {return createVersion(functionName);})
.then(function () {return setAliases(functionName);})
.then(function () {return setPackageVersionAlias(functionName);})
.then(function () {
done(true);
}).catch(function (err) {
grunt.fail.warn('Uncaught exception: ' + err.message);
});
};

if(!s3_bucket) {
grunt.log.writeln('Uploading...');
fs.readFile(deploy_package, function (err, data) {
if (err) {
grunt.fail.warn('Could not read package file (' + deploy_package + '), verify the lambda package ' +
'location is correct, and that you have already created the package using lambda_package.');
}

var codeParams = {
FunctionName: deploy_function,
ZipFile: data
};

lambda.updateFunctionCode(codeParams, function (err, data) {
if (err) {
grunt.fail.warn('Package upload failed, check you have lambda:UpdateFunctionCode permissions and that your package is not too big to upload.');
}

grunt.log.writeln('Package deployed.');
updateLambdaConfig(deploy_function, configParams);
});
});
} else {
var s3_key = !s3_path? deploy_package:s3_path + '/' + deploy_package;
grunt.log.writeln([
'Using code deployed to S3 at [',
s3_bucket, '/', s3_key,
'] (version: ',
s3_version || 'LATEST',
')' ].join(''));

var codeParams = {
FunctionName: deploy_function,
ZipFile: data
S3Bucket: s3_bucket,
S3Key: s3_key
};

if(s3_version) {
codeParams.S3ObjectVersion = s3_version;
}

lambda.updateFunctionCode(codeParams, function (err, data) {
if (err) {
grunt.fail.warn('Package upload failed, check you have lambda:UpdateFunctionCode permissions and that your package is not too big to upload.');
grunt.fail.warn('Package deployment failed, check you have lambda:UpdateFunctionCode permissions and that your package is not too big to upload.');
}

grunt.log.writeln('Package deployed.');

updateConfig(deploy_function, configParams)
.then(function () {return createVersion(deploy_function);})
.then(function () {return setAliases(deploy_function);})
.then(function () {return setPackageVersionAlias(deploy_function);})
.then(function () {
done(true);
}).catch(function (err) {
grunt.fail.warn('Uncaught exception: ' + err.message);
});
updateLambdaConfig(deploy_function, configParams);
});
});
}
});
};
};
Expand Down
Loading