kanrisuru 0.20.0 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 767ab1b59818ddd394ef7f4bb96435e5be43d2bf89c2c4469419f20a8a5f4a0c
4
- data.tar.gz: 4c370eb4c60270ed707a78606976b391d098c1298de026558c80a543e28d8326
3
+ metadata.gz: 38c3969fd06510c73c0237e611fb1b0acd31dade42489f21b9d118a456e5b834
4
+ data.tar.gz: 604ca2ef34b74dc435aa35ee24853f8f563e42cff6309d6d7d2c6b6437aa7bc3
5
5
  SHA512:
6
- metadata.gz: 8cacf38cbfc427dfe1c3a1980a8c52e3c004f119b13473380f0eaeeb0eba39c5c495bed0a2a2be37add8b8d148505f6a34ff7f0455b6a6c4c6b71f2e80849c75
7
- data.tar.gz: fbf05703912544955455f75af13ce799e0a039ee7269e7106bb3e2db9e1882cc2b2d90ee535c85e3bd0f259bffe4cfc4684ef49f97bf76884eaa61e1b8d3bc72
6
+ metadata.gz: 6ef8d8316b07a088e88a4aad0f5d0bb48419890ba0f00895c2bbae01eb356db246104e095d4e7fe06b91d9cebeaa2c2efe973d3302a40e3eeb4714d3e394dd83
7
+ data.tar.gz: b78410887ec8b5b3e809f4e59934f7c7f6e5d0363ddf9e4a38f436bd42ca0a43de8117f837646edec963c07051f4e546a0705ae2e4581a8971ead44943f22cca
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## Kanrisuru 1.0.0.beta1 (February 27, 2022) ##
2
+ * Add parallel mode for cluster. Allows hosts to run commands concurrently, reducing time it takes due to the high I/O blocking nature of the network requests.
3
+ * Add test cases for cluster parallel mode.
4
+ * Clean up methods on cluster class to use map and each methods in a simplified manner.
5
+ * Remove `/spec` dir from codecoverage.
6
+
1
7
  ## Kanrisuru 0.20.0 (February 21, 2022) ##
2
8
  * Allow hosts to be connected via proxy host. This is much like using a bastion / jump server.
3
9
  * Add integration test cases for proxy host connection.
data/README.md CHANGED
@@ -54,6 +54,27 @@ host = Kanrisuru::Remote::Host.new(
54
54
  )
55
55
  ```
56
56
 
57
+ #### Connect with a Jump / Bastion Host
58
+ To connect to a host behind a firewall through a jump / bastion host, pass either an instance of another Kanrisuru::Remote::Host, or a hash of host config values
59
+
60
+ ```ruby
61
+ proxy = Kanrisuru::Remote::Host.new(
62
+ host: 'proxy-host',
63
+ username: 'ubuntu',
64
+ keys: ['~/.ssh/proxy.pem']
65
+ )
66
+
67
+ host = Kanrisuru::Remote::Host.new(
68
+ host: '1.2.3.4',
69
+ username: 'ubuntu',
70
+ keys: ['~/.ssh/id_rsa'],
71
+ proxy: proxy
72
+ )
73
+
74
+ host.whoami
75
+ 'ubuntu'
76
+ ```
77
+
57
78
  #### run a simple echo command on the remote host
58
79
  ```ruby
59
80
  host.env['VAR'] = 'world'
