mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
358 lines
8.8 KiB
JavaScript
358 lines
8.8 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Serverless Project Class
|
|
*/
|
|
|
|
const SError = require('./Error'),
|
|
SUtils = require('./utils/index'),
|
|
SCli = require('./utils/cli'),
|
|
SerializerFileSystem = require('./SerializerFileSystem'),
|
|
BbPromise = require('bluebird'),
|
|
path = require('path'),
|
|
_ = require('lodash'),
|
|
fs = require('fs'),
|
|
os = require('os');
|
|
|
|
class Project extends SerializerFileSystem {
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
|
|
constructor(S) {
|
|
|
|
super();
|
|
|
|
let _this = this;
|
|
_this._S = S;
|
|
_this._class = 'Project';
|
|
|
|
// Default properties
|
|
_this.name = 'serverless' + SUtils.generateShortId(6);
|
|
_this.version = '0.0.1';
|
|
_this.profile = 'serverless-v' + require('../package.json').version;
|
|
_this.location = 'https://github.com/...';
|
|
_this.author = '';
|
|
_this.description = 'A Slick New Serverless Project';
|
|
_this.custom = {};
|
|
_this.plugins = [];
|
|
_this.components = {};
|
|
_this.resources = {};
|
|
_this.stages = {};
|
|
_this.variables = {};
|
|
_this.templates = {};
|
|
}
|
|
|
|
/**
|
|
* Load
|
|
* - Return promise
|
|
*/
|
|
|
|
load() {
|
|
return this.deserialize(this);
|
|
}
|
|
|
|
/**
|
|
* Save
|
|
* - Returns promise
|
|
*/
|
|
|
|
save(options) {
|
|
return this.serialize(this, options);
|
|
}
|
|
|
|
/**
|
|
* To Object
|
|
* - Returns a raw object
|
|
*/
|
|
|
|
toObject() {
|
|
return SUtils.exportObject(_.cloneDeep(this));
|
|
}
|
|
|
|
/**
|
|
* toObjectPopulated
|
|
* - Fill in templates then variables
|
|
* - Returns Promise
|
|
*/
|
|
|
|
toObjectPopulated(options) {
|
|
|
|
let _this = this;
|
|
options = options || {};
|
|
|
|
// Validate: Check Stage & Region
|
|
if (!options.stage || !options.region) throw new SError('Both "stage" and "region" params are required');
|
|
|
|
}
|
|
|
|
fromObject() {
|
|
|
|
}
|
|
|
|
getName(){
|
|
return this.name;
|
|
}
|
|
|
|
getComponent( componentName ){
|
|
return _.find( _.values( this.components ), c => {
|
|
return c.getName() === componentName;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get All Components
|
|
*/
|
|
|
|
getAllComponents(options) {
|
|
return _.values( this.components );
|
|
}
|
|
|
|
setComponent( component ) {
|
|
this.components[ component.name ] = component;
|
|
}
|
|
|
|
getPlugins(){
|
|
return this.plugins;
|
|
}
|
|
|
|
addPlugin( pluginName ){
|
|
this.plugins.push( pluginName );
|
|
}
|
|
|
|
/**
|
|
* Get All Functions
|
|
* - Returns an array of this project's function instances
|
|
*/
|
|
|
|
getAllFunctions(options) {
|
|
return _.flatten( _.map( this.getAllComponents(), component =>
|
|
component.getAllFunctions()
|
|
));
|
|
}
|
|
|
|
getFunction( functionName ){
|
|
return _.find( this.getAllFunctions(), f =>
|
|
f.getName() === functionName
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Get Endpoints
|
|
* - Returns an array of this project's Endpoint instances
|
|
*/
|
|
|
|
getAllEndpoints(options) {
|
|
return _.flatten( _.map( this.getAllFunctions(), f => f.getAllEndpoints() ) );
|
|
}
|
|
|
|
getEndpoint( endpointPath, endpointMethod ){
|
|
return _.find( _.values( this.getAllEndpoints() ), e =>
|
|
e.path === endpointPath && e.method === endpointMethod
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Get Events
|
|
* - Returns an array of this project's Events instances
|
|
*/
|
|
|
|
getAllEvents(options) {
|
|
return _.flatten( _.map( this.getAllFunctions(), f => f.getAllEvents() ) );
|
|
}
|
|
|
|
getEvent( eventName ){
|
|
return _.find( _.values( this.getAllEvents() ), e =>
|
|
e.name === eventName
|
|
)
|
|
}
|
|
|
|
setResources(resources) {
|
|
this.resources = resources;
|
|
}
|
|
|
|
/**
|
|
* Get Resources
|
|
* - Returns Promise & clone of resources
|
|
* - TODO: Make Get Local Resources Only, then make another method for combined resources
|
|
*/
|
|
|
|
getResources(options) {
|
|
|
|
let _this = this,
|
|
resources;
|
|
options = options || {};
|
|
|
|
return BbPromise.try(function() {
|
|
|
|
if (_this.get().cloudFormation) {
|
|
|
|
// TODO: Back Compat Support -- Remove in V1
|
|
resources = _this.get().cloudFormation;
|
|
|
|
} else if (SUtils.fileExistsSync(_this._S.getProject().getFilePath('s-resources-cf.json'))) {
|
|
resources = SUtils.readAndParseJsonSync(_this._S.getProject().getFilePath('s-resources-cf.json'));
|
|
}
|
|
|
|
return _.flatten( _.map( _.values( _this.components ), c => c.getCFSnippets() ) );
|
|
})
|
|
.then(function (cfSnippets) {
|
|
|
|
// Merge s-module.json CF syntax
|
|
for (let i = 0; i < cfSnippets.length; i++) {
|
|
|
|
let cf = cfSnippets[i];
|
|
|
|
// Merge Lambda Policy Statements - s-resources-cf.json uses different keys
|
|
if (cf.LambdaIamPolicyStatements && cf.LambdaIamPolicyStatements.length > 0) {
|
|
cf.LambdaIamPolicyStatements.forEach(function (policyStmt) {
|
|
try {
|
|
resources.Resources.IamPolicyLambda.Properties.PolicyDocument.Statement.push(policyStmt);
|
|
}
|
|
catch (e) {
|
|
}
|
|
});
|
|
}
|
|
|
|
// Merge Resources - s-resources-cf.json uses different keys
|
|
if (cf.Resources) {
|
|
let cfResourceKeys = Object.keys(cf.Resources);
|
|
cfResourceKeys.forEach(function (resourceKey) {
|
|
if (resources.Resources[resourceKey]) {
|
|
SCli.log(`WARN: Resource key ${resourceKey} already defined in CF template. Overwriting...`);
|
|
}
|
|
try {
|
|
resources.Resources[resourceKey] = cf.Resources[resourceKey];
|
|
} catch (e) {
|
|
}
|
|
});
|
|
}
|
|
|
|
// Merge Resources
|
|
// TODO: Remove @ V1 when we can make breaking changes
|
|
if (cf.resources) {
|
|
let cfResourceKeys = Object.keys(cf.resources);
|
|
cfResourceKeys.forEach(function (resourceKey) {
|
|
if (resources.Resources[resourceKey]) {
|
|
SCli.log(`WARN: Resource key ${resourceKey} already defined in CF template. Overwriting...`);
|
|
}
|
|
try {
|
|
resources.Resources[resourceKey] = cf.resources[resourceKey];
|
|
} catch (e) {
|
|
}
|
|
});
|
|
}
|
|
|
|
// Merge Lambda Policy Statements
|
|
// TODO: Remove @ V1 when we can make breaking changes
|
|
if (cf.lambdaIamPolicyDocumentStatements && cf.lambdaIamPolicyDocumentStatements.length > 0) {
|
|
cf.lambdaIamPolicyDocumentStatements.forEach(function (policyStmt) {
|
|
try {
|
|
resources.Resources.IamPolicyLambda.Properties.PolicyDocument.Statement.push(policyStmt);
|
|
}
|
|
catch (e) {
|
|
}
|
|
});
|
|
}
|
|
|
|
// Merge Resources
|
|
// TODO: Remove @ V1 when we can make breaking changes
|
|
if (cf.resources) {
|
|
let cfResourceKeys = Object.keys(cf.resources);
|
|
cfResourceKeys.forEach(function (resourceKey) {
|
|
if (resources.Resources[resourceKey]) {
|
|
SCli.log(`WARN: Resource key ${resourceKey} already defined in CF template. Overwriting...`);
|
|
}
|
|
try {
|
|
resources.Resources[resourceKey] = cf.resources[resourceKey];
|
|
} catch (e) {
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Return
|
|
if (options.populate) {
|
|
return SUtils.populate(_this._S.state.getMeta(), _this.getTemplates(), resources, options.stage, options.region);
|
|
} else {
|
|
return resources;
|
|
}
|
|
});
|
|
}
|
|
|
|
getStages() {
|
|
return Object.keys( this.stages );
|
|
}
|
|
|
|
getStage( name ) {
|
|
return this.stages[ name ];
|
|
}
|
|
|
|
setStage(stage ) {
|
|
this.stages[ stage.getName() ] = stage;
|
|
}
|
|
|
|
removeStage( name ) {
|
|
let stage = this.stages[ name ];
|
|
|
|
delete this.stages[ name ];
|
|
|
|
return BbPromise.try(function(){
|
|
if( stage ){
|
|
return stage.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
validateStageExists( name ){
|
|
return this.stages[ name ] != undefined;
|
|
}
|
|
|
|
saveStages(){
|
|
let _this = this;
|
|
|
|
return BbPromise.each( _.values( _this.stages ), function(stage){
|
|
stage.save();
|
|
});
|
|
}
|
|
|
|
getRegion( stageName, regionName ){
|
|
if( this.hasStage( stageName ) ){
|
|
let stage = this.getStage( stageName );
|
|
|
|
if( stage.hasRegion( regionName ) ){
|
|
return stage.getRegion( regionName );
|
|
} else {
|
|
throw new SError(`Region ${regionName} doesnt exist in stage ${stageName}!`);
|
|
}
|
|
} else {
|
|
throw new SError(`Stage ${stageName} doesnt exist in this project!`);
|
|
}
|
|
}
|
|
|
|
setRegion(stageName, region){
|
|
let stage = this.getStage(stageName);
|
|
stage.setRegion(region);
|
|
}
|
|
|
|
getRegions( stageName ){
|
|
return this.getStage( stageName ).getRegions();
|
|
}
|
|
|
|
validateRegionExists( stageName, regionName ){
|
|
let stage = this.getStage( stageName );
|
|
|
|
if( stage ){
|
|
return stage.hasRegion( regionName );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
getVariables() {
|
|
return this.variables;
|
|
}
|
|
}
|
|
|
|
module.exports = Project; |