poolparty 1.4.7 → 1.4.8

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
+ :patch: 8
2
3
  :major: 1
3
- :minor: 4
4
4
  :build:
5
- :patch: 7
5
+ :minor: 4
data/bin/cloud CHANGED
@@ -31,7 +31,12 @@ EOS
31
31
  $DEBUGGING = true if command[:debug]
32
32
  $VERY_DEBUGGING = true if command[:very_debug]
33
33
 
34
- require command[:clouds_dot_rb]
34
+ begin
35
+ require command[:clouds_dot_rb]
36
+ rescue LoadError => e
37
+ puts "Failed loading #{command[:clouds_dot_rb]}, try using -c to specify the location of your clouds.rb"
38
+ exit
39
+ end
35
40
 
36
41
  @loaded_pool = pool
37
42
  @loaded_clouds = command[:name] ? [pool.clouds[command[:name]]] : pool.clouds.map {|name,cld|cld}
@@ -47,4 +52,4 @@ EOS
47
52
 
48
53
  See 'cloud help COMMAND' for more information on a specific command"
49
54
  end
50
- end
55
+ end
data/bin/cloud-console CHANGED
@@ -16,18 +16,31 @@ EOS
16
16
 
17
17
  run do |command|
18
18
 
19
- irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
20
-
21
- libs = " -r irb/completion"
22
- # Perhaps use a console_lib to store any extra methods I may want available in the cosole
23
- # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
24
- libs << " -r #{File.dirname(__FILE__) + '/../lib/poolparty.rb'}"
25
- f = command[:clouds_dot_rb]
26
- File.open("/tmp/console.rb", "w") {|f| f << "require '#{command[:clouds_dot_rb]}'\npool.auto_execute = false" }
27
- libs << " -r /tmp/console.rb"
28
-
29
19
  puts "Loading PoolParty console..."
30
- exec "#{irb} #{libs} --simple-prompt"
20
+ #exec "#{irb} #{libs} --simple-prompt"
21
+ require 'irb/completion'
22
+ require command[:clouds_dot_rb]
23
+ require "#{File.dirname(__FILE__) + '/../lib/poolparty.rb'}"
24
+ require 'irb'
25
+ pool.auto_execute = false
31
26
 
27
+ IRB.setup(nil)
28
+ IRB.conf[:IRB_NAME]="cloud"
29
+ IRB.conf[:PROMPT_MODE]=:CLOUD
30
+ IRB.conf[:PROMPT][:CLOUD]={
31
+ :PROMPT_I => "%N> ",
32
+ :PROMPT_S => "%l> ",
33
+ :PROMPT_C => "* ",
34
+ :PROMPT_N => ">> ",
35
+ :RETURN => "=>%s\n" }
36
+ irb=IRB::Irb.new
37
+ IRB.conf[:IRB_RC].call(irb.context) if IRB.conf[:IRB_RC]
38
+ IRB.conf[:MAIN_CONTEXT] = irb.context
39
+ trap("SIGINT") do
40
+ irb.signal_handle
41
+ end
42
+ catch(:IRB_EXIT) do
43
+ irb.eval_input
44
+ end
32
45
  end
33
- end
46
+ end
@@ -7,7 +7,8 @@ module CloudProviders
7
7
 
8
8
  default_options(
9
9
  :image_id => 'ami-ed46a784',
10
- :user => "root"
10
+ :user => "root",
11
+ :bootstrap_gems => []
11
12
  )
12
13
 
13
14
  attr_reader :name, :init_opts
@@ -61,4 +62,4 @@ module CloudProviders
61
62
  end
62
63
 
63
64
  end
64
- end
65
+ end
@@ -62,12 +62,12 @@ module CloudProviders
62
62
  return {:access_key => @access_key, :secret_access_key => @secret_access_key} if @access_key and @secret_access_key
63
63
  return {} if filename.nil? or not File.exists?(filename)
64
64
  puts("Reading keys from file: #{filename}")