@@ -124,7 +145,24 @@ host = Kanrisuru::Remote::Host.new(host: 'remote-host-4', username: 'rhel', keys
124
145
  cluster << host
125
146
  ```
126
147
 
127
- Kanrisuru at this point only runs commands sequentially. We plan on creating a parallel run mode in a future release.
148
+ #### Run cluster in parallel mode to reduce time waiting on blocking IO
149
+ ```ruby
150
+ Benchmark.measure do
151
+ cluster.each do |host|
152
+ puts cluster.pwd
153
+ end
154
+ end
155
+ # => 0.198980 0.029681 0.228661 ( 5.258496)
156
+
157
+ cluster.parallel = true
158
+
159
+ Benchmark.measure do
160
+ cluster.each do |host|
161
+ puts cluster.pwd
162
+ end
163
+ end
164
+ # => 0.016478 0.007956 0.024434 ( 0.120066)
165
+ ```
128
166
 
129
167
  #### To run across all hosts with a single command, cluster will return a array of result hashes
130
168
  ```ruby
@@ -34,9 +34,8 @@ module Kanrisuru
34
34
  os_method_names.each do |method_name|
35
35
  define_method method_name do |*args, &block|
36
36
  cluster = namespace_instance.instance_variable_get(:@cluster)
37
- hosts = cluster.instance_variable_get(:@hosts)
38
- hosts.map do |host_addr, host|
39
- { host: host_addr, result: host.send(namespace).send(method_name, *args, &block) }
37
+ cluster.map do |host|
38
+ host.send(namespace).send(method_name, *args, &block)
40
39
  end
41
40
  end
42
41
  end
@@ -45,8 +44,8 @@ module Kanrisuru
45
44
  class_eval do
46
45
  os_method_names.each do |method_name|
47
46
  define_method method_name do |*args, &block|
48
- @hosts.map do |host_addr, host|
49
- { host: host_addr, result: host.send(method_name, *args, &block) }
47
+ map do |host|
48
+ host.send(method_name, *args, &block)
50
49
  end
51
50
  end
52
51
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ require 'etc'
3
+
4
+ module Kanrisuru
5
+ # https://github.com/grosser/parallel/blob/master/lib/parallel/processor_count.rb
6
+ module ProcessorCount
7
+ # Number of processors seen by the OS, used for process scheduling
8
+ def self.processor_count
9
+ @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
10
+ end
11
+
12
+ # Number of physical processor cores on the current system.
13
+ def self.physical_processor_count
14
+ @physical_processor_count ||= begin
15
+ ppc =
16
+ case RbConfig::CONFIG["target_os"]
17
+ when /darwin[12]/
18
+ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
19
+ when /linux/
20
+ cores = {} # unique physical ID / core ID combinations
21
+ phy = 0
22
+ IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
23
+ if ln.start_with?("physical")
24
+ phy = ln[/\d+/]
25
+ elsif ln.start_with?("core")
26
+ cid = "#{phy}:#{ln[/\d+/]}"
27
+ cores[cid] = true unless cores[cid]
28
+ end
29
+ end
30
+ cores.count
31
+ when /mswin|mingw/
32
+ require 'win32ole'
33
+ result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
34
+ "select NumberOfCores from Win32_Processor"
35
+ )
36
+ result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
37
+ else
38
+ processor_count
39
+ end
40
+ # fall back to logical count if physical info is invalid
41
+ ppc > 0 ? ppc : processor_count
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'thread'
2
3
 
3
4
  module Kanrisuru
4
5
  module Remote
@@ -6,7 +7,12 @@ module Kanrisuru
6
7
  extend OsPackage::Collection
7
8
  include Enumerable
8
9
 
10
+ attr_accessor :parallel, :concurrency
11
+
9
12
  def initialize(*hosts)
13
+ @parallel = false
14
+ @concurrency = local_concurrency
15
+
10
16
  @hosts = {}
11
17
  hosts.each do |host_opts|
12
18
  add_host(host_opts)
@@ -30,37 +36,23 @@ module Kanrisuru
30
36
  end
31
37
 
32
38
  def execute(command)
33
- @hosts.map do |host_addr, host|
34
- ## Need to evaluate each host independently for the command.
35
- cmd = create_command(command)
36
-
37
- { host: host_addr, result: host.execute(cmd) }
38
- end
39
+ map { |host| host.execute(create_command(command)) }
39
40
  end
40
41
 
41
42
  def execute_shell(command)
42
- @hosts.map do |host_addr, host|
43
- ## Need to evaluate each host independently for the command.
44
- cmd = create_command(command)
45
-
46
- { host: host_addr, result: host.execute_shell(cmd) }
47
- end
48
- end
49
-
50
- def each(&block)
51
- @hosts.each { |_host_addr, host| block.call(host) }
43
+ map { |host| host.execute_shell(create_command(command)) }
52
44
  end
53
45
 
54
46
  def hostname
55
- map_host_results(:hostname)
47
+ map { |host| host.send(:hostname) }
56
48
  end
57
49
 
58
50
  def ping?
59
- map_host_results(:ping?)
51
+ map { |host| host.send(:ping?) }
60
52
  end
61
53
 
62
54
  def su(user)
