auser-poolparty 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG +3 -2
  2. data/Rakefile +61 -4
  3. data/bin/instance +3 -1
  4. data/bin/pool +6 -2
  5. data/config/sample-config.yml +4 -4
  6. data/lib/core/object.rb +3 -0
  7. data/lib/helpers/plugin_spec_helper.rb +59 -0
  8. data/lib/modules/ec2_wrapper.rb +3 -1
  9. data/lib/modules/file_writer.rb +1 -1
  10. data/lib/modules/vlad_override.rb +83 -83
  11. data/lib/poolparty.rb +31 -13
  12. data/lib/poolparty/application.rb +22 -15
  13. data/lib/poolparty/init.rb +1 -1
  14. data/lib/poolparty/master.rb +41 -28
  15. data/lib/poolparty/monitors.rb +1 -3
  16. data/lib/poolparty/monitors/cpu.rb +7 -3
  17. data/lib/poolparty/monitors/memory.rb +14 -7
  18. data/lib/poolparty/monitors/web.rb +11 -5
  19. data/lib/poolparty/provider/packages/essential.rb +1 -1
  20. data/lib/poolparty/provider/packages/heartbeat.rb +1 -1
  21. data/lib/poolparty/provider/packages/ruby.rb +1 -10
  22. data/lib/poolparty/remote_instance.rb +5 -18
  23. data/lib/poolparty/remoter.rb +55 -4
  24. data/lib/poolparty/scheduler.rb +15 -25
  25. data/lib/poolparty/thread_pool.rb +94 -0
  26. data/poolparty.gemspec +9 -6
  27. data/spec/application_spec.rb +32 -13
  28. data/spec/callback_spec.rb +20 -1
  29. data/spec/file_writer_spec.rb +1 -0
  30. data/spec/kernel_spec.rb +13 -0
  31. data/spec/master_spec.rb +50 -20
  32. data/spec/monitors/cpu_monitor_spec.rb +1 -1
  33. data/spec/plugin_manager_spec.rb +9 -17
  34. data/spec/plugin_spec.rb +34 -34
  35. data/spec/poolparty_spec.rb +41 -1
  36. data/spec/remote_instance_spec.rb +5 -18
  37. data/spec/scheduler_spec.rb +7 -6
  38. data/spec/spec_helper.rb +8 -18
  39. metadata +19 -6
  40. data/lib/poolparty/tasks/package.rake +0 -53
@@ -1,6 +1,7 @@
1
1
  =begin rdoc
2
2
  Handle the remoting aspects of the remote_instances
3
3
  =end
4
+ require 'open4'
4
5
  module PoolParty
5
6
  module Remoter
6
7
  module ClassMethods
@@ -66,10 +67,8 @@ module PoolParty
66
67
  run_array_of_tasks arr
67
68
  end
68
69
 
69
- def run_now command
70
- unless command.empty?
71
- Kernel.system "#{self.class.ssh_string} #{self.ip} #{command.runnable}"
72
- end
70
+ def run_now command
71
+ run command unless command.empty?
73
72
  end
74
73
 
75
74
  def ssh_tasks;@ssh_tasks ||= [];end
@@ -107,6 +106,58 @@ module PoolParty
107
106
  def set_hosts(c=nil)
108
107
  end
109
108
 
109
+ # Nearly Directly from vlad
110
+ def run command, on=self
111
+ cmd = [self.class.ssh_string, on.ip].compact
112
+ result = []
113
+
114
+ commander = cmd.join(" ") << " \"#{command.runnable}\""
115
+
116
+ pid, inn, out, err = Open4::popen4(commander)
117
+
118
+ inn.sync = true
119
+ streams = [out, err]
120
+ out_stream = {
121
+ out => $stdout,
122
+ err => $stderr,
123
+ }
124
+
125
+ # Handle process termination ourselves
126
+ status = nil
127
+ Thread.start do
128
+ status = Process.waitpid2(pid).last
129
+ end
130
+
131
+ until streams.empty? do
132
+ # don't busy loop
133
+ selected, = select streams, nil, nil, 0.1
134
+
135
+ next if selected.nil? or selected.empty?
136
+
137
+ selected.each do |stream|
138
+ if stream.eof? then
139
+ streams.delete stream if status # we've quit, so no more writing
140
+ next
141
+ end
142
+
143
+ data = stream.readpartial(1024)
144
+ out_stream[stream].write data
145
+
146
+ if stream == err and data =~ /^Password:/ then
147
+ inn.puts sudo_password
148
+ data << "\n"
149
+ $stderr.write "\n"
150
+ end
151
+
152
+ result << data
153
+ end
154
+ end
155
+
156
+ PoolParty.message "execution failed with status #{status.exitstatus}: #{cmd.join ' '}" unless status.success?
157
+
158
+ result.join
159
+ end
160
+
110
161
  end
111
162
 
112
163
  def self.included(receiver)
@@ -9,28 +9,21 @@ module PoolParty
9
9
  end
10
10
  # Synchronize the running threaded tasks
11
11
  def run
