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,133 @@
1
+ =begin rdoc
2
+ Basic callbacks
3
+ =end
4
+ module PoolParty
5
+ module Callbacks
6
+ module ClassMethods
7
+ def define_callback_module(mod)
8
+ callbacks << mod
9
+ end
10
+ def define_callback_class(cla)
11
+ classes << cla
12
+ end
13
+ def callback(type, m, *args, &block)
14
+ arr = []
15
+ args.each do |arg|
16
+ arr << case arg.class.to_s
17
+ when "Hash"
18
+ arg.collect do |meth, klass|
19
+ case klass.class.to_s
20
+ when "String"
21
+ define_callback_class(klass)
22
+ "self.#{klass.to_s.downcase}.#{meth}(self)"
23
+ else
24
+ "#{klass}.send :#{meth}, self"
25
+ end
26
+ end
27
+ when "Symbol"
28
+ "self.send :#{arg}, self"
29
+ end
30
+ end
31
+
32
+ string = ""
33
+ if block_given?
34
+ num = store_proc(block.to_proc)
35
+ arr << <<-EOM
36
+ self.class.get_proc(#{num}).bind(self).call
37
+ EOM
38
+ end
39
+
40
+ string = create_eval_for_mod_with_string_and_type!(m, type) do
41
+ arr.join("\n")
42
+ end
43
+
44
+ mMode = Module.new {eval string}
45
+
46
+ define_callback_module(mMode)
47
+ end
48
+ def before(m, *args, &block)
49
+ callback(:before, m, *args, &block)
50
+ end
51
+ def after(m, *args, &block)
52
+ callback(:after, m, *args, &block)
53
+ end
54
+
55
+ def create_eval_for_mod_with_string_and_type!(meth, type=nil, &block)
56
+ str = ""
57
+ case type
58
+ when :before
59
+ str << <<-EOD
60
+ def #{meth}(*args)
61
+ #{yield}
62
+ super
63
+ end
64
+ EOD
65
+ when :after
66
+ str << <<-EOD
67
+ def #{meth}(*args)
68
+ super
69
+ #{yield}
70
+ end
71
+ EOD
72
+ else
73
+ str << <<-EOD
74
+ def #{meth}(*args)
75
+ #{yield}
76
+ end
77
+ EOD
78
+ end
79
+ str
80
+ end
81
+
82
+ def callbacks
83
+ @callbacks ||= []
84
+ end
85
+ def classes
86
+ @classes ||= []
87
+ end
88
+ end
89
+
90
+ module InstanceMethods
91
+ def initialize(*args)
92
+ extend_callbacks
93
+ extend_callback_methods
94
+ end
95
+
96
+ def extend_callback_methods
97
+ unless self.class.classes.empty?
98
+ self.class.classes.each do |klass|
99
+ m = %{def #{klass.to_s.downcase};@#{klass.to_s.downcase} ||= #{klass}.new;end}
100
+ self.class.class_eval m unless self.class.method_defined?(m)
101
+ end
102
+ end
103
+ end
104
+
105
+ def extend_callbacks
106
+ unless self.class.callbacks.empty?
107
+ self.class.callbacks.each do |mod|
108
+ self.extend(mod)
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ module ProcStoreMethods
115
+ def store_proc(proc)
116
+ proc_storage << proc
117
+ proc_storage.index(proc)
118
+ end
119
+ def get_proc(num)
120
+ proc_storage[num]
121
+ end
122
+ def proc_storage
123
+ @proc_store ||= []
124
+ end
125
+ end
126
+
127
+ def self.included(receiver)
128
+ receiver.extend ClassMethods
129
+ receiver.extend ProcStoreMethods
130
+ receiver.send :include, InstanceMethods
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,82 @@
1
+ module PoolParty
2
+ extend self
3
+
4
+ module Ec2Wrapper
5
+
6
+ module ClassMethods
7
+ end
8
+
9
+ module InstanceMethods
10
+ # Run a new instance, with the user_data and the ami described in the config
11
+ def launch_new_instance!
12
+ instance = ec2.run_instances(
13
+ :image_id => Application.ami,
14
+ :user_data => "#{Application.launching_user_data}",
15
+ :minCount => 1,
16
+ :maxCount => 1,
17
+ :key_name => Application.keypair,
18
+ :size => "#{Application.size}")
19
+
20
+ item = instance.RunInstancesResponse.instancesSet.item
21
+ EC2ResponseObject.get_hash_from_response(item)
22
+ end
23
+ # Shutdown the instance by instance_id
24
+ def terminate_instance!(instance_id)
25
+ ec2.terminate_instances(:instance_id => instance_id)
26
+ end
27
+ def associate_address_with(ip, instance_id)
28
+ ec2.associate_address(:instance_id => instance_id, :public_ip => ip)
29
+ end
30
+ # Instance description
31
+ def describe_instance(id)
32
+ instance = ec2.describe_instances(:instance_id => id)
33
+ item = instance.DescribeInstancesResponse.reservationSet.item.instancesSet.item
34
+ EC2ResponseObject.get_hash_from_response(item)
35
+ end
36
+ # Get instance by id
37
+ def get_instance_by_id(id)
38
+ get_instances_description.select {|a| a.instance_id == id}[0] rescue nil
39
+ end
40
+ # Get the s3 description for the response in a hash format
41
+ def get_instances_description
42
+ @cached_descriptions ||= EC2ResponseObject.get_descriptions(ec2.describe_instances)
43
+ end
44
+
45
+ # EC2 connections
46
+ def ec2
47
+ @ec2 ||= EC2::Base.new(:access_key_id => Application.access_key, :secret_access_key => Application.secret_access_key)
48
+ end
49
+ end
50
+
51
+ def self.included(receiver)
52
+ receiver.extend ClassMethods
53
+ receiver.send :include, InstanceMethods
54
+ end
55
+ end
56
+ # Provides a simple class to wrap around the amazon responses
57
+ class EC2ResponseObject
58
+ def self.get_descriptions(resp)
59
+ rs = resp.DescribeInstancesResponse.reservationSet.item
60
+ rs = rs.respond_to?(:instancesSet) ? rs.instancesSet : rs
61
+ out = begin
62
+ rs.reject {|a| a.empty? }.collect {|r| EC2ResponseObject.get_hash_from_response(r.instancesSet.item)}.reject {|a| a.nil? }
63
+ rescue Exception => e
64
+ begin
65
+ # Really weird bug with amazon's ec2 gem
66
+ rs.reject {|a| a.empty? }.collect {|r| EC2ResponseObject.get_hash_from_response(r)}.reject {|a| a.nil? }
67
+ rescue Exception => e
68
+ []
69
+ end
70
+ end
71
+ out
72
+ end
73
+ def self.get_hash_from_response(resp)
74
+ {
75
+ :instance_id => resp.instanceId,
76
+ :ip => resp.dnsName,
77
+ :status => resp.instanceState.name,
78
+ :launching_time => resp.launchTime
79
+ } rescue nil
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+ =begin rdoc
2
+ Make a command thread-safe
3
+ =end
4
+ require "monitor"
5
+ module PoolParty
6
+ extend self
7
+
8
+ module ThreadSafeInstance
9
+
10
+ module ClassMethods
11
+ def make_safe(meth)
12
+ original_method = "_unsafe_#{meth}_"
13
+ alias_method original_method, meth
14
+ define_method(meth) {|*args| self.class.synchronize { self.send(original_method) } }
15
+ self
16
+ end
17
+ end
18
+
19
+ module InstanceMethods
20
+ def make_safe meth
21
+ self.class.make_safe meth
22
+ end
23
+ end
24
+
25
+ def self.included(receiver)
26
+ receiver.extend MonitorMixin
27
+ receiver.extend ClassMethods
28
+ receiver.send :include, InstanceMethods
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,82 @@
1
+ require "vlad"
2
+ class Rake::RemoteTask < Rake::Task
3
+ def run command
4
+ cmd = [ssh_cmd, ssh_flags, target_host, command].compact
5
+ result = []
6
+
7
+ warn cmd.join(' ') if $TRACE
8
+
9
+ pid, inn, out, err = popen4(*cmd.join(" "))
10
+
11
+ inn.sync = true
12
+ streams = [out, err]
13
+ out_stream = {
14
+ out => $stdout,
15
+ err => $stderr,
16
+ }
17
+
18
+ # Handle process termination ourselves
19
+ status = nil
20
+ Thread.start do
21
+ status = Process.waitpid2(pid).last
22
+ end
23
+
24
+ until streams.empty? do
25
+ # don't busy loop
26
+ selected, = select streams, nil, nil, 0.1
27
+
28
+ next if selected.nil? or selected.empty?
29
+
30
+ selected.each do |stream|
31
+ if stream.eof? then
32
+ streams.delete stream if status # we've quit, so no more writing
33
+ next
34
+ end
35
+
36
+ data = stream.readpartial(1024)
37
+ out_stream[stream].write data
38
+
39
+ if stream == err and data =~ /^Password:/ then
40
+ inn.puts sudo_password
41
+ data << "\n"
42
+ $stderr.write "\n"
43
+ end
44
+
45
+ result << data
46
+ end
47
+ end
48
+
49
+ PoolParty.message "execution failed with status #{status.exitstatus}: #{cmd.join ' '}" unless status.success?
50
+
51
+ result.join
52
+ end
53
+
54
+ def rsync local, remote
55
+ cmd = [rsync_cmd, rsync_flags, local, "#{@target_host}:#{remote}"].flatten.compact
56
+
57
+ success = system(*cmd.join(" "))
58
+
59
+ unless success then
60
+ raise Vlad::CommandFailedError, "execution failed: #{cmd.join ' '}"
61
+ end
62
+ end
63
+ def set name, val = nil, &b
64
+ rt.set name, val, &b
65
+ end
66
+ def rt
67
+ @rt ||= Rake::RemoteTask
68
+ end
69
+
70
+ def target_hosts
71
+ if hosts = ENV["HOSTS"] then
72
+ hosts.strip.gsub(/\s+/, '').split(",")
73
+ elsif options[:single]
74
+ @roles = {}; @roles[:app] = {}
75
+ @roles[:app][options[:single]] = options[:single]
76
+ roles = Rake::RemoteTask.hosts_for(@roles)
77
+ else
78
+ roles = options[:roles]
79
+ roles ? Rake::RemoteTask.hosts_for(roles) : Rake::RemoteTask.all_hosts
80
+ end
81
+ end
82
+ end
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,170 @@
1
+ =begin rdoc
2
+ Application
3
+ This handles user interaction
4
+ =end
5
+ module PoolParty
6
+ class Application
7
+ class << self
8
+ attr_accessor :verbose, :options
9
+
10
+ # The application options
11
+ def options(opts={})
12
+ @options ||= make_options(opts)
13
+ end
14
+ # Make the options with the config_file overrides included
15
+ # Default config file assumed to be at config/config.yml
16
+ def make_options(opts={})
17
+ loading_options = opts.delete(:optsparse) || {}
18
+ loading_options.merge!( {:argv => opts.delete(:argv)} )
19
+
20
+ load_options!(loading_options)
21
+ # default_options.merge!(opts)
22
+ # If the config_file options are specified and not empty
23
+ unless default_options[:config_file].nil? || default_options[:config_file].empty?
24
+ require "yaml"
25
+ # Try loading the file if it exists
26
+ filedata = open(default_options[:config_file]).read if File.file?(default_options[:config_file])
27
+ default_options.merge!( YAML.load(filedata) ) if filedata # We want the command-line to overwrite the config file
28
+ end
29
+
30
+ OpenStruct.new(default_options.merge(opts))
31
+ end
32
+
33
+ # Load options via commandline
34
+ def load_options!(opts={})
35
+ require 'optparse'
36
+ OptionParser.new do |op|
37
+ op.banner = opts[:banner] if opts[:banner]
38
+ op.on('-A key', '--access-key key', "Ec2 access key (ENV['ACCESS_KEY'])") { |key| default_options[:access_key] = key }
39
+ op.on('-S key', '--secret-access-key key', "Ec2 secret access key (ENV['SECRET_ACCESS_KEY'])") { |key| default_options[:secret_access_key] = key }
40
+ op.on('-I ami', '--image-id id', "AMI instance (default: 'ami-4a46a323')") {|id| default_options[:ami] = id }
41
+ op.on('-k keypair', '--keypair name', "Keypair name (ENV['KEYPAIR_NAME'])") { |key| default_options[:keypair] = key }
42
+ op.on('-b bucket', '--bucket bucket', "Application bucket") { |bucket| default_options[:shared_bucket] = bucket }
43
+ op.on('-D ec2 directory', '--ec2-dir dir', "Directory with ec2 data (default: '~/.ec2')") {|id| default_options[:ec2_dir] = id }
44
+ op.on('-r names', '--services names', "Monitored services (default: '')") {|id| default_options[:services] = id }
45
+ op.on('-c file', '--config-file file', "Config file (default: '')") {|file| default_options[:config_file] = file }
46
+ op.on('-l plugin_dir', '--plugin-dir dir', "Plugin directory (default: '')") {|file| default_options[:plugin_dir] = file }
47
+ op.on('-p port', '--host_port port', "Run on specific host_port (default: 7788)") { |host_port| default_options[:host_port] = host_port }
48
+ op.on('-m monitors', '--monitors names', "Monitor instances using (default: 'web,memory,cpu')") {|s| default_options[:monitor_load_on] = s }
49
+ op.on('-o port', '--client_port port', "Run on specific client_port (default: 7788)") { |client_port| default_options[:client_port] = client_port }
50
+ op.on('-O os', '--os os', "Configure for os (default: ubuntu)") { |os| default_options[:os] = os }
51
+ op.on('-e env', '--environment env', "Run on the specific environment (default: development)") { |env| default_options[:env] = env }
52
+ op.on('-a address', '--public-ip address', "Associate this public address with the master node") {|s| default_options[:public_ip] = s}
53
+ op.on('-s size', '--size size', "Run specific sized instance") {|s| default_options[:size] = s}
54
+ op.on('-n name', '--name name', "Application name") {|n| default_options[:app_name] = n}
55
+ op.on('-u username', '--username name', "Login with the user (default: root)") {|s| default_options[:user] = s}
56
+ op.on('-d user-data','--user-data data', "Extra data to send each of the instances (default: "")") { |data| default_options[:user_data] = data }
57
+ op.on('-t seconds', '--polling-time', "Time between polling in seconds (default 50)") {|t| default_options[:polling_time] = t }
58
+ op.on('-v', '--[no-]verbose', 'Run verbosely (default: false)') {|v| default_options[:verbose] = true}
59
+ op.on('-i number', '--minimum-instances', "The minimum number of instances to run at all times (default 1)") {|i| default_options[:minimum_instances] = i.to_i}
60
+ op.on('-x number', '--maximum-instances', "The maximum number of instances to run (default 3)") {|x| default_options[:maximum_instances] = x.to_i}
61
+
62
+ op.on_tail("-V", "Show version") do
63
+ puts Application.version
64
+ exit
65
+ end
66
+ op.on_tail("-h", "-?", "Show this message") do
67
+ puts op
68
+ exit
69
+ end
70
+ end.parse!(opts[:argv] ? opts.delete(:argv) : ARGV.dup)
71
+ end
72
+
73
+ # Basic default options
74
+ # All can be overridden by the command line
75
+ # or in a config.yml file
76
+ def default_options
77
+ @default_options ||= {
78
+ :app_name => "application_name",
79
+ :host_port => 80,
80
+ :client_port => 8001,
81
+ :environment => 'development',
82
+ :verbose => false,
83
+ :logging => true,
84
+ :size => "m1.small",
85
+ :polling_time => "30.seconds",
86
+ :user_data => "",
87
+ :heavy_load => 0.80,
88
+ :light_load => 0.15,
89
+ :minimum_instances => 2,
90
+ :maximum_instances => 4,
91
+ :public_ip => "",
92
+ :access_key => ENV["AWS_ACCESS_KEY_ID"],
93
+ :secret_access_key => ENV["AWS_SECRET_ACCESS_ID"],
94
+ :config_file => if ENV["CONFIG_FILE"] && !ENV["CONFIG_FILE"].empty?
95
+ ENV["CONFIG_FILE"]
96
+ elsif File.file?("config/config.yml")
97
+ "config/config.yml"
98
+ else
99
+ nil
100
+ end,
101
+ :username => "root",
102
+ :ec2_dir => ENV["EC2_HOME"],
103
+ :keypair => ENV["KEYPAIR_NAME"],
104
+ :ami => 'ami-4a46a323',
105
+ :shared_bucket => "",
106
+ :services => "",
107
+ :expand_when => "web_usage < 1.5\n memory > 0.85",
108
+ :contract_when => "cpu < 0.20\n memory < 0.10",
109
+ :os => "ubuntu",
110
+ :plugin_dir => "vendor",
111
+ :install_on_load => true
112
+ }
113
+ end
114
+ # Services monitored by Heartbeat
115
+ # Always at least monitors haproxy
116
+ def managed_services
117
+ "#{services}"
118
+ end
119
+ def master_managed_services
120
+ "cloud_master_takeover #{services}"
121
+ end
122
+ def launching_user_data
123
+ {:polling_time => polling_time}.to_yaml
124
+ end
125
+ # Keypair path
126
+ # Idiom:
127
+ # /Users/username/.ec2/id_rsa-name
128
+ def keypair_path
129
+ "#{ec2_dir}/id_rsa#{keypair ? "-#{keypair}" : "" }"
130
+ end
131
+ # Are we in development or test mode
132
+ %w(development production test).each do |env|
133
+ eval <<-EOE
134
+ def #{env}?
135
+ environment == '#{env}'
136
+ end
137
+ EOE
138
+ end
139
+ def environment=(env)
140
+ environment = env
141
+ end
142
+ def maintain_pid_path
143
+ "/var/run/pool_maintain.pid"
144
+ end
145
+ %w(scp_instances_script reconfigure_instances_script).each do |file|
146
+ define_method "sh_#{file}" do
147
+ File.join(File.dirname(__FILE__), "../..", "config", "#{file}.sh")
148
+ end
149
+ end
150
+ # Standard configuration files
151
+ %w(haproxy monit heartbeat heartbeat_authkeys).each do |file|
152
+ define_method "#{file}_config_file" do
153
+ File.join(File.dirname(__FILE__), "../..", "config", "#{file}.conf")
154
+ end
155
+ end
156
+ def version
157
+ PoolParty::Version::STRING
158
+ end
159
+ def install_on_load?
160
+ options.install_on_load == true
161
+ end
162
+ # Call the options from the Application
163
+ def method_missing(m,*args)
164
+ options.methods.include?("#{m}") ? options.send(m,args) : super
165
+ end
166
+ end
167
+
168
+ end
169
+
170
+ end