dreadpiratepj-poolparty 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/CHANGELOG +12 -0
  2. data/Manifest +115 -0
  3. data/README.txt +140 -0
  4. data/Rakefile +27 -0
  5. data/bin/instance +61 -0
  6. data/bin/pool +62 -0
  7. data/config/cloud_master_takeover +17 -0
  8. data/config/create_proxy_ami.sh +582 -0
  9. data/config/haproxy.conf +29 -0
  10. data/config/heartbeat.conf +8 -0
  11. data/config/heartbeat_authkeys.conf +2 -0
  12. data/config/installers/ubuntu_install.sh +77 -0
  13. data/config/monit.conf +9 -0
  14. data/config/monit/haproxy.monit.conf +7 -0
  15. data/config/monit/nginx.monit.conf +0 -0
  16. data/config/nginx.conf +24 -0
  17. data/config/reconfigure_instances_script.sh +18 -0
  18. data/config/sample-config.yml +23 -0
  19. data/config/scp_instances_script.sh +12 -0
  20. data/lib/core/array.rb +13 -0
  21. data/lib/core/exception.rb +9 -0
  22. data/lib/core/float.rb +13 -0
  23. data/lib/core/hash.rb +11 -0
  24. data/lib/core/kernel.rb +12 -0
  25. data/lib/core/module.rb +22 -0
  26. data/lib/core/object.rb +18 -0
  27. data/lib/core/proc.rb +15 -0
  28. data/lib/core/string.rb +49 -0
  29. data/lib/core/time.rb +41 -0
  30. data/lib/modules/callback.rb +133 -0
  31. data/lib/modules/ec2_wrapper.rb +82 -0
  32. data/lib/modules/safe_instance.rb +31 -0
  33. data/lib/modules/vlad_override.rb +82 -0
  34. data/lib/poolparty.rb +105 -0
  35. data/lib/poolparty/application.rb +170 -0
  36. data/lib/poolparty/init.rb +6 -0
  37. data/lib/poolparty/master.rb +329 -0
  38. data/lib/poolparty/monitors.rb +13 -0
  39. data/lib/poolparty/monitors/cpu.rb +19 -0
  40. data/lib/poolparty/monitors/memory.rb +26 -0
  41. data/lib/poolparty/monitors/web.rb +23 -0
  42. data/lib/poolparty/optioner.rb +16 -0
  43. data/lib/poolparty/plugin.rb +43 -0
  44. data/lib/poolparty/plugin_manager.rb +67 -0
  45. data/lib/poolparty/provider.rb +2 -0
  46. data/lib/poolparty/provider/packages/essential.rb +6 -0
  47. data/lib/poolparty/provider/packages/git.rb +4 -0
  48. data/lib/poolparty/provider/packages/haproxy.rb +20 -0
  49. data/lib/poolparty/provider/packages/heartbeat.rb +4 -0
  50. data/lib/poolparty/provider/packages/monit.rb +6 -0
  51. data/lib/poolparty/provider/packages/rsync.rb +4 -0
  52. data/lib/poolparty/provider/packages/ruby.rb +37 -0
  53. data/lib/poolparty/provider/packages/s3fuse.rb +11 -0
  54. data/lib/poolparty/provider/provider.rb +60 -0
  55. data/lib/poolparty/remote_instance.rb +216 -0
  56. data/lib/poolparty/remoter.rb +106 -0
  57. data/lib/poolparty/remoting.rb +112 -0
  58. data/lib/poolparty/scheduler.rb +103 -0
  59. data/lib/poolparty/tasks.rb +29 -0
  60. data/lib/poolparty/tasks/cloud.rake +57 -0
  61. data/lib/poolparty/tasks/development.rake +38 -0
  62. data/lib/poolparty/tasks/ec2.rake +20 -0
  63. data/lib/poolparty/tasks/instance.rake +63 -0
  64. data/lib/poolparty/tasks/plugins.rake +30 -0
  65. data/lib/poolparty/tasks/server.rake +42 -0
  66. data/lib/poolparty/tmp.rb +46 -0
  67. data/lib/s3/s3_object_store_folders.rb +44 -0
  68. data/misc/basics_tutorial.txt +142 -0
  69. data/poolparty.gemspec +72 -0
  70. data/spec/application_spec.rb +39 -0
  71. data/spec/callback_spec.rb +194 -0
  72. data/spec/core_spec.rb +15 -0
  73. data/spec/helpers/ec2_mock.rb +44 -0
  74. data/spec/kernel_spec.rb +11 -0
  75. data/spec/master_spec.rb +203 -0
  76. data/spec/monitors/cpu_monitor_spec.rb +38 -0
  77. data/spec/monitors/memory_spec.rb +50 -0
  78. data/spec/monitors/misc_monitor_spec.rb +50 -0
  79. data/spec/monitors/web_spec.rb +39 -0
  80. data/spec/optioner_spec.rb +22 -0
  81. data/spec/plugin_manager_spec.rb +31 -0
  82. data/spec/plugin_spec.rb +101 -0
  83. data/spec/pool_binary_spec.rb +10 -0
  84. data/spec/poolparty_spec.rb +15 -0
  85. data/spec/provider_spec.rb +17 -0
  86. data/spec/remote_instance_spec.rb +149 -0
  87. data/spec/remoter_spec.rb +65 -0
  88. data/spec/remoting_spec.rb +84 -0
  89. data/spec/scheduler_spec.rb +75 -0
  90. data/spec/spec_helper.rb +39 -0
  91. data/spec/string_spec.rb +28 -0
  92. data/web/static/conf/nginx.conf +22 -0
  93. data/web/static/site/images/balloon.png +0 -0
  94. data/web/static/site/images/cb.png +0 -0
  95. data/web/static/site/images/clouds.png +0 -0
  96. data/web/static/site/images/railsconf_preso_img.png +0 -0
  97. data/web/static/site/index.html +71 -0
  98. data/web/static/site/javascripts/application.js +3 -0
  99. data/web/static/site/javascripts/corner.js +178 -0
  100. data/web/static/site/javascripts/jquery-1.2.6.pack.js +11 -0
  101. data/web/static/site/misc.html +42 -0
  102. data/web/static/site/storage/pool_party_presentation.pdf +0 -0
  103. data/web/static/site/stylesheets/application.css +100 -0
  104. data/web/static/site/stylesheets/reset.css +17 -0
  105. data/web/static/src/layouts/application.haml +25 -0
  106. data/web/static/src/pages/index.haml +25 -0
  107. data/web/static/src/pages/misc.haml +5 -0
  108. data/web/static/src/stylesheets/application.sass +100 -0
  109. metadata +260 -0