63
- @hosts.each { |_, host| host.su(user) }
55
+ each { |host| host.su(user) }
64
56
  end
65
57
 
66
58
  def chdir(path = '~')
@@ -68,15 +60,70 @@ module Kanrisuru
68
60
  end
69
61
 
70
62
  def cd(path = '~')
71
- @hosts.each { |_, host| host.cd(path) }
63
+ each { |host| host.cd(path) }
72
64
  end
73
65
 
74
66
  def disconnect
75
- @hosts.each { |_, host| host.disconnect }
67
+ each { |host| host.disconnect }
68
+ end
69
+
70
+ def map(&block)
71
+ parallel? ? each_parallel(preserve: true, &block) : each_sequential(preserve: true, &block)
72
+ end
73
+
74
+ def each(&block)
75
+ parallel? ? each_parallel(preserve: false, &block) : each_sequential(preserve: false, &block)
76
+ end
77
+
78
+ def parallel?
79
+ @parallel
80
+ end
81
+
82
+ def sequential?
83
+ !parallel?
76
84
  end
77
85
 
78
86
  private
79
87
 
88
+ def each_sequential(opts = {}, &block)
89
+ results = @hosts.map do |host_addr, host|
90
+ { host: host_addr, result: block.call(host) }
91
+ end
92
+
93
+ opts[:preserve] ? results : self
94
+ end
95
+
96
+ def each_parallel(opts = {}, &block)
97
+ queue = Queue.new.tap do |q|
98
+ @hosts.each { |_, host| q << host }
99
+ end
100
+
101
+ threads = []
102
+ results = []
103
+ mutex = Mutex.new
104
+
105
+ ## No need to spawn more threads then number of hosts in cluster
106
+ concurrency = queue.length < @concurrency ? queue.length : @concurrency
107
+ concurrency.times do
108
+ threads << Thread.new do
109
+ loop do
110
+ host = queue.pop(true) rescue Thread.exit
111
+
112
+ begin
113
+ result = block.call(host)
114
+ mutex.synchronize { results.push({ host: host.host, result: result }) }
115
+ rescue Exception => exception
116
+ mutex.synchronize { results.push({ host: host.host, result: exception }) }
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ threads.each(&:join)
123
+
124
+ opts[:preserve] ? results : self
125
+ end
126
+
80
127
  def create_command(command)
81
128
  case command
82
129
  when String
@@ -88,12 +135,6 @@ module Kanrisuru
88
135
  end
89
136
  end
90
137
 
91
- def map_host_results(action)
92
- @hosts.map do |host_addr, host|
93
- { host: host_addr, result: host.send(action) }
94
- end
95
- end
96
-
97
138
  def remove_host(host)
98
139
  if host.instance_of?(Kanrisuru::Remote::Host)
99
140
  removed = false
@@ -119,14 +160,22 @@ module Kanrisuru
119
160
  end
120
161
 
121
162
  def add_host(host_opts)
122
- if host_opts.instance_of?(Hash)
163
+ case host_opts
164
+ when Hash
123
165
  @hosts[host_opts[:host]] = Kanrisuru::Remote::Host.new(host_opts)
124
- elsif host_opts.instance_of?(Kanrisuru::Remote::Host)
166
+ when Kanrisuru::Remote::Host
125
167
  @hosts[host_opts.host] = host_opts
168
+ when Kanrisuru::Remote::Cluster
169
+ host_opts.send(:each_sequential) { |host| @hosts[host.host] = host }
126
170
  else
127
171
  raise ArgumentError, 'Invalid host option'
128
172
  end
129
173
  end
174
+
175
+ def local_concurrency
176
+ ProcessorCount.physical_processor_count
177
+ end
178
+
130
179
  end
131
180
  end
132
181
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kanrisuru
4
- VERSION = '0.20.0'
4
+ VERSION = '1.0.0.beta1'
5
5
  end
data/lib/kanrisuru.rb CHANGED
@@ -29,6 +29,7 @@ require_relative 'kanrisuru/util'
29
29
  require_relative 'kanrisuru/mode'
30
30
  require_relative 'kanrisuru/os_package'
31
31
  require_relative 'kanrisuru/command'
32
+ require_relative 'kanrisuru/processor_count'
32
33
  require_relative 'kanrisuru/remote'
33
34
  require_relative 'kanrisuru/result'
