Net::SSH 2.0 (and friends)

Posted by Jamis on May 02, 2008 @ 09:39 AM

At last! Net::SSH 2.0 is available! Also available are Net::SFTP 2.0, Net::SCP 1.0, Net::SSH::Gateway 1.0, and Net::SSH::Multi 1.0.

1
2
3
4
5
$ gem install net-ssh \
  net-sftp \
  net-scp \
  net-ssh-gateway \
  net-ssh-multi

All of these Ruby libraries are for communicating with remote servers via the SSH protocol in different ways.

Net::SSH and Net::SFTP are both significant upgrades from their previous incarnations; if you have used either library in the past, you’ll want to read the documentation (Net::SSH, Net::SFTP). The Net::SSH API is still fairly similar to the way it was before, but the Net::SFTP API is entirely different.

All have pretty complete RDoc documentation, so you should be able to employ “ri” to good effect to find your way around the libraries. (Try “ri Net::SSH”, for example, to get started.)

Per-library synopses follow.

Net::SSH 2.0

This is a significant upgrade from Net::SSH 1.x. Changes from 1.x include (but are not limited to):

  • Net::SSH 2.0 no longer requires the Needle dependency-injection library. This has made the library faster, lighter, and easier to understand.
  • The “sync” and “sync-shell” services have been removed and will not return. (If you need the functionality of those services, I strongly encourage you to port them to Net::SSH 2 and release them as separate extensions.)
  • Options in ~/.ssh/config files are (partially) supported, and are loaded by default now.
  • The Net::SSH::start method now requires both a host and a username as the first two parameters, rather than inferring the username.
  • There is now a Session#exec method that makes it easier than ever to just execute and interact with a command.
  • Channel now sports an #on_process method that you can send a block to, which will be executed on every pass of the event loop.
  • Channel#on_request now accepts a string to indicate which request you want to respond to.
  • Channel open failures may be captured via Channel#on_open_failure.
  • Lots, lots, LOTS, more—refer to the rdocs for all the gory details.
1
2
3
4
5
6
require 'net/ssh'

Net::SSH.start('localhost', 'jamis') do |ssh|
  ssh.exec('hostname') # prints the results to $stdout
  ssh.loop
end

Net::SFTP 2.0

This is a complete rewrite of the original Net::SFTP 1.x code, and shares very, very little in common with it. The new version has a much cleaner implementation and API, and provides some really handy methods for transferring files and directories.

1
2
3
4
5
6
7
8
9
10
require 'net/sftp'

Net::SFTP.start('localhost', 'jamis') do |sftp|
  sftp.upload! "/local/file", "/remote/file"
  sftp.download! "/remote/file", "/local/file"

  sftp.file.open("/remote/file", "w") do |file|
    file.puts "here is some data"
  end
end

Net::SCP 1.0

This provides a way to transfer files and directories via the SCP protocol, over Net::SSH.

1
2
3
4
5
6
require 'net/scp'

Net::SCP.start('localhost', 'jamis') do |scp|
  scp.upload! "/local/file", "/remote/file"
  scp.download! "/remote/file", "/local/file"
end

Net::SSH::Gateway 1.0

This library makes it easy to tunnel connections though firewalls. You simply connect to the gateway machine, and then specify which ports you want forwarded.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'net/ssh/gateway'

gateway = Net::SSH::Gateway.new('host', 'user')

gateway.ssh("host.private", "user") do |ssh|
  puts ssh.exec!("hostname")
end

gateway.open("host.private", 80) do |port|
  require 'net/http'
  Net::HTTP.get_print("127.0.0.1", "/path", port)
end

gateway.shutdown!

Net::SSH::Multi 1.0

This library makes it simple to open multiple Net::SSH connections and tie them all together, running commands in parallel (much like Capistrano does).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require 'net/ssh/multi'

Net::SSH::Multi.start do |session|
  # access servers via a gateway
  session.via 'gateway', 'gateway-user'

  # define the servers we want to use
  session.use 'user1@host1'
  session.use 'user2@host2'

  # define servers in groups for more granular access
  session.group :app do
    session.use 'user@app1'
    session.use 'user@app2'
  end

  # execute commands on all servers
  session.exec "uptime"

  # execute commands on a subset of servers
  session.with(:app).exec "hostname"

  # run the aggregated event loop
  session.loop
end

Enjoy!

Posted in Announcements

Comments

Have something to add? Click here to leave a comment.

02 May 2008

1. James said...

All this looks great! Your work on these libraries really helps Ruby be a successful language.

I have one suggestion, though: session.via(gateway info here) seems like it’s a perfect match for the decorator or wrapper pattern. That is, the following code makes more sense to me:

Net::SSH::Multi.start do |outer_session|
  # access servers via a gateway
  outer_session.via 'gateway', 'gateway-user' do |session|
    ... above code here ...
  end
end

That is, session.via should return a new session object rather than being mutable. This would allow chained gateways, though I’m not really sure anybody needs that. The real advantage is the decrease on the conceptual weight of Session – it need only return a WrappedSession or a GatewaySessionWrapper or something instead of needing to keep track of the gateway information itself.

Bravo on the release!

2. Jamis said...

@James, thanks for the suggestion, I’ll take it under consideration. What session#via really does, though, is set the default gateway instance to use. You can specify per-session gateways with session.use(‘host’, ‘name’, :via => Net::SSH::Gateway.new(...)).

3. mark said...

Congrats Jamis!! This is awesome!

05 May 2008

4. Charles L said...

Yeah this is great. Have been using v1 of Net::SSH & Net::SFTP quite a bit.

The cleaned up SFTP api is a nice touch – mimicing the Dir and File methods similar to how “zip/zipfilesystem” works makes it easy to write code that is agnostic of the method it uses to access files (local fs, zip, remote sftp, etc). Kind of a de-facto ruby vfs.

5. tobi said...

I like how SSH:Multi + Rake gives you a very low-magic version of capistrano.

06 May 2008

6. Alex said...

I try to update my gem and not find the 2.0 version :

  1. gem search net-ssh -r
  • REMOTE GEMS *

net-ssh (1.1.2, 1.1.1, 1.1.0, 1.0.10, 1.0.9, 1.0.8, 1.0.7, 1.0.6, 1.0.5, 1.0.4, 1.0.3, 1.0.2, 1.0.1, 1.0.0, 0.9.0, 0.6.0, 0.5.0, 0.1.0, 0.0.5, 0.0.4, 0.0.3, 0.0.2, 0.0.1) Net::SSH is a pure-Ruby implementation of the SSH2 client protocol.

Where is the 2.0 ??

7. Alex said...

Solved with, gem update—system

Great work, thanks.

07 May 2008

8. rafa said...

net/ssh requires jruby-openssl when when running on JRuby, is there some way for it to be added as dependency on the net/ssh gem?

Also, running on JRuby+Windows I had to add ‘net/ssh/pageant.rb’ to $LOADED_FEATURES before requiring net/ssh, jruby does not have a ‘dl/import’

http://www.nabble.com/dl-import-on-JRuby-td16465077.html

: (leave url/email »)
: