From e34be438c0e059b327fc4491d003d43b211e11f2 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 15 Feb 2016 18:22:52 +0700 Subject: [PATCH] updates the actions to use ProviderAws --- lib/actions/FunctionLogs.js | 39 +++--- lib/actions/FunctionRun.js | 9 +- lib/actions/ProjectCreate.js | 11 +- lib/actions/ProjectInit.js | 64 ++++----- lib/actions/RegionCreate.js | 107 ++++++++------- lib/actions/RegionRemove.js | 19 +-- lib/actions/ResourcesDeploy.js | 237 +++++++++++++++++++++++++-------- lib/actions/ResourcesDiff.js | 11 +- lib/actions/ResourcesRemove.js | 18 +-- lib/actions/StageCreate.js | 3 +- 10 files changed, 297 insertions(+), 221 deletions(-) diff --git a/lib/actions/FunctionLogs.js b/lib/actions/FunctionLogs.js index 98596252d..e737bd710 100644 --- a/lib/actions/FunctionLogs.js +++ b/lib/actions/FunctionLogs.js @@ -123,18 +123,6 @@ module.exports = function(SPlugin, serverlessPath) { this.spinner = SCli.spinner(); - this.CWL = require('../utils/aws/CloudWatch')({ - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }); - - this.Lambda = require('../utils/aws/Lambda')({ - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }); - const func = this.S.getProject().getFunction( this.evt.options.path ), duration = this.evt.options.duration; @@ -146,14 +134,30 @@ module.exports = function(SPlugin, serverlessPath) { this.evt.data.lambdaName = lambdaName; } + _getLogStreams() { + let params = { + logGroupName: this.evt.data.logGroupName, + descending: true, + limit: 50, + orderBy: 'LastEventTime' + }; + + return this.S.getProvider('aws') + .request('CloudWatchLogs', 'describeLogStreams', params, this.evt.options.stage, this.evt.options.region) + .error(error => BbPromise.reject(new SError(error.message, SError.errorCodes.UNKNOWN))) + .then(reply => reply.logStreams); + } + _getLogStreamNames() { - return this.Lambda.getAliasPromised({ + const params = { FunctionName: this.evt.data.lambdaName, Name: this.evt.options.stage - }) + }; + + return this.S.getProvider('aws') + .request('Lambda', 'getAlias', params, this.evt.options.stage, this.evt.options.region); .then(reply => this.evt.data.version = reply.FunctionVersion) - .then(() => this.CWL.sGetLogStreams(this.evt.data.logGroupName, 50)) - .then(reply => reply.logStreams) + .then(this._getLogStreams) .then( logStreams => { if (logStreams.length === 0) return BbPromise.reject(new SError('No existing streams for the function')); @@ -186,7 +190,8 @@ module.exports = function(SPlugin, serverlessPath) { if (this.evt.options.filter) params.filterPattern = this.evt.options.filter; if (this.evt.data.nextToken) params.nextToken = this.evt.data.nextToken; - return this.CWL.filterLogEventsAsync(params) + return this.S.getProvider('aws') + .request('CloudWatchLogs', 'filterLogEvents', params, this.evt.options.stage, this.evt.options.region) .then(results => { if (this.S.config.interactive && results.events) { diff --git a/lib/actions/FunctionRun.js b/lib/actions/FunctionRun.js index d3ea98999..3e2de23b9 100644 --- a/lib/actions/FunctionRun.js +++ b/lib/actions/FunctionRun.js @@ -177,12 +177,6 @@ module.exports = function(SPlugin, serverlessPath) { // Invoke Lambda - _this.Lambda = require('../utils/aws/Lambda')({ - region: _this.evt.options.region, - accessKeyId: _this.S.config.awsAdminKeyId, - secretAccessKey: _this.S.config.awsAdminSecretKey - }); - let params = { FunctionName: _this.function.getDeployedName({ stage: _this.evt.options.stage, region: _this.evt.options.region }), // ClientContext: new Buffer(JSON.stringify({x: 1, y: [3,4]})).toString('base64'), @@ -192,7 +186,8 @@ module.exports = function(SPlugin, serverlessPath) { Qualifier: _this.evt.options.stage }; - return _this.Lambda.invokePromised(params) + return this.S.getProvider('aws') + .request('Lambda', 'invoke', params, _this.evt.options.stage, _this.evt.options.region); .then( reply => { let color = !reply.FunctionError ? 'white' : 'red'; diff --git a/lib/actions/ProjectCreate.js b/lib/actions/ProjectCreate.js index 98cf249b4..1abacda6f 100644 --- a/lib/actions/ProjectCreate.js +++ b/lib/actions/ProjectCreate.js @@ -20,16 +20,7 @@ module.exports = function(SPlugin, serverlessPath) { - const path = require('path'), - SError = require( path.join( serverlessPath, 'ServerlessError' ) ), - SCli = require( path.join( serverlessPath, 'utils/cli' ) ), - SUtils = require( path.join( serverlessPath, 'utils' ) ), - os = require('os'), - fs = require('fs'), - BbPromise = require('bluebird'), - awsMisc = require( path.join( serverlessPath, 'utils/aws/Misc' ) ); - - BbPromise.promisifyAll(fs); + const BbPromise = require('bluebird'); /** * ProjectInstall Class diff --git a/lib/actions/ProjectInit.js b/lib/actions/ProjectInit.js index dc791f0ff..420ff2d79 100644 --- a/lib/actions/ProjectInit.js +++ b/lib/actions/ProjectInit.js @@ -22,13 +22,10 @@ module.exports = function(SPlugin, serverlessPath) { SError = require( path.join( serverlessPath, 'ServerlessError' ) ), SCli = require( path.join( serverlessPath, 'utils/cli' ) ), SUtils = require( path.join( serverlessPath, 'utils' ) ), - os = require('os'), - fs = require('fs'), - fse = require('fs-extra'), BbPromise = require('bluebird'), - awsMisc = require( path.join( serverlessPath, 'utils/aws/Misc' ) ); + os = require('os'), + fs = BbPromise.promisifyAll(require('fs')); - BbPromise.promisifyAll(fs); /** * ProjectInit Class @@ -91,44 +88,38 @@ module.exports = function(SPlugin, serverlessPath) { projectInit(evt) { - let _this = this; this.evt = evt; // Check for AWS Profiles - let profilesList = awsMisc.profilesMap(); + let profilesList = this.S.getProvider('aws').getAllProfiles(); this.profiles = Object.keys(profilesList); // Set Stage default - if (!_this.evt.options.stage) _this.evt.options.stage = 'dev'; + if (!this.evt.options.stage) this.evt.options.stage = 'dev'; // Greet - if (_this.S.config.interactive && !_this.evt.options.noGreeting) SCli.asciiGreeting(); + if (this.S.config.interactive && !this.evt.options.noGreeting) SCli.asciiGreeting(); + console.log(''); + SCli.log('Initializing Serverless Project...'); /** * Control Flow */ - return BbPromise.try(function() { - console.log(''); - SCli.log('Initializing Serverless Project...'); - }) - .bind(_this) - .then(_this._prompt) - .then(_this._validateAndPrepare) - .then(_this._scaffold) - .then(_this._createStageAndRegion) - .then(_this._installComponentDeps) - .then(function() { - - SCli.log('Successfully initialized project "' - + _this.evt.options.name - + '"'); + return this._prompt() + .bind(this) + .then(this._validateAndPrepare) + .then(this._scaffold) + .then(this._createStageAndRegion) + .then(this._installComponentDeps) + .then(() => { + SCli.log(`Successfully initialized project "${this.evt.options.name}"`); /** * Return EVT */ - return _this.evt; + return this.evt; }); } @@ -235,11 +226,14 @@ module.exports = function(SPlugin, serverlessPath) { _this.evt.options.domain = answers.domain; _this.evt.options.notificationEmail = answers.notificationEmail; + // init AWS with the provided keys + _this.S.initProviders(); + // Show region prompt if (!_this.evt.options.region) { // Prompt: region select - let choices = awsMisc.validLambdaRegions.map(r => { + let choices = _this.S.getProvider('aws').validLambdaRegions.map(r => { return { key: '', value: r, @@ -285,13 +279,12 @@ module.exports = function(SPlugin, serverlessPath) { _validateAndPrepare() { - // Initialize AWS Misc Service - this.AwsMisc = require('../utils/aws/Misc'); + this.S.getProvider('aws').getProfile(this.evt.options.profile) // If Profile, extract API Keys if (this.evt.options.profile) { - this.S.config.awsAdminKeyId = this.AwsMisc.profilesGet(this.evt.options.profile)[this.evt.options.profile].aws_access_key_id; - this.S.config.awsAdminSecretKey = this.AwsMisc.profilesGet(this.evt.options.profile)[this.evt.options.profile].aws_secret_access_key; + this.S.config.awsAdminKeyId = this.S.getProvider('aws').getProfile(this.evt.options.profile).aws_access_key_id; + this.S.config.awsAdminSecretKey = this.S.getProvider('aws').getProfile(this.evt.options.profile).aws_secret_access_key; } // Validate API Keys @@ -299,15 +292,6 @@ module.exports = function(SPlugin, serverlessPath) { return BbPromise.reject(new SError('Missing AWS API Key and/or AWS Secret Key')); } - // Initialize Other AWS Services - let awsConfig = { - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }; - this.S3 = require('../utils/aws/S3')(awsConfig); - this.CF = require('../utils/aws/CloudFormation')(awsConfig); - // Validate Name - AWS only allows Alphanumeric and - in name let nameOk = /^([a-zA-Z0-9-]+)$/.exec(this.evt.options.name); if (!nameOk) { @@ -327,7 +311,7 @@ module.exports = function(SPlugin, serverlessPath) { } // Validate Region - if (awsMisc.validLambdaRegions.indexOf(this.evt.options.region) == -1) { + if (this.S.getProvider('aws').validLambdaRegions.indexOf(this.evt.options.region) == -1) { return BbPromise.reject(new SError('Invalid region. Lambda not supported in ' + this.evt.options.region, SError.errorCodes.UNKNOWN)); } diff --git a/lib/actions/RegionCreate.js b/lib/actions/RegionCreate.js index bb575cbc1..fc0c19231 100644 --- a/lib/actions/RegionCreate.js +++ b/lib/actions/RegionCreate.js @@ -19,13 +19,9 @@ module.exports = function(SPlugin, serverlessPath) { const path = require('path'), SError = require(path.join(serverlessPath, 'ServerlessError')), SCli = require(path.join(serverlessPath, 'utils/cli')), - fs = require('fs'), BbPromise = require('bluebird'), - awsMisc = require(path.join(serverlessPath, 'utils/aws/Misc')), SUtils = require(path.join(serverlessPath, 'utils')); - BbPromise.promisifyAll(fs); - /** * RegionCreate Class */ @@ -107,24 +103,13 @@ usage: serverless region create`, */ _prompt() { - - let _this = this; - // Skip if non-interactive or stage is provided - if (!_this.S.config.interactive || (_this.evt.options.stage && _this.evt.options.region)) return BbPromise.resolve(); + if (!this.S.config.interactive || (this.evt.options.stage && this.evt.options.region)) return BbPromise.resolve(); - return _this.cliPromptSelectStage('Select an existing stage for your new region: ', _this.evt.options.stage, false) - .then(stage => { - _this.evt.options.stage = stage; - BbPromise.resolve(); - }) - .then(function() { - return _this.cliPromptSelectRegion('Select a new region for your existing stage: ', false, false, _this.evt.options.region, _this.evt.options.stage) - .then(region => { - _this.evt.options.region = region; - BbPromise.resolve(); - }); - }); + return this.cliPromptSelectStage('Select an existing stage for your new region: ', this.evt.options.stage, false) + .then(stage => this.evt.options.stage = stage;) + .then(() => this.cliPromptSelectRegion('Select a new region for your existing stage: ', false, false, this.evt.options.region, this.evt.options.stage)); + .then(region => this.evt.options.region = region); } /** @@ -148,7 +133,7 @@ usage: serverless region create`, } // Validate region: make sure Lambda is supported in that region - if (awsMisc.validLambdaRegions.indexOf(_this.evt.options.region) == -1) { + if (this.S.getProvider('aws').validLambdaRegions.indexOf(_this.evt.options.region) == -1) { return BbPromise.reject(new SError('Invalid region. Lambda not supported in ' + _this.evt.options.region)); } @@ -175,13 +160,6 @@ usage: serverless region create`, _createProjectBucket() { - let awsConfig = { - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }; - this.S3 = require('../utils/aws/S3')(awsConfig); - if (this.evt.options.noExeCf) { // If no CloudFormation is set, skip project bucket creation @@ -189,11 +167,39 @@ usage: serverless region create`, SCli.log('Notice -- Skipping project bucket creation. Don\'t forget to point this project to your existing project bucket in _meta/s-variables-common.json. You will also need to manually create the file structure on the bucket and add a .env file to the tour first stage folder (e.g., "dev").'); return BbPromise.resolve(); - } else { - - // Create bucket, or skip if already exists - return this.S3.sCreateBucket(this.S.state.getMeta().variables.projectBucket); } + + // Create bucket, or skip if already exists + + const stage = this.evt.options.stage, + region = this.evt.options.region, + bucketName = this.S.state.getMeta().variables.projectBucket; + + return this.S.getProvider('aws') + .request('S3', 'getBucketAcl', { Bucket: bucketName }, stage, region) + .then(() => SUtils.sDebug(`Project bucket already exists: ${bucketName}`)) + .catch(function(err) { + + if (err.code == 'AccessDenied') { + + throw new SError( + `S3 Bucket "${bucketName}" already exists and you do not have permissions to use it`, + SError.errorCodes.ACCESS_DENIED + ); + + } else if (err.code == 'NoSuchBucket') { + + SCli.log('Creating your project bucket on S3: ' + bucketName + '...'); + + return this.S.getProvider('aws') + .request('S3', 'createBucket', {Bucket: bucketName, ACL: 'private'}, stage, region); + + } else { + + // Otherwise throw error + throw new SError(err); + } + }); } /** @@ -202,29 +208,29 @@ usage: serverless region create`, */ _putEnvFile() { + const projectName = this.S.getProject().name, + stage = this.evt.options.stage, + region = this.evt.options.region, + key = ['serverless', projectName, stage, region, 'envVars', '.env'].join('/'); // If noExeCf option, skip if (this.evt.options.noExeCf) return BbPromise.resolve(); - // Init AWS S3 - let awsConfig = { - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }; - this.S3 = require('../utils/aws/S3')(awsConfig); - // Create ENV file in new region - let envFileContents = `SERVERLESS_STAGE=${this.evt.options.stage} -SERVERLESS_DATA_MODEL_STAGE=${this.evt.options.stage} -SERVERLESS_PROJECT_NAME=${this.S.getProject().name}`; + let envFileContents = `SERVERLESS_STAGE=${stage} +SERVERLESS_DATA_MODEL_STAGE=${stage} +SERVERLESS_PROJECT_NAME=${projectName}`; - return this.S3.sPutEnvFile( - this.S.state.getMeta().variables.projectBucket, - this.S.getProject().name, - this.evt.options.stage, - this.evt.options.region, - envFileContents); + let params = { + Bucket: this.S.state.getMeta().variables.projectBucket, + Key: key, + ACL: 'private', + ContentType: 'text/plain', + Body: envFileContents + }; + + return this.S.getProvider('aws') + .request('S3', 'putObject', params, stage, region); } /** @@ -241,7 +247,10 @@ SERVERLESS_PROJECT_NAME=${this.S.getProject().name}`; } }); } + + } + return( RegionCreate ); }; diff --git a/lib/actions/RegionRemove.js b/lib/actions/RegionRemove.js index 68df6a931..1ef62083a 100644 --- a/lib/actions/RegionRemove.js +++ b/lib/actions/RegionRemove.js @@ -20,7 +20,6 @@ module.exports = function(SPlugin, serverlessPath) { SCli = require(path.join(serverlessPath, 'utils/cli')), BbPromise = require('bluebird'), fs = BbPromise.promisifyAll(require('fs')), - awsMisc = require(path.join(serverlessPath, 'utils/aws/Misc')), SUtils = require(path.join(serverlessPath, 'utils')), _ = require('lodash'); @@ -83,7 +82,6 @@ usage: serverless region remove`, .bind(this) .then(this._validateAndPrepare) .then(() => { SCli.log(`Removing region "${this.evt.options.region}" in stage "${this.evt.options.stage}"...`); }) - .then(this._initS3) .then(this._listS3Objects) .then(this._removeS3Objects) .then(this._removeResources) @@ -137,7 +135,7 @@ usage: serverless region remove`, } // Validate region: make sure Lambda is supported in that region - if (awsMisc.validLambdaRegions.indexOf(this.evt.options.region) == -1) { + if (this.S.getProvider('aws').validLambdaRegions.indexOf(this.evt.options.region) == -1) { return BbPromise.reject(new SError('Invalid region. Lambda not supported in ' + this.evt.options.region)); } @@ -148,16 +146,6 @@ usage: serverless region remove`, } - _initS3() { - let awsConfig = { - region: SUtils.getProjectBucketRegion(this.S.state.getMeta().variables), - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }; - - this.S3 = require('../utils/aws/S3')(awsConfig); - } - _listS3Objects() { SUtils.sDebug("List related S3 objects"); @@ -166,8 +154,7 @@ usage: serverless region remove`, Bucket: this.S.state.getMeta().variables.projectBucket, Prefix: prefix }; - - return this.S3.listObjectsPromised(params) + return this.S.getProvider('aws').request('S3', 'listObjects', params, stage, region); .then(reply => {return _.map(reply.Contents, (item) => ({Key: item.Key}) )}); } @@ -181,7 +168,7 @@ usage: serverless region remove`, Objects: objects } }; - return this.S3.deleteObjectsPromised(params) + return this.S.getProvider('aws').request('S3', 'deleteObjects', params, stage, region); } else { SUtils.sDebug("S3 objects are not found. Skipping."); return BbPromise.resolve(); diff --git a/lib/actions/ResourcesDeploy.js b/lib/actions/ResourcesDeploy.js index e04152621..0912816e4 100644 --- a/lib/actions/ResourcesDeploy.js +++ b/lib/actions/ResourcesDeploy.js @@ -13,6 +13,7 @@ module.exports = function(SPlugin, serverlessPath) { SCli = require(path.join(serverlessPath, 'utils/cli')), BbPromise = require('bluebird'), _ = require('lodash'), + async = require('async'), SUtils = require(path.join(serverlessPath, 'utils/index')); class ResourcesDeploy extends SPlugin { @@ -189,15 +190,6 @@ usage: serverless resources deploy`, return; } - // Config AWS Services - let awsConfig = { - region: _this.evt.options.region, - accessKeyId: _this.S.config.awsAdminKeyId, - secretAccessKey: _this.S.config.awsAdminSecretKey - }; - _this.CF = require('../utils/aws/CloudFormation')(awsConfig); - _this.S3 = require('../utils/aws/S3')(awsConfig); - // Otherwise, deploy to CloudFormation SCli.log('Deploying resources to stage "' + _this.evt.options.stage @@ -210,59 +202,46 @@ usage: serverless resources deploy`, _this._spinner.start(); // Upload to S3 Bucket - return _this.S3.sPutCfFile( - _this.S.state.getMeta().variables.projectBucket, - _this.S.getProject().getName(), - _this.evt.options.stage, - _this.evt.options.region, - _this.cfTemplate - ) - .then(function(templateUrl) { + return _this._putCfFile(_this.cfTemplate) + .bind(_this) + .then(_this._createOrUpdateResourcesStack) + .then(cfData => { - // Trigger CF Stack Create/Update - return _this.CF.sCreateOrUpdateResourcesStack( - _this.S.getProject().getName(), - _this.evt.options.stage, - _this.evt.options.region, - regionVars.resourcesStackName ? regionVars.resourcesStackName : null, - templateUrl) - .then(cfData => { + // If string, log output + if (typeof cfData === 'string') { + _this._spinner.stop(true); + SCli.log(cfData); + return; + } - // If string, log output - if (typeof cfData === 'string') { - _this._spinner.stop(true); - SCli.log(cfData); - return; + // Monitor CF Status + return _monitorCf(cfData) + .then(cfStackData => { + + // Save stack name + regionVars.resourcesStackName = cfStackData.StackName; + + // Save allowed (exported) CF output variables for Project Lambdas + for (let i = 0; i < cfStackData.Outputs.length; i++) { + let varName = _.lowerFirst(cfStackData.Outputs[i].OutputKey); + if (resourceVars.indexOf(varName) !== -1) { + regionVars[varName] = cfStackData.Outputs[i].OutputValue; + } } - - // Monitor CF Status - return _this.CF.sMonitorCf(cfData) - .then(cfStackData => { - - // Save stack name - regionVars.resourcesStackName = cfStackData.StackName; - - // Save allowed (exported) CF output variables for Project Lambdas - for (let i = 0; i < cfStackData.Outputs.length; i++) { - let varName = _.lowerFirst(cfStackData.Outputs[i].OutputKey); - if (resourceVars.indexOf(varName) !== -1) { - regionVars[varName] = cfStackData.Outputs[i].OutputValue; - } - } - }) - .then(() => { - - // Stop Spinner - _this._spinner.stop(true); - - // Save State - _this.S.state.save(); - - // Status - SCli.log('Successfully deployed "' + _this.evt.options.stage + '" resources to "' + _this.evt.options.region + '"'); - }); }) + .then(() => { + + // Stop Spinner + _this._spinner.stop(true); + + // Save State + _this.S.state.save(); + + // Status + SCli.log('Successfully deployed "' + _this.evt.options.stage + '" resources to "' + _this.evt.options.region + '"'); + }); }) + .catch(function(e) { // Stop Spinner @@ -272,7 +251,149 @@ usage: serverless resources deploy`, }) }); } + + /** + * Create Or Update Resources Stack + * moved from lib/utils/aws/CloudFormation.js + */ + + _createOrUpdateResourcesStack(templateUrl) { + const projectName = this.S.getProject().getName(), + stage = this.evt.options.stage, + region = this.evt.options.region, + aws = this.S.getProvider('aws'), + stackName = this.S.state.getMeta().stages[stage].regions[region].variables.resourcesStackName || aws.getLambdasStackName(stage, projectName); + + // CF Params + let params = { + Capabilities: [ + 'CAPABILITY_IAM' + ], + Parameters: [], + TemplateURL: templateUrl + }; + + // Helper function to create Stack + let createStack = () => { + + params.Tags = [{ + Key: 'STAGE', + Value: stage + }]; + + params.StackName = stackName + params.OnFailure = 'DELETE'; + return aws.request('CloudFormation', 'createStack', params, stage, region); + }; + + // Check to see if Stack Exists + return aws.request('CloudFormation', 'describeStackResources', {StackName: stackName}, stage, region); + .then(function(data) { + + params.StackName = stackName; + // Update stack + return aws.request('CloudFormation', 'updateStack', params, stage, region) + }) + .catch(function(e) { + + // No updates are to be performed + if (e.cause.message == 'No updates are to be performed.') { + return 'No resource updates are to be performed.'; + } + + // If does not exist, create stack + if (e.cause.message.indexOf('does not exist') > -1) { + return createStack(); + } + + // Otherwise throw another error + throw new SError(e.cause.message); + }) + } + + + /** + * Monitor CF Stack Status (Create/Update) + * moved from lib/utils/aws/CloudFormation.js + */ + + _monitorCf(cfData, checkFreq) { + + let _this = this, + stackStatusComplete; + + let validStatuses = ['CREATE_COMPLETE', 'CREATE_IN_PROGRESS', 'UPDATE_COMPLETE', 'UPDATE_IN_PROGRESS', 'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS']; + + return new BbPromise(function(resolve, reject) { + + let stackStatus = null, + stackData = null; + + async.whilst( + function() { + return (stackStatus !== 'UPDATE_COMPLETE' && stackStatus !== 'CREATE_COMPLETE'); + }, + + function(callback) { + setTimeout(function() { + + let params = { + StackName: cfData.StackId + }; + _this.S.getProvider('aws') + .request('CloudFormation', 'describeStacks', params, _this.evt.options.stage, _this.evt.options.region) + .then(function(data) { + + stackData = data; + stackStatus = stackData.Stacks[0].StackStatus; + + SUtils.sDebug('CF stack status: ', stackStatus); + + if (!stackStatus || validStatuses.indexOf(stackStatus) === -1) { + return reject(new SError(`An error occurred while provisioning your cloudformation: ${stackData.Stacks[0].StackStatusReason}`)); + } else { + return callback(); + } + }); + }, checkFreq ? checkFreq : 5000); + }, + + function() { + return resolve(stackData.Stacks[0]); + } + ); + }); + } + + /** + * Put CF File On S3 + * moved from lib/utils/aws/S3.js + */ + + _putCfFile = function(cfTemplate) { + const time = new Date().getTime(), + stage = this.evt.options.stage, + region = this.evt.options.region, + projectName = this.S.getProject().getName(), + bucketName = this.S.state.getMeta().variables.projectBucket, + key = ['serverless', projectName, stage, region, 'resources/' + 's-resources-cf'].join('/') + '@' + time + '.json', + params = { + Bucket: bucketName, + Key: key, + ACL: 'private', + ContentType: 'application/json', + Body: JSON.stringify(cfTemplate) + }; + + return this.S.getProvider('aws') + .request('S3', 'putObject', params, stage, region) + .then(function() { + const hostname = new require('aws-sdk').S3().endpoint.hostname; + return `https://${hostname}/${bucketName}/${key}`; + }); + }; } + return( ResourcesDeploy ); -}; +}; \ No newline at end of file diff --git a/lib/actions/ResourcesDiff.js b/lib/actions/ResourcesDiff.js index c13dfca62..bc2c56485 100644 --- a/lib/actions/ResourcesDiff.js +++ b/lib/actions/ResourcesDiff.js @@ -141,13 +141,6 @@ module.exports = function(SPlugin, serverlessPath) { return BbPromise.reject(new SError('Region "' + this.evt.options.region + '" does not exists in stage "' + this.evt.options.stage + '"')); } - const awsConfig = { - region: this.evt.options.region, - accessKeyId: this.S.config.awsAdminKeyId, - secretAccessKey: this.S.config.awsAdminSecretKey - }; - - this.CloudFormation = require('../utils/aws/CloudFormation')(awsConfig); } _getLocalTemplate() { @@ -173,7 +166,9 @@ module.exports = function(SPlugin, serverlessPath) { // const StackName = this.CloudFormation.sGetResourcesStackName(this.evt.options.stage, this.S.getProject().getName()); const StackName = this.S.state.getMeta().stages[this.evt.options.stage].regions[this.evt.options.region].variables.resourcesStackName; - return this.CloudFormation.getTemplatePromised({StackName}) + return this.S + .getProvider('aws') + .request('CloudFormation', 'getTemplate', {StackName}, this.evt.options.stage, this.evt.options.region) .then((reply) => JSON.parse(reply.TemplateBody)); } } diff --git a/lib/actions/ResourcesRemove.js b/lib/actions/ResourcesRemove.js index 2717da6bf..364090244 100644 --- a/lib/actions/ResourcesRemove.js +++ b/lib/actions/ResourcesRemove.js @@ -159,26 +159,16 @@ usage: serverless resources remove`, region = _this.evt.options.region, regionVars = _this.S.state.getMeta().stages[stage].regions[region].variables, projectBucket = _this.S.state.getMeta().variables.projectBucket, - projectName = _this.S.getProject().getName(); + projectName = _this.S.getProject().getName(), + aws = _this.S.getProvider('aws'); - // Config AWS Services - let awsConfig = { - region: region, - accessKeyId: _this.S.config.awsAdminKeyId, - secretAccessKey: _this.S.config.awsAdminSecretKey - }; - - _this.CF = require('../utils/aws/CloudFormation')(awsConfig); - _this.S3 = require('../utils/aws/S3')(awsConfig); - _this.S3.sSetProjectBucketConfig(projectBucket); - - let stackName = (regionVars.resourcesStackName || _this.CF.sGetResourcesStackName(stage, projectName)); + let stackName = (regionVars.resourcesStackName || aws.getLambdasStackName(stage, projectName)); SCli.log(`Removing resources from stage "${stage}" in region "${region}" via Cloudformation (~3 minutes)...`); let removeCfStack = function() { SUtils.sDebug(`Removing "${stackName}" CF stack`); - return _this.CF.deleteStackPromised({StackName: stackName}); + return aws.request('CloudFormation', 'deleteStack', {StackName: stackName}, stage, region); }; let removeLocalResourceFile = function() { diff --git a/lib/actions/StageCreate.js b/lib/actions/StageCreate.js index bc2de41d6..b973eee52 100644 --- a/lib/actions/StageCreate.js +++ b/lib/actions/StageCreate.js @@ -19,7 +19,6 @@ module.exports = function(SPlugin, serverlessPath) { os = require('os'), fs = require('fs'), BbPromise = require('bluebird'), - awsMisc = require(path.join(serverlessPath, 'utils/aws/Misc')), SUtils = require(path.join(serverlessPath, 'utils')); BbPromise.promisifyAll(fs); @@ -171,7 +170,7 @@ usage: serverless stage create`, } // Validate region - if (awsMisc.validLambdaRegions.indexOf(this.evt.options.region) == -1) { + if (this.S.getProvider('aws').validLambdaRegions.indexOf(this.evt.options.region) == -1) { return BbPromise.reject(new SError('Invalid region. Lambda not supported in ' + this.evt.options.region)); }