resin ssh proxy support

This commit is contained in:
Eugene Mirotin 2017-05-11 14:34:22 +03:00
parent 1d06bc1b4f
commit bc79832e1d
10 changed files with 70 additions and 76 deletions

View File

@ -14,6 +14,7 @@ Requisites
- [Git](https://git-scm.com) - [Git](https://git-scm.com)
- The following executables should be correctly installed in your shell environment: - The following executables should be correctly installed in your shell environment:
- `ssh`: Any recent version of the OpenSSH ssh client (required by `resin sync` and `resin ssh`) - `ssh`: Any recent version of the OpenSSH ssh client (required by `resin sync` and `resin ssh`)
- if you need `ssh` to work behind the proxy you also need `proxytunnel`[http://proxytunnel.sourceforge.net/] installed (available as `proxytunnel` package for Ubuntu, for example)
- `rsync`: >= 2.6.9 (required by `resin sync`) - `rsync`: >= 2.6.9 (required by `resin sync`)
##### Windows Support ##### Windows Support
@ -26,6 +27,7 @@ If you still want to use `cmd.exe` you will have to use a package manager like M
2. Install the `msys-rsync` and `msys-openssh` packages. 2. Install the `msys-rsync` and `msys-openssh` packages.
3. Add MinGW to the `%PATH%` if this hasn't been done by the installer already. The location where the binaries are places is usually `C:\MinGW\msys\1.0\bin`, but it can vary if you selected a different location in the installer. 3. Add MinGW to the `%PATH%` if this hasn't been done by the installer already. The location where the binaries are places is usually `C:\MinGW\msys\1.0\bin`, but it can vary if you selected a different location in the installer.
4. Copy your SSH keys to `%homedrive%%homepath\.ssh`. 4. Copy your SSH keys to `%homedrive%%homepath\.ssh`.
5. Install [proxytunnel](http://proxytunnel.sourceforge.net/)
Getting Started Getting Started
--------------- ---------------

View File

@ -94,18 +94,4 @@ exports.pipeContainerStream = Promise.method(function(arg) {
}); });
}); });
exports.getSubShellCommand = function(command) { exports.getSubShellCommand = require('../../utils/helpers');
var os;
os = require('os');
if (os.platform() === 'win32') {
return {
program: 'cmd.exe',
args: ['/s', '/c', command]
};
} else {
return {
program: '/bin/sh',
args: ['-c', command]
};
}
};

View File