34
35
  require_relative 'kanrisuru/core'
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::ProcessorCount do
6
+ it 'gets processor count' do
7
+ expect(described_class.processor_count).to be > 0
8
+ end
9
+
10
+ it 'gets physical processor count' do
11
+ expect(described_class.physical_processor_count).to be > 0
12
+ end
13
+
14
+ it "is even factor of logical cpus" do
15
+ expect(described_class.processor_count % described_class.physical_processor_count).to be == 0
16
+ end
17
+ end
@@ -27,6 +27,14 @@ RSpec.describe Kanrisuru::Remote::Cluster do
27
27
  )
28
28
  end
29
29
 
30
+ let(:host3) do
31
+ Kanrisuru::Remote::Host.new(
32
+ host: 'centos-host',
33
+ username: 'centos',
34
+ keys: ['id_rsa']
35
+ )
36
+ end
37
+
30
38
  it 'adds host to a cluster' do
31
39
  cluster = described_class.new(host1)
32
40
  expect(cluster.hosts.length).to eq(1)
@@ -46,7 +54,7 @@ RSpec.describe Kanrisuru::Remote::Cluster do
46
54
  username: 'centos',
47
55
  keys: ['id_rsa']
48
56
  }
49
-
57
+
50
58
  expect(cluster.hosts.length).to eq(3)
51
59
  expect(cluster.count).to eq(3)
52
60
  expect(cluster.count).to eq(3)
@@ -55,6 +63,19 @@ RSpec.describe Kanrisuru::Remote::Cluster do
55
63
  expect(cluster.hosts).to include(host2)
56
64
  end
57
65
 
66
+ it 'adds a cluster to another cluster' do
67
+ cluster1 = described_class.new(host1, host2)
68
+ cluster2 = described_class.new(host3)
69
+
70
+ cluster1 << cluster2
71
+ expect(cluster1.hosts.length).to eq(3)
72
+ expect(cluster1.count).to eq(3)
73
+ expect(cluster1.count).to eq(3)
74
+ expect(cluster1['centos-host'].username).to eq('centos')
75
+ expect(cluster1.hosts).to include(host1)
76
+ expect(cluster1.hosts).to include(host2)
77
+ end
78
+
58
79
  it 'fails to add host to a cluster' do
59
80
  cluster = described_class.new
60
81
  expect { cluster << 1 }.to raise_error(ArgumentError)
@@ -90,6 +111,58 @@ RSpec.describe Kanrisuru::Remote::Cluster do
90
111
  end.to raise_error(ArgumentError)
91
112
  end
92
113
 
114
+ it 'initializes cluster and is run in sequential mode by default' do
115
+ cluster = described_class.new
116
+ expect(cluster).to be_sequential
117
+ end
118
+
119
+ it 'sets cluster to parallel mode' do
120
+ cluster = described_class.new
121
+ cluster.parallel = true
122
+ expect(cluster).to be_parallel
123
+ end
124
+
125
+ it 'runs commands on a cluster sequentialy' do
126
+ cluster = described_class.new(host1, host2)
127
+
128
+ expect(cluster).to receive(:each_sequential)
129
+
130
+ command = Kanrisuru::Command.new('pwd')
131
+ cluster.execute(command)
132
+ end
133
+
134
+ it 'runs commands on a cluster in parallel across hosts' do
135
+ cluster = described_class.new(host1, host2)
136
+ cluster.parallel = true
137
+
138
+ expect(cluster).to receive(:each_parallel)
139
+
140
+ command = Kanrisuru::Command.new('pwd')
141
+ cluster.execute(command)
142
+ end
143
+
144
+ it 'gets cluster back from each method' do
145
+ cluster = described_class.new(host1, host2)
146
+
147
+ c = cluster.each { |h| h.su('root') }
148
+ expect(c).to be_instance_of(Kanrisuru::Remote::Cluster)
149
+ expect(c.object_id).to eq(cluster.object_id)
150
+ end
151
+
152
+ it 'gets results back from map method' do
153
+ cluster = described_class.new(host1, host2)
154
+
155
+ results = cluster.map do |host|
156
+ host.execute('hello')
157
+ end
158
+
159
+ expect(results).to be_instance_of(Array)
160
+ results.each do |result|
161
+ expect(result).to have_key(:host)
162
+ expect(result).to have_key(:result)
163
+ end
164
+ end
165
+
93
166
  it 'runs execute for a command on a cluster' do
