net-ssh-simple 1.1.1 → 1.2.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/.gitignore +1 -0
- data/README.rdoc +16 -1
- data/Rakefile +8 -2
- data/lib/net/ssh/simple.rb +1 -1
- data/lib/net/ssh/simple/core.rb +72 -31
- data/lib/net/ssh/simple/version.rb +1 -1
- data/net-ssh-simple.gemspec +2 -2
- data/spec/net-ssh-simple.rb +211 -14
- metadata +65 -104
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -55,7 +55,22 @@ Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
|
|
55
55
|
s.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
|
56
56
|
s.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
|
57
57
|
s.close
|
58
|
-
|
58
|
+
|
59
|
+
=== Handling a Timeout
|
60
|
+
|
61
|
+
require 'net/ssh/simple'
|
62
|
+
|
63
|
+
# Hint: Set timeout=0 to disable, default is 60
|
64
|
+
begin
|
65
|
+
Net::SSH::Simple.sync({:timeout => 5}) do
|
66
|
+
ssh('example1.com', 'sleep 1') # I will (probably) succeed!
|
67
|
+
ssh('example2.com', 'sleep 60') # I will fail :(
|
68
|
+
end
|
69
|
+
rescue Net::SSH::Simple::Error => e
|
70
|
+
puts e.result.timed_out #=> true
|
71
|
+
end
|
72
|
+
|
73
|
+
|
59
74
|
== Documentation
|
60
75
|
|
61
76
|
See {Net::SSH::Simple}[http://rubydoc.info/gems/net-ssh-simple/Net/SSH/Simple] for more examples and full API.
|
data/Rakefile
CHANGED
@@ -8,10 +8,16 @@ task :default => :test
|
|
8
8
|
RSpec::Core::RakeTask.new("test:spec") do |t|
|
9
9
|
t.pattern = 'spec/*.rb'
|
10
10
|
t.rcov = false
|
11
|
-
|
12
|
-
t.rspec_opts = '-b -c -f documentation'
|
11
|
+
t.rspec_opts = '-b -c -f progress --tag ~benchmark'
|
13
12
|
end
|
14
13
|
|
14
|
+
RSpec::Core::RakeTask.new("test:benchmark") do |t|
|
15
|
+
t.pattern = 'spec/*.rb'
|
16
|
+
t.rcov = false
|
17
|
+
t.rspec_opts = '-b -c -f documentation --tag benchmark'
|
18
|
+
end
|
19
|
+
|
20
|
+
|
15
21
|
namespace :test do
|
16
22
|
task :coverage do
|
17
23
|
require 'cover_me'
|
data/lib/net/ssh/simple.rb
CHANGED
data/lib/net/ssh/simple/core.rb
CHANGED
@@ -66,8 +66,8 @@ module Net
|
|
66
66
|
# rescue Net::SSH::Simple::Error => e
|
67
67
|
# puts "Something bad happened!"
|
68
68
|
# puts e # Human readable error
|
69
|
-
# puts e.wrapped # Original Exception
|
70
|
-
# puts e.
|
69
|
+
# puts e.wrapped # Original Exception
|
70
|
+
# puts e.result # Net::SSH::Simple::Result (partial result)
|
71
71
|
# end
|
72
72
|
#
|
73
73
|
# @example
|
@@ -115,8 +115,8 @@ module Net
|
|
115
115
|
# rescue Net::SSH::Simple::Error => e
|
116
116
|
# puts "Something bad happened!"
|
117
117
|
# puts e # Human readable error
|
118
|
-
# puts e.wrapped # Original Exception
|
119
|
-
# puts e.
|
118
|
+
# puts e.wrapped # Original Exception
|
119
|
+
# puts e.result # Net::SSH::Simple::Result (partial result)
|
120
120
|
# ensure
|
121
121
|
# s.close # don't forget the clean up!
|
122
122
|
# end
|
@@ -128,6 +128,27 @@ module Net
|
|
128
128
|
# {:user => 'tom', :password => 'jerry', :port => 1234})
|
129
129
|
# end
|
130
130
|
#
|
131
|
+
# # Parameter inheritance
|
132
|
+
# Net::SSH::Simple.sync({:user => 'tom', :port => 1234}) do
|
133
|
+
# # Both commands will inherit :user and :port
|
134
|
+
# ssh('example1.com', 'echo "Hello World."', {:password => 'jerry'})
|
135
|
+
# scp_ul('example2.com', '/tmp/a', '/tmp/a', {:password => 's3cr3t'})
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# # Timeout handling
|
140
|
+
# #
|
141
|
+
# # Note: The timeout applies to each command independently.
|
142
|
+
# # Hint: Set timeout=0 to disable, default is 60
|
143
|
+
# begin
|
144
|
+
# Net::SSH::Simple.sync({:timeout => 5}) do
|
145
|
+
# ssh('example1.com', 'sleep 1') # I will (probably) succeed!
|
146
|
+
# ssh('example2.com', 'sleep 60') # I will fail :(
|
147
|
+
# end
|
148
|
+
# rescue Net::SSH::Simple::Error => e
|
149
|
+
# puts e.result.timed_out #=> true
|
150
|
+
# end
|
151
|
+
#
|
131
152
|
# @example
|
132
153
|
# # Using the SCP progress callback
|
133
154
|
# Net::SSH::Simple.sync do
|
@@ -229,9 +250,9 @@ module Net
|
|
229
250
|
# @param (see Net::SSH::Simple#ssh)
|
230
251
|
# @raise [Net::SSH::Simple::Error]
|
231
252
|
# @return [Net::SSH::Simple::Result] Result
|
232
|
-
def self.ssh(*args)
|
253
|
+
def self.ssh(*args, &block)
|
233
254
|
s = self.new
|
234
|
-
r = s.ssh(*args)
|
255
|
+
r = s.ssh(*args, &block)
|
235
256
|
s.close
|
236
257
|
r
|
237
258
|
end
|
@@ -297,6 +318,7 @@ module Net
|
|
297
318
|
# @return [Net::SSH::Simple::Result] Result
|
298
319
|
#
|
299
320
|
def scp_ul(host, src, dst, opts={}, &block)
|
321
|
+
opts = @opts.merge(opts)
|
300
322
|
scp(:upload, host, src, dst, opts, &block)
|
301
323
|
end
|
302
324
|
|
@@ -307,12 +329,13 @@ module Net
|
|
307
329
|
#
|
308
330
|
# @param [String] host Destination hostname or ip-address
|
309
331
|
# @param [String] cmd Shell command to execute
|
310
|
-
# @param
|
332
|
+
# @param opts (see Net::SSH::Simple#ssh)
|
311
333
|
# @param [Block] &block Progress callback (optional)
|
312
334
|
# @return [Net::SSH::Simple::Result] Result
|
313
335
|
# @see Net::SSH::Simple#scp_ul
|
314
336
|
#
|
315
337
|
def scp_dl(host, src, dst, opts={}, &block)
|
338
|
+
opts = @opts.merge(opts)
|
316
339
|
scp(:download, host, src, dst, opts, &block)
|
317
340
|
end
|
318
341
|
|
@@ -324,8 +347,8 @@ module Net
|
|
324
347
|
# @return [Net::SSH::Simple::Result] Result
|
325
348
|
# @param [String] host Destination hostname or ip-address
|
326
349
|
# @param [String] cmd Shell command to execute
|
327
|
-
# @param [Hash] opts Parameters for the underlying Net::SSH
|
328
350
|
# @param [Block] &block Use the event-API (see example above)
|
351
|
+
# @param [Hash] opts SSH options
|
329
352
|
# @option opts [Array] :auth_methods
|
330
353
|
# an array of authentication methods to try
|
331
354
|
#
|
@@ -399,7 +422,7 @@ module Net
|
|
399
422
|
# the port to use when connecting to the remote host
|
400
423
|
#
|
401
424
|
# @option opts [Hash] :properties
|
402
|
-
# a hash of key/value pairs to add to the new connection
|
425
|
+
# a hash of key/value pairs to add to the new connection's properties
|
403
426
|
# (see Net::SSH::Connection::Session#properties)
|
404
427
|
#
|
405
428
|
# @option opts [String] :proxy
|
@@ -414,8 +437,8 @@ module Net
|
|
414
437
|
# @option opts [Integer] :rekey_packet_limit
|
415
438
|
# the max number of packets to process before rekeying
|
416
439
|
#
|
417
|
-
# @option opts [Integer] :timeout
|
418
|
-
#
|
440
|
+
# @option opts [Integer] :timeout (60)
|
441
|
+
# connection timeout. this is enforced by Net::SSH::Simple.
|
419
442
|
#
|
420
443
|
# @option opts [String] :user
|
421
444
|
# the username to log in as
|
@@ -434,10 +457,11 @@ module Net
|
|
434
457
|
# @see http://net-ssh.github.com/ssh/v2/api/classes/Net/SSH/Config.html
|
435
458
|
# Net::SSH documentation for the 'opts'-hash
|
436
459
|
def ssh(host, cmd, opts={}, &block)
|
460
|
+
opts = @opts.merge(opts)
|
437
461
|
with_session(host, opts) do |session|
|
438
462
|
@result = Result.new(
|
439
|
-
{ :host
|
440
|
-
:stdout => ''
|
463
|
+
{ :op => :ssh, :host => host, :cmd => cmd, :start_at => Time.new,
|
464
|
+
:opts => opts, :stdout => '', :stderr => '', :success => nil
|
441
465
|
} )
|
442
466
|
|
443
467
|
channel = session.open_channel do |chan|
|
@@ -477,7 +501,8 @@ module Net
|
|
477
501
|
|
478
502
|
dsl_methods false
|
479
503
|
|
480
|
-
def initialize()
|
504
|
+
def initialize(opts={})
|
505
|
+
@opts = opts
|
481
506
|
@sessions = {}
|
482
507
|
@result = Result.new
|
483
508
|
end
|
@@ -486,23 +511,25 @@ module Net
|
|
486
511
|
# Spawn a Thread to perform a sequence of ssh/scp operations.
|
487
512
|
#
|
488
513
|
# @param [Block] block
|
514
|
+
# @param opts (see Net::SSH::Simple#ssh)
|
489
515
|
# @return [Thread] Thread executing the SSH-Block.
|
490
516
|
#
|
491
|
-
def self.async(&block)
|
517
|
+
def self.async(opts={}, &block)
|
492
518
|
Thread.new do
|
493
|
-
self.sync(&block)
|
519
|
+
self.sync(opts, &block)
|
494
520
|
end
|
495
521
|
end
|
496
522
|
|
497
523
|
#
|
498
524
|
# Perform a sequence of ssh/scp operations.
|
499
525
|
#
|
526
|
+
# @param opts (see Net::SSH::Simple#ssh)
|
500
527
|
# @return [Net::SSH::Simple::Result] Result
|
501
528
|
#
|
502
|
-
def self.sync(&block)
|
503
|
-
|
504
|
-
r = Blockenspiel.invoke(block,
|
505
|
-
|
529
|
+
def self.sync(opts={}, &block)
|
530
|
+
s = self.new(opts)
|
531
|
+
r = Blockenspiel.invoke(block, s)
|
532
|
+
s.close
|
506
533
|
r
|
507
534
|
end
|
508
535
|
|
@@ -519,23 +546,27 @@ module Net
|
|
519
546
|
end
|
520
547
|
|
521
548
|
private
|
522
|
-
def with_session(host, opts, &block)
|
549
|
+
def with_session(host, opts={:timeout => 60}, &block)
|
523
550
|
begin
|
524
|
-
|
525
|
-
|
526
|
-
|
551
|
+
Timeout.timeout(opts[:timeout]) do
|
552
|
+
session = @sessions[host.hash] = @sessions[host.hash] ||\
|
553
|
+
Net::SSH.start(*[host, opts[:user], opts])
|
554
|
+
block.call(session)
|
555
|
+
end
|
527
556
|
rescue => e
|
528
557
|
opts[:password].gsub!(/./,'*') if opts.include? :password
|
529
558
|
@result[:exception] = e
|
530
|
-
@result[:
|
531
|
-
|
559
|
+
@result[:success] = false
|
560
|
+
@result[:timed_out] = true
|
561
|
+
@result[:finish_at] = Time.new
|
562
|
+
raise Net::SSH::Simple::Error, [e, [host,opts,@result]]
|
532
563
|
end
|
533
564
|
end
|
534
565
|
|
535
566
|
def scp(mode, host, src, dst, opts={}, &block)
|
536
567
|
@result = Result.new(
|
537
|
-
{ :host
|
538
|
-
:src => src
|
568
|
+
{ :op => :scp, :host => host, :opts => opts, :cmd => :scp_dl,
|
569
|
+
:start_at => Time.new, :src => src, :dst => dst, :success => false
|
539
570
|
} )
|
540
571
|
with_session(host, opts) do |session|
|
541
572
|
lt = 0
|
@@ -556,15 +587,23 @@ module Net
|
|
556
587
|
# Error that occured during a Net::SSH::Simple operation.
|
557
588
|
#
|
558
589
|
class Error < RuntimeError
|
559
|
-
# Reference to the underlying
|
590
|
+
# Reference to the underlying Exception
|
560
591
|
attr_reader :wrapped
|
561
|
-
|
592
|
+
|
593
|
+
# Context for the operation that failed, as an Array: [host, opts, result].
|
594
|
+
#
|
595
|
+
# @deprecated
|
596
|
+
# This will be removed soon, use {#result} instead!
|
562
597
|
attr_reader :context
|
563
598
|
|
599
|
+
# {Net::SSH::Simple::Result} for the interrupted operation.
|
600
|
+
attr_reader :result
|
601
|
+
|
564
602
|
def initialize(msg, e=$!)
|
565
603
|
super(msg)
|
566
604
|
@wrapped = e
|
567
605
|
@context = msg[1]
|
606
|
+
@result = msg[1][2]
|
568
607
|
end
|
569
608
|
|
570
609
|
def to_s
|
@@ -576,9 +615,11 @@ module Net
|
|
576
615
|
# Result of a Net::SSH::Simple operation.
|
577
616
|
#
|
578
617
|
# @attr [String] host Hostname/IP address
|
618
|
+
# @attr [Symbol] op :ssh or :scp
|
579
619
|
# @attr [String] cmd Shell command (SSH only)
|
580
620
|
# @attr [Time] start_at Operation start timestamp
|
581
621
|
# @attr [Time] finish_at Operation finish timestamp
|
622
|
+
# @attr [Boolean] timed_out Set to true if the operation timed out
|
582
623
|
# @attr [String] stdout Output to stdout (SSH only)
|
583
624
|
# @attr [String] stderr Output to stderr (SSH only)
|
584
625
|
# @attr [boolean] success
|
@@ -586,7 +627,7 @@ module Net
|
|
586
627
|
# @attr [Integer] total Size of requested file (in bytes, SCP only)
|
587
628
|
# @attr [Integer] sent Number of bytes transferred (SCP only)
|
588
629
|
# @attr [String] exit_signal
|
589
|
-
# Only present if the remote command
|
630
|
+
# Only present if the remote command terminated due to a signal (SSH only)
|
590
631
|
#
|
591
632
|
class Result < Hashie::Mash; end
|
592
633
|
end
|
data/net-ssh-simple.gemspec
CHANGED
@@ -11,14 +11,14 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.description = %q{Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.}
|
12
12
|
s.summary = %q{SSH without the headache}
|
13
13
|
|
14
|
-
s.
|
14
|
+
s.required_ruby_version = '>= 1.9.2'
|
15
15
|
|
16
16
|
s.add_dependency "net-ssh", "~> 2.1.4"
|
17
17
|
s.add_dependency "net-scp", "~> 1.0.4"
|
18
18
|
s.add_dependency "blockenspiel", "~> 0.4.3"
|
19
19
|
s.add_dependency "hashie", "~> 1.1.0"
|
20
20
|
|
21
|
-
s.add_development_dependency "rake"
|
21
|
+
s.add_development_dependency "rake", "~> 0.9.2.2"
|
22
22
|
s.add_development_dependency "rspec"
|
23
23
|
s.add_development_dependency "cover_me"
|
24
24
|
|
data/spec/net-ssh-simple.rb
CHANGED
@@ -17,14 +17,19 @@ require 'securerandom'
|
|
17
17
|
# Port 22
|
18
18
|
#
|
19
19
|
# The test-suite will (over)write the following files on localhost:
|
20
|
-
# /tmp/ssh_test_in
|
21
|
-
# /tmp/ssh_test_out
|
20
|
+
# /tmp/ssh_test_in*
|
21
|
+
# /tmp/ssh_test_out*
|
22
22
|
#
|
23
23
|
|
24
|
+
CONCURRENCY = 16
|
25
|
+
|
26
|
+
BENCHMARK_ITER = 10
|
27
|
+
BENCHMARK_CONCURRENCY = 128
|
28
|
+
|
24
29
|
describe Net::SSH::Simple do
|
25
30
|
describe "singleton" do
|
26
31
|
before :each do
|
27
|
-
(0..
|
32
|
+
(0..CONCURRENCY).each do |i|
|
28
33
|
begin
|
29
34
|
File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
|
30
35
|
rescue; end
|
@@ -37,16 +42,32 @@ describe Net::SSH::Simple do
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
it "
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
it "enforces timeout" do
|
46
|
+
raised = false
|
47
|
+
begin
|
48
|
+
r = Net::SSH::Simple.ssh('localhost', 'sleep 60', {:timeout => 1})
|
49
|
+
rescue => e
|
50
|
+
raised = true
|
51
|
+
e.to_s.should match /^execution expired @ .*/
|
52
|
+
e.result.op == :ssh
|
53
|
+
e.result.timed_out.should == true
|
54
|
+
end
|
55
|
+
raised.should == true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "interprets timeout=0 as no timeout" do
|
59
|
+
Net::SSH::Simple.ssh('localhost', 'sleep 2', {:timeout => 0})
|
60
|
+
end
|
44
61
|
|
62
|
+
it "fails gently" do
|
63
|
+
raised = false
|
45
64
|
begin
|
46
65
|
Net::SSH::Simple.ssh('localhost', 'true', {:port => 0})
|
47
66
|
rescue => e
|
48
|
-
|
67
|
+
raised = true
|
68
|
+
e.to_s.should match /^Connection refused - connect\(2\).*/
|
49
69
|
end
|
70
|
+
raised.should == true
|
50
71
|
end
|
51
72
|
|
52
73
|
it "returns a result" do
|
@@ -95,7 +116,7 @@ describe Net::SSH::Simple do
|
|
95
116
|
before :each do
|
96
117
|
@s = Net::SSH::Simple.new
|
97
118
|
|
98
|
-
(0..
|
119
|
+
(0..CONCURRENCY).each do |i|
|
99
120
|
begin
|
100
121
|
File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
|
101
122
|
rescue; end
|
@@ -140,6 +161,7 @@ describe Net::SSH::Simple do
|
|
140
161
|
mockback.ping
|
141
162
|
end
|
142
163
|
r.success.should == true
|
164
|
+
r.op.should == :scp
|
143
165
|
Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
|
144
166
|
end
|
145
167
|
|
@@ -150,6 +172,7 @@ describe Net::SSH::Simple do
|
|
150
172
|
mockback.ping
|
151
173
|
end
|
152
174
|
r.success.should == true
|
175
|
+
r.op.should == :scp
|
153
176
|
Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
|
154
177
|
end
|
155
178
|
end
|
@@ -211,7 +234,7 @@ describe Net::SSH::Simple do
|
|
211
234
|
|
212
235
|
describe "asynchronous block syntax" do
|
213
236
|
before :each do
|
214
|
-
(0..
|
237
|
+
(0..CONCURRENCY).each do |i|
|
215
238
|
begin
|
216
239
|
File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
|
217
240
|
rescue; end
|
@@ -226,7 +249,7 @@ describe Net::SSH::Simple do
|
|
226
249
|
|
227
250
|
it "copes with a little concurrency" do
|
228
251
|
t = []
|
229
|
-
(0..
|
252
|
+
(0..CONCURRENCY).each do |i|
|
230
253
|
t[i] = Net::SSH::Simple.async do
|
231
254
|
mockback = mock(:progress_callback)
|
232
255
|
mockback.should_receive(:ping).at_least(:once)
|
@@ -245,13 +268,47 @@ describe Net::SSH::Simple do
|
|
245
268
|
end
|
246
269
|
end
|
247
270
|
|
248
|
-
(0..
|
271
|
+
(0..CONCURRENCY).each do |i|
|
249
272
|
r = t[i].value
|
250
273
|
r.stdout.should == "hello #{i}\n"
|
251
274
|
Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
|
252
275
|
end
|
253
276
|
end
|
254
277
|
|
278
|
+
it "doesn't break under high concurrency", :benchmark => true do
|
279
|
+
iter = 0
|
280
|
+
(0..BENCHMARK_ITER).each do
|
281
|
+
iter += 1
|
282
|
+
t = []
|
283
|
+
(0..BENCHMARK_CONCURRENCY).each do |i|
|
284
|
+
#t[i] = Net::SSH::Simple.async(:verbose=>Logger::DEBUG) do
|
285
|
+
t[i] = Net::SSH::Simple.async do
|
286
|
+
mockback = mock(:progress_callback)
|
287
|
+
mockback.should_receive(:ping).at_least(:once)
|
288
|
+
r = nil
|
289
|
+
if 0 == i % 2
|
290
|
+
r = scp_dl('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
|
291
|
+
mockback.ping
|
292
|
+
end
|
293
|
+
else
|
294
|
+
r = scp_ul('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
|
295
|
+
mockback.ping
|
296
|
+
end
|
297
|
+
end
|
298
|
+
r.success.should == true
|
299
|
+
ssh('localhost', "echo hello #{i}")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
(0..BENCHMARK_CONCURRENCY).each do |i|
|
304
|
+
r = t[i].value
|
305
|
+
r.stdout.should == "hello #{i}\n"
|
306
|
+
Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
|
307
|
+
end
|
308
|
+
puts "#{iter}/#{BENCHMARK_ITER}"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
255
312
|
it "handles signals" do
|
256
313
|
victim = Net::SSH::Simple.async do
|
257
314
|
begin
|
@@ -269,11 +326,151 @@ describe Net::SSH::Simple do
|
|
269
326
|
k.success.should == true
|
270
327
|
|
271
328
|
v = victim.value
|
272
|
-
v.to_s.should
|
329
|
+
v.to_s.should match /Killed by SIGTERM @ .*/
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe "parameter inheritance" do
|
334
|
+
it "works with instance syntax" do
|
335
|
+
s = Net::SSH::Simple.new({:timeout => 7})
|
336
|
+
r = s.ssh('localhost', 'date', {:rekey_packet_limit => 42})
|
337
|
+
r.op.should == :ssh
|
338
|
+
r.opts[:timeout].should == 7
|
339
|
+
r.opts[:rekey_packet_limit].should == 42
|
340
|
+
|
341
|
+
r = s.scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
342
|
+
{:rekey_packet_limit => 42})
|
343
|
+
r.op.should == :scp
|
344
|
+
r.opts[:timeout].should == 7
|
345
|
+
r.opts[:rekey_packet_limit].should == 42
|
346
|
+
|
347
|
+
r = s.scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
348
|
+
{:rekey_packet_limit => 42})
|
349
|
+
r.op.should == :scp
|
350
|
+
r.opts[:timeout].should == 7
|
351
|
+
r.opts[:rekey_packet_limit].should == 42
|
352
|
+
|
353
|
+
s.close
|
354
|
+
end
|
355
|
+
|
356
|
+
it "works with synchronous block syntax" do
|
357
|
+
r = Net::SSH::Simple.sync({:timeout => 7}) do
|
358
|
+
r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
|
359
|
+
r.opts[:timeout].should == 7
|
360
|
+
r.opts[:rekey_packet_limit].should == 42
|
361
|
+
|
362
|
+
r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
363
|
+
{:rekey_packet_limit => 42})
|
364
|
+
r.opts[:timeout].should == 7
|
365
|
+
r.opts[:rekey_packet_limit].should == 42
|
366
|
+
|
367
|
+
r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
368
|
+
{:rekey_packet_limit => 42})
|
369
|
+
r.opts[:timeout].should == 7
|
370
|
+
r.opts[:rekey_packet_limit].should == 42
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
it "works with asynchronous block syntax" do
|
375
|
+
t = Net::SSH::Simple.async({:timeout => 7}) do
|
376
|
+
r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
|
377
|
+
r.opts[:timeout].should == 7
|
378
|
+
r.opts[:rekey_packet_limit].should == 42
|
379
|
+
|
380
|
+
r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
381
|
+
{:rekey_packet_limit => 42})
|
382
|
+
r.opts[:timeout].should == 7
|
383
|
+
r.opts[:rekey_packet_limit].should == 42
|
384
|
+
|
385
|
+
r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
|
386
|
+
{:rekey_packet_limit => 42})
|
387
|
+
r.opts[:timeout].should == 7
|
388
|
+
r.opts[:rekey_packet_limit].should == 42
|
389
|
+
:happy
|
390
|
+
end
|
391
|
+
t.value.should == :happy
|
273
392
|
end
|
274
393
|
end
|
275
394
|
|
276
395
|
describe "event api" do
|
396
|
+
it "works with singleton syntax" do
|
397
|
+
mockie = mock(:callbacks)
|
398
|
+
mockie.should_receive(:start).once.ordered
|
399
|
+
mockie.should_receive(:finish).once.ordered
|
400
|
+
r = Net::SSH::Simple.ssh('localhost', '/bin/sh') do |e,c,d|
|
401
|
+
case e
|
402
|
+
when :start
|
403
|
+
mockie.start()
|
404
|
+
c.send_data("echo 'hello stdout'\n")
|
405
|
+
c.eof!
|
406
|
+
when :finish
|
407
|
+
mockie.finish()
|
408
|
+
end
|
409
|
+
end
|
410
|
+
r.stdout.should == "hello stdout\n"
|
411
|
+
r.stderr.should == ''
|
412
|
+
end
|
413
|
+
|
414
|
+
it "works with instance syntax" do
|
415
|
+
mockie = mock(:callbacks)
|
416
|
+
mockie.should_receive(:start).once.ordered
|
417
|
+
mockie.should_receive(:finish).once.ordered
|
418
|
+
s = Net::SSH::Simple.new
|
419
|
+
r = s.ssh('localhost', '/bin/sh') do |e,c,d|
|
420
|
+
case e
|
421
|
+
when :start
|
422
|
+
mockie.start()
|
423
|
+
c.send_data("echo 'hello stdout'\n")
|
424
|
+
c.eof!
|
425
|
+
when :finish
|
426
|
+
mockie.finish()
|
427
|
+
end
|
428
|
+
end
|
429
|
+
r.stdout.should == "hello stdout\n"
|
430
|
+
r.stderr.should == ''
|
431
|
+
end
|
432
|
+
|
433
|
+
it "works with synchronous block syntax" do
|
434
|
+
mockie = mock(:callbacks)
|
435
|
+
mockie.should_receive(:start).once.ordered
|
436
|
+
mockie.should_receive(:finish).once.ordered
|
437
|
+
r = Net::SSH::Simple.sync do
|
438
|
+
ssh('localhost', '/bin/sh') do |e,c,d|
|
439
|
+
case e
|
440
|
+
when :start
|
441
|
+
mockie.start()
|
442
|
+
c.send_data("echo 'hello stdout'\n")
|
443
|
+
c.eof!
|
444
|
+
when :finish
|
445
|
+
mockie.finish()
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
r.stdout.should == "hello stdout\n"
|
450
|
+
r.stderr.should == ''
|
451
|
+
end
|
452
|
+
|
453
|
+
it "works with asynchronous block syntax" do
|
454
|
+
t = Net::SSH::Simple.async do
|
455
|
+
mockie = mock(:callbacks)
|
456
|
+
mockie.should_receive(:start).once.ordered
|
457
|
+
mockie.should_receive(:finish).once.ordered
|
458
|
+
ssh('localhost', '/bin/sh') do |e,c,d|
|
459
|
+
case e
|
460
|
+
when :start
|
461
|
+
mockie.start()
|
462
|
+
c.send_data("echo 'hello stdout'\n")
|
463
|
+
c.eof!
|
464
|
+
when :finish
|
465
|
+
mockie.finish()
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
r = t.value
|
470
|
+
r.stdout.should == "hello stdout\n"
|
471
|
+
r.stderr.should == ''
|
472
|
+
end
|
473
|
+
|
277
474
|
it "handles long stdin->stdout pipe" do
|
278
475
|
mockie = mock(:callbacks)
|
279
476
|
mockie.should_receive(:start).once.ordered
|
@@ -414,7 +611,7 @@ describe Net::SSH::Simple do
|
|
414
611
|
k.success.should == true
|
415
612
|
|
416
613
|
v = victim.value
|
417
|
-
v.to_s.should
|
614
|
+
v.to_s.should match /Killed by SIGTERM @ .*/
|
418
615
|
end
|
419
616
|
|
420
617
|
it "handles signals (:no_raise)" do
|
metadata
CHANGED
@@ -1,131 +1,100 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh-simple
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
version: 1.1.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Moe
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-10-25 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: net-ssh
|
22
|
-
requirement: &
|
16
|
+
requirement: &7024800 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
18
|
+
requirements:
|
25
19
|
- - ~>
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 2
|
29
|
-
- 1
|
30
|
-
- 4
|
20
|
+
- !ruby/object:Gem::Version
|
31
21
|
version: 2.1.4
|
32
22
|
type: :runtime
|
33
23
|
prerelease: false
|
34
|
-
version_requirements: *
|
35
|
-
- !ruby/object:Gem::Dependency
|
24
|
+
version_requirements: *7024800
|
25
|
+
- !ruby/object:Gem::Dependency
|
36
26
|
name: net-scp
|
37
|
-
requirement: &
|
27
|
+
requirement: &7024140 !ruby/object:Gem::Requirement
|
38
28
|
none: false
|
39
|
-
requirements:
|
29
|
+
requirements:
|
40
30
|
- - ~>
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
segments:
|
43
|
-
- 1
|
44
|
-
- 0
|
45
|
-
- 4
|
31
|
+
- !ruby/object:Gem::Version
|
46
32
|
version: 1.0.4
|
47
33
|
type: :runtime
|
48
34
|
prerelease: false
|
49
|
-
version_requirements: *
|
50
|
-
- !ruby/object:Gem::Dependency
|
35
|
+
version_requirements: *7024140
|
36
|
+
- !ruby/object:Gem::Dependency
|
51
37
|
name: blockenspiel
|
52
|
-
requirement: &
|
38
|
+
requirement: &7023480 !ruby/object:Gem::Requirement
|
53
39
|
none: false
|
54
|
-
requirements:
|
40
|
+
requirements:
|
55
41
|
- - ~>
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
- 4
|
60
|
-
- 3
|
42
|
+
- !ruby/object:Gem::Version
|
61
43
|
version: 0.4.3
|
62
44
|
type: :runtime
|
63
45
|
prerelease: false
|
64
|
-
version_requirements: *
|
65
|
-
- !ruby/object:Gem::Dependency
|
46
|
+
version_requirements: *7023480
|
47
|
+
- !ruby/object:Gem::Dependency
|
66
48
|
name: hashie
|
67
|
-
requirement: &
|
49
|
+
requirement: &7022900 !ruby/object:Gem::Requirement
|
68
50
|
none: false
|
69
|
-
requirements:
|
51
|
+
requirements:
|
70
52
|
- - ~>
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
segments:
|
73
|
-
- 1
|
74
|
-
- 1
|
75
|
-
- 0
|
53
|
+
- !ruby/object:Gem::Version
|
76
54
|
version: 1.1.0
|
77
55
|
type: :runtime
|
78
56
|
prerelease: false
|
79
|
-
version_requirements: *
|
80
|
-
- !ruby/object:Gem::Dependency
|
57
|
+
version_requirements: *7022900
|
58
|
+
- !ruby/object:Gem::Dependency
|
81
59
|
name: rake
|
82
|
-
requirement: &
|
60
|
+
requirement: &7022240 !ruby/object:Gem::Requirement
|
83
61
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
88
|
-
- 0
|
89
|
-
version: "0"
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.9.2.2
|
90
66
|
type: :development
|
91
67
|
prerelease: false
|
92
|
-
version_requirements: *
|
93
|
-
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: *7022240
|
69
|
+
- !ruby/object:Gem::Dependency
|
94
70
|
name: rspec
|
95
|
-
requirement: &
|
71
|
+
requirement: &7021660 !ruby/object:Gem::Requirement
|
96
72
|
none: false
|
97
|
-
requirements:
|
98
|
-
- -
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
|
101
|
-
- 0
|
102
|
-
version: "0"
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
103
77
|
type: :development
|
104
78
|
prerelease: false
|
105
|
-
version_requirements: *
|
106
|
-
- !ruby/object:Gem::Dependency
|
79
|
+
version_requirements: *7021660
|
80
|
+
- !ruby/object:Gem::Dependency
|
107
81
|
name: cover_me
|
108
|
-
requirement: &
|
82
|
+
requirement: &7020960 !ruby/object:Gem::Requirement
|
109
83
|
none: false
|
110
|
-
requirements:
|
111
|
-
- -
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
|
114
|
-
- 0
|
115
|
-
version: "0"
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
116
88
|
type: :development
|
117
89
|
prerelease: false
|
118
|
-
version_requirements: *
|
90
|
+
version_requirements: *7020960
|
119
91
|
description: Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
|
120
|
-
email:
|
92
|
+
email:
|
121
93
|
- moe@busyloop.net
|
122
94
|
executables: []
|
123
|
-
|
124
95
|
extensions: []
|
125
|
-
|
126
96
|
extra_rdoc_files: []
|
127
|
-
|
128
|
-
files:
|
97
|
+
files:
|
129
98
|
- .gitignore
|
130
99
|
- Gemfile
|
131
100
|
- README.rdoc
|
@@ -135,39 +104,31 @@ files:
|
|
135
104
|
- lib/net/ssh/simple/version.rb
|
136
105
|
- net-ssh-simple.gemspec
|
137
106
|
- spec/net-ssh-simple.rb
|
138
|
-
has_rdoc: true
|
139
107
|
homepage: https://github.com/busyloop/net-ssh-simple
|
140
108
|
licenses: []
|
141
|
-
|
142
109
|
post_install_message:
|
143
110
|
rdoc_options: []
|
144
|
-
|
145
|
-
require_paths:
|
111
|
+
require_paths:
|
146
112
|
- lib
|
147
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
114
|
none: false
|
149
|
-
requirements:
|
150
|
-
- -
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
|
153
|
-
|
154
|
-
- 0
|
155
|
-
version: "0"
|
156
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 1.9.2
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
120
|
none: false
|
158
|
-
requirements:
|
159
|
-
- -
|
160
|
-
- !ruby/object:Gem::Version
|
161
|
-
|
162
|
-
segments:
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
segments:
|
163
126
|
- 0
|
164
|
-
|
127
|
+
hash: 2238180045890726956
|
165
128
|
requirements: []
|
166
|
-
|
167
|
-
|
168
|
-
rubygems_version: 1.3.7
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 1.8.10
|
169
131
|
signing_key:
|
170
132
|
specification_version: 3
|
171
133
|
summary: SSH without the headache
|
172
134
|
test_files: []
|
173
|
-
|