12
- unless tasks.empty?
13
- self.class.synchronize do
14
- tasks.reject!{|a|
15
- begin
16
- a.run
17
- a.join
18
- rescue Exception => e
19
- puts "There was an error in the task: #{e} #{e.backtrace.join("\n")}"
20
- end
21
- true
22
- }
12
+ unless tasks.empty? && !running?
13
+ running = true
14
+ pool = ThreadPool.new(10)
15
+ tasks.reject! do |task|
16
+ pool.process {task.call}
23
17
  end
18
+ pool.join() # When all the tasks are done
19
+ running = false
24
20
  end
25
21
  end
22
+ def running?;@running == true;end
23
+ def running;@running ||= false;end
26
24
  # Add a task in a new thread
27
25
  def <<(a, *args)
28
- thread = Thread.new(a) do |task|
29
- Thread.stop rescue ""
30
- Thread.current[:callee] = task
31
- a.call args
32
- end
33
- tasks << thread
26
+ tasks << a
34
27
  end
35
28
  alias_method :push, :<<
36
29
  # In the ThreadSafeInstance
@@ -45,7 +38,7 @@ module PoolParty
45
38
  end
46
39
  # Add a task to the new threaded block
47
40
  def add_task(&blk)
48
- _tasker.push proc{blk.call}
41
+ _tasker.push blk
49
42
  end
50
43
  # Grab the polling_time
51
44
  def interval
@@ -74,16 +67,17 @@ module PoolParty
74
67
  end
75
68
  # Run the loop and wait the amount of time between running the tasks
76
69
  # You can send it daemonize => true and it will daemonize
77
- def run_thread_loop(opts={}, &block)
70
+ def run_thread_loop(opts={}, &blk)
78
71
  block = lambda {
79
72
  loop do
80
73
  begin
81
74
  yield if block_given?
75
+ add_task { Signal.trap("INT") { exit } }
82
76
  run_thread_list
77
+ PoolParty.message "Waiting: #{interval}"
83
78
  wait interval
84
- reset!
85
79
  rescue Exception => e
86
- puts "There was an error in the run_thread_loop: #{e}"
80
+ Process.kill("INT", Process.pid)
87
81
  end
88
82
  end
89
83
  }
@@ -94,10 +88,6 @@ module PoolParty
94
88
  def run_thread_list
95
89
  run_threads
96
90
  end
97
- # Reset
98
- def reset!
99
- cached_variables.each {|cached| cached = nil }
100
- end
101
91
 
102
92
  end
103
93
  end
@@ -0,0 +1,94 @@
1
+ module PoolParty
2
+ class ThreadPool
3
+ class Worker
4
+ def initialize
5
+ @mutex = Mutex.new
6
+ @thread = Thread.new do
7
+ while true
8
+ sleep 0.001
9
+ block = get_block
10
+ if block
11
+ block.call
12
+ reset_block
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ def get_block
19
+ @mutex.synchronize {@block}
20
+ end
21
+
22
+ def set_block(block)
23
+ @mutex.synchronize do
24
+ raise RuntimeError, "Thread already busy." if @block
25
+ @block = block
26
+ end
27
+ end
28
+
29
+ def reset_block
30
+ @mutex.synchronize {@block = nil}
31
+ end
32
+
33
+ def busy?
34
+ @mutex.synchronize {!@block.nil?}
35
+ end
36
+ end
37
+
38
+ attr_accessor :max_size
39
+ attr_reader :workers
40
+
41
+ def initialize(max_size = 10)
42
+ @max_size = max_size
43
+ @workers = []
44
+ @mutex = Mutex.new
45
+ end
46
+
47
+ def size
48
+ @mutex.synchronize {@workers.size}
49
+ end
50
+
51
+ def busy?
52
+ @mutex.synchronize {@workers.any? {|w| w.busy?}}
53
+ end
54
+
55
+ def join
56
+ sleep 0.01 while busy?
57
+ end
58
+
59
+ def process(&block)
60
+ while true
61
+ @mutex.synchronize do
62
+ worker = find_available_worker
63
+ if worker
64
+ return worker.set_block(block)
65
+ end
66
+ end
67
+ sleep 0.01
68
+ end
69
+ end
70
+
71
+ def find_available_worker
72
+ free_worker || create_worker
73
+ end
74
+
75
+ def wait_for_worker
76
+ while true
77
+ worker = find_available_worker
78
+ return worker if worker
79
+ sleep 0.01
80
+ end
81
+ end
82
+
83
+ def free_worker
84
+ @workers.each {|w| return w unless w.busy?}; nil
85
+ end
86
+
87
+ def create_worker
88
+ return nil if @workers.size >= @max_size
89
+ worker = Worker.new
90
+ @workers << worker
91
+ worker
92
+ end
93
+ end
94
+ end
@@ -1,21 +1,21 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{poolparty}
3
- s.version = "0.0.9"
3
+ s.version = "0.1.0"
4
4
 
5
5
  s.required_rubygems_version = Gem::Requirement.new("= 1.2") if s.respond_to? :required_rubygems_version=
6
6
  s.authors = ["Ari Lerner"]
7
7
  s.cert_chain = nil
