net-ssh-simple 1.5.0 → 1.5.1

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.
@@ -1,7 +1,7 @@
1
1
  module Net
2
2
  module SSH
3
3
  class Simple
4
- VERSION = "1.5.0"
4
+ VERSION = "1.5.1"
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-simple
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-25 00:00:00.000000000Z
12
+ date: 2011-12-08 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-ssh
16
- requirement: &19079780 !ruby/object:Gem::Requirement
16
+ requirement: &20268640 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.1.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *19079780
24
+ version_requirements: *20268640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: net-scp
27
- requirement: &19079300 !ruby/object:Gem::Requirement
27
+ requirement: &20909120 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *19079300
35
+ version_requirements: *20909120
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: blockenspiel
38
- requirement: &19078800 !ruby/object:Gem::Requirement
38
+ requirement: &21271860 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.4.3
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *19078800
46
+ version_requirements: *21271860
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hashie
49
- requirement: &19078340 !ruby/object:Gem::Requirement
49
+ requirement: &21280120 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.1.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *19078340
57
+ version_requirements: *21280120
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &19077840 !ruby/object:Gem::Requirement
60
+ requirement: &22924860 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 0.9.2.2
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *19077840
68
+ version_requirements: *22924860
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &19077460 !ruby/object:Gem::Requirement
71
+ requirement: &23604040 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *19077460
79
+ version_requirements: *23604040
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: cover_me
82
- requirement: &19076980 !ruby/object:Gem::Requirement
82
+ requirement: &23831720 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *19076980
90
+ version_requirements: *23831720
91
91
  description: Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
92
92
  email:
93
93
  - moe@busyloop.net
@@ -100,7 +100,6 @@ files:
100
100
  - README.rdoc
101
101
  - Rakefile
102
102
  - lib/net/ssh/simple.rb
103
- - lib/net/ssh/simple/core.rb
104
103
  - lib/net/ssh/simple/version.rb
105
104
  - net-ssh-simple.gemspec
106
105
  - spec/net-ssh-simple.rb
@@ -124,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
123
  version: '0'
125
124
  segments:
126
125
  - 0
127
- hash: 2921598519931635186
126
+ hash: 173875200728558481
128
127
  requirements: []
129
128
  rubyforge_project:
130
129
  rubygems_version: 1.8.10
