auser-poolparty 0.1.2 → 0.2.2

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 (199) hide show
  1. data/History.txt +22 -0
  2. data/License.txt +20 -0
  3. data/README.txt +52 -0
  4. data/Rakefile +4 -109
  5. data/bin/cloud +31 -0
  6. data/bin/cloud-add-keypair +23 -0
  7. data/bin/cloud-configure +35 -0
  8. data/bin/cloud-contract +27 -0
  9. data/bin/cloud-expand +27 -0
  10. data/bin/cloud-list +32 -0
  11. data/bin/cloud-maintain +36 -0
  12. data/bin/cloud-provision +30 -0
  13. data/bin/cloud-reconfigure +24 -0
  14. data/bin/cloud-ssh +18 -0
  15. data/bin/cloud-start +29 -0
  16. data/bin/pool +23 -75
  17. data/bin/pool-console +12 -0
  18. data/bin/pool-describe +9 -0
  19. data/bin/pool-list +28 -0
  20. data/bin/pool-provision +34 -0
  21. data/bin/pool-spec +17 -0
  22. data/bin/pool-start +32 -0
  23. data/examples/basic.rb +20 -0
  24. data/examples/plugin_without_plugin_directory.rb +13 -0
  25. data/examples/poolparty.rb +12 -0
  26. data/examples/with_apache_plugin.rb +22 -0
  27. data/generators/poolspec/USAGE +5 -0
  28. data/generators/poolspec/poolspec_generator.rb +65 -0
  29. data/generators/poolspec/templates/pool_spec_template.erb +9 -0
  30. data/lib/erlang/eb_server.erl +27 -0
  31. data/lib/poolparty.rb +40 -116
  32. data/lib/poolparty/base_packages/haproxy.rb +41 -0
  33. data/lib/poolparty/base_packages/heartbeat.rb +43 -0
  34. data/lib/poolparty/base_packages/poolparty.rb +18 -0
  35. data/lib/poolparty/base_packages/ruby.rb +27 -0
  36. data/lib/poolparty/core/array.rb +24 -0
  37. data/lib/{core → poolparty/core}/exception.rb +0 -0
  38. data/lib/{core → poolparty/core}/float.rb +0 -0
  39. data/lib/poolparty/core/hash.rb +29 -0
  40. data/lib/poolparty/core/kernel.rb +34 -0
  41. data/lib/{core → poolparty/core}/module.rb +18 -0
  42. data/lib/poolparty/core/my_open_struct.rb +18 -0
  43. data/lib/poolparty/core/object.rb +54 -0
  44. data/lib/poolparty/core/proc.rb +2 -0
  45. data/lib/poolparty/core/string.rb +72 -0
  46. data/lib/poolparty/core/symbol.rb +8 -0
  47. data/lib/{core → poolparty/core}/time.rb +15 -0
  48. data/lib/poolparty/exceptions/RemoteException.rb +12 -0
  49. data/lib/poolparty/exceptions/ResourceException.rb +7 -0
  50. data/lib/poolparty/exceptions/RuntimeException.rb +7 -0
  51. data/lib/poolparty/exceptions/SpecException.rb +7 -0
  52. data/lib/poolparty/exceptions/TemplateNotFound.rb +7 -0
  53. data/lib/poolparty/helpers/binary.rb +30 -0
  54. data/lib/poolparty/helpers/console.rb +30 -0
  55. data/lib/poolparty/helpers/display.rb +25 -0
  56. data/lib/poolparty/helpers/optioner.rb +61 -0
  57. data/lib/poolparty/helpers/provisioner_base.rb +226 -0
  58. data/lib/poolparty/helpers/provisioners/master.rb +120 -0
  59. data/lib/poolparty/helpers/provisioners/slave.rb +52 -0
  60. data/lib/poolparty/modules/cloud_resourcer.rb +72 -0
  61. data/lib/poolparty/modules/configurable.rb +34 -0
  62. data/lib/poolparty/modules/definable_resource.rb +59 -0
  63. data/lib/poolparty/modules/file_writer.rb +55 -0
  64. data/lib/poolparty/modules/method_missing_sugar.rb +17 -0
  65. data/lib/poolparty/modules/output.rb +13 -0
  66. data/lib/poolparty/modules/pretty_printer.rb +38 -0
  67. data/lib/{core/string.rb → poolparty/modules/s3_string.rb} +5 -29
  68. data/lib/{modules → poolparty/modules}/safe_instance.rb +0 -0
  69. data/lib/poolparty/monitors/base_monitor.rb +16 -0
  70. data/lib/poolparty/net/remote.rb +35 -0
  71. data/lib/poolparty/net/remote_bases/ec2.rb +145 -0
  72. data/lib/poolparty/net/remote_instance.rb +68 -0
  73. data/lib/poolparty/net/remoter.rb +209 -0
  74. data/lib/poolparty/net/remoter_base.rb +117 -0
  75. data/lib/poolparty/plugins/gem_package.rb +39 -0
  76. data/lib/poolparty/plugins/line.rb +76 -0
  77. data/lib/poolparty/plugins/svn.rb +48 -0
  78. data/lib/poolparty/pool/base.rb +74 -0
  79. data/lib/poolparty/pool/cloud.rb +132 -0
  80. data/lib/poolparty/pool/custom_resource.rb +61 -0
  81. data/lib/poolparty/pool/loggable.rb +29 -0
  82. data/lib/poolparty/pool/plugin.rb +42 -0
  83. data/lib/poolparty/pool/plugin_model.rb +48 -0
  84. data/lib/poolparty/pool/pool.rb +55 -0
  85. data/lib/poolparty/pool/resource.rb +235 -0
  86. data/lib/poolparty/pool/resources/class_package.rb +60 -0
  87. data/lib/poolparty/pool/resources/cron.rb +14 -0
  88. data/lib/poolparty/pool/resources/directory.rb +23 -0
  89. data/lib/poolparty/pool/resources/exec.rb +26 -0
  90. data/lib/poolparty/pool/resources/file.rb +23 -0
  91. data/lib/poolparty/pool/resources/gem.rb +14 -0
  92. data/lib/poolparty/pool/resources/host.rb +14 -0
  93. data/lib/poolparty/pool/resources/package.rb +14 -0
  94. data/lib/poolparty/pool/resources/remote_file.rb +20 -0
  95. data/lib/poolparty/pool/resources/service.rb +21 -0
  96. data/lib/poolparty/pool/resources/sshkey.rb +19 -0
  97. data/lib/poolparty/pool/resources/variable.rb +27 -0
  98. data/lib/poolparty/pool/script.rb +21 -0
  99. data/{config/heartbeat_authkeys.conf → lib/poolparty/templates/authkeys} +0 -0
  100. data/lib/poolparty/templates/cib.xml +1 -0
  101. data/lib/poolparty/templates/fileserver.conf +4 -0
  102. data/{config/heartbeat.conf → lib/poolparty/templates/ha.cf} +3 -1
  103. data/{config → lib/poolparty/templates}/haproxy.conf +13 -6
  104. data/lib/poolparty/templates/namespaceauth.conf +19 -0
  105. data/lib/poolparty/templates/puppet.conf +13 -0
  106. data/lib/poolparty/version.rb +9 -0
  107. data/lib/poolpartycl.rb +3 -0
  108. data/script/destroy +14 -0
  109. data/script/generate +14 -0
  110. data/script/txt2html +82 -0
  111. data/{lib/poolparty/tasks → tasks}/cloud.rake +1 -1
  112. data/tasks/deployment.rake +34 -0
  113. data/tasks/development.rake +78 -0
  114. data/{lib/poolparty/tasks → tasks}/ec2.rake +1 -1
  115. data/tasks/environment.rake +7 -0
  116. data/{lib/poolparty/tasks → tasks}/instance.rake +0 -0
  117. data/{lib/poolparty/tasks → tasks}/server.rake +0 -0
  118. data/tasks/spec.rake +17 -0
  119. data/tasks/website.rake +17 -0
  120. metadata +154 -249
  121. data/CHANGELOG +0 -23
  122. data/LICENSE +0 -22
  123. data/README +0 -139
  124. data/assets/clouds.png +0 -0
  125. data/bin/instance +0 -68
  126. data/bin/poolnotify +0 -34
  127. data/config/cloud_master_takeover +0 -17
  128. data/config/create_proxy_ami.sh +0 -582
  129. data/config/installers/ubuntu_install.sh +0 -77
  130. data/config/monit.conf +0 -9
  131. data/config/monit/haproxy.monit.conf +0 -8
  132. data/config/monit/nginx.monit.conf +0 -0
  133. data/config/nginx.conf +0 -24
  134. data/config/reconfigure_instances_script.sh +0 -37
  135. data/config/sample-config.yml +0 -23
  136. data/config/scp_instances_script.sh +0 -12
  137. data/lib/core/array.rb +0 -16
  138. data/lib/core/hash.rb +0 -11
  139. data/lib/core/kernel.rb +0 -12
  140. data/lib/core/object.rb +0 -21
  141. data/lib/core/proc.rb +0 -15
  142. data/lib/helpers/plugin_spec_helper.rb +0 -58
  143. data/lib/modules/callback.rb +0 -133
  144. data/lib/modules/ec2_wrapper.rb +0 -108
  145. data/lib/modules/file_writer.rb +0 -38
  146. data/lib/modules/sprinkle_overrides.rb +0 -27
  147. data/lib/modules/vlad_override.rb +0 -83
  148. data/lib/poolparty/application.rb +0 -199
  149. data/lib/poolparty/init.rb +0 -6
  150. data/lib/poolparty/master.rb +0 -492
  151. data/lib/poolparty/monitors.rb +0 -11
  152. data/lib/poolparty/monitors/cpu.rb +0 -23
  153. data/lib/poolparty/monitors/memory.rb +0 -33
  154. data/lib/poolparty/monitors/web.rb +0 -29
  155. data/lib/poolparty/optioner.rb +0 -20
  156. data/lib/poolparty/plugin.rb +0 -78
  157. data/lib/poolparty/provider.rb +0 -104
  158. data/lib/poolparty/provider/essential.rb +0 -6
  159. data/lib/poolparty/provider/git.rb +0 -8
  160. data/lib/poolparty/provider/haproxy.rb +0 -9
  161. data/lib/poolparty/provider/heartbeat.rb +0 -6
  162. data/lib/poolparty/provider/rsync.rb +0 -8
  163. data/lib/poolparty/provider/ruby.rb +0 -65
  164. data/lib/poolparty/provider/s3fuse.rb +0 -22
  165. data/lib/poolparty/remote_instance.rb +0 -250
  166. data/lib/poolparty/remoter.rb +0 -171
  167. data/lib/poolparty/remoting.rb +0 -137
  168. data/lib/poolparty/scheduler.rb +0 -93
  169. data/lib/poolparty/tasks.rb +0 -47
  170. data/lib/poolparty/tasks/development.rake +0 -78
  171. data/lib/poolparty/tasks/plugins.rake +0 -30
  172. data/lib/poolparty/thread_pool.rb +0 -94
  173. data/lib/s3/s3_object_store_folders.rb +0 -44
  174. data/poolparty.gemspec +0 -71
  175. data/spec/files/describe_response +0 -37
  176. data/spec/files/multi_describe_response +0 -69
  177. data/spec/files/remote_desc_response +0 -37
  178. data/spec/helpers/ec2_mock.rb +0 -57
  179. data/spec/lib/core/core_spec.rb +0 -26
  180. data/spec/lib/core/kernel_spec.rb +0 -24
  181. data/spec/lib/core/string_spec.rb +0 -28
  182. data/spec/lib/modules/callback_spec.rb +0 -213
  183. data/spec/lib/modules/file_writer_spec.rb +0 -74
  184. data/spec/lib/poolparty/application_spec.rb +0 -135
  185. data/spec/lib/poolparty/ec2_wrapper_spec.rb +0 -110
  186. data/spec/lib/poolparty/master_spec.rb +0 -479
  187. data/spec/lib/poolparty/optioner_spec.rb +0 -34
  188. data/spec/lib/poolparty/plugin_spec.rb +0 -115
  189. data/spec/lib/poolparty/poolparty_spec.rb +0 -60
  190. data/spec/lib/poolparty/provider_spec.rb +0 -74
  191. data/spec/lib/poolparty/remote_instance_spec.rb +0 -178
  192. data/spec/lib/poolparty/remoter_spec.rb +0 -72
  193. data/spec/lib/poolparty/remoting_spec.rb +0 -148
  194. data/spec/lib/poolparty/scheduler_spec.rb +0 -70
  195. data/spec/monitors/cpu_monitor_spec.rb +0 -39
  196. data/spec/monitors/memory_spec.rb +0 -51
  197. data/spec/monitors/misc_monitor_spec.rb +0 -51
  198. data/spec/monitors/web_spec.rb +0 -40
  199. data/spec/spec_helper.rb +0 -53