@ -17,21 +17,7 @@ limitations under the License.
*/ */
var getSubShellCommand; var getSubShellCommand;
getSubShellCommand = function(command) { getSubShellCommand = require('../utils/helpers').getSubShellCommand;
var os;
os = require('os');
if (os.platform() === 'win32') {
return {
program: 'cmd.exe',
args: ['/s', '/c', command]
};
} else {
return {
program: '/bin/sh',
args: ['-c', command]
};
}
};
module.exports = { module.exports = {
signature: 'ssh [uuid]', signature: 'ssh [uuid]',
@ -73,7 +59,7 @@ module.exports = {
} }
return patterns.inferOrSelectDevice(); return patterns.inferOrSelectDevice();
}).then(function(uuid) { }).then(function(uuid) {
console.info("Connecting with: " + uuid); console.info("Connecting to: " + uuid);
return resin.models.device.get(uuid); return resin.models.device.get(uuid);
}).then(function(device) { }).then(function(device) {
if (!device.is_online) { if (!device.is_online) {
@ -91,8 +77,17 @@ module.exports = {
throw new Error('Did not find running application container'); throw new Error('Did not find running application container');
} }
return Promise["try"](function() { return Promise["try"](function() {
var command, subShellCommand; var command, proxyAuth, proxyConfig, proxyHost, proxytunnelCommand, sshProxyCommand, subShellCommand;
command = "ssh " + verbose + " -t -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=no -p " + options.port + " " + username + "@ssh." + proxyUrl + " enter " + uuid + " " + containerId; sshProxyCommand = '';
proxyConfig = global.PROXY_CONFIG;
if (proxyConfig) {
proxyAuth = proxyConfig.proxyAuth;
proxyHost = "-p " + proxyConfig.host + ":" + proxyConfig.port;
proxyAuth = proxyAuth ? "-P " + proxyAuth : '';
proxytunnelCommand = "proxytunnel " + proxyHost + " " + proxyAuth + " -d %h:%p";
sshProxyCommand = "-o ProxyCommand='" + proxytunnelCommand + "'";
}
command = "ssh " + verbose + " -t -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=no " + sshProxyCommand + " -p " + options.port + " " + username + "@ssh." + proxyUrl + " enter " + uuid + " " + containerId;
subShellCommand = getSubShellCommand(command); subShellCommand = getSubShellCommand(command);
return child_process.spawn(subShellCommand.program, subShellCommand.args, { return child_process.spawn(subShellCommand.program, subShellCommand.args, {
stdio: 'inherit' stdio: 'inherit'

View File

@ -47,6 +47,8 @@ try {
globalTunnel.initialize(proxy); globalTunnel.initialize(proxy);
global.PROXY_CONFIG = globalTunnel.proxyConfig;
_ = require('lodash'); _ = require('lodash');
Promise = require('bluebird'); Promise = require('bluebird');

View File

@ -110,3 +110,19 @@ exports.getAppInfo = function(application) {
return app; return app;
}); });
}; };
exports.getSubShellCommand = function(command) {
var os;
os = require('os');
if (os.platform() === 'win32') {
return {
program: 'cmd.exe',
args: ['/s', '/c', command]
};
} else {
return {
program: '/bin/sh',
args: ['-c', command]
};
}
};

View File

@ -58,21 +58,4 @@ exports.pipeContainerStream = Promise.method ({ deviceIp, name, outStream, follo
return console.log(chalk.red.bold("Container '#{name}' not found.")) return console.log(chalk.red.bold("Container '#{name}' not found."))
throw err throw err
# A function to reliably execute a command exports.getSubShellCommand = require('../../utils/helpers')
# in all supported operating systems, including
# different Windows environments like `cmd.exe`
# and `Cygwin` should be encapsulated in a
# re-usable package.
exports.getSubShellCommand = (command) ->
os = require('os')
if os.platform() is 'win32'
return {
program: 'cmd.exe'
args: [ '/s', '/c', command ]
}
else
return {
program: '/bin/sh'
args: [ '-c', command ]
}

View File

@ -14,26 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
### ###
# TODO: A function to reliably execute a command { getSubShellCommand } = require('../utils/helpers')
# in all supported operating systems, including
# different Windows environments like `cmd.exe`
# and `Cygwin` should be encapsulated in a
# re-usable package.
# This is literally copy-pasted from the `resin-sync`
# module.
getSubShellCommand = (command) ->
os = require('os')
if os.platform() is 'win32'
return {
program: 'cmd.exe'
args: [ '/s', '/c', command ]
}
else
return {
program: '/bin/sh'
args: [ '-c', command ]
}
module.exports = module.exports =
signature: 'ssh [uuid]' signature: 'ssh [uuid]'
@ -68,12 +49,11 @@ module.exports =
] ]
action: (params, options, done) -> action: (params, options, done) ->
child_process = require('child_process') child_process = require('child_process')
Promise = require 'bluebird' Promise = require('bluebird')
resin = require('resin-sdk-preconfigured') resin = require('resin-sdk-preconfigured')
patterns = require('../utils/patterns') patterns = require('../utils/patterns')
if not options.port? options.port ?= 22
options.port = 22
verbose = if options.verbose then '-vvv' else '' verbose = if options.verbose then '-vvv' else ''
@ -84,7 +64,7 @@ module.exports =
return params.uuid if uuidExists return params.uuid if uuidExists
return patterns.inferOrSelectDevice() return patterns.inferOrSelectDevice()
.then (uuid) -> .then (uuid) ->
console.info("Connecting with: #{uuid}") console.info("Connecting to: #{uuid}")
resin.models.device.get(uuid) resin.models.device.get(uuid)
.then (device) -> .then (device) ->
throw new Error('Device is not online') if not device.is_online throw new Error('Device is not online') if not device.is_online
@ -98,11 +78,20 @@ module.exports =
.then ({ username, uuid, containerId, proxyUrl }) -> .then ({ username, uuid, containerId, proxyUrl }) ->
throw new Error('Did not find running application container') if not containerId? throw new Error('Did not find running application container') if not containerId?
Promise.try -> Promise.try ->
sshProxyCommand = ''
proxyConfig = global.PROXY_CONFIG
if proxyConfig
{ proxyAuth } = proxyConfig
proxyHost = "-p #{proxyConfig.host}:#{proxyConfig.port}"
proxyAuth = if proxyAuth then "-P #{proxyAuth}" else ''
proxytunnelCommand = "proxytunnel #{proxyHost} #{proxyAuth} -d %h:%p"
sshProxyCommand = "-o ProxyCommand='#{proxytunnelCommand}'"
command = "ssh #{verbose} -t \ command = "ssh #{verbose} -t \
-o LogLevel=ERROR \ -o LogLevel=ERROR \
-o StrictHostKeyChecking=no \ -o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \ -o UserKnownHostsFile=/dev/null \
-o ControlMaster=no \ -o ControlMaster=no \
#{sshProxyCommand} \
-p #{options.port} #{username}@ssh.#{proxyUrl} enter #{uuid} #{containerId}" -p #{options.port} #{username}@ssh.#{proxyUrl} enter #{uuid} #{containerId}"
subShellCommand = getSubShellCommand(command) subShellCommand = getSubShellCommand(command)

View File

@ -38,6 +38,9 @@ catch
# If that is not set as well the initialize will do nothing # If that is not set as well the initialize will do nothing
globalTunnel.initialize(proxy) globalTunnel.initialize(proxy)
# TODO: make this a feature of capitano
global.PROXY_CONFIG = globalTunnel.proxyConfig
_ = require('lodash') _ = require('lodash')
Promise = require('bluebird') Promise = require('bluebird')
capitano = require('capitano') capitano = require('capitano')

View File

@ -105,3 +105,21 @@ exports.getAppInfo = (application) ->
app.arch = config.arch app.arch = config.arch
return app return app
) )
# A function to reliably execute a command
# in all supported operating systems, including
# different Windows environments like `cmd.exe`
# and `Cygwin`.
exports.getSubShellCommand = (command) ->
os = require('os')
if os.platform() is 'win32'
return {
program: 'cmd.exe'
args: [ '/s', '/c', command ]
}
else
return {
program: '/bin/sh'
args: [ '-c', command ]
}

View File

@ -47,7 +47,7 @@
"dockerode": "^2.4.2", "dockerode": "^2.4.2",
"drivelist": "^5.0.16", "drivelist": "^5.0.16",
"etcher-image-write": "^9.0.3", "etcher-image-write": "^9.0.3",
"global-tunnel-ng": "^2.0.0", "global-tunnel-ng": "emirotin/global-tunnel#fix-auth",
"inquirer": "^3.0.6", "inquirer": "^3.0.6",
"is-root": "^1.0.0", "is-root": "^1.0.0",
"js-yaml": "^3.7.0", "js-yaml": "^3.7.0",