triton instances
This commit is contained in:
parent
23fc9d4b3f
commit
eaf93e619b
120
lib/cloudapi2.js
120
lib/cloudapi2.js
@ -29,6 +29,7 @@ var p = console.log;
|
||||
var assert = require('assert-plus');
|
||||
var auth = require('smartdc-auth');
|
||||
var format = require('util').format;
|
||||
var LOMStream = require('lomstream').LOMStream;
|
||||
var os = require('os');
|
||||
var querystring = require('querystring');
|
||||
var restifyClients = require('restify-clients');
|
||||
@ -387,84 +388,61 @@ CloudAPI.prototype.getMachine = function getMachine(options, callback) {
|
||||
* List the user's machines.
|
||||
* <http://apidocs.joyent.com/cloudapi/#ListMachines>
|
||||
*
|
||||
* If no `offset` is given, then this will return all machines, calling
|
||||
* multiple times if necessary. If `offset` is specified given, then just
|
||||
* a single response will be made.
|
||||
* @param {Object} options
|
||||
* See document above
|
||||
* @return {LOMStream} a stream for each machine entry
|
||||
*/
|
||||
CloudAPI.prototype.createListMachinesStream =
|
||||
function createListMachinesStream(options) {
|
||||
var self = this;
|
||||
|
||||
// if the user specifies an offset we don't paginate
|
||||
var once = options.limit !== undefined;
|
||||
|
||||
return new LOMStream({
|
||||
fetch: fetch,
|
||||
limit: 1000,
|
||||
offset: true
|
||||
});
|
||||
|
||||
function fetch(fetcharg, limitObj, datacb, donecb) {
|
||||
options.limit = limitObj.limit;
|
||||
options.offset = limitObj.offset;
|
||||
var endpoint = self._path(format('/%s/machines', self.user), options);
|
||||
|
||||
self._request(endpoint, function (err, req, res, body) {
|
||||
var resourcecount = res.headers['x-resource-count'];
|
||||
var done = once || resourcecount < options.limit;
|
||||
donecb(err, {done: done, results: body});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* List the user's machines.
|
||||
* <http://apidocs.joyent.com/cloudapi/#ListMachines>
|
||||
*
|
||||
* @param {Object} options (optional)
|
||||
* - {Number} offset (optional) An offset number of machine at which to
|
||||
* return results.
|
||||
* - {Number} limit (optional) Max number of machines to return.
|
||||
* @param {Function} callback of the form `function (err, machines, responses)`
|
||||
* where `responses` is an array of response objects in retrieving all
|
||||
* the machines. ListMachines has a max number of machines, so can require
|
||||
* multiple requests to list all of them.
|
||||
* @param {Object} options
|
||||
* See document above
|
||||
* @param {Function} callback - called like `function (err, machines)`
|
||||
*/
|
||||
CloudAPI.prototype.listMachines = function listMachines(options, callback) {
|
||||
var self = this;
|
||||
if (callback === undefined) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
assert.object(options, 'options');
|
||||
assert.func(callback, 'callback');
|
||||
|
||||
var query = {
|
||||
limit: options.limit
|
||||
};
|
||||
|
||||
var paging = options.offset === undefined;
|
||||
var offset = options.offset || 0;
|
||||
var lastHeaders;
|
||||
var responses = [];
|
||||
var bodies = [];
|
||||
async.doWhilst(
|
||||
function getPage(next) {
|
||||
self._getAuthHeaders(function (hErr, headers) {
|
||||
if (hErr) {
|
||||
next(hErr);
|
||||
return;
|
||||
}
|
||||
query.offset = offset;
|
||||
var path = sprintf('/%s/machines?%s', self.user,
|
||||
querystring.stringify(query));
|
||||
var opts = {
|
||||
path: path,
|
||||
headers: headers
|
||||
};
|
||||
self.client.get(opts, function (err, req, res, body) {
|
||||
lastHeaders = res.headers;
|
||||
responses.push(res);
|
||||
bodies.push(body);
|
||||
next(err);
|
||||
var machines = [];
|
||||
var s = this.createListMachinesStream(options);
|
||||
s.on('error', function (e) {
|
||||
callback(e);
|
||||
});
|
||||
s.on('readable', function () {
|
||||
var machine;
|
||||
while ((machine = s.read()) !== null) {
|
||||
machines.push(machine);
|
||||
}
|
||||
});
|
||||
s.on('end', function () {
|
||||
callback(null, machines);
|
||||
});
|
||||
},
|
||||
function testContinue() {
|
||||
if (!paging) {
|
||||
return false;
|
||||
}
|
||||
xQueryLimit = Number(lastHeaders['x-query-limit']);
|
||||
xResourceCount = Number(lastHeaders['x-resource-count']);
|
||||
assert.number(xQueryLimit, 'x-query-limit header');
|
||||
assert.number(xResourceCount, 'x-resource-count header');
|
||||
offset += Number(lastHeaders['x-resource-count']);
|
||||
return xResourceCount >= xQueryLimit;
|
||||
},
|
||||
function doneMachines(err) {
|
||||
if (err) {
|
||||
callback(err, null, responses);
|
||||
} else if (bodies.length === 1) {
|
||||
callback(null, bodies[0], responses);
|
||||
} else {
|
||||
var machines = Array.prototype.concat.apply([], bodies);
|
||||
callback(null, machines, responses);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List machine audit (successful actions on the machine).
|
||||
*
|
||||
|
@ -10,17 +10,24 @@ function do_cloudapi (subcmd, opts, args, callback) {
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], callback);
|
||||
return;
|
||||
} else if (args.length !== 2) {
|
||||
} else if (args.length < 1 || args.length > 2) {
|
||||
callback(new Error('invalid arguments'));
|
||||
return;
|
||||
}
|
||||
|
||||
var method = args[0];
|
||||
var path = args[1];
|
||||
if (path === undefined) {
|
||||
path = method;
|
||||
method = 'GET';
|
||||
}
|
||||
|
||||
var reqopts = {
|
||||
method: args[0].toLowerCase(),
|
||||
path: args[1]
|
||||
method: method.toLowerCase(),
|
||||
path: path
|
||||
};
|
||||
|
||||
this.triton.cloudapi.request(reqopts, function (err, req, res, body) {
|
||||
this.triton.cloudapi._request(reqopts, function (err, req, res, body) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
|
@ -1,68 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Joyent Inc. All rights reserved.
|
||||
* Copyright 2015 Joyent Inc.
|
||||
*
|
||||
* `triton instances ...`
|
||||
*/
|
||||
|
||||
var format = require('util').format;
|
||||
var tabula = require('tabula');
|
||||
|
||||
var errors = require('./errors');
|
||||
var common = require('./common');
|
||||
|
||||
// to be passed as query string args to /my/machines
|
||||
var validFilters = [
|
||||
'name',
|
||||
'image',
|
||||
'state',
|
||||
'memory',
|
||||
'tombstone',
|
||||
'credentials'
|
||||
];
|
||||
|
||||
// valid output fields to be printed
|
||||
var validFields = [
|
||||
'id',
|
||||
'name',
|
||||
'type',
|
||||
'state',
|
||||
'dataset',
|
||||
'memory',
|
||||
'disk',
|
||||
'ips',
|
||||
'metadata',
|
||||
'created',
|
||||
'updated',
|
||||
'package',
|
||||
'image'
|
||||
];
|
||||
|
||||
function do_instances(subcmd, opts, args, callback) {
|
||||
var self = this;
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], callback);
|
||||
return;
|
||||
} else if (args.length > 1) {
|
||||
return callback(new Error('too many args: ' + args));
|
||||
callback(new Error('too many args: ' + args));
|
||||
return;
|
||||
}
|
||||
|
||||
var machines = [];
|
||||
var errs = [];
|
||||
var res = this.sdc.listMachines();
|
||||
res.on('data', function (dc, dcMachines) {
|
||||
for (var i = 0; i < dcMachines.length; i++) {
|
||||
dcMachines[i].dc = dc;
|
||||
machines.push(dcMachines[i]);
|
||||
}
|
||||
});
|
||||
res.on('dcError', function (dc, dcErr) {
|
||||
dcErr.dc = dc;
|
||||
errs.push(dcErr);
|
||||
});
|
||||
res.on('end', function () {
|
||||
if (opts.json) {
|
||||
p(JSON.stringify(machines, null, 4));
|
||||
} else {
|
||||
/* BEGIN JSSTYLED */
|
||||
// TODO: get short output down to something like
|
||||
// 'us-west-1 e91897cf testforyunong2 linux running 2013-11-08'
|
||||
// 'us-west-1 e91897cf testforyunong2 ubuntu/13.3.0 running 2013-11-08'
|
||||
/* END JSSTYLED */
|
||||
common.tabulate(machines, {
|
||||
columns: 'dc,id,name,image,state,created',
|
||||
sort: 'created',
|
||||
validFields: 'dc,id,name,type,state,image,package,memory,'
|
||||
+ 'disk,created,updated,compute_node,primaryIp'
|
||||
});
|
||||
}
|
||||
var err;
|
||||
if (errs.length === 1) {
|
||||
err = errs[0];
|
||||
} else if (errs.length > 1) {
|
||||
err = new errors.MultiError(errs);
|
||||
var columns = opts.o.trim().split(',');
|
||||
var sort = opts.s.trim().split(',');
|
||||
|
||||
var listOpts;
|
||||
try {
|
||||
listOpts = common.kvToObj(args, validFilters);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.triton.cloudapi.listMachines(listOpts, function (err, machines) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (opts.json) {
|
||||
console.log(common.jsonStream(machines));
|
||||
} else {
|
||||
tabula(machines, {
|
||||
skipHeader: opts.H,
|
||||
columns: columns,
|
||||
sort: sort,
|
||||
validFields: validFields
|
||||
});
|
||||
};
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
do_instances.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['H'],
|
||||
type: 'bool',
|
||||
help: 'Omit table header row.'
|
||||
},
|
||||
{
|
||||
names: ['o'],
|
||||
type: 'string',
|
||||
default: 'id,name,state,type,image,memory,disk',
|
||||
help: 'Specify fields (columns) to output.',
|
||||
helpArg: 'field1,...'
|
||||
},
|
||||
{
|
||||
names: ['s'],
|
||||
type: 'string',
|
||||
default: 'name',
|
||||
help: 'Sort on the given fields. Default is "name".',
|
||||
helpArg: 'field1,...'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
@ -77,7 +113,6 @@ do_instances.help = (
|
||||
+ '\n'
|
||||
+ '{{options}}'
|
||||
);
|
||||
do_instances.aliases = ['insts'];
|
||||
|
||||
|
||||
module.exports = do_instances;
|
||||
|
@ -32,6 +32,10 @@ function do_packages (subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
this.triton.cloudapi.listPackages(listOpts, function (err, packages) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (opts.json) {
|
||||
console.log(common.jsonStream(packages));
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user