UNPKG

serverless-sam

Version:

Serverless framework plugin to export AWS SAM templates for a service

225 lines (197 loc) 7.1 kB
/* * Copyright 2017 Stefano Buliani (@sapessi) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; const path = require('path'); const fs = require('fs'); const BbPromise = require('bluebird'); const SamGenerator = require('./lib/SamGenerator'); const utils = require('./lib/utils') const SERVERLESS_FILE_NAME = 'serverless.yml'; const ERROR_MISSING_SERVERLESS_FILE = "Could not find " + SERVERLESS_FILE_NAME; const ERROR_MISSING_OUTPUT_OPTION = "Missing output option"; const ERROR_MISSING_OUTPUT_DIR = "Output directory for SAM template does not exist"; /** * Main SAM plugin object. Defines the sam and export commands. The lifecycle events exposed by this plugin are * validate and export. */ class SamPlugin { constructor(serverless, options) { this.serverless = serverless; this.options = options; this.writeFile = BbPromise.promisify(fs.writeFile); this.samGenerator = new SamGenerator(this.serverless); this.errorStrings = { MissingServerlessFile: ERROR_MISSING_SERVERLESS_FILE, MissingOutputOption: ERROR_MISSING_OUTPUT_OPTION, MissingOutputDir: ERROR_MISSING_OUTPUT_DIR }; this.commands = { sam: { commands: { export: { usage: 'Creates a Serverless Application Model (SAM) template from your serverless app definition', lifecycleEvents: [ 'validate', 'export', ], options: { output: { usage: 'Specify the output file name ' + '(e.g. "--output ./sam-template.yml" or "-o ./sam-template.yml")', required: true, shortcut: 'o', }, }, } } } }; this.hooks = { 'sam:export:validate': () => BbPromise.bind(this) .then(this.validateOptions) .then(this.validateDefinition), 'before:sam:export:export': () => BbPromise.bind(this) .then(this.prepareTemplate) .then(this.packageFunctions), 'sam:export:export': () => BbPromise.bind(this) .then(this.exportSam) .then(this.writeSamTemplate) }; } /** * Checks that the serverless.yml file exists in the local folder that the --output option * points to an existing folder. */ validateOptions() { return new BbPromise((resolve, reject) => { this.serverless.cli.log("Working folder: " + __dirname); const yamlFileName = path.join(process.cwd(), SERVERLESS_FILE_NAME); if (!fs.existsSync(yamlFileName)) { reject(new Error(ERROR_MISSING_SERVERLESS_FILE)); } if (!this.serverless.providers.aws.options || !this.serverless.providers.aws.options.output) { reject(new Error(ERROR_MISSING_OUTPUT_OPTION)); } if (!fs.existsSync(path.dirname(this.serverless.providers.aws.options.output))) { reject(new Error(ERROR_MISSING_OUTPUT_DIR)); } resolve(); }); } /** * Uses the Serverless frameowkr to validate the current definiton */ validateDefinition() { return new BbPromise((resolve, reject) => { try { this.serverless.cli.log("Validate"); this.serverless.service.load(); this.serverless.service.validate(); resolve(); } catch (err) { reject(err); } }); } /** * Loads the Package plugin and uses it to create the deployment package for all * Lambda functions in the service. */ packageFunctions() { const plugin = this.getPlugin("Package"); if (!plugin) { throw new Error("Could not find Package plugin"); } this.serverless.cli.log("Packaging functions"); return new BbPromise.bind(plugin) .then(plugin.cleanup) .then(plugin.validate) .then(plugin.packageService); } /** * Uses the AwsDeploy plugin to create the compiledCloudFormationTemplate in the * serverless framework object. */ prepareTemplate() { // latest version of serverless const plugin = this.getPlugin("AwsPackage"); if (!plugin) { throw new Error("Could not find AwsDeploy plugin"); } this.serverless.cli.log("Preparing original CloudFormation template"); this.serverless.variables.populateService(this.serverless.pluginManager.cliOptions); // remove deployment bucket settings before we start working on the template. We do not need to trigger // a deployment or any calls to S3 if (this.serverless.service.provider.deploymentBucket) { delete this.serverless.service.provider.deploymentBucket; } return new BbPromise.bind(plugin) .then(plugin.generateCoreTemplate) .then(plugin.mergeIamTemplates) .then(plugin.generateArtifactDirectoryName) .then(plugin.mergeCustomProviderResources) .then(plugin.saveServiceState) .then(plugin.saveCompiledTemplate); /*const plugin = this.getPlugin("AwsDeploy"); if (!plugin) { throw new Error("Could not find AwsDeploy plugin"); } this.serverless.cli.log("Preparing original CloudFormation template"); this.serverless.variables.populateService(this.serverless.pluginManager.cliOptions); return new BbPromise.bind(plugin) .then(plugin.validate) .then(plugin.configureStack) .then(plugin.mergeIamTemplates) .then(plugin.generateArtifactDirectoryName) .then(plugin.mergeCustomProviderResources);*/ } /** * Loads a plugin of the Serverless framework given the plugin name. For example, AwsDeploy * @param {String} name Plugin name */ getPlugin(name) { for (let plugin of this.serverless.pluginManager.getPlugins()) { if (plugin.constructor.name === name) { return plugin; } } return null; } /** * Saves the generated SAM template in the local samTemplate variable */ exportSam() { return new BbPromise((resolve, reject) => { this.serverless.cli.log('Export:'); try { this.samTemplate = this.samGenerator.generate(); resolve(this.samTemplate); } catch (err) { reject(err); } }); } /** * Writes the SAM template string to the local files specified by the --output option */ writeSamTemplate() { const writeFilePromise = this.writeFile(this.serverless.providers.aws.options.output, this.samTemplate); this.serverless.cli.log("SAM template written to: " + path.resolve(this.serverless.providers.aws.options.output)); return writeFilePromise; } } module.exports = SamPlugin;