ProjectInit is now working

This commit is contained in:
Eslam A. Hefnawy 2016-02-25 17:34:22 +07:00
parent a146ef6c76
commit 40423b3b97
9 changed files with 122 additions and 60 deletions

View File

@ -181,6 +181,7 @@ class Project extends SerializerFileSystem {
this.resources[ resources.getName() ] = resources;
}
getResources(resourcesName) {
if (this.resources[resourcesName]) return this.resources[resourcesName];
else return this.resources[Object.keys(this.resources)[0]]; // This temporarily defaults to a single resource stack for backward compatibility

View File

@ -258,7 +258,7 @@ class ServerlessProviderAws {
Bucket: bucketName
};
return this.request('S3', 'getBucketAclPromised', params, stage, region)
return this.request('S3', 'getBucketAcl', params, stage, region)
.then(function(response) {
SUtils.sDebug(`Project bucket already exists: ${bucketName}`);
})
@ -269,7 +269,7 @@ class ServerlessProviderAws {
} else if (err.code == 'NoSuchBucket') {
SCli.log('Creating your project bucket on S3: ' + bucketName + '...');
params.ACL = 'private';
return _this.request('S3', 'createBucketPromised', params, stage, region);
return _this.request('S3', 'createBucket', params, stage, region);
} else {
throw new SError(err);
}
@ -288,9 +288,9 @@ class ServerlessProviderAws {
let _this = this;
return _this.findOrCreateProjectBucket()
return _this.findOrCreateProjectBucket(params.Bucket, stage, region)
.then(function() {
SUtils.sDebug(`Uploading to project bucket: ${key}...`);
SUtils.sDebug(`Uploading to project bucket: ${params.Bucket}...`);
return _this.request('S3', 'upload', params, stage);
});
}

View File

@ -15,7 +15,70 @@ class Resources extends SerializerFileSystem {
this._class = 'Resources';
this._config = config;
this._partials = [];
this.name = 'resources-' + SUtils.generateShortId(4);
this.AWSTemplateFormatVersion = "2010-09-09";
this.Description = "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway";
this.Resources = {
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "${stage}-${project}-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${region}:*:*"
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
}
};
this.Outputs = {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
};
}
updateConfig(config) {
@ -49,10 +112,10 @@ class Resources extends SerializerFileSystem {
if (!options.stage || !options.region) throw new SError('Both "stage" and "region" params are required');
// Validate: Check project path is set
if (!this._S.hasProject()) throw new SError('Function could not be populated because no project path has been set on Serverless instance');
if (!this._S.hasProject()) throw new SError('Resources could not be populated because no project path has been set on Serverless instance');
// Populate
return SUtils.populate(this.getVariables(), this.getTemplates(), this.toObject(), options.stage, options.region);
return SUtils.populate(this.getProject(), this.toObject(), options.stage, options.region);
}
fromObject(data) {

View File

@ -114,10 +114,11 @@ class SerializerFileSystem {
})
.then(function() {
// Load Resources
if (SUtils.fileExistsSync(path.join(_this._projectPath, 's-resources-cf.json'))) {
let resources = new _this._S.classes.Resources(_this._S);
return resources.load();
return resources.load()
}
})
.then(function () {
@ -154,7 +155,7 @@ class SerializerFileSystem {
.then(function() {
// Save Project Variables "s-variables-common.json"
let variables = new _this._S.classes.Variables(_this._S);
let variables = project.getVariables();
let variablesPath = project.getFilePath('_meta', 'variables', 's-variables-common.json');
SUtils.writeFileSync(variablesPath, variables.toObject());
@ -392,11 +393,12 @@ class SerializerFileSystem {
if (!_this._S.hasProject()) throw new SError('Resources could not be loaded because no project path has been set on Serverless instance');
// Validate: Check resources exists
if (!SUtils.fileExistsSync(resources.getProject().getFilePath())) return resources;
//if (!SUtils.fileExistsSync(resources.getProject().getFilePath())) return resources;
// Set Data
resources.fromObject(SUtils.readFileSync(resources.getProject().getFilePath('s-resources-cf.json')));
})
.then(function() {

View File

@ -250,17 +250,6 @@ module.exports = function(SPlugin, serverlessPath) {
projectBucketRegion: _this.evt.options.region
});
// Create s-resources-cf.json
if (!_this.project.cloudFormation && // TODO: Remove Back-compat support - In case initializing older project w/ cloudFormation property
!SUtils.fileExistsSync( _this.project.getFilePath( 's-resources-cf.json' ))) {
files.push(
SUtils.writeFile(
_this.project.getFilePath( 's-resources-cf.json' ),
JSON.stringify(
SUtils.readFileSync(path.join(_this.S.getServerlessPath(), 'templates', 's-resources-cf.json')),
null, 2)
));
}
// Save Project
return _this.project.save()

View File

@ -145,8 +145,14 @@ usage: serverless region create`,
// Add region to stage
_this.stage = _this.project.getStage(_this.evt.options.stage);
_this.region = new _this.S.classes.Region(_this.S, _this.stage, _this.evt.options.region);
// Add default project variables
_this.regionVariables = _this.region.getVariables();
_this.regionVariables.fromObject({
region: _this.evt.options.region
});
_this.stage.setRegion(_this.region);
return _this.stage.save();
return _this.region.save();
}
/**

View File

@ -155,16 +155,15 @@ usage: serverless resources deploy`,
_deployResources() {
let _this = this;
let regionVars = _this.S.getProject().getRegion(_this.evt.options.stage, _this.evt.options.region)._variables
let resourceVars = [ 'iamRoleArnLambda' ].concat( _this.S.getProject().resourceVars);
let _this = this,
region = _this.S.getProject().getRegion(_this.evt.options.stage, _this.evt.options.region),
regionVariables = region.getVariables();
return BbPromise.try(function() {
return _this.S.getProject().getResources({
populate: true,
stage: _this.evt.options.stage,
region: _this.evt.options.region
}).toObject();
return _this.S.getProject().getResources().toObjectPopulated({
stage: _this.evt.options.stage,
region: _this.evt.options.region
});
})
.then(function(resources) {
@ -221,23 +220,27 @@ usage: serverless resources deploy`,
.then(cfStackData => {
// Save stack name
regionVars.resourcesStackName = cfStackData.StackName;
//regionVariables.resourcesStackName = cfStackData.StackName;
// Save allowed (exported) CF output variables for Project Lambdas
regionVariables.fromObject({
resourcesStackName: cfStackData.StackName
});
// Save IAM Role ARN 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;
}
if (cfStackData.Outputs[i].OutputKey === 'IamRoleArnLambda') {
//regionVariables.iamRoleArnLambda = cfStackData.Outputs[i].OutputValue;
regionVariables.fromObject({
iamRoleArnLambda: cfStackData.Outputs[i].OutputValue
});
}
}
})
.then(() => {
// Stop Spinner
_this._spinner.stop(true);
// Save State
_this.S.state.save();
region.save();
// Status
SCli.log('Successfully deployed "' + _this.evt.options.stage + '" resources to "' + _this.evt.options.region + '"');
@ -264,7 +267,7 @@ usage: serverless resources deploy`,
stage = this.evt.options.stage,
region = this.evt.options.region,
aws = this.S.getProvider('aws'),
stackName = this.S.getProject().getRegion(stage, region)._variables.resourcesStackName || aws.getLambdasStackName(stage, projectName);
stackName = this.S.getProject().getRegion(stage, region).getVariables().resourcesStackName || aws.getResourcesStackName(stage, projectName);
// CF Params
let params = {
@ -283,7 +286,7 @@ usage: serverless resources deploy`,
Value: stage
}];
params.StackName = stackName
params.StackName = stackName;
params.OnFailure = 'DELETE';
return aws.request('CloudFormation', 'createStack', params, stage, region);
};

View File

@ -161,7 +161,7 @@ usage: serverless stage create`,
}
];
return _this.cliPromptSelect(`For this stage, do you want to use an existing ${_this.provider.getProviderName()} profile or create a new one?`, choices, false)
return _this.cliPromptSelect(`For the "${_this.evt.options.stage}" stage, do you want to use an existing ${_this.provider.getProviderName()} profile or create a new one?`, choices, false)
.then(function(values) {
// If "Use Existing" is selected, skip
@ -232,6 +232,8 @@ usage: serverless stage create`,
return _this.cliPromptSelect('Select a profile for your project: ', choices, false)
.then(function(results) {
_this.evt.options.profile = results[0].value;
_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;
});
});
});
@ -278,7 +280,14 @@ usage: serverless stage create`,
*/
_createStage() {
this.stage = new this.S.classes.Stage(this.S, this.project, this.evt.options.stage);
this.stage = new this.S.classes.Stage(this.S, this.project, this.evt.options.stage);
// Add default project variables
this.stageVariables = this.stage.getVariables();
this.stageVariables.fromObject({
stage: this.evt.options.stage
});
this.project.setStage(this.stage);
return this.stage.save();
}

View File

@ -408,12 +408,10 @@ exports.doesFunctionExist = function(functionName, componentName, projectRootPat
* Example: {"variableSyntax": "<%([\\s\\S]+?)%>"}
*/
exports.populate = function(meta, templates, data, stage, region) {
const project = meta._S.getProject()
exports.populate = function(project, data, stage, region) {
// Validate required params
if (!meta || !templates || !data || !stage || !region) throw new SError(`Missing required params: Serverless, project, stage, region`);
if (!project || !data || !stage || !region) throw new SError(`Missing required params: project, data, stage, region`);
// Validate: Check stage exists
if (typeof stage != 'undefined' && !project.validateStageExists(stage)) throw new SError(`Stage doesn't exist`);
@ -421,15 +419,10 @@ exports.populate = function(meta, templates, data, stage, region) {
// Validate: Check region exists in stage
if (typeof region != 'undefined' && !project.validateRegionExists(stage, region)) throw new SError(`Region "${region}" doesn't exist in provided stage "${stage}"`);
// Sanitize: Remove nested properties. DO NOT populate these. Rely on calling those classes toObjectPopulated methods instead.
let _components = data.components;
let _functions = data.functions;
if (data.components) delete data.components;
if (data.functions) delete data.functions;
let varTemplateSyntax = /\${([\s\S]+?)}/g,
templateTemplateSyntax = /\$\${([\s\S]+?)}/g;
templateTemplateSyntax = /\$\${([\s\S]+?)}/g,
templates = project.getTemplates();
if (project.variableSyntax) {
varTemplateSyntax = RegExp(project.variableSyntax,'g');
@ -481,8 +474,8 @@ exports.populate = function(meta, templates, data, stage, region) {
value = project.getRegion(stage, region).getVariables()[variableName]
} else if (project.getStage(stage).getVariables()[variableName]) {
value = project.getStage(stage).getVariables()[variableName];
} else if (meta[variableName]) {
value = meta[variableName];
} else if (project.getVariables()[variableName]) {
value = project.getVariables()[variableName];
}
// Reserved Variables
@ -501,10 +494,6 @@ exports.populate = function(meta, templates, data, stage, region) {
}
});
if (_components) data.components = _.mapValues(_components, (c) => c.toObjectPopulated({stage, region}));
if (_functions) data.functions = _.mapValues(_functions, (f) => f.toObjectPopulated({stage, region}));
return data;
};