@@ -1,32 +1,4 @@
1
- class String
2
- def hasherize(format=[])
3
- hash = {}
4
- i = 0
5
- self.split(%r{[\n|\t|\s| ]+}).collect {|a| a.strip}.each do |f|
6
- break unless format[i]
7
- unless f == "" || f.nil?
8
- hash[format[i]] = f
9
- i+=1
10
- end
11
- end
12
- hash
13
- end
14
- def ^(h={})
15
- self.gsub(/:([\w]+)/) {h[$1.to_sym] if h.include?($1.to_sym)}
16
- end
17
- def arrayable
18
- self.strip.split(/\n/)
19
- end
20
- def runnable(quite=true)
21
- # map {|l| l << "#{" >/dev/null 2>/dev/null" if quite}" }.
22
- self.strip.split(/\n/).join(" && ")
23
- end
24
- def nice_runnable(quite=true)
25
- self.split(/ && /).join("\n")
26
- end
27
- def classify
28
- self.capitalize
29
- end
1
+ module S3String
30
2
  def bucket_objects
31
3
  AWS::S3::Bucket.objects(self)
32
4
  end
@@ -53,4 +25,8 @@ class String
53
25
  def delete_bucket
54
26
  AWS::S3::Bucket.delete(self, :force => true) if bucket_exists?
