Factor out spinner to prep for using it for 'triton wait'.
Also refactor 'triton wait' for debuggability and to avoid possible multiple calls to the callback.
This commit is contained in:
parent
9241f90ccf
commit
12c9cb64a6
5
TODO.txt
5
TODO.txt
@ -4,7 +4,10 @@ MPL blurb at the start of each file.
|
|||||||
|
|
||||||
'make check'
|
'make check'
|
||||||
|
|
||||||
test suite
|
test suite:
|
||||||
|
- all the commands: test/integration/cli-*.test.js
|
||||||
|
- TritonApi testing: test/integration/api-*.test.js
|
||||||
|
- more test/unit/...
|
||||||
|
|
||||||
note in README that full UUIDs is much faster in the API
|
note in README that full UUIDs is much faster in the API
|
||||||
|
|
||||||
|
33
lib/distractions.js
Normal file
33
lib/distractions.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Joyent Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* A CLI distraction during a long process (e.g. waiting for
|
||||||
|
* create).
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* var distractions = require('./distractions');
|
||||||
|
* var distraction = distractions.createDistraction();
|
||||||
|
* setTimeout(function () {
|
||||||
|
* distraction.destroy();
|
||||||
|
* }, 5000);
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bigspinner = require('bigspinner');
|
||||||
|
|
||||||
|
|
||||||
|
function createDistraction() {
|
||||||
|
var BORDER = 10;
|
||||||
|
return bigspinner.createSpinner({
|
||||||
|
delay: 50,
|
||||||
|
positions: 40,
|
||||||
|
stream: process.stderr,
|
||||||
|
height: Math.max(2, process.stdout.rows - 2 - BORDER),
|
||||||
|
width: Math.max(2, process.stdout.columns - 1 - BORDER),
|
||||||
|
hideCursor: true,
|
||||||
|
fontChar: '\u2588' // '\x1b[7m \x1b[m'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createDistraction: createDistraction
|
||||||
|
}
|
@ -4,12 +4,12 @@
|
|||||||
* `triton create ...`
|
* `triton create ...`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var bigspinner = require('bigspinner');
|
|
||||||
var format = require('util').format;
|
var format = require('util').format;
|
||||||
var tabula = require('tabula');
|
var tabula = require('tabula');
|
||||||
var vasync = require('vasync');
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('./common');
|
var common = require('./common');
|
||||||
|
var distractions = require('./distractions');
|
||||||
var errors = require('./errors');
|
var errors = require('./errors');
|
||||||
|
|
||||||
|
|
||||||
@ -107,18 +107,9 @@ function do_create_instance(subcmd, opts, args, callback) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
var spinner;
|
var distraction;
|
||||||
if (!opts.quiet && process.stderr.isTTY) {
|
if (!opts.quiet && process.stderr.isTTY) {
|
||||||
var BORDER = 10;
|
distraction = distractions.createDistraction();
|
||||||
spinner = bigspinner.createSpinner({
|
|
||||||
delay: 50,
|
|
||||||
positions: 40,
|
|
||||||
stream: process.stderr,
|
|
||||||
height: Math.max(2, process.stdout.rows - 2 - BORDER),
|
|
||||||
width: Math.max(2, process.stdout.columns - 1 - BORDER),
|
|
||||||
hideCursor: true,
|
|
||||||
fontChar: '\u2588' // '\x1b[7m \x1b[m'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dry-run: fake wait for a few seconds.
|
// Dry-run: fake wait for a few seconds.
|
||||||
@ -135,8 +126,8 @@ function do_create_instance(subcmd, opts, args, callback) {
|
|||||||
id: ctx.inst.id,
|
id: ctx.inst.id,
|
||||||
states: ['running', 'failed']
|
states: ['running', 'failed']
|
||||||
}, function (err, inst) {
|
}, function (err, inst) {
|
||||||
if (spinner) {
|
if (distraction) {
|
||||||
spinner.destroy();
|
distraction.destroy();
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
|
@ -5,19 +5,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var format = require('util').format;
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('./common');
|
var common = require('./common');
|
||||||
|
var distractions = require('./distractions');
|
||||||
var errors = require('./errors');
|
var errors = require('./errors');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function do_wait_instance(subcmd, opts, args, cb) {
|
function do_wait_instance(subcmd, opts, args, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (opts.help) {
|
if (opts.help) {
|
||||||
return this.do_help('help', {}, [subcmd], cb);
|
return this.do_help('help', {}, [subcmd], cb);
|
||||||
} else if (args.length < 1) {
|
} else if (args.length < 1) {
|
||||||
return cb(new errors.UsageError(format(
|
return cb(new errors.UsageError('missing INSTANCE arg(s)'));
|
||||||
'incorrect number of args (%d): %s', args.length, args.join(' '))));
|
|
||||||
}
|
}
|
||||||
var ids = args;
|
var ids = args;
|
||||||
var states = [];
|
var states = [];
|
||||||
@ -25,40 +25,81 @@ function do_wait_instance(subcmd, opts, args, cb) {
|
|||||||
states = states.concat(s.trim().split(/\s*,\s*/g));
|
states = states.concat(s.trim().split(/\s*,\s*/g));
|
||||||
});
|
});
|
||||||
|
|
||||||
function log() {
|
var distraction;
|
||||||
if (!opts.quiet)
|
|
||||||
console.log.apply(console, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
var done = 0;
|
var done = 0;
|
||||||
|
var instFromId = {};
|
||||||
|
|
||||||
var machines = {};
|
vasync.pipeline({funcs: [
|
||||||
|
function getInsts(_, next) {
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: ids,
|
||||||
|
func: function getInst(id, nextInst) {
|
||||||
|
self.triton.getInstance(id, function (err, inst) {
|
||||||
|
if (err) {
|
||||||
|
return nextInst(err);
|
||||||
|
}
|
||||||
|
if (states.indexOf(inst.state) !== -1) {
|
||||||
|
console.log('%d/%d: Instance %s (%s) already %s',
|
||||||
|
++done, ids.length, inst.name, id, inst.state);
|
||||||
|
} else {
|
||||||
|
instFromId[inst.id] = inst;
|
||||||
|
}
|
||||||
|
nextInst();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
|
||||||
var i = 0;
|
function waitForInsts(_, next) {
|
||||||
ids.forEach(function (id) {
|
var idsToWaitFor = Object.keys(instFromId);
|
||||||
i++;
|
if (idsToWaitFor.length === 0) {
|
||||||
if (common.isUUID(id)) {
|
return next();
|
||||||
machines[id] = {};
|
}
|
||||||
go1();
|
|
||||||
return;
|
if (idsToWaitFor.length === 1) {
|
||||||
|
var inst2 = instFromId[idsToWaitFor[0]];
|
||||||
|
console.log(
|
||||||
|
"Waiting for instance %s (%s) to enter state (states: %s)",
|
||||||
|
inst2.name, inst2.id, states.join(', '));
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"Waiting for %d instances to enter state (states: %s)",
|
||||||
|
idsToWaitFor.length, states.join(', '));
|
||||||
|
}
|
||||||
|
|
||||||
|
var distraction;
|
||||||
|
if (false /* TODO: need BigSpinner.log first */
|
||||||
|
&& !opts.quiet && process.stderr.isTTY)
|
||||||
|
{
|
||||||
|
distraction = distractions.createDistraction();
|
||||||
|
}
|
||||||
|
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: idsToWaitFor,
|
||||||
|
func: function waitForInst(id, nextInst) {
|
||||||
|
self.triton.cloudapi.waitForMachineStates({
|
||||||
|
id: id,
|
||||||
|
states: states
|
||||||
|
}, function (err, inst, res) {
|
||||||
|
if (err) {
|
||||||
|
return nextInst(err);
|
||||||
|
}
|
||||||
|
console.log('%d/%d: Instance %s (%s) moved to state %s',
|
||||||
|
++done, ids.length, inst.name, inst.id, inst.state);
|
||||||
|
nextInst();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.triton.getInstance(id, function (err, machine) {
|
]}, function (err) {
|
||||||
if (err) {
|
if (distraction) {
|
||||||
cb(err);
|
distraction.destroy();
|
||||||
return;
|
}
|
||||||
}
|
cb(err);
|
||||||
if (states.indexOf(machine.state) >= 0) {
|
|
||||||
// machine in acceptable state already... skip it
|
|
||||||
log('%d/%d: %s already in acceptable state: %s',
|
|
||||||
++done, ids.length, id, machine.state);
|
|
||||||
} else {
|
|
||||||
machines[machine.id] = machine;
|
|
||||||
}
|
|
||||||
go1();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function go1() {
|
function go1() {
|
||||||
if (--i > 0)
|
if (--i > 0)
|
||||||
return;
|
return;
|
||||||
@ -95,7 +136,7 @@ function do_wait_instance(subcmd, opts, args, cb) {
|
|||||||
|
|
||||||
do_wait_instance.aliases = ['wait'];
|
do_wait_instance.aliases = ['wait'];
|
||||||
do_wait_instance.help = [
|
do_wait_instance.help = [
|
||||||
'Wait on instances moving to given states.',
|
'Wait on instances changing state.',
|
||||||
'',
|
'',
|
||||||
'Usage:',
|
'Usage:',
|
||||||
' {{name}} wait [-s STATES] INSTANCE [INSTANCE ...]',
|
' {{name}} wait [-s STATES] INSTANCE [INSTANCE ...]',
|
||||||
@ -114,7 +155,7 @@ do_wait_instance.options = [
|
|||||||
{
|
{
|
||||||
names: ['quiet', 'q'],
|
names: ['quiet', 'q'],
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
help: 'Disable all output.'
|
help: 'No progress spinner while waiting.'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
names: ['states', 's'],
|
names: ['states', 's'],
|
||||||
|
Reference in New Issue
Block a user