94
167
  cluster = described_class.new
95
168
  cluster << host1
@@ -185,6 +258,19 @@ RSpec.describe Kanrisuru::Remote::Cluster do
185
258
  StubNetwork.unstub_command!(:realpath)
186
259
  end
187
260
 
261
+ it 'raises and catches exception in parallel mode' do
262
+ cluster = described_class.new(host1, host2, host3)
263
+ cluster.parallel = true
264
+
265
+ results = cluster.map do |host|
266
+ raise ArgumentError
267
+ end
268
+
269
+ results.each do |result|
270
+ expect(result[:result]).to be_instance_of(ArgumentError)
271
+ end
272
+ end
273
+
188
274
  it 'changes current working directory for each host in a cluster' do
189
275
  cluster = described_class.new(host1, host2)
190
276
 
@@ -4,6 +4,8 @@ require 'simplecov'
4
4
  require 'simplecov-cobertura'
5
5
 
6
6
  SimpleCov.start do
7
+ add_filter '/spec/'
8
+
7
9
  command_name "kanrisuru-tests#{ENV['TEST_ENV_NUMBER'] || ''}"
8
10
  merge_timeout 2400
9
11
 
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'spec_helper'
5
+
6
+ RSpec.describe Kanrisuru::Remote::Cluster do
7
+ let(:host1) do
8
+ Kanrisuru::Remote::Host.new(
9
+ host: TestHosts.host('ubuntu')['hostname'],
10
+ username: TestHosts.host('ubuntu')['username'],
11
+ keys: [TestHosts.host('ubuntu')['ssh_key']]
12
+ )
13
+ end
14
+
15
+ let(:host2) do
16
+ Kanrisuru::Remote::Host.new(
17
+ host: TestHosts.host('debian')['hostname'],
18
+ username: TestHosts.host('debian')['username'],
19
+ keys: [TestHosts.host('debian')['ssh_key']]
20
+ )
21
+ end
22
+
23
+ let(:host3) do
24
+ Kanrisuru::Remote::Host.new(
25
+ host: TestHosts.host('centos')['hostname'],
26
+ username: TestHosts.host('centos')['username'],
27
+ keys: [TestHosts.host('centos')['ssh_key']]
28
+ )
29
+ end
30
+
31
+ let(:host4) do
32
+ Kanrisuru::Remote::Host.new(
33
+ host: TestHosts.host('opensuse')['hostname'],
34
+ username: TestHosts.host('opensuse')['username'],
35
+ keys: [TestHosts.host('opensuse')['ssh_key']]
36
+ )
37
+ end
38
+
39
+ it 'gets hostname for cluster' do
40
+ cluster = described_class.new(host1, host2, host3, host4)
41
+ expect(cluster.hostname).to match([
42
+ { host: 'ubuntu-host', result: 'ubuntu-host' },
43
+ { host: 'debian-host', result: 'debian-host' },
44
+ { host: 'centos-host', result: 'centos-host' },
45
+ { host: 'opensuse-host', result: 'opensuse-host' },
46
+ ])
47
+
48
+ cluster.disconnect
49
+ end
50
+
51
+ it 'can ping host cluster' do
52
+ cluster = described_class.new(host1, host2, host3, host4)
53
+ expect(cluster.ping?).to match([
54
+ { host: 'ubuntu-host', result: true },
55
+ { host: 'debian-host', result: true },
56
+ { host: 'centos-host', result: true },
57
+ { host: 'opensuse-host', result: true },
58
+ ])
59
+
60
+ cluster.disconnect
61
+ end
62
+
63
+ it 'should use specific number of threads as number of hosts' do
64
+ cluster = described_class.new(host1, host2, host3, host4)
65
+ cluster.parallel = true
66
+
67
+ ## Called x2 b/c two methods invoke the parallel runner
68
+ expect(Thread).to receive(:new).exactly(cluster.count * 2).times.and_call_original
69
+
70
+ cluster.hostname
71
+ cluster.disconnect
72
+ end
73
+
74
+ it 'should respect concurrency setting' do
75
+ concurrency = 2
76
+
77
+ cluster = described_class.new(host1, host2, host3, host4)
78
+ cluster.parallel = true
79
+ cluster.concurrency = concurrency
80
+
81
+ ## Called x2 b/c two methods invoke the parallel runner
82
+ expect(Thread).to receive(:new).exactly(concurrency * 2).times.and_call_original
83
+
84
+ cluster.hostname
85
+ cluster.disconnect
86
+ end
87
+
88
+ it 'saves time running cluster in parallel mode' do
89
+ cluster = described_class.new(host1, host2, host3, host4)
90
+ time1 = Benchmark.measure {
91
+ cluster.each do |host|
92
+ expect(host.pwd).to be_success
93
+ end
94
+ }
95
+
96
+ cluster.parallel = true
97
+ time2 = Benchmark.measure {
98
+ cluster.each do |host|
99
+ expect(host.pwd).to be_success
100
+ end
101
+ }
102
+
103
+ expect(time1.total).to be > time2.total
104
+ cluster.disconnect
105
+ end
106
+
107
+ it 'disconnects all hosts' do
108
+ cluster = described_class.new(host1, host2, host3, host4)
109
+ cluster.disconnect
110
+
111
+ cluster.each do |host|
112
+ expect(host.ssh).to be_closed
113
+ end
114
+ end
115
+ end
@@ -41,7 +41,7 @@ RSpec.shared_examples 'host' do |os_name, host_json, _spec_dir|
41
41
  proxy: proxy
