diff --git a/lib/cloudapi2.js b/lib/cloudapi2.js index 4c9f221..55301c4 100644 --- a/lib/cloudapi2.js +++ b/lib/cloudapi2.js @@ -342,6 +342,7 @@ CloudApi.prototype.listKeys = function listKeys(opts, cb) { * * * @param {Object} options (optional) + * XXX be more strict about accepted options * XXX document this, see the api doc above :) * @param {Function} callback of the form `function (err, images, res)` */ @@ -553,9 +554,12 @@ function createListMachinesStream(options) { var endpoint = self._path(format('/%s/machines', self.user), options); self._request(endpoint, function (err, req, res, body) { + if (err) { + return donecb(err); + } var resourcecount = res.headers['x-resource-count']; var done = once || resourcecount < options.limit; - donecb(err, {done: done, results: body}); + donecb(null, {done: done, results: body}); }); } }; diff --git a/lib/do_instances.js b/lib/do_instances.js index e337719..07147ae 100644 --- a/lib/do_instances.js +++ b/lib/do_instances.js @@ -10,12 +10,14 @@ * `triton instances ...` */ -var f = require('util').format; - +var format = require('util').format; var tabula = require('tabula'); +var vasync = require('vasync'); var common = require('./common'); + + // to be passed as query string args to /my/machines var validFilters = [ 'name', @@ -36,6 +38,7 @@ var columnsDefaultLong = 'id,name,img,package,state,primaryIp,created'; var sortDefault = 'created'; function do_instances(subcmd, opts, args, callback) { + var self = this; if (opts.help) { this.do_help('help', {}, [subcmd], callback); return; @@ -59,55 +62,64 @@ function do_instances(subcmd, opts, args, callback) { return; } - var i = 0; - i++; - var images; - this.tritonapi.listImages({useCache: true}, function (err, _images) { - if (err) { - callback(err); - return; + var imgs; + var insts; + + vasync.parallel({funcs: [ + function getTheImages(next) { + self.tritonapi.listImages({useCache: true}, function (err, _imgs) { + if (err) { + next(err); + } else { + imgs = _imgs; + next(); + } + }); + }, + function getTheMachines(next) { + self.tritonapi.cloudapi.listMachines(listOpts, + function (err, _insts) { + if (err) { + next(err); + } else { + insts = _insts; + next(); + } + }); } - images = _images; - done(); - }); - - i++; - var machines; - this.tritonapi.cloudapi.listMachines(listOpts, function (err, _machines) { + ]}, function (err, results) { + /* + * Error handling: vasync.parallel's `err` is always a MultiError. We + * want to prefer the `getTheMachines` err, e.g. if both get a + * self-signed cert error. + */ if (err) { - callback(err); - return; + err = results.operations[1].err || err; + return callback(err); } - machines = _machines; - done(); - }); - - function done() { - if (--i > 0) - return; // map "uuid" => "image_name" var imgmap = {}; - images.forEach(function (image) { - imgmap[image.id] = f('%s@%s', image.name, image.version); + imgs.forEach(function (img) { + imgmap[img.id] = format('%s@%s', img.name, img.version); }); // Add extra fields for nice output. // XXX FWIW, the "extra fields" for images and packages are not added // for `opts.json`. Thoughts? We should be consistent there. --TM var now = new Date(); - machines.forEach(function (machine) { - var created = new Date(machine.created); - machine.ago = common.longAgo(created, now); - machine.img = imgmap[machine.image] || machine.image; - machine.shortid = machine.id.split('-', 1)[0]; + insts.forEach(function (inst) { + var created = new Date(inst.created); + inst.ago = common.longAgo(created, now); + inst.img = imgmap[inst.image] || inst.image; + inst.shortid = inst.id.split('-', 1)[0]; }); if (opts.json) { - common.jsonStream(machines); + common.jsonStream(insts); } else { - tabula(machines, { + tabula(insts, { skipHeader: opts.H, columns: columns, sort: sort, @@ -115,7 +127,7 @@ function do_instances(subcmd, opts, args, callback) { }); } callback(); - } + }); } do_instances.options = [