poolparty 1.4.7 → 1.4.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.
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