8
- s.date = %q{2008-06-28}
8
+ s.date = %q{2008-07-02}
9
9
  s.description = %q{Run your entire application off EC2, managed and auto-scaling}
10
10
  s.email = %q{ari.lerner@citrusbyte.com}
11
11
  s.executables = ["instance", "pool", "poolnotify"]
12
- s.extra_rdoc_files = ["CHANGELOG", "README.txt", "bin", "bin/instance", "bin/pool", "bin/poolnotify", "lib", "lib/core", "lib/core/array.rb", "lib/core/exception.rb", "lib/core/float.rb", "lib/core/hash.rb", "lib/core/kernel.rb", "lib/core/module.rb", "lib/core/object.rb", "lib/core/proc.rb", "lib/core/string.rb", "lib/core/time.rb", "lib/modules", "lib/modules/callback.rb", "lib/modules/ec2_wrapper.rb", "lib/modules/file_writer.rb", "lib/modules/safe_instance.rb", "lib/modules/sprinkle_overrides.rb", "lib/modules/vlad_override.rb", "lib/poolparty", "lib/poolparty.rb", "lib/poolparty/application.rb", "lib/poolparty/init.rb", "lib/poolparty/master.rb", "lib/poolparty/monitors", "lib/poolparty/monitors.rb", "lib/poolparty/monitors/cpu.rb", "lib/poolparty/monitors/memory.rb", "lib/poolparty/monitors/web.rb", "lib/poolparty/optioner.rb", "lib/poolparty/plugin.rb", "lib/poolparty/plugin_manager.rb", "lib/poolparty/provider", "lib/poolparty/provider.rb", "lib/poolparty/provider/packages", "lib/poolparty/provider/packages/essential.rb", "lib/poolparty/provider/packages/git.rb", "lib/poolparty/provider/packages/haproxy.rb", "lib/poolparty/provider/packages/heartbeat.rb", "lib/poolparty/provider/packages/monit.rb", "lib/poolparty/provider/packages/rsync.rb", "lib/poolparty/provider/packages/ruby.rb", "lib/poolparty/provider/packages/s3fuse.rb", "lib/poolparty/provider/provider.rb", "lib/poolparty/remote_instance.rb", "lib/poolparty/remoter.rb", "lib/poolparty/remoting.rb", "lib/poolparty/scheduler.rb", "lib/poolparty/tasks", "lib/poolparty/tasks.rb", "lib/poolparty/tasks/cloud.rake", "lib/poolparty/tasks/development.rake", "lib/poolparty/tasks/ec2.rake", "lib/poolparty/tasks/instance.rake", "lib/poolparty/tasks/package.rake", "lib/poolparty/tasks/plugins.rake", "lib/poolparty/tasks/server.rake", "lib/s3", "lib/s3/s3_object_store_folders.rb"]
13
- s.files = ["CHANGELOG", "README.txt", "Rakefile", "assets", "assets/clouds.png", "bin", "bin/instance", "bin/pool", "bin/poolnotify", "config", "config/cloud_master_takeover", "config/create_proxy_ami.sh", "config/haproxy.conf", "config/heartbeat.conf", "config/heartbeat_authkeys.conf", "config/installers", "config/installers/ubuntu_install.sh", "config/monit", "config/monit.conf", "config/monit/haproxy.monit.conf", "config/monit/nginx.monit.conf", "config/nginx.conf", "config/reconfigure_instances_script.sh", "config/sample-config.yml", "config/scp_instances_script.sh", "lib", "lib/core", "lib/core/array.rb", "lib/core/exception.rb", "lib/core/float.rb", "lib/core/hash.rb", "lib/core/kernel.rb", "lib/core/module.rb", "lib/core/object.rb", "lib/core/proc.rb", "lib/core/string.rb", "lib/core/time.rb", "lib/modules", "lib/modules/callback.rb", "lib/modules/ec2_wrapper.rb", "lib/modules/file_writer.rb", "lib/modules/safe_instance.rb", "lib/modules/sprinkle_overrides.rb", "lib/modules/vlad_override.rb", "lib/poolparty", "lib/poolparty.rb", "lib/poolparty/application.rb", "lib/poolparty/init.rb", "lib/poolparty/master.rb", "lib/poolparty/monitors", "lib/poolparty/monitors.rb", "lib/poolparty/monitors/cpu.rb", "lib/poolparty/monitors/memory.rb", "lib/poolparty/monitors/web.rb", "lib/poolparty/optioner.rb", "lib/poolparty/plugin.rb", "lib/poolparty/plugin_manager.rb", "lib/poolparty/provider", "lib/poolparty/provider.rb", "lib/poolparty/provider/packages", "lib/poolparty/provider/packages/essential.rb", "lib/poolparty/provider/packages/git.rb", "lib/poolparty/provider/packages/haproxy.rb", "lib/poolparty/provider/packages/heartbeat.rb", "lib/poolparty/provider/packages/monit.rb", "lib/poolparty/provider/packages/rsync.rb", "lib/poolparty/provider/packages/ruby.rb", "lib/poolparty/provider/packages/s3fuse.rb", "lib/poolparty/provider/provider.rb", "lib/poolparty/remote_instance.rb", "lib/poolparty/remoter.rb", "lib/poolparty/remoting.rb", "lib/poolparty/scheduler.rb", "lib/poolparty/tasks", "lib/poolparty/tasks.rb", "lib/poolparty/tasks/cloud.rake", "lib/poolparty/tasks/development.rake", "lib/poolparty/tasks/ec2.rake", "lib/poolparty/tasks/instance.rake", "lib/poolparty/tasks/package.rake", "lib/poolparty/tasks/plugins.rake", "lib/poolparty/tasks/server.rake", "lib/s3", "lib/s3/s3_object_store_folders.rb", "spec", "spec/application_spec.rb", "spec/callback_spec.rb", "spec/core_spec.rb", "spec/ec2_wrapper_spec.rb", "spec/file_writer_spec.rb", "spec/files", "spec/files/describe_response", "spec/files/multi_describe_response", "spec/files/remote_desc_response", "spec/helpers", "spec/helpers/ec2_mock.rb", "spec/kernel_spec.rb", "spec/master_spec.rb", "spec/monitors", "spec/monitors/cpu_monitor_spec.rb", "spec/monitors/memory_spec.rb", "spec/monitors/misc_monitor_spec.rb", "spec/monitors/web_spec.rb", "spec/optioner_spec.rb", "spec/plugin_manager_spec.rb", "spec/plugin_spec.rb", "spec/pool_binary_spec.rb", "spec/poolparty_spec.rb", "spec/provider_spec.rb", "spec/remote_instance_spec.rb", "spec/remoter_spec.rb", "spec/remoting_spec.rb", "spec/scheduler_spec.rb", "spec/spec_helper.rb", "spec/string_spec.rb", "poolparty.gemspec"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "README.txt", "bin", "bin/instance", "bin/pool", "bin/poolnotify", "lib", "lib/core", "lib/core/array.rb", "lib/core/exception.rb", "lib/core/float.rb", "lib/core/hash.rb", "lib/core/kernel.rb", "lib/core/module.rb", "lib/core/object.rb", "lib/core/proc.rb", "lib/core/string.rb", "lib/core/time.rb", "lib/helpers", "lib/helpers/plugin_spec_helper.rb", "lib/modules", "lib/modules/callback.rb", "lib/modules/ec2_wrapper.rb", "lib/modules/file_writer.rb", "lib/modules/safe_instance.rb", "lib/modules/sprinkle_overrides.rb", "lib/modules/vlad_override.rb", "lib/poolparty", "lib/poolparty.rb", "lib/poolparty/application.rb", "lib/poolparty/init.rb", "lib/poolparty/master.rb", "lib/poolparty/monitors", "lib/poolparty/monitors.rb", "lib/poolparty/monitors/cpu.rb", "lib/poolparty/monitors/memory.rb", "lib/poolparty/monitors/web.rb", "lib/poolparty/optioner.rb", "lib/poolparty/plugin.rb", "lib/poolparty/plugin_manager.rb", "lib/poolparty/provider", "lib/poolparty/provider.rb", "lib/poolparty/provider/packages", "lib/poolparty/provider/packages/essential.rb", "lib/poolparty/provider/packages/git.rb", "lib/poolparty/provider/packages/haproxy.rb", "lib/poolparty/provider/packages/heartbeat.rb", "lib/poolparty/provider/packages/monit.rb", "lib/poolparty/provider/packages/rsync.rb", "lib/poolparty/provider/packages/ruby.rb", "lib/poolparty/provider/packages/s3fuse.rb", "lib/poolparty/provider/provider.rb", "lib/poolparty/remote_instance.rb", "lib/poolparty/remoter.rb", "lib/poolparty/remoting.rb", "lib/poolparty/scheduler.rb", "lib/poolparty/tasks", "lib/poolparty/tasks.rb", "lib/poolparty/tasks/cloud.rake", "lib/poolparty/tasks/development.rake", "lib/poolparty/tasks/ec2.rake", "lib/poolparty/tasks/instance.rake", "lib/poolparty/tasks/plugins.rake", "lib/poolparty/tasks/server.rake", "lib/poolparty/thread_pool.rb", "lib/s3", "lib/s3/s3_object_store_folders.rb"]
13
+ s.files = ["CHANGELOG", "README.txt", "Rakefile", "assets", "assets/clouds.png", "bin", "bin/instance", "bin/pool", "bin/poolnotify", "config", "config/cloud_master_takeover", "config/create_proxy_ami.sh", "config/haproxy.conf", "config/heartbeat.conf", "config/heartbeat_authkeys.conf", "config/installers", "config/installers/ubuntu_install.sh", "config/monit", "config/monit.conf", "config/monit/haproxy.monit.conf", "config/monit/nginx.monit.conf", "config/nginx.conf", "config/reconfigure_instances_script.sh", "config/sample-config.yml", "config/scp_instances_script.sh", "lib", "lib/core", "lib/core/array.rb", "lib/core/exception.rb", "lib/core/float.rb", "lib/core/hash.rb", "lib/core/kernel.rb", "lib/core/module.rb", "lib/core/object.rb", "lib/core/proc.rb", "lib/core/string.rb", "lib/core/time.rb", "lib/helpers", "lib/helpers/plugin_spec_helper.rb", "lib/modules", "lib/modules/callback.rb", "lib/modules/ec2_wrapper.rb", "lib/modules/file_writer.rb", "lib/modules/safe_instance.rb", "lib/modules/sprinkle_overrides.rb", "lib/modules/vlad_override.rb", "lib/poolparty", "lib/poolparty.rb", "lib/poolparty/application.rb", "lib/poolparty/init.rb", "lib/poolparty/master.rb", "lib/poolparty/monitors", "lib/poolparty/monitors.rb", "lib/poolparty/monitors/cpu.rb", "lib/poolparty/monitors/memory.rb", "lib/poolparty/monitors/web.rb", "lib/poolparty/optioner.rb", "lib/poolparty/plugin.rb", "lib/poolparty/plugin_manager.rb", "lib/poolparty/provider", "lib/poolparty/provider.rb", "lib/poolparty/provider/packages", "lib/poolparty/provider/packages/essential.rb", "lib/poolparty/provider/packages/git.rb", "lib/poolparty/provider/packages/haproxy.rb", "lib/poolparty/provider/packages/heartbeat.rb", "lib/poolparty/provider/packages/monit.rb", "lib/poolparty/provider/packages/rsync.rb", "lib/poolparty/provider/packages/ruby.rb", "lib/poolparty/provider/packages/s3fuse.rb", "lib/poolparty/provider/provider.rb", "lib/poolparty/remote_instance.rb", "lib/poolparty/remoter.rb", "lib/poolparty/remoting.rb", "lib/poolparty/scheduler.rb", "lib/poolparty/tasks", "lib/poolparty/tasks.rb", "lib/poolparty/tasks/cloud.rake", "lib/poolparty/tasks/development.rake", "lib/poolparty/tasks/ec2.rake", "lib/poolparty/tasks/instance.rake", "lib/poolparty/tasks/plugins.rake", "lib/poolparty/tasks/server.rake", "lib/poolparty/thread_pool.rb", "lib/s3", "lib/s3/s3_object_store_folders.rb", "spec", "spec/application_spec.rb", "spec/callback_spec.rb", "spec/core_spec.rb", "spec/ec2_wrapper_spec.rb", "spec/file_writer_spec.rb", "spec/files", "spec/files/describe_response", "spec/files/multi_describe_response", "spec/files/remote_desc_response", "spec/helpers", "spec/helpers/ec2_mock.rb", "spec/kernel_spec.rb", "spec/master_spec.rb", "spec/monitors", "spec/monitors/cpu_monitor_spec.rb", "spec/monitors/memory_spec.rb", "spec/monitors/misc_monitor_spec.rb", "spec/monitors/web_spec.rb", "spec/optioner_spec.rb", "spec/plugin_manager_spec.rb", "spec/plugin_spec.rb", "spec/pool_binary_spec.rb", "spec/poolparty_spec.rb", "spec/provider_spec.rb", "spec/remote_instance_spec.rb", "spec/remoter_spec.rb", "spec/remoting_spec.rb", "spec/scheduler_spec.rb", "spec/spec_helper.rb", "spec/string_spec.rb", "poolparty.gemspec"]
14
14
  s.has_rdoc = true
