joyent/node-triton#146 triton instance rename --wait
This commit is contained in:
parent
586b1924a0
commit
5dab69c002
@ -778,7 +778,7 @@ CloudApi.prototype.getMachine = function getMachine(opts, cb) {
|
||||
* @param {Object} opts
|
||||
* - id {UUID} Required. The machine id.
|
||||
* - {String} name. The machine name
|
||||
* @param {Function} callback of the form `function (err, res)`
|
||||
* @param {Function} callback of the form `function (err, body, res)`
|
||||
*/
|
||||
CloudApi.prototype.renameMachine = function renameMachine(opts, callback) {
|
||||
assert.uuid(opts.id, 'opts.id');
|
||||
@ -793,7 +793,7 @@ CloudApi.prototype.renameMachine = function renameMachine(opts, callback) {
|
||||
path: format('/%s/machines/%s', this.account, opts.id),
|
||||
data: data
|
||||
}, function (err, req, res, body) {
|
||||
callback(err, res);
|
||||
callback(err, body, res);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -7,13 +7,7 @@
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
|
||||
|
||||
function perror(err) {
|
||||
console.error('error: %s', err.message);
|
||||
}
|
||||
|
||||
function do_rename(subcmd, opts, args, callback) {
|
||||
var self = this;
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], callback);
|
||||
return;
|
||||
@ -24,14 +18,30 @@ function do_rename(subcmd, opts, args, callback) {
|
||||
callback(new errors.UsageError('missing NEWNAME arg'));
|
||||
return;
|
||||
}
|
||||
var cOpts = {id: args[0], name: args[1]};
|
||||
self.top.tritonapi.renameInstance(cOpts, function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
|
||||
var id = args[0];
|
||||
var name = args[1];
|
||||
console.log('Renaming instance %s to "%s"', id, name);
|
||||
|
||||
var tritonapi = this.top.tritonapi;
|
||||
common.cliSetupTritonApi({cli: this.top}, function onSetup(setupErr) {
|
||||
if (setupErr) {
|
||||
callback(setupErr);
|
||||
}
|
||||
console.log('Renamed instance %s to "%s"', cOpts.id, cOpts.name);
|
||||
callback();
|
||||
|
||||
tritonapi.renameInstance({
|
||||
id: id,
|
||||
name: name,
|
||||
wait: opts.wait,
|
||||
waitTimeout: opts.wait_timeout * 1000
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
console.log('Renamed instance %s to "%s"', id, name);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,6 +51,18 @@ do_rename.options = [
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['wait', 'w'],
|
||||
type: 'bool',
|
||||
help: 'Block until renaming instance is complete.'
|
||||
},
|
||||
{
|
||||
names: ['wait-timeout'],
|
||||
type: 'positiveInteger',
|
||||
default: 120,
|
||||
help: 'The number of seconds to wait before timing out with an error. '
|
||||
+ 'The default is 120 seconds.'
|
||||
}
|
||||
];
|
||||
|
||||
@ -53,7 +75,11 @@ do_rename.help = [
|
||||
'',
|
||||
'{{options}}',
|
||||
'Where "INST" is an instance name, id, or short id',
|
||||
'and "NEWNAME" is an instance name.'
|
||||
'and "NEWNAME" is an instance name.',
|
||||
'',
|
||||
'Changing an instance name is asynchronous.',
|
||||
'Use "--wait" to not return until',
|
||||
'the changes are completed.'
|
||||
].join('\n');
|
||||
|
||||
do_rename.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
@ -817,7 +817,6 @@ TritonApi.prototype.getInstance = function getInstance(opts, cb) {
|
||||
if (inst || instFromList) {
|
||||
return next();
|
||||
}
|
||||
|
||||
self.cloudapi.listMachines({name: opts.id}, function (err, insts) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
@ -2266,14 +2265,24 @@ TritonApi.prototype.deletePolicy = function deletePolicy(opts, cb) {
|
||||
* rename a machine by id.
|
||||
*
|
||||
* @param {Object} opts
|
||||
* - id {UUID} or The machine name or shortID Required.
|
||||
* - {String} name. The machine name
|
||||
* @param {Function} callback of the form `function (err, res)`
|
||||
* - {String} id: Required. The instance name, short id, or id (a UUID).
|
||||
* - {String} name: Required. The new instance name.
|
||||
* - {Boolean} wait: Wait (via polling) until the rename is complete.
|
||||
* Warning: A concurrent rename of the same instance can result in this
|
||||
* polling being unable to notice the change. Use `waitTimeout` to
|
||||
* put an upper bound.
|
||||
* - {Number} waitTimeout: The number of milliseconds after which to
|
||||
* timeout (call `cb` with a timeout error) waiting. Only relevant if
|
||||
* `opts.wait === true`. Default is Infinity (i.e. it doesn't timeout).
|
||||
* @param {Function} callback of the form `function (err, _, res)`
|
||||
*/
|
||||
TritonApi.prototype.renameInstance = function renameInstance(opts, cb) {
|
||||
assert.string(opts.id, 'opts.id');
|
||||
assert.string(opts.name, 'opts.name');
|
||||
assert.optionalBool(opts.wait, 'opts.wait');
|
||||
assert.optionalNumber(opts.waitTimeout, 'opts.waitTimeout');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var self = this;
|
||||
var res;
|
||||
|
||||
@ -2282,16 +2291,86 @@ TritonApi.prototype.renameInstance = function renameInstance(opts, cb) {
|
||||
|
||||
function renameMachine(arg, next) {
|
||||
self.cloudapi.renameMachine({id: arg.instId, name: opts.name},
|
||||
function (err, _res) {
|
||||
function (err, _, _res) {
|
||||
res = _res;
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
|
||||
function waitForNameChanges(arg, next) {
|
||||
if (!opts.wait) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
self._waitForInstanceRename({
|
||||
id: arg.instId,
|
||||
timeout: opts.waitTimeout,
|
||||
name: opts.name
|
||||
}, next);
|
||||
}
|
||||
]}, function (err) {
|
||||
cb(err, res);
|
||||
cb(err, null, res);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared implementation for any methods to change instance name.
|
||||
*
|
||||
* @param {Object} opts
|
||||
* - {String} id: The instance ID Required.
|
||||
* - {String} name: Required change new name
|
||||
* - {Number} timeout: The number of milliseconds after which to
|
||||
* timeout (call `cb` with a timeout error) waiting.
|
||||
* Default is Infinity (i.e. it doesn't timeout).
|
||||
* @param {Function} cb: `function (err)`
|
||||
*/
|
||||
|
||||
TritonApi.prototype._waitForInstanceRename =
|
||||
function _waitForInstanceRename(opts, cb) {
|
||||
var self = this;
|
||||
assert.object(opts, 'opts');
|
||||
assert.uuid(opts.id, 'opts.id');
|
||||
assert.optionalNumber(opts.timeout, 'opts.timeout');
|
||||
var timeout = opts.hasOwnProperty('timeout') ? opts.timeout : Infinity;
|
||||
assert.ok(timeout > 0, 'opts.timeout must be greater than zero');
|
||||
assert.string(opts.name, 'opts.name');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
/*
|
||||
* Hardcoded 2s poll interval for now. Not yet configurable, being mindful
|
||||
* of avoiding lots of clients naively swamping a CloudAPI and hitting
|
||||
* throttling.
|
||||
*/
|
||||
var POLL_INTERVAL = 2 * 1000;
|
||||
|
||||
var startTime = Date.now();
|
||||
|
||||
var poll = function () {
|
||||
self.cloudapi.getMachine({id: opts.id}, function (err, machine) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
if (opts.name === machine.name) {
|
||||
cb();
|
||||
return;
|
||||
|
||||
} else {
|
||||
var elapsedTime = Date.now() - startTime;
|
||||
if (elapsedTime > timeout) {
|
||||
cb(new errors.TimeoutError(format('timeout waiting for '
|
||||
+ 'instance %s rename (elapsed %ds)',
|
||||
opts.id, Math.round(elapsedTime / 1000))));
|
||||
} else {
|
||||
setTimeout(poll, POLL_INTERVAL);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setImmediate(poll);
|
||||
};
|
||||
|
||||
//---- exports
|
||||
|
||||
module.exports = {
|
||||
|
@ -24,6 +24,7 @@ var h = require('./helpers');
|
||||
// --- globals
|
||||
|
||||
var INST_ALIAS = f('nodetritontest-managewf-%s', os.hostname());
|
||||
var INST_ALIAS_NEWNAME = INST_ALIAS + '-renamed';
|
||||
|
||||
var opts = {
|
||||
skip: !h.CONFIG.allowWriteActions
|
||||
@ -236,6 +237,27 @@ test('triton manage workflow', opts, function (tt) {
|
||||
});
|
||||
});
|
||||
|
||||
// rename the instance
|
||||
tt.test(' triton inst rename', function (t) {
|
||||
var args = ['inst', 'rename', '-w', instance.id, INST_ALIAS_NEWNAME];
|
||||
h.safeTriton(t, args, function (err, stdout) {
|
||||
t.ok(stdout.match(/^Renaming instance/m),
|
||||
'"Renaming instance" in stdout');
|
||||
t.ok(stdout.match(/^Renamed instance/m),
|
||||
'"Renamed instance" in stdout');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' confirm renamed', function (t) {
|
||||
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j',
|
||||
INST_ALIAS_NEWNAME]},
|
||||
function (err, inst) {
|
||||
t.equal(inst.name, INST_ALIAS_NEWNAME, 'instance was renamed');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// remove test instance
|
||||
tt.test(' cleanup (triton delete)', function (t) {
|
||||
h.safeTriton(t, ['delete', '-w', instance.id], function () {
|
||||
|
Reference in New Issue
Block a user