cluster_chef 3.0.5

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 (46) hide show
  1. data/.gitignore +51 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +63 -0
  4. data/Gemfile +18 -0
  5. data/LICENSE +201 -0
  6. data/README.md +332 -0
  7. data/Rakefile +92 -0
  8. data/TODO.md +8 -0
  9. data/VERSION +1 -0
  10. data/chefignore +41 -0
  11. data/cluster_chef.gemspec +115 -0
  12. data/clusters/website_demo.rb +65 -0
  13. data/config/client.rb +59 -0
  14. data/lib/cluster_chef/chef_layer.rb +297 -0
  15. data/lib/cluster_chef/cloud.rb +409 -0
  16. data/lib/cluster_chef/cluster.rb +118 -0
  17. data/lib/cluster_chef/compute.rb +144 -0
  18. data/lib/cluster_chef/cookbook_munger/README.md.erb +47 -0
  19. data/lib/cluster_chef/cookbook_munger/licenses.yaml +16 -0
  20. data/lib/cluster_chef/cookbook_munger/metadata.rb.erb +23 -0
  21. data/lib/cluster_chef/cookbook_munger.rb +588 -0
  22. data/lib/cluster_chef/deprecated.rb +33 -0
  23. data/lib/cluster_chef/discovery.rb +158 -0
  24. data/lib/cluster_chef/dsl_object.rb +123 -0
  25. data/lib/cluster_chef/facet.rb +144 -0
  26. data/lib/cluster_chef/fog_layer.rb +134 -0
  27. data/lib/cluster_chef/private_key.rb +110 -0
  28. data/lib/cluster_chef/role_implications.rb +49 -0
  29. data/lib/cluster_chef/security_group.rb +103 -0
  30. data/lib/cluster_chef/server.rb +265 -0
  31. data/lib/cluster_chef/server_slice.rb +259 -0
  32. data/lib/cluster_chef/volume.rb +93 -0
  33. data/lib/cluster_chef.rb +137 -0
  34. data/notes/aws_console_screenshot.jpg +0 -0
  35. data/rspec.watchr +29 -0
  36. data/spec/cluster_chef/cluster_spec.rb +13 -0
  37. data/spec/cluster_chef/facet_spec.rb +70 -0
  38. data/spec/cluster_chef/server_slice_spec.rb +19 -0
  39. data/spec/cluster_chef/server_spec.rb +112 -0
  40. data/spec/cluster_chef_spec.rb +193 -0
  41. data/spec/spec_helper/dummy_chef.rb +25 -0
  42. data/spec/spec_helper.rb +50 -0
  43. data/spec/test_config.rb +20 -0
  44. data/tasks/chef_config.rb +38 -0
  45. data/tasks/jeweler_use_alt_branch.rb +47 -0
  46. metadata +227 -0