55
27
  end
28
+ end
29
+
30
+ class String
31
+ include S3String
56
32
  end
File without changes
@@ -0,0 +1,16 @@
1
+ =begin rdoc
2
+ Monitor class
3
+
4
+ TODO: Fill this out
5
+ =end
6
+ module PoolParty
7
+ module Monitors
8
+
9
+ class BaseMonitor
10
+
11
+
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + "/remoter_base"
2
+ require File.dirname(__FILE__) + "/remoter"
3
+
4
+ module PoolParty
5
+ module Remote
6
+
7
+ include PoolParty::Remote::Remoter
8
+
9
+ def using(t)
10
+ if available_bases.include?(t.to_sym)
11
+ unless using_remoter? || t.nil?
12
+ self.class.send :attr_reader, :remote_base
13
+ mod = "#{t}".preserved_module_constant
14
+
15
+ mod.send :include, PoolParty::Remote::RemoterBase
16
+ self.class.send :include, mod
17
+ self.extend mod
18
+
19
+ @remote_base = "#{t}".preserved_module_constant
20
+ end
21
+ else
22
+ puts "Unknown remote base"
23
+ end
24
+ end
25
+
26
+ def available_bases
27
+ remote_bases
28
+ end
29
+
30
+ def using_remoter?
31
+ @remote_base ||= nil
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,145 @@
1
+ require "ec2"
2
+ class String
3
+ def convert_from_ec2_to_ip
4
+ self.gsub(/.compute-1.amazonaws.com*/, '').gsub(/ec2-/, '').gsub(/-/, '.')
5
+ end
6
+ end
7
+ module PoolParty
8
+ module Ec2
9
+ def launch_new_instance!
10
+ instance = ec2.run_instances(
11
+ :image_id => self.respond_to?(:ami) ? ami : Base.ami,
12
+ :user_data => "",
13
+ :minCount => 1,
14
+ :maxCount => 1,
15
+ :key_name => "#{self.respond_to?(:keypair) ? keypair : Base.keypair}",
16
+ :availability_zone => nil,
17
+ :size => "#{self.respond_to?(:size) ? size : Base.size}")
18
+ begin
19
+ item = instance#.instancesSet.item
20
+ EC2ResponseObject.get_hash_from_response(item)
21
+ rescue Exception => e
22
+ end
23
+ end
24
+ # Terminate an instance by id
25
+ def terminate_instance!(instance_id=nil)
26
+ ec2.terminate_instances(:instance_id => instance_id)
27
+ end
28
+ # Describe an instance's status
29
+ def describe_instance(id=nil)
30
+ describe_instances.select {|a| a[:name] == id}[0] rescue nil
31
+ end
32
+ def describe_instances
33
+ unless @describe_instances && !@describe_instances.empty?
34
+ @id = 0
35
+ @describe_instances = get_instances_description.each_with_index do |h,i|
36
+ if h[:status] == "running"
37
+ @name = "node#{@id}"
38
+ @id += 1
39
+ else
40
+ @name = "#{h[:status]}_node#{i}"
41
+ end
42
+ h.merge!({
43
+ :name => @name,
44
+ :hostname => h[:ip],
45
+ :ip => h[:ip].convert_from_ec2_to_ip
46
+ })
47
+ end
48
+ @describe_instances.first[:name] = "master" unless @describe_instances.empty?
49
+ end
50
+ @describe_instances
51
+ end
52
+ # Get the s3 description for the response in a hash format
53
+ def get_instances_description
54
+ @cached_descriptions ||= EC2ResponseObject.get_descriptions(ec2.describe_instances).sort_by {|a| a[:launching_time]}
55
+ end
56
+
57
+ # Help create a keypair for the cloud
58
+ # This is a helper to create the keypair and add them to the cloud for you
59
+ def create_keypair
60
+ return false unless keypair
61
+ FileUtils.mkdir_p ::File.dirname(new_keypair_path) unless ::File.directory?(::File.dirname(new_keypair_path))
62
+ Kernel.system "ec2-add-keypair #{keypair} > #{new_keypair_path} && chmod 600 #{new_keypair_path}"
63
+ end
64
+ # EC2 connections
65
+ def ec2
66
+ @ec2 ||= EC2::Base.new( :access_key_id => (access_key || Base.access_key),
67
+ :secret_access_key => (secret_access_key || Base.secret_access_key)
68
+ )
69
+ end
70
+
71
+ # Callback
72
+ def custom_install_tasks_for(o)
73
+ [
74
+ "# ec2 installation tasks",
75
+ "# Set hostname",
76
+ # "if [ -z $(grep -v '#' /etc/hosts | grep '#{o.name}') ]; then echo \"$(curl http://169.254.169.254/latest/meta-data/public-ipv4) #{o.name}\" >> /etc/hosts; fi",
77
+ "if [ -z \"$(grep -v '#' /etc/hosts | grep '#{o.name}')\" ]; then echo '127.0.0.1 #{o.name}' >> /etc/hosts; fi",
78
+ "hostname #{o.name}",
79
+ "echo #{o.name} > /etc/hostname"
80
+ ]
81
+ end
82
+
83
+ def custom_configure_tasks_for(o)
84
+ [
85
+ "# ec2 configuration"
86
+ ]
87
+ end
88
+
89
+ def reset!
90
+ @describe_instances = @cached_descriptions = nil
91
+ end
92
+ end
93
+ register_remote_base :Ec2
94
+ end
95
+
96
+ # Provides a simple class to wrap around the amazon responses
97
+ class EC2ResponseObject
98
+ def self.get_descriptions(resp)
99
+ rs = get_response_from(resp)
100
+
101
+ # puts rs.methods.sort - rs.ancestors.methods
102
+ out = begin
103
+ if rs.respond_to?(:instancesSet)
104
+ [EC2ResponseObject.get_hash_from_response(rs.instancesSet.item)]
105
+ else
106
+ rs.collect {|r|
107
+ if r.instancesSet.item.class == Array
108
+ r.instancesSet.item.map {|t| EC2ResponseObject.get_hash_from_response(t)}
109
+ else
110
+ [EC2ResponseObject.get_hash_from_response(r.instancesSet.item)]
111
+ end
112
+ }.flatten.reject {|a| a.nil? }
113
+ end
114
+ rescue Exception => e
115
+ # Really weird bug with amazon's ec2 gem
116
+ rs.collect {|r| EC2ResponseObject.get_hash_from_response(r)}.reject {|a| a.nil? } rescue []
117
+ end
118
+
119
+ out
120
+ end
121
+ def self.get_response_from(resp)
122
+ begin
123
+ rs = resp.reservationSet.item unless resp.reservationSet.nil?
124
+ rs ||= resp.DescribeInstancesResponse.reservationSet.item
125
+ rs ||= rs.respond_to?(:instancesSet) ? rs.instancesSet : rs
126
+ rs.reject! {|a| a.nil? || a.empty? }
127
+ rescue Exception => e
128
+ end
129
+ rs
130
+ end
131
+ def self.get_hash_from_response(resp)
132
+ begin
133
+ {
134
+ :instance_id => resp.instanceId,
135
+ :name => resp.instanceId,
136
+ :ip => resp.dnsName || "not-assigned",
137
+ :status => resp.instanceState.name,
138
+ :launching_time => resp.launchTime,
139
+ :keypair => resp.keyName
140
+ }
141
+ rescue Exception => e
142
+ nil
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + "/remoter"
2
+
3
+ module PoolParty
4
+ module Remote
5
+
6
+ class RemoteInstance
7
+ include Remote
8
+ include Configurable
9
+ include CloudResourcer
10
+
11
+ def initialize(opts, parent=self)
12
+ set_parent(parent) if parent
13
+ set_vars_from_options(opts) unless opts.empty?
14
+ on_init
15
+ end
16
+
17
+ # Callback
18
+ def on_init
19
+ end
20
+
21
+ # Is this remote instance the master?
22
+ def master?
23
+ name == "master"
24
+ end
25
+
26
+ # The remote instances is only valid if there is an ip and a name
27
+ def valid?
28
+ !(ip.nil? || name.nil?)
29
+ end
30
+
31
+ # Determine if the RemoteInstance is responding
32
+ def responding?
33
+ !responding.nil?
34
+ end
35
+
36
+ # This is how we get the current load of the instance
37
+ # The approach of this may change entirely, but the usage of
38
+ # it will always be the same
39
+ def load
40
+ current_load ||= 0.0
41
+ end
42
+
43
+ # Is this instance running?
44
+ def running?
45
+ !(status =~ /running/).nil?
46
+ end
47
+ # Is this instance pending?
48
+ def pending?
49
+ !(status =~ /pending/).nil?
50
+ end
51
+ # Is this instance terminating?
52
+ def terminating?
53
+ !(status =~ /shutting/).nil?
54
+ end
55
+ # Has this instance been terminated?
56
+ def terminated?
57
+ !(status =~ /terminated/).nil?
58
+ end
59
+
60
+ # Printing. This is how we extract the instances into the listing on the
61
+ # local side into the local listing file
62
+ def to_s
63
+ "#{name} #{ip}"
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,209 @@
1
+ =begin rdoc
2
+ This module is included by the remote module and defines the remoting methods
3
+ that the clouds can use to rsync or run remote commands
4
+ =end
5
+ require File.dirname(__FILE__) + "/../helpers/provisioner_base"
6
+
7
+ module PoolParty
8
+ module Remote
9
+ module Remoter
10
+ def rsync_storage_files_to_command(remote_instance)
11
+ if remote_instance
12
+ "#{rsync_command} #{Base.storage_directory} #{remote_instance.ip}:#{Base.remote_storage_path}"
13
+ end
14
+ end
15
+ def run_command_on_command(cmd="ls -l", remote_instance=nil)
16
+ "#{ssh_command(remote_instance)} '#{cmd}'"
17
+ end
18
+ def ssh_command(remote_instance)
19
+ "#{ssh_string} #{remote_instance.ip}"
20
+ end
21
+ # Generic commandable strings
22
+ def ssh_string
23
+ (["ssh"] << ssh_array).join(" ")
24
+ end
25
+ # Array of ssh options
26
+ # Includes StrictHostKeyChecking to no
27
+ # Ssh with the user in Base
28
+ # And including the keypair_path
29
+ def ssh_array
30
+ ["-o StrictHostKeyChecking=no", "-l '#{Base.user}'", '-i "'+full_keypair_path+'"']
31
+ end
32
+ def rsync_command
33
+ "rsync --delete -azP --exclude cache -e '#{ssh_string}'"
34
+ end
35
+ # Open the cached local copy of the instances list and
36
+ # create a new RemoteInstance from each line
37
+ def list_from_local
38
+ list_file = get_working_listing_file
39
+ if list_file
40
+ out = returning Array.new do |instances|
41
+ open(list_file).read.split("\n").each do |line|
42
+ instances << RemoteInstance.new(line)
43
+ end
44
+ end
45
+ else
46
+ out = list_from_remote(:cache => true)
47
+ end
48
+ return out
49
+ end
50
+ # List the instances that are known from the remoter_base
51
+ # Create a RemoteInstance for each of the instances from the hash
52
+ # returned by the list of instances, write them to the cached file
53
+ # and then return the array of instances
54
+ def list_from_remote(options={})
55
+ out_array = get_remote_nodes
56
+ write_to_file( local_instances_list_file_locations.first, out_array.map{|a| a.to_s }.join("\n")) if options[:cache]
57
+ out_array
58
+ end
59
+ # Get the names of the nodes. Mainly used for puppet templating
60
+ def list_of_node_names(options={})
61
+ list_of_running_instances.collect {|ri| ri.name }
62
+ end
63
+ # An array of node ips. Mainly used for puppet templating
64
+ def list_of_node_ips(options={})
65
+ list_of_running_instances.collect {|ri| ri.ip }
66
+ end
67
+ def get_remote_nodes
68
+ returning Array.new do |instances|
69
+ list_of_instances(respond_to?(:keypair) ? keypair : nil).each do |h|
70
+ instances << PoolParty::Remote::RemoteInstance.new(h)
71
+ end
72
+ end
73
+ end
74
+ # Get the instance first instance file that exists on the system from the expected places
75
+ # denoted in the local_instances_list_file_locations
76
+ def get_working_listing_file
77
+ local_instances_list_file_locations.reject {|f| f unless File.file?(f) }.first
78
+ end
79
+ # Expected places for the instances.list to be located at on the machine
80
+ def local_instances_list_file_locations
81
+ [
82
+ "#{Base.storage_directory}/#{name}-instances.list",
83
+ "#{Base.base_config_directory}/#{name}-instances.list",
84
+ "~/.#{name}-instances.list",
85
+ "~/#{name}-instances.list",
86
+ "#{name}-instances.list"
87
+ ]
88
+ end
89
+
90
+ # More functional methods
91
+ # Are the minimum number of instances running?
92
+ def minimum_number_of_instances_are_running?
93
+ list_of_running_instances.size >= minimum_instances
94
+ end
95
+ # Can we shutdown an instance?
96
+ def can_shutdown_an_instance?
97
+ list_of_running_instances.size > minimum_instances
98
+ end
99
+ # Request to launch a number of instances
100
+ def request_launch_new_instances(num=1)
101
+ out = []
102
+ num.times {out << launch_new_instance!}
103
+ out
104
+ end
105
+ # Let's terminate an instance that is not the master instance
106
+ def request_termination_of_non_master_instance
107
+ inst = nonmaster_nonterminated_instances.last
108
+ terminate_instance!(inst.instance_id) if inst
109
+ end
110
+ # Can we start a new instance?
111
+ def can_start_a_new_instance?
112
+ maximum_number_of_instances_are_not_running?
113
+ end
114
+ # Are the maximum number of instances running?
115
+ def maximum_number_of_instances_are_not_running?
116
+ list_of_running_instances.size < maximum_instances
117
+ end
118
+ # Launch new instance while waiting for the number of pending instances
119
+ # to be zero before actually launching. This ensures that we only
120
+ # launch one instance at a time
121
+ def request_launch_one_instance_at_a_time
122
+ when_no_pending_instances do
123
+ launch_new_instance!
124
+ end
125
+ end
126
+ # A convenience method for waiting until there are no more
127
+ # pending instances and then running the block
128
+ def when_no_pending_instances(&block)
129
+ reset!
130
+ if list_of_pending_instances.size > 0
131
+ wait "5.seconds"
132
+ when_no_pending_instances(&block)
133
+ else
134
+ block.call if block
135
+ end
136
+ end
137
+
138
+ # This will launch the minimum_instances if the minimum number of instances are not running
139
+ # If the minimum number of instances are not running and if we can start a new instance
140
+ def launch_minimum_number_of_instances
141
+ if can_start_a_new_instance?
142
+ while !minimum_number_of_instances_are_running?
143
+ request_launch_one_instance_at_a_time
144
+ wait "5.seconds"
145
+ end
146
+ end
147
+ end
148
+ # Stub method for the time being to handle expansion of the cloud
149
+ def should_expand_cloud?(force=false)
150
+ force || false
151
+ end
152
+ # Stub method for the time being to handle the contraction of the cloud
153
+ def should_contract_cloud?(force=false)
154
+ force || false
155
+ end
156
+ # Expand the cloud
157
+ # If we can start a new instance and the load requires us to expand
158
+ # the cloud, then we should request_launch_new_instances
159
+ # Wait for the instance to boot up and when it does come back
160
+ # online, then provision it as a slave, this way, it is ready for action from the
161
+ # get go
162
+ def expand_cloud_if_necessary(force=false)
163
+ if can_start_a_new_instance? && should_expand_cloud?(force)
164
+ @out = request_launch_new_instances(1)
165
+
166
+ reset!
167
+ when_no_pending_instances do
168
+ @ri = list_of_running_instances.last
169
+ PoolParty::Provisioner.provision_slave(@ri, self, !force)
170
+ end
171
+ end
172
+ end
173
+ # Contract the cloud
174
+ # If we can shutdown an instnace and the load allows us to contract
175
+ # the cloud, then we should request_termination_of_non_master_instance
176
+ def contract_cloud_if_necessary(force=false)
177
+ if can_shutdown_an_instance?
178
+ request_termination_of_non_master_instance if should_contract_cloud?(force)
179
+ end
180
+ end
181
+
182
+ # Rsync command to the instance
183
+ def rsync_storage_files_to(instance=nil)
184
+ hide_output do
185
+ Kernel.system "#{rsync_storage_files_to_command(instance)}" if instance
186
+ end
187
+ end
188
+ # Take the rsync command and execute it on the system
189
+ # if there is an instance given
190
+ def run_command_on(cmd, instance=nil)
191
+ Kernel.system "#{run_command_on_command(cmd, instance)}" if instance
192
+ end
193
+
194
+ # Ssh into the instance given
195
+ def ssh_into(instance=nil)
196
+ Kernel.system "#{ssh_command(instance)}" if instance
197
+ end
198
+ # Find the instance by the number given
199
+ # and then ssh into the instance
200
+ def ssh_into_instance_number(num=0)
201
+ ssh_into( get_instance_by_number( num || 0 ) )
202
+ end
203
+
204
+ def self.included(receiver)
205
+ receiver.extend self
206
+ end
207
+ end
208
+ end
209
+ end