65
- File.open(filename).each_line {|line|
66
- if line =~ /AWSAccessKeyId=([a-zA-Z0-9]+)$/
67
- @access_key=$1.chomp
68
- elsif line =~ /AWSSecretKey=([^ ]+)$/
69
- @secret_access_key=$1.chomp
70
- end
65
+ File.open(filename).each_line { |line|
66
+ if line =~ /AWSAccessKeyId=([a-zA-Z0-9]+)$/
67
+ @access_key=$1.chomp
68
+ elsif line =~ /AWSSecretKey=([^ ]+)$/
69
+ @secret_access_key=$1.chomp
70
+ end
71
71
  }
72
72
  return {:access_key => @access_key, :secret_access_key => @secret_access_key}
73
73
  end
@@ -92,8 +92,7 @@ module CloudProviders
92
92
  :addressing_type => nil,
93
93
  :kernel_id => nil,
94
94
  :ramdisk_id => nil,
95
- :block_device_mappings => nil,
96
- :ebs_volumes => [] # The volume id of an ebs volume # TODO: ensure this is consistent with :block_device_mappings
95
+ :block_device_mapping => [{}]
97
96
  )
98
97
 
99
98
  # Called when the create command is called on the cloud
@@ -174,6 +173,8 @@ module CloudProviders
174
173
  end
175
174
 
176
175
  assign_elastic_ips
176
+ puts "Attaching EBS volumes"
177
+ assign_ebs_volumes # Assign EBS volumes
177
178
  end
178
179
 
179
180
  def teardown
@@ -194,7 +195,8 @@ module CloudProviders
194
195
  :instance_type => instance_type,
195
196
  :availability_zone => availability_zones.first,
196
197
  :base64_encoded => true,
197
- :cloud => cloud
198
+ :cloud => cloud,
199
+ :block_device_mapping => block_device_mapping
198
200
  })
199
201
  progress_bar_until("Waiting for node to launch...") do
200
202
  wait_for_node(e)
@@ -283,8 +285,8 @@ module CloudProviders
283
285
  # Describe instances
284
286
  # Describe the instances that are available on this cloud
285
287
  # @params id (optional) if present, details about the instance
286
- # with the id given will be returned
287
- # if not given, details for all instances will be returned
288
+ # with the id given will be returned
289
+ # if not given, details for all instances will be returned
288
290
  def describe_instances(id=nil)
289
291
  begin
290
292
  @describe_instances = ec2.describe_instances.reservationSet.item.map do |r|
@@ -303,6 +305,10 @@ module CloudProviders
303
305
 
304
306
  # Extras!
305
307
 
308
+ def block_device_mapping(o=[], given_name=cloud.proper_name )
309
+ @mappings ||= o
310
+ end
311
+
306
312
  def load_balancer(given_name=cloud.proper_name, o={}, &block)
307
313
  load_balancers << ElasticLoadBalancer.new(given_name, sub_opts.merge(o || {}), &block)
308
314
  end
@@ -362,6 +368,25 @@ module CloudProviders
362
368
  @elastic_ips ||= []
363
369
  end
364
370
 
371
+ def ebs_volume_groups
372
+ @ebs_volume_groups ||= []
373
+ end
374
+
375
+ # dsl method for EBS volumes. E.G.:
376
+ # ebs_volumes do
377
+ # volumes "vol-001248ff", "vol-01ff4b85" # use existing volumes, not mandatory
378
+ # device "/dev/sdf"
379
+ # snapshot_id "snap-602030dd"
380
+ # size 200
381
+ # end
382
+ def ebs_volumes(name=nil, &block)
383
+ ebs_volume_groups << ElasticBlockStoreGroup.new(sub_opts,&block)
384
+ end
385
+
386
+ def assign_ebs_volumes
387
+ ebs_volume_groups.each{|ebs_volume_group| ebs_volume_group.attach(nodes)}
388
+ end
389
+
365
390
  def rds_instances
366
391
  @rds_instances ||= []
367
392
  end
@@ -371,11 +396,29 @@ module CloudProviders
371
396
  @nodes = @describe_instances = nil
