remote_run 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ module RemoteRun
2
+ class Configuration
3
+ attr_accessor :remote_path, :local_path, :login_as, :exclude, :temp_path, :quiet
4
+ attr_reader :local_hostname, :identifier, :start_time
5
+ attr_reader :host_manager, :task_manager
6
+
7
+ def initialize
8
+ @task_manager = TaskManager.new
9
+ @host_manager = HostManager.new
10
+
11
+ @local_path = Dir.getwd
12
+ @login_as = `whoami`.strip
13
+ @remote_path = "/tmp/remote"
14
+ @exclude = []
15
+ @temp_path = "/tmp/remote"
16
+ @quiet = false
17
+ @start_time = Time.now
18
+
19
+ # used in the runner
20
+ @identifier = `echo $RANDOM`.strip
21
+ @local_hostname = `hostname`.strip
22
+
23
+ $runner = self
24
+ yield self
25
+ end
26
+
27
+ def hosts
28
+ @host_manager.hosts
29
+ end
30
+
31
+ def tasks
32
+ @task_manager.tasks
33
+ end
34
+
35
+ def hosts=(hostnames)
36
+ hostnames.each do |hostname|
37
+ @host_manager.add(Host.new(hostname))
38
+ end
39
+ end
40
+
41
+ def tasks=(shell_commands)
42
+ shell_commands.each do |shell_command|
43
+ @task_manager.add(Task.new(shell_command))
44
+ end
45
+ end
46
+
47
+ def run
48
+ Runner.new(self).run
49
+ end
50
+
51
+ private
52
+
53
+ class HostManager
54
+ def initialize(&block)
55
+ @hosts = []
56
+ end
57
+
58
+ def add(host)
59
+ Thread.new do
60
+ if host.is_up?
61
+ @hosts << host
62
+ end
63
+ end
64
+ end
65
+
66
+ def hosts
67
+ while @hosts.empty?
68
+ sleep(0.5)
69
+ end
70
+ @hosts
71
+ end
72
+ end
73
+
74
+ class TaskManager
75
+ attr_reader :tasks
76
+
77
+ def initialize
78
+ @tasks = []
79
+ end
80
+
81
+ def add(task)
82
+ @tasks.push(task)
83
+ end
84
+
85
+ def find_task
86
+ @tasks.shift
87
+ end
88
+
89
+ def count
90
+ @tasks.length
91
+ end
92
+
93
+ def has_more_tasks?
94
+ @tasks.size > 0
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,128 +1,125 @@
1
- class Host
2
- FAIL = 1
3
- PASS = 0
4
- SSH_CONFIG = " -o ControlMaster=auto -o ControlPath=~/.ssh/master-%l-%r@%h:%p -o NumberOfPasswordPrompts=0 -o StrictHostKeyChecking=no -4 "
5
- attr_reader :hostname
6
- attr_reader :lock_file
7
-
8
- def initialize(hostname)
9
- @hostname = hostname
10
- @lock_file = LockFile.new(@hostname, $runner.local_hostname, $runner.identifier)
11
- end
12
-
13
- def lock
14
- unless locked?
15
- @lock_file.get && locked_by_me?
1
+ module RemoteRun
2
+ class Host
3
+ FAIL = 1
4
+ PASS = 0
5
+ SSH_CONFIG = " -o ControlMaster=auto -o ControlPath=~/.ssh/master-%l-%r@%h:%p -o NumberOfPasswordPrompts=0 -o StrictHostKeyChecking=no -4 "
6
+ attr_reader :hostname
7
+
8
+ def initialize(hostname)
9
+ @hostname = hostname
10
+ @lock_file = LockFile.new(@hostname, $runner.local_hostname, $runner.identifier)
16
11
  end
