PUBAPI-1233/PUBAPI-1234 - add support for --snapshot= flag when
starting a machine, and shortId support for fwrules.
This commit is contained in:
parent
f3956df8ce
commit
e6334db9e1
@ -1067,6 +1067,7 @@ function getMachineSnapshot(opts, cb) {
|
||||
* - {String} name (required) the snapshot's name.
|
||||
* @param {Function} callback of the form f(err, res).
|
||||
*/
|
||||
CloudApi.prototype.startMachineFromSnapshot =
|
||||
function startMachineFromSnapshot(opts, cb) {
|
||||
assert.object(opts, 'opts');
|
||||
assert.uuid(opts.id, 'opts.id');
|
||||
@ -1075,13 +1076,13 @@ function startMachineFromSnapshot(opts, cb) {
|
||||
|
||||
this._request({
|
||||
method: 'POST',
|
||||
path: format('/%s/machine/%s/snapshots/%s', this.account, opts.id,
|
||||
path: format('/%s/machines/%s/snapshots/%s', this.account, opts.id,
|
||||
opts.name),
|
||||
data: opts
|
||||
}, function (err, req, res, body) {
|
||||
cb(err, body, res);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -314,8 +314,7 @@ function uuidToShortId(s) {
|
||||
*
|
||||
* Short IDs:
|
||||
* - UUID prefix
|
||||
* - allow '-' to be elided (to support using containers IDs from
|
||||
* docker)
|
||||
* - allow '-' to be elided (to support using containers IDs from docker)
|
||||
* - support docker ID *longer* than a UUID? The curr implementation does.
|
||||
*/
|
||||
function normShortId(s) {
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var format = require('util').format;
|
||||
var fs = require('fs');
|
||||
var sshpk = require('sshpk');
|
||||
var vasync = require('vasync');
|
||||
|
||||
var common = require('../common');
|
||||
@ -60,20 +58,27 @@ function do_delete(subcmd, opts, args, cb) {
|
||||
});
|
||||
},
|
||||
function deleteThem(_, next) {
|
||||
vasync.forEachPipeline({
|
||||
vasync.forEachParallel({
|
||||
inputs: ruleIds,
|
||||
func: function deleteOne(id, nextId) {
|
||||
cli.tritonapi.cloudapi.deleteFirewallRule({
|
||||
id: id
|
||||
}, function (err) {
|
||||
cli.tritonapi.getFirewallRule(id, function (err, fwrule) {
|
||||
if (err) {
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
cli.tritonapi.cloudapi.deleteFirewallRule({
|
||||
id: fwrule.id
|
||||
}, function (err2) {
|
||||
if (err2) {
|
||||
nextId(err2);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Deleted rule %s', id);
|
||||
nextId();
|
||||
});
|
||||
});
|
||||
}
|
||||
}, next);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var vasync = require('vasync');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
@ -25,28 +26,46 @@ function do_disable(subcmd, opts, args, cb) {
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
cb(new errors.UsageError('Missing FWRULE-ID argument'));
|
||||
return;
|
||||
} else if (args.length > 1) {
|
||||
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||
cb(new errors.UsageError('Missing FWRULE-ID argument(s)'));
|
||||
return;
|
||||
}
|
||||
|
||||
var id = args[0];
|
||||
var cli = this.top;
|
||||
|
||||
// XXX add support for shortId
|
||||
cli.tritonapi.cloudapi.disableFirewallRule(id, function onRule(err) {
|
||||
vasync.forEachParallel({
|
||||
inputs: args,
|
||||
func: function disableOne(id, nextId) {
|
||||
if (common.isUUID(id)) {
|
||||
enable();
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to look up the full UUID if the given id is a short id
|
||||
cli.tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
id = fwrule.id;
|
||||
|
||||
enable();
|
||||
});
|
||||
|
||||
function enable() {
|
||||
cli.tritonapi.cloudapi.disableFirewallRule(id, function (err) {
|
||||
if (err) {
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Disabled firewall rule %s', id);
|
||||
|
||||
cb();
|
||||
nextId();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, cb);
|
||||
}
|
||||
|
||||
|
||||
do_disable.options = [
|
||||
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var vasync = require('vasync');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
@ -25,28 +26,46 @@ function do_enable(subcmd, opts, args, cb) {
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
cb(new errors.UsageError('Missing FWRULE-ID argument'));
|
||||
return;
|
||||
} else if (args.length > 1) {
|
||||
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||
cb(new errors.UsageError('Missing FWRULE-ID argument(s)'));
|
||||
return;
|
||||
}
|
||||
|
||||
var id = args[0];
|
||||
var cli = this.top;
|
||||
|
||||
// XXX add support for shortId
|
||||
cli.tritonapi.cloudapi.enableFirewallRule(id, function onRule(err) {
|
||||
vasync.forEachParallel({
|
||||
inputs: args,
|
||||
func: function enableOne(id, nextId) {
|
||||
if (common.isUUID(id)) {
|
||||
enable();
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to look up the full UUID if the given id is a short id
|
||||
cli.tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
id = fwrule.id;
|
||||
|
||||
enable();
|
||||
});
|
||||
|
||||
function enable() {
|
||||
cli.tritonapi.cloudapi.enableFirewallRule(id, function (err) {
|
||||
if (err) {
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Enabled firewall rule %s', id);
|
||||
|
||||
cb();
|
||||
nextId();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, cb);
|
||||
}
|
||||
|
||||
|
||||
do_enable.options = [
|
||||
@ -60,7 +79,7 @@ do_enable.help = [
|
||||
'Enable a specific firewall rule.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} enable FWRULE-ID',
|
||||
' {{name}} enable FWRULE-ID [FWRULE-ID...]',
|
||||
'',
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
@ -36,8 +36,7 @@ function do_get(subcmd, opts, args, cb) {
|
||||
var id = args[0];
|
||||
var cli = this.top;
|
||||
|
||||
// XXX add support for shortId
|
||||
cli.tritonapi.cloudapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||
cli.tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
|
@ -58,7 +58,7 @@ function do_list(subcmd, opts, args, cb) {
|
||||
|
||||
if (columns.indexOf('shortid') !== -1) {
|
||||
rules.forEach(function (rule) {
|
||||
rule.shortid = common.normShortId(rule.id);
|
||||
rule.shortid = common.uuidToShortId(rule.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,13 @@ function do_update(subcmd, opts, args, cb) {
|
||||
|
||||
function validateIt(ctx, next) {
|
||||
var keys = Object.keys(ctx.data);
|
||||
|
||||
if (keys.length === 0) {
|
||||
console.log('No fields given for firewall rule update');
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = ctx.data[key];
|
||||
@ -129,24 +136,38 @@ function do_update(subcmd, opts, args, cb) {
|
||||
next();
|
||||
},
|
||||
|
||||
function updateAway(ctx, next) {
|
||||
var keys = Object.keys(ctx.data);
|
||||
if (keys.length === 0) {
|
||||
console.log('No fields given for firewall rule update');
|
||||
// we need to look up the full UUID if the given id is a short id
|
||||
function getFullId(ctx, next) {
|
||||
if (common.isUUID(id)) {
|
||||
ctx.data.id = id;
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.data.id = id;
|
||||
|
||||
tritonapi.cloudapi.updateFirewallRule(ctx.data, function (err) {
|
||||
tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.data.id = fwrule.id;
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
function updateAway(ctx, next) {
|
||||
var data = ctx.data;
|
||||
|
||||
tritonapi.cloudapi.updateFirewallRule(data, function (err) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
|
||||
delete data.id;
|
||||
console.log('Updated firewall rule %s (fields: %s)', id,
|
||||
keys.join(', '));
|
||||
Object.keys(data).join(', '));
|
||||
|
||||
next();
|
||||
});
|
||||
|
@ -66,6 +66,14 @@ function gen_do_ACTION(opts) {
|
||||
}
|
||||
];
|
||||
|
||||
if (action === 'start') {
|
||||
do_ACTION.options.push({
|
||||
names: ['snapshot'],
|
||||
type: 'string',
|
||||
help: 'Name of snapshot to start machine with.'
|
||||
});
|
||||
}
|
||||
|
||||
return do_ACTION;
|
||||
}
|
||||
|
||||
@ -77,7 +85,8 @@ function _doTheAction(action, subcmd, opts, args, callback) {
|
||||
var command, state;
|
||||
switch (action) {
|
||||
case 'start':
|
||||
command = 'startMachine';
|
||||
command = opts.snapshot ? 'startMachineFromSnapshot' :
|
||||
'startMachine';
|
||||
state = 'running';
|
||||
break;
|
||||
case 'stop':
|
||||
@ -126,7 +135,12 @@ function _doTheAction(action, subcmd, opts, args, callback) {
|
||||
|
||||
// called when "uuid" is set
|
||||
function done() {
|
||||
self.top.tritonapi.cloudapi[command](uuid,
|
||||
var cOpts = uuid;
|
||||
if (command === 'startMachineFromSnapshot') {
|
||||
cOpts = { id: uuid, name: opts.snapshot };
|
||||
}
|
||||
|
||||
self.top.tritonapi.cloudapi[command](cOpts,
|
||||
function (err, body, res) {
|
||||
|
||||
if (err) {
|
||||
|
@ -30,7 +30,9 @@ function SnapshotCLI(top) {
|
||||
'list',
|
||||
'get',
|
||||
'delete'
|
||||
]
|
||||
],
|
||||
helpBody: 'Machines can be rolled back to a snapshot using\n' +
|
||||
'`triton instance start --snapshot=SNAPSHOT-NAME`'
|
||||
});
|
||||
}
|
||||
util.inherits(SnapshotCLI, Cmdln);
|
||||
|
@ -221,7 +221,7 @@ TritonApi.prototype._cacheGetJson = function _cacheGetJson(key, cb) {
|
||||
*
|
||||
* @param opts {Object} Optional.
|
||||
* - useCache {Boolean} Default false. Whether to use Triton's local cache.
|
||||
* Note that the *currently* implementation will only use the cache
|
||||
* Note that the *current* implementation will only use the cache
|
||||
* when there are no filter options.
|
||||
* - ... all other cloudapi ListImages options per
|
||||
* <https://apidocs.joyent.com/cloudapi/#ListImages>
|
||||
@ -537,6 +537,53 @@ TritonApi.prototype.getNetwork = function getNetwork(name, cb) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a firewall rule by ID, or short ID, in that order.
|
||||
*
|
||||
* If there is more than one firewall rule with that short ID, then this errors
|
||||
* out.
|
||||
*/
|
||||
TritonApi.prototype.getFirewallRule = function getFirewallRule(id, cb) {
|
||||
assert.string(id, 'id');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
if (common.isUUID(id)) {
|
||||
this.cloudapi.getFirewallRule(id, function (err, fwrule) {
|
||||
if (err) {
|
||||
if (err.restCode === 'ResourceNotFound') {
|
||||
err = new errors.ResourceNotFoundError(err,
|
||||
format('firewall rule with id %s was not found', id));
|
||||
}
|
||||
cb(err);
|
||||
} else {
|
||||
cb(null, fwrule);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.cloudapi.listFirewallRules(function (err, fwrules) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
var shortIdMatches = fwrules.filter(function (fwrule) {
|
||||
return fwrule.id.slice(0, 8) === id;
|
||||
});
|
||||
|
||||
if (shortIdMatches.length === 1) {
|
||||
cb(null, shortIdMatches[0]);
|
||||
} else if (shortIdMatches.length === 0) {
|
||||
cb(new errors.ResourceNotFoundError(format(
|
||||
'no firewall rule with short id "%s" was found', id)));
|
||||
} else {
|
||||
cb(new errors.ResourceNotFoundError(
|
||||
format('"%s" is an ambiguous short id, with multiple ' +
|
||||
'matching firewall rules', id)));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get an instance by ID, exact name, or short ID, in that order.
|
||||
*
|
||||
|
@ -86,6 +86,19 @@ test('triton snapshot', function (tt) {
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' triton instance start --snapshot', function (t) {
|
||||
var cmd = 'instance start ' + INST + ' -w --snapshot=' + SNAP_NAME;
|
||||
|
||||
h.triton(cmd, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'triton instance start --snapshot'))
|
||||
return t.end();
|
||||
|
||||
t.ok(stdout.match('Start instance ' + INST));
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' triton snapshot delete', function (t) {
|
||||
var cmd = 'snapshot delete ' + INST + ' ' + SNAP_NAME + ' -w --force';
|
||||
h.triton(cmd, function (err, stdout, stderr) {
|
||||
|
Reference in New Issue
Block a user