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.
|
* - {String} name (required) the snapshot's name.
|
||||||
* @param {Function} callback of the form f(err, res).
|
* @param {Function} callback of the form f(err, res).
|
||||||
*/
|
*/
|
||||||
|
CloudApi.prototype.startMachineFromSnapshot =
|
||||||
function startMachineFromSnapshot(opts, cb) {
|
function startMachineFromSnapshot(opts, cb) {
|
||||||
assert.object(opts, 'opts');
|
assert.object(opts, 'opts');
|
||||||
assert.uuid(opts.id, 'opts.id');
|
assert.uuid(opts.id, 'opts.id');
|
||||||
@ -1075,13 +1076,13 @@ function startMachineFromSnapshot(opts, cb) {
|
|||||||
|
|
||||||
this._request({
|
this._request({
|
||||||
method: 'POST',
|
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),
|
opts.name),
|
||||||
data: opts
|
data: opts
|
||||||
}, function (err, req, res, body) {
|
}, function (err, req, res, body) {
|
||||||
cb(err, body, res);
|
cb(err, body, res);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,8 +314,7 @@ function uuidToShortId(s) {
|
|||||||
*
|
*
|
||||||
* Short IDs:
|
* Short IDs:
|
||||||
* - UUID prefix
|
* - UUID prefix
|
||||||
* - allow '-' to be elided (to support using containers IDs from
|
* - allow '-' to be elided (to support using containers IDs from docker)
|
||||||
* docker)
|
|
||||||
* - support docker ID *longer* than a UUID? The curr implementation does.
|
* - support docker ID *longer* than a UUID? The curr implementation does.
|
||||||
*/
|
*/
|
||||||
function normShortId(s) {
|
function normShortId(s) {
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
var assert = require('assert-plus');
|
var assert = require('assert-plus');
|
||||||
var format = require('util').format;
|
var format = require('util').format;
|
||||||
var fs = require('fs');
|
|
||||||
var sshpk = require('sshpk');
|
|
||||||
var vasync = require('vasync');
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
@ -60,19 +58,26 @@ function do_delete(subcmd, opts, args, cb) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function deleteThem(_, next) {
|
function deleteThem(_, next) {
|
||||||
vasync.forEachPipeline({
|
vasync.forEachParallel({
|
||||||
inputs: ruleIds,
|
inputs: ruleIds,
|
||||||
func: function deleteOne(id, nextId) {
|
func: function deleteOne(id, nextId) {
|
||||||
cli.tritonapi.cloudapi.deleteFirewallRule({
|
cli.tritonapi.getFirewallRule(id, function (err, fwrule) {
|
||||||
id: id
|
|
||||||
}, function (err) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
nextId(err);
|
nextId(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Deleted rule %s', id);
|
cli.tritonapi.cloudapi.deleteFirewallRule({
|
||||||
nextId();
|
id: fwrule.id
|
||||||
|
}, function (err2) {
|
||||||
|
if (err2) {
|
||||||
|
nextId(err2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Deleted rule %s', id);
|
||||||
|
nextId();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, next);
|
}, next);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var assert = require('assert-plus');
|
var assert = require('assert-plus');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
var errors = require('../errors');
|
var errors = require('../errors');
|
||||||
@ -25,27 +26,45 @@ function do_disable(subcmd, opts, args, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
cb(new errors.UsageError('Missing FWRULE-ID argument'));
|
cb(new errors.UsageError('Missing FWRULE-ID argument(s)'));
|
||||||
return;
|
|
||||||
} else if (args.length > 1) {
|
|
||||||
cb(new errors.UsageError('Incorrect number of arguments'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = args[0];
|
|
||||||
var cli = this.top;
|
var cli = this.top;
|
||||||
|
|
||||||
// XXX add support for shortId
|
vasync.forEachParallel({
|
||||||
cli.tritonapi.cloudapi.disableFirewallRule(id, function onRule(err) {
|
inputs: args,
|
||||||
if (err) {
|
func: function disableOne(id, nextId) {
|
||||||
cb(err);
|
if (common.isUUID(id)) {
|
||||||
return;
|
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) {
|
||||||
|
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);
|
||||||
|
nextId();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}, cb);
|
||||||
console.log('Disabled firewall rule %s', id);
|
|
||||||
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var assert = require('assert-plus');
|
var assert = require('assert-plus');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
var errors = require('../errors');
|
var errors = require('../errors');
|
||||||
@ -25,27 +26,45 @@ function do_enable(subcmd, opts, args, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
cb(new errors.UsageError('Missing FWRULE-ID argument'));
|
cb(new errors.UsageError('Missing FWRULE-ID argument(s)'));
|
||||||
return;
|
|
||||||
} else if (args.length > 1) {
|
|
||||||
cb(new errors.UsageError('Incorrect number of arguments'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = args[0];
|
|
||||||
var cli = this.top;
|
var cli = this.top;
|
||||||
|
|
||||||
// XXX add support for shortId
|
vasync.forEachParallel({
|
||||||
cli.tritonapi.cloudapi.enableFirewallRule(id, function onRule(err) {
|
inputs: args,
|
||||||
if (err) {
|
func: function enableOne(id, nextId) {
|
||||||
cb(err);
|
if (common.isUUID(id)) {
|
||||||
return;
|
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) {
|
||||||
|
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);
|
||||||
|
nextId();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}, cb);
|
||||||
console.log('Enabled firewall rule %s', id);
|
|
||||||
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +79,7 @@ do_enable.help = [
|
|||||||
'Enable a specific firewall rule.',
|
'Enable a specific firewall rule.',
|
||||||
'',
|
'',
|
||||||
'Usage:',
|
'Usage:',
|
||||||
' {{name}} enable FWRULE-ID',
|
' {{name}} enable FWRULE-ID [FWRULE-ID...]',
|
||||||
'',
|
'',
|
||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
@ -36,8 +36,7 @@ function do_get(subcmd, opts, args, cb) {
|
|||||||
var id = args[0];
|
var id = args[0];
|
||||||
var cli = this.top;
|
var cli = this.top;
|
||||||
|
|
||||||
// XXX add support for shortId
|
cli.tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||||
cli.tritonapi.cloudapi.getFirewallRule(id, function onRule(err, fwrule) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
return;
|
return;
|
||||||
|
@ -58,7 +58,7 @@ function do_list(subcmd, opts, args, cb) {
|
|||||||
|
|
||||||
if (columns.indexOf('shortid') !== -1) {
|
if (columns.indexOf('shortid') !== -1) {
|
||||||
rules.forEach(function (rule) {
|
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) {
|
function validateIt(ctx, next) {
|
||||||
var keys = Object.keys(ctx.data);
|
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++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
var key = keys[i];
|
var key = keys[i];
|
||||||
var value = ctx.data[key];
|
var value = ctx.data[key];
|
||||||
@ -129,24 +136,38 @@ function do_update(subcmd, opts, args, cb) {
|
|||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
|
|
||||||
function updateAway(ctx, next) {
|
// we need to look up the full UUID if the given id is a short id
|
||||||
var keys = Object.keys(ctx.data);
|
function getFullId(ctx, next) {
|
||||||
if (keys.length === 0) {
|
if (common.isUUID(id)) {
|
||||||
console.log('No fields given for firewall rule update');
|
ctx.data.id = id;
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.data.id = id;
|
tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
|
||||||
|
|
||||||
tritonapi.cloudapi.updateFirewallRule(ctx.data, function (err) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
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,
|
console.log('Updated firewall rule %s (fields: %s)', id,
|
||||||
keys.join(', '));
|
Object.keys(data).join(', '));
|
||||||
|
|
||||||
next();
|
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;
|
return do_ACTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +85,8 @@ function _doTheAction(action, subcmd, opts, args, callback) {
|
|||||||
var command, state;
|
var command, state;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'start':
|
case 'start':
|
||||||
command = 'startMachine';
|
command = opts.snapshot ? 'startMachineFromSnapshot' :
|
||||||
|
'startMachine';
|
||||||
state = 'running';
|
state = 'running';
|
||||||
break;
|
break;
|
||||||
case 'stop':
|
case 'stop':
|
||||||
@ -126,7 +135,12 @@ function _doTheAction(action, subcmd, opts, args, callback) {
|
|||||||
|
|
||||||
// called when "uuid" is set
|
// called when "uuid" is set
|
||||||
function done() {
|
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) {
|
function (err, body, res) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -30,7 +30,9 @@ function SnapshotCLI(top) {
|
|||||||
'list',
|
'list',
|
||||||
'get',
|
'get',
|
||||||
'delete'
|
'delete'
|
||||||
]
|
],
|
||||||
|
helpBody: 'Machines can be rolled back to a snapshot using\n' +
|
||||||
|
'`triton instance start --snapshot=SNAPSHOT-NAME`'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
util.inherits(SnapshotCLI, Cmdln);
|
util.inherits(SnapshotCLI, Cmdln);
|
||||||
|
@ -221,7 +221,7 @@ TritonApi.prototype._cacheGetJson = function _cacheGetJson(key, cb) {
|
|||||||
*
|
*
|
||||||
* @param opts {Object} Optional.
|
* @param opts {Object} Optional.
|
||||||
* - useCache {Boolean} Default false. Whether to use Triton's local cache.
|
* - 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.
|
* when there are no filter options.
|
||||||
* - ... all other cloudapi ListImages options per
|
* - ... all other cloudapi ListImages options per
|
||||||
* <https://apidocs.joyent.com/cloudapi/#ListImages>
|
* <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.
|
* 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) {
|
tt.test(' triton snapshot delete', function (t) {
|
||||||
var cmd = 'snapshot delete ' + INST + ' ' + SNAP_NAME + ' -w --force';
|
var cmd = 'snapshot delete ' + INST + ' ' + SNAP_NAME + ' -w --force';
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
Reference in New Issue
Block a user