@@ -0,0 +1,106 @@
1
+ =begin rdoc
2
+ Handle the remoting aspects of the remote_instances
3
+ =end
4
+ module PoolParty
5
+ module Remoter
6
+ module ClassMethods
7
+ def ssh_string
8
+ "ssh -i #{Application.keypair_path} -o StrictHostKeyChecking=no -l #{Application.username}"
9
+ end
10
+ end
11
+
12
+ module InstanceMethods
13
+ include Callbacks
14
+ include Scheduler
15
+
16
+ def scp local, remote, opts={}
17
+ data = open(local).read
18
+ begin
19
+
20
+ cmd = "rsync --delete -azP -e '#{self.class.ssh_string} -l #{Application.username} -i #{Application.keypair_path}' "
21
+
22
+ if opts[:dir]
23
+ ssh("mkdir -p #{opts[:dir]}")
24
+ end
25
+
26
+ if opts[:single]
27
+ scp_tasks << "#{cmd} #{local} #{Application.username}@#{opts[:single]}:#{remote}"
28
+ else
29
+ target_hosts.each do |ip|
30
+ scp_tasks << "#{cmd} #{local} #{Application.username}@#{ip}:#{remote}"
31
+ end
32
+ end
33
+
34
+ rescue Exception => e
35
+ end
36
+ end
37
+
38
+ def single_scp local, remote, opts={}
39
+ scp local, remote, opts.merge({:single => self.ip})
40
+ end
41
+
42
+ def ssh command="", opts={}, &block
43
+ cmd = self.class.ssh_string
44
+ if command.empty?
45
+ system("#{cmd} #{Application.username}@#{self.ip}")
46
+ else
47
+ if opts[:single]
48
+ ssh_tasks << "#{cmd} #{Application.username}@#{self.ip} '#{command.runnable}'"
49
+ else
50
+ target_hosts.each do |ip|
51
+ ssh_tasks << "#{cmd} #{Application.username}@#{ip} '#{command.runnable}'"
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def run_now command=""
58
+ system("#{self.class.ssh_string} #{Application.username}@#{self.ip} #{command.runnable}")
59
+ end
60
+
61
+ def install *names
62
+ names.each {|name| install_tasks << name }
63
+ end
64
+
65
+ def ssh_tasks;@ssh_tasks ||= [];end
66
+ def scp_tasks;@scp_tasks ||= [];end
67
+ def install_tasks;@install_tasks ||= [];end
68
+
69
+ def reset!
70
+ @ssh_tasks = @scp_tasks = nil
71
+ @hosts = nil
72
+ end
73
+
74
+ def execute_tasks(opts={})
75
+ # reset!
76
+
77
+ set_hosts(nil) unless opts[:dont_set_hosts]
78
+
79
+ yield if block_given?
80
+
81
+ run_array_of_tasks(scp_tasks)
82
+ run_array_of_tasks(ssh_tasks)
83
+
84
+ PoolParty.message "running #{ssh_tasks.size} tasks"
85
+ end
86
+
87
+ def target_hosts
88
+ @hosts ||= Master.collect_nodes {|a| a.ip }
89
+ end
90
+
91
+ def run_array_of_tasks(task_list)
92
+ add_task {`#{task_list.join(" && ")}`}
93
+ run_thread_list
94
+ end
95
+
96
+ def set_hosts(c=nil)
97
+ end
98
+
99
+ end
100
+
101
+ def self.included(receiver)
102
+ receiver.extend ClassMethods
103
+ receiver.send :include, InstanceMethods
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,112 @@
1
+ module PoolParty
2
+ extend self
3
+
4
+ class Remoting
5
+ include PoolParty
6
+ include Ec2Wrapper
7
+ include Scheduler
8
+
9
+ # == GENERAL METHODS
10
+ # == LISTING
11
+ # List all the running instances associated with this account
12
+ def list_of_running_instances
13
+ list_of_nonterminated_instances.select {|a| a[:status] =~ /running/}
14
+ end
15
+ # Get a list of the pending instances
16
+ def list_of_pending_instances
17
+ list_of_nonterminated_instances.select {|a| a[:status] =~ /pending/}
18
+ end
19
+ # list of shutting down instances
20
+ def list_of_terminating_instances
21
+ list_of_nonterminated_instances.select {|a| a[:status] =~ /shutting/}
22
+ end
23
+ # list all the nonterminated instances
24
+ def list_of_nonterminated_instances
25
+ list_of_instances.reject {|a| a[:status] =~ /terminated/}
26
+ end
27
+ # List the instances, regardless of their states
28
+ def list_of_instances
29
+ get_instances_description
30
+ end
31
+ # Get number of pending instances
32
+ def number_of_pending_instances
33
+ list_of_pending_instances.size
34
+ end
35
+ # get the number of running instances
36
+ def number_of_running_instances
37
+ list_of_running_instances.size
38
+ end
39
+ # get the number of pending and running instances
40
+ def number_of_pending_and_running_instances
41
+ number_of_running_instances + number_of_pending_instances
42
+ end
43
+ # == LAUNCHING
44
+ # Request to launch a new instance
45
+ def request_launch_new_instance
46
+ if can_start_a_new_instance?
47
+ request_launch_one_instance_at_a_time
48
+ return true
49
+ else
50
+ return false
51
+ end
52
+ end
53
+ # Can we start a new instance?
54
+ def can_start_a_new_instance?
55
+ maximum_number_of_instances_are_not_running?
56
+ end
57
+ # Are the maximum number of instances running?
58
+ def maximum_number_of_instances_are_not_running?
59
+ list_of_running_instances.size < Application.maximum_instances
60
+ end
61
+ # Request to launch a number of instances
62
+ def request_launch_new_instances(num=1)
63
+ out = []
64
+ num.times {out << request_launch_one_instance_at_a_time}
65
+ out
66
+ end
67
+ # Launch one instance at a time
68
+ def request_launch_one_instance_at_a_time
69
+ reset!
70
+ while !number_of_pending_instances.zero?
71
+ wait "5.seconds"
72
+ reset!
73
+ end
74
+ return launch_new_instance!
75
+ end
76
+ # == SHUTDOWN
77
+ # Terminate all running instances
78
+ def request_termination_of_running_instances
79
+ list_of_running_instances.each {|a| terminate_instance!(a[:instance_id])}
80
+ end
81
+ # Request termination of all instances regardless of their state (includes pending instances)
82
+ def request_termination_of_all_instances
83
+ get_instances_description.each {|a| terminate_instance!(a[:instance_id])}
84
+ end
85
+ # Terminate instance by id
86
+ def request_termination_of_instance(id)
87
+ if can_shutdown_an_instance?
88
+ terminate_instance! id
89
+ return true
90
+ else
91
+ return false
92
+ end
93
+ end
94
+ # Can we shutdown an instance?
95
+ def can_shutdown_an_instance?
96
+ minimum_number_of_instances_are_running?
97
+ end
98
+ # Are the minimum number of instances running?
99
+ def minimum_number_of_instances_are_running?
100
+ list_of_running_instances.size > Application.minimum_instances
101
+ end
102
+ # Get the cached running_instances
103
+ def running_instances
104
+ @running_instances ||= update_instance_values
105
+ end
106
+ # Update the instance values
107
+ def update_instance_values
108
+ @running_instances = list_of_running_instances.collect {|a| RemoteInstance.new(a) }.sort
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,103 @@
1
+ module PoolParty
2
+ extend self
3
+ # Schedule tasks container
4
+ class ScheduleTasks
5
+ include ThreadSafeInstance
6
+ # Initialize tasks array and run
7
+ def tasks
8
+ @_tasks ||= []
9
+ end
10
+ # Synchronize the running threaded tasks
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
+ }
23
+ end
24
+ end
25
+ end
26
+ # Add a task in a new thread
27
+ def <<(a, *args)
28
+ thread = Thread.new(a) do |task|
29
+ Thread.stop
30
+ Thread.current[:callee] = task
31
+ a.call args
32
+ end
33
+ tasks << thread
34
+ end
35
+ alias_method :push, :<<
36
+ # In the ThreadSafeInstance
37
+ make_safe :<<
38
+ end
39
+ # Scheduler class
40
+ module Scheduler
41
+ attr_reader :tasker
42
+ # Get the tasks or ScheduleTasks
43
+ def _tasker
44
+ @_tasker ||= ScheduleTasks.new
45
+ end
46
+ # Add a task to the new threaded block
47
+ def add_task(&blk)
48
+ _tasker.push proc{blk.call}
49
+ end
50
+ # Grab the polling_time
51
+ def interval
52
+ @interval ||= Application.polling_time
53
+ end
54
+ # Run the threads
55
+ def run_threads
56
+ _tasker.run
57
+ end
58
+ alias_method :run_tasks, :run_threads
59
+ # Daemonize the process
60
+ def daemonize
61
+ PoolParty.message "Daemonizing..."
62
+
63
+ pid = fork do
64
+ Signal.trap('HUP', 'IGNORE') # Don't die upon logout
65
+ File.open("/dev/null", "r+") do |devnull|
66
+ $stdout.reopen(devnull)
67
+ $stderr.reopen(devnull)
68
+ $stdin.reopen(devnull) unless @use_stdin
69
+ end
70
+ yield if block_given?
71
+ end
72
+ Process.detach(pid)
73
+ pid
74
+ end
75
+ # Run the loop and wait the amount of time between running the tasks
76
+ # You can send it daemonize => true and it will daemonize
77
+ def run_thread_loop(opts={}, &block)
78
+ block = lambda {
79
+ loop do
80
+ begin
81
+ run_thread_list(&block)
82
+ wait interval
83
+ reset!
84
+ rescue Exception => e
85
+ puts "There was an error in the run_thread_loop: #{e}"
86
+ end
87
+ end
88
+ }
89
+ # Run the tasks
90
+ opts[:daemonize] ? daemonize(&block) : block.call
91
+ end
92
+
93
+ def run_thread_list
94
+ yield if block_given?
95
+ run_threads
96
+ end
97
+ # Reset
98
+ def reset!
99
+ cached_variables.each {|cached| cached = nil }
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,29 @@
1
+ module PoolParty
2
+ class Tasks
3
+ include Callbacks
4
+
5
+ # Setup and define all the tasks
6
+ def initialize
7
+ yield self if block_given?
8
+ end
9
+ # Define the tasks in the rakefile
10
+ # From the rakefile
11
+ def define_tasks
12
+ # Run the command on the local system
13
+ def run(cmd)
14
+ system(cmd.runnable)
15
+ end
16
+ # Basic setup action
17
+ def setup_application
18
+ PoolParty.options({:config_file => (ENV["CONFIG_FILE"] || ENV["config"]) })
19
+ end
20
+
21
+ # Require the poolparty specific tasks
22
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].each { |t| eval open(t).read }
23
+
24
+ Dir["#{PoolParty.plugin_dir}/*/Rakefile"].each {|t| load "#{t}" }
25
+
26
+ true
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,57 @@
1
+ # Cloud tasks
2
+ namespace(:cloud) do
3
+ # Setup
4
+ task :init do
5
+ setup_application
6
+ raise Exception.new("You must specify your access_key and secret_access_key") unless Application.access_key && Application.secret_access_key
7
+ end
8
+ # Install the stack on all of the nodes
9
+ desc "Prepare all servers"
10
+ task :prepare => :init do
11
+ PoolParty::Master.new.nodes.each do |node|
12
+ node.install
13
+ end
14
+ end
15
+ # Start the cloud
16
+ desc "Start the cloud"
17
+ task :start => :init do
18
+ PoolParty::Master.new.start_cloud!
19
+ end
20
+ # Reload the cloud with the new updated data
21
+ desc "Reload all instances with updated data"
22
+ task :reload => :init do
23
+ PoolParty::Master.new.nodes.each do |node|
24
+ node.configure
25
+ node.restart_with_monit
26
+ end
27
+ end
28
+ # List the cloud
29
+ desc "List cloud"
30
+ task :list => :init do
31
+ PoolParty::Master.new.list
32
+ end
33
+ # Shutdown the cloud
34
+ desc "Shutdown the entire cloud"
35
+ task :shutdown => :init do
36
+ PoolParty::Master.new.request_termination_of_all_instances
37
+ end
38
+ # Watch the cloud and scale it if necessary
39
+ desc "Watch the cloud and maintain it"
40
+ task :scale => :init do
41
+ begin
42
+ PoolParty::Master.new.scale_cloud!
43
+ rescue Exception => e
44
+ puts "There was an error scaling the cloud: #{e}"
45
+ end
46
+
47
+ end
48
+ # Maintain the cloud in a background process
49
+ desc "Maintain the cloud (run on the master)"
50
+ task :maintain => :init do
51
+ begin
52
+ PoolParty::Master.new.start_monitor!
53
+ rescue Exception => e
54
+ puts "There was an error starting the monitor: #{e}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,38 @@
1
+ namespace(:dev) do
2
+ task :init do
3
+ setup_application
4
+ run "mkdir ~/.ec2 >/dev/null 2>/dev/null" unless File.directory?("~/.ec2")
5
+ end
6
+ # Setup a basic development environment for the user
7
+ desc "Setup development environment specify the config_file"
8
+ task :setup => [:init] do
9
+ keyfilename = ".#{Application.keypair}_pool_keys"
10
+ run <<-EOR
11
+ echo 'export AWS_ACCESS_KEY_ID=\"#{Application.access_key}\"' > $HOME/#{keyfilename}
12
+ echo 'export AWS_SECRET_ACCESS_ID=\"#{Application.secret_access_key}\"' >> $HOME/#{keyfilename}
13
+ echo 'export EC2_HOME=\"#{Application.ec2_dir}\"' >> $HOME/#{keyfilename}
14
+ echo 'export KEYPAIR_NAME=\"#{Application.keypair}\"' >> $HOME/#{keyfilename}
15
+ echo 'export CONFIG_FILE=\"#{Application.config_file}\"' >> $HOME/#{keyfilename}
16
+ echo 'export EC2_PRIVATE_KEY=`ls ~/.ec2/#{Application.keypair}/pk-*.pem`;' >> $HOME/#{keyfilename}
17
+ echo 'export EC2_CERT=`ls ~/.ec2/#{Application.keypair}/cert-*.pem`;' >> $HOME/#{keyfilename}
18
+ source $HOME/#{keyfilename}
19
+ EOR
20
+ end
21
+ desc "Generate a keypair"
22
+ task :setup_keypair => :init do
23
+ unless File.file?(Application.keypair_path)
24
+ Application.keypair = "cloud"
25
+ run <<-EOR
26
+ ec2-add-keypair cloud > #{Application.keypair_path}
27
+ chmod 600 #{Application.keypair_path}
28
+ EOR
29
+ end
30
+ end
31
+ desc "Authorize base ports for application"
32
+ task :authorize_ports => :init do
33
+ run <<-EOR
34
+ ec2-authorize -p 22 default
35
+ ec2-authorize -p 80 default
36
+ EOR
37
+ end
38
+ end