From 786036b4ca7d20c97d223c4e0098a361da49251e Mon Sep 17 00:00:00 2001 From: dcook Date: Wed, 20 May 2015 16:55:56 -0400 Subject: [PATCH 01/13] making changes, adding update-cookbooks, deploy --- config.json | 18 +- lib/fetcher.js | 115 +++++--- opsworks-cli.js | 722 +++++++++++++++++++++++++++++------------------- package.json | 4 +- 4 files changed, 516 insertions(+), 343 deletions(-) diff --git a/config.json b/config.json index 56d5369..5145b96 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,12 @@ { - "ssh":{ - "options":{ - "StrictHostKeyChecking":"yes" - }, - "identity": "~/.ssh/some_key.pem" - } -} + "ssh": { + "options": { + "StrictHostKeyChecking": "yes" + }, + "identity": "~/.ssh/some_key.pem", + "username": "ubuntu" + }, + "aws": { + "region": "us-east-1" + } +} \ No newline at end of file diff --git a/lib/fetcher.js b/lib/fetcher.js index f90b437..5afbcaf 100644 --- a/lib/fetcher.js +++ b/lib/fetcher.js @@ -1,6 +1,7 @@ var fetcher = {}; var AWS = require('aws-sdk'); +var _ = require('lodash'); //=============================================== // Begin Configuration @@ -9,12 +10,16 @@ var AWS = require('aws-sdk'); var AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID; var AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY; -if(typeof AWS_ACCESS_KEY_ID == 'undefined' || typeof AWS_SECRET_ACCESS_KEY == 'undefined'){ +if (typeof AWS_ACCESS_KEY_ID == 'undefined' || typeof AWS_SECRET_ACCESS_KEY == 'undefined') { console.log("AWS credentials must be set"); process.exit(1); } -var awsOptions = { "accessKeyId": AWS_ACCESS_KEY_ID, "secretAccessKey": AWS_SECRET_ACCESS_KEY, "region": "us-east-1" }; +var awsOptions = { + "accessKeyId": AWS_ACCESS_KEY_ID, + "secretAccessKey": AWS_SECRET_ACCESS_KEY, + "region": "us-east-1" +}; AWS.config.update(awsOptions); fetcher.AWS = AWS; @@ -26,97 +31,115 @@ var ec2 = new AWS.EC2(); // End Configuration //=============================================== -fetcher.getStackId = function(params, callback){ - opsworks.describeStacks(function(error, data){ - if(error){ +fetcher.getStackId = function(params, callback) { + opsworks.describeStacks(function(error, data) { + if (error) { console.log(error); - } - else{ - for(var i=0; i', 'The location of the key to use') -.option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') -.action(function(stack, layer, options){ - if(typeof options.hostname != 'undefined'){ - } - console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); - - fetcher.getLayerId({StackName:stack, LayerName:layer}, function(StackId, LayerId){ - if(LayerId==null){ - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({LayerId:LayerId}, function(error, data){ - if(error){ - console.log(error); + .description('Log into a single instance or an entire layer') + .option('-i, --identity ', 'The location of the key to use') + .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') + .action(function(stack, layer, options) { + if (typeof options.hostname != 'undefined') {} + console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); + + fetcher.getLayerId({ + StackName: stack, + LayerName: layer + }, function(StackId, LayerId) { + if (LayerId == null) { + console.log('Layer ' + layer + ' not found'); + process.exit(1); } - else{ - var hosts = new Array(); - for(var i=0; i Date: Wed, 24 Jun 2015 16:58:51 -0400 Subject: [PATCH 02/13] adding in some describe-deployment fun --- opsworks-cli.js | 59 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/opsworks-cli.js b/opsworks-cli.js index 68860d9..ba7e340 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -66,11 +66,19 @@ app.command('describe [stack]') app.command('list [stack] [layer]') .description('List the instances in a layer') .action(function(stack, layer, options) { + + if(typeof layer == "undefined"){ + layer = stack; + stack = config.get('stack'); + } fetcher.getLayerId({ StackName: stack, LayerName: layer }, function(StackId, LayerId) { + + + if (LayerId == null) { console.log('Layer ' + layer + ' not found'); process.exit(1); @@ -168,14 +176,13 @@ app.command('ssh2 [stack] [layer]') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') .action(function(stack, layer, options) { if (typeof options.hostname != 'undefined') {} - console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); - console.log(stack); if(typeof layer == "undefined"){ layer = stack; stack = config.get('stack'); } - console.log(layer); - + + console.log('Creating an SSH connection to first instance on %s::%s', stack, layer); + fetcher.getLayerId({ StackName: stack, LayerName: layer @@ -233,7 +240,7 @@ app.command('ssh2 [stack] [layer]') } var sshCommand = "ssh " + sshOptionsString + " -i " + keyToUse + " " + ssh_username + '@' + hosts[0]; - + console.log(sshCommand); exec_sh(sshCommand); } }); @@ -503,9 +510,49 @@ app.command('update-cookbooks [stack]') else console.log(data); // successful response }); }); + }); + +app.command('describe-deployments [deploymentId]') + .description('Updates the custom cookbooks within a stack') + .action(function(deploymentId, options) { + var stack = config.get('stack'); + fetcher.getStackId({ + StackName: stack + }, function(StackId) { + var _params = { + // DeploymentIds: [ + // '71796665-e306-42c9-a0be-b5f1f5201acf' + // ], + StackId: StackId + // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] + }; + opsworks.describeDeployments(_params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data); // successful response + }); + }); + }); +app.command('describe-deployment [deploymentId]') + .description('Updates the custom cookbooks within a stack') + .action(function(deploymentId, options) { + var stack = config.get('stack'); - // console.log('NOT IMPLEMENTED:\tUpdating custom cookbooks in %s::%s', stack, layer); + fetcher.getStackId({ + StackName: stack + }, function(StackId) { + var _params = { + // DeploymentIds: [ + // '71796665-e306-42c9-a0be-b5f1f5201acf' + // ], + StackId: StackId + // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] + }; + opsworks.describeDeployments(_params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data.Deployments[0]); // successful response + }); + }); }); app.command('exec-recipe [recipe] [stack] [layer]') From 202a96d6a91836af41a2f4b0426ae4aac9d99584 Mon Sep 17 00:00:00 2001 From: dcook Date: Wed, 24 Jun 2015 17:06:04 -0400 Subject: [PATCH 03/13] config without arguments now displays the current config --- opsworks-cli.js | 1 + 1 file changed, 1 insertion(+) diff --git a/opsworks-cli.js b/opsworks-cli.js index ba7e340..7ef5d9a 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -253,6 +253,7 @@ app.command('config [key] [value]') if (key === undefined || value === undefined) { console.log('A key and value must be defined'); + console.log(config.get()); process.exit(1); } From 444b51316a1afd87e99db47a79c9f66235066042 Mon Sep 17 00:00:00 2001 From: dcook Date: Tue, 22 Sep 2015 10:55:22 -0400 Subject: [PATCH 04/13] adding config manager, using stacks via config --- lib/config.js | 42 ++++++++++++ lib/fetcher.js | 25 +++---- lib/util.js | 4 +- opsworks-cli.js | 170 +++++++++++++++++++----------------------------- 4 files changed, 120 insertions(+), 121 deletions(-) create mode 100644 lib/config.js diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..98a7510 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,42 @@ +var config = require('nconf'); +var fs = require('fs'); + +var USER_CONFIG_FILE = process.env.HOME + '/.opsworks_cli_config.json'; + +config + .env() + .argv() + .file({ + file: USER_CONFIG_FILE + }) + .defaults({ + 'stack': config.get('default_stack') + }); +var profile = (config.get('stacks:'+config.get('stack')+':profile'))? config.get('stacks:'+config.get('stack')+':profile') : 'default'; + +config.set('profile', profile); +config.update = function(key, value, options) { + + if (key === undefined || value === undefined) { + console.log('A key and value must be defined'); + console.log(config.get()); + process.exit(1); + } + + key = key.replace('.', ':'); + config.set(key, value); + + config.save(function(err) { + fs.readFile(USER_CONFIG_FILE, function(err, data) { + console.dir(JSON.parse(data.toString())); + }); + if (err) { + console.log('Config file could not be saved'); + console.log(err.message); + } else { + console.log('Config file updated'); + } + }); +}; + +module.exports = config; \ No newline at end of file diff --git a/lib/fetcher.js b/lib/fetcher.js index 5afbcaf..ddcecd6 100644 --- a/lib/fetcher.js +++ b/lib/fetcher.js @@ -3,26 +3,19 @@ var fetcher = {}; var AWS = require('aws-sdk'); var _ = require('lodash'); +var config = require('./config'); + + //=============================================== // Begin Configuration //=============================================== -var AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID; -var AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY; - -if (typeof AWS_ACCESS_KEY_ID == 'undefined' || typeof AWS_SECRET_ACCESS_KEY == 'undefined') { - console.log("AWS credentials must be set"); - process.exit(1); -} - var awsOptions = { - "accessKeyId": AWS_ACCESS_KEY_ID, - "secretAccessKey": AWS_SECRET_ACCESS_KEY, - "region": "us-east-1" + "region": config.get('aws:region') }; AWS.config.update(awsOptions); -fetcher.AWS = AWS; +// console.log(AWS.config.credentials); var opsworks = new AWS.OpsWorks(); var ec2 = new AWS.EC2(); @@ -72,7 +65,7 @@ fetcher.getLayerId = function(params, callback) { fetcher.getStackId({ StackName: params.StackName }, function(StackId) { - if (StackId == null) { + if (StackId === null) { console.log('Stack ' + params.StackName + ' not found'); process.exit(1); } @@ -106,7 +99,7 @@ fetcher.getInstance = function(params, callback) { }); } else if (typeof params.StackName != 'undefined' && typeof params.LayerName != 'undefined') { fetcher.getLayerId(params, function(LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + params.LayerName + ' not found'); process.exit(1); } @@ -128,7 +121,7 @@ fetcher.getAvailabilityZones = function(callback) { callback(data); } }); -} +}; fetcher.getAppId = function(params, callback) { if (typeof params.StackId != 'undefined' && typeof params.AppName != 'undefined') { @@ -140,6 +133,6 @@ fetcher.getAppId = function(params, callback) { callback(_.pluck(_.filter(data.Apps, {'Name': params.AppName}), 'AppId')[0]); }); } -} +}; module.exports = fetcher; \ No newline at end of file diff --git a/lib/util.js b/lib/util.js index a358edf..d0927da 100644 --- a/lib/util.js +++ b/lib/util.js @@ -29,7 +29,7 @@ util.validateAvailabilityZone = function(availabilityZone, callback){ }; util.validateUUID = function(uuid){ - var rgx = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/ + var rgx = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; return rgx.test(uuid); }; @@ -76,6 +76,6 @@ util.createInstance = function(StackId, LayerId, AvailabilityZone, options){ } } }); -} +}; module.exports = util; \ No newline at end of file diff --git a/opsworks-cli.js b/opsworks-cli.js index 7ef5d9a..cc1a8ca 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -1,48 +1,41 @@ // Third-Party Dependencies + + + var app = require('commander'); -var AWS = require('aws-sdk'); var exec_sh = require('exec-sh'); // Node Stuff var fs = require('fs'); -var config = require('nconf'); // Internal Dependencies -// var config = require('./config.json'); -var out = require('./lib/out'); -var util = require('./lib/util') -var fetcher = require('./lib/fetcher'); - -var AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID; -var AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY; -var USER_CONFIG_FILE = process.env.HOME + '/.opsworks_cli_config.json'; +var config = require('./lib/config'); +process.env.AWS_PROFILE = config.get('profile'); -config.argv() - .env() - .file({ - file: USER_CONFIG_FILE - }) - .defaults(require('./config.json')); +var AWS = require('aws-sdk'); -if (AWS_ACCESS_KEY_ID === undefined || AWS_SECRET_ACCESS_KEY === undefined) { - console.log("AWS credentials must be set"); - process.exit(1); -} +var out = require('./lib/out'); +var util = require('./lib/util'); +var fetcher = require('./lib/fetcher'); var awsOptions = { - "accessKeyId": AWS_ACCESS_KEY_ID, - "secretAccessKey": AWS_SECRET_ACCESS_KEY, - "region": config.get('aws:region') + "region": config.get('aws:region'), + "profile": config.get('profile') }; + AWS.config.update(awsOptions); var opsworks = new AWS.OpsWorks(); -app.version(require('./package.json').version); +app + .version(require('./package.json').version) + .option('-s, --stack ', 'The stack to use'); + app.command('describe [stack]') .description('List the layers in a stack') .action(function(stack, options) { + // console.log(config); stack = (stack) ? stack : config.get('stack'); fetcher.getStackId({ @@ -55,6 +48,7 @@ app.command('describe [stack]') if (error) { console.log(error); } else { + console.log(stack); data.Layers.forEach(function(layer, index, layers) { out.layerOverview(layer); }); @@ -66,8 +60,8 @@ app.command('describe [stack]') app.command('list [stack] [layer]') .description('List the instances in a layer') .action(function(stack, layer, options) { - - if(typeof layer == "undefined"){ + + if (typeof layer == "undefined") { layer = stack; stack = config.get('stack'); } @@ -76,10 +70,10 @@ app.command('list [stack] [layer]') StackName: stack, LayerName: layer }, function(StackId, LayerId) { - - - - if (LayerId == null) { + + + + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -110,7 +104,7 @@ app.command('ssh [stack] [layer]') StackName: stack, LayerName: layer }, function(StackId, LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -121,7 +115,7 @@ app.command('ssh [stack] [layer]') if (error) { console.log(error); } else { - var hosts = new Array(); + var hosts = []; for (var i = 0; i < data.Instances.length; i++) { var instance = data.Instances[i]; if (instance.Status == 'online') { @@ -176,18 +170,18 @@ app.command('ssh2 [stack] [layer]') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') .action(function(stack, layer, options) { if (typeof options.hostname != 'undefined') {} - if(typeof layer == "undefined"){ + if (typeof layer == "undefined") { layer = stack; stack = config.get('stack'); } - + console.log('Creating an SSH connection to first instance on %s::%s', stack, layer); - + fetcher.getLayerId({ StackName: stack, LayerName: layer }, function(StackId, LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -198,7 +192,7 @@ app.command('ssh2 [stack] [layer]') if (error) { console.log(error); } else { - var hosts = new Array(); + var hosts = []; for (var i = 0; i < data.Instances.length; i++) { var instance = data.Instances[i]; if (instance.Status == 'online') { @@ -249,39 +243,7 @@ app.command('ssh2 [stack] [layer]') app.command('config [key] [value]') .description('Update settings in the OpsWorks config file') - .action(function(key, value, options) { - - if (key === undefined || value === undefined) { - console.log('A key and value must be defined'); - console.log(config.get()); - process.exit(1); - } - - key = key.replace('.', ':'); - config.set(key, value); - - config.save(function(err) { - fs.readFile(USER_CONFIG_FILE, function(err, data) { - console.dir(JSON.parse(data.toString())) - }); - if (err) { - console.log('Config file could not be saved'); - console.log(err.message); - } else { - console.log('Config file updated'); - } - }); - - // fs.writeFile(__dirname+'/config.json', JSON.stringify(config, null, '\t'), function(err){ - // if(err){ - // console.log('Config file could not be saved'); - // console.log(err.message); - // } - // else{ - // console.log('Config file updated'); - // } - // }); - }); + .action(config.update); app.command('add [stack] [layer]') .description('Add one or more instances to a layer') @@ -315,7 +277,7 @@ app.command('add [stack] [layer]') StackName: stack, LayerName: layer }, function(StackId, LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -344,7 +306,7 @@ app.command('add [stack] [layer]') console.log("Starting " + options.count + " in distributed mode"); fetcher.getAvailabilityZones(function(data) { - var zones = new Array(); + var zones = []; for (var i = 0; i < data.AvailabilityZones.length; i++) { zones.push(data.AvailabilityZones[i].ZoneName); } @@ -371,7 +333,7 @@ app.command('stop [stack] [layer]') StackName: stack, LayerName: layer }, function(StackId, LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -382,7 +344,13 @@ app.command('stop [stack] [layer]') if (error) { console.log(error); } else { - var hosts = new Array(); + var hosts = []; + var stopInstanceHandler = function(error, data) { + if (error) { + console.log('Failed to stop instance %s (%s)', instance.Hostname, instance.InstanceId); + process.exit(1); + } + }; for (var i = 0; i < data.Instances.length; i++) { var instance = data.Instances[i]; if (options.all || instance.Hostname.indexOf(options.prefix) === 0) { @@ -390,12 +358,7 @@ app.command('stop [stack] [layer]') console.log("Stopping %s", instance.Hostname); opsworks.stopInstance({ InstanceId: instance.InstanceId - }, function(error, data) { - if (error) { - console.log('Failed to stop instance %s (%s)', instance.Hostname, instance.InstanceId); - process.exit(1); - } - }); + }, stopInstanceHandler); } } } @@ -417,7 +380,7 @@ app.command('delete [stack] [layer]') StackName: stack, LayerName: layer }, function(StackId, LayerId) { - if (LayerId == null) { + if (LayerId === null) { console.log('Layer ' + layer + ' not found'); process.exit(1); } @@ -428,7 +391,13 @@ app.command('delete [stack] [layer]') if (error) { console.log(error); } else { - var hosts = new Array(); + var hosts = []; + var deleteInstanceHandler = function(error, data) { + if (error) { + console.log('Failed to delete instance %s (%s)', instance.Hostname, instance.InstanceId); + process.exit(1); + } + }; for (var i = 0; i < data.Instances.length; i++) { var instance = data.Instances[i]; @@ -438,12 +407,7 @@ app.command('delete [stack] [layer]') opsworks.deleteInstance({ InstanceId: instance.InstanceId - }, function(error, data) { - if (error) { - console.log('Failed to delete instance %s (%s)', instance.Hostname, instance.InstanceId); - process.exit(1); - } - }); + }, deleteInstanceHandler); } } } @@ -481,7 +445,7 @@ app.command('deploy [app] [stack] [layer]') if (err) console.log(err, err.stack); // an error occurred else console.log(data); // successful response }); - }) + }); }); }); @@ -522,15 +486,15 @@ app.command('describe-deployments [deploymentId]') StackName: stack }, function(StackId) { var _params = { - // DeploymentIds: [ - // '71796665-e306-42c9-a0be-b5f1f5201acf' - // ], - StackId: StackId - // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] + // DeploymentIds: [ + // '71796665-e306-42c9-a0be-b5f1f5201acf' + // ], + StackId: StackId + // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] }; opsworks.describeDeployments(_params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data); // successful response + if (err) console.log(err, err.stack); // an error occurred + else console.log(data); // successful response }); }); }); @@ -543,15 +507,15 @@ app.command('describe-deployment [deploymentId]') StackName: stack }, function(StackId) { var _params = { - // DeploymentIds: [ - // '71796665-e306-42c9-a0be-b5f1f5201acf' - // ], - StackId: StackId - // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] + // DeploymentIds: [ + // '71796665-e306-42c9-a0be-b5f1f5201acf' + // ], + StackId: StackId + // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] }; opsworks.describeDeployments(_params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data.Deployments[0]); // successful response + if (err) console.log(err, err.stack); // an error occurred + else console.log(data.Deployments[0]); // successful response }); }); }); From 37fabea795e6c6831fe954e844692e0af83e8399 Mon Sep 17 00:00:00 2001 From: dcook Date: Thu, 24 Sep 2015 10:09:01 -0400 Subject: [PATCH 05/13] starting addLayers, not working --- lib/commands.js | 31 ++++++++++++++++++++++++++++ opsworks-cli.js | 48 ++++++++++++++++++++----------------------- package.json | 54 +++++++++++++++++++++++++------------------------ 3 files changed, 81 insertions(+), 52 deletions(-) create mode 100644 lib/commands.js diff --git a/lib/commands.js b/lib/commands.js new file mode 100644 index 0000000..34a4087 --- /dev/null +++ b/lib/commands.js @@ -0,0 +1,31 @@ +"use strict"; + +let fs = require('q-io/fs'); +var AWS = require('aws-sdk'); +var Promise = require('bluebird'); +let fetcher = Promise.promisifyAll(require('./fetcher')); + +var config = require('./config'); + +class Commands{ + + static addLayer(jsonFile){ + let _file = process.cwd()+'/'+jsonFile; + + let file = fs.exists(_file).then(function(result){ + if(result){ + return file; + } + }); + + // let stackId = fetcher. + fetcher.getStackId({ + StackName: config.get('stack') + }, function(StackId) { + console.log(StackId); + }); + } +} + + +module.exports = Commands; \ No newline at end of file diff --git a/opsworks-cli.js b/opsworks-cli.js index cc1a8ca..1e23281 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -17,6 +17,7 @@ var AWS = require('aws-sdk'); var out = require('./lib/out'); var util = require('./lib/util'); var fetcher = require('./lib/fetcher'); +// var fetcher = require('./lib/commands'); var awsOptions = { "region": config.get('aws:region'), @@ -32,11 +33,10 @@ app .option('-s, --stack ', 'The stack to use'); -app.command('describe [stack]') +app.command('describe') .description('List the layers in a stack') - .action(function(stack, options) { - // console.log(config); - stack = (stack) ? stack : config.get('stack'); + .action(function(options) { + var stack = config.get('stack'); fetcher.getStackId({ StackName: stack @@ -57,15 +57,11 @@ app.command('describe [stack]') }); }); -app.command('list [stack] [layer]') +app.command('list [layer]') .description('List the instances in a layer') .action(function(stack, layer, options) { - - if (typeof layer == "undefined") { - layer = stack; - stack = config.get('stack'); - } - + stack = config.get('stack'); + fetcher.getLayerId({ StackName: stack, LayerName: layer @@ -92,16 +88,16 @@ app.command('list [stack] [layer]') }); }); -app.command('ssh [stack] [layer]') +app.command('ssh [layer]') .description('Log into a single instance or an entire layer') .option('-i, --identity ', 'The location of the key to use') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') - .action(function(stack, layer, options) { + .action(function(layer, options) { if (typeof options.hostname != 'undefined') {} console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); fetcher.getLayerId({ - StackName: stack, + StackName: config.get('stack'), LayerName: layer }, function(StackId, LayerId) { if (LayerId === null) { @@ -164,17 +160,15 @@ app.command('ssh [stack] [layer]') }); }); -app.command('ssh2 [stack] [layer]') +app.command('ssh2 [layer]') .description('Log into a single instance or an entire layer') .option('-i, --identity ', 'The location of the key to use') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') - .action(function(stack, layer, options) { + .action(function(layer, options) { + stack = config.get('stack'); + if (typeof options.hostname != 'undefined') {} - if (typeof layer == "undefined") { - layer = stack; - stack = config.get('stack'); - } - + console.log('Creating an SSH connection to first instance on %s::%s', stack, layer); fetcher.getLayerId({ @@ -211,8 +205,6 @@ app.command('ssh2 [stack] [layer]') } } - //console.log("Reaching out to %s hosts", hosts.length); - // Start the options string with a space so it doesn't collide with the preceding argument var sshOptionsString = " "; var sshOpts = config.get('ssh:options'); @@ -456,10 +448,10 @@ app.command('undeploy [app] [stack] [layer]') console.log('NOT IMPLEMENTED:\tUndeploying %s from %s::%s', app, stack, layer); }); -app.command('update-cookbooks [stack]') +app.command('update-cookbooks') .description('Updates the custom cookbooks within a stack') - .action(function(stack, options) { - stack = (stack) ? stack : config.get('stack'); + .action(function(options) { + stack = config.get('stack'); fetcher.getStackId({ StackName: stack @@ -525,6 +517,10 @@ app.command('exec-recipe [recipe] [stack] [layer]') .action(function(recipe, stack, layer, options) { console.log('NOT IMPLEMENTED:\tExecuting recipe %s on %s::%s', recipe, stack, layer); }); +// +// app.command('add-layer [jsonFile]') +// .description('Add a layer to a stack based on a json file') +// .action(commands.addLayer); // Process the arguments (This needs to happen after all of the commands are declared) app.parse(process.argv); \ No newline at end of file diff --git a/package.json b/package.json index 1a30072..93ad56a 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,29 @@ { - "name": "opsworks-cli", - "version": "0.1.1", - "author": "Skye Book ", - "description": "Perform common OpsWorks tasks from the command line", - "repository":{ - "type":"git", - "url":"https://github.com/skyebook/opsworks-cli" - }, - "keywords": [ - "AWS", - "OpsWorks", - "Chef", - "CLI" - ], - "bin":{ - "opsworks":"./bin/opsworks" - }, - "dependencies": { - "aws-sdk": "1.10.0", - "commander": "2.0.0", - "exec-sh": "0.1.3", - "nconf": "~0.7.0", - "lodash": "*" - }, - "license": "MIT" -} \ No newline at end of file + "name": "opsworks-cli", + "version": "0.1.1", + "author": "Skye Book ", + "description": "Perform common OpsWorks tasks from the command line", + "repository": { + "type": "git", + "url": "https://github.com/skyebook/opsworks-cli" + }, + "keywords": [ + "AWS", + "OpsWorks", + "Chef", + "CLI" + ], + "bin": { + "opsworks": "./bin/opsworks" + }, + "dependencies": { + "aws-sdk": "1.10.0", + "bluebird": "^2.10.1", + "commander": "2.0.0", + "exec-sh": "0.1.3", + "lodash": "*", + "nconf": "~0.7.0", + "q-io": "*" + }, + "license": "MIT" +} From dacc00dbd19adadfaba12f55bb4bb9d90840bf80 Mon Sep 17 00:00:00 2001 From: dcook Date: Thu, 24 Sep 2015 14:22:29 -0400 Subject: [PATCH 06/13] add-layer and add-app working --- lib/commands.js | 66 ++++++++++++++++++++++++++++++++++++++----------- lib/fetcher.js | 14 +++++++++++ opsworks-cli.js | 14 +++++++---- package.json | 4 +-- 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 34a4087..22cc322 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -2,30 +2,68 @@ let fs = require('q-io/fs'); var AWS = require('aws-sdk'); -var Promise = require('bluebird'); -let fetcher = Promise.promisifyAll(require('./fetcher')); +var P2 = require('bluebird'); +let fetcher = require('./fetcher'); var config = require('./config'); -class Commands{ +var opsworks = new AWS.OpsWorks(); +P2.promisifyAll(Object.getPrototypeOf(opsworks)); + +class Commands { + + static addLayer(jsonFile) { + let _file = process.cwd() + '/' + jsonFile; + let file = fs.exists(_file).then(function(result) { + if (result) { + return _file; + } + }).then(function(file) { + return fs.read(file).then(JSON.parse); + }); + + let stackID = fetcher.getStackIdAsync({ + StackName: config.get('stack') + }).then(function(StackId) { + return StackId; + }); + + Promise.all([file, stackID]).then(function(args) { + let layerConfig = args[0]; + layerConfig.StackId = args[1]; + + return opsworks.createLayerAsync(layerConfig).then(logger).catch(logger); + }); + } - static addLayer(jsonFile){ - let _file = process.cwd()+'/'+jsonFile; - - let file = fs.exists(_file).then(function(result){ - if(result){ - return file; + static addApp(jsonFile) { + let _file = process.cwd() + '/' + jsonFile; + let file = fs.exists(_file).then(function(result) { + if (result) { + return _file; } + }).then(function(file) { + return fs.read(file).then(JSON.parse); }); - - // let stackId = fetcher. - fetcher.getStackId({ + + let stackID = fetcher.getStackIdAsync({ StackName: config.get('stack') - }, function(StackId) { - console.log(StackId); + }).then(function(StackId) { + return StackId; + }); + + Promise.all([file, stackID]).then(function(args) { + let layerConfig = args[0]; + layerConfig.StackId = args[1]; + + return opsworks.createAppAsync(layerConfig).then(logger).catch(logger); }); } } +function logger(e) { + console.log(e); +} + module.exports = Commands; \ No newline at end of file diff --git a/lib/fetcher.js b/lib/fetcher.js index ddcecd6..50461d1 100644 --- a/lib/fetcher.js +++ b/lib/fetcher.js @@ -42,6 +42,20 @@ fetcher.getStackId = function(params, callback) { }); }; +fetcher.getStackIdAsync = function(params){ + return new Promise( + function(resolve, reject){ + fetcher.getStackId(params,function(stackId){ + if(stackId){ + resolve(stackId); + }else{ + reject(); + } + }); + } + ); +}; + fetcher.getLayerId = function(params, callback) { if (typeof params.StackId != 'undefined' && typeof params.LayerName != 'undefined') { opsworks.describeLayers({ diff --git a/opsworks-cli.js b/opsworks-cli.js index 1e23281..c337e8a 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -17,7 +17,7 @@ var AWS = require('aws-sdk'); var out = require('./lib/out'); var util = require('./lib/util'); var fetcher = require('./lib/fetcher'); -// var fetcher = require('./lib/commands'); +var commands = require('./lib/commands'); var awsOptions = { "region": config.get('aws:region'), @@ -517,10 +517,14 @@ app.command('exec-recipe [recipe] [stack] [layer]') .action(function(recipe, stack, layer, options) { console.log('NOT IMPLEMENTED:\tExecuting recipe %s on %s::%s', recipe, stack, layer); }); -// -// app.command('add-layer [jsonFile]') -// .description('Add a layer to a stack based on a json file') -// .action(commands.addLayer); + +app.command('add-layer [jsonFile]') + .description('Add a Layer to a stack based on a json file') + .action(commands.addLayer); + +app.command('add-app [jsonFile]') + .description('Add an App to a stack based on a json file') + .action(commands.addApp); // Process the arguments (This needs to happen after all of the commands are declared) app.parse(process.argv); \ No newline at end of file diff --git a/package.json b/package.json index 93ad56a..e7db4fd 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "opsworks": "./bin/opsworks" }, "dependencies": { - "aws-sdk": "1.10.0", + "aws-sdk": "^2.2.0", "bluebird": "^2.10.1", "commander": "2.0.0", "exec-sh": "0.1.3", - "lodash": "*", + "lodash": "^3.10.1", "nconf": "~0.7.0", "q-io": "*" }, From 6c9639ad48313001c7420e49a46896eae9bd1634 Mon Sep 17 00:00:00 2001 From: dcook Date: Thu, 24 Sep 2015 17:22:59 -0400 Subject: [PATCH 07/13] adding some tests, upgrading getLayerId --- .gitignore | 3 +- lib/commands.js | 26 +++++++++++-- lib/fetcher.js | 101 +++++++++++++++++++++--------------------------- opsworks-cli.js | 25 +----------- package.json | 1 + test/fetcher.js | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ test/mocha.opts | 3 ++ 7 files changed, 173 insertions(+), 87 deletions(-) create mode 100644 test/fetcher.js create mode 100644 test/mocha.opts diff --git a/.gitignore b/.gitignore index b512c09..9d84681 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +test_data.js \ No newline at end of file diff --git a/lib/commands.js b/lib/commands.js index 22cc322..6744c4d 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -3,8 +3,9 @@ let fs = require('q-io/fs'); var AWS = require('aws-sdk'); var P2 = require('bluebird'); -let fetcher = require('./fetcher'); +let fetcher = require('./fetcher'); +var out = require('./out'); var config = require('./config'); var opsworks = new AWS.OpsWorks(); @@ -12,6 +13,23 @@ P2.promisifyAll(Object.getPrototypeOf(opsworks)); class Commands { + static describe(options) { + + fetcher.getStackId({ + StackName: config.get('stack') + }).then(function(stackId) { + return opsworks.describeLayersAsync({ + StackId: stackId + }); + }).then(function(data) { + console.log(stack); + + data.Layers.forEach(function(layer, index, layers) { + out.layerOverview(layer); + }); + }); + } + static addLayer(jsonFile) { let _file = process.cwd() + '/' + jsonFile; let file = fs.exists(_file).then(function(result) { @@ -22,7 +40,7 @@ class Commands { return fs.read(file).then(JSON.parse); }); - let stackID = fetcher.getStackIdAsync({ + let stackID = fetcher.getStackId({ StackName: config.get('stack') }).then(function(StackId) { return StackId; @@ -35,7 +53,7 @@ class Commands { return opsworks.createLayerAsync(layerConfig).then(logger).catch(logger); }); } - + static addApp(jsonFile) { let _file = process.cwd() + '/' + jsonFile; let file = fs.exists(_file).then(function(result) { @@ -46,7 +64,7 @@ class Commands { return fs.read(file).then(JSON.parse); }); - let stackID = fetcher.getStackIdAsync({ + let stackID = fetcher.getStackId({ StackName: config.get('stack') }).then(function(StackId) { return StackId; diff --git a/lib/fetcher.js b/lib/fetcher.js index 50461d1..25b4c0e 100644 --- a/lib/fetcher.js +++ b/lib/fetcher.js @@ -2,6 +2,8 @@ var fetcher = {}; var AWS = require('aws-sdk'); var _ = require('lodash'); +var P2 = require('bluebird'); + var config = require('./config'); @@ -20,76 +22,59 @@ AWS.config.update(awsOptions); var opsworks = new AWS.OpsWorks(); var ec2 = new AWS.EC2(); +P2.promisifyAll(Object.getPrototypeOf(opsworks)); +P2.promisifyAll(Object.getPrototypeOf(ec2)); + + //=============================================== // End Configuration //=============================================== -fetcher.getStackId = function(params, callback) { - opsworks.describeStacks(function(error, data) { - if (error) { - console.log(error); - } else { - for (var i = 0; i < data.Stacks.length; i++) { - var stack = data.Stacks[i]; - if (stack.Name === params.StackName) { - callback(stack.StackId); - return; - } - } - - callback(null); - } +fetcher.getStack = function(params){ + return opsworks.describeStacksAsync().then(function(data){ + return _.find(data.Stacks, {'Name': params.StackName}); }); }; -fetcher.getStackIdAsync = function(params){ - return new Promise( - function(resolve, reject){ - fetcher.getStackId(params,function(stackId){ - if(stackId){ - resolve(stackId); - }else{ - reject(); - } - }); +fetcher.getStackId = function(params, callback) { + + return opsworks.describeStacksAsync().then(function(data){ + return _.result(_.find(data.Stacks, {'Name': params.StackName}), 'StackId'); + }).then(function(StackId){ + if(callback){ + callback(StackId); + } + return StackId; + }).catch(function(e){ + console.log(e); + if(callback){ + callback(null); } - ); + }); }; fetcher.getLayerId = function(params, callback) { - if (typeof params.StackId != 'undefined' && typeof params.LayerName != 'undefined') { - opsworks.describeLayers({ - StackId: params.StackId - }, function(error, data) { - if (error) { - console.log(error); - } else { - for (var i = 0; i < data.Layers.length; i++) { - var layer = data.Layers[i]; - if (layer.Shortname === params.LayerName) { - callback(params.StackId, layer.LayerId); - return; - } - } - - callback(null); - } + + var prStackID = (typeof params.StackId != 'undefined')? Promise.resolve(params.StackId) : fetcher.getStackId({StackName: params.StackName}); + + var prLayerID = prStackID.then(function(stackId){ + return opsworks.describeLayersAsync({StackId: stackId}).then(function(data){ + return _.result(_.find(data.Layers, {'Shortname': params.LayerName}), 'LayerId'); }); - } else if (typeof params.StackName != 'undefined') { - fetcher.getStackId({ - StackName: params.StackName - }, function(StackId) { - if (StackId === null) { - console.log('Stack ' + params.StackName + ' not found'); - process.exit(1); - } - - fetcher.getLayerId({ - StackId: StackId, - LayerName: params.LayerName - }, callback); - }); - } + }); + + return Promise.all([prStackID, prLayerID]).then(function(rtn){ + if(callback){ + callback(rtn[0], rtn[1]); + } + return rtn; + }).catch(function(e){ + if(callback){ + callback(null); + } + + console.log(e); + }); }; fetcher.getInstance = function(params, callback) { diff --git a/opsworks-cli.js b/opsworks-cli.js index c337e8a..d8f8449 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -5,9 +5,6 @@ var app = require('commander'); var exec_sh = require('exec-sh'); -// Node Stuff -var fs = require('fs'); - // Internal Dependencies var config = require('./lib/config'); process.env.AWS_PROFILE = config.get('profile'); @@ -35,27 +32,7 @@ app app.command('describe') .description('List the layers in a stack') - .action(function(options) { - var stack = config.get('stack'); - - fetcher.getStackId({ - StackName: stack - }, function(StackId) { - - opsworks.describeLayers({ - StackId: StackId - }, function(error, data) { - if (error) { - console.log(error); - } else { - console.log(stack); - data.Layers.forEach(function(layer, index, layers) { - out.layerOverview(layer); - }); - } - }); - }); - }); + .action(commands.describe); app.command('list [layer]') .description('List the instances in a layer') diff --git a/package.json b/package.json index e7db4fd..414cd21 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "aws-sdk": "^2.2.0", "bluebird": "^2.10.1", + "chai": "^3.3.0", "commander": "2.0.0", "exec-sh": "0.1.3", "lodash": "^3.10.1", diff --git a/test/fetcher.js b/test/fetcher.js new file mode 100644 index 0000000..f82e265 --- /dev/null +++ b/test/fetcher.js @@ -0,0 +1,101 @@ +var chai = require('chai'); + +var fetcher = require('../lib/fetcher'); + +var test_data = { + StackId: '' +}; + +//save the actual details in test_data.js for safety +var test_data = require('../test_data'); + +describe("Fetcher ", function() { + describe("getStackId", function() { + stackId = ""; + it("returns a promise", function() { + rtn = fetcher.getStackId({ + StackName: test_data.StackName + }); + chai.expect(rtn).to.be.a('Object'); + chai.expect(rtn.then).to.be.a('Function'); + }); + it("contains a string", function(done) { + rtn = fetcher.getStackId({ + StackName: test_data.StackName + }); + rtn.then(function(a) { + stackId = a; + chai.expect(a).to.be.a('String'); + chai.expect(a).to.have.length(36); + done(); + }); + }); + it("allows a callback", function(done) { + rtn = fetcher.getStackId({ + StackName: test_data.StackName + }, function(a) { + chai.expect(a).to.be.a('String'); + chai.expect(a).to.equal(stackId); + done(); + }); + }); + }); + + + describe("getLayerId", function() { + layerId = ""; + this.timeout(5000); + it("returns a promise", function() { + rtn = fetcher.getLayerId({ + StackName: test_data.StackName, + LayerName: test_data.LayerName + + }); + chai.expect(rtn.then).to.be.a('Function'); + }); + it("works with known StackId", function(done) { + rtn = fetcher.getLayerId({ + StackId: test_data.StackId, + LayerName: test_data.LayerName + + }); + rtn.then(function(a) { + chai.expect(a[0]).to.be.a('String'); + chai.expect(a[1]).to.be.a('String'); + chai.expect(a[0]).to.have.length(36); + chai.expect(a[1]).to.have.length(36); + done(); + }); + }); + it("contains an array of 2 strings", function(done) { + rtn = fetcher.getLayerId({ + StackName: test_data.StackName, + LayerName: test_data.LayerName + + }); + rtn.then(function(a) { + chai.expect(a[0]).to.be.a('String'); + chai.expect(a[1]).to.be.a('String'); + chai.expect(a[0]).to.have.length(36); + chai.expect(a[1]).to.have.length(36); + done(); + }); + }); + it("allows a callback", function(done) { + fetcher.getLayerId({ + StackName: test_data.StackName, + LayerName: test_data.LayerName + }, function(a, b) { + chai.expect(a).to.be.a('String'); + chai.expect(b).to.be.a('String'); + chai.expect(a).to.have.length(36); + chai.expect(b).to.have.length(36); + + // chai.expect(b).to.equal(layerId); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..66ee203 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,3 @@ +--reporter spec +--recursive +--growl \ No newline at end of file From 6cb533f10fc39466618a5d5c4ba8758bf9c92a0f Mon Sep 17 00:00:00 2001 From: dcook Date: Wed, 21 Oct 2015 15:42:31 -0400 Subject: [PATCH 08/13] changing list to handle all of the stack, removed ES6 class from commands --- lib/commands.js | 71 +++++++++++++++++++++++++++++++++++-------------- opsworks-cli.js | 29 +------------------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 6744c4d..ef41748 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -1,19 +1,19 @@ -"use strict"; - -let fs = require('q-io/fs'); +var fs = require('q-io/fs'); var AWS = require('aws-sdk'); var P2 = require('bluebird'); +var _ = require('lodash'); + -let fetcher = require('./fetcher'); +var fetcher = require('./fetcher'); var out = require('./out'); var config = require('./config'); var opsworks = new AWS.OpsWorks(); P2.promisifyAll(Object.getPrototypeOf(opsworks)); -class Commands { +var Commands = { - static describe(options) { + describe: function(options) { fetcher.getStackId({ StackName: config.get('stack') @@ -28,11 +28,11 @@ class Commands { out.layerOverview(layer); }); }); - } - - static addLayer(jsonFile) { - let _file = process.cwd() + '/' + jsonFile; - let file = fs.exists(_file).then(function(result) { + }, + + addLayer: function(jsonFile) { + var _file = process.cwd() + '/' + jsonFile; + var file = fs.exists(_file).then(function(result) { if (result) { return _file; } @@ -40,23 +40,23 @@ class Commands { return fs.read(file).then(JSON.parse); }); - let stackID = fetcher.getStackId({ + var stackID = fetcher.getStackId({ StackName: config.get('stack') }).then(function(StackId) { return StackId; }); Promise.all([file, stackID]).then(function(args) { - let layerConfig = args[0]; + var layerConfig = args[0]; layerConfig.StackId = args[1]; return opsworks.createLayerAsync(layerConfig).then(logger).catch(logger); }); - } + }, - static addApp(jsonFile) { - let _file = process.cwd() + '/' + jsonFile; - let file = fs.exists(_file).then(function(result) { + addApp: function(jsonFile) { + var _file = process.cwd() + '/' + jsonFile; + var file = fs.exists(_file).then(function(result) { if (result) { return _file; } @@ -64,20 +64,51 @@ class Commands { return fs.read(file).then(JSON.parse); }); - let stackID = fetcher.getStackId({ + var stackID = fetcher.getStackId({ StackName: config.get('stack') }).then(function(StackId) { return StackId; }); Promise.all([file, stackID]).then(function(args) { - let layerConfig = args[0]; + var layerConfig = args[0]; layerConfig.StackId = args[1]; return opsworks.createAppAsync(layerConfig).then(logger).catch(logger); }); + }, + + list: function(layer, options) { + + var prItemID = (_.isUndefined(layer)) ? + fetcher.getStackId({ + StackName: config.get('stack') + }) : + fetcher.getLayerId({ + StackName: config.get('stack'), + LayerName: layer + }); + + prItemID.then(function(data) { + + var params = {}; + if (_.isArray(data)) { + params.LayerId = data[1]; + } else { + params.StackId = data; + + } + + opsworks.describeInstancesAsync(params) + .then(function(data) { + data.Instances.forEach(function(instance, index, instances) { + out.instanceOverview(instance); + }); + }); + + }); } -} +}; function logger(e) { console.log(e); diff --git a/opsworks-cli.js b/opsworks-cli.js index d8f8449..c5dddf8 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -36,34 +36,7 @@ app.command('describe') app.command('list [layer]') .description('List the instances in a layer') - .action(function(stack, layer, options) { - stack = config.get('stack'); - - fetcher.getLayerId({ - StackName: stack, - LayerName: layer - }, function(StackId, LayerId) { - - - - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({ - LayerId: LayerId - }, function(error, data) { - if (error) { - console.log(error); - } else { - data.Instances.forEach(function(instance, index, instances) { - out.instanceOverview(instance); - }); - } - }); - }); - }); + .action(commands.list); app.command('ssh [layer]') .description('Log into a single instance or an entire layer') From 88c8b87250e7dc645c53cd4be2cbc144f93f1171 Mon Sep 17 00:00:00 2001 From: dcook Date: Wed, 21 Oct 2015 16:14:08 -0400 Subject: [PATCH 09/13] fix --verbose --- lib/commands.js | 6 +++++- lib/out.js | 2 +- opsworks-cli.js | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index ef41748..58f9ce3 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -96,11 +96,15 @@ var Commands = { params.LayerId = data[1]; } else { params.StackId = data; - } opsworks.describeInstancesAsync(params) .then(function(data) { + + if(options.parent.verbose){ + console.log(data.Instances[0]); + } + data.Instances.forEach(function(instance, index, instances) { out.instanceOverview(instance); }); diff --git a/lib/out.js b/lib/out.js index e2758b3..68e9f12 100644 --- a/lib/out.js +++ b/lib/out.js @@ -3,7 +3,7 @@ var out = {}; out.instanceOverview = function(instance){ - console.log('%s\t%s\t%s\t%s\t%s\t%s\t%s', instance.InstanceId, instance.Hostname, instance.AvailabilityZone, instance.Status, instance.PublicIp, instance.PrivateIp, instance.PublicDns); + console.log('%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s', instance.InstanceId, instance.Hostname, instance.AvailabilityZone, instance.Status, instance.PublicIp, instance.PrivateIp, instance.PublicDns, instance.Ec2InstanceId); }; out.layerOverview = function(layer){ diff --git a/opsworks-cli.js b/opsworks-cli.js index c5dddf8..16d39e5 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -27,7 +27,8 @@ var opsworks = new AWS.OpsWorks(); app .version(require('./package.json').version) - .option('-s, --stack ', 'The stack to use'); + .option('-s, --stack ', 'The stack to use') + .option('-v, --verbose', 'Show more details'); app.command('describe') From 3c4c5691cbf39eb7f64388e76d18a833d7c9196f Mon Sep 17 00:00:00 2001 From: dcook Date: Tue, 27 Oct 2015 10:31:09 -0400 Subject: [PATCH 10/13] added ablility to ssh2 into individual instance based on hostname --- lib/commands.js | 88 ++++++++++++++++++++++++++++++++++++++++++++++++- opsworks-cli.js | 69 +------------------------------------- 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 58f9ce3..f5aba9f 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -2,6 +2,8 @@ var fs = require('q-io/fs'); var AWS = require('aws-sdk'); var P2 = require('bluebird'); var _ = require('lodash'); +var exec_sh = require('exec-sh'); + var fetcher = require('./fetcher'); @@ -13,6 +15,8 @@ P2.promisifyAll(Object.getPrototypeOf(opsworks)); var Commands = { + self: this, + describe: function(options) { fetcher.getStackId({ @@ -101,7 +105,7 @@ var Commands = { opsworks.describeInstancesAsync(params) .then(function(data) { - if(options.parent.verbose){ + if (options.parent.verbose) { console.log(data.Instances[0]); } @@ -111,6 +115,88 @@ var Commands = { }); }); + }, + + ssh2: function(layer, options) { + + var ipAddress; + + if (_.isNaN(Number(layer.substr(layer.length - 1, 1)))) { + + console.log('Creating an SSH connection to first instance on %s::%s', config.get('stack'), layer); + + ipAddress = fetcher.getLayerId({ + StackName: config.get('stack'), + LayerName: layer + }) + .then(function(data) { + + return opsworks.describeInstancesAsync({ + LayerId: data[1] + }) + .then(function(data) { + return _.result(_.find(data.Instances, { + Status: 'online' + }), 'PublicIp'); + }); + + }); + + } else { + console.log('Creating an SSH connection to hostname instance on %s::%s', config.get('stack'), layer); + + ipAddress = fetcher.getStackId({ + StackName: config.get('stack'), + }) + .then(function(data) { + + return opsworks.describeInstancesAsync({ + StackId: data + }) + .then(function(data) { + return _.result(_.find(data.Instances, { + Hostname: layer, + Status: 'online' + }), 'PublicIp'); + }); + + }); + } + + ipAddress.then(function(ip_address) { + if (!_.isUndefined(ip_address)) { + Commands._ssh(ip_address, options); + } else { + console.log('No Valid IP Address'); + } + }); + + }, + + _ssh: function(hostname, options) { + // Start the options string with a space so it doesn't collide with the preceding argument + var sshOptionsString = " "; + var sshOpts = config.get('ssh:options'); + if (sshOpts !== undefined) { + for (var key in sshOpts) { + if (sshOpts.hasOwnProperty(key)) { + sshOptionsString += "-o " + key + "=" + sshOpts[key]; + } + } + } + + var ssh_username = config.get('ssh:username'); + + // Get the default key from the config file + var keyToUse = config.get('ssh:identity'); + // Override the default if supplied as a command-line argument + if (typeof options.identity != 'undefined') { + keyToUse = options.identity; + } + + var sshCommand = "ssh " + sshOptionsString + " -i " + keyToUse + " " + ssh_username + '@' + hostname; + console.log(sshCommand); + exec_sh(sshCommand); } }; diff --git a/opsworks-cli.js b/opsworks-cli.js index 16d39e5..6d9f812 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -115,74 +115,7 @@ app.command('ssh2 [layer]') .description('Log into a single instance or an entire layer') .option('-i, --identity ', 'The location of the key to use') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') - .action(function(layer, options) { - stack = config.get('stack'); - - if (typeof options.hostname != 'undefined') {} - - console.log('Creating an SSH connection to first instance on %s::%s', stack, layer); - - fetcher.getLayerId({ - StackName: stack, - LayerName: layer - }, function(StackId, LayerId) { - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({ - LayerId: LayerId - }, function(error, data) { - if (error) { - console.log(error); - } else { - var hosts = []; - for (var i = 0; i < data.Instances.length; i++) { - var instance = data.Instances[i]; - if (instance.Status == 'online') { - - // Are we only looking for one instance and is this the one? - if (typeof options.hostname != 'undefined') { - //console.log("Hostname is " + options.hostname); - //console.log("Instance is " + instance.Hostname); - if (instance.Hostname === options.hostname) { - hosts.push(data.Instances[i].PublicIp); - break; - } - } else { - hosts.push(data.Instances[i].PublicIp); - } - } - } - - // Start the options string with a space so it doesn't collide with the preceding argument - var sshOptionsString = " "; - var sshOpts = config.get('ssh:options'); - if (sshOpts !== undefined) { - for (var key in sshOpts) { - if (sshOpts.hasOwnProperty(key)) { - sshOptionsString += "-o " + key + "=" + sshOpts[key]; - } - } - } - - var ssh_username = config.get('ssh:username'); - - // Get the default key from the config file - var keyToUse = config.get('ssh:identity'); - // Override the default if supplied as a command-line argument - if (typeof options.identity != 'undefined') { - keyToUse = options.identity; - } - - var sshCommand = "ssh " + sshOptionsString + " -i " + keyToUse + " " + ssh_username + '@' + hosts[0]; - console.log(sshCommand); - exec_sh(sshCommand); - } - }); - }); - }); + .action(commands.ssh2); app.command('config [key] [value]') .description('Update settings in the OpsWorks config file') From 4145cfc7ea91dbb5a249454a4c641bbb9d5b2c60 Mon Sep 17 00:00:00 2001 From: dcook Date: Tue, 15 Dec 2015 09:02:58 -0500 Subject: [PATCH 11/13] adding scp to just one server or all in layer --- lib/commands.js | 71 +++++++++++++++++++++++++++++++++++++------------ opsworks-cli.js | 6 +++++ 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index f5aba9f..3a9bdb5 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -119,23 +119,58 @@ var Commands = { ssh2: function(layer, options) { - var ipAddress; + if (_.isNaN(Number(layer.substr(layer.length - 1, 1)))) { + console.log('Creating an SSH connection to first instance on %s::%s', config.get('stack'), layer); + + }else{ + console.log('Creating an SSH connection to hostname instance on %s::%s', config.get('stack'), layer); + + } + + Commands._getHostnames(layer).then(function(ip_address) { + if (!_.isUndefined(ip_address)) { + Commands._ssh(ip_address, options); + } else { + console.log('No Valid IP Address'); + } + }); + + }, + + scp: function(layer, file, options){ + + var keyToUse = config.get('ssh:identity'); + var ssh_username = config.get('ssh:username'); + + Commands._getHostnames(layer, true).then(function(ipAddresses){ + _.forEach(ipAddresses, function(ipAddress){ + + var scpCommand = "scp -r " + " -i " + keyToUse + " " + file + " " + ssh_username + '@' + ipAddress + ":~"; + console.log(scpCommand); + exec_sh(scpCommand); + + }); + }); + + }, + + _getHostnames: function(layer, multiple){ + + var ipAddresses; if (_.isNaN(Number(layer.substr(layer.length - 1, 1)))) { - console.log('Creating an SSH connection to first instance on %s::%s', config.get('stack'), layer); - ipAddress = fetcher.getLayerId({ + ipAddresses = fetcher.getLayerId({ StackName: config.get('stack'), LayerName: layer }) .then(function(data) { - return opsworks.describeInstancesAsync({ LayerId: data[1] }) .then(function(data) { - return _.result(_.find(data.Instances, { + return _.pluck(_.filter(data.Instances, { Status: 'online' }), 'PublicIp'); }); @@ -143,9 +178,8 @@ var Commands = { }); } else { - console.log('Creating an SSH connection to hostname instance on %s::%s', config.get('stack'), layer); - ipAddress = fetcher.getStackId({ + ipAddresses = fetcher.getStackId({ StackName: config.get('stack'), }) .then(function(data) { @@ -154,23 +188,26 @@ var Commands = { StackId: data }) .then(function(data) { - return _.result(_.find(data.Instances, { + return [_.result(_.find(data.Instances, { Hostname: layer, Status: 'online' - }), 'PublicIp'); + }), 'PublicIp')]; }); }); } - ipAddress.then(function(ip_address) { - if (!_.isUndefined(ip_address)) { - Commands._ssh(ip_address, options); - } else { - console.log('No Valid IP Address'); - } - }); - + if(multiple){ + return ipAddresses.then(function(data){ + return data; + }); + }else{ + return ipAddresses.then(function(data){ + return data.shift(); + }); + } + + }, _ssh: function(hostname, options) { diff --git a/opsworks-cli.js b/opsworks-cli.js index 6d9f812..a607168 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -117,6 +117,12 @@ app.command('ssh2 [layer]') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') .action(commands.ssh2); +app.command('scp [layer] [file]') + .description('SCP to a server') + .option('-i, --identity ', 'The location of the key to use') + .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') + .action(commands.scp); + app.command('config [key] [value]') .description('Update settings in the OpsWorks config file') .action(config.update); From e55e79ffb54af1cd119016482ec536a665e86e57 Mon Sep 17 00:00:00 2001 From: dcook Date: Tue, 15 Dec 2015 09:35:17 -0500 Subject: [PATCH 12/13] moved all to lib/commands --- lib/commands.js | 336 ++++++++++++++++++++++++++++++++++++++++++++---- opsworks-cli.js | 324 ++-------------------------------------------- 2 files changed, 323 insertions(+), 337 deletions(-) diff --git a/lib/commands.js b/lib/commands.js index 3a9bdb5..661e58b 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -4,8 +4,6 @@ var P2 = require('bluebird'); var _ = require('lodash'); var exec_sh = require('exec-sh'); - - var fetcher = require('./fetcher'); var out = require('./out'); var config = require('./config'); @@ -121,10 +119,10 @@ var Commands = { if (_.isNaN(Number(layer.substr(layer.length - 1, 1)))) { console.log('Creating an SSH connection to first instance on %s::%s', config.get('stack'), layer); - - }else{ + + } else { console.log('Creating an SSH connection to hostname instance on %s::%s', config.get('stack'), layer); - + } Commands._getHostnames(layer).then(function(ip_address) { @@ -136,26 +134,126 @@ var Commands = { }); }, - - scp: function(layer, file, options){ - + + scp: function(layer, file, options) { + var keyToUse = config.get('ssh:identity'); var ssh_username = config.get('ssh:username'); - - Commands._getHostnames(layer, true).then(function(ipAddresses){ - _.forEach(ipAddresses, function(ipAddress){ + + Commands._getHostnames(layer, true).then(function(ipAddresses) { + _.forEach(ipAddresses, function(ipAddress) { var scpCommand = "scp -r " + " -i " + keyToUse + " " + file + " " + ssh_username + '@' + ipAddress + ":~"; console.log(scpCommand); exec_sh(scpCommand); - + + }); + }); + + }, + + ssh: function(layer, options) { + if (typeof options.hostname != 'undefined') {} + console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); + + fetcher.getLayerId({ + StackName: config.get('stack'), + LayerName: layer + }, function(StackId, LayerId) { + if (LayerId === null) { + console.log('Layer ' + layer + ' not found'); + process.exit(1); + } + + opsworks.describeInstances({ + LayerId: LayerId + }, function(error, data) { + if (error) { + console.log(error); + } else { + var hosts = []; + for (var i = 0; i < data.Instances.length; i++) { + var instance = data.Instances[i]; + if (instance.Status == 'online') { + + // Are we only looking for one instance and is this the one? + if (typeof options.hostname != 'undefined') { + //console.log("Hostname is " + options.hostname); + //console.log("Instance is " + instance.Hostname); + if (instance.Hostname === options.hostname) { + hosts.push(data.Instances[i].PublicIp); + break; + } + } else { + hosts.push(data.Instances[i].PublicIp); + } + } + } + + //console.log("Reaching out to %s hosts", hosts.length); + + // Start the options string with a space so it doesn't collide with the preceding argument + var sshOptionsString = " "; + var sshOpts = config.get('ssh:options'); + if (sshOpts !== undefined) { + for (var key in sshOpts) { + if (sshOpts.hasOwnProperty(key)) { + sshOptionsString += "-o " + key + "=" + sshOpts[key]; + } + } + } + + var ssh_username = config.get('ssh:username'); + + // Get the default key from the config file + var keyToUse = config.get('ssh:identity'); + // Override the default if supplied as a command-line argument + if (typeof options.identity != 'undefined') { + keyToUse = options.identity; + } + + var sshCommand = __dirname + "/bin/ssh.sh -n " + layer + " -u " + ssh_username + sshOptionsString + " -i " + keyToUse + " " + hosts.join(" "); + + exec_sh(sshCommand); + } }); }); - }, - - _getHostnames: function(layer, multiple){ - + + describe_deployments: function(deploymentId, options) { + var stack = config.get('stack'); + + fetcher.getStackId({ + StackName: stack + }, function(StackId) { + var _params = { + StackId: StackId + }; + opsworks.describeDeployments(_params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data); // successful response + }); + }); + }, + + describe_deployment: function(deploymentId, options) { + var stack = config.get('stack'); + + fetcher.getStackId({ + StackName: stack + }, function(StackId) { + var _params = { + StackId: StackId + }; + opsworks.describeDeployments(_params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data.Deployments[0]); // successful response + }); + }); + }, + + _getHostnames: function(layer, multiple) { + var ipAddresses; if (_.isNaN(Number(layer.substr(layer.length - 1, 1)))) { @@ -197,17 +295,210 @@ var Commands = { }); } - if(multiple){ - return ipAddresses.then(function(data){ + if (multiple) { + return ipAddresses.then(function(data) { return data; }); - }else{ - return ipAddresses.then(function(data){ + } else { + return ipAddresses.then(function(data) { return data.shift(); }); } - - + }, + + update_cookbooks: function(options) { + stack = config.get('stack'); + + fetcher.getStackId({ + StackName: stack + }, function(StackId) { + var params = { + Command: { + Name: 'update_custom_cookbooks', + }, + StackId: StackId, + }; + opsworks.createDeployment(params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data); // successful response + }); + }); + }, + + deploy: function(app, stack, layer, options) { + stack = (stack) ? stack : config.get('stack'); + fetcher.getStackId({ + StackName: stack, + + }, function(StackId) { + + fetcher.getAppId({ + StackId: StackId, + AppName: app + }, function(appId) { + var params = { + Command: { + Name: 'deploy', + }, + StackId: StackId, + AppId: appId + }; + opsworks.createDeployment(params, function(err, data) { + if (err) console.log(err, err.stack); // an error occurred + else console.log(data); // successful response + }); + }); + + }); + }, + + delete: function(stack, layer, options) { + + if (!options.allStopped && typeof options.prefix == 'undefined') { + console.log('Need to pass a hostname prefix '); + } + + fetcher.getLayerId({ + StackName: stack, + LayerName: layer + }, function(StackId, LayerId) { + if (LayerId === null) { + console.log('Layer ' + layer + ' not found'); + process.exit(1); + } + + opsworks.describeInstances({ + LayerId: LayerId + }, function(error, data) { + if (error) { + console.log(error); + } else { + var hosts = []; + var deleteInstanceHandler = function(error, data) { + if (error) { + console.log('Failed to delete instance %s (%s)', instance.Hostname, instance.InstanceId); + process.exit(1); + } + }; + for (var i = 0; i < data.Instances.length; i++) { + var instance = data.Instances[i]; + + if (instance.Status == "stopped" && (options.allStopped || instance.Hostname.indexOf(options.prefix) === 0)) { + + console.log("Deleting %s", instance.Hostname); + + opsworks.deleteInstance({ + InstanceId: instance.InstanceId + }, deleteInstanceHandler); + } + } + } + }); + }); + }, + + stop: function(stack, layer, options) { + + if (!options.all && typeof options.prefix == 'undefined') { + console.log('Need to pass a hostname prefix '); + } + + fetcher.getLayerId({ + StackName: stack, + LayerName: layer + }, function(StackId, LayerId) { + if (LayerId === null) { + console.log('Layer ' + layer + ' not found'); + process.exit(1); + } + + opsworks.describeInstances({ + LayerId: LayerId + }, function(error, data) { + if (error) { + console.log(error); + } else { + var hosts = []; + var stopInstanceHandler = function(error, data) { + if (error) { + console.log('Failed to stop instance %s (%s)', instance.Hostname, instance.InstanceId); + process.exit(1); + } + }; + for (var i = 0; i < data.Instances.length; i++) { + var instance = data.Instances[i]; + if (options.all || instance.Hostname.indexOf(options.prefix) === 0) { + + console.log("Stopping %s", instance.Hostname); + opsworks.stopInstance({ + InstanceId: instance.InstanceId + }, stopInstanceHandler); + } + } + } + }); + }); + }, + + add: function(stack, layer, options) { + // Is the instance size valid? + if (!util.validateInstanceType(options.size)) { + console.log('%s is not a valid instance type.', options.size); + process.exit(1); + } + + if (typeof options.scalingType != 'undefined') { + if (!util.validateAutoScalingType(options.scalingType)) { + console.log('%s is not a valid scaling type', options.scalingType); + process.exit(1); + } + } + + var startIn = function(count, zones, options) { + fetcher.getLayerId({ + StackName: stack, + LayerName: layer + }, function(StackId, LayerId) { + if (LayerId === null) { + console.log('Layer ' + layer + ' not found'); + process.exit(1); + } + for (var i = 0; i < count; i++) { + var AvailabilityZone = zones[i % zones.length]; + + options.hostname = options.prefix + '-' + i; + + util.createInstance(StackId, LayerId, AvailabilityZone, options); + } + }); + }; + + if (typeof options.availabilityZone != 'undefined') { + util.validateAvailabilityZone(options.availabilityZone, function(valid) { + if (!valid) { + console.log('%s is not a valid availability zone', options.availabilityZone); + process.exit(1); + } else { + // Create Instance + console.log("Starting " + options.count + " in " + options.availabilityZone); + startIn(options.count, [options.availabilityZone], options); + } + }); + } else if (options.distribute) { + console.log("Starting " + options.count + " in distributed mode"); + + fetcher.getAvailabilityZones(function(data) { + var zones = []; + for (var i = 0; i < data.AvailabilityZones.length; i++) { + zones.push(data.AvailabilityZones[i].ZoneName); + } + + startIn(options.count, zones, options); + }); + } else { + console.log('You must either use --distribute or assign an availability zone using --availability-zone'); + process.exit(1); + } }, _ssh: function(hostname, options) { @@ -226,6 +517,7 @@ var Commands = { // Get the default key from the config file var keyToUse = config.get('ssh:identity'); + // Override the default if supplied as a command-line argument if (typeof options.identity != 'undefined') { keyToUse = options.identity; diff --git a/opsworks-cli.js b/opsworks-cli.js index a607168..09ea658 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -1,30 +1,10 @@ // Third-Party Dependencies - - - var app = require('commander'); -var exec_sh = require('exec-sh'); // Internal Dependencies var config = require('./lib/config'); -process.env.AWS_PROFILE = config.get('profile'); - -var AWS = require('aws-sdk'); - -var out = require('./lib/out'); -var util = require('./lib/util'); -var fetcher = require('./lib/fetcher'); var commands = require('./lib/commands'); -var awsOptions = { - "region": config.get('aws:region'), - "profile": config.get('profile') -}; - -AWS.config.update(awsOptions); - -var opsworks = new AWS.OpsWorks(); - app .version(require('./package.json').version) .option('-s, --stack ', 'The stack to use') @@ -43,73 +23,7 @@ app.command('ssh [layer]') .description('Log into a single instance or an entire layer') .option('-i, --identity ', 'The location of the key to use') .option('-h, --hostname [hostname]', 'The hostname of a single instance to log in to') - .action(function(layer, options) { - if (typeof options.hostname != 'undefined') {} - console.log('Creating an SSH connection to all instances on %s::%s', stack, layer); - - fetcher.getLayerId({ - StackName: config.get('stack'), - LayerName: layer - }, function(StackId, LayerId) { - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({ - LayerId: LayerId - }, function(error, data) { - if (error) { - console.log(error); - } else { - var hosts = []; - for (var i = 0; i < data.Instances.length; i++) { - var instance = data.Instances[i]; - if (instance.Status == 'online') { - - // Are we only looking for one instance and is this the one? - if (typeof options.hostname != 'undefined') { - //console.log("Hostname is " + options.hostname); - //console.log("Instance is " + instance.Hostname); - if (instance.Hostname === options.hostname) { - hosts.push(data.Instances[i].PublicIp); - break; - } - } else { - hosts.push(data.Instances[i].PublicIp); - } - } - } - - //console.log("Reaching out to %s hosts", hosts.length); - - // Start the options string with a space so it doesn't collide with the preceding argument - var sshOptionsString = " "; - var sshOpts = config.get('ssh:options'); - if (sshOpts !== undefined) { - for (var key in sshOpts) { - if (sshOpts.hasOwnProperty(key)) { - sshOptionsString += "-o " + key + "=" + sshOpts[key]; - } - } - } - - var ssh_username = config.get('ssh:username'); - - // Get the default key from the config file - var keyToUse = config.get('ssh:identity'); - // Override the default if supplied as a command-line argument - if (typeof options.identity != 'undefined') { - keyToUse = options.identity; - } - - var sshCommand = __dirname + "/bin/ssh.sh -n " + layer + " -u " + ssh_username + sshOptionsString + " -i " + keyToUse + " " + hosts.join(" "); - - exec_sh(sshCommand); - } - }); - }); - }); + .action(commands.ssh); app.command('ssh2 [layer]') .description('Log into a single instance or an entire layer') @@ -140,162 +54,19 @@ app.command('add [stack] [layer]') //.option('--scaling-type [scaling-type]', 'Specify the scaling type of the instance (accepts \'timer\' or \'load\')') .option('--availability-zone [availability-zone]', 'Specify the availability zone if the distribute flag has not been used') .option('--distribute', 'Use this flag to automatically distribute nodes across all of the stack\'s availability zones') - .action(function(stack, layer, options) { - // Is the instance size valid? - if (!util.validateInstanceType(options.size)) { - console.log('%s is not a valid instance type.', options.size); - process.exit(1); - } - - if (typeof options.scalingType != 'undefined') { - if (!util.validateAutoScalingType(options.scalingType)) { - console.log('%s is not a valid scaling type', options.scalingType); - process.exit(1); - } - } - - var startIn = function(count, zones, options) { - fetcher.getLayerId({ - StackName: stack, - LayerName: layer - }, function(StackId, LayerId) { - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - for (var i = 0; i < count; i++) { - var AvailabilityZone = zones[i % zones.length]; - - options.hostname = options.prefix + '-' + i; - - util.createInstance(StackId, LayerId, AvailabilityZone, options); - } - }); - }; - - if (typeof options.availabilityZone != 'undefined') { - util.validateAvailabilityZone(options.availabilityZone, function(valid) { - if (!valid) { - console.log('%s is not a valid availability zone', options.availabilityZone); - process.exit(1); - } else { - // Create Instance - console.log("Starting " + options.count + " in " + options.availabilityZone); - startIn(options.count, [options.availabilityZone], options); - } - }); - } else if (options.distribute) { - console.log("Starting " + options.count + " in distributed mode"); - - fetcher.getAvailabilityZones(function(data) { - var zones = []; - for (var i = 0; i < data.AvailabilityZones.length; i++) { - zones.push(data.AvailabilityZones[i].ZoneName); - } - - startIn(options.count, zones, options); - }); - } else { - console.log('You must either use --distribute or assign an availability zone using --availability-zone'); - process.exit(1); - } - }); + .action(commands.add); app.command('stop [stack] [layer]') .description('Stops an instance either by using Stack/Layer/Hostname') .option('-p, --prefix [prefix]', 'Instances with a hostname starting with this prefix will be stopped') .option('--all', 'All instances in this layer will be stopped', '') - .action(function(stack, layer, options) { - - if (!options.all && typeof options.prefix == 'undefined') { - console.log('Need to pass a hostname prefix '); - } - - fetcher.getLayerId({ - StackName: stack, - LayerName: layer - }, function(StackId, LayerId) { - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({ - LayerId: LayerId - }, function(error, data) { - if (error) { - console.log(error); - } else { - var hosts = []; - var stopInstanceHandler = function(error, data) { - if (error) { - console.log('Failed to stop instance %s (%s)', instance.Hostname, instance.InstanceId); - process.exit(1); - } - }; - for (var i = 0; i < data.Instances.length; i++) { - var instance = data.Instances[i]; - if (options.all || instance.Hostname.indexOf(options.prefix) === 0) { - - console.log("Stopping %s", instance.Hostname); - opsworks.stopInstance({ - InstanceId: instance.InstanceId - }, stopInstanceHandler); - } - } - } - }); - }); - }); + .action(commands.stop); app.command('delete [stack] [layer]') .description('Deletes stopped instances in a layer by hostname prefix or an \'all\' flag') .option('-p, --prefix [prefix]', 'Stopped instances with a hostname starting with this prefix will be deleted') .option('--all-stopped', 'All stopped instances in this layer will be deleted', '') - .action(function(stack, layer, options) { - - if (!options.allStopped && typeof options.prefix == 'undefined') { - console.log('Need to pass a hostname prefix '); - } - - fetcher.getLayerId({ - StackName: stack, - LayerName: layer - }, function(StackId, LayerId) { - if (LayerId === null) { - console.log('Layer ' + layer + ' not found'); - process.exit(1); - } - - opsworks.describeInstances({ - LayerId: LayerId - }, function(error, data) { - if (error) { - console.log(error); - } else { - var hosts = []; - var deleteInstanceHandler = function(error, data) { - if (error) { - console.log('Failed to delete instance %s (%s)', instance.Hostname, instance.InstanceId); - process.exit(1); - } - }; - for (var i = 0; i < data.Instances.length; i++) { - var instance = data.Instances[i]; - - if (instance.Status == "stopped" && (options.allStopped || instance.Hostname.indexOf(options.prefix) === 0)) { - - console.log("Deleting %s", instance.Hostname); - - opsworks.deleteInstance({ - InstanceId: instance.InstanceId - }, deleteInstanceHandler); - } - } - } - }); - }); - }); + .action(commands.delete); app.command('start [stack] [layer] [hostname]') .description('Start an instance') @@ -305,32 +76,7 @@ app.command('start [stack] [layer] [hostname]') app.command('deploy [app] [stack] [layer]') .description('Deploy an application to a layer.') - .action(function(app, stack, layer, options) { - stack = (stack) ? stack : config.get('stack'); - fetcher.getStackId({ - StackName: stack, - - }, function(StackId) { - - fetcher.getAppId({ - StackId: StackId, - AppName: app - }, function(appId) { - var params = { - Command: { - Name: 'deploy', - }, - StackId: StackId, - AppId: appId - }; - opsworks.createDeployment(params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data); // successful response - }); - }); - - }); - }); + .action(commands.deploy); app.command('undeploy [app] [stack] [layer]') .description('Undeploys an application from a layer') @@ -340,74 +86,22 @@ app.command('undeploy [app] [stack] [layer]') app.command('update-cookbooks') .description('Updates the custom cookbooks within a stack') - .action(function(options) { - stack = config.get('stack'); - - fetcher.getStackId({ - StackName: stack - }, function(StackId) { - var params = { - Command: { - Name: 'update_custom_cookbooks', - }, - StackId: StackId, - }; - opsworks.createDeployment(params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data); // successful response - }); - }); - }); + .action(commands.update_cookbooks); app.command('describe-deployments [deploymentId]') .description('Updates the custom cookbooks within a stack') - .action(function(deploymentId, options) { - var stack = config.get('stack'); + .action(commands.describe_deployments); - fetcher.getStackId({ - StackName: stack - }, function(StackId) { - var _params = { - // DeploymentIds: [ - // '71796665-e306-42c9-a0be-b5f1f5201acf' - // ], - StackId: StackId - // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] - }; - opsworks.describeDeployments(_params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data); // successful response - }); - }); - }); app.command('describe-deployment [deploymentId]') .description('Updates the custom cookbooks within a stack') - .action(function(deploymentId, options) { - var stack = config.get('stack'); - - fetcher.getStackId({ - StackName: stack - }, function(StackId) { - var _params = { - // DeploymentIds: [ - // '71796665-e306-42c9-a0be-b5f1f5201acf' - // ], - StackId: StackId - // DeploymentIds: ['71796665-e306-42c9-a0be-b5f1f5201acf'] - }; - opsworks.describeDeployments(_params, function(err, data) { - if (err) console.log(err, err.stack); // an error occurred - else console.log(data.Deployments[0]); // successful response - }); - }); - }); + .action(commands.describe_deployment); app.command('exec-recipe [recipe] [stack] [layer]') .description('Executes a recipe on instances within a layer') .action(function(recipe, stack, layer, options) { console.log('NOT IMPLEMENTED:\tExecuting recipe %s on %s::%s', recipe, stack, layer); }); - + app.command('add-layer [jsonFile]') .description('Add a Layer to a stack based on a json file') .action(commands.addLayer); From cca8b8a562ca3aefb821d466a6538d5fbd995384 Mon Sep 17 00:00:00 2001 From: dcook Date: Tue, 15 Dec 2015 14:50:17 -0500 Subject: [PATCH 13/13] fixing other profile support --- lib/config.js | 2 +- opsworks-cli.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/config.js b/lib/config.js index 98a7510..983c494 100644 --- a/lib/config.js +++ b/lib/config.js @@ -12,7 +12,7 @@ config .defaults({ 'stack': config.get('default_stack') }); -var profile = (config.get('stacks:'+config.get('stack')+':profile'))? config.get('stacks:'+config.get('stack')+':profile') : 'default'; +var profile = (config.get('stacks:' + config.get('stack') + ':profile')) ? config.get('stacks:' + config.get('stack') + ':profile') : 'default'; config.set('profile', profile); config.update = function(key, value, options) { diff --git a/opsworks-cli.js b/opsworks-cli.js index 09ea658..0d56598 100644 --- a/opsworks-cli.js +++ b/opsworks-cli.js @@ -3,6 +3,8 @@ var app = require('commander'); // Internal Dependencies var config = require('./lib/config'); + +process.env.AWS_PROFILE = config.get('profile'); var commands = require('./lib/commands'); app