UNPKG

pancakes-syrup

Version:

Deployment build tasks for pancakes projects

286 lines (249 loc) 6.98 kB
/** * Author: Jeff Whelpley * Date: 5/12/15 * * Common AWS functions that we want to share among tasks */ var _ = require('lodash'); var Q = require('q'); var AWS = require('aws-sdk'); // help determine if environment variable is secure var secureHints = ['KEY', 'SECRET', 'TOKEN', 'URL', 'PWD', 'PASSWORD', 'JWT']; /** * Get a reference to the opsworks object * @param awsConfig */ function getOpsworks(awsConfig) { return new AWS.OpsWorks({ accessKeyId: awsConfig.keyId, secretAccessKey: awsConfig.secret, region: awsConfig.uploads && awsConfig.uploads.region }); } /** * Get the instance ids for a particular layer * @param target [web|api] * @param awsConfig */ function getInstanceIds(target, awsConfig) { var deferred = Q.defer(); var params = {}; switch (target) { case 'web': params.LayerId = awsConfig.webLayerId; break; case 'api': params.LayerId = awsConfig.apiLayerId; break; case 'batch': params.LayerId = awsConfig.batchLayerId; break; default: return new Q(); } var opsworks = getOpsworks(awsConfig); opsworks.describeInstances(params, function (err, data) { if (err) { deferred.reject(err); } else if (!data || !data.Instances) { deferred.resolve(); } else { deferred.resolve(data.Instances.map(function (instance) { return instance.InstanceId; })); } err ? deferred.reject(err) : deferred.resolve(data); }); return deferred.promise; } /** * Run one of the createDeployment commands. * @param commandParams * @param target * @param awsConfig */ function runCommand(commandParams, target, awsConfig) { var deferred = Q.defer(); commandParams = commandParams || {}; commandParams.StackId = awsConfig.stackId; getInstanceIds(target, awsConfig) .then(function (instanceIds) { if (instanceIds) { commandParams.InstanceIds = instanceIds; } var opsworks = getOpsworks(awsConfig); opsworks.createDeployment(commandParams, function (err, data) { err ? deferred.reject(err) : deferred.resolve(data); }); }) .catch(function (err) { deferred.reject(err); }); return deferred.promise; } /** * Determine if an environment key should be secure or not * @param envKey * @returns {boolean} */ function isSecure(envKey) { var i, secureHint; for (i = 0; i < secureHints.length; i++) { secureHint = secureHints[i]; if (envKey.indexOf(secureHint) > -1) { return true; } } return false; } /** * Conver the command line environment vars (i.e. --vars="blah=foo,choo=moo") * into custom JSON. * * @param envVars Name/value pairs from the command line (ex. blah=boo) */ function getEnvVarsJson(envVars) { envVars = envVars || ''; var json = {}; // if string need to convert to an object if (_.isString(envVars)) { var keyValues = envVars.split(',') || []; _.each(keyValues, function (keyValue) { var keyValArr = keyValue.split(':'); var key = keyValArr[0]; json[key] = keyValArr[1]; }); } else { json = envVars; } return JSON.stringify({ deploy: { app: { 'environment_variables': json } } }); } /** * Update the cookbooks * @param target * @param awsConfig * @returns {*} */ function updateCookbooks(target, awsConfig) { var params = { Command: { Name: 'update_custom_cookbooks' } }; return runCommand(params, target, awsConfig); } /** * Execute a given set of recipes * @param recipeNames * @param json * @param target * @param awsConfig * @returns {*} */ function execRecipes(recipeNames, json, target, awsConfig) { if (!recipeNames) { return Q.reject('No recipe names specified'); } var recipes = recipeNames.split(','); var params = { Command: { Name: 'execute_recipes', Args: { recipes: recipes } } }; if (json) { params.CustomJson = json; } return runCommand(params, target, awsConfig); } /** * Update environment variables for a given app * * @param newVars From command line * @param envVars From config * @param awsConfig */ function updateEnvironmentVariables(newVars, envVars, awsConfig) { var deferred = Q.defer(); var env = []; // create an array of environment variables _.each(envVars, function (val, key) { var secure = isSecure(key); if (key !== 'GOOGLE_KEY' && key !== 'type' && val) { env.push({ Key: key, Value: val + '', Secure: secure }); } }); _.each(newVars, function (val, key) { env.push({ Key: key, Value: val + '' }); }); // set up the params for updateApp var params = { AppId: awsConfig.appId, Environment: env }; var opsworks = getOpsworks(awsConfig); opsworks.updateApp(params, function (err, data) { err ? deferred.reject(err) : deferred.resolve(data); }); return deferred.promise; } /** * Deploy app * @param vars * @param target * @param awsConfig * @returns {*} */ function deploy(vars, target, awsConfig) { var params = { Command: { Name: 'deploy' }, AppId: awsConfig.appId, CustomJson: getEnvVarsJson(vars) }; return runCommand(params, target, awsConfig); } /** * Rollback the last deployment * @param target * @param awsConfig * @returns {*} */ function rollbackDeployment(target, awsConfig) { var params = { Command: { Name: 'rollback' }, AppId: awsConfig.appId }; return runCommand(params, target, awsConfig); } /** * Restart an app (changing environment variables if passed in) * Note that we use the pm2 recipe instead of deploy::nodejs-restart * because the pm2 recipe will also update all the environment * variables which is needed when we modify them during deployment. * * @param vars * @param target * @param awsConfig * @returns {*} */ function restartApp(vars, target, awsConfig) { var params = { Command: { Name: 'execute_recipes', Args: { recipes: ['pm2'] } }, CustomJson: getEnvVarsJson(vars) }; return runCommand(params, target, awsConfig); } // expose functions for testing module.exports = { getOpsworks: getOpsworks, getInstanceIds: getInstanceIds, runCommand: runCommand, isSecure: isSecure, getEnvVarsJson: getEnvVarsJson, updateCookbooks: updateCookbooks, execRecipes: execRecipes, updateEnvironmentVariables: updateEnvironmentVariables, deploy: deploy, rollbackDeployment: rollbackDeployment, restartApp: restartApp };