joyent/node-triton#101 Bash completion for server-side data: instances, images, etc.
This commit is contained in:
parent
7d635fc81c
commit
e3b5e6b016
@ -1,7 +1,14 @@
|
|||||||
# node-triton changelog
|
# node-triton changelog
|
||||||
|
|
||||||
## 4.6.1 (not yet released)
|
## 4.7.0 (not yet released)
|
||||||
|
|
||||||
|
- #101 Bash completion for server-side data: instances, images, etc.
|
||||||
|
Bash completion on TAB should now work for things like the following:
|
||||||
|
`triton create <TAB to complete images> <TAB to complete packages`,
|
||||||
|
`triton inst tag ls <TAB to complete instances>`. Cached (with a 5 minute
|
||||||
|
TTL) completions for the following data are supported: instances, images,
|
||||||
|
packages, networks, fwrules, account keys.
|
||||||
|
See `triton completion --help` for adding/updating Bash completion.
|
||||||
- #99 `triton profile set ...` alias for `set-current`
|
- #99 `triton profile set ...` alias for `set-current`
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Functions for Bash completion of some 'triton' option/arg types.
|
# Functions for Bash completion of some 'triton' option/arg types.
|
||||||
|
|
||||||
function complete_tritonprofile {
|
function complete_tritonprofile {
|
||||||
local word="$1"
|
local word="$1"
|
||||||
local candidates
|
local candidates
|
||||||
@ -7,6 +8,144 @@ function complete_tritonprofile {
|
|||||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get completions for a given type of Triton (server-side) data.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# _complete_tritondata $type # e.g. _complete_tritondata images
|
||||||
|
#
|
||||||
|
# The easiest/slowest thing to do to complete images would be to just call:
|
||||||
|
# triton [profile-related-args] images -Ho name
|
||||||
|
# or similar. Too slow.
|
||||||
|
#
|
||||||
|
# The next easiest would be this:
|
||||||
|
# candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||||
|
# where `triton` is setup to specially just handle completions if
|
||||||
|
# `TRITON_COMPLETE` is set. That special handling writes out a cache file to
|
||||||
|
# avoid hitting the server every time. This is still too slow because the
|
||||||
|
# node.js startup time for `triton` is too slow (around 1s on my laptop).
|
||||||
|
#
|
||||||
|
# The next choice is to (a) use the special `TRITON_COMPLETE` handling to
|
||||||
|
# fetch data from the server and write out a cache file, but (b) attempt to
|
||||||
|
# find and use that cache file without calling node.js code. The win is
|
||||||
|
# (at least in my usage) faster response time to a <TAB>. The cost is doing
|
||||||
|
# reproducing (imperfectly) in Bash the logic for determining the Triton profile
|
||||||
|
# info to find the cache.
|
||||||
|
#
|
||||||
|
function _complete_tritondata {
|
||||||
|
local type=$1
|
||||||
|
|
||||||
|
# First, find the Triton CLI profile.
|
||||||
|
local profile
|
||||||
|
profile=$(echo "$COMP_LINE" | grep -- '\s\+-p\s*\w\+\s\+' | sed -E 's/.* +-p *([^ ]+) +.*/\1/')
|
||||||
|
if [[ -z "$profile" ]]; then
|
||||||
|
profile=$TRITON_PROFILE
|
||||||
|
fi
|
||||||
|
if [[ -z "$profile" ]]; then
|
||||||
|
profile=$(grep '"profile":' ~/.triton/config.json | cut -d'"' -f4)
|
||||||
|
fi
|
||||||
|
if [[ -z "$profile" ]]; then
|
||||||
|
profile=env
|
||||||
|
fi
|
||||||
|
trace " profile: $profile"
|
||||||
|
|
||||||
|
# Then, determine the account and url that go into the cache dir.
|
||||||
|
# TODO: include -a/-U options that change from profile values
|
||||||
|
# TODO: subuser support
|
||||||
|
local url
|
||||||
|
local account
|
||||||
|
local profileFile
|
||||||
|
profileFile=$HOME/.triton/profiles.d/$profile.json
|
||||||
|
if [[ "$profile" == "env" ]]; then
|
||||||
|
url=$TRITON_URL
|
||||||
|
if [[ -z "$url" ]]; then
|
||||||
|
url=$SDC_URL
|
||||||
|
fi
|
||||||
|
account=$TRITON_ACCOUNT
|
||||||
|
if [[ -z "$account" ]]; then
|
||||||
|
account=$SDC_ACCOUNT
|
||||||
|
fi
|
||||||
|
elif [[ -f $profileFile ]]; then
|
||||||
|
url=$(grep '"url":' $profileFile | cut -d'"' -f4)
|
||||||
|
account=$(grep '"account":' $profileFile | cut -d'"' -f4)
|
||||||
|
fi
|
||||||
|
trace " url: $url"
|
||||||
|
trace " account: $account"
|
||||||
|
|
||||||
|
# Mimic node-triton/lib/common.js#profileSlug
|
||||||
|
local profileSlug
|
||||||
|
profileSlug="$(echo "$account" | sed -E 's/@/_/g')@$(echo "$url" | sed -E 's#^https?://##')"
|
||||||
|
profileSlug="$(echo "$profileSlug" | sed -E 's/[^a-zA-Z0-9_@-]/_/g')"
|
||||||
|
|
||||||
|
local cacheFile
|
||||||
|
cacheFile="$HOME/.triton/cache/$profileSlug/$type.completions"
|
||||||
|
trace " cacheFile: $cacheFile"
|
||||||
|
|
||||||
|
# If we have a cache file, remove it and regenerate if it is >5 minutes old.
|
||||||
|
#
|
||||||
|
# Dev Note: This 5min TTL should match what `lib/cli.js#_emitCompletions()`
|
||||||
|
# is using.
|
||||||
|
local candidates
|
||||||
|
if [[ ! -f "$cacheFile" ]]; then
|
||||||
|
candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||||
|
else
|
||||||
|
local mtime
|
||||||
|
mtime=$(stat -r "$cacheFile" | awk '{print $10}')
|
||||||
|
local ttl=300 # 5 minutes in seconds
|
||||||
|
local age
|
||||||
|
age=$(echo "$(date +%s) - $mtime" | bc)
|
||||||
|
if [[ $age -gt $ttl ]]; then
|
||||||
|
# Out of date. Regenerate the cache file.
|
||||||
|
trace " cacheFile out-of-date (mtime=$mtime, age=$age, ttl=$ttl)"
|
||||||
|
rm "$cacheFile"
|
||||||
|
candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||||
|
else
|
||||||
|
trace " cacheFile is in-date (mtime=$mtime, age=$age, ttl=$ttl)"
|
||||||
|
candidates=$(cat "$cacheFile")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$candidates"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritonpackage {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata packages)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritonimage {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata images)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritoninstance {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata instances)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritonnetwork {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata networks)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritonfwrule {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata fwrules)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
function complete_tritonkey {
|
||||||
|
local word="$1"
|
||||||
|
candidates=$(_complete_tritondata keys)
|
||||||
|
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function complete_tritonupdateaccountfield {
|
function complete_tritonupdateaccountfield {
|
||||||
local word="$1"
|
local word="$1"
|
||||||
local candidates
|
local candidates
|
||||||
|
208
lib/cli.js
208
lib/cli.js
@ -17,6 +17,7 @@ var child_process = require('child_process'),
|
|||||||
exec = child_process.exec;
|
exec = child_process.exec;
|
||||||
var cmdln = require('cmdln'),
|
var cmdln = require('cmdln'),
|
||||||
Cmdln = cmdln.Cmdln;
|
Cmdln = cmdln.Cmdln;
|
||||||
|
var fs = require('fs');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
var util = require('util'),
|
var util = require('util'),
|
||||||
format = util.format;
|
format = util.format;
|
||||||
@ -32,7 +33,7 @@ var tritonapi = require('./tritonapi');
|
|||||||
|
|
||||||
//---- globals
|
//---- globals
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
var packageJson = require('../package.json');
|
||||||
|
|
||||||
var CONFIG_DIR;
|
var CONFIG_DIR;
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
@ -198,7 +199,7 @@ cmdln.dashdash.addOptionType({
|
|||||||
function CLI() {
|
function CLI() {
|
||||||
Cmdln.call(this, {
|
Cmdln.call(this, {
|
||||||
name: 'triton',
|
name: 'triton',
|
||||||
desc: pkg.description,
|
desc: packageJson.description,
|
||||||
options: OPTIONS,
|
options: OPTIONS,
|
||||||
helpOpts: {
|
helpOpts: {
|
||||||
includeEnv: true,
|
includeEnv: true,
|
||||||
@ -260,7 +261,7 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opts.version) {
|
if (opts.version) {
|
||||||
console.log(this.name, pkg.version);
|
console.log(this.name, packageJson.version);
|
||||||
callback(false);
|
callback(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -298,8 +299,26 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
return self._tritonapi;
|
return self._tritonapi;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cmdln class handles `opts.help`.
|
if (process.env.TRITON_COMPLETE) {
|
||||||
Cmdln.prototype.init.apply(this, arguments);
|
/*
|
||||||
|
* If `TRITON_COMPLETE=<type>` is set (typically only in the
|
||||||
|
* Triton CLI bash completion driver, see
|
||||||
|
* "etc/triton-bash-completion-types.sh"), then Bash completions are
|
||||||
|
* fetched and printed, instead of the usual subcommand handling.
|
||||||
|
*
|
||||||
|
* Completion results are typically cached (under "~/.triton/cache")
|
||||||
|
* to avoid hitting the server for data everytime.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* TRITON_COMPLETE=images triton -p my-profile create
|
||||||
|
*/
|
||||||
|
this._emitCompletions(process.env.TRITON_COMPLETE, function (err) {
|
||||||
|
callback(err || false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Cmdln class handles `opts.help`.
|
||||||
|
Cmdln.prototype.init.apply(this, arguments);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -313,6 +332,185 @@ CLI.prototype.fini = function fini(subcmd, err, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch and display Bash completions (one completion per line) for the given
|
||||||
|
* Triton data type (e.g. 'images', 'instances', 'packages', ...).
|
||||||
|
* This caches results (per profile) with a 5 minute TTL.
|
||||||
|
*
|
||||||
|
* Dev Note: If the cache path logic changes, then the *Bash* implementation
|
||||||
|
* of the same logic in "etc/triton-bash-completion-types.sh" must be updated
|
||||||
|
* to match.
|
||||||
|
*/
|
||||||
|
CLI.prototype._emitCompletions = function _emitCompletions(type, cb) {
|
||||||
|
assert.string(type, 'type');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var cacheFile = path.join(this.tritonapi.cacheDir, type + '.completions');
|
||||||
|
var ttl = 5 * 60 * 1000; // timeout of cache file info (ms)
|
||||||
|
var cloudapi = this.tritonapi.cloudapi;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function tryCacheFile(arg, next) {
|
||||||
|
fs.stat(cacheFile, function (err, stats) {
|
||||||
|
if (!err &&
|
||||||
|
stats.mtime.getTime() + ttl >= (new Date()).getTime()) {
|
||||||
|
process.stdout.write(fs.readFileSync(cacheFile));
|
||||||
|
next(true); // early abort
|
||||||
|
} else if (err && err.code !== 'ENOENT') {
|
||||||
|
next(err);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function gather(arg, next) {
|
||||||
|
var completions;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'packages':
|
||||||
|
cloudapi.listPackages({}, function (err, pkgs) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
pkgs.forEach(function (pkg) {
|
||||||
|
if (pkg.name.indexOf(' ') === -1) {
|
||||||
|
// Cannot bash complete results with spaces, so
|
||||||
|
// skip them here.
|
||||||
|
completions.push(pkg.name);
|
||||||
|
}
|
||||||
|
completions.push(pkg.id);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'images':
|
||||||
|
cloudapi.listImages({}, function (err, imgs) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
imgs.forEach(function (img) {
|
||||||
|
// Cannot bash complete results with spaces, so
|
||||||
|
// skip them here.
|
||||||
|
if (img.name.indexOf(' ') === -1) {
|
||||||
|
completions.push(img.name);
|
||||||
|
if (img.version.indexOf(' ') === -1) {
|
||||||
|
completions.push(img.name + '@' + img.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completions.push(img.id);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'instances':
|
||||||
|
cloudapi.listMachines({}, function (err, insts) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
insts.forEach(function (inst) {
|
||||||
|
if (inst.name.indexOf(' ') === -1) {
|
||||||
|
// Cannot bash complete results with spaces, so
|
||||||
|
// skip them here.
|
||||||
|
completions.push(inst.name);
|
||||||
|
}
|
||||||
|
completions.push(inst.id);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'networks':
|
||||||
|
cloudapi.listNetworks({}, function (err, nets) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
nets.forEach(function (net) {
|
||||||
|
if (net.name.indexOf(' ') === -1) {
|
||||||
|
// Cannot bash complete results with spaces, so
|
||||||
|
// skip them here.
|
||||||
|
completions.push(net.name);
|
||||||
|
}
|
||||||
|
completions.push(net.id);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'fwrules':
|
||||||
|
cloudapi.listFirewallRules({}, function (err, fwrules) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
fwrules.forEach(function (fwrule) {
|
||||||
|
completions.push(fwrule.id);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'keys':
|
||||||
|
cloudapi.listKeys({}, function (err, keys) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
completions = [];
|
||||||
|
keys.forEach(function (key) {
|
||||||
|
if (key.name.indexOf(' ') === -1) {
|
||||||
|
// Cannot bash complete results with spaces, so
|
||||||
|
// skip them here.
|
||||||
|
completions.push(key.name);
|
||||||
|
}
|
||||||
|
completions.push(key.fingerprint);
|
||||||
|
});
|
||||||
|
arg.completions = completions.join('\n') + '\n';
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
process.stderr.write('warning: unknown triton completion type: '
|
||||||
|
+ type + '\n');
|
||||||
|
next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
function saveCache(arg, next) {
|
||||||
|
if (!arg.completions) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs.writeFile(cacheFile, arg.completions, next);
|
||||||
|
},
|
||||||
|
|
||||||
|
function emit(arg, next) {
|
||||||
|
if (arg.completions) {
|
||||||
|
console.log(arg.completions);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
if (err === true) { // early abort signal
|
||||||
|
err = null;
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply overrides from CLI options to the given profile object *in place*.
|
* Apply overrides from CLI options to the given profile object *in place*.
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton create ...` bwcompat shortcut for `triton instance create ...`.
|
* `triton create ...` bwcompat shortcut for `triton instance create ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_create');
|
||||||
|
|
||||||
function do_create(subcmd, opts, args, callback) {
|
function do_create(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'create',
|
subcmd: 'create',
|
||||||
@ -19,6 +21,8 @@ function do_create(subcmd, opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_create.help = 'A shortcut for "triton instance create".';
|
do_create.help = 'A shortcut for "triton instance create".';
|
||||||
do_create.options = require('./do_instance/do_create').options;
|
do_create.options = targ.options;
|
||||||
|
|
||||||
|
do_create.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_create;
|
module.exports = do_create;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton delete ...` bwcompat shortcut for `triton instance delete ...`.
|
* `triton delete ...` bwcompat shortcut for `triton instance delete ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_delete');
|
||||||
|
|
||||||
function do_delete(subcmd, opts, args, callback) {
|
function do_delete(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'delete',
|
subcmd: 'delete',
|
||||||
@ -20,6 +22,7 @@ function do_delete(subcmd, opts, args, callback) {
|
|||||||
|
|
||||||
do_delete.help = 'A shortcut for "triton instance delete".';
|
do_delete.help = 'A shortcut for "triton instance delete".';
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
do_delete.options = require('./do_instance/do_delete').options;
|
do_delete.options = targ.options;
|
||||||
|
do_delete.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -107,4 +107,6 @@ do_delete.help = [
|
|||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonfwrule'];
|
||||||
|
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -65,4 +65,6 @@ do_disable.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_disable.completionArgtypes = ['tritonfwrule'];
|
||||||
|
|
||||||
module.exports = do_disable;
|
module.exports = do_disable;
|
||||||
|
@ -65,4 +65,6 @@ do_enable.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_enable.completionArgtypes = ['tritonfwrule'];
|
||||||
|
|
||||||
module.exports = do_enable;
|
module.exports = do_enable;
|
||||||
|
@ -73,4 +73,6 @@ do_get.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonfwrule', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -159,4 +159,6 @@ do_instances.help = [
|
|||||||
|
|
||||||
do_instances.aliases = ['insts'];
|
do_instances.aliases = ['insts'];
|
||||||
|
|
||||||
|
do_instances.completionArgtypes = ['tritonfwrule', 'none'];
|
||||||
|
|
||||||
module.exports = do_instances;
|
module.exports = do_instances;
|
||||||
|
@ -265,5 +265,6 @@ do_create.helpOpts = {
|
|||||||
maxHelpCol: 20
|
maxHelpCol: 20
|
||||||
};
|
};
|
||||||
|
|
||||||
|
do_create.completionArgtypes = ['tritoninstance', 'file'];
|
||||||
|
|
||||||
module.exports = do_create;
|
module.exports = do_create;
|
||||||
|
@ -151,5 +151,7 @@ do_delete.options = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonimage'];
|
||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -67,4 +67,6 @@ do_get.help = (
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -116,13 +116,14 @@ do_wait.help = [
|
|||||||
'Wait for images to change to a particular state.',
|
'Wait for images to change to a particular state.',
|
||||||
'',
|
'',
|
||||||
'Usage:',
|
'Usage:',
|
||||||
' {{name}} wait [-s STATES] IMAGE [IMAGE ...]',
|
' {{name}} wait [-s STATES] IMAGE [IMAGE ...]',
|
||||||
'',
|
'',
|
||||||
'{{options}}',
|
'{{options}}',
|
||||||
'Where "states" is a comma-separated list of target instance states,',
|
'Where "states" is a comma-separated list of target instance states,',
|
||||||
'by default "active,failed". In other words, "triton img wait foo0" will',
|
'by default "active,failed". In other words, "triton img wait foo0" will',
|
||||||
'wait for image "foo0" to complete creation.'
|
'wait for image "foo0" to complete creation.'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
do_wait.options = [
|
do_wait.options = [
|
||||||
{
|
{
|
||||||
names: ['help', 'h'],
|
names: ['help', 'h'],
|
||||||
@ -139,4 +140,6 @@ do_wait.options = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
do_wait.completionArgtypes = ['tritonimage'];
|
||||||
|
|
||||||
module.exports = do_wait;
|
module.exports = do_wait;
|
||||||
|
@ -111,4 +111,6 @@ do_audit.help = (
|
|||||||
+ '{{options}}'
|
+ '{{options}}'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
do_audit.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_audit;
|
module.exports = do_audit;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2015 Joyent, Inc.
|
* Copyright 2016 Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton instance create ...`
|
* `triton instance create ...`
|
||||||
*/
|
*/
|
||||||
@ -289,7 +289,8 @@ do_create.options = [
|
|||||||
type: 'arrayOfCommaSepString',
|
type: 'arrayOfCommaSepString',
|
||||||
helpArg: 'NETWORK',
|
helpArg: 'NETWORK',
|
||||||
help: 'One or more comma-separated networks (ID, name or short id). ' +
|
help: 'One or more comma-separated networks (ID, name or short id). ' +
|
||||||
'This option can be used multiple times.'
|
'This option can be used multiple times.',
|
||||||
|
completionType: 'tritonnetwork'
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX locality: near, far
|
// XXX locality: near, far
|
||||||
@ -330,5 +331,6 @@ do_create.helpOpts = {
|
|||||||
maxHelpCol: 18
|
maxHelpCol: 18
|
||||||
};
|
};
|
||||||
|
|
||||||
|
do_create.completionArgtypes = ['tritonimage', 'tritonpackage', 'none'];
|
||||||
|
|
||||||
module.exports = do_create;
|
module.exports = do_create;
|
||||||
|
@ -100,4 +100,6 @@ do_fwrules.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_fwrules.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_fwrules;
|
module.exports = do_fwrules;
|
||||||
|
@ -60,4 +60,6 @@ do_get.help = (
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -133,4 +133,6 @@ do_create.help = [
|
|||||||
'Snapshot do not work for instances of type "kvm".'
|
'Snapshot do not work for instances of type "kvm".'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_create.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_create;
|
module.exports = do_create;
|
||||||
|
@ -150,4 +150,8 @@ do_delete.help = [
|
|||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
// TODO: When have 'tritonsnapshot' completion, then use this:
|
||||||
|
// do_get.completionArgtypes = ['tritoninstance', 'tritonsnapshot'];
|
||||||
|
do_delete.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -77,4 +77,8 @@ do_get.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
// TODO: When have 'tritonsnapshot' completion, then use this:
|
||||||
|
// do_get.completionArgtypes = ['tritoninstance', 'tritonsnapshot', 'none'];
|
||||||
|
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -93,6 +93,8 @@ do_list.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_list.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
do_list.aliases = ['ls'];
|
do_list.aliases = ['ls'];
|
||||||
|
|
||||||
module.exports = do_list;
|
module.exports = do_list;
|
||||||
|
@ -86,4 +86,8 @@ do_ssh.help = (
|
|||||||
|
|
||||||
do_ssh.interspersedOptions = false;
|
do_ssh.interspersedOptions = false;
|
||||||
|
|
||||||
|
// Use 'file' to fallback to the default bash completion... even though 'file'
|
||||||
|
// isn't quite right.
|
||||||
|
do_ssh.completionArgtypes = ['tritoninstance', 'file'];
|
||||||
|
|
||||||
module.exports = do_ssh;
|
module.exports = do_ssh;
|
||||||
|
@ -109,4 +109,6 @@ do_delete.help = [
|
|||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -65,4 +65,7 @@ do_get.help = [
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
// TODO: When have 'tritoninstancetag' completion, add that in.
|
||||||
|
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -66,4 +66,6 @@ do_list.help = [
|
|||||||
|
|
||||||
do_list.aliases = ['ls'];
|
do_list.aliases = ['ls'];
|
||||||
|
|
||||||
|
do_list.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
|
||||||
module.exports = do_list;
|
module.exports = do_list;
|
||||||
|
@ -129,4 +129,6 @@ do_replace_all.help = [
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_replace_all.completionArgtypes = ['tritoninstance', 'file'];
|
||||||
|
|
||||||
module.exports = do_replace_all;
|
module.exports = do_replace_all;
|
||||||
|
@ -130,4 +130,6 @@ do_set.help = [
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_set.completionArgtypes = ['tritoninstance', 'file'];
|
||||||
|
|
||||||
module.exports = do_set;
|
module.exports = do_set;
|
||||||
|
@ -137,4 +137,6 @@ do_wait.options = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
do_wait.completionArgtypes = ['tritoninstance'];
|
||||||
|
|
||||||
module.exports = do_wait;
|
module.exports = do_wait;
|
||||||
|
@ -66,6 +66,8 @@ function gen_do_ACTION(opts) {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
do_ACTION.completionArgtypes = ['tritoninstance'];
|
||||||
|
|
||||||
if (action === 'start') {
|
if (action === 'start') {
|
||||||
do_ACTION.options.push({
|
do_ACTION.options.push({
|
||||||
names: ['snapshot'],
|
names: ['snapshot'],
|
||||||
|
@ -116,4 +116,6 @@ do_delete.help = [
|
|||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonkey'];
|
||||||
|
|
||||||
module.exports = do_delete;
|
module.exports = do_delete;
|
||||||
|
@ -77,4 +77,6 @@ do_get.help = [
|
|||||||
'Where "KEY" is an SSH key "name" or "fingerprint".'
|
'Where "KEY" is an SSH key "name" or "fingerprint".'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonkey', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -60,4 +60,6 @@ do_get.help = (
|
|||||||
+ '{{options}}'
|
+ '{{options}}'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonnetwork', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -66,4 +66,6 @@ do_get.help = (
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonpackage', 'none'];
|
||||||
|
|
||||||
module.exports = do_get;
|
module.exports = do_get;
|
||||||
|
@ -129,6 +129,7 @@ do_delete.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonprofile', 'none'];
|
||||||
|
|
||||||
do_delete.aliases = ['rm'];
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
@ -163,5 +163,6 @@ do_edit.help = [
|
|||||||
'{{options}}'
|
'{{options}}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
do_edit.completionArgtypes = ['tritonprofile', 'none'];
|
||||||
|
|
||||||
module.exports = do_edit;
|
module.exports = do_edit;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton reboot ...` bwcompat shortcut for `triton instance reboot ...`.
|
* `triton reboot ...` bwcompat shortcut for `triton instance reboot ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_reboot');
|
||||||
|
|
||||||
function do_reboot(subcmd, opts, args, callback) {
|
function do_reboot(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'reboot',
|
subcmd: 'reboot',
|
||||||
@ -19,6 +21,7 @@ function do_reboot(subcmd, opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_reboot.help = 'A shortcut for "triton instance reboot".';
|
do_reboot.help = 'A shortcut for "triton instance reboot".';
|
||||||
do_reboot.options = require('./do_instance/do_reboot').options;
|
do_reboot.options = targ.options;
|
||||||
|
do_reboot.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_reboot;
|
module.exports = do_reboot;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton ssh ...` bwcompat shortcut for `triton instance ssh ...`.
|
* `triton ssh ...` bwcompat shortcut for `triton instance ssh ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_ssh');
|
||||||
|
|
||||||
function do_ssh(subcmd, opts, args, callback) {
|
function do_ssh(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'ssh',
|
subcmd: 'ssh',
|
||||||
@ -19,6 +21,7 @@ function do_ssh(subcmd, opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_ssh.help = 'A shortcut for "triton instance ssh".';
|
do_ssh.help = 'A shortcut for "triton instance ssh".';
|
||||||
do_ssh.options = require('./do_instance/do_ssh').options;
|
do_ssh.options = targ.options;
|
||||||
|
do_ssh.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_ssh;
|
module.exports = do_ssh;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton start ...` bwcompat shortcut for `triton instance start ...`.
|
* `triton start ...` bwcompat shortcut for `triton instance start ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_start');
|
||||||
|
|
||||||
function do_start(subcmd, opts, args, callback) {
|
function do_start(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'start',
|
subcmd: 'start',
|
||||||
@ -19,6 +21,7 @@ function do_start(subcmd, opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_start.help = 'A shortcut for "triton instance start".';
|
do_start.help = 'A shortcut for "triton instance start".';
|
||||||
do_start.options = require('./do_instance/do_start').options;
|
do_start.options = targ.options;
|
||||||
|
do_start.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_start;
|
module.exports = do_start;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
* `triton stop ...` bwcompat shortcut for `triton instance stop ...`.
|
* `triton stop ...` bwcompat shortcut for `triton instance stop ...`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var targ = require('./do_instance/do_stop');
|
||||||
|
|
||||||
function do_stop(subcmd, opts, args, callback) {
|
function do_stop(subcmd, opts, args, callback) {
|
||||||
this.handlerFromSubcmd('instance').dispatch({
|
this.handlerFromSubcmd('instance').dispatch({
|
||||||
subcmd: 'stop',
|
subcmd: 'stop',
|
||||||
@ -19,6 +21,7 @@ function do_stop(subcmd, opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_stop.help = 'A shortcut for "triton instance stop".';
|
do_stop.help = 'A shortcut for "triton instance stop".';
|
||||||
do_stop.options = require('./do_instance/do_stop').options;
|
do_stop.options = targ.options;
|
||||||
|
do_stop.completionArgtypes = targ.completionArgtypes;
|
||||||
|
|
||||||
module.exports = do_stop;
|
module.exports = do_stop;
|
||||||
|
@ -1271,7 +1271,7 @@ function waitForInstanceTagChanges(opts, cb) {
|
|||||||
if (elapsedTime > timeout) {
|
if (elapsedTime > timeout) {
|
||||||
cb(new errors.TimeoutError(format('timeout waiting for '
|
cb(new errors.TimeoutError(format('timeout waiting for '
|
||||||
+ 'tag changes on instance %s (elapsed %ds)',
|
+ 'tag changes on instance %s (elapsed %ds)',
|
||||||
opts.id, Math.round(elapsedTime * 1000))));
|
opts.id, Math.round(elapsedTime / 1000))));
|
||||||
} else {
|
} else {
|
||||||
setTimeout(poll, POLL_INTERVAL);
|
setTimeout(poll, POLL_INTERVAL);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "triton",
|
"name": "triton",
|
||||||
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
||||||
"version": "4.6.1",
|
"version": "4.7.0",
|
||||||
"author": "Joyent (joyent.com)",
|
"author": "Joyent (joyent.com)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assert-plus": "0.2.0",
|
"assert-plus": "0.2.0",
|
||||||
|
Reference in New Issue
Block a user