auser-poolparty 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/Manifest +115 -0
- data/README.txt +140 -0
- data/Rakefile +27 -0
- data/bin/instance +61 -0
- data/bin/pool +62 -0
- data/config/cloud_master_takeover +17 -0
- data/config/create_proxy_ami.sh +582 -0
- data/config/haproxy.conf +29 -0
- data/config/heartbeat.conf +8 -0
- data/config/heartbeat_authkeys.conf +2 -0
- data/config/installers/ubuntu_install.sh +77 -0
- data/config/monit/haproxy.monit.conf +7 -0
- data/config/monit/nginx.monit.conf +0 -0
- data/config/monit.conf +9 -0
- data/config/nginx.conf +24 -0
- data/config/reconfigure_instances_script.sh +18 -0
- data/config/sample-config.yml +23 -0
- data/config/scp_instances_script.sh +12 -0
- data/lib/core/array.rb +13 -0
- data/lib/core/exception.rb +9 -0
- data/lib/core/float.rb +13 -0
- data/lib/core/hash.rb +11 -0
- data/lib/core/kernel.rb +12 -0
- data/lib/core/module.rb +22 -0
- data/lib/core/object.rb +18 -0
- data/lib/core/proc.rb +15 -0
- data/lib/core/string.rb +49 -0
- data/lib/core/time.rb +41 -0
- data/lib/modules/callback.rb +133 -0
- data/lib/modules/ec2_wrapper.rb +82 -0
- data/lib/modules/safe_instance.rb +31 -0
- data/lib/modules/vlad_override.rb +82 -0
- data/lib/poolparty/application.rb +170 -0
- data/lib/poolparty/init.rb +6 -0
- data/lib/poolparty/master.rb +329 -0
- data/lib/poolparty/monitors/cpu.rb +19 -0
- data/lib/poolparty/monitors/memory.rb +26 -0
- data/lib/poolparty/monitors/web.rb +23 -0
- data/lib/poolparty/monitors.rb +13 -0
- data/lib/poolparty/optioner.rb +16 -0
- data/lib/poolparty/plugin.rb +43 -0
- data/lib/poolparty/plugin_manager.rb +67 -0
- data/lib/poolparty/provider/packages/essential.rb +6 -0
- data/lib/poolparty/provider/packages/git.rb +4 -0
- data/lib/poolparty/provider/packages/haproxy.rb +20 -0
- data/lib/poolparty/provider/packages/heartbeat.rb +4 -0
- data/lib/poolparty/provider/packages/monit.rb +6 -0
- data/lib/poolparty/provider/packages/rsync.rb +4 -0
- data/lib/poolparty/provider/packages/ruby.rb +37 -0
- data/lib/poolparty/provider/packages/s3fuse.rb +11 -0
- data/lib/poolparty/provider/provider.rb +60 -0
- data/lib/poolparty/provider.rb +2 -0
- data/lib/poolparty/remote_instance.rb +216 -0
- data/lib/poolparty/remoter.rb +106 -0
- data/lib/poolparty/remoting.rb +112 -0
- data/lib/poolparty/scheduler.rb +103 -0
- data/lib/poolparty/tasks/cloud.rake +57 -0
- data/lib/poolparty/tasks/development.rake +38 -0
- data/lib/poolparty/tasks/ec2.rake +20 -0
- data/lib/poolparty/tasks/instance.rake +63 -0
- data/lib/poolparty/tasks/plugins.rake +30 -0
- data/lib/poolparty/tasks/server.rake +42 -0
- data/lib/poolparty/tasks.rb +29 -0
- data/lib/poolparty/tmp.rb +46 -0
- data/lib/poolparty.rb +105 -0
- data/lib/s3/s3_object_store_folders.rb +44 -0
- data/misc/basics_tutorial.txt +142 -0
- data/poolparty.gemspec +72 -0
- data/spec/application_spec.rb +39 -0
- data/spec/callback_spec.rb +194 -0
- data/spec/core_spec.rb +15 -0
- data/spec/helpers/ec2_mock.rb +44 -0
- data/spec/kernel_spec.rb +11 -0
- data/spec/master_spec.rb +203 -0
- data/spec/monitors/cpu_monitor_spec.rb +38 -0
- data/spec/monitors/memory_spec.rb +50 -0
- data/spec/monitors/misc_monitor_spec.rb +50 -0
- data/spec/monitors/web_spec.rb +39 -0
- data/spec/optioner_spec.rb +22 -0
- data/spec/plugin_manager_spec.rb +31 -0
- data/spec/plugin_spec.rb +101 -0
- data/spec/pool_binary_spec.rb +10 -0
- data/spec/poolparty_spec.rb +15 -0
- data/spec/provider_spec.rb +17 -0
- data/spec/remote_instance_spec.rb +149 -0
- data/spec/remoter_spec.rb +65 -0
- data/spec/remoting_spec.rb +84 -0
- data/spec/scheduler_spec.rb +75 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/string_spec.rb +28 -0
- data/web/static/conf/nginx.conf +22 -0
- data/web/static/site/images/balloon.png +0 -0
- data/web/static/site/images/cb.png +0 -0
- data/web/static/site/images/clouds.png +0 -0
- data/web/static/site/images/railsconf_preso_img.png +0 -0
- data/web/static/site/index.html +71 -0
- data/web/static/site/javascripts/application.js +3 -0
- data/web/static/site/javascripts/corner.js +178 -0
- data/web/static/site/javascripts/jquery-1.2.6.pack.js +11 -0
- data/web/static/site/misc.html +42 -0
- data/web/static/site/storage/pool_party_presentation.pdf +0 -0
- data/web/static/site/stylesheets/application.css +100 -0
- data/web/static/site/stylesheets/reset.css +17 -0
- data/web/static/src/layouts/application.haml +25 -0
- data/web/static/src/pages/index.haml +25 -0
- data/web/static/src/pages/misc.haml +5 -0
- data/web/static/src/stylesheets/application.sass +100 -0
- metadata +260 -0
@@ -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,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
|
@@ -0,0 +1,20 @@
|
|
1
|
+
namespace(:ec2) do
|
2
|
+
task :init do
|
3
|
+
Application.options
|
4
|
+
end
|
5
|
+
# Start a new instance in the cloud
|
6
|
+
desc "Add and start an instance to the pool"
|
7
|
+
task :start_new_instance => [:init] do
|
8
|
+
puts PoolParty::Remoting.new.launch_new_instance!
|
9
|
+
end
|
10
|
+
# Stop all the instances via command-line
|
11
|
+
desc "Stop all running instances"
|
12
|
+
task :stop_running_instances => [:init] do
|
13
|
+
Thread.new {`ec2-describe-instances | grep INSTANCE | grep running | awk '{print $2}' | xargs ec2-terminate-instances`}
|
14
|
+
end
|
15
|
+
# Reboot the instances via commandline
|
16
|
+
desc "Restart all running instances"
|
17
|
+
task :restart_running_instances => [:init] do
|
18
|
+
Thread.new {`ec2-describe-instances | grep INSTANCE | grep running | awk '{print $2}' | xargs ec2-reboot-instances`}
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
namespace(:instance) do
|
2
|
+
# Find the instance we want to deal with
|
3
|
+
# interface can be: num=0, i=0, inst=0, 0
|
4
|
+
# defaults to the master instance (0)
|
5
|
+
task :init do
|
6
|
+
num = (ENV['num'] || ENV["i"] || ENV["inst"] || ARGV.shift || 0).to_i
|
7
|
+
raise Exception.new("Please set the number of the instance (i.e. num=1, i=1, or as an argument)") unless num
|
8
|
+
@node = PoolParty::Master.new.get_node(num)
|
9
|
+
end
|
10
|
+
# Ssh into the node
|
11
|
+
desc "Remotely login to the remote instance"
|
12
|
+
task :ssh => [:init] do
|
13
|
+
@node.ssh
|
14
|
+
end
|
15
|
+
desc "Send a file to the remote instance"
|
16
|
+
task :exec => :init do
|
17
|
+
@node.ssh ENV['cmd']
|
18
|
+
end
|
19
|
+
# Send a file to the remote instance
|
20
|
+
# as designated by src='' and dest=''
|
21
|
+
desc "Send a file to the remote instance"
|
22
|
+
task :scp => :init do
|
23
|
+
@node.scp ENV['src'], ENV['dest']
|
24
|
+
end
|
25
|
+
# Execute a command on the remote instance as designated
|
26
|
+
# by cmd=''
|
27
|
+
desc "Execute cmd on a remote instance"
|
28
|
+
task :exec => [:init] do
|
29
|
+
cmd = ENV['cmd'] || "ls -l"
|
30
|
+
puts @node.ssh(cmd.runnable)
|
31
|
+
end
|
32
|
+
# Restart all the services monitored by monit
|
33
|
+
desc "Restart all the services"
|
34
|
+
task :reload => [:init] do
|
35
|
+
@node.restart_with_monit
|
36
|
+
end
|
37
|
+
# Start all the services monitored by monit
|
38
|
+
desc "Start all services"
|
39
|
+
task :load => [:init] do
|
40
|
+
@node.start_with_monit
|
41
|
+
end
|
42
|
+
# Stop the services monitored by monit
|
43
|
+
desc "Stop all services"
|
44
|
+
task :stop => [:init] do
|
45
|
+
@node.stop_with_monit
|
46
|
+
end
|
47
|
+
# Install the required services on this node
|
48
|
+
desc "Install stack on this node"
|
49
|
+
task :install => :init do
|
50
|
+
@node.install
|
51
|
+
end
|
52
|
+
# Turnoff this instance
|
53
|
+
desc "Teardown instance"
|
54
|
+
task :shutdown => :init do
|
55
|
+
`ec2-terminate-instances #{@node.instance_id}`
|
56
|
+
end
|
57
|
+
# Configure this node and start the services
|
58
|
+
desc "Configure the stack on this node"
|
59
|
+
task :configure => :init do
|
60
|
+
@node.configure
|
61
|
+
@node.restart_with_monit
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
namespace(:plugin) do
|
2
|
+
task :init do
|
3
|
+
@command = ARGV.shift # Get rid of the command
|
4
|
+
@name = (ENV['location'] || ENV["l"] || ARGV.shift)
|
5
|
+
unless @name
|
6
|
+
puts <<-EOM
|
7
|
+
Usage:
|
8
|
+
rake #{@command} location
|
9
|
+
|
10
|
+
Example:
|
11
|
+
rake #{@command} git://github.com/auser/pool-party-plugins.git
|
12
|
+
|
13
|
+
Check the help does for more information how to install a plugin
|
14
|
+
http://poolpartyrb.com
|
15
|
+
|
16
|
+
EOM
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
desc "Install a plugin from a git repository"
|
21
|
+
task :install => :init do |command|
|
22
|
+
PoolParty::PluginManager.install_plugin @name
|
23
|
+
end
|
24
|
+
desc "Remove an installed plugin"
|
25
|
+
task :remove => :init do |command|
|
26
|
+
PoolParty::PluginManager.remove_plugin @name
|
27
|
+
end
|
28
|
+
rule "" do |t|
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Tasks to be run on the server
|
2
|
+
namespace(:server) do
|
3
|
+
task :init do
|
4
|
+
PoolParty::Coordinator.init(false)
|
5
|
+
end
|
6
|
+
# bundle, upload and register your bundle on the server
|
7
|
+
desc "Bundle, upload and register your ami"
|
8
|
+
task :all => [:bundle, :upload, :register] do
|
9
|
+
puts "== your ami is ready"
|
10
|
+
end
|
11
|
+
# Cleanup the /mnt directory
|
12
|
+
desc "Clean the /mnt directory"
|
13
|
+
task :clean_mnt do
|
14
|
+
`rm -rf /mnt/image* img*`
|
15
|
+
end
|
16
|
+
# Before we can bundle, we have to make sure we have the cert and pk files
|
17
|
+
desc "Ensure the required bundle files are present in /mnt"
|
18
|
+
task :check_bundle_files do
|
19
|
+
raise Exception.new("You must have a private key in your /mnt directory") unless File.exists?("/mnt/pk-*.pem")
|
20
|
+
raise Exception.new("You must have your access key in your /mnt directory") unless File.exists?("/mnt/cert-*.pem")
|
21
|
+
end
|
22
|
+
# Bundle the image
|
23
|
+
desc "Bundle this image into the /mnt directory"
|
24
|
+
task :bundle => [:clean_mnt, :check_bundle_files] do
|
25
|
+
puts `ec2-bundle-vol -k /mnt/pk-*.pem -u '#{Planner.user_id}' -d /mnt -c /mnt/cert-*.pem -r i386`
|
26
|
+
end
|
27
|
+
# Upload the bundle into the app_name bucket
|
28
|
+
desc "Upload the bundle to your bucket with a unique name: deletes old ami"
|
29
|
+
task :upload => [:init, :delete_bucket] do
|
30
|
+
puts `ec2-upload-bundle -b #{Planner.app_name} -m /mnt/image.manifest.xml -a #{Planner.access_key} -s #{Planner.secret_access_key}`
|
31
|
+
end
|
32
|
+
# Register the bucket with amazon and get back an ami
|
33
|
+
desc "Register the bundle with amazon"
|
34
|
+
task :register do
|
35
|
+
puts `ec2-register -K /mnt/pk-*.pem -C /mnt/cert-*.pem #{Planner.app_name}/image.manifest.xml`
|
36
|
+
end
|
37
|
+
# Delete the bucket
|
38
|
+
desc "Delete the bucket with the bundle under tha app name"
|
39
|
+
task :delete_bucket do
|
40
|
+
Planner.app_name.delete_bucket
|
41
|
+
end
|
42
|
+
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,46 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
require "backcall"
|
3
|
+
require "remoter"
|
4
|
+
class Test
|
5
|
+
include PoolParty::Remoter
|
6
|
+
include Callbacks
|
7
|
+
|
8
|
+
after :initialize, :set_hosts
|
9
|
+
def rt
|
10
|
+
@rt ||= Rake::RemoteTask
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_hosts(c)
|
14
|
+
rt.host "myslice", :app, :db
|
15
|
+
end
|
16
|
+
|
17
|
+
def rtask(name, *args, &block)
|
18
|
+
rt.remote_task(name.to_sym => args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def scp local, remote
|
22
|
+
require "tempfile"
|
23
|
+
rtask(:scp) do
|
24
|
+
put remote do
|
25
|
+
open(local).read
|
26
|
+
end
|
27
|
+
end.execute
|
28
|
+
end
|
29
|
+
before :scp, :set_hosts
|
30
|
+
def ssh command=nil, &block
|
31
|
+
block = Proc.new do
|
32
|
+
run command
|
33
|
+
end
|
34
|
+
rtask(:ssh, &block).execute
|
35
|
+
end
|
36
|
+
before :ssh, :set_hosts
|
37
|
+
end
|
38
|
+
|
39
|
+
t = Test.new
|
40
|
+
t.scp("/Users/auser/Sites/work/citrusbyte/internal/gems/pool-party/pool/CHANGELOG", "ho")
|
41
|
+
t.ssh("ls -l")
|
42
|
+
t.ssh <<-EOE
|
43
|
+
ls -l
|
44
|
+
mv ho CHANGELOG
|
45
|
+
cat CHANGELOG
|
46
|
+
EOE
|
data/lib/poolparty.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
The main file, contains the client and the server application methods
|
3
|
+
=end
|
4
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
5
|
+
|
6
|
+
# rubygems
|
7
|
+
require 'rubygems'
|
8
|
+
require "aws/s3"
|
9
|
+
require "sqs"
|
10
|
+
require "EC2"
|
11
|
+
require 'thread'
|
12
|
+
require "pp"
|
13
|
+
require "tempfile"
|
14
|
+
require "aska"
|
15
|
+
require "vlad"
|
16
|
+
begin
|
17
|
+
require 'fastthread'
|
18
|
+
require 'thin'
|
19
|
+
require 'system_timer'
|
20
|
+
Timer = SystemTimer
|
21
|
+
rescue LoadError
|
22
|
+
require 'timeout'
|
23
|
+
Timer = Timeout
|
24
|
+
end
|
25
|
+
|
26
|
+
## Load PoolParty
|
27
|
+
pwd = File.dirname(__FILE__)
|
28
|
+
|
29
|
+
# Load the required files
|
30
|
+
# If there is an init file, load that, otherwise
|
31
|
+
# require all the files in each directory
|
32
|
+
%w(core modules s3 poolparty).each do |dir|
|
33
|
+
Dir["#{pwd}/#{dir}"].each do |dir|
|
34
|
+
begin
|
35
|
+
require File.join(dir, "init")
|
36
|
+
rescue LoadError => e
|
37
|
+
Dir["#{pwd}/#{File.basename(dir)}/**"].each {|file| require File.join(dir, File.basename(file))}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module PoolParty
|
43
|
+
module Version #:nodoc:
|
44
|
+
MAJOR = 0
|
45
|
+
MINOR = 0
|
46
|
+
TINY = 8
|
47
|
+
|
48
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
49
|
+
end
|
50
|
+
# PoolParty options
|
51
|
+
def options(opts={})
|
52
|
+
Application.options(opts)
|
53
|
+
end
|
54
|
+
# Are we working in verbose-mode
|
55
|
+
def verbose?
|
56
|
+
options.verbose == true
|
57
|
+
end
|
58
|
+
# Send a message if we are in verbose-mode
|
59
|
+
def message(msg="")
|
60
|
+
puts "-- #{msg}" if verbose?
|
61
|
+
end
|
62
|
+
# Root directory of the application
|
63
|
+
def root_dir
|
64
|
+
File.expand_path(File.dirname(__FILE__) + "/..")
|
65
|
+
end
|
66
|
+
# User directory
|
67
|
+
def user_dir
|
68
|
+
Dir.pwd
|
69
|
+
end
|
70
|
+
# Write string to a tempfile
|
71
|
+
def write_to_temp_file(str="")
|
72
|
+
tempfile = Tempfile.new("rand#{rand(1000)}-#{rand(1000)}")
|
73
|
+
tempfile.print(str)
|
74
|
+
tempfile.flush
|
75
|
+
tempfile
|
76
|
+
end
|
77
|
+
def register_monitor(*names)
|
78
|
+
names.each do |name|
|
79
|
+
PoolParty::Monitors.extend name
|
80
|
+
|
81
|
+
PoolParty::Master.send :include, name::Master
|
82
|
+
PoolParty::RemoteInstance.send :include, name::Remote
|
83
|
+
end
|
84
|
+
end
|
85
|
+
def load_plugins
|
86
|
+
Dir["#{plugin_dir}/**/init.rb"].each {|a| require a}
|
87
|
+
end
|
88
|
+
def reset!
|
89
|
+
@@installed_plugins = nil
|
90
|
+
Application.options = nil
|
91
|
+
end
|
92
|
+
def plugin_dir
|
93
|
+
"#{user_dir}/vendor"
|
94
|
+
end
|
95
|
+
def read_config_file(filename)
|
96
|
+
return {} unless filename
|
97
|
+
YAML.load(open(filename).read)
|
98
|
+
end
|
99
|
+
def include_cloud_tasks
|
100
|
+
Tasks.new.define_tasks
|
101
|
+
end
|
102
|
+
|
103
|
+
alias_method :tasks, :include_cloud_tasks
|
104
|
+
alias_method :include_tasks, :include_cloud_tasks
|
105
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
S3 overloads
|
3
|
+
=end
|
4
|
+
module AWS
|
5
|
+
module S3
|
6
|
+
class S3Object
|
7
|
+
class << self
|
8
|
+
|
9
|
+
alias :original_store :store
|
10
|
+
def store(key, data, bucket = nil, options = {})
|
11
|
+
store_folders(key, bucket, options) if options[:use_virtual_directories]
|
12
|
+
original_store(key, data, bucket, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def streamed_store(key, filepath, bucket = nil, options = {})
|
16
|
+
store_folders(key, bucket, options) if options[:use_virtual_directories]
|
17
|
+
store(key,File.open(filepath), bucket)
|
18
|
+
end
|
19
|
+
|
20
|
+
def store_directory(directory, bucket, options = {})
|
21
|
+
Dir[File.join(directory, "*")].each do |file|
|
22
|
+
streamed_store("#{File.basename(File.dirname(file))}/#{File.basename(file)}", file, bucket, options.update(:use_virtual_directories => true))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def store_folders(key, bucket = nil, options = {})
|
27
|
+
folders = key.split("/")
|
28
|
+
folders.slice!(0)
|
29
|
+
folders.pop
|
30
|
+
current_folder = "/"
|
31
|
+
folders.each {|folder|
|
32
|
+
current_folder += folder
|
33
|
+
store_folder(current_folder, bucket, options)
|
34
|
+
current_folder += "/"
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def store_folder(key, bucket = nil, options = {})
|
39
|
+
original_store(key + "_$folder$", "", bucket, options) # store the magic entry that emulates a folder
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|