372
397
  end
373
398
 
399
+ # Get existing volumes on EC2. filters is a hash of filters, either single valued or multivalued (value is an array of possible values).
400
+ # The function will return volumes matching *all* filters. A volume is a filter match if *any* one of the filter values equals the volume parameter value.
401
+ def list_ec2_volumes(filters=nil)
402
+ @volumes_on_ec2=ec2.describe_volumes.volumeSet.item unless @volumes_on_ec2
403
+ return @volumes_on_ec2 if filters.nil? # no filter to check, so return at once
404
+ @volumes_on_ec2.select{|vol| # select volumes for which no filter failed
405
+ not filters.map {|filter_key, filter_val|
406
+ filter_key=filter_key.to_s if filter_key.is_a?(Symbol) # filter_key may be given as a symbol
407
+ raise ArgumentError, "Filter key #{filter_key} is invalid" unless vol.has_key?(filter_key)
408
+ if filter_val.is_a?(Array) # Deal with multiple filter values
409
+ filter_val.map{|val| val.is_a?(String) ? val : val.to_s}.member?(vol[filter_key]) # make sure fiter_val array values are Strings before checking for match
410
+ else
411
+ filter_val.is_a?(String) ? filter_val : filter_val.to_s==vol[filter_key] # make sure fiter_val is a String before comparing
412
+ end
413
+ }.member?(false) # Check if a filter failed, the 'not' statement at the beginning of the map block negates this so 'select' will choose only when no filter failed
414
+ }.compact # remove nil results from volume set.
415
+ end
416
+
374
417
  # Read credentials from credential_file if one exists
375
418
  def credential_file(file=nil)
376
419
  unless file.nil?
377
- dsl_options[:credential_file]=file
378
- dsl_options.merge((Ec2.load_keys_from_credential_file(file)))
420
+ dsl_options[:credential_file]=file
421
+ dsl_options.merge((Ec2.load_keys_from_credential_file(file)))
379
422
  else
380
423
  fetch(:credential_file)
381
424
  end
@@ -410,7 +453,9 @@ require "#{File.dirname(__FILE__)}/helpers/ec2_helper"
410
453
  %w( security_group
411
454
  authorize
412
455
  elastic_auto_scaler
456
+ elastic_block_device_mapping
413
457
  elastic_block_store
458
+ elastic_block_store_group
414
459
  elastic_load_balancer
415
460
  elastic_ip
416
461
  rds_instance
@@ -9,7 +9,8 @@ module CloudProviders
9
9
  :public_ip => nil,
10
10
  :key_name => nil,
11
11
  :launch_time => nil,
12
- :availability_zones => []
12
+ :availability_zones => [],
13
+ :block_device_mapping => [{}]
13
14
  )
14
15
 
15
16
  def initialize(raw_response={})
@@ -25,6 +26,7 @@ module CloudProviders
25
26
  self.launch_time = raw_response["launchTime"] rescue nil
26
27
  self.availability_zones = raw_response["placement"]["availabilityZone"] rescue nil
27
28
  self.status = raw_response["instanceState"]["name"] rescue nil
29
+ self.block_device_mapping = raw_response["blockDeviceMapping"] rescue nil
28
30
  super
29
31
  end
30
32
 
@@ -53,6 +55,7 @@ module CloudProviders
53
55
  :user_data => user_data,
54
56
  :instance_type => instance_type,
55
57
  :availability_zone => availability_zone,
58
+ :block_device_mapping => block_device_mapping,
56
59
  :base64_encoded => true)
57
60
  r.instancesSet.item.map do |i|
58
61
  inst_options = i.merge(r.merge(:cloud => cloud)).merge(cloud.cloud_provider.dsl_options)
@@ -130,4 +133,4 @@ module CloudProviders
130
133
  end
131
134
 
132
135
  end
133
- end
136
+ end
@@ -44,4 +44,4 @@ module CloudProviders
44
44
  end
45
45
 
46
46
  end