17
- end
18
-
19
- def unlock
20
- @lock_file.release
21
- end
22
-
23
- def run(task)
24
- Runner.log("Running '#{task}' on #{@hostname}", :white)
25
- command = %Q{ssh #{SSH_CONFIG} #{ssh_host_and_user} 'cd #{$runner.remote_path}; #{task}' 2>&1}
26
- system(command)
27
- $?.exitstatus
28
- end
29
12
 
30
- def copy_codebase
31
- Runner.log("Copying from #{$runner.temp_path} to #{@hostname}:#{$runner.remote_path}", :yellow)
32
- system("ssh #{SSH_CONFIG} #{ssh_host_and_user} 'mkdir -p #{$runner.remote_path}'")
33
- excludes = $runner.exclude.map { |dir| "--exclude '#{dir}'"}
34
- if system(%{rsync --delete --delete-excluded #{excludes.join(" ")} --rsh='ssh #{SSH_CONFIG}' --timeout=60 -a #{$runner.temp_path}/ #{ssh_host_and_user}:#{$runner.remote_path}/})
35
- Runner.log("Finished copying to #{@hostname}", :green)
36
- return true
37
- else
38
- Runner.log("rsync failed on #{@hostname}.", :red)
39
- return false
13
+ def lock
14
+ unless locked?
15
+ @lock_file.get && locked_by_me?
16
+ end
40
17
  end
41
- end
42
18
 
43
- def is_up?
44
- result = `ssh #{SSH_CONFIG} -o ConnectTimeout=2 #{ssh_host_and_user} "echo 'success'" 2>/dev/null`.strip
45
- if result == "success"
46
- Runner.log("#{@hostname} is up", :green)
47
- return true
48
- else
49
- Runner.log("#{@hostname} is down: #{result}", :red)
50
- return false
19
+ def unlock
20
+ @lock_file.release
51
21
  end
52
- end
53
-
54
- def start_ssh_master_connection
55
- system("ssh #{SSH_CONFIG} #{ssh_host_and_user} -M &> /dev/null")
56
- end
57
-
58
- private
59
-
60
- def ssh_host_and_user
61
- "#{$runner.login_as}@#{@hostname}"
62
- end
63
-
64
- def locked?
65
- @lock_file.locked?
66
- end
67
22
 
68
- def locked_by_me?
69
- @lock_file.locked_by_me?
70
- end
23
+ def run(task)
24
+ command = %Q{ssh #{SSH_CONFIG} #{ssh_host_and_user} 'cd #{$runner.remote_path}; #{task}' 2>&1}
25
+ system(command)
26
+ $?.exitstatus
27
+ end
71
28
 
72
- class LockFile
73
- FILE = "/tmp/remote-run-lock"
29
+ def copy_codebase
30
+ system("ssh #{SSH_CONFIG} #{ssh_host_and_user} 'mkdir -p #{$runner.remote_path}'")
31
+ excludes = $runner.exclude.map { |dir| "--exclude '#{dir}'"}
32
+ if system(%{rsync --delete --delete-excluded #{excludes.join(" ")} --rsh='ssh #{SSH_CONFIG}' --timeout=60 -a #{$runner.temp_path}/ #{ssh_host_and_user}:#{$runner.remote_path}/})
33
+ return true
34
+ else
35
+ return false
36
+ end
37
+ end
74
38
 
75
- def initialize(remote_hostname, local_hostname, unique_run_marker)
76
- @filename = FILE
77
- @locker = "#{local_hostname}-#{unique_run_marker}"
78
- @remote_file = RemoteFile.new(remote_hostname)
39
+ def is_up?
40
+ result = `ssh #{SSH_CONFIG} -o ConnectTimeout=2 #{ssh_host_and_user} "echo 'success'" 2>/dev/null`.strip
41
+ if result == "success"
42
+ return true
43
+ else
44
+ return false
45
+ end
79
46
  end
80
47
 
81
- def release
82
- if locked_by_me?
83
- @remote_file.delete(@filename)
48
+ def start_ssh_master_connection
49
+ fork do
50
+ system("ssh #{SSH_CONFIG} #{ssh_host_and_user} -M &> /dev/null")
84
51
  end
85
52
  end
86
53
 
54
+ private
55
+
56
+ def ssh_host_and_user
57
+ "#{$runner.login_as}@#{@hostname}"
58
+ end
59
+
87
60
  def locked?
88
- @remote_file.exist?(@filename)
61
+ @lock_file.locked?
89
62
  end
90
63
 
91
64
  def locked_by_me?
92
- @remote_file.exist?(@filename) && @remote_file.read(@filename).strip == @locker
65
+ @lock_file.locked_by_me?
93
66
  end
94
67
 
95
- def get
96
- @remote_file.write(@filename, @locker)
97
- end
68
+ class LockFile
69
+ FILE = "/tmp/remote-run-lock"
98
70
 
99
- class RemoteFile
100
- def initialize(hostname)
101
- @hostname = hostname
71
+ def initialize(remote_hostname, local_hostname, unique_run_marker)
72
+ @filename = FILE
73
+ @locker = "#{local_hostname}-#{unique_run_marker}"
74
+ @remote_file = RemoteFile.new(remote_hostname)
102
75
  end
103
76
 
104
- def exist?(file_path)
105
- run_and_test("test -f #{file_path}")
77
+ def release
78
+ if locked_by_me?
79
+ @remote_file.delete(@filename)
80
+ end
106
81
  end
107
82
 
108
- def read(file_path)
109
- run("test -e #{file_path} && cat #{file_path}")
83
+ def locked?
84
+ @remote_file.exist?(@filename)
110
85
  end
111
86
 
112
- def write(file_path, text)
113
- run_and_test("test -e #{file_path} || echo #{text} > #{file_path}")
87
+ def locked_by_me?
88
+ @remote_file.exist?(@filename) && @remote_file.read(@filename).strip == @locker
114
89
  end
115
90
 
116
- def delete(file_path)
117
- run_and_test("rm -f #{file_path}")
91
+ def get
92
+ @remote_file.write(@filename, @locker)
118
93
  end
119
94
 
120
- def run(command)
121
- `ssh #{Host::SSH_CONFIG} #{$runner.login_as}@#{@hostname} '#{command};'`.strip
122
- end
95
+ class RemoteFile
96
+ def initialize(hostname)
97
+ @hostname = hostname
98
+ end
99
+
100
+ def exist?(file_path)
101
+ run_and_test("test -f #{file_path}")
102
+ end
103
+
104
+ def read(file_path)
105
+ run("test -e #{file_path} && cat #{file_path}")
106
+ end
107
+
108
+ def write(file_path, text)
109
+ run_and_test("test -e #{file_path} || echo #{text} > #{file_path}")
110
+ end
111
+
112
+ def delete(file_path)
113
+ run_and_test("rm -f #{file_path}")
114
+ end
115
+
116
+ def run(command)
117
+ `ssh #{Host::SSH_CONFIG} #{$runner.login_as}@#{@hostname} '#{command};'`.strip
118
+ end
123
119
 
124
- def run_and_test(command)
125
- system("ssh #{Host::SSH_CONFIG} #{$runner.login_as}@#{@hostname} '#{command}' 2>/dev/null")
120
+ def run_and_test(command)
121
+ system("ssh #{Host::SSH_CONFIG} #{$runner.login_as}@#{@hostname} '#{command}' 2>/dev/null")
122
+ end
126
123
  end
127
124
  end
128
125
  end
@@ -1,233 +1,155 @@
1
- class Runner
2
- attr_accessor :remote_path, :local_path, :login_as, :exclude, :temp_path
3
- attr_reader :local_hostname, :identifier
4
- @@start_time = Time.now
5
- @@stty_config = `stty -g`
6
-
7
- def initialize
8
- @task_manager = TaskManager.new
9
- @host_manager = HostManager.new
10
-
11
- # config options
12
- @local_path = Dir.getwd
13
- @login_as = `whoami`.strip
14
- @remote_path = "/tmp/remote"
15
- @exclude = []
16
- @temp_path = "/tmp/remote"
17
-
18
- # used in the runner
19
- @identifier = `echo $RANDOM`.strip
20
- @local_hostname = `hostname`.strip
21
- @results = []
22
- @children = []
23
- @failed = []
24
- @last_timestamp = Time.now.strftime("%S")[0]
25
-
26
- $runner = self
27
- yield self
28
- end
29
-
30
- def self.run(&block)
31
- @@start_time = Time.now
32
- runner = new(&block)
33
- runner.run
34
- end
35
-
36
- def self.run_time
37
- minutes = ((Time.now - @@start_time) / 60).to_i
38
- seconds = ((Time.now - @@start_time) % 60).to_i
39
- "#{minutes}:#{"%02d" % seconds}"
40
- end
41
-
42
- def self.log(message, color = :yellow)
43
- highline = HighLine.new
44
- system("stty #{@@stty_config} 2>/dev/null")
45
- highline.say(highline.color("[Remote :: #{$runner.identifier} :: #{run_time}] #{message}", color))
46
- end
47
-
48
- def hosts
49
- @host_manager.all
50
- end
1
+ module RemoteRun
2
+ class Runner
3
+ def initialize(configuration)
4
+ @configuration = configuration
5
+ @results = []
6
+ @children = []
7
+ @failed = []
8
+ @stty_config = `stty -g`
9
+ @last_timestamp = Time.now.strftime("%S")[0]
10
+ @hosts = []
51
11
 
52
- def hosts=(hostnames)
53
- hostnames.each do |hostname|
54
- @host_manager.add(hostname)
12
+ @task_manager = @configuration.task_manager
13
+ @host_manager = @configuration.host_manager
14
+ @starting_number_of_tasks = @task_manager.count
55
15
  end
56
- end
57
16
 
58
- def tasks=(shell_commands)
59
- shell_commands.each do |shell_command|
60
- @task_manager.add(shell_command)
17
+ def run
18
+ setup_unlock_on_exit
19
+ start_ssh_master_connections
20
+ sync_working_copy_to_temp_location
21
+ start_tasks
22
+ wait_for_tasks_to_finish
23
+ handle_results
61
24
  end
62
- end
63
-
64
- def run
65
- @host_manager.unlock_on_exit
66
- @host_manager.start_ssh_master_connections
67
- sync_working_copy_to_temp_location
68
- hosts = []
69
-
70
- Runner.log("Starting tasks... #{Time.now}")
71
25
 
72
- @starting_number_of_tasks = @task_manager.count
73
- while @task_manager.has_more_tasks?
74
- hosts = @host_manager.hosts.dup if hosts.empty?
26
+ private
75
27
 
76
- display_log
77
- check_for_finished
78
-
79
- if host = hosts.sample
80
- hosts.delete(host)
81
- if host.lock
82
- task = @task_manager.find_task
83
- @children << fork do
84
- begin
85
- this_host = host.dup
86
- unless this_host.copy_codebase
87
- @task_manager.add(task)
88
- status = 0
89
- end
90
- status = this_host.run(task)
91
- host.unlock
92
- Runner.log("#{host.hostname} failed.", :red) if status != 0
93
- rescue Errno::EPIPE
94
- Runner.log("broken pipe on #{host.hostname}...")
95
- ensure
96
- Process.exit!(status)
97
- end
28
+ def setup_unlock_on_exit
29
+ at_exit do
30
+ @configuration.hosts.each do |host|
31
+ begin
32
+ host.unlock
33
+ rescue Errno::EPIPE
98
34
  end
99
35
  end
100
36
  end
101
37
  end
102
38
 
103
- Runner.log("All tasks started... #{Time.now}")
104
-
105
- while @children.length > 0
106
- display_log
107
- check_for_finished
108
- end
109
-
110
- failed_tasks = @results.select { |result| result != 0 }
111
- status_code = if failed_tasks.length == 0
112
- Runner.log("Task passed.", :green)
113
- Host::PASS
114
- else
115
- Runner.log("#{failed_tasks.length} task(s) failed.", :red)
116
- Host::FAIL
117
- end
118
-
119
- Runner.log("Total Time: #{self.class.run_time} minutes.")
120
- status_code
121
- end
122
-
123
- def check_for_finished
124
- @children.each do |child_pid|
125
- if Process.waitpid(child_pid, Process::WNOHANG)
126
- if $?.exitstatus != 0
127
- @failed << child_pid
128
- end
129
-
130
- @results << $?.exitstatus
131
- @children.delete(child_pid)
39
+ def start_ssh_master_connections
40
+ @configuration.hosts.each do |host|
41
+ host.start_ssh_master_connection
132
42
  end
133
43
  end
134
- sleep(0.5)
135
- end
136
-
137
- private
138
44
 
139
- def sync_working_copy_to_temp_location
140
- Runner.log("Creating temporary copy of #{@local_path} in #{@temp_path}...")
141
- excludes = exclude.map { |dir| "--exclude '#{dir}'"}
142
- system("rsync --delete --delete-excluded #{excludes.join(" ")} -aq #{@local_path}/ #{@temp_path}/")
143
- Runner.log("Done.")
144
- end
145
-
146
- def display_log
147
- now = Time.now.strftime("%S")[0]
148
- unless now == @last_timestamp
149
- display_status("Waiting on #{@task_manager.count} of #{@starting_number_of_tasks} tasks to start.") if @task_manager.count > 0
150
- display_status("Waiting on #{@children.length} of #{@starting_number_of_tasks - @task_manager.count} started tasks to finish. #{@failed.size} failed.") if @children.length > 0
151
- $stdout.print("\n\n")
152
- $stdout.flush
153
- @last_timestamp = now
45
+ def sync_working_copy_to_temp_location
46
+ log("Creating temporary copy of #{@configuration.local_path} in #{@configuration.temp_path}...")
47
+ excludes = @configuration.exclude.map { |dir| "--exclude '#{dir}'"}
48
+ system("rsync --delete --delete-excluded #{excludes.join(" ")} -aq #{@configuration.local_path}/ #{@configuration.temp_path}/")
49
+ log("Done.")
154
50
  end
155
- end
156
51
 
157
- def display_status(message)
158
- Runner.log(message, :yellow)
159
- end
52
+ def start_tasks
53
+ log("Starting tasks... #{Time.now}")
160
54
 
161
- class HostManager
162
- def initialize(&block)
163
- @hosts = []
164
- end
55
+ while @task_manager.has_more_tasks?
56
+ display_log
57
+ check_for_finished
58
+ find_lock_and_start
59
+ end
165
60
 
166
- def all
167
- @hosts
61
+ log("All tasks started... #{Time.now}")
168
62
  end
169
63
 
170
- def add(hostname)
171
- host = Host.new(hostname)
172
- Thread.new do
173
- if host.is_up?
174
- @hosts << host
175
- end
64
+ def wait_for_tasks_to_finish
65
+ while @children.length > 0
66
+ display_log
67
+ check_for_finished
176
68
  end
177
69
  end
178
70
 
179
- def hosts
180
- while @hosts.empty?
181
- Runner.log("Waiting for hosts...")
182
- sleep(0.5)
71
+ def handle_results
72
+ failed_tasks = @results.select { |result| result != 0 }
73
+ status_code = if failed_tasks.length == 0
74
+ log("Task passed.", :green)
75
+ Host::PASS
76
+ else
77
+ log("#{failed_tasks.length} task(s) failed.", :red)
78
+ Host::FAIL
183
79
  end
184
80
 
185
- @hosts
81
+ log("Total Time: #{run_time} minutes.")
82
+ status_code
186
83
  end
187
84
 
188
- def unlock_on_exit
189
- at_exit do
190
- all.each do |host|
191
- begin
192
- host.unlock
193
- rescue Errno::EPIPE
194
- end
195
- end
85
+ def start_task(host)
86
+ task = @task_manager.find_task
87
+ @children << fork do
88
+ start_forked_task(host, task)
196
89
  end
197
90
  end
198
91
 
199
- def start_ssh_master_connections
200
- all.each do |host|
201
- fork do
202
- host.start_ssh_master_connection
92
+ def start_forked_task(host, task)
93
+ begin
94
+ this_host = host.dup
95
+ unless this_host.copy_codebase
96
+ @task_manager.add(task)
97
+ status = 0
203
98
  end
99
+ status = this_host.run(task.command)
100
+ host.unlock
101
+ rescue Errno::EPIPE
102
+ ensure
103
+ Process.exit!(status)
204
104
  end
205
105
  end
206
- end
207
106
 
208
- class TaskManager
209
- def initialize
210
- @tasks = []
107
+ def find_lock_and_start
108
+ @hosts = @host_manager.hosts.dup if @hosts.empty?
109
+ if host = @hosts.sample
110
+ @hosts.delete(host)
111
+ if host.lock
112
+ start_task(host)
113
+ end
114
+ end
211
115
  end
212
116
 
213
- def add(script)
214
- @tasks.push(script)
117
+ def run_time
118
+ minutes = ((Time.now - @configuration.start_time) / 60).to_i
119
+ seconds = ((Time.now - @configuration.start_time) % 60).to_i
120
+ "#{minutes}:#{"%02d" % seconds}"
215
121
  end
216
122
 
217
- def find_task
218
- @tasks.shift
123
+ def log(message, color = :yellow)
124
+ unless @configuration.quiet
125
+ highline = HighLine.new
126
+ system("stty #{@stty_config} 2>/dev/null")
127
+ highline.say(highline.color("[Remote :: #{@configuration.identifier} :: #{run_time}] #{message}", color))
128
+ end
219
129
  end
220
130
 
221
- def all
222
- @tasks
131
+ def check_for_finished
132
+ @children.each do |child_pid|
133
+ if task_is_finished?(child_pid)
134
+ @failed << child_pid unless $?.success?
135
+ @results << $?.exitstatus
136
+ @children.delete(child_pid)
137
+ end
138
+ end
223
139
  end
224
140
 
225
- def count
226
- @tasks.length
141
+ def task_is_finished?(pid)
142
+ Process.waitpid(pid, Process::WNOHANG)
227
143
  end
228
144
 
229
- def has_more_tasks?
230
- @tasks.size > 0
145
+ def display_log
146
+ now = Time.now.strftime("%S")[0]
147
+ unless now == @last_timestamp
148
+ log("Waiting on #{@task_manager.count} of #{@starting_number_of_tasks} tasks to start.") if @task_manager.count > 0
149
+ log("Waiting on #{@children.length} of #{@starting_number_of_tasks - @task_manager.count} started tasks to finish. #{@failed.size} failed.") if @children.length > 0
150
+ $stdout.flush
151
+ @last_timestamp = now
152
+ end
231
153
  end
232
154
  end
233
155
  end
@@ -0,0 +1,10 @@
1
+ module RemoteRun
2
+ class Task
3
+ attr_accessor :command
4
+
5
+ def initialize(command)
6
+ @command = command
7
+ end
8
+ end
9
+ end
10
+
@@ -1,3 +1,3 @@
1
1
  module RemoteRun
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/remote_run.rb CHANGED
@@ -1,3 +1,8 @@
1
+ require File.join(File.dirname(__FILE__), "remote_run", "task")
1
2
  require File.join(File.dirname(__FILE__), "remote_run", "host")
2
3
  require File.join(File.dirname(__FILE__), "remote_run", "runner")
4
+ require File.join(File.dirname(__FILE__), "remote_run", "configuration")
3
5
  require 'highline'
6
+
7
+ module RemoteRun
8
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe RemoteRun::Configuration::HostManager do
4
+ subject { RemoteRun::Configuration::HostManager.new }
5
+
6
+ describe "#add" do
7
+ it "adds the given host to a list of hosts" do
8
+ subject.add(stub(:host, :is_up? => true, :name => "foobar"))
9
+ subject.hosts.size.should == 1
10
+ subject.hosts.first.name.should == "foobar"
11
+ end
12
+ end
13
+
14
+ describe "#hosts" do
15
+ it "returns all hosts in the list" do
16
+ host = stub(:host, :is_up? => true, :name => "foobar")
17
+ subject.add(host)
18
+ subject.hosts.should == [host]
19
+ end
20
+ end
21
+
22
+ describe "#start_ssh_master_connections" do
23
+ before do
24
+ @host = stub(:host, :is_up? => true, :name => "foobar")
25
+ subject.add(@host)
26
+ end
27
+
28
+ it "asks each host to start their ssh master connection" do
29
+ @host.should_receive(:start_ssh_master_connection)
30
+ subject.start_ssh_master_connections
31
+ end
32
+ end
33
+ end
34
+
35
+ describe RemoteRun::Configuration::TaskManager do
36
+ subject { RemoteRun::Configuration::TaskManager.new }
37
+ describe "#add" do
38
+ it "takes a string and puts it on a list of tasks" do
39
+ task = RemoteRun::Task.new("date")
40
+ subject.add(task)
41
+ subject.tasks.should include(task)
42
+ end
43
+ end
44
+
45
+ describe "#find_task" do
46
+ before do
47
+ @task = RemoteRun::Task.new("date")
48
+ subject.add(@task)
49
+ end
50
+
51
+ it "finds a task from the list, returns it and removes it" do
52
+ subject.tasks.should == [@task]
53
+ subject.find_task.should == @task
54
+ subject.tasks.should == []
55
+ end
56
+ end
57
+
58
+ describe "#tasks" do
59
+ it "returns all of the tasks stored in the manager" do
60
+ task = RemoteRun::Task.new("foo")
61
+ task2 = RemoteRun::Task.new("bar")
62
+ subject.add(task)
63
+ subject.add(task2)
64
+ subject.tasks.should == [task, task2]
65
+ end
66
+ end
67
+
68
+ describe "#count" do
69
+ it "returns the number of tasks stored" do
70
+ task = RemoteRun::Task.new("foo")
71
+ task2 = RemoteRun::Task.new("bar")
72
+ subject.add(task)
73
+ subject.add(task2)
74
+ subject.count.should == 2
75
+ end
76
+ end
77
+
78
+ describe "#has_more_tasks?" do
79
+ it "returns true when there are tasks in the list" do
80
+ task = RemoteRun::Task.new("foo")
81
+ task2 = RemoteRun::Task.new("bar")
82
+ subject.add(task)
83
+ subject.add(task2)
84
+
85
+ subject.has_more_tasks?.should be_true
86
+ subject.find_task
87
+ subject.has_more_tasks?.should be_true
88
+ subject.find_task
89
+ subject.has_more_tasks?.should be_false
90
+ end
91
+ end
92
+ end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Host do
3
+ describe RemoteRun::Host do
4
4
  context "when locking" do
5
- let(:host) { Host.new("localhost") }
5
+ let(:host) { RemoteRun::Host.new("localhost") }
6
6
 
7
7
  it "can be locked" do
8
8
  host.lock.should be_true
@@ -21,9 +21,9 @@ describe Host do
21
21
 
22
22
  context "when locked by someone else" do
23
23
  before { lock_file.get }
24
- let(:host) { Host.new("localhost") }
24
+ let(:host) { RemoteRun::Host.new("localhost") }
25
25
  let(:lock_file) {
26
- lock_file = Host::LockFile.new("localhost", "myfakelocalhost", "999")
26
+ lock_file = RemoteRun::Host::LockFile.new("localhost", "myfakelocalhost", "999")
27
27
  }
28
28
 
29
29
  it "cannot be unlocked by me" do
@@ -33,7 +33,7 @@ describe Host do
33
33
 
34
34
  context "when locked by me" do
35
35
  before { host.lock }
36
- let(:host) { Host.new("localhost") }
36
+ let(:host) { RemoteRun::Host.new("localhost") }
37
37
 
38
38
  it "cannot be locked" do
39
39
  host.lock.should be_false
@@ -52,7 +52,7 @@ describe Host do
52
52
 
53
53
  context "when checking to see if a host is up" do
54
54
  context "when using an authorized host" do
55
- let(:host) { Host.new("localhost") }
55
+ let(:host) { RemoteRun::Host.new("localhost") }
56
56
 
57
57
  it "returns true" do
58
58
  host.is_up?.should be_true
@@ -60,7 +60,7 @@ describe Host do
60
60
  end
61
61
 
62
62
  context "when using an unauthorized host" do
63
- let(:host) { Host.new("foozmcbarry") }
63
+ let(:host) { RemoteRun::Host.new("foozmcbarry") }
64
64
 
65
65
  it "returns false" do
66
66
  host.is_up?.should be_false
@@ -74,7 +74,7 @@ describe Host do
74
74
  host.lock
75
75
  end
76
76
 
77
- let(:host) { Host.new("localhost") }
77
+ let(:host) { RemoteRun::Host.new("localhost") }
78
78
 
79
79
  context "when executing a shell command with a zero status code" do
80
80
  it "returns zero" do
@@ -95,7 +95,7 @@ describe Host do
95
95
  host.lock
96
96
  end
97
97
 
98
- let(:host) { Host.new("localhost") }
98
+ let(:host) { RemoteRun::Host.new("localhost") }
99
99
 
100
100
  it "copies the codebase to a remote directory" do
101
101
  $runner.remote_path = "/tmp/testing-remote-run"
File without changes
data/spec/spec_helper.rb CHANGED
@@ -3,13 +3,14 @@ require 'bundler/setup'
3
3
  require 'rspec'
4
4
  require Dir.pwd + '/lib/remote_run'
5
5
 
6
- Runner.new do |config|
6
+ RemoteRun::Configuration.new do |config|
7
7
  config.tasks = []
8
8
  config.hosts = []
9
+ config.quiet = true
9
10
  end
10
11
 
11
12
  RSpec.configure do |config|
12
13
  config.after(:each) do
13
- system("rm -f #{Host::LockFile::FILE}")
14
+ system("rm -f #{RemoteRun::Host::LockFile::FILE}")
14
15
  end
15
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remote_run
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.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-08-11 00:00:00.000000000Z
12
+ date: 2011-09-13 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: highline
16
- requirement: &2151825780 !ruby/object:Gem::Requirement
16
+ requirement: &2151951040 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2151825780
24
+ version_requirements: *2151951040
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2151824680 !ruby/object:Gem::Requirement
27
+ requirement: &2151943360 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2151824680
35
+ version_requirements: *2151943360
36
36
  description: Can be used as a parallel unit test runner
37
37
  email:
38
38
  - casecommons-dev@googlegroups.com
@@ -48,11 +48,15 @@ files:
48
48
  - Readme.md
49
49
  - examples/demo-remote-run
50
50
  - lib/remote_run.rb
51
+ - lib/remote_run/configuration.rb
51
52
  - lib/remote_run/host.rb
52
53
  - lib/remote_run/runner.rb
54
+ - lib/remote_run/task.rb
53
55
  - lib/remote_run/version.rb
54
56
  - remote_run.gemspec
57
+ - spec/remote_run/configuration_spec.rb
55
58
  - spec/remote_run/host_spec.rb
59
+ - spec/remote_run/runner_spec.rb
56
60
  - spec/spec_helper.rb
57
61
  homepage: https://github.com/Casecommons/remote_run
58
62
  licenses: []
@@ -68,7 +72,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
72
  version: '0'
69
73
  segments:
70
74
  - 0
71
- hash: -4543623679604844651
75
+ hash: 3128109979642869878
72
76
  required_rubygems_version: !ruby/object:Gem::Requirement
73
77
  none: false
74
78
  requirements:
@@ -77,13 +81,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
81
  version: '0'
78
82
  segments:
79
83
  - 0
80
- hash: -4543623679604844651
84
+ hash: 3128109979642869878
81
85
  requirements: []
82
86
  rubyforge_project: remote_run
83
- rubygems_version: 1.8.6
87
+ rubygems_version: 1.8.10
84
88
  signing_key:
85
89
  specification_version: 3
86
90
  summary: Run N shell scripts on a pool of remote hosts
87
91
  test_files:
92
+ - spec/remote_run/configuration_spec.rb
88
93
  - spec/remote_run/host_spec.rb
94
+ - spec/remote_run/runner_spec.rb
89
95
  - spec/spec_helper.rb