@@ -1,701 +0,0 @@
1
- #
2
- # Copyright (C) 2011 by moe@busyloop.net
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the "Software"), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in
12
- # all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- # THE SOFTWARE.
21
- #
22
- module Net
23
- module SSH
24
- # Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
25
- #
26
- # @example
27
- # # Block Syntax (synchronous)
28
- # Net::SSH::Simple.sync do
29
- # r = ssh 'example1.com', 'echo "Hello World."'
30
- # puts r.stdout #=> "Hello World."
31
- # puts r.exit_code #=> 0
32
- #
33
- # scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
34
- # scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
35
- # end
36
- #
37
- # @example
38
- # # Block Syntax (asynchronous)
39
- # t1 = Net::SSH::Simple.async do
40
- # scp_ul 'example1.com', '/tmp/local_foo', '/tmp/remote_bar'
41
- # ssh 'example3.com', 'echo "Hello World A."'
42
- # end
43
- # t2 = Net::SSH::Simple.async do
44
- # scp_dl 'example6.com', '/tmp/remote_foo', '/tmp/local_bar'
45
- # ssh 'example7.com', 'echo "Hello World B."'
46
- # end
47
- # r1 = t1.value # wait for t1 to finish and grab return value
48
- # r2 = t2.value # wait for t2 to finish and grab return value
49
- #
50
- # puts r1.stdout #=> "Hello World A."
51
- # puts r2.stdout #=> "Hello World B."
52
- #
53
- # @example
54
- # # Using an instance
55
- # s = Net::SSH::Simple.new
56
- # s.ssh 'example1.com', 'echo "Hello World."'
57
- # s.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
58
- # s.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
59
- # s.close
60
- #
61
- # @example
62
- # # Using no instance
63
- # # Note: This will create a new connection for each operation!
64
- # # Use instance- or block-syntax for better performance.
65
- # Net::SSH::Simple.ssh 'example1.com', 'echo "Hello World."'
66
- # Net::SSH::Simple.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
67
- # Net::SSH::Simple.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
68
- #
69
- # @example
70
- # # Error Handling with Block Syntax (synchronous)
71
- # begin
72
- # Net::SSH::Simple.sync do
73
- # r = ssh 'example1.com', 'echo "Hello World."'
74
- # if r.success and r.stdout == 'Hello World.'
75
- # puts "Success! I Helloed World."
76
- # end
77
- #
78
- # r = scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
79
- # if r.success and r.sent == r.total
80
- # puts "Success! Uploaded #{r.sent} of #{r.total} bytes."
81
- # end
82
- #
83
- # r = scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
84
- # if r.success and r.sent == r.total
85
- # puts "Success! Downloaded #{r.sent} of #{r.total} bytes."
86
- # end
87
- # end
88
- # rescue Net::SSH::Simple::Error => e
89
- # puts "Something bad happened!"
90
- # puts e # Human readable error
91
- # puts e.wrapped # Original Exception
92
- # puts e.result # Net::SSH::Simple::Result
93
- # end
94
- #
95
- # @example
96
- # # Error Handling with Block Syntax (asynchronous)
97
- # #
98
- # # Exceptions are raised inside your thread.
99
- # # You are free to handle them or pass them outwards.
100
- #
101
- # a = Net::SSH::Simple.async do
102
- # begin
103
- # ssh 'example1.com', 'echo "Hello World."'
104
- # scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
105
- # scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
106
- # rescue Net::SSH::Simple::Error => e
107
- # # return our exception to the parent thread
108
- # e
109
- # end
110
- # end
111
- # r = a.value # Wait for thread to finish and capture result
112
- #
113
- # unless r.is_a? Net::SSH::Simple::Result
114
- # puts "Something bad happened!"
115
- # puts r
116
- # end
117
- #
118
- # @example
119
- # # Error Handling with an instance
120
- # s = Net::SSH::Simple.new
121
- # begin
122
- # r = s.ssh 'example1.com', 'echo "Hello World."'
123
- # if r.success and r.stdout == 'Hello World.'
124
- # puts "Success! I Helloed World."
125
- # end
126
- #
127
- # r = s.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
128
- # if r.success and r.sent == r.total
129
- # puts "Success! Uploaded #{r.sent} of #{r.total} bytes."
130
- # end
131
- #
132
- # r = s.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
133
- # if r.success and r.sent == r.total
134
- # puts "Success! Downloaded #{r.sent} of #{r.total} bytes."
135
- # end
136
- # rescue Net::SSH::Simple::Error => e
137
- # puts "Something bad happened!"
138
- # puts e # Human readable error
139
- # puts e.wrapped # Original Exception
140
- # puts e.result # Net::SSH::Simple::Result (partial result)
141
- # ensure
142
- # s.close # don't forget the clean up!
143
- # end
144
- #
145
- # @example
146
- # # Parameters
147
- # Net::SSH::Simple.sync do
148
- # ssh('example1.com', 'echo "Hello World."',
149
- # {:user => 'tom', :password => 'jerry', :port => 1234})
150
- # end
151
- #
152
- # # Parameter inheritance
153
- # Net::SSH::Simple.sync({:user => 'tom', :port => 1234}) do
154
- # # Both commands will inherit :user and :port
155
- # ssh('example1.com', 'echo "Hello World."', {:password => 'jerry'})
156
- # scp_ul('example2.com', '/tmp/a', '/tmp/a', {:password => 's3cr3t'})
157
- # end
158
- #
159
- # @example
160
- # # Using the SCP progress callback
161
- # Net::SSH::Simple.sync do
162
- # scp_ul 'example1.com', '/tmp/local_foo', '/tmp/remote_bar' do |sent, total|
163
- # puts "Bytes uploaded: #{sent} of #{total}"
164
- # end
165
- # end
166
- #
167
- # @example
168
- # #
169
- # # Here be dragons: Using the event-API for a stdin->stdout pipeline
170
- # #
171
- # r = Net::SSH::Simple.sync do
172
- # # open a shell
173
- # ssh('localhost', '/bin/sh') do |e,c,d|
174
- # # e = :start, :stdout, :stderr, :exit_code, :exit_signal or :finish
175
- # # c = our Net::SSH::Connection::Channel instance
176
- # # d = data for this event
177
- # case e
178
- # # :start is triggered exactly once per connection
179
- # when :start
180
- # # we can send data using Channel#send_data
181
- # c.send_data("echo 'hello stdout'\n")
182
- # c.send_data("echo 'hello stderr' 1>&2\n")
183
- # # don't forget to eof when done feeding!
184
- # c.eof!
185
- #
186
- # # :stdout is triggered when there's stdout data from remote.
187
- # # by default the data is also appended to result[:stdout].
188
- # # you may return :no_append as seen below to avoid that.
189
- # when :stdout
190
- # # read the input line-wise (it *will* arrive fragmented!)
191
- # (@buf ||= '') << d
192
- # while line = @buf.slice!(/(.*)\r?\n/)
193
- # puts line #=> "hello stdout"
194
- # end
195
- # :no_append
196
- #
197
- # # :stderr is triggered when there's stderr data from remote.
198
- # # by default the data is also appended to result[:stderr].
199
- # # you may return :no_append as seen below to avoid that.
200
- # when :stderr
201
- # # read the input line-wise (it *will* arrive fragmented!)
202
- # (@buf ||= '') << d
203
- # while line = @buf.slice!(/(.*)\r?\n/)
204
- # puts line #=> "hello stderr"
205
- # end
206
- # :no_append
207
- #
208
- # # :exit_code is triggered when the remote process exits normally.
209
- # # it does *not* trigger when the remote process exits by signal!
210
- # when :exit_code
211
- # puts d #=> 0
212
- #
213
- # # :exit_signal is triggered when the remote is killed by signal.
214
- # # this would normally raise a Net::SSH::Simple::Error but
215
- # # we suppress that here by returning :no_raise
216
- # when :exit_signal
217
- # puts d # won't fire in this example, could be "TERM"
218
- # :no_raise
219
- #
220
- # # :finish triggers after :exit_code when the command exits normally.
221
- # # it does *not* trigger when the remote process exits by signal!
222
- # when :finish
223
- # puts "we are finished!"
224
- # end
225
- # end
226
- # end
227
- #
228
- # # Our Result has been populated normally, except for
229
- # # :stdout and :stdin (because we used :no_append).
230
- # puts r #=> Net::SSH::Simple::Result
231
- # puts r.exit_code #=> 0
232
- # puts r.stdout #=> ''
233
- # puts r.stderr #=> ''
234
- #
235
- #
236
- # @author moe@busyloop.net
237
- #
238
- class Simple
239
- include Blockenspiel::DSL
240
-
241
- #
242
- # Result of the current Net::SSH::Simple::Operation.
243
- #
244
- # @return [Net::SSH::Simple::Result] Result of the current operation
245
- attr_reader :result
246
-
247
- #
248
- # Perform ssh command on a remote host and capture the result.
249
- # This will create a new connection for each invocation.
250
- #
251
- # @example
252
- # Net::SSH::Simple.ssh('localhost', 'echo Hello').class #=> Net::SSH::Simple::Result
253
- #
254
- # @example
255
- # Net::SSH::Simple.ssh('localhost', 'echo Hello').stdout #=> "Hello"
256
- #
257
- # @param (see Net::SSH::Simple#ssh)
258
- # @raise [Net::SSH::Simple::Error]
259
- # @return [Net::SSH::Simple::Result] Result
260
- def self.ssh(*args, &block)
261
- s = self.new
262
- r = s.ssh(*args, &block)
263
- s.close
264
- r
265
- end
266
-
267
- #
268
- # SCP upload to a remote host.
269
- # This will create a new connection for each invocation.
270
- #
271
- # @example
272
- # # SCP Upload
273
- # Net::SSH::Simple.scp_ul('localhost', '/tmp/local_foo', '/tmp/remote_bar')
274
- #
275
- # @example
276
- # # Pass a block to monitor progress
277
- # Net::SSH::Simple.scp_ul('localhost', '/tmp/local_foo', '/tmp/remote_bar') do |sent, total|
278
- # puts "Bytes uploaded: #{sent} of #{total}"
279
- # end
280
- #
281
- # @param (see Net::SSH::Simple#scp_ul)
282
- # @raise [Net::SSH::Simple::Error]
283
- # @return [Net::SSH::Simple::Result] Result
284
- def self.scp_ul(*args, &block)
285
- s = self.new
286
- r = s.scp_ul(*args, &block)
287
- s.close
288
- r
289
- end
290
-
291
- #
292
- # SCP download from a remote host.
293
- # This will create a new connection for each invocation.
294
- #
295
- # @example
296
- # # SCP Download
297
- # Net::SSH::Simple.scp_dl('localhost', '/tmp/remote_foo', '/tmp/local_bar')
298
- #
299
- # @example
300
- # # Pass a block to monitor progress
301
- # Net::SSH::Simple.scp_dl('localhost', '/tmp/remote_foo', '/tmp/local_bar') do |sent, total|
302
- # puts "Bytes downloaded: #{sent} of #{total}"
303
- # end
304
- #
305
- # @param (see Net::SSH::Simple#scp_dl)
306
- # @raise [Net::SSH::Simple::Error]
307
- # @return [Net::SSH::Simple::Result] Result
308
- #
309
- def self.scp_dl(*args, &block)
310
- s = self.new
311
- r = s.scp_dl(*args, &block)
312
- s.close
313
- r
314
- end
315
-
316
- #
317
- # SCP upload to a remote host.
318
- # The underlying Net::SSH::Simple instance will re-use
319
- # existing connections for optimal performance.
320
- #
321
- # @param [String] host Destination hostname or ip-address
322
- # @param [String] cmd Shell command to execute
323
- # @param opts (see Net::SSH::Simple#ssh)
324
- # @param [Block] &block Progress callback (optional)
325
- # @return [Net::SSH::Simple::Result] Result
326
- #
327
- def scp_ul(host, src, dst, opts={}, &block)
328
- opts = @opts.merge(opts)
329
- scp(:upload, host, src, dst, opts, &block)
330
- end
331
-
332
- #
333
- # SCP download from a remote host.
334
- # The underlying Net::SSH::Simple instance will re-use
335
- # existing connections for optimal performance.
336
- #
337
- # @param [String] host Destination hostname or ip-address
338
- # @param [String] cmd Shell command to execute
339
- # @param opts (see Net::SSH::Simple#ssh)
340
- # @param [Block] &block Progress callback (optional)
341
- # @return [Net::SSH::Simple::Result] Result
342
- # @see Net::SSH::Simple#scp_ul
343
- #
344
- def scp_dl(host, src, dst, opts={}, &block)
345
- opts = @opts.merge(opts)
346
- scp(:download, host, src, dst, opts, &block)
347
- end
348
-
349
- #
350
- # Perform SSH operation on a remote host and capture the result.
351
- # The underlying Net::SSH::Simple instance will re-use
352
- # existing connections for optimal performance.
353
- #
354
- # @return [Net::SSH::Simple::Result] Result
355
- # @param [String] host Destination hostname or ip-address
356
- # @param [String] cmd Shell command to execute
357
- # @param [Block] &block Use the event-API (see example above)
358
- # @param [Hash] opts SSH options
359
- # @option opts [Array] :auth_methods
360
- # an array of authentication methods to try
361
- #
362
- # @option opts [String] :compression
363
- # the compression algorithm to use,
364
- # or true to use whatever is supported.
365
- #
366
- # @option opts [Number] :compression_level
367
- # the compression level to use when sending data
368
- #
369
- # @option opts [String/boolean] :opts (true)
370
- # set to true to load the default OpenSSH opts files
371
- # (~/.ssh/opts, /etc/ssh_opts), or to false to not load them,
372
- # or to a file-name (or array of file-names) to load those
373
- # specific configuration files.
374
- #
375
- # @option opts [Array] :encryption
376
- # the encryption cipher (or ciphers) to use
377
- #
378
- # @option opts [boolean] :forward_agent
379
- # set to true if you want the SSH agent connection to be forwarded
380
- #
381
- # @option opts [String/Array] :global_known_hosts_file
382
- # (['/etc/ssh/known_hosts','/etc/ssh/known_hosts2'])
383
- # the location of the global known hosts file.
384
- # Set to an array if you want to specify multiple
385
- # global known hosts files.
386
- #
387
- # @option opts [String/Array] :hmac
388
- # the hmac algorithm (or algorithms) to use
389
- #
390
- # @option opts [String] :host_key
391
- # the host key algorithm (or algorithms) to use
392
- #
393
- # @option opts [String] :host_key_alias
394
- # the host name to use when looking up or adding a host to a known_hosts dictionary file
395
- #
396
- # @option opts [String] :host_name
397
- # the real host name or IP to log into. This is used instead of the host parameter,
398
- # and is primarily only useful when specified in an SSH configuration file.
399
- # It lets you specify an alias, similarly to adding an entry in /etc/hosts but
400
- # without needing to modify /etc/hosts.
401
- #
402
- # @option opts [String/Array] :kex
403
- # the key exchange algorithm (or algorithms) to use
404
- #
405
- # @option opts [Array] :keys
406
- # an array of file names of private keys to use for publickey and hostbased authentication
407
- #
408
- # @option opts [Array] :key_data
409
- # an array of strings, with each element of the array being a raw private key in PEM format.
410
- #
411
- # @option opts [boolean] :keys_only
412
- # set to true to use only private keys from keys and key_data parameters, even if
413
- # ssh-agent offers more identities. This option is intended for situations where
414
- # ssh-agent offers many different identites.
415
- #
416
- # @option opts [Logger] :logger
417
- # the logger instance to use when logging
418
- #
419
- # @option opts [boolean/:very] :paranoid
420
- # either true, false, or :very, specifying how strict host-key verification should be
421
- #
422
- # @option opts [String] :passphrase (nil)
423
- # the passphrase to use when loading a private key (default is nil, for no passphrase)
424
- #
425
- # @option opts [String] :password
426
- # the password to use to login
427
- #
428
- # @option opts [Integer] :port
429
- # the port to use when connecting to the remote host
430
- #
431
- # @option opts [Hash] :properties
432
- # a hash of key/value pairs to add to the new connection's properties
433
- # (see Net::SSH::Connection::Session#properties)
434
- #
435
- # @option opts [String] :proxy
436
- # a proxy instance (see Proxy) to use when connecting
437
- #
438
- # @option opts [Integer] :rekey_blocks_limit
439
- # the max number of blocks to process before rekeying
440
- #
441
- # @option opts [Integer] :rekey_limit
442
- # the max number of bytes to process before rekeying
443
- #
444
- # @option opts [Integer] :rekey_packet_limit
445
- # the max number of packets to process before rekeying
446
- #
447
- # @option opts [Integer] :timeout (60)
448
- # maximum idle time before a connection will time out (0 = disable).
449
- #
450
- # @option opts [Integer] :operation_timeout (3600)
451
- # maximum time before aborting an operation (0 = disable).
452
- # you may use this to guard against run-away processes.
453
- #
454
- # @option opts [Integer] :keepalive_interval (60)
455
- # send keep-alive probes at this interval to prevent connections
456
- # from timing out unexpectedly.
457
- #
458
- # @option opts [Integer] :close_timeout (5)
459
- # grace-period on close before the connection will be terminated forcefully
460
- # (0 = terminate immediately).
461
- #
462
- # @option opts [String] :user
463
- # the username to log in as
464
- #
465
- # @option opts [String/Array] :user_known_hosts_file
466
- # (['~/.ssh/known_hosts, ~/.ssh/known_hosts2'])
467
- # the location of the user known hosts file. Set to an array to specify multiple
468
- # user known hosts files.
469
- #
470
- # @option opts [Symbol] :verbose
471
- # how verbose to be (Logger verbosity constants, Logger::DEBUG is very verbose,
472
- # Logger::FATAL is all but silent). Logger::FATAL is the default. The symbols
473
- # :debug, :info, :warn, :error, and :fatal are also supported and are translated
474
- # to the corresponding Logger constant.
475
- #
476
- # @see http://net-ssh.github.com/ssh/v2/api/classes/Net/SSH.html#M000002
477
- # Net::SSH documentation for the 'opts'-hash
478
- def ssh(host, cmd, opts={}, &block)
479
- opts = @opts.merge(opts)
480
- with_session(host, opts) do |session|
481
- @result = Result.new(
482
- { :op => :ssh, :host => host, :cmd => cmd, :start_at => Time.new,
483
- :last_event_at => Time.new, :opts => opts, :stdout => '', :stderr => '',
484
- :success => nil
485
- } )
486
-
487
- channel = session.open_channel do |chan|
488
- chan.exec cmd do |ch, success|
489
- @result[:success] = success
490
- ch.on_data do |c, data|
491
- @result[:last_event_at] = Time.new
492
- r = block.call(:stdout, ch, data) if block
493
- @result[:stdout] += data.to_s unless r == :no_append
494
- end
495
- ch.on_extended_data do |c, type, data|
496
- @result[:last_event_at] = Time.new
497
- r = block.call(:stderr, ch, data) if block
498
- @result[:stderr] += data.to_s unless r == :no_append
499
- end
500
- ch.on_request('exit-status') do |c, data|
501
- @result[:last_event_at] = Time.new
502
- exit_code = data.read_long
503
- block.call(:exit_code, ch, exit_code) if block
504
- @result[:exit_code] = exit_code
505
- end
506
- ch.on_request('exit-signal') do |c, data|
507
- @result[:last_event_at] = Time.new
508
- exit_signal = data.read_string
509
- r = block.call(:exit_signal, ch, exit_signal) if block
510
- @result[:exit_signal] = exit_signal
511
- @result[:success] = false
512
- unless r == :no_raise
513
- raise "Killed by SIG#{@result[:exit_signal]}"
514
- end
515
- end
516
- block.call(:start, ch, nil) if block
517
- end
518
- end
519
- wait_for_channel session, channel, @result, opts
520
- @result[:finish_at] = Time.new
521
- block.call(:finish, channel, nil) if block
522
- @result
523
- end
524
- end
525
-
526
- dsl_methods false
527
-
528
- def initialize(opts={})
529
- @opts = opts
530
- Thread.current[:ssh_simple_sessions] = {}
531
- @result = Result.new
532
- end
533
-
534
- #
535
- # Spawn a Thread to perform a sequence of ssh/scp operations.
536
- #
537
- # @param [Block] block
538
- # @param opts (see Net::SSH::Simple#ssh)
539
- # @return [Thread] Thread executing the SSH-Block.
540
- #
541
- def self.async(opts={}, &block)
542
- Thread.new do
543
- self.sync(opts, &block)
544
- end
545
- end
546
-
547
- #
548
- # Spawn a Thread to perform a sequence of ssh/scp operations.
549
- #
550
- # @param [Block] block
551
- # @param opts (see Net::SSH::Simple#ssh)
552
- # @return [Thread] Thread executing the SSH-Block.
553
- #
554
- def async(opts={}, &block)
555
- self.class.async(opts, &block)
556
- end
557
-
558
- #
559
- # Perform a sequence of ssh/scp operations.
560
- #
561
- # @param opts (see Net::SSH::Simple#ssh)
562
- # @return [Net::SSH::Simple::Result] Result
563
- #
564
- def self.sync(opts={}, &block)
565
- s = self.new(opts)
566
- r = Blockenspiel.invoke(block, s)
567
- s.close
568
- r
569
- end
570
-
571
- #
572
- # Close and cleanup.
573
- #
574
- # @return [Net::SSH::Simple::Result] Result
575
- #
576
- def close
577
- Thread.current[:ssh_simple_sessions].values.each do |session|
578
- begin
579
- Timeout.timeout(@opts[:close_timeout] || 5) { session.close }
580
- rescue => e
581
- begin
582
- session.shutdown!
583
- rescue
584
- end
585
- end
586
- end
587
- @result
588
- end
589
-
590
-
591
- private
592
- EXTRA_OPTS = [:operation_timeout, :close_timeout, :keepalive_interval]
593
-
594
- def with_session(host, opts={}, &block)
595
- opts[:timeout] ||= 60
596
- opts[:timeout] = 2**32 if opts[:timeout] == 0
597
- opts[:operation_timeout] ||= 3600
598
- opts[:operation_timeout] = 2**32 if opts[:operation_timeout] == 0
599
- opts[:close_timeout] ||= 5
600
- opts[:keepalive_interval] ||= 60
601
- begin
602
- net_ssh_opts = opts.reject{|k,v| EXTRA_OPTS.include? k }
603
- Timeout.timeout(opts[:operation_timeout]) do
604
- session = Thread.current[:ssh_simple_sessions][host.hash] \
605
- = Thread.current[:ssh_simple_sessions][host.hash] \
606
- || Net::SSH.start(*[host, opts[:user], net_ssh_opts])
607
- block.call(session)
608
- end
609
- rescue => e
610
- opts[:password].gsub!(/./,'*') if opts.include? :password
611
- @result[:exception] = e
612
- @result[:success] = false
613
- @result[:timed_out] = true if e.is_a? Timeout::Error
614
- @result[:finish_at] = Time.new
615
- raise Net::SSH::Simple::Error, [e, @result]
616
- end
617
- end
618
-
619
- def wait_for_channel(session, channel, result, opts)
620
- session.loop(1) do
621
- if opts[:timeout] < Time.now - result[:last_event_at]
622
- raise Timeout::Error, 'idle timeout'
623
- end
624
-
625
- # Send keep-alive probes at the configured interval.
626
- if opts[:keepalive_interval] < Time.now.to_i - (@result[:last_keepalive_at]||0).to_i
627
- session.send_global_request('keep-alive@openssh.com')
628
- @result[:last_keepalive_at] = Time.now
629
- end
630
- channel.active?
631
- end
632
- end
633
-
634
- def scp(mode, host, src, dst, opts={}, &block)
635
- @result = Result.new(
636
- { :op => :scp, :host => host, :opts => opts, :cmd => :scp_dl,
637
- :last_event_at => Time.new, :start_at => Time.new,
638
- :src => src, :dst => dst, :success => false
639
- } )
640
- with_session(host, opts) do |session|
641
- lt = 0
642
- channel = session.scp.send(mode, src, dst) do |ch, name, sent, total|
643
- @result[:name] ||= name
644
- @result[:total] ||= total
645
- @result[:sent] = sent
646
- @result[:last_event_at] = Time.new
647
- block.call(sent, total) unless block.nil?
648
- end
649
- wait_for_channel session, channel, @result, opts
650
- @result[:finish_at] = Time.new
651
- @result[:success] = @result[:sent] == @result[:total]
652
- @result
653
- end
654
- end
655
-
656
- #
657
- # Error that occured during a Net::SSH::Simple operation.
658
- #
659
- class Error < RuntimeError
660
- # Reference to the underlying Exception
661
- attr_reader :wrapped
662
-
663
- # {Net::SSH::Simple::Result} of the interrupted operation.
664
- attr_reader :result
665
-
666
- def initialize(msg, e=$!)
667
- super(msg)
668
- @wrapped = e
669
- @result = msg[1]
670
- end
671
-
672
- def to_s
673
- "#{super[0]} @ #{super[1]}"
674
- end
675
- end
676
-
677
- #
678
- # Result of a Net::SSH::Simple operation.
679
- #
680
- # @attr [String] host Hostname/IP address
681
- # @attr [Symbol] op :ssh or :scp
682
- # @attr [String] cmd Shell command (SSH only)
683
- # @attr [Time] start_at Timestamp of operation start
684
- # @attr [Time] finish_at Timestamp of operation finish
685
- # @attr [Time] last_keepalive_at Timestamp of last keepalive (if any)
686
- # @attr [Time] last_event_at Timestamp of last activity
687
- # @attr [Boolean] timed_out True if the operation timed out
688
- # @attr [String] stdout Output to stdout (SSH only)
689
- # @attr [String] stderr Output to stderr (SSH only)
690
- # @attr [boolean] success
691
- # @attr [String] exit_code UNIX exit code (SSH only)
692
- # @attr [Integer] total Size of requested file (in bytes, SCP only)
693
- # @attr [Integer] sent Number of bytes transferred (SCP only)
694
- # @attr [String] exit_signal
695
- # Only present if the remote command terminated due to a signal (SSH only)
696
- #
697
- class Result < Hashie::Mash; end
698
- end
699
- end
700
- end
701
-