47
- end
47
+ end
@@ -0,0 +1,7 @@
1
+ module CloudProviders
2
+ class ElasticBlockDeviceMapping < Ec2Helper
3
+ def initialize(name, init_opts={}, &block)
4
+ super
5
+ end
6
+ end
7
+ end
@@ -1,9 +1,66 @@
1
1
  module CloudProviders
2
- class ElasticBlockStore < Ec2Helper
3
-
4
- def run
5
- warn "ElasticBlockStore unimplemented as of now"
2
+ class ElasticBlockStore < Ec2Helper
3
+
4
+ # instance methods
5
+ attr_accessor :volumeId, :size, :snapshotId, :status, :attachments, :device, :availabilityZone, :instance_id
6
+ attr_reader :createTime
7
+
8
+ alias :volume_id :volumeId
9
+ alias :snapshot_id :snapshotId
10
+ alias :availability_zone :availabilityZone
11
+ alias :create_time :createTime
12
+
13
+ def createTime(create_time)
14
+ unless create_time.class==DateTime
15
+ @create_time=(DateTime.new(create_time) rescue nil)
16
+ else
17
+ @createTime=create_time
18
+ end
19
+ end
20
+ def initialize(raw_response,init_opts={},&block)
21
+ parse_raw_response(raw_response)
22
+ super(volumeId,init_opts,&block)
23
+ end
24
+
25
+ def parse_raw_response(raw_response)
26
+ @raw_respons = raw_response
27
+ raw_response.each{|k,v| send k+"=", v if respond_to?(k+"=") }
28
+ if raw_response.attachmentSet.respond_to?(:item)
29
+ @attachments=raw_response.attachmentSet.item
30
+ @attachments.each{|attch| instance_id=attch.instanceId if attch.status=="attached"}
31
+ end
32
+ end
33
+
34
+ def attached?(fn_instance_id=nil)
35
+ return false unless @status=="in-use" or @status=="attaching"
36
+ return true if fn_instance_id.nil?
37
+ return true if fn_instance_id == instance_id
38
+ return false
39
+ end
40
+
41
+ def available?
42
+ @status=="available"
43
+ end
44
+
45
+ def attach(ec2_instance,device)
46
+ ec2.attach_volume(:volume_id => volume_id, :instance_id => ec2_instance.instance_id, :device => device).return=="true"
47
+ end
48
+
49
+ def detach
50
+ ec2.detach_volume(:volume_id => volume_id).return=="true"
51
+ end
52
+
53
+ def detach!
54
+ ec2.detach_volume(:volume_id => volume_id, :force => true).return=="true"
55
+ end
56
+
57
+ def delete!
58
+ ec2.delete(:volume_id => volume_id).return == "true"
59
+ end
60
+
61
+ def update!
62
+ parse_raw_response ec2.describe_volumes(:volume_id => volume_id)
6
63
  end
7
64
 
8
65
  end
