em-ssh 0.0.3 → 0.1.0
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 +0 -1
- data/bin/em-ssh-shell +1 -1
- data/lib/em-ssh/connection.rb +21 -12
- data/lib/em-ssh/shell.rb +54 -17
- data/lib/em-ssh/version.rb +1 -1
- data/lib/em-ssh.rb +3 -1
- metadata +12 -13
data/README.md
CHANGED
data/bin/em-ssh-shell
CHANGED
@@ -47,7 +47,7 @@ abort("command is required") if commands.empty?
|
|
47
47
|
|
48
48
|
|
49
49
|
EM.run do
|
50
|
-
EM::Ssh::Shell.new(host, options[:user], options[:password]) do |shell|
|
50
|
+
EM::Ssh::Shell.new(host, options[:user], options[:password], :net_ssh => options) do |shell|
|
51
51
|
commands.each do |command|
|
52
52
|
mys = shell.split
|
53
53
|
mys.on(:closed) { info("#{mys} has closed") }
|
data/lib/em-ssh/connection.rb
CHANGED
@@ -10,9 +10,8 @@ module EventMachine
|
|
10
10
|
# Allows other objects to register callbacks with events that occur on a Ssh instance
|
11
11
|
include Callbacks
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
# maximum number of seconds to wait for a connection
|
14
|
+
TIMEOUT = 20
|
16
15
|
# @return [String] The host to connect to, as given to the constructor.
|
17
16
|
attr_reader :host
|
18
17
|
|
@@ -113,7 +112,10 @@ module EventMachine
|
|
113
112
|
fire(:data, data)
|
114
113
|
end
|
115
114
|
|
116
|
-
|
115
|
+
def connection_completed
|
116
|
+
@contimeout.cancel
|
117
|
+
@nocon.cancel
|
118
|
+
end # connection_completed
|
117
119
|
|
118
120
|
def initialize(options = {})
|
119
121
|
debug("#{self.class}.new(#{options})")
|
@@ -122,14 +124,18 @@ module EventMachine
|
|
122
124
|
@password = options[:password]
|
123
125
|
@queue = []
|
124
126
|
@options = options
|
125
|
-
|
127
|
+
@timeout = options[:timeout] || TIMEOUT
|
128
|
+
|
126
129
|
begin
|
127
130
|
on(:connected, &options[:callback]) if options[:callback]
|
131
|
+
@nocon = on(:closed) { raise ConnectionFailed, @host }
|
132
|
+
@contimeout = EM::Timer.new(@timeout) { raise ConnectionTimeout, @host }
|
133
|
+
|
128
134
|
@error_callback = lambda { |code| raise SshError.new(code) }
|
129
135
|
|
130
136
|
@host_key_verifier = select_host_key_verifier(options[:paranoid])
|
131
137
|
@server_version = ServerVersion.new(self)
|
132
|
-
on(:version_negotiated) do
|
138
|
+
on(:version_negotiated) do
|
133
139
|
@data.consume!(@server_version.header.length)
|
134
140
|
@algorithms = Net::SSH::Transport::Algorithms.new(self, options)
|
135
141
|
|
@@ -142,8 +148,8 @@ module EventMachine
|
|
142
148
|
if auth.authenticate("ssh-connection", user, options[:password])
|
143
149
|
fire(:connected, Session.new(self, options))
|
144
150
|
else
|
151
|
+
fire(:error, Net::SSH::AuthenticationFailed.new(user))
|
145
152
|
close_connection
|
146
|
-
raise Net::SSH::AuthenticationFailed, user
|
147
153
|
end # auth.authenticate("ssh-connection", user, options[:password])
|
148
154
|
end.resume # Fiber
|
149
155
|
end # :algo_init
|
@@ -223,11 +229,10 @@ module EventMachine
|
|
223
229
|
# @return [Callback] the callback that was registered
|
224
230
|
def register_data_handler
|
225
231
|
on(:data) do |data|
|
226
|
-
|
227
|
-
while (packet = @socket.poll_next_packet)
|
232
|
+
while (packet = @socket.poll_next_packet)
|
228
233
|
case packet.type
|
229
234
|
when DISCONNECT
|
230
|
-
|
235
|
+
close_connection
|
231
236
|
when IGNORE
|
232
237
|
debug("IGNORE packet received: #{packet[:data].inspect}")
|
233
238
|
when UNIMPLEMENTED
|
@@ -236,8 +241,12 @@ module EventMachine
|
|
236
241
|
log.send((packet[:always_display] ? :fatal : :debug), packet[:message])
|
237
242
|
when KEXINIT
|
238
243
|
Fiber.new do
|
239
|
-
|
240
|
-
|
244
|
+
begin
|
245
|
+
algorithms.accept_kexinit(packet)
|
246
|
+
fire(:algo_init) if algorithms.initialized?
|
247
|
+
rescue Exception => e
|
248
|
+
fire(:error, e)
|
249
|
+
end # begin
|
241
250
|
end.resume
|
242
251
|
else
|
243
252
|
@queue.push(packet)
|
data/lib/em-ssh/shell.rb
CHANGED
@@ -32,8 +32,6 @@ module EventMachine
|
|
32
32
|
attr_reader :shell
|
33
33
|
# @return [Net::SSH::Connection]
|
34
34
|
attr_reader :connection
|
35
|
-
# @return [Boolean] Default (false) halt on timeout value - when true any timeouts will be halt the shell by raising an exception
|
36
|
-
attr_reader :halt_on_timeout
|
37
35
|
# @return [Hash] the options passed to initialize
|
38
36
|
attr_reader :options
|
39
37
|
# @return [Hash] the options to pass to connect automatically. They will be extracted from the opptions[:net_ssh] on initialization
|
@@ -62,11 +60,9 @@ module EventMachine
|
|
62
60
|
# @param [String, nil] pass by default publickey and password auth will be attempted
|
63
61
|
# @param [Hash] opts
|
64
62
|
# @option opts [Hash] :net_ssh options to pass to Net::SSH; see Net::SSH.start
|
65
|
-
# @option opts [Boolean] :halt_on_timeout (false)
|
66
63
|
# @option opts [Fixnum] :timeout (TIMEOUT) default timeout for all #wait_for and #send_wait calls
|
67
64
|
# @option opts [Boolean] :reconnect when disconnected reconnect
|
68
65
|
def initialize(address, user, pass, opts = {}, &blk)
|
69
|
-
@halt_on_timeout = opts[:halt_on_timeout] || false
|
70
66
|
@timeout = opts[:timeout].is_a?(Fixnum) ? opts[:timeout] : TIMEOUT
|
71
67
|
@host = address
|
72
68
|
@user = user
|
@@ -76,7 +72,7 @@ module EventMachine
|
|
76
72
|
@connection = opts[:connection]
|
77
73
|
@parent = opts[:parent]
|
78
74
|
@children = []
|
79
|
-
@reconnect
|
75
|
+
@reconnect = opts[:reconnect]
|
80
76
|
|
81
77
|
block_given? ? Fiber.new { open(&blk) }.resume : open
|
82
78
|
end
|
@@ -118,7 +114,7 @@ module EventMachine
|
|
118
114
|
# @param [String] send_str
|
119
115
|
# @return [String] all data in the buffer including the wait_str if it was found
|
120
116
|
def send_and_wait(send_str, wait_str = nil, opts = {})
|
121
|
-
reconnect? ? connect : raise(Disconnected)
|
117
|
+
reconnect? ? connect : raise(Disconnected) if !connected?
|
122
118
|
raise ClosedChannel if closed?
|
123
119
|
debug("send_and_wait(#{send_str.inspect}, #{wait_str.inspect}, #{opts})")
|
124
120
|
send_data(send_str)
|
@@ -129,31 +125,37 @@ module EventMachine
|
|
129
125
|
# @param [String, Regexp] strregex a string or regex to match the console output against.
|
130
126
|
# @param [Hash] opts
|
131
127
|
# @option opts [Fixnum] :timeout (Session::TIMEOUT) the maximum number of seconds to wait
|
132
|
-
# @option opts [Boolean] (false) :halt_on_timeout
|
133
128
|
# @return [String] the contents of the buffer
|
134
129
|
def wait_for(strregex, opts = { })
|
135
130
|
reconnect? ? connect : raise(Disconnected) unless connected?
|
136
131
|
raise ClosedChannel if closed?
|
137
132
|
debug("wait_for(#{strregex.inspect}, #{opts})")
|
138
|
-
opts = { :timeout => @timeout
|
133
|
+
opts = { :timeout => @timeout }.merge(opts)
|
139
134
|
buffer = ''
|
140
135
|
found = nil
|
141
136
|
f = Fiber.current
|
142
137
|
|
143
138
|
timer = nil
|
144
139
|
timeout = proc do
|
140
|
+
debug("timeout #{timer} fired")
|
141
|
+
shell.on_data {|c,d| }
|
142
|
+
begin
|
143
|
+
raise TimeoutError.new("#{host}: timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
|
144
|
+
rescue Exception => e
|
145
|
+
error(e)
|
146
|
+
debug(e.backtrace)
|
147
|
+
fire(:error, e)
|
148
|
+
end # begin
|
149
|
+
f.resume(nil)
|
145
150
|
shell.on_data {|c,d| }
|
146
|
-
# @todo fire an em errback
|
147
|
-
if opts[:halt_on_timeout]
|
148
|
-
raise TimeoutError("timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
|
149
|
-
else
|
150
|
-
warn("timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
|
151
|
-
end # opts[:halt_on_timeout]
|
152
151
|
end # timeout
|
153
152
|
|
154
153
|
shell.on_data do |ch,data|
|
155
154
|
buffer = "#{buffer}#{data}"
|
155
|
+
debug("data: #{buffer.dump}")
|
156
156
|
if strregex.is_a?(Regexp) ? buffer.match(strregex) : buffer.include?(strregex)
|
157
|
+
debug("data matched")
|
158
|
+
debug("canceling timer #{timer}")
|
157
159
|
timer.respond_to?(:cancel) && timer.cancel
|
158
160
|
shell.on_data {|c,d| }
|
159
161
|
f.resume(buffer)
|
@@ -161,6 +163,7 @@ module EventMachine
|
|
161
163
|
end # |ch,data|
|
162
164
|
|
163
165
|
timer = EM::Timer.new(opts[:timeout], &timeout)
|
166
|
+
debug("set timer: #{timer} for #{opts[:timeout]}")
|
164
167
|
return Fiber.yield
|
165
168
|
end # wait_for(strregex, opts = { })
|
166
169
|
|
@@ -169,8 +172,20 @@ module EventMachine
|
|
169
172
|
# @return [self]
|
170
173
|
def open(&blk)
|
171
174
|
debug("open(#{blk})")
|
172
|
-
f
|
173
|
-
|
175
|
+
f = Fiber.current
|
176
|
+
|
177
|
+
conerr = nil
|
178
|
+
unless connected?
|
179
|
+
conerr = on(:error) do |e|
|
180
|
+
error("#{e} (#{e.class})")
|
181
|
+
debug(e.backtrace)
|
182
|
+
conerr = e
|
183
|
+
f.resume(e)
|
184
|
+
end # |e|
|
185
|
+
connect
|
186
|
+
end # connected?
|
187
|
+
|
188
|
+
connection || raise(ConnectionError, "failed to create shell for #{host}: #{conerr} (#{conerr.class})")
|
174
189
|
|
175
190
|
connection.open_channel do |channel|
|
176
191
|
debug "**** channel open: #{channel}"
|
@@ -178,6 +193,7 @@ module EventMachine
|
|
178
193
|
debug "***** pty open: #{pty}; suc: #{suc}"
|
179
194
|
pty.send_channel_request("shell") do |shell,success|
|
180
195
|
raise ConnectionError, "Failed to create shell." unless success
|
196
|
+
conerr && conerr.cancel
|
181
197
|
debug "***** shell open: #{shell}"
|
182
198
|
@shell = shell
|
183
199
|
Fiber.new { yield(self) if block_given? }.resume
|
@@ -213,10 +229,11 @@ module EventMachine
|
|
213
229
|
def connect
|
214
230
|
return if connected?
|
215
231
|
f = Fiber.current
|
216
|
-
::EM::Ssh.start(host, user, connect_opts) do |connection|
|
232
|
+
con = ::EM::Ssh.start(host, user, connect_opts) do |connection|
|
217
233
|
@connection = connection
|
218
234
|
f.resume
|
219
235
|
end # |connection|
|
236
|
+
con.on(:error) { |e| fire(:error, e) }
|
220
237
|
return Fiber.yield
|
221
238
|
end # connect
|
222
239
|
|
@@ -231,6 +248,26 @@ module EventMachine
|
|
231
248
|
end
|
232
249
|
|
233
250
|
|
251
|
+
def debug(msg = nil, &blk)
|
252
|
+
super("#{host} #{msg}", &blk)
|
253
|
+
end
|
254
|
+
|
255
|
+
def info(msg = nil, &blk)
|
256
|
+
super("#{host} #{msg}", &blk)
|
257
|
+
end
|
258
|
+
|
259
|
+
def fatal(msg = nil, &blk)
|
260
|
+
super("#{host} #{msg}", &blk)
|
261
|
+
end
|
262
|
+
|
263
|
+
def warn(msg = nil, &blk)
|
264
|
+
super("#{host} #{msg}", &blk)
|
265
|
+
end
|
266
|
+
|
267
|
+
def error(msg = nil, &blk)
|
268
|
+
super("#{host} #{msg}", &blk)
|
269
|
+
end
|
270
|
+
|
234
271
|
end # class::Shell
|
235
272
|
end # class::Ssh
|
236
273
|
end # module::EventMachine
|
data/lib/em-ssh/version.rb
CHANGED
data/lib/em-ssh.rb
CHANGED
@@ -22,7 +22,9 @@ module EventMachine
|
|
22
22
|
class SshError < Net::SSH::Exception; include Error; end
|
23
23
|
class TimeoutError < Timeout::Error; include Error; end
|
24
24
|
class ClosedChannel < SshError; end
|
25
|
-
class
|
25
|
+
class Disconnected < SshError; end
|
26
|
+
class ConnectionFailed < SshError; end
|
27
|
+
class ConnectionTimeout < ConnectionFailed; end
|
26
28
|
|
27
29
|
|
28
30
|
class << self
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-10-30 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: eventmachine
|
17
|
-
requirement: &
|
16
|
+
requirement: &70168320140920 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: '0'
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *70168320140920
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: net-ssh
|
28
|
-
requirement: &
|
27
|
+
requirement: &70168320140460 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: '0'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *70168320140460
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: ruby-termios
|
39
|
-
requirement: &
|
38
|
+
requirement: &70168320140040 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: '0'
|
45
44
|
type: :development
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *70168320140040
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: highline
|
50
|
-
requirement: &
|
49
|
+
requirement: &70168320139620 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,7 +54,7 @@ dependencies:
|
|
55
54
|
version: '0'
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *70168320139620
|
59
58
|
description: ''
|
60
59
|
email:
|
61
60
|
- em-ssh@simulacre.org
|
@@ -78,7 +77,6 @@ files:
|
|
78
77
|
- bin/em-ssh
|
79
78
|
- bin/em-ssh-shell
|
80
79
|
- README.md
|
81
|
-
has_rdoc: true
|
82
80
|
homepage: http://github.com/simulacre/em-ssh
|
83
81
|
licenses:
|
84
82
|
- MIT
|
@@ -100,8 +98,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
98
|
version: 1.3.6
|
101
99
|
requirements: []
|
102
100
|
rubyforge_project:
|
103
|
-
rubygems_version: 1.
|
101
|
+
rubygems_version: 1.8.10
|
104
102
|
signing_key:
|
105
103
|
specification_version: 3
|
106
104
|
summary: An EventMachine compatible net-ssh
|
107
105
|
test_files: []
|
106
|
+
has_rdoc:
|