joyent/node-triton#52 Fix interactive 'triton ssh <inst>' sessions; add workaround for #52

This commit is contained in:
Trent Mick 2016-03-11 14:58:27 -08:00
parent 3824623404
commit 4f778f696e
3 changed files with 70 additions and 17 deletions

View File

@ -1,13 +1,25 @@
# node-triton changelog # node-triton changelog
Known issues:
- `triton ssh ...` disables ssh ControlMaster to avoid issue #52.
## 4.7.1 (not yet released) ## 4.7.1 (not yet released)
- #52 Workaround for `triton ssh ...`. In version 4.6.0, `triton ssh ...`
interactive sessions were broken. This version reverts that change and adds
a workaround for #52 (by disabling ControlMaster when spawning `ssh`).
See <https://github.com/joyent/node-triton/issues/52> for details.
- #97 `triton profile set -` to set the *last* profile as current. - #97 `triton profile set -` to set the *last* profile as current.
- PUBAPI-1266 Added `instance enable-firewall` and `instance disable-firewall` - PUBAPI-1266 Added `instance enable-firewall` and `instance disable-firewall`
## 4.7.0 ## 4.7.0
**Known issue: `triton ssh` interactive sessions are broken.
Upgrade to v4.7.1.**
- #101 Bash completion for server-side data: instances, images, etc. - #101 Bash completion for server-side data: instances, images, etc.
Bash completion on TAB should now work for things like the following: Bash completion on TAB should now work for things like the following:
`triton create <TAB to complete images> <TAB to complete packages`, `triton create <TAB to complete images> <TAB to complete packages`,
@ -20,6 +32,9 @@
## 4.6.0 ## 4.6.0
**Known issue: `triton ssh` interactive sessions are broken.
Upgrade to v4.7.1.**
- #98 `triton inst get ID` for a deleted instance will now emit the instance - #98 `triton inst get ID` for a deleted instance will now emit the instance
object and error less obtusely. This adds a new `InstanceDeleted` error code object and error less obtusely. This adds a new `InstanceDeleted` error code
from `TritonApi`. from `TritonApi`.

View File

@ -10,6 +10,7 @@
* `triton instance ssh ...` * `triton instance ssh ...`
*/ */
var path = require('path');
var spawn = require('child_process').spawn; var spawn = require('child_process').spawn;
var common = require('../common'); var common = require('../common');
@ -26,6 +27,7 @@ function do_ssh(subcmd, opts, args, callback) {
return; return;
} }
var cli = this.top;
var id = args.shift(); var id = args.shift();
var user = 'root'; var user = 'root';
@ -35,7 +37,7 @@ function do_ssh(subcmd, opts, args, callback) {
id = id.substr(i + 1); id = id.substr(i + 1);
} }
this.top.tritonapi.getInstance(id, function (err, inst) { cli.tritonapi.getInstance(id, function (err, inst) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
@ -47,16 +49,33 @@ function do_ssh(subcmd, opts, args, callback) {
return; return;
} }
args = ['-l', user].concat(ip).concat(args); args = ['-l', user, ip].concat(args);
/*
* By default we disable ControlMaster (aka mux, aka SSH connection
* multiplexing) because of
* https://github.com/joyent/node-triton/issues/52
*
*/
if (!opts.no_disable_mux) {
/*
* A simple `-o ControlMaster=no` doesn't work. With just that
* option, a `ControlPath` option (from ~/.ssh/config) will still
* be used if it exists. Our hack is to set a ControlPath we
* know should not exist. Using '/dev/null' wasn't a good
* alternative because `ssh` tries "$ControlPath.$somerandomnum"
* and also because Windows.
*/
var nullSshControlPath = path.resolve(
cli.tritonapi.config._configDir, 'tmp', 'nullSshControlPath');
args = [
'-o', 'ControlMaster=no',
'-o', 'ControlPath='+nullSshControlPath
].concat(args);
}
self.top.log.info({args: args}, 'forking ssh'); self.top.log.info({args: args}, 'forking ssh');
var child = spawn('ssh', args); var child = spawn('ssh', args, {stdio: 'inherit'});
child.stdout.on('data', function (chunk) {
process.stdout.write(chunk);
});
child.stderr.on('data', function (chunk) {
process.stderr.write(chunk);
});
child.on('close', function (code) { child.on('close', function (code) {
/* /*
* Once node 0.10 support is dropped we could instead: * Once node 0.10 support is dropped we could instead:
@ -73,16 +92,34 @@ do_ssh.options = [
names: ['help', 'h'], names: ['help', 'h'],
type: 'bool', type: 'bool',
help: 'Show this help.' help: 'Show this help.'
},
{
names: ['no-disable-mux', 'M'],
type: 'bool',
help: 'Do *not* disable usage of SSH connection multiplexing. Using '
+ 'this option might result in hitting a known issue where '
+ 'command output is lost. See below.'
} }
]; ];
do_ssh.help = ( do_ssh.help = [
'SSH to the primary IP of an instance\n' /* BEGIN JSSTYLED */
+ '\n' 'SSH to the primary IP of an instance',
+ 'Usage:\n' '',
+ ' {{name}} ssh <alias|id> [arguments]\n' 'Usage:',
+ '\n' ' {{name}} ssh [-h] [-M] <inst> [<ssh-arguments>]',
+ '{{options}}' '',
); '{{options}}',
'Where <inst> is the name, short ID or ID of a given instance. Note that',
'the <inst> argument must come before any `ssh` options or arguments.',
'',
'There is a known issue with SSH connection multiplexing (a.k.a. ',
'ControlMaster, mux) where stdout/stderr is lost. As a workaround, `ssh`',
'is spawned with options disabling ControlMaster. You may use the `-M`',
'option to not disable ControlMaster but, with node >=0.12, you will lose',
'stdout/stderr output. See <https://github.com/joyent/node-triton/issues/52>',
'for details.'
/* END JSSTYLED */
].join('\n');
do_ssh.interspersedOptions = false; do_ssh.interspersedOptions = false;

View File

@ -21,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.interspersedOptions = targ.interspersedOptions;
do_ssh.options = targ.options; do_ssh.options = targ.options;
do_ssh.completionArgtypes = targ.completionArgtypes; do_ssh.completionArgtypes = targ.completionArgtypes;