9
- end
66
+ end
@@ -0,0 +1,73 @@
1
+
2
+ module CloudProviders
3
+ # ElasticBlockStoreGroup class allows easy manipulation of EBS volumes matching defined criterias.
4
+ # Existing volumes in *cloud*'s availability zones that match the criterias will be selected for the group. When cloud instances need to attach EBS volumes from the group, the attach method should called.
5
+ # When attaching volumes the ElasticBlockStoreGroup will select existing (unattached) volumes until there are non, afterwhich the group will create new volumes according to the criterias given as needed.
6
+ #
7
+ # Currently, EBS volumes will not be deleted when tearing down a cloud. This is because poolparty is stateless and thus deleting drives from it will probably result in catastroph (deletions will be too general and delete stuff you don't want deleted).
8
+ # Hopefully, we will come up with a scheme for a deletion flag of some sort to solve this situation.
9
+ class ElasticBlockStoreGroup < Ec2Helper
10
+
11
+ default_options(:device => nil, :size => 0, :snapshot_id => nil)
12
+ alias :snapshotId :snapshot_id
13
+
14
+ def initialize(name=cloud.proper_name, init_opts={}, &block)
15
+ @volumes=[]
16
+ super
17
+ end
18
+ def after_initialized
19
+ unless @volumes.size > 0
20
+ filters={:size => size, :availabilityZone => availability_zones}
21
+ filters[:snapshotId]=snapshot_id if snapshot_id
22
+ @volumes=cloud.list_ec2_volumes filters
23
+ end
24
+ end
25
+ def volumes(*volume_ids)
26
+ return @volumes if volume_ids.size==0
27
+ volume_ids.each{|volume_id| @volumes << cloud.list_ec2_volumes(:volumeId => volume_id)}
28
+ end
29
+ def volumes_attached_to(instanceId)
30
+ @volumes.select {|vol| vol.attached?(instanceId)}
31
+ end
32
+
33
+ # get volumes that are not attached
34
+ def free_volumes(availability_zone)
35
+ @volumes.select{|vol| vol.available? and vol.availability_zone == availability_zone}
36
+ end
37
+ # Get a free volume from existing volumes in group or create a new one
38
+ def get_free_volume(availability_zone)
39
+ free=free_volumes(availability_zone)
40
+ if free.size>=1
41
+ return free[0]
42
+ end
43
+ create(availability_zone)
44
+ end
45
+
46
+ # Create new volume on availability_zone
47
+ def create(availability_zone)
48
+ options={:availability_zone => availability_zone, :size => size.to_s}
49
+ options[:snapshot_id]=snapshot_id if snapshot_id
50
+ vol=ElasticBlockStore.new(ec2.create_volume(options),:cloud => cloud)
51
+ @volumes<<vol
52
+ vol
53
+ end
54
+
55
+ def attach(nodes)
56
+ nodes.each{|node|
57
+ # Check no volumes are attached to node on device
58
+ skip_node=false
59
+ cloud.list_ec2_volumes.each{|vol|
60
+ if vol.attached?(node.instance_id)and vol.device == device
61
+ warn "A volume is allready attached to device #{device} of instance #{node.instance_id}"
62
+ skip_node = true
63
+ end
64
+ }
65
+ unless skip_node
66
+ vol=get_free_volume(node.zone)
67
+ vol.device=device
68
+ vol.attach(node,device)
69
+ end
70
+ }
71
+ end
72
+ end
73
+ end
@@ -47,8 +47,8 @@ module CloudProviders
47
47
  'apt-get autoremove -y',
48
48
  'apt-get install -y ruby ruby-dev rubygems git-core',
49
49
  'gem sources -a http://gems.opscode.com',
50
- 'gem install chef ohai --no-rdoc --no-ri'
51
- ])
50
+ 'gem install chef ohai --no-rdoc --no-ri' ] +
51
+ bootstrap_gems.collect { |gem| "gem install #{gem} --no-rdoc --no-ri" } )
52
52
  end
53
53
  end
54
54
 
@@ -138,4 +138,4 @@ module CloudProviders
138
138
  end
139
139
 
140
140
  end
141
- end
141
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poolparty
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.7
4
+ version: 1.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Lerner
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2010-01-13 00:00:00 -08:00
14
+ date: 2010-01-27 00:00:00 -08:00
15
15
  default_executable:
16
16
  dependencies: []
17
17
 
@@ -250,7 +250,9 @@ files:
250
250
  - lib/cloud_providers/ec2/helpers/authorize.rb
251
251
  - lib/cloud_providers/ec2/helpers/ec2_helper.rb
252
252
  - lib/cloud_providers/ec2/helpers/elastic_auto_scaler.rb
253
+ - lib/cloud_providers/ec2/helpers/elastic_block_device_mapping.rb
253
254
  - lib/cloud_providers/ec2/helpers/elastic_block_store.rb
255
+ - lib/cloud_providers/ec2/helpers/elastic_block_store_group.rb
254
256
  - lib/cloud_providers/ec2/helpers/elastic_ip.rb
255
257
  - lib/cloud_providers/ec2/helpers/elastic_load_balancer.rb
256
258
  - lib/cloud_providers/ec2/helpers/rds_instance.rb