em-ssh 0.2.1 → 0.3.0.pre0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +44 -39
- data/bin/em-ssh +39 -31
- data/lib/em-ssh.rb +2 -2
- data/lib/em-ssh/connection.rb +27 -7
- data/lib/em-ssh/packet-stream.rb +7 -2
- data/lib/em-ssh/server-version.rb +3 -1
- data/lib/em-ssh/session.rb +4 -1
- data/lib/em-ssh/shell.rb +9 -5
- data/lib/em-ssh/version.rb +1 -1
- metadata +32 -12
data/README.md
CHANGED
@@ -7,45 +7,50 @@ Em-ssh is not associated with the Jamis Buck's [net-ssh](http://net-ssh.github.c
|
|
7
7
|
|
8
8
|
##Synopsis
|
9
9
|
EM.run do
|
10
|
-
EM::Ssh.start(host, user, :password => password) do |
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
10
|
+
EM::Ssh.start(host, user, :password => password) do |connection|
|
11
|
+
connection.errback do |err|
|
12
|
+
$stderr.puts "#{err} (#{err.class})"
|
13
|
+
end
|
14
|
+
connection.callback do |ssh|
|
15
|
+
# capture all stderr and stdout output from a remote process
|
16
|
+
ssh.exec!('uname -a').tap {|r| puts "\nuname: #{r}"}
|
17
|
+
|
18
|
+
# capture only stdout matching a particular pattern
|
19
|
+
stdout = ""
|
20
|
+
ssh.exec!("ls -l /home") do |channel, stream, data|
|
21
|
+
stdout << data if stream == :stdout
|
22
|
+
end
|
23
|
+
puts "\n#{stdout}"
|
24
|
+
|
25
|
+
# run multiple processes in parallel to completion
|
26
|
+
ssh.exec('ping -c 1 www.google.com')
|
27
|
+
ssh.exec('ping -c 1 www.yahoo.com')
|
28
|
+
ssh.exec('ping -c 1 www.rakuten.co.jp')
|
29
|
+
|
30
|
+
#open a new channel and configure a minimal set of callbacks, then wait for the channel to finishes (closees).
|
31
|
+
channel = ssh.open_channel do |ch|
|
32
|
+
ch.exec "/usr/local/bin/ruby /path/to/file.rb" do |ch, success|
|
33
|
+
raise "could not execute command" unless success
|
34
|
+
|
35
|
+
# "on_data" is called when the process writes something to stdout
|
36
|
+
ch.on_data do |c, data|
|
37
|
+
$stdout.print data
|
38
|
+
end
|
39
|
+
|
40
|
+
# "on_extended_data" is called when the process writes something to stderr
|
41
|
+
ch.on_extended_data do |c, type, data|
|
42
|
+
$stderr.print data
|
43
|
+
end
|
44
|
+
|
45
|
+
ch.on_close { puts "done!" }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
channel.wait
|
50
|
+
|
51
|
+
ssh.close
|
52
|
+
EM.stop
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
data/bin/em-ssh
CHANGED
@@ -66,37 +66,45 @@ end
|
|
66
66
|
|
67
67
|
|
68
68
|
EM.run do
|
69
|
-
EM::Ssh.start(host, options[:user], options) do |
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
shell
|
82
|
-
|
83
|
-
shell
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
69
|
+
EM::Ssh.start(host, options[:user], options) do |ssh|
|
70
|
+
ssh.errback do |err|
|
71
|
+
puts "#{err} (#{err.class})"
|
72
|
+
EM.stop
|
73
|
+
end
|
74
|
+
|
75
|
+
ssh.callback do |connection|
|
76
|
+
debug "**** connected: #{connection}"
|
77
|
+
connection.open_channel do |channel|
|
78
|
+
debug "**** channel: #{channel}"
|
79
|
+
channel.request_pty(options[:pty] || {}) do |pty,suc|
|
80
|
+
debug "***** pty: #{pty}; suc: #{suc}"
|
81
|
+
pty.send_channel_request("shell") do |shell,success|
|
82
|
+
raise ConnectionError, "Failed to create shell." unless success
|
83
|
+
debug "***** shell: #{shell}"
|
84
|
+
connected = true
|
85
|
+
|
86
|
+
shell.on_data { |c,d| $stdout.print d }
|
87
|
+
shell.on_extended_data { |c,data| $STDERR.print data }
|
88
|
+
shell.on_eof do
|
89
|
+
shell.close
|
90
|
+
EM.stop
|
91
|
+
end #
|
92
|
+
|
93
|
+
trap("SIGINT") { shell.send_data("\C-c") }
|
94
|
+
trap("SIGEXIT") do
|
95
|
+
shell.close
|
96
|
+
trap("SIGINT", "SIG_DFL")
|
97
|
+
end #
|
98
|
+
|
99
|
+
conn = EM.watch($stdin, CInput)
|
100
|
+
conn.shell = shell
|
101
|
+
conn.notify_readable = true
|
102
|
+
|
103
|
+
end # |shell,success|
|
104
|
+
end # |pty,suc|
|
105
|
+
end # |channel|
|
106
|
+
end
|
107
|
+
|
100
108
|
end # |connection|
|
101
109
|
end # EM.start
|
102
110
|
|
data/lib/em-ssh.rb
CHANGED
@@ -50,8 +50,8 @@ module EventMachine
|
|
50
50
|
# channel.request_pty(options[:pty] || {}) do |pty,suc|
|
51
51
|
def connect(host, user, opts = {}, &blk)
|
52
52
|
logger.debug("#{self}.connect(#{host}, #{user}, #{opts})")
|
53
|
-
options = { :host => host, :user => user, :port => DEFAULT_PORT
|
54
|
-
EM.connect(options[:host], options[:port], Connection, options)
|
53
|
+
options = { :host => host, :user => user, :port => DEFAULT_PORT }.merge(opts)
|
54
|
+
EM.connect(options[:host], options[:port], Connection, options, &blk)
|
55
55
|
end
|
56
56
|
alias :start :connect
|
57
57
|
end # << self
|
data/lib/em-ssh/connection.rb
CHANGED
@@ -5,6 +5,7 @@ module EventMachine
|
|
5
5
|
# itself into Net::SSH so that the EventMachine reactor loop can take the place of the Net::SSH event loop.
|
6
6
|
# Most of the methods here are only for compatibility with Net::SSH
|
7
7
|
class Connection < EventMachine::Connection
|
8
|
+
include EM::Deferrable
|
8
9
|
include Log
|
9
10
|
|
10
11
|
# Allows other objects to register callbacks with events that occur on a Ssh instance
|
@@ -127,11 +128,26 @@ module EventMachine
|
|
127
128
|
@timeout = options[:timeout] || TIMEOUT
|
128
129
|
|
129
130
|
begin
|
130
|
-
on(:connected
|
131
|
-
|
132
|
-
|
131
|
+
on(:connected) do |session|
|
132
|
+
succeed(session, @host)
|
133
|
+
end
|
134
|
+
on(:error) do |e|
|
135
|
+
fail(e)
|
136
|
+
close_connection
|
137
|
+
end
|
138
|
+
@nocon = on(:closed) do
|
139
|
+
fail(SshError.new(@host))
|
140
|
+
close_connection
|
141
|
+
end
|
142
|
+
@contimeout = EM::Timer.new(@timeout) do
|
143
|
+
fail(ConnectionTimeout.new(@host))
|
144
|
+
close_connection
|
145
|
+
end
|
133
146
|
|
134
|
-
@error_callback = lambda
|
147
|
+
@error_callback = lambda do |code|
|
148
|
+
fail(SshError.new(code))
|
149
|
+
close_connection
|
150
|
+
end
|
135
151
|
|
136
152
|
@host_key_verifier = select_host_key_verifier(options[:paranoid])
|
137
153
|
@server_version = ServerVersion.new(self)
|
@@ -149,7 +165,6 @@ module EventMachine
|
|
149
165
|
fire(:connected, Session.new(self, options))
|
150
166
|
else
|
151
167
|
fire(:error, Net::SSH::AuthenticationFailed.new(user))
|
152
|
-
close_connection
|
153
168
|
end # auth.authenticate("ssh-connection", user, options[:password])
|
154
169
|
end.resume # Fiber
|
155
170
|
end # :algo_init
|
@@ -157,7 +172,7 @@ module EventMachine
|
|
157
172
|
|
158
173
|
rescue Exception => e
|
159
174
|
log.fatal("caught an error during initialization: #{e}\n #{e.backtrace.join("\n ")}")
|
160
|
-
|
175
|
+
fail(e)
|
161
176
|
end # begin
|
162
177
|
self
|
163
178
|
end # initialize(options = {})
|
@@ -273,7 +288,12 @@ module EventMachine
|
|
273
288
|
when :very then
|
274
289
|
Net::SSH::Verifiers::Strict.new
|
275
290
|
else
|
276
|
-
paranoid.respond_to?(:verify)
|
291
|
+
if paranoid.respond_to?(:verify)
|
292
|
+
paranoid
|
293
|
+
else
|
294
|
+
fail(@host, ArgumentError.new("argument to :paranoid is not valid: #{paranoid.inspect}"))
|
295
|
+
close_connection
|
296
|
+
end # paranoid.respond_to?(:verify)
|
277
297
|
end # paranoid
|
278
298
|
end # select_host_key_verifier(paranoid)
|
279
299
|
end # class::Connection < EventMachine::Connection
|
data/lib/em-ssh/packet-stream.rb
CHANGED
@@ -61,7 +61,9 @@ module EventMachine
|
|
61
61
|
@packet_length = @packet.read_long
|
62
62
|
end
|
63
63
|
need = @packet_length + 4 - server.block_size
|
64
|
-
|
64
|
+
if need % server.block_size != 0
|
65
|
+
@connection.fire(:error, SshError.new("padding error, need #{need} block #{server.block_size}"))
|
66
|
+
end
|
65
67
|
|
66
68
|
return nil if available < need + server.hmac.mac_length
|
67
69
|
|
@@ -82,7 +84,10 @@ module EventMachine
|
|
82
84
|
padding = @packet.read(padding_length) if padding_length > 0
|
83
85
|
|
84
86
|
my_computed_hmac = server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
|
85
|
-
|
87
|
+
if real_hmac != my_computed_hmac
|
88
|
+
@connection.fire(:error, Net::SSH::Exception.new("corrupted mac detected"))
|
89
|
+
return
|
90
|
+
end
|
86
91
|
|
87
92
|
# try to decompress the payload, in case compression is active
|
88
93
|
payload = server.decompress(payload)
|
@@ -23,7 +23,9 @@ module EventMachine
|
|
23
23
|
if @version[-1] == "\n"
|
24
24
|
@version.chomp!
|
25
25
|
log.debug("server version: #{@version}")
|
26
|
-
|
26
|
+
unless @version.match(/^SSH-(1\.99|2\.0)-/)
|
27
|
+
return connection.fire(:error, SshError.new("incompatible SSH version `#{@version}'"))
|
28
|
+
end
|
27
29
|
log.debug("local version: #{Net::SSH::Transport::ServerVersion::PROTO_VERSION}")
|
28
30
|
connection.send_data("#{Net::SSH::Transport::ServerVersion::PROTO_VERSION}\r\n")
|
29
31
|
cb.cancel
|
data/lib/em-ssh/session.rb
CHANGED
@@ -34,7 +34,10 @@ module EventMachine
|
|
34
34
|
|
35
35
|
def register_callbacks
|
36
36
|
transport.on(:packet) do |packet|
|
37
|
-
|
37
|
+
unless MAP.key?(packet.type)
|
38
|
+
transport.fire(:error, SshError.new("unexpected response #{packet.type} (#{packet.inspect})"))
|
39
|
+
return
|
40
|
+
end
|
38
41
|
send(MAP[packet.type], packet)
|
39
42
|
end # |packet|
|
40
43
|
|
data/lib/em-ssh/shell.rb
CHANGED
@@ -236,11 +236,15 @@ module EventMachine
|
|
236
236
|
return if connected?
|
237
237
|
trace = caller
|
238
238
|
f = Fiber.current
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
::EM::Ssh.start(host, user, connect_opts) do |connection|
|
240
|
+
connection.callback do |ssh|
|
241
|
+
f.resume(@connection = ssh)
|
242
|
+
end # ssh
|
243
|
+
connection.errback do |e|
|
244
|
+
e.set_backtrace(trace + Array(e.backtrace))
|
245
|
+
fire(:error, e)
|
246
|
+
f.resume(e)
|
247
|
+
end # err
|
244
248
|
end
|
245
249
|
return Fiber.yield
|
246
250
|
end
|
data/lib/em-ssh/version.rb
CHANGED
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0.pre0
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Caleb Crane
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: net-ssh
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: ruby-termios
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: highline
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,7 +69,12 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
description: ''
|
59
79
|
email:
|
60
80
|
- em-ssh@simulacre.org
|
@@ -98,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
118
|
version: 1.3.6
|
99
119
|
requirements: []
|
100
120
|
rubyforge_project:
|
101
|
-
rubygems_version: 1.8.
|
121
|
+
rubygems_version: 1.8.21
|
102
122
|
signing_key:
|
103
123
|
specification_version: 3
|
104
124
|
summary: An EventMachine compatible net-ssh
|