42
42
  )
43
43
 
44
- ## Test instiation
44
+ ## Test instantiation
45
45
  expect(host.proxy).to be_instance_of(Net::SSH::Gateway)
46
46
  expect(host.ssh).to be_instance_of(Net::SSH::Connection::Session)
47
47
 
@@ -61,8 +61,6 @@ RSpec.shared_examples 'host' do |os_name, host_json, _spec_dir|
61
61
  expect(result).to be_instance_of(String)
62
62
  lines = result.split("\n")
63
63
  expect(lines.length).to be >= 1
64
-
65
- ## Test upload
66
64
  end
67
65
 
68
66
  it 'changes directories' do
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::ProcessorCount do
6
+ it 'responds to methods' do
7
+ expect(described_class).to respond_to(:processor_count)
8
+ expect(described_class).to respond_to(:physical_processor_count)
9
+ end
10
+ end
@@ -26,11 +26,16 @@ RSpec.describe Kanrisuru::Remote::Cluster do
26
26
  expect(cluster).to respond_to(:execute)
27
27
  expect(cluster).to respond_to(:execute_shell)
28
28
  expect(cluster).to respond_to(:each)
29
+ expect(cluster).to respond_to(:map)
29
30
  expect(cluster).to respond_to(:hostname)
30
31
  expect(cluster).to respond_to(:ping?)
31
32
  expect(cluster).to respond_to(:su)
32
33
  expect(cluster).to respond_to(:chdir)
33
34
  expect(cluster).to respond_to(:cd)
34
35
  expect(cluster).to respond_to(:disconnect)
36
+ expect(cluster).to respond_to(:parallel)
37
+ expect(cluster).to respond_to(:concurrency)
38
+ expect(cluster).to respond_to(:parallel?)
39
+ expect(cluster).to respond_to(:sequential?)
35
40
  end
36
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kanrisuru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.0
4
+ version: 1.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mammina
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-20 00:00:00.000000000 Z
11
+ date: 2022-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel_tests
@@ -440,6 +440,7 @@ files:
440
440
  - lib/kanrisuru/os_package/collection.rb
441
441
  - lib/kanrisuru/os_package/define.rb
442
442
  - lib/kanrisuru/os_package/include.rb
443
+ - lib/kanrisuru/processor_count.rb
443
444
  - lib/kanrisuru/remote.rb
444
445
  - lib/kanrisuru/remote/cluster.rb
445
446
  - lib/kanrisuru/remote/cpu.rb
@@ -486,6 +487,7 @@ files:
486
487
  - spec/functional/core/user_spec.rb
487
488
  - spec/functional/core/yum_spec.rb
488
489
  - spec/functional/core/zypper_spec.rb
490
+ - spec/functional/processor_count_spec.rb
489
491
  - spec/functional/remote/cluster_spec.rb
490
492
  - spec/functional/remote/cpu_spec.rb
491
493
  - spec/functional/remote/env_spec.rb