@@ -0,0 +1,409 @@
1
+ module ClusterChef
2
+ module Cloud
3
+
4
+ #
5
+ # Right now only one cloud provider is implemented, so the separation
6
+ # between `cloud` and `cloud(:ec2)` is muddy.
7
+ #
8
+ # The goal though is to allow
9
+ #
10
+ # * cloud with no predicate -- definitions that apply to all cloud
11
+ # providers. If you only use one provider ever nothing stops you from
12
+ # always saying `cloud`.
13
+ # * Declarations irrelevant to other providers are acceptable and will be ignored
14
+ # * Declarations that are wrong in the context of other providers (a `public_ip`
15
+ # that is not available) will presumably cause a downstream error -- it's
16
+ # your responsibility to overlay with provider-correct values.
17
+ # * There are several declarations that *could* be sensibly abstracted, but
18
+ # are not. Rather than specifying `flavor 'm1.xlarge'`, I could ask for
19
+ # :ram => 15, :cores => 4 or storage => 1500 and get the cheapest machine
20
+ # that met or exceeded each constraint -- the default of `:price =>
21
+ # :smallest` would get me a t1.micro on EC2, a 256MB on
22
+ # Rackspace. Availability zones could also plausibly be parameterized.
23
+ #
24
+ # @example
25
+ # # these apply regardless of cloud provider
26
+ # cloud do
27
+ # # this makes sense everywhere
28
+ # image_name 'maverick'
29
+ #
30
+ # # this is not offered by many providers, and its value is non-portable;
31
+ # # but if you only run in one cloud there's harm in putting it here
32
+ # # or overriding it.
33
+ # public_ip '1.2.3.4'
34
+ #
35
+ # # Implemented differently across providers but its meaning is clear
36
+ # security_group :nagios
37
+ #
38
+ # # This is harmless for the other clouds
39
+ # availability_zones ['us-east-1d']
40
+ # end
41
+ #
42
+ # # these only apply to ec2 launches.
43
+ # # `ec2` is sugar for `cloud(:ec2)`.
44
+ # ec2 do
45
+ # spot_price_fraction 0.4
46
+ # end
47
+ #
48
+ class Base < ClusterChef::DslObject
49
+ has_keys(
50
+ :name, :flavor, :image_name, :image_id, :keypair,
51
+ :chef_client_script, :public_ip, :permanent )
52
+ attr_accessor :owner
53
+
54
+ def initialize(owner, *args)
55
+ self.owner = owner
56
+ super(*args)
57
+ end
58
+
59
+ # default values to apply where no value was set
60
+ # @returns [Hash] hash of defaults
61
+ def defaults
62
+ reverse_merge!({
63
+ :image_name => 'maverick',
64
+ })
65
+ end
66
+
67
+ # The username to ssh with.
68
+ # @return the ssh_user if set explicitly; otherwise, the user implied by the image name, if any; or else 'root'
69
+ def ssh_user(val=nil)
70
+ from_setting_or_image_info :ssh_user, val, 'root'
71
+ end
72
+
73
+ # Location of ssh private keys
74
+ def ssh_identity_dir(val=nil)
75
+ set :ssh_identity_dir, File.expand_path(val) unless val.nil?
76
+ @settings.include?(:ssh_identity_dir) ? @settings[:ssh_identity_dir] : Chef::Config.ec2_key_dir
77
+ end
78
+
79
+ # SSH identity file used for knife ssh, knife boostrap and such
80
+ def ssh_identity_file(val=nil)
81
+ set :ssh_identity_file, File.expand_path(val) unless val.nil?
82
+ @settings.include?(:ssh_identity_file) ? @settings[:ssh_identity_file] : File.join(ssh_identity_dir, "#{keypair}.pem")
83
+ end
84
+
85
+ # ID of the machine image to use.
86
+ # @return the image_id if set explicitly; otherwise, the id implied by the image name
87
+ def image_id(val=nil)
88
+ from_setting_or_image_info :image_id, val
89
+ end
90
+
91
+ # Distribution knife should target when bootstrapping an instance
92
+ # @return the bootstrap_distro if set explicitly; otherwise, the bootstrap_distro implied by the image name
93
+ def bootstrap_distro(val=nil)
94
+ from_setting_or_image_info :bootstrap_distro, val, "ubuntu10.04-gems"
95
+ end
96
+
97
+ def validation_key
98
+ IO.read(Chef::Config.validation_key) rescue ''
99
+ end
100
+
101
+ # The instance price, drawn from the compute flavor's info
102
+ def price
103
+ flavor_info[:price]
104
+ end
105
+
106
+ # The instance bitness, drawn from the compute flavor's info
107
+ def bits
108
+ flavor_info[:bits]
109
+ end
110
+
111
+ protected
112
+ # If value was explicitly set, use that; if the Chef::Config[:ec2_image_info] implies a value use that; otherwise use the default
113
+ def from_setting_or_image_info(key, val=nil, default=nil)
114
+ @settings[key] = val unless val.nil?
115
+ return @settings[key] if @settings.include?(key)
116
+ return image_info[key] unless image_info.nil?
117
+ return default # otherwise
118
+ end
119
+ end
120
+
121
+ class Ec2 < Base
122
+ has_keys(
123
+ :region, :availability_zones, :backing,
124
+ :spot_price, :spot_price_fraction,
125
+ :user_data, :security_groups,
126
+ :monitoring
127
+ )
128
+
129
+ def initialize(*args)
130
+ super *args
131
+ @settings[:security_groups] ||= Mash.new
132
+ @settings[:user_data] ||= Mash.new
133
+ end
134
+
135
+ #
136
+ # Sets some defaults for amazon cloud usage, and registers the root volume
137
+ #
138
+ def defaults
139
+ owner.volume(:root).reverse_merge!({
140
+ :device => '/dev/sda1',
141
+ :mount_point => '/',
142
+ :mountable => false,
143
+ })
144
+ self.reverse_merge!({
145
+ :availability_zones => ['us-east-1d'],
146
+ :backing => 'ebs',
147
+ :flavor => 't1.micro',
148
+ })
149
+ super
150
+ end
151
+
152
+ # adds a security group to the cloud instance
153
+ def security_group(sg_name, hsh={}, &block)
154
+ sg_name = sg_name.to_s
155
+ security_groups[sg_name] ||= ClusterChef::Cloud::SecurityGroup.new(self, sg_name)
156
+ security_groups[sg_name].configure(hsh, &block)
157
+ security_groups[sg_name]
158
+ end
159
+
160
+ # With a value, sets the spot price to the given fraction of the
161
+ # instance's full price (as found in ClusterChef::Cloud::Aws::FLAVOR_INFO)
162
+ # With no value, returns the spot price as a fraction of the full instance price.
163
+ def spot_price_fraction(val=nil)
164
+ if val
165
+ spot_price( price.to_f * val )
166
+ else
167
+ spot_price / price rescue 0
168
+ end
169
+ end
170
+
171
+ # EC2 User data -- DNA typically used to bootstrap the machine.
172
+ # @param [Hash] value -- when present, merged with the existing user data (overriding it)
173
+ # @return the user_data hash
174
+ def user_data(hsh={})
175
+ @settings[:user_data].merge!(hsh.to_hash) unless hsh.empty?
176
+ @settings[:user_data]
177
+ end
178
+
179
+ def reverse_merge!(hsh)
180
+ super(hsh.to_mash.compact)
181
+ @settings[:security_groups].reverse_merge!(hsh.security_groups) if hsh.respond_to?(:security_groups)
182
+ @settings[:user_data ].reverse_merge!(hsh.user_data) if hsh.respond_to?(:user_data)
183
+ self
184
+ end
185
+
186
+ def region(val=nil)
187
+ set(:region, val)
188
+ if @settings[:region] then @settings[:region]
189
+ elsif default_availability_zone then default_availability_zone.gsub(/^(\w+-\w+-\d)[a-z]/, '\1')
190
+ else nil
191
+ end
192
+ end
193
+
194
+ def default_availability_zone
195
+ availability_zones.first if availability_zones
196
+ end
197
+
198
+ # Bring the ephemeral storage (local scratch disks) online
199
+ def mount_ephemerals(attrs={})
200
+ owner.volume(:ephemeral0, attrs){ device '/dev/sdb'; volume_id 'ephemeral0' ; mount_point '/mnt' ; tags( :bulk => true, :local => true, :fallback => true) } if flavor_info[:ephemeral_volumes] > 0
201
+ owner.volume(:ephemeral1, attrs){ device '/dev/sdc'; volume_id 'ephemeral1' ; mount_point '/mnt2'; tags( :bulk => true, :local => true, :fallback => true) } if flavor_info[:ephemeral_volumes] > 1
202
+ owner.volume(:ephemeral2, attrs){ device '/dev/sdd'; volume_id 'ephemeral2' ; mount_point '/mnt3'; tags( :bulk => true, :local => true, :fallback => true) } if flavor_info[:ephemeral_volumes] > 2
203
+ owner.volume(:ephemeral3, attrs){ device '/dev/sde'; volume_id 'ephemeral3' ; mount_point '/mnt4'; tags( :bulk => true, :local => true, :fallback => true) } if flavor_info[:ephemeral_volumes] > 3
204
+ end
205
+
206
+ # Utility methods
207
+
208
+ def image_info
209
+ Chef::Config[:ec2_image_info][ [region, bits, backing, image_name] ] or ui.warn "Make sure to define the machine's region, bits, backing and image_name. (Have #{[region, bits, backing, image_name].inspect})"
210
+ end
211
+
212
+ def list_images
213
+ ui.info("Available images:")
214
+ Chef::Config[:ec2_image_info].each do |flavor_name, flavor|
215
+ ui.info(" #{flavor_name}\t#{flavor.inspect}")
216
+ end
217
+ end
218
+
219
+ def flavor(val=nil)
220
+ warn("Unknown machine image name '#{val}'") if val && (not FLAVOR_INFO.has_key?(val.to_s))
221
+ set :flavor, val
222
+ end
223
+
224
+ def flavor_info
225
+ FLAVOR_INFO[flavor] or raise "Please define the machine's flavor: have #{self.inspect}"
226
+ end
227
+
228
+ def list_flavors
229
+ ui.info("Available flavors:")
230
+ FLAVOR_INFO.each do |flavor_name, flavor|
231
+ ui.info(" #{flavor_name}\t#{flavor.inspect}")
232
+ end
233
+ end
234
+
235
+ # code $/hr $/mo $/day CPU/$ Mem/$ mem cpu cores cpcore storage bits IO type name
236
+ # t1.micro $0.02 14 0.48 10.00 33.50 0.67 0.2 1 0.2 0 64 Low Micro Micro
237
+ # m1.small $0.085 61 2.04 11.76 20.00 1.7 1 1 1 160 32 Moderate Standard Small
238
+ # c1.medium $0.17 123 4.08 29.41 10.00 1.7 5 2 2.5 350 32 Moderate High-CPU Medium
239
+ # m1.large $0.34 246 8.16 11.76 22.06 7.5 4 2 2 850 64 High Standard Large
240
+ # m2.xlarge $0.50 363 12.00 13.00 35.40 17.7 6.5 2 3.25 420 64 Moderate High-Memory Extra Large
241
+ # c1.xlarge $0.68 493 16.32 29.41 10.29 7 20 8 2.5 1690 64 High High-CPU Extra Large
242
+ # m1.xlarge $0.68 493 16.32 11.76 22.06 15 8 4 2 1690 64 High Standard Extra Large
243
+ # m2.2xlarge $1.00 726 24.00 13.00 34.20 34.2 13 4 3.25 850 64 High High-Memory Double Extra Large
244
+ # m2.4xlarge $2.00 1452 48.00 13.00 34.20 68.4 26 8 3.25 1690 64 High High-Memory Quadruple Extra Large
245
+ # cc1.4xlarge $1.60 1161 38.40 20.94 14.38 23 33.5 2 16.75 1690 64 Very High 10GB Compute Quadruple Extra Large
246
+ # cg1.4xlarge $2.10 1524 50.40 15.95 10.48 22 33.5 2 16.75 1690 64 Very High 10GB Cluster GPU Quadruple Extra Large
247
+
248
+ FLAVOR_INFO = {
249
+ 't1.micro' => { :price => 0.02, :bits => '64-bit', :ram => 686, :cores => 1, :core_size => 0.25, :inst_disks => 0, :inst_disk_size => 0, :ephemeral_volumes => 0 },
250
+ 'm1.small' => { :price => 0.085, :bits => '32-bit', :ram => 1740, :cores => 1, :core_size => 1, :inst_disks => 1, :inst_disk_size => 160, :ephemeral_volumes => 1 },
251
+ 'c1.medium' => { :price => 0.17, :bits => '32-bit', :ram => 1740, :cores => 2, :core_size => 2.5, :inst_disks => 1, :inst_disk_size => 350, :ephemeral_volumes => 1 },
252
+ 'm1.large' => { :price => 0.34, :bits => '64-bit', :ram => 7680, :cores => 2, :core_size => 2, :inst_disks => 2, :inst_disk_size => 850, :ephemeral_volumes => 2 },
253
+ 'm2.xlarge' => { :price => 0.50, :bits => '64-bit', :ram => 18124, :cores => 2, :core_size => 3.25, :inst_disks => 1, :inst_disk_size => 420, :ephemeral_volumes => 1 },
254
+ 'c1.xlarge' => { :price => 0.68, :bits => '64-bit', :ram => 7168, :cores => 8, :core_size => 2.5, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
255
+ 'm1.xlarge' => { :price => 0.68, :bits => '64-bit', :ram => 15360, :cores => 4, :core_size => 2, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
256
+ 'm2.2xlarge' => { :price => 1.00, :bits => '64-bit', :ram => 35020, :cores => 4, :core_size => 3.25, :inst_disks => 2, :inst_disk_size => 850, :ephemeral_volumes => 2 },
257
+ 'm2.4xlarge' => { :price => 2.00, :bits => '64-bit', :ram => 70041, :cores => 8, :core_size => 3.25, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 4 },
258
+ 'cc1.4xlarge' => { :price => 1.60, :bits => '64-bit', :ram => 23552, :cores => 2, :core_size =>16.75, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 2 },
259
+ 'cg1.4xlarge' => { :price => 2.10, :bits => '64-bit', :ram => 22528, :cores => 2, :core_size =>16.75, :inst_disks => 4, :inst_disk_size => 1690, :ephemeral_volumes => 2 },
260
+ }
261
+
262
+ #
263
+ # To add to this list, use this snippet:
264
+ #
265
+ # Chef::Config[:ec2_image_info] ||= {}
266
+ # Chef::Config[:ec2_image_info].merge!({
267
+ # # ... lines like the below
268
+ # })
269
+ #
270
+ # in your knife.rb or whereever. We'll notice that it exists and add to it, rather than clobbering it.
271
+ #
272
+ Chef::Config[:ec2_image_info] ||= {}
273
+ Chef::Config[:ec2_image_info].merge!({
274
+
275
+ #
276
+ # Lucid (Ubuntu 9.10)
277
+ #
278
+ %w[us-east-1 64-bit instance karmic ] => { :image_id => 'ami-55739e3c', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
279
+ %w[us-east-1 32-bit instance karmic ] => { :image_id => 'ami-bb709dd2', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
280
+ %w[us-west-1 64-bit instance karmic ] => { :image_id => 'ami-cb2e7f8e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
281
+ %w[us-west-1 32-bit instance karmic ] => { :image_id => 'ami-c32e7f86', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
282
+ %w[eu-west-1 64-bit instance karmic ] => { :image_id => 'ami-05c2e971', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
283
+ %w[eu-west-1 32-bit instance karmic ] => { :image_id => 'ami-2fc2e95b', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
284
+
285
+ #
286
+ # Lucid (Ubuntu 10.04.3)
287
+ #
288
+ %w[ap-southeast-1 64-bit ebs lucid ] => { :image_id => 'ami-77f28d25', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
289
+ %w[ap-southeast-1 32-bit ebs lucid ] => { :image_id => 'ami-4df28d1f', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
290
+ %w[ap-southeast-1 64-bit instance lucid ] => { :image_id => 'ami-57f28d05', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
291
+ %w[ap-southeast-1 32-bit instance lucid ] => { :image_id => 'ami-a5f38cf7', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
292
+ %w[eu-west-1 64-bit ebs lucid ] => { :image_id => 'ami-ab4d67df', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
293
+ %w[eu-west-1 32-bit ebs lucid ] => { :image_id => 'ami-a94d67dd', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
294
+ %w[eu-west-1 64-bit instance lucid ] => { :image_id => 'ami-a54d67d1', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
295
+ %w[eu-west-1 32-bit instance lucid ] => { :image_id => 'ami-cf4d67bb', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
296
+ #
297
+ %w[us-east-1 64-bit ebs lucid ] => { :image_id => 'ami-4b4ba522', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
298
+ %w[us-east-1 32-bit ebs lucid ] => { :image_id => 'ami-714ba518', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
299
+ %w[us-east-1 64-bit instance lucid ] => { :image_id => 'ami-fd4aa494', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
300
+ %w[us-east-1 32-bit instance lucid ] => { :image_id => 'ami-2d4aa444', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
301
+ #
302
+ %w[us-west-1 64-bit ebs lucid ] => { :image_id => 'ami-d197c694', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
303
+ %w[us-west-1 32-bit ebs lucid ] => { :image_id => 'ami-cb97c68e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
304
+ %w[us-west-1 64-bit instance lucid ] => { :image_id => 'ami-c997c68c', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
305
+ %w[us-west-1 32-bit instance lucid ] => { :image_id => 'ami-c597c680', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
306
+
307
+ #
308
+ # Maverick (Ubuntu 10.10)
309
+ #
310
+ %w[ ap-southeast-1 64-bit ebs maverick ] => { :image_id => 'ami-32423c60', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
311
+ %w[ ap-southeast-1 64-bit instance maverick ] => { :image_id => 'ami-12423c40', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
312
+ %w[ ap-southeast-1 32-bit ebs maverick ] => { :image_id => 'ami-0c423c5e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
313
+ %w[ ap-southeast-1 32-bit instance maverick ] => { :image_id => 'ami-7c423c2e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
314
+ #
315
+ %w[ eu-west-1 64-bit ebs maverick ] => { :image_id => 'ami-e59ca991', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
316
+ %w[ eu-west-1 64-bit instance maverick ] => { :image_id => 'ami-1b9ca96f', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
317
+ %w[ eu-west-1 32-bit ebs maverick ] => { :image_id => 'ami-fb9ca98f', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
318
+ %w[ eu-west-1 32-bit instance maverick ] => { :image_id => 'ami-339ca947', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
319
+ #
320
+ %w[ us-east-1 64-bit ebs maverick ] => { :image_id => 'ami-cef405a7', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
321
+ %w[ us-east-1 64-bit instance maverick ] => { :image_id => 'ami-08f40561', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
322
+ %w[ us-east-1 32-bit ebs maverick ] => { :image_id => 'ami-ccf405a5', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
323
+ %w[ us-east-1 32-bit instance maverick ] => { :image_id => 'ami-a6f504cf', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
324
+ #
325
+ %w[ us-west-1 64-bit ebs maverick ] => { :image_id => 'ami-af7e2eea', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
326
+ %w[ us-west-1 64-bit instance maverick ] => { :image_id => 'ami-a17e2ee4', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
327
+ %w[ us-west-1 32-bit ebs maverick ] => { :image_id => 'ami-ad7e2ee8', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
328
+ %w[ us-west-1 32-bit instance maverick ] => { :image_id => 'ami-957e2ed0', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
329
+
330
+ #
331
+ # Natty (Ubuntu 11.04)
332
+ #
333
+ %w[ ap-northeast-1 32-bit ebs natty ] => { :image_id => 'ami-00b10501', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
334
+ %w[ ap-northeast-1 32-bit instance natty ] => { :image_id => 'ami-f0b004f1', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
335
+ %w[ ap-northeast-1 64-bit ebs natty ] => { :image_id => 'ami-02b10503', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
336
+ %w[ ap-northeast-1 64-bit instance natty ] => { :image_id => 'ami-fab004fb', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
337
+ #
338
+ %w[ ap-southeast-1 32-bit ebs natty ] => { :image_id => 'ami-06255f54', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
339
+ %w[ ap-southeast-1 32-bit instance natty ] => { :image_id => 'ami-72255f20', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
340
+ %w[ ap-southeast-1 64-bit ebs natty ] => { :image_id => 'ami-04255f56', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
341
+ %w[ ap-southeast-1 64-bit instance natty ] => { :image_id => 'ami-7a255f28', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
342
+ #
343
+ %w[ eu-west-1 32-bit ebs natty ] => { :image_id => 'ami-a4f7c5d0', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
344
+ %w[ eu-west-1 32-bit instance natty ] => { :image_id => 'ami-fef7c58a', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
345
+ %w[ eu-west-1 64-bit ebs natty ] => { :image_id => 'ami-a6f7c5d2', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
346
+ %w[ eu-west-1 64-bit instance natty ] => { :image_id => 'ami-c0f7c5b4', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
347
+ #
348
+ %w[ us-east-1 32-bit ebs natty ] => { :image_id => 'ami-e358958a', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
349
+ %w[ us-east-1 32-bit instance natty ] => { :image_id => 'ami-c15994a8', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
350
+ %w[ us-east-1 64-bit ebs natty ] => { :image_id => 'ami-fd589594', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
351
+ %w[ us-east-1 64-bit instance natty ] => { :image_id => 'ami-71589518', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
352
+ #
353
+ %w[ us-west-1 32-bit ebs natty ] => { :image_id => 'ami-43580406', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
354
+ %w[ us-west-1 32-bit instance natty ] => { :image_id => 'ami-e95f03ac', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
355
+ %w[ us-west-1 64-bit ebs natty ] => { :image_id => 'ami-4d580408', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
356
+ %w[ us-west-1 64-bit instance natty ] => { :image_id => 'ami-a15f03e4', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
357
+
358
+ #
359
+ # Oneric (Ubuntu 11.10)
360
+ #
361
+ %w[ ap-northeast-1 32-bit ebs oneric ] => { :image_id => 'ami-2e90242f', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
362
+ %w[ ap-northeast-1 32-bit instance oneric ] => { :image_id => 'ami-e49723e5', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
363
+ %w[ ap-northeast-1 64-bit ebs oneric ] => { :image_id => 'ami-30902431', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
364
+ %w[ ap-northeast-1 64-bit instance oneric ] => { :image_id => 'ami-fa9723fb', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
365
+ #
366
+ %w[ ap-southeast-1 32-bit ebs oneric ] => { :image_id => 'ami-76057f24', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
367
+ %w[ ap-southeast-1 32-bit instance oneric ] => { :image_id => 'ami-82047ed0', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
368
+ %w[ ap-southeast-1 64-bit ebs oneric ] => { :image_id => 'ami-7a057f28', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
369
+ %w[ ap-southeast-1 64-bit instance oneric ] => { :image_id => 'ami-54057f06', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
370
+ #
371
+ %w[ eu-west-1 32-bit ebs oneric ] => { :image_id => 'ami-65b28011', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
372
+ %w[ eu-west-1 32-bit instance oneric ] => { :image_id => 'ami-dfcdffab', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
373
+ %w[ eu-west-1 64-bit ebs oneric ] => { :image_id => 'ami-61b28015', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
374
+ %w[ eu-west-1 64-bit instance oneric ] => { :image_id => 'ami-75b28001', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
375
+ #
376
+ %w[ us-east-1 32-bit ebs oneric ] => { :image_id => 'ami-a7f539ce', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
377
+ %w[ us-east-1 32-bit instance oneric ] => { :image_id => 'ami-29f43840', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
378
+ %w[ us-east-1 64-bit ebs oneric ] => { :image_id => 'ami-bbf539d2', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
379
+ %w[ us-east-1 64-bit instance oneric ] => { :image_id => 'ami-21f53948', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
380
+ #
381
+ %w[ us-west-1 32-bit ebs oneric ] => { :image_id => 'ami-79772b3c', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
382
+ %w[ us-west-1 32-bit instance oneric ] => { :image_id => 'ami-a7762ae2', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
383
+ %w[ us-west-1 64-bit ebs oneric ] => { :image_id => 'ami-7b772b3e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
384
+ %w[ us-west-1 64-bit instance oneric ] => { :image_id => 'ami-4b772b0e', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
385
+ #
386
+ %w[ us-west-2 32-bit ebs oneric ] => { :image_id => 'ami-20f97410', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
387
+ %w[ us-west-2 32-bit instance oneric ] => { :image_id => 'ami-52f67b62', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
388
+ %w[ us-west-2 64-bit ebs oneric ] => { :image_id => 'ami-2af9741a', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
389
+ %w[ us-west-2 64-bit instance oneric ] => { :image_id => 'ami-56f67b66', :ssh_user => 'ubuntu', :bootstrap_distro => "ubuntu10.04-gems", },
390
+ })
391
+ end
392
+
393
+ class Slicehost < Base
394
+ # server_name
395
+ # slicehost_password
396
+ # Proc.new { |password| Chef::Config[:knife][:slicehost_password] = password }
397
+
398
+ # personality
399
+ end
400
+
401
+ class Rackspace < Base
402
+ # api_key, api_username, server_name
403
+ end
404
+
405
+ class Terremark < Base
406
+ # password, username, service
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,118 @@
1
+ module ClusterChef
2
+ #
3
+ # A cluster has many facets. Any setting applied here is merged with the facet
4
+ # at resolve time; if the facet explicitly sets any attributes they will win out.
5
+ #
6
+ class Cluster < ClusterChef::ComputeBuilder
7
+ attr_reader :facets, :undefined_servers
8
+
9
+ def initialize(name, attrs={})
10
+ super(name.to_sym, attrs)
11
+ @facets = Mash.new
12
+ @chef_roles = []
13
+ environment :_default if environment.blank?
14
+ create_cluster_role
15
+ create_cluster_security_group unless attrs[:no_security_group]
16
+ end
17
+
18
+ def cluster
19
+ self
20
+ end
21
+
22
+ def cluster_name
23
+ name
24
+ end
25
+
26
+ # The auto-generated role for this cluster.
27
+ # Instance-evals the given block in the context of that role
28
+ #
29
+ # @example
30
+ # cluster_role do
31
+ # override_attributes({
32
+ # :time_machine => { :transition_speed => 88 },
33
+ # })
34
+ # end
35
+ #
36
+ # @return [Chef::Role] The auto-generated role for this facet.
37
+ def cluster_role(&block)
38
+ @cluster_role.instance_eval( &block ) if block_given?
39
+ @cluster_role
40
+ end
41
+
42
+ #
43
+ # Retrieve or define the given facet
44
+ #
45
+ # @param [String] facet_name -- name of the desired facet
46
+ # @param [Hash] attrs -- attributes to configure on the object
47
+ # @yield a block to execute in the context of the object
48
+ #
49
+ # @return [ClusterChef::Facet]
50
+ #
51
+ def facet(facet_name, attrs={}, &block)
52
+ facet_name = facet_name.to_sym
53
+ @facets[facet_name] ||= ClusterChef::Facet.new(self, facet_name)
54
+ @facets[facet_name].configure(attrs, &block)
55
+ @facets[facet_name]
56
+ end
57
+
58
+ def has_facet? facet_name
59
+ @facets.include?(facet_name)
60
+ end
61
+
62
+ def find_facet(facet_name)
63
+ @facets[facet_name] or raise("Facet '#{facet_name}' is not defined in cluster '#{cluster_name}'")
64
+ end
65
+
66
+ # All servers in this facet, sorted by facet name and index
67
+ #
68
+ # @return [ClusterChef::ServerSlice] slice containing all servers
69
+ def servers
70
+ svrs = @facets.sort.map{|name, facet| facet.servers.to_a }
71
+ ClusterChef::ServerSlice.new(self, svrs.flatten)
72
+ end
73
+
74
+ #
75
+ # A slice of a cluster:
76
+ #
77
+ # If +facet_name+ is nil, returns all servers.
78
+ # Otherwise, takes slice (given by +*args+) from the requested facet.
79
+ #
80
+ # @param [String] facet_name -- facet to slice (or nil for all in cluster)
81
+ # @param [Array, String] slice_indexes -- servers in that facet (or nil for all in facet).
82
+ # You must specify a facet if you use slice_indexes.
83
+ #
84
+ # @return [ClusterChef::ServerSlice] the requested slice
85
+ def slice facet_name=nil, slice_indexes=nil
86
+ return ClusterChef::ServerSlice.new(self, self.servers) if facet_name.nil?
87
+ find_facet(facet_name).slice(slice_indexes)
88
+ end
89
+
90
+ def to_s
91
+ "#{super[0..-3]} @facets=>#{@facets.keys.inspect}}>"
92
+ end
93
+
94
+ #
95
+ # Resolve:
96
+ #
97
+ def resolve!
98
+ facets.values.each(&:resolve!)
99
+ end
100
+
101
+ protected
102
+
103
+ # Create a security group named for the cluster
104
+ # that is friends with everything in the cluster
105
+ def create_cluster_security_group
106
+ clname = self.name # put it in scope
107
+ cloud.security_group(clname){ authorize_group(clname) }
108
+ end
109
+
110
+ # Creates a chef role named for the cluster
111
+ def create_cluster_role
112
+ @cluster_role_name = "#{name}_cluster"
113
+ @cluster_role = new_chef_role(@cluster_role_name, cluster)
114
+ role(@cluster_role_name, :last)
115
+ end
116
+
117
+ end
118
+ end