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/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/commands.js b/lib/commands.js new file mode 100644 index 0000000..661e58b --- /dev/null +++ b/lib/commands.js @@ -0,0 +1,537 @@ +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'); +var out = require('./out'); +var config = require('./config'); + +var opsworks = new AWS.OpsWorks(); +P2.promisifyAll(Object.getPrototypeOf(opsworks)); + +var Commands = { + + self: this, + + describe: function(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); + }); + }); + }, + + addLayer: function(jsonFile) { + var _file = process.cwd() + '/' + jsonFile; + var file = fs.exists(_file).then(function(result) { + if (result) { + return _file; + } + }).then(function(file) { + return fs.read(file).then(JSON.parse); + }); + + var stackID = fetcher.getStackId({ + StackName: config.get('stack') + }).then(function(StackId) { + return StackId; + }); + + Promise.all([file, stackID]).then(function(args) { + var layerConfig = args[0]; + layerConfig.StackId = args[1]; + + return opsworks.createLayerAsync(layerConfig).then(logger).catch(logger); + }); + }, + + addApp: function(jsonFile) { + var _file = process.cwd() + '/' + jsonFile; + var file = fs.exists(_file).then(function(result) { + if (result) { + return _file; + } + }).then(function(file) { + return fs.read(file).then(JSON.parse); + }); + + var stackID = fetcher.getStackId({ + StackName: config.get('stack') + }).then(function(StackId) { + return StackId; + }); + + Promise.all([file, stackID]).then(function(args) { + 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) { + + if (options.parent.verbose) { + console.log(data.Instances[0]); + } + + data.Instances.forEach(function(instance, index, instances) { + out.instanceOverview(instance); + }); + }); + + }); + }, + + ssh2: function(layer, options) { + + 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); + + }); + }); + + }, + + 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); + } + }); + }); + }, + + 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)))) { + + + ipAddresses = fetcher.getLayerId({ + StackName: config.get('stack'), + LayerName: layer + }) + .then(function(data) { + return opsworks.describeInstancesAsync({ + LayerId: data[1] + }) + .then(function(data) { + return _.pluck(_.filter(data.Instances, { + Status: 'online' + }), 'PublicIp'); + }); + + }); + + } else { + + ipAddresses = 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')]; + }); + + }); + } + + if (multiple) { + return ipAddresses.then(function(data) { + return 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) { + // 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); + } +}; + +function logger(e) { + console.log(e); +} + + +module.exports = Commands; \ No newline at end of file diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..983c494 --- /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 f90b437..25b4c0e 100644 --- a/lib/fetcher.js +++ b/lib/fetcher.js @@ -1,122 +1,137 @@ var fetcher = {}; var AWS = require('aws-sdk'); +var _ = require('lodash'); +var P2 = require('bluebird'); + + +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" }; +var awsOptions = { + "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(); +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); +fetcher.getStack = function(params){ + return opsworks.describeStacksAsync().then(function(data){ + return _.find(data.Stacks, {'Name': params.StackName}); + }); +}; + +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); } - else{ - for(var i=0; i', 'The stack to use') + .option('-v, --verbose', 'Show more details'); -var awsOptions = { "accessKeyId": AWS_ACCESS_KEY_ID, "secretAccessKey": AWS_SECRET_ACCESS_KEY, "region": "us-east-1" }; -AWS.config.update(awsOptions); -var opsworks = new AWS.OpsWorks(); +app.command('describe') + .description('List the layers in a stack') + .action(commands.describe); -app.version(require('./package.json').version); +app.command('list [layer]') + .description('List the instances in a layer') + .action(commands.list); -app.command('describe [stack]') -.description('List the layers in a stack') -.action(function(stack, options){ - - fetcher.getStackId({StackName:stack}, function(StackId){ - - opsworks.describeLayers({StackId:StackId}, function(error, data){ - if(error){ - console.log(error); - } - else{ - data.Layers.forEach(function(layer, index, layers){ - out.layerOverview(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(commands.ssh); -app.command('list [stack] [layer]') -.description('List the instances in a layer') -.action(function(stack, layer, options){ - - 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); - }); - } - }); - }); -}); +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(commands.ssh2); -app.command('ssh [stack] [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){ - 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); - } - else{ - var hosts = new Array(); - 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(commands.scp); 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'); - process.exit(1); - } - - var keyPaths = key.split("."); - - var walk = function(currentPath, next, valueToSet){ - if(typeof currentPath[next] == 'undefined'){ - currentPath[next] = {}; - } - - if(arguments.length==3){ - currentPath[next] = valueToSet; - } - - return currentPath[next]; - }; - - var currentlyAt = config; - keyPaths.forEach(function(element, index, array){ - console.log('Descending to ' + element); - if(index==array.length-1){ - currentlyAt = walk(currentlyAt, element, value); - } - else{ - currentlyAt = walk(currentlyAt, element); - } - }); - - //config[key] = value; - - 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'); - } - }); -}); + .description('Update settings in the OpsWorks config file') + .action(config.update); app.command('add [stack] [layer]') -.description('Add one or more instances to a layer') -.option('--start', 'Starts the instance immediately.') -.option('-h, --hostname [hostname]', 'Supply the hostname to be used for the instance.') -.option('-p, --prefix [prefix]', 'Supply a prefix to be used for the instance hostname.', '') -.option('-k, --keypair [keypair]', 'Specify which key pair to use when logging into the instance.') -.option('-a, --ami [ami]', 'Specify a custom AMI to boot.') -.option('-s,--size [size]', 'Specify the size of the EC2 instance.', 'c1.medium') -.option('-c,--count [count]', 'Specify the number of EC2 instances to add', 1) -// Scaling Type not yet supported -//.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 = new Array(); - for(var i=0; i", - "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" - }, - "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": "^2.2.0", + "bluebird": "^2.10.1", + "chai": "^3.3.0", + "commander": "2.0.0", + "exec-sh": "0.1.3", + "lodash": "^3.10.1", + "nconf": "~0.7.0", + "q-io": "*" + }, + "license": "MIT" +} 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