@@ -602,7 +604,7 @@ files:
602
604
  - spec/integration/core/zypper/opensuse_spec.rb
603
605
  - spec/integration/core/zypper/sles_spec.rb
604
606
  - spec/integration/os_package_spec.rb
605
- - spec/integration/remote/cluster/ubuntu_spec.rb
607
+ - spec/integration/remote/cluster/cluster_spec.rb
606
608
  - spec/integration/remote/cpu/centos_spec.rb
607
609
  - spec/integration/remote/cpu/debian_spec.rb
608
610
  - spec/integration/remote/cpu/fedora_spec.rb
@@ -670,7 +672,6 @@ files:
670
672
  - spec/support/shared_examples/integration/core/user.rb
671
673
  - spec/support/shared_examples/integration/core/yum.rb
672
674
  - spec/support/shared_examples/integration/core/zypper.rb
673
- - spec/support/shared_examples/integration/remote/cluster.rb
674
675
  - spec/support/shared_examples/integration/remote/cpu.rb
675
676
  - spec/support/shared_examples/integration/remote/env_spec.rb
676
677
  - spec/support/shared_examples/integration/remote/fstab.rb
@@ -697,6 +698,7 @@ files:
697
698
  - spec/unit/core/zypper_spec.rb
698
699
  - spec/unit/kanrisuru_spec.rb
699
700
  - spec/unit/mode_spec.rb
701
+ - spec/unit/processor_count_spec.rb
700
702
  - spec/unit/remote/cluster_spec.rb
701
703
  - spec/unit/remote/cpu_spec.rb
702
704
  - spec/unit/remote/env_spec.rb
@@ -722,9 +724,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
722
724
  version: 2.5.0
723
725
  required_rubygems_version: !ruby/object:Gem::Requirement
724
726
  requirements:
725
- - - ">="
727
+ - - ">"
726
728
  - !ruby/object:Gem::Version
727
- version: '0'
729
+ version: 1.3.1
728
730
  requirements: []
729
731
  rubygems_version: 3.3.5
730
732
  signing_key:
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- TestHosts.each_os(only: %w[ubuntu]) do |os_name, host_json, spec_dir|
6
- RSpec.describe Kanrisuru::Core::Disk do
7
- include_examples 'disk', os_name, host_json, spec_dir
8
- end
9
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.shared_examples 'cluster' do |os_name, host_json, _spec_dir|
6
- context "with #{os_name}" do
7
- let(:host1) do
8
- Kanrisuru::Remote::Host.new(
9
- host: host_json['hostname'],
10
- username: host_json['username'],
11
- keys: [host_json['ssh_key']]
12
- )
13
- end
14
-
15
- let(:host2) do
16
- Kanrisuru::Remote::Host.new(
17
- host: 'localhost',
18
- username: 'ubuntu',
19
- keys: ['~/.ssh/id_rsa']
20
- )
21
- end
22
-
23
- it 'gets hostname for cluster' do
24
- cluster = described_class.new({
25
- host: 'localhost',
26
- username: 'ubuntu',
27
- keys: ['~/.ssh/id_rsa']
28
- }, {
29
- host: '127.0.0.1',
30
- username: 'ubuntu',
31
- keys: ['~/.ssh/id_rsa']
32
- })
33
-
34
- expect(cluster.hostname).to match([
35
- { host: 'localhost', result: 'ubuntu' },
36
- { host: '127.0.0.1', result: 'ubuntu' }
37
- ])
38
-
39
- cluster.disconnect
40
- end
41
-
42
- it 'can ping host cluster' do
43
- cluster = described_class.new({
44
- host: 'localhost',
45
- username: 'ubuntu',
46
- keys: ['~/.ssh/id_rsa']
47
- }, {
48
- host: '127.0.0.1',
49
- username: 'ubuntu',
50
- keys: ['~/.ssh/id_rsa']
51
- })
52
-
53
- expect(cluster.ping?).to match([
54
- { host: 'localhost', result: true },
55
- { host: '127.0.0.1', result: true }
56
- ])
57
-
58
- cluster.disconnect
59
- end
60
-
61
- it 'disconnects all hosts' do
62
- cluster = described_class.new(host1, host2)
63
- cluster.disconnect
64
-
65
- cluster.each do |host|
66
- expect(host.ssh.closed).to be_truthy
67
- end
68
- end
69
- end
70
- end