diff --git a/build/actions/enter.js b/build/actions/enter.js new file mode 100644 index 00000000..faec42aa --- /dev/null +++ b/build/actions/enter.js @@ -0,0 +1,87 @@ + +/* +Copyright 2016 Resin.io + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +(function() { + var getSubShellCommand; + + getSubShellCommand = function(command) { + var os; + os = require('os'); + if (os.platform() === 'win32') { + return { + program: 'sh', + args: ['-c', command] + }; + } else { + return { + program: '/bin/sh', + args: ['-c', command] + }; + } + }; + + module.exports = { + signature: 'enter ', + description: '(beta) get a shell into the running app container of a device', + help: 'Use this command to get a shell into the running application container of\nyour device.\n\nExamples:\n\n $ resin enter 7cf02a6\n $ resin enter 7cf02a6 --port 8080', + permission: 'user', + primary: true, + options: [ + { + signature: 'port', + parameter: 'port', + description: 'ssh port', + alias: 't' + } + ], + action: function(params, options, done) { + var Promise, child_process, resin, settings; + child_process = require('child_process'); + Promise = require('bluebird'); + resin = require('resin-sdk'); + settings = require('resin-settings-client'); + if (options.port == null) { + options.port = 22; + } + console.info("Connecting with: " + params.uuid); + return Promise.props({ + isOnline: resin.models.device.isOnline(params.uuid), + username: resin.auth.whoami(), + uuid: resin.models.device.get(params.uuid).get('uuid'), + containerId: resin.models.device.getApplicationInfo(params.uuid).get('containerId') + }).then(function(arg) { + var containerId, isOnline, username, uuid; + isOnline = arg.isOnline, username = arg.username, uuid = arg.uuid, containerId = arg.containerId; + if (!isOnline) { + throw new Error('Device is not online'); + } + if (containerId == null) { + throw new Error('Did not find running application container'); + } + return Promise["try"](function() { + var command, spawn, subShellCommand; + command = "ssh -t -p " + options.port + " " + username + "@" + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId; + subShellCommand = getSubShellCommand(command); + return spawn = child_process.spawn(subShellCommand.program, subShellCommand.args, { + stdio: 'inherit' + }); + }); + }); + } + }; + +}).call(this); diff --git a/build/actions/index.js b/build/actions/index.js index db9efe23..6c6e7a96 100644 --- a/build/actions/index.js +++ b/build/actions/index.js @@ -30,7 +30,8 @@ limitations under the License. os: require('./os'), settings: require('./settings'), config: require('./config'), - sync: require('./sync') + sync: require('./sync'), + ssh: require('./ssh') }; }).call(this); diff --git a/build/actions/ssh.js b/build/actions/ssh.js new file mode 100644 index 00000000..9ad5ead7 --- /dev/null +++ b/build/actions/ssh.js @@ -0,0 +1,87 @@ + +/* +Copyright 2016 Resin.io + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +(function() { + var getSubShellCommand; + + getSubShellCommand = function(command) { + var os; + os = require('os'); + if (os.platform() === 'win32') { + return { + program: 'sh', + args: ['-c', command] + }; + } else { + return { + program: '/bin/sh', + args: ['-c', command] + }; + } + }; + + module.exports = { + signature: 'ssh ', + description: '(beta) get a shell into the running app container of a device', + help: 'Use this command to get a shell into the running application container of\nyour device.\n\nExamples:\n\n $ resin ssh 7cf02a6\n $ resin ssh 7cf02a6 --port 8080', + permission: 'user', + primary: true, + options: [ + { + signature: 'port', + parameter: 'port', + description: 'ssh gateway port', + alias: 't' + } + ], + action: function(params, options, done) { + var Promise, child_process, resin, settings; + child_process = require('child_process'); + Promise = require('bluebird'); + resin = require('resin-sdk'); + settings = require('resin-settings-client'); + if (options.port == null) { + options.port = 22; + } + console.info("Connecting with: " + params.uuid); + return Promise.props({ + isOnline: resin.models.device.isOnline(params.uuid), + username: resin.auth.whoami(), + uuid: resin.models.device.get(params.uuid).get('uuid'), + containerId: resin.models.device.getApplicationInfo(params.uuid).get('containerId') + }).then(function(arg) { + var containerId, isOnline, username, uuid; + isOnline = arg.isOnline, username = arg.username, uuid = arg.uuid, containerId = arg.containerId; + if (!isOnline) { + throw new Error('Device is not online'); + } + if (containerId == null) { + throw new Error('Did not find running application container'); + } + return Promise["try"](function() { + var command, spawn, subShellCommand; + command = "ssh -t -o LogLevel=QUIET -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p " + options.port + " " + username + "@ssh." + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId; + subShellCommand = getSubShellCommand(command); + return spawn = child_process.spawn(subShellCommand.program, subShellCommand.args, { + stdio: 'inherit' + }); + }); + }); + } + }; + +}).call(this); diff --git a/build/app.js b/build/app.js index 6036a84f..0da7595f 100644 --- a/build/app.js +++ b/build/app.js @@ -135,6 +135,8 @@ limitations under the License. capitano.command(actions.sync); + capitano.command(actions.ssh); + update.notify(); plugins.register(/^resin-plugin-(.+)$/).then(function() { diff --git a/capitanodoc.json b/capitanodoc.json index e11b7c9d..6cbac838 100644 --- a/capitanodoc.json +++ b/capitanodoc.json @@ -56,6 +56,12 @@ "lib/actions/sync.coffee" ] }, + { + "title": "SSH", + "files": [ + "lib/actions/ssh.coffee" + ] + }, { "title": "Notes", "files": [ diff --git a/doc/cli.markdown b/doc/cli.markdown index 317d3f59..3082c157 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -71,6 +71,10 @@ Now you have access to all the commands referenced below. - [sync [source]](#sync-source-) +- SSH + + - [enter <uuid>](#enter-60-uuid-62-) + - Notes - [note <|note>](#note-60-note-62-) @@ -626,6 +630,24 @@ show progress ssh port +# SSH + +## enter <uuid> + +Use this command to get a shell into the running application container of +your device. + +Examples: + + $ resin enter 7cf02a6 + $ resin enter 7cf02a6 --port 8080 + +### Options + +#### --port, -t <port> + +ssh port + # Notes ## note <|note> diff --git a/lib/actions/index.coffee b/lib/actions/index.coffee index 12619bca..0ec98c17 100644 --- a/lib/actions/index.coffee +++ b/lib/actions/index.coffee @@ -29,3 +29,4 @@ module.exports = settings: require('./settings') config: require('./config') sync: require('./sync') + ssh: require('./ssh') diff --git a/lib/actions/ssh.coffee b/lib/actions/ssh.coffee new file mode 100644 index 00000000..667da15c --- /dev/null +++ b/lib/actions/ssh.coffee @@ -0,0 +1,77 @@ +### +Copyright 2016 Resin.io + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +### + +getSubShellCommand = (command) -> + os = require('os') + + # Assume Cygwin + if os.platform() is 'win32' + return { + program: 'sh' + args: [ '-c', command ] + } + else + return { + program: '/bin/sh' + args: [ '-c', command ] + } + +module.exports = + signature: 'ssh ' + description: '(beta) get a shell into the running app container of a device' + help: ''' + Use this command to get a shell into the running application container of + your device. + + Examples: + + $ resin ssh 7cf02a6 + $ resin ssh 7cf02a6 --port 8080 + ''' + permission: 'user' + primary: true + options: [ + signature: 'port' + parameter: 'port' + description: 'ssh gateway port' + alias: 't' + ] + action: (params, options, done) -> + child_process = require('child_process') + Promise = require 'bluebird' + resin = require('resin-sdk') + settings = require('resin-settings-client') + + if not options.port? + options.port = 22 + + console.info("Connecting with: #{params.uuid}") + + Promise.props + isOnline: resin.models.device.isOnline(params.uuid) + username: resin.auth.whoami() + uuid: resin.models.device.get(params.uuid).get('uuid') # get full uuid + containerId: resin.models.device.getApplicationInfo(params.uuid).get('containerId') + .then ({ isOnline, username, uuid, containerId }) -> + throw new Error('Device is not online') if not isOnline + throw new Error('Did not find running application container') if not containerId? + Promise.try -> + command = "ssh -t -o LogLevel=QUIET -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + -p #{options.port} #{username}@ssh.#{settings.get('proxyUrl')} enter #{uuid} #{containerId}" + + subShellCommand = getSubShellCommand(command) + spawn = child_process.spawn subShellCommand.program, subShellCommand.args, + stdio: 'inherit' diff --git a/lib/app.coffee b/lib/app.coffee index 09291fa2..d7a30d87 100644 --- a/lib/app.coffee +++ b/lib/app.coffee @@ -110,6 +110,9 @@ capitano.command(actions.logs) # ---------- Sync Module ---------- capitano.command(actions.sync) +# ---------- SSH Module ---------- +capitano.command(actions.ssh) + update.notify() plugins.register(/^resin-plugin-(.+)$/).then ->