weave 1.0.2.beta1 → 1.1.0.pre.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -3
- data/examples/basic.rb +2 -2
- data/lib/weave.rb +40 -59
- data/weave.gemspec +6 -9
- metadata +28 -28
- data/lib/weave/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa0ce3c6677178d9891d65239ab9982fe0e6038d
|
4
|
+
data.tar.gz: 892226999386cb1e0caf1a93b55fd4f72e362703
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c691d81f57e0d6ae599fea383ee7bd9b9b31341d17b6614719198a5de20989c9d87b7e07a91bb405b8824db4a36626bf2b3c9c81543bd4fa7d29cfed63778e9
|
7
|
+
data.tar.gz: 0fe3897f7c733b1228742bd76588f6b2cc831037d38013840fa434d5baecf96135ec7952aba7c76d94dbb48bc50f1fcf8918492f53c1cb1aaa7590ad572f0327
|
data/README.md
CHANGED
@@ -10,9 +10,8 @@ Put `weave` in your Gemfile or install directly:
|
|
10
10
|
|
11
11
|
## Documentation
|
12
12
|
|
13
|
-
[Method docs here](http://rubydoc.info/github/cespare/weave/master/frames).
|
14
|
-
|
15
|
-
|
13
|
+
[Method docs here](http://rubydoc.info/github/cespare/weave/master/frames). See the examples (in `examples/`)
|
14
|
+
to get started.
|
16
15
|
|
17
16
|
## Implemented features
|
18
17
|
|
@@ -22,3 +21,9 @@ examples (in `examples/`) to get started.
|
|
22
21
|
* Commands:
|
23
22
|
|
24
23
|
- `run`
|
24
|
+
|
25
|
+
## Tests
|
26
|
+
|
27
|
+
You need vagrant installed. `vagrant up` to get the machines running. Then:
|
28
|
+
|
29
|
+
$ bundle exec rake test
|
data/examples/basic.rb
CHANGED
data/lib/weave.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "net/ssh"
|
2
2
|
require "thread"
|
3
|
-
require "timeout"
|
4
3
|
|
5
4
|
module Weave
|
6
5
|
DEFAULT_THREAD_POOL_SIZE = 10
|
@@ -12,16 +11,18 @@ module Weave
|
|
12
11
|
COLORS = { :red => 1, :green => 2 }
|
13
12
|
|
14
13
|
# Create a connection pool for an array of hosts. Each host must have a user specified (e.g.,
|
15
|
-
# root@example.com). If
|
16
|
-
#
|
17
|
-
#
|
14
|
+
# root@example.com). If the key :net_ssh_options is present in options, then the value is a hash of options
|
15
|
+
# that is passed directly to Net::SSH.start. If a block is given, then the options (except for
|
16
|
+
# :net_ssh_options) are passed through to the underlying ConnectionPool and the block is immediately run in
|
17
|
+
# the context of each connection. Otherwise, a pool is returned.
|
18
18
|
#
|
19
19
|
# @see ConnectionPool#execute
|
20
20
|
def self.connect(host_list, options = {}, &block)
|
21
21
|
unless host_list.is_a? Array
|
22
22
|
raise Weave::Error, "Must pass an array for host_list. Received: #{host_list.inspect}"
|
23
23
|
end
|
24
|
-
|
24
|
+
net_ssh_options = options.delete(:net_ssh_options)
|
25
|
+
pool = ConnectionPool.new(host_list, net_ssh_options)
|
25
26
|
if block_given?
|
26
27
|
pool.execute(options, &block)
|
27
28
|
pool.disconnect!
|
@@ -61,9 +62,12 @@ module Weave
|
|
61
62
|
class ConnectionPool
|
62
63
|
# @param [Array] host_list the array of hosts, of the form user@host. You may leave off this argument, and
|
63
64
|
# use #execute_with (instead of #execute) to specify the whole list of hosts each time.
|
64
|
-
def initialize(host_list = [])
|
65
|
+
def initialize(host_list = [], net_ssh_options = {})
|
65
66
|
@hosts = host_list
|
66
|
-
@
|
67
|
+
@net_ssh_options = net_ssh_options
|
68
|
+
@connections = host_list.reduce({}) do |pool, host|
|
69
|
+
pool.merge(host => LazyConnection.new(host, @net_ssh_options))
|
70
|
+
end
|
67
71
|
end
|
68
72
|
|
69
73
|
# Run a command over the connection pool. The block is evaluated in the context of LazyConnection.
|
@@ -82,7 +86,7 @@ module Weave
|
|
82
86
|
# This is the same as #execute, except that host_list overrides the list of connections with which this
|
83
87
|
# ConnectionPool was initialized. Any hosts in here that weren't already in the pool will be added.
|
84
88
|
def execute_with(host_list, options = {}, &block)
|
85
|
-
host_list.each { |host| @connections[host] ||= LazyConnection.new(host) }
|
89
|
+
host_list.each { |host| @connections[host] ||= LazyConnection.new(host, @net_ssh_options) }
|
86
90
|
args = options[:args] || []
|
87
91
|
num_threads = options[:num_threads] || DEFAULT_THREAD_POOL_SIZE
|
88
92
|
if options[:serial]
|
@@ -120,9 +124,10 @@ module Weave
|
|
120
124
|
attr_reader :host
|
121
125
|
|
122
126
|
# @param [String] host_string the host of the form user@host
|
123
|
-
def initialize(host_string)
|
127
|
+
def initialize(host_string, net_ssh_options = {})
|
124
128
|
@user, @host = self.class.user_and_host(host_string)
|
125
129
|
@connection = nil
|
130
|
+
@net_ssh_options = net_ssh_options || {}
|
126
131
|
@mutex = NilMutex
|
127
132
|
end
|
128
133
|
|
@@ -144,71 +149,47 @@ module Weave
|
|
144
149
|
# command terminated via a signal or with a non-zero exit status. Otherwise (the default), these will
|
145
150
|
# cause a `Weave::Error` to be raised.
|
146
151
|
#
|
147
|
-
# The option `:timeout`, if provided, specifies the number of seconds to allow the command to execute
|
148
|
-
# before timing it out. If this happens, the output is unchanged (but in most cases, this will be an error
|
149
|
-
# as your process was killed by a signal from the pseudo-tty Weave allocates for it on the remote host).
|
150
|
-
# If the command is timed out, the result hash also has `:timed_out => true` (is is `false` otherwise).
|
151
|
-
#
|
152
152
|
# @param [Hash] options the output options
|
153
153
|
# @option options [Symbol] :output the output format
|
154
|
-
# @option options [Symbol] :continue_on_failure whether to raise an exception if the command exits with a
|
155
|
-
# non-zero exit status or because of a signal
|
156
|
-
# @option options[Symbol] :timeout if given, how many seconds to give the command before timing it out
|
157
154
|
def run(command, options = {})
|
158
155
|
options[:output] ||= :pretty
|
159
|
-
@connection ||= Net::SSH.start(@host, @user)
|
156
|
+
@connection ||= Net::SSH.start(@host, @user, @net_ssh_options)
|
160
157
|
result = options[:output] == :capture ? { :stdout => "", :stderr => "" } : {}
|
161
|
-
result[:timed_out] = false
|
162
158
|
@connection.open_channel do |channel|
|
163
|
-
channel.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
raise Error, "Could not run ssh command: #{command}"
|
168
|
-
end
|
159
|
+
channel.exec(command) do |_, success|
|
160
|
+
unless success
|
161
|
+
raise Error, "Could not run ssh command: #{command}"
|
162
|
+
end
|
169
163
|
|
170
|
-
|
171
|
-
|
172
|
-
|
164
|
+
channel.on_data do |_, data|
|
165
|
+
append_or_print_output(result, data, :stdout, options)
|
166
|
+
end
|
173
167
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
168
|
+
channel.on_extended_data do |_, type, data|
|
169
|
+
next unless type == 1
|
170
|
+
append_or_print_output(result, data, :stderr, options)
|
171
|
+
end
|
178
172
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
184
|
-
result[:exit_code] = code
|
173
|
+
channel.on_request("exit-status") do |_, data|
|
174
|
+
code = data.read_long
|
175
|
+
unless code.zero? || options[:continue_on_failure]
|
176
|
+
raise Error, "[#{@host}] command finished with exit status #{code}: #{command}"
|
185
177
|
end
|
178
|
+
result[:exit_code] = code
|
179
|
+
end
|
186
180
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end
|
194
|
-
result[:exit_signal] = signal
|
181
|
+
channel.on_request("exit-signal") do |_, data|
|
182
|
+
signal = data.read_long
|
183
|
+
unless options[:continue_on_failure]
|
184
|
+
signal_name = Signal.list.invert[signal]
|
185
|
+
signal_message = signal_name ? "#{signal} (#{signal_name})" : "#{signal}"
|
186
|
+
raise Error, "[#{@host}] command received signal #{signal_message}: #{command}"
|
195
187
|
end
|
188
|
+
result[:exit_signal] = signal
|
196
189
|
end
|
197
190
|
end
|
198
191
|
end
|
199
|
-
|
200
|
-
@connection.loop(0.05)
|
201
|
-
else
|
202
|
-
begin
|
203
|
-
Timeout.timeout(options[:timeout]) do
|
204
|
-
@connection.loop(0.05)
|
205
|
-
end
|
206
|
-
rescue Timeout::Error
|
207
|
-
@connection.close
|
208
|
-
@connection = nil
|
209
|
-
result[:timed_out] = true
|
210
|
-
end
|
211
|
-
end
|
192
|
+
@connection.loop(0.05)
|
212
193
|
result
|
213
194
|
end
|
214
195
|
|
data/weave.gemspec
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../lib/weave/version', __FILE__)
|
3
|
-
|
4
1
|
Gem::Specification.new do |gem|
|
5
2
|
gem.authors = ["Caleb Spare"]
|
6
3
|
gem.email = ["cespare@gmail.com"]
|
@@ -14,14 +11,14 @@ Gem::Specification.new do |gem|
|
|
14
11
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
12
|
gem.name = "weave"
|
16
13
|
gem.require_paths = ["lib"]
|
17
|
-
gem.version =
|
14
|
+
gem.version = "1.1.0-beta1"
|
18
15
|
|
19
|
-
gem.add_dependency "net-ssh", "
|
16
|
+
gem.add_dependency "net-ssh", "~> 2.9"
|
20
17
|
|
21
18
|
# For running integration tests.
|
22
|
-
gem.add_development_dependency "minitest"
|
23
|
-
gem.add_development_dependency "rake"
|
19
|
+
gem.add_development_dependency "minitest", "~> 5.0"
|
20
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
24
21
|
# For generating the docs
|
25
|
-
gem.add_development_dependency "yard"
|
26
|
-
gem.add_development_dependency "redcarpet"
|
22
|
+
gem.add_development_dependency "yard", "~> 0.8"
|
23
|
+
gem.add_development_dependency "redcarpet", "~> 3.0"
|
27
24
|
end
|
metadata
CHANGED
@@ -1,85 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: weave
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.1.0.pre.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caleb Spare
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: '2.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: '2.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '5.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '5.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '10.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '10.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: yard
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '0.8'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
68
|
+
version: '0.8'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: redcarpet
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '3.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '3.0'
|
83
83
|
description: Simple parallel ssh.
|
84
84
|
email:
|
85
85
|
- cespare@gmail.com
|
@@ -87,8 +87,8 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
-
- .gitignore
|
91
|
-
- .yardopts
|
90
|
+
- ".gitignore"
|
91
|
+
- ".yardopts"
|
92
92
|
- Gemfile
|
93
93
|
- LICENSE
|
94
94
|
- README.md
|
@@ -97,7 +97,6 @@ files:
|
|
97
97
|
- examples/basic.rb
|
98
98
|
- examples/parallel-console.rb
|
99
99
|
- lib/weave.rb
|
100
|
-
- lib/weave/version.rb
|
101
100
|
- test/integrations/sanity_test.rb
|
102
101
|
- test/test_helper.rb
|
103
102
|
- weave.gemspec
|
@@ -111,20 +110,21 @@ require_paths:
|
|
111
110
|
- lib
|
112
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
112
|
requirements:
|
114
|
-
- -
|
113
|
+
- - ">="
|
115
114
|
- !ruby/object:Gem::Version
|
116
115
|
version: '0'
|
117
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
117
|
requirements:
|
119
|
-
- -
|
118
|
+
- - ">"
|
120
119
|
- !ruby/object:Gem::Version
|
121
120
|
version: 1.3.1
|
122
121
|
requirements: []
|
123
122
|
rubyforge_project:
|
124
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.2.2
|
125
124
|
signing_key:
|
126
125
|
specification_version: 4
|
127
126
|
summary: Simple parallel ssh.
|
128
127
|
test_files:
|
129
128
|
- test/integrations/sanity_test.rb
|
130
129
|
- test/test_helper.rb
|
130
|
+
has_rdoc:
|
data/lib/weave/version.rb
DELETED