diff --git a/lib/actions/EndpointDeploy.js b/lib/actions/EndpointDeploy.js index cc712eafb..1009dba84 100644 --- a/lib/actions/EndpointDeploy.js +++ b/lib/actions/EndpointDeploy.js @@ -19,13 +19,13 @@ module.exports = function(SPlugin, serverlessPath) { - const path = require('path'), + const path = require('path'), SError = require(path.join(serverlessPath, 'Error')), SCli = require(path.join(serverlessPath, 'utils/cli')), BbPromise = require('bluebird'), - async = require('async'), fs = require('fs'), os = require('os'); + let SUtils; // Promisify fs module @@ -79,7 +79,7 @@ module.exports = function(SPlugin, serverlessPath) { parameters: [ { parameter: 'names', - description: 'The names/ids of the endpoints you want to deploy in this format: user/create#GET', + description: 'The names/ids of the endpoints you want to deploy in this format: user/create~GET', position: '0->' } ] @@ -160,8 +160,7 @@ module.exports = function(SPlugin, serverlessPath) { _validateAndPrepare() { - let _this = this; - + let _this = this; _this.project = _this.S.getProject(); _this.aws = _this.S.getProvider(); _this.endpoints = []; @@ -171,7 +170,7 @@ module.exports = function(SPlugin, serverlessPath) { // Prepare endpoints if (_this.evt.options.names.length) { - _this.evt.options.names = _this.project.getEndpointsByName(_this.evt.options.names); + _this.endpoints = _this.project.getEndpointsByName(_this.evt.options.names); } // If CLI and no endpoint names targeted, deploy from CWD @@ -227,7 +226,5 @@ module.exports = function(SPlugin, serverlessPath) { } } - - return( EndpointDeploy ); }; \ No newline at end of file diff --git a/lib/actions/EndpointDeployApiGateway.js b/lib/actions/EndpointDeployApiGateway.js index befff0f20..d33bbc877 100644 --- a/lib/actions/EndpointDeployApiGateway.js +++ b/lib/actions/EndpointDeployApiGateway.js @@ -14,11 +14,12 @@ */ module.exports = function(SPlugin, serverlessPath) { - const path = require('path'), - SError = require(path.join(serverlessPath, 'Error')), - SCli = require('../utils/cli'), - BbPromise = require('bluebird'), - fs = require('fs'); + const path = require('path'), + SError = require(path.join(serverlessPath, 'Error')), + SCli = require('../utils/cli'), + BbPromise = require('bluebird'), + async = require('async'), + fs = require('fs'); let SUtils; // Promisify fs module @@ -59,19 +60,19 @@ module.exports = function(SPlugin, serverlessPath) { _this.endpoints = _this.project.getEndpointsByName(_this.evt.options.names); return _this._validateAndPrepare() - .bind(_this) - .then(_this._processDeployment) - .then(_this._createDeployment) - .then(function() { + .bind(_this) + .then(_this._processDeployment) + .then(_this._createDeployment) + .then(function() { - /** - * Return EVT - */ + /** + * Return EVT + */ - _this.evt.data.deploymentId = _this.deployment.id; - return _this.evt; + _this.evt.data.deploymentId = _this.deployment.id; + return _this.evt; - }); + }); } /** @@ -96,19 +97,19 @@ module.exports = function(SPlugin, serverlessPath) { _this.spinner.start(); return BbPromise.try(function() { - return _this.regions; - }) - .bind(_this) - .each(function(region) { + return _this.regions; + }) + .bind(_this) + .each(function(region) { - // Process each Region - return _this._processRegionDeployment(region); - }) - .then(function() { + // Process each Region + return _this._processRegionDeployment(region); + }) + .then(function() { - // Stop Spinner - _this.spinner.stop(true); - }); + // Stop Spinner + _this.spinner.stop(true); + }); } /** @@ -128,95 +129,96 @@ module.exports = function(SPlugin, serverlessPath) { } return _this._findOrCreateRestApi( - restApi, - _this.evt.options.stage, - region) - .then(function(restApiData) { + restApi, + _this.evt.options.stage, + region) + .then(function(restApiData) { - _this.restApiData = restApiData; + _this.restApiData = restApiData; - let regionInstance = _this.project.getRegion(_this.evt.options.stage, region); - regionInstance.addVariables({ - apiGatewayApi: restApiData.name - }); + let regionInstance = _this.project.getRegion(_this.evt.options.stage, region); + regionInstance.addVariables({ + apiGatewayApi: restApiData.name + }); - return regionInstance.save(); - }) - .then(_this._createAuthorizers) - .then(function() { - return new BbPromise(function (resolve, reject) { + return regionInstance.save(); + }) + .bind(_this) + .then(_this._createAuthorizers) + .then(function() { + return new BbPromise(function (resolve, reject) { - // A function can have multiple endpoints. Process all endpoints for this Function - async.eachSeries(_this.endpoints, function (endpoint, eCb) { + // A function can have multiple endpoints. Process all endpoints for this Function + async.eachSeries(_this.endpoints, function (endpoint, eCb) { - return BbPromise.try(function () { + return BbPromise.try(function () { - // Find authorizerId, if specified - let authorizerId; - if (endpoint.authorizerFunction) { - if (_this.authorizers[endpoint.authorizerFunction]) { - authorizerId = _this.authorizers[endpoint.authorizerFunction]; - } else { - throw new SError(`Endpoint ${endpoint.getName()} has an 'authorizerFunction' specified that does not exist in this project.`); - } + // Find authorizerId, if specified + let authorizerId; + if (endpoint.authorizerFunction) { + if (_this.authorizers[endpoint.authorizerFunction]) { + authorizerId = _this.authorizers[endpoint.authorizerFunction]; + } else { + throw new SError(`Endpoint ${endpoint.getName()} has an 'authorizerFunction' specified that does not exist in this project.`); } - if (endpoint.authorizerId) { - authorizerId = endpoint.authorizerId; + } + if (endpoint.authorizerId) { + authorizerId = endpoint.authorizerId; + } + + // Create new event object + let newEvt = { + options: { + stage: _this.evt.options.stage, + region: region, + name: endpoint.getName(), + authorizerId: authorizerId ? authorizerId : null, + aliasEndpoint: _this.evt.options.aliasEndpoint } + }; - // Create new event object - let newEvt = { - options: { - stage: _this.evt.options.stage, - region: region, - name: endpoint.getName(), - authorizerId: authorizerId ? authorizerId : null, - aliasEndpoint: _this.evt.options.aliasEndpoint - } - }; + return _this.S.actions.endpointBuildApiGateway(newEvt); + }) + .then(function (result) { - return _this.S.actions.endpointBuildApiGateway(newEvt); - }) - .then(function (result) { - - // Stash deployed endpoints - if (!_this.deployed) _this.deployed = {}; - if (!_this.deployed[region]) _this.deployed[region] = []; - _this.deployed[region].push({ - endpointPath: endpoint.path, - endpointMethod: endpoint.method, - endpointUrl: result.data.url - }); - - }) - .catch(function (e) { - - // Stash Failed Endpoint - if (!_this.failed) _this.failed = {}; - if (!_this.failed[region]) _this.failed[region] = []; - _this.failed[region].push({ - endpointPath: endpoint ? endpoint.path : 'unknown', - endpointMethod: endpoint ? endpoint.method : 'unknown', - message: e.message, - stack: e.stack - }); - }) - .then(function() { - - // If no endpoints were successfully deployed, skip - if (!_this.deployed) return eCb(); - - // Deploy API Gateway Deployment in region - return _this._createDeployment() - .then(function() { - return eCb(); - }); + // Stash deployed endpoints + if (!_this.deployed) _this.deployed = {}; + if (!_this.deployed[region]) _this.deployed[region] = []; + _this.deployed[region].push({ + endpointPath: endpoint.path, + endpointMethod: endpoint.method, + endpointUrl: result.data.url }); - }, function () { - return resolve(); - }); - }) - }); + + }) + .catch(function (e) { + + // Stash Failed Endpoint + if (!_this.failed) _this.failed = {}; + if (!_this.failed[region]) _this.failed[region] = []; + _this.failed[region].push({ + endpointPath: endpoint ? endpoint.path : 'unknown', + endpointMethod: endpoint ? endpoint.method : 'unknown', + message: e.message, + stack: e.stack + }); + }) + .then(function() { + + // If no endpoints were successfully deployed, skip + if (!_this.deployed) return eCb(); + + // Deploy API Gateway Deployment in region + return _this._createDeployment() + .then(function() { + return eCb(); + }); + }); + }, function () { + return resolve(); + }); + }) + }); } /** @@ -227,31 +229,31 @@ module.exports = function(SPlugin, serverlessPath) { let _this = this; return _this.provider.getApiByName(restApiName, stage, region) - .then(function(restApi) { + .then(function(restApi) { - // Return, if found - if (restApi) return restApi; + // Return, if found + if (restApi) return restApi; - // Otherwise, create new REST API - let params = { - name: restApiName, /* required */ - description: 'A REST API for a Serverless project in region: ' + region - }; + // Otherwise, create new REST API + let params = { + name: restApiName, /* required */ + description: 'A REST API for a Serverless project in region: ' + region + }; - return _this.provider.request('APIGateway', 'createRestApi', params, stage, region) - .then(function (response) { + return _this.provider.request('APIGateway', 'createRestApi', params, stage, region) + .then(function (response) { - SUtils.sDebug( - '"' - + stage - + ' - ' - + region - + '": created a new REST API on AWS API Gateway with name: ' - + response.name); + SUtils.sDebug( + '"' + + stage + + ' - ' + + region + + '": created a new REST API on AWS API Gateway with name: ' + + response.name); - return response; - }); - }); + return response; + }); + }); } /** @@ -266,77 +268,77 @@ module.exports = function(SPlugin, serverlessPath) { return BbPromise.try(function() { - // Delete pre-existing on authorizers deployed on API Gateway - let params = { - restApiId: _this.evt.options.restApiId, - limit: 100 - }; + // Delete pre-existing on authorizers deployed on API Gateway + let params = { + restApiId: _this.restApiData.id, + limit: 100 + }; - return _this.provider.request('APIGateway', 'getAuthorizers', params, _this.evt.options.stage, _this.evt.options.region) - .then(function(a) { - return a.items; - }); - }) - .each(function(a) { + return _this.provider.request('APIGateway', 'getAuthorizers', params, _this.evt.options.stage, _this.evt.options.region) + .then(function(a) { + return a.items; + }); + }) + .each(function(a) { - // Otherwise, delete pre-existing on authorizers deployed on API Gateway - let params = { - restApiId: _this.evt.options.restApiId, - authorizerId: a.id - }; + // Otherwise, delete pre-existing on authorizers deployed on API Gateway + let params = { + restApiId: _this.restApiData.id, + authorizerId: a.id + }; - return _this.provider.request('APIGateway', 'deleteAuthorizer', params, _this.evt.options.stage, _this.evt.options.region); - }) - .then(function() { - return functions; - }) - .each(function(fn) { + return _this.provider.request('APIGateway', 'deleteAuthorizer', params, _this.evt.options.stage, _this.evt.options.region); + }) + .then(function() { + return functions; + }) + .each(function(fn) { - // If no authorizer data, skip - if (!fn.authorizer || !Object.keys(fn.authorizer).length) return; + // If no authorizer data, skip + if (!fn.authorizer || !Object.keys(fn.authorizer).length) return; - let f = fn.toObjectPopulated({ stage: _this.evt.options.stage, region: _this.evt.options.region }); + let f = fn.toObjectPopulated({ stage: _this.evt.options.stage, region: _this.evt.options.region }); - // Create new authorizer on API Gateway + // Create new authorizer on API Gateway - // Fetch Lambda - let params = { - FunctionName: fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }), - Qualifier: _this.evt.options.stage - }; + // Fetch Lambda + let params = { + FunctionName: fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }), + Qualifier: _this.evt.options.stage + }; - return _this.provider.request('Lambda', 'getFunction', params, _this.evt.options.stage, _this.evt.options.region) - .then(function(l) { - // Validate required authorizer params - if (!f.authorizer.identitySource) throw new SError(`Authorizer is missing identitySource property in function ${f.name}`); + return _this.provider.request('Lambda', 'getFunction', params, _this.evt.options.stage, _this.evt.options.region) + .then(function(l) { + // Validate required authorizer params + if (!f.authorizer.identitySource) throw new SError(`Authorizer is missing identitySource property in function ${f.name}`); - // Create Authorizer params. Set defaults. - let authorizer = f.authorizer; - authorizer.restApiId = _this.evt.options.restApiId; - authorizer.name = authorizer.name || fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }); - authorizer.type = authorizer.type || 'TOKEN'; + // Create Authorizer params. Set defaults. + let authorizer = f.authorizer; + authorizer.restApiId = _this.restApiData.id; + authorizer.name = authorizer.name || fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }); + authorizer.type = authorizer.type || 'TOKEN'; - let alias = '${stageVariables.functionAlias}'; + let alias = '${stageVariables.functionAlias}'; - // Construct authorizer URI - authorizer.authorizerUri = 'arn:aws:apigateway:' - + _this.evt.options.region - + ':lambda:path/2015-03-31/functions/arn:aws:lambda:' - + _this.evt.options.region - + ':' - + _this.awsAccountNumber - + ':function:' - + fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }) - + ':' - + alias - + '/invocations'; + // Construct authorizer URI + authorizer.authorizerUri = 'arn:aws:apigateway:' + + _this.evt.options.region + + ':lambda:path/2015-03-31/functions/arn:aws:lambda:' + + _this.evt.options.region + + ':' + + _this.awsAccountNumber + + ':function:' + + fn.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }) + + ':' + + alias + + '/invocations'; - return _this.provider.request('APIGateway', 'createAuthorizer', authorizer, _this.evt.options.stage, _this.evt.options.region) - .then(function(a) { - _this.authorizers[fn.name] = a.id; - }); - }); - }); + return _this.provider.request('APIGateway', 'createAuthorizer', authorizer, _this.evt.options.stage, _this.evt.options.region) + .then(function(a) { + _this.authorizers[fn.name] = a.id; + }); + }); + }); } /** @@ -352,7 +354,7 @@ module.exports = function(SPlugin, serverlessPath) { let doDeploy = function() { let params = { - restApiId: _this.evt.options.restApiId, /* required */ + restApiId: _this.restApiData.id, /* required */ stageName: _this.evt.options.stage, /* required */ //cacheClusterEnabled: false, TODO: Implement //cacheClusterSize: '0.5 | 1.6 | 6.1 | 13.5 | 28.4 | 58.2 | 118 | 237', TODO: Implement @@ -364,28 +366,28 @@ module.exports = function(SPlugin, serverlessPath) { }; _this.provider.request('APIGateway', 'createDeployment', params, _this.evt.options.stage, _this.evt.options.region) - .then(function(response) { + .then(function(response) { - _this.deployment = response; + _this.deployment = response; - SUtils.sDebug( - '"' - + _this.evt.options.stage - + ' - ' - + _this.evt.options.region - + ' - REST API: ' - + 'created API Gateway deployment: ' - + response.id); + SUtils.sDebug( + '"' + + _this.evt.options.stage + + ' - ' + + _this.evt.options.region + + ' - REST API: ' + + 'created API Gateway deployment: ' + + response.id); - return resolve(); - }) - .catch(function(error) { - if( error.statusCode == 429 ) { - SUtils.sDebug("'Too many requests' received, sleeping 5 seconds"); - setTimeout( doDeploy, 5000 ); - } else - reject( new SError(error.message) ); - }); + return resolve(); + }) + .catch(function(error) { + if( error.statusCode == 429 ) { + SUtils.sDebug("'Too many requests' received, sleeping 5 seconds"); + setTimeout( doDeploy, 5000 ); + } else + reject( new SError(error.message) ); + }); }; return doDeploy(); diff --git a/tests/tests/actions/EndpointDeploy.js b/tests/tests/actions/EndpointDeploy.js index 05e5b6ba8..f203a177d 100644 --- a/tests/tests/actions/EndpointDeploy.js +++ b/tests/tests/actions/EndpointDeploy.js @@ -78,7 +78,7 @@ describe('Test Action: Endpoint Deploy', function() { stage: config.stage, region: config.region, names: [ - 'group1/function1#GET' + 'group1/function1~GET' ] }; @@ -106,7 +106,7 @@ describe('Test Action: Endpoint Deploy', function() { stage: config.stage, region: config.region, names: [ - 'group2/function4#GET' + 'group2/function4~GET' ] };