15
- s.homepage = %q{http://blog.citrusbyte.com}
15
+ s.homepage = %q{http://poolpartyrb.com}
16
16
  s.post_install_message = %q{
17
17
 
18
- Get ready to jump in the pool, you just installed PoolParty! (Updated at 05:15PM, 06/28/08)
18
+ Get ready to jump in the pool, you just installed PoolParty! (Updated at 02:12PM, 07/02/08)
19
19
 
20
20
  Please check out the documentation for any questions or check out the google groups at
21
21
  http://groups.google.com/group/poolpartyrb
@@ -45,6 +45,7 @@ Gem::Specification.new do |s|
45
45
  s.add_runtime_dependency(%q<git>, [">= 0"])
46
46
  s.add_runtime_dependency(%q<crafterm-sprinkle>, [">= 0"])
47
47
  s.add_runtime_dependency(%q<SystemTimer>, [">= 0"])
48
+ s.add_development_dependency(%q<echoe>, [">= 0"])
48
49
  else
49
50
  s.add_dependency(%q<aws-s3>, [">= 0"])
50
51
  s.add_dependency(%q<amazon-ec2>, [">= 0"])
@@ -52,6 +53,7 @@ Gem::Specification.new do |s|
52
53
  s.add_dependency(%q<git>, [">= 0"])
53
54
  s.add_dependency(%q<crafterm-sprinkle>, [">= 0"])
54
55
  s.add_dependency(%q<SystemTimer>, [">= 0"])
56
+ s.add_dependency(%q<echoe>, [">= 0"])
55
57
  end
56
58
  else
57
59
  s.add_dependency(%q<aws-s3>, [">= 0"])
@@ -60,5 +62,6 @@ Gem::Specification.new do |s|
60
62
  s.add_dependency(%q<git>, [">= 0"])
61
63
  s.add_dependency(%q<crafterm-sprinkle>, [">= 0"])
62
64
  s.add_dependency(%q<SystemTimer>, [">= 0"])
65
+ s.add_dependency(%q<echoe>, [">= 0"])
63
66
  end
64
67
  end
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/spec_helper'
3
3
  describe "Application" do
4
4
  before(:each) do
5
5
  stub_option_load
6
+ Application.reset!
6
7
  end
7
8
  it "should be able to send options in the Application.options" do
8
9
  options({:optparse => {:banner => "hi"}})
@@ -39,29 +40,47 @@ describe "Application" do
39
40
  it "should show the version as a string" do
40
41
  Application.version.class.should == String
41
42
  end
42
- it "should be able to start instances with the the key access information on the user-data" do
43
- Application.launching_user_data.should =~ /:access_key/
44
- Application.launching_user_data.should =~ /:secret_access_key/
45
- end
46
- it "should be able to pull out the access_key from the user data" do
47
- Application.local_user_data[:access_key].should == 3.14159
48
- end
49
- it "should overwrite the default_options when passing in to the instance data" do
50
- Application.stub!(:default_options).and_return({:access_key => 42})
51
- Application.options.access_key.should == 3.14159
43
+ describe "User data" do
44
+ before(:each) do
45
+ @str = ":access_key: 3.14159\n:secret_access_key: pi"
46
+ Application.options = nil
47
+ Application.stub!(:open).with("http://169.254.169.254/latest/user-data").and_return(@str)
48
+ @str.stub!(:read).and_return ":access_key: 3.14159\n:secret_access_key: pi"
49
+ Application.default_options.stub!(:merge!).with({})
50
+ Application.default_options.stub!(:merge!).with({:access_key => 3.14159, :secret_access_key => "pi"})
51
+ end
52
+ it "should try to load the user data into a yaml hash" do
53
+ YAML.should_receive(:load).with(":access_key: 3.14159\n:secret_access_key: pi")
54
+ Application.local_user_data
55
+ end
56
+ it "should be able to start instances with the the key access information on the user-data" do
57
+ Application.launching_user_data.should =~ /:access_key/
58
+ Application.launching_user_data.should =~ /:secret_access_key/
59
+ end
60
+ it "should be able to pull out the access_key from the user data" do
61
+ Application.local_user_data[:access_key].should == 3.14159
62
+ end
63
+ it "should be able tp pull out the secret_access_key from the user-data" do
64
+ Application.local_user_data[:secret_access_key].should == "pi"
65
+ end
66
+ it "should overwrite the default_options when passing in to the instance data" do
67
+ Application.stub!(:default_options).and_return({:access_key => 42})
68
+ Application.local_user_data
69
+ Application.options.access_key.should == 3.14159
70
+ end
52
71
  end
53
72
  it "should parse and use a config file if it is given for the options" do
54
- YAML.should_receive(:load).and_return({:config_file => "config/sample-config.yml"})
73
+ YAML.should_receive(:load).at_least(1).and_return({:config_file => "config/sample-config.yml"})
55
74
  Application.make_options(:config_file => "config/sample-config.yml")
56
75
  end
57
76
  it "should not read the config file if it is not passed and doesn't exist" do
58
77
  File.stub!(:file?).and_return false
59
- YAML.should_not_receive(:load)
78
+ YAML.should_not_receive(:load).with("config/config.yml")
60
79
  Application.make_options
61
80
  end
62
81
  it "should not read the config file if it is passed and doesn't exist" do
63
82
  File.stub!(:file?).and_return false
64
- YAML.should_not_receive(:load)
83
+ YAML.should_not_receive(:load).with("config/config.yml")
65
84
  Application.make_options(:config_file => "ted")
66
85
  end
67
86
  end
@@ -68,7 +68,7 @@ describe "Multiple callbacks" do
68
68
  end
69
69
  class OutsideClass
70
70
  def self.hello(caller)
71
- puts "hello"
71
+ "hello"
72
72
  end
73
73
  end
74
74
  class TestOutsideClass
@@ -191,4 +191,23 @@ describe "Variables on the plugin callbacker class" do
191
191
  BindingClass.new.print
192
192
  BindingClass.new.methods.include?("eviloutsideclass").should == true
193
193
  end
194
+ end
195
+ class DoubleClass
196
+ include Callbacks
197
+ before :print, :hello => "OutsideBindingClass"
198
+ after :print, :hello => "OutsideBindingClass"
199
+
200
+ def print
201
+ string
202
+ end
203
+ def string
204
+ @string ||= ""
205
+ end
206
+ end
207
+ describe "Chaining" do
208
+ it "should be able to call both a before and an after spec" do
209
+ @d = DoubleClass.new
210
+ @d.print
211
+ @d.string.should == "hellohello"
212
+ end
194
213
  end
@@ -5,6 +5,7 @@ class TestClass
5
5
  end
6
6
  describe "FileWriter" do
7
7
  before(:each) do
8
+ Application.reset!
8
9
  @instance = RemoteInstance.new
9
10
  @instance.stub!(:name).and_return "node0"
10
11
  @instance.stub!(:ip).and_return "127.0.0.1"
@@ -8,4 +8,17 @@ describe "Kernel extensions" do
8
8
  @host.should_receive(:sleep).once.and_return true
9
9
  @host.wait "10.seconds"
10
10
  end
11
+ end
12
+ describe "Object extensions" do
13
+ before(:each) do
14
+ @klass = Object.new
15
+ @klass.instance_eval <<-EOE
16
+ def hello
17
+ puts "hello"
18
+ end
19
+ EOE
20
+ end
21
+ it "should be able to get a list of the defined methods on the object" do
22
+ @klass.my_methods.should == ["hello"]
23
+ end
11
24
  end
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/helpers/ec2_mock'
2
3
 
3
4
  describe "Master" do
4
5
  before(:each) do
@@ -86,22 +87,25 @@ describe "Master" do
86
87
  it "should be able to get a specific node in the nodes from the master" do
87
88
  @master.get_node(2).instance_id.should == "i-5849bc"
88
89
  end
90
+ it "should be able to get the next node" do
91
+ @master.get_next_node(@instance).instance_id.should == "i-5849bb"
92
+ end
89
93
  it "should be able to build a hosts file" do
90
94
  open(@master.build_hosts_file_for(@instance).path).read.should == "127.0.0.1 node0\n127.0.0.1 localhost.localdomain localhost ubuntu\n127.0.0.2 node1\n127.0.0.3 node2"
91
95
  end
92
96
  it "should be able to build a hosts file for a specific instance" do
93
- open(@master.build_hosts_file_for(@instance).path).read.should =~ "127.0.0.1 node0"
97
+ open(@master.build_hosts_file_for(@instance).path).read.should =~ /127\.0\.0\.1 node0/
94
98
  end
95
99
  it "should be able to build a haproxy file" do
96
- open(@master.build_haproxy_file.path).read.should =~ "server node0 127.0.0.1:#{Application.client_port}"
100
+ open(@master.build_haproxy_file.path).read.should =~ /server node0 127\.0\.0\.1:#{Application.client_port}/
97
101
  end
98
102
  it "should be able to reconfigure the instances (working on two files a piece)" do
99
103
  @master.should_receive(:remote_configure_instances).and_return true
100
104
  @master.stub!(:number_of_unconfigured_nodes).and_return 1
101
105
  @master.reconfigure_cloud_when_necessary
102
106
  end
103
- it "should return the number of unconfigured nodes when asked" do
104
- @master.nodes.each {|node| node.stub!(:stack_installed?).and_return(true) unless node.master? }
107
+ it "should return the number of unconfigured nodes when asked" do
108
+ @master.nodes.each {|node| node.stub!(:stack_installed?).and_return(node.master? ? false : true) }
105
109
  @master.number_of_unconfigured_nodes.should == 1
106
110
  end
107
111
  it "should be able to return the size of the cloud" do
@@ -118,39 +122,50 @@ describe "Master" do
118
122
  describe "sending configuration files" do
119
123
  before(:each) do
120
124
  Master.stub!(:new).and_return(@master)
125
+ @master.stub!(:ssh)
126
+ @master.stub!(:scp)
127
+ @master.nodes.each do |node|
128
+ node.stub!(:ssh)
129
+ node.stub!(:scp)
130
+ node.stub!(:stack_installed?).and_return true
131
+ end
121
132
  end
122
133
  it "should be able to build a heartbeat resources file for the specific node" do
123
- open(Master.build_heartbeat_resources_file_for(@master.nodes.first).path).read.should =~ /node0 127/
134
+ open(@master.build_heartbeat_resources_file_for(@master.nodes.first).path).read.should == "node0 127.0.0.1\nnode1 127.0.0.2"
124
135
  end
125
136
  it "should be able to build a heartbeat config file" do
126
- open(Master.build_heartbeat_config_file_for(@master.nodes.first).path).read.should =~ /\nnode node0\nnode node1/
137
+ open(@master.build_heartbeat_config_file_for(@master.nodes.first).path).read.should =~ /\nnode node0\nnode node1/
127
138
  end
128
139
  it "should be able to say if heartbeat is necessary with more than 1 server or not" do
129
140
  Master.requires_heartbeat?.should == true
130
141
  end
131
142
  it "should be able to say that heartbeat is not necessary if there is 1 server" do
132
- @master.stub!(:list_of_nonterminated_instances).and_return([
143
+ @master.stub!(:nodes).and_return([
133
144
  {:instance_id => "i-5849ba", :ip => "127.0.0.1", :status => "running"}
134
145
  ])
135
146
  Master.requires_heartbeat?.should == false
136
147
  end
137
148
  it "should only install the stack on nodes that don't have it marked locally as installed" do
138
- @master.nodes.each {|i| i.should_receive(:stack_installed?).and_return(true)}
149
+ @master.nodes.each {|i| i.should_receive(:stack_installed?).at_least(1).and_return(true)}
139
150
  @master.should_not_receive(:reconfigure_running_instances)
140
151
  @master.reconfigure_cloud_when_necessary
141
152
  end
142
153
  it "should install the stack on all the nodes (because it needs reconfiguring) if there is any node that needs the stack" do
143
- @master.nodes.first.should_receive(:stack_installed?).and_return(false)
154
+ @master.nodes.first.should_receive(:stack_installed?).at_least(1).and_return(false)
144
155
  @master.should_receive(:configure_cloud).once.and_return(true)
145
156
  @master.reconfigure_cloud_when_necessary
146
157
  end
147
158
  describe "rsync'ing the files to the instances" do
159
+ it "should cleanup the tmp directory before sending configuration to the nodes" do
160
+ @master.should_receive(:cleanup_tmp_directory).once
161
+ @master.build_and_send_config_files_in_temp_directory
162
+ end
148
163
  it "should receive send_config_files_to_nodes after it builds the config files in the temp directory" do
149
- @master.should_receive(:send_config_files_to_nodes).once
164
+ @master.should_receive(:send_config_files_to_nodes).at_least(1)
150
165
  @master.build_and_send_config_files_in_temp_directory
151
166
  end
152
167
  it "should run_array_of_tasks(scp_tasks)" do
153
- @master.should_receive(:run_array_of_tasks).and_return true
168
+ @master.should_receive(:run_array_of_tasks).at_least(1).and_return true
154
169
  @master.build_and_send_config_files_in_temp_directory
155
170
  end
156
171
  it "should compile a list of files to rsync" do
@@ -184,14 +199,18 @@ describe "Master" do
184
199
  before(:each) do
185
200
  Application.stub!(:install_on_load?).and_return true
186
201
  Sprinkle::Script.stub!(:sprinkle).and_return true
187
- @master.stub!(:execute_tasks).and_return true
202
+ @master.stub!(:ssh).and_return true
203
+ @master.nodes.each do |node|
204
+ node.stub!(:run_now).and_return true
205
+ end
188
206
  end
189
207
  it "should install on the instances if the application says it should" do
208
+ Provider.stub!(:install_userpackages)
190
209
  Provider.should_receive(:install_poolparty)
191
210
  @master.install_cloud
192
211
  end
193
212
  it "should execute the remote tasks on all of the instances" do
194
- @master.should_receive(:execute_tasks).and_return true
213
+ @master.should_receive(:ssh).and_return true
195
214
  @master.install_cloud
196
215
  end
197
216
  describe "stubbing installation" do
@@ -244,30 +263,35 @@ describe "Master" do
244
263
  @master.should_receive(:request_termination_of_instance).and_return(true)
245
264
  @master.terminate_instance_if_load_is_low
246
265
  end
266
+ it "should launch the minimum_instances when the minimum aren't launched"
267
+ it "should reconfigure the cloud if it's necessary to do so"
268
+ it "should try to scale the cloud when monitoring"
269
+ it "should check the stats of the cloud"
247
270
  end
248
- describe "expanding and contracting" do
271
+ describe "expanding and contracting" do
249
272
  it "should be able to say that it should not contract" do
250
273
  @master.stub!(:web).and_return(10.2)
251
274
  @master.stub!(:cpu).and_return(0.32)
252
275
 
253
276
  @master.contract?.should == false
254
277
  end
255
- it "should be able to say that it should contract" do
256
- @master.stub!(:web).and_return(31.2)
257
- @master.stub!(:cpu).and_return(0.05)
258
-
278
+ it "should be able to say that it should contract" do
279
+ @master.should_receive(:cpu).once.and_return(0.05)
280
+ @master.should_receive(:web).once.and_return(35.2)
281
+
259
282
  @master.contract?.should == true
260
283
  end
261
284
  it "should be able to say that it should not expand if it shouldn't expand" do
262
285
  @master.stub!(:web).and_return(30.2)
263
286
  @master.stub!(:cpu).and_return(0.92)
264
-
287
+
265
288
  @master.expand?.should == false
266
289
  end
267
290
  it "should be able to say that it should expand if it should expand" do
268
291
  @master.stub!(:web).and_return(1.2)
269
292
  @master.stub!(:cpu).and_return(0.92)
270
-
293
+
294
+ @master.should_receive(:web).once.and_return(1.2)
271
295
  @master.expand?.should == true
272
296
  end
273
297
  describe "scaling" do
@@ -313,6 +337,12 @@ describe "Master" do
313
337
  File.should_receive(:copy).exactly(3).and_return true
314
338
  @master.build_and_send_config_files_in_temp_directory
315
339
  end
340
+ it "should tar the plugin_dir into the tmp directory" do
341
+ FileUtils.mkdir_p Application.plugin_dir rescue ""
342
+
343
+ Kernel.should_receive(:system).with("tar -czf #{@master.base_tmp_dir}/plugins.tar.gz #{File.basename(Application.plugin_dir)}").and_return true
344
+ @master.build_and_send_config_files_in_temp_directory
345
+ end
316
346
  describe "get configs" do
317
347
  before(:each) do
318
348
  @master.stub!(:user_dir).and_return("user")