em-ssh 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|