deltacloud-core 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/deltacloud.rb +1 -0
  2. data/lib/deltacloud/backend_capability.rb +21 -0
  3. data/lib/deltacloud/base_driver/base_driver.rb +6 -0
  4. data/lib/deltacloud/base_driver/features.rb +16 -0
  5. data/lib/deltacloud/base_driver/mock_driver.rb +25 -5
  6. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +137 -15
  7. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +4 -7
  8. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +116 -3
  9. data/lib/deltacloud/drivers/mock/mock_driver.rb +56 -2
  10. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +5 -19
  11. data/lib/deltacloud/helpers/application_helper.rb +22 -2
  12. data/lib/deltacloud/models/instance.rb +22 -5
  13. data/lib/deltacloud/models/key.rb +16 -0
  14. data/lib/deltacloud/models/{tag.rb → load_balancer.rb} +14 -18
  15. data/lib/sinatra/rabbit.rb +3 -0
  16. data/parse.rb +7 -0
  17. data/public/javascripts/application.js +10 -24
  18. data/public/stylesheets/compiled/application.css +2 -0
  19. data/server.rb +141 -15
  20. data/test.rb +3 -0
  21. data/views/blobs/new.html.haml +10 -0
  22. data/views/blobs/show.html.haml +21 -15
  23. data/views/buckets/index.html.haml +1 -1
  24. data/views/buckets/show.html.haml +5 -2
  25. data/views/errors/backend_capability_failure.html.haml +11 -0
  26. data/views/errors/backend_capability_failure.xml.haml +4 -0
  27. data/views/errors/not_allowed.html.haml +6 -0
  28. data/views/errors/not_allowed.xml.haml +2 -0
  29. data/views/instances/index.html.haml +1 -1
  30. data/views/instances/new.html.haml +8 -0
  31. data/views/instances/show.html.haml +1 -1
  32. data/views/keys/index.html.haml +1 -1
  33. data/views/load_balancers/index.html.haml +33 -0
  34. data/views/load_balancers/index.xml.haml +5 -0
  35. data/views/load_balancers/new.html.haml +38 -0
  36. data/views/load_balancers/show.html.haml +37 -0
  37. data/views/load_balancers/show.xml.haml +21 -0
  38. data/views/storage_snapshots/index.xml.haml +0 -2
  39. data/views/storage_snapshots/show.xml.haml +0 -2
  40. data/views/storage_volumes/index.xml.haml +6 -6
  41. data/views/storage_volumes/show.xml.haml +7 -7
  42. metadata +48 -36
  43. data/views/tags/index.html.haml +0 -1
@@ -15,6 +15,7 @@ require 'deltacloud/models/storage_snapshot'
15
15
  require 'deltacloud/models/storage_volume'
16
16
  require 'deltacloud/models/bucket'
17
17
  require 'deltacloud/models/blob'
18
+ require 'deltacloud/models/load_balancer'
18
19
 
19
20
  require 'deltacloud/validation'
20
21
  require 'deltacloud/helpers'
@@ -0,0 +1,21 @@
1
+ module Deltacloud::BackendCapability
2
+
3
+ class Failure < StandardError
4
+ attr_reader :capability
5
+ def initialize(capability, msg='')
6
+ super(msg)
7
+ @capability = capability
8
+ end
9
+ end
10
+
11
+ attr_reader :capability
12
+ def with_capability(capability)
13
+ @capability = capability
14
+ end
15
+
16
+ def check_capability(backend)
17
+ if capability and !backend.respond_to?(capability)
18
+ raise Failure.new(capability, "#{capability} capability not supported by backend #{backend.class.name}")
19
+ end
20
+ end
21
+ end
@@ -215,6 +215,12 @@ module Deltacloud
215
215
  def blob_data(credentials, bucket_id, blob_id, opts)
216
216
  end
217
217
 
218
+ def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
219
+ end
220
+
221
+ def delete_blob(credentials, bucket_id, blob_id, opts=nil)
222
+ end
223
+
218
224
  def filter_on(collection, attribute, opts)
219
225
  return collection if opts.nil?
220
226
  return collection if opts[attribute].nil?
@@ -143,6 +143,14 @@ module Deltacloud
143
143
  end
144
144
  end
145
145
 
146
+ declare_feature :instances, :security_group do
147
+ description "Put instance in one or more security groups on launch"
148
+ operation :create do
149
+ param :security_group, :array, :optional, nil,
150
+ "Array of security group names"
151
+ end
152
+ end
153
+
146
154
  declare_feature :instances, :authentication_key do
147
155
  operation :create do
148
156
  param :keyname, :string, :optional, nil
@@ -169,5 +177,13 @@ module Deltacloud
169
177
  param :location, :string, :optional
170
178
  end
171
179
  end
180
+
181
+ declare_feature :instances, :register_to_load_balancer do
182
+ description "Register instance to load balancer"
183
+ operation :create do
184
+ param :load_balancer_id, :string, :optional
185
+ end
186
+ end
187
+
172
188
  end
173
189
  end
@@ -16,6 +16,19 @@ module Mock
16
16
  MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'tests', 'ec2', 'support'))
17
17
  end
18
18
 
19
+ class ELB < AWS::ELB::Base
20
+ include MethodSerializer::Cache
21
+
22
+ def self.cached_methods
23
+ [
24
+ :describe_load_balancers
25
+ ]
26
+ end
27
+
28
+ MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'tests', 'ec2', 'support'))
29
+
30
+ end
31
+
19
32
  class EC2 < AWS::EC2::Base
20
33
 
21
34
  include MethodSerializer::Cache
@@ -44,11 +57,18 @@ Deltacloud::Drivers::EC2::EC2Driver.class_eval do
44
57
  alias_method :original_new_client, :new_client
45
58
  alias_method :original_s3_client, :s3_client
46
59
 
47
- def new_client(credentials, opts={})
48
- Mock::EC2.new(
49
- :access_key_id => credentials.user,
50
- :secret_access_key => credentials.password
51
- )
60
+ def new_client(credentials, provider = :ec2)
61
+ if provider == :elb
62
+ Mock::ELB.new(
63
+ :access_key_id => credentials.user,
64
+ :secret_access_key => credentials.password
65
+ )
66
+ else
67
+ Mock::EC2.new(
68
+ :access_key_id => credentials.user,
69
+ :secret_access_key => credentials.password
70
+ )
71
+ end
52
72
  end
53
73
 
54
74
  def s3_client(credentials)
@@ -22,29 +22,21 @@ require 'active_support'
22
22
  require 'AWS'
23
23
  require 'right_aws'
24
24
 
25
- class Instance
26
- attr_accessor :keyname
27
- attr_accessor :authn_error
28
-
29
- def authn_feature_failed?
30
- return true unless authn_error.nil?
31
- end
32
-
33
- end
34
-
35
25
  module Deltacloud
36
26
  module Drivers
37
27
  module EC2
38
28
  class EC2Driver < Deltacloud::BaseDriver
39
29
 
40
30
  def supported_collections
41
- DEFAULT_COLLECTIONS + [ :keys, :buckets ]
31
+ DEFAULT_COLLECTIONS + [ :keys, :buckets, :load_balancers ]
42
32
  end
43
33
 
44
34
  feature :instances, :user_data
45
35
  feature :instances, :authentication_key
36
+ feature :instances, :security_group
46
37
  feature :images, :owner_id
47
38
  feature :buckets, :bucket_location
39
+ feature :instances, :register_to_load_balancer
48
40
 
49
41
  define_hardware_profile('m1.small') do
50
42
  cpu 1
@@ -192,9 +184,18 @@ class EC2Driver < Deltacloud::BaseDriver
192
184
  :monitoring_enabled => true,
193
185
  :instance_type => hwp.name,
194
186
  :disable_api_termination => false,
195
- :instance_initiated_shutdown_behavior => 'terminate'
187
+ :instance_initiated_shutdown_behavior => 'terminate',
188
+ :security_group => opts[:security_group]
196
189
  )
197
- return convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
190
+ new_instance = convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
191
+ if opts[:load_balancer_id] and opts[:load_balancer_id]!=""
192
+ elb = new_client(credentials, :elb)
193
+ elb.register_instances_with_load_balancer({
194
+ :instances => [new_instance.id],
195
+ :load_balancer_name => opts[:load_balancer_id]
196
+ })
197
+ end
198
+ return new_instance
198
199
  end
199
200
  end
200
201
 
@@ -402,19 +403,140 @@ class EC2Driver < Deltacloud::BaseDriver
402
403
  end
403
404
  end
404
405
 
406
+ #--
407
+ # Create Blob
408
+ #--
409
+ def create_blob(credentials, bucket_id, blob_id, data = nil, opts = nil)
410
+ s3_client = s3_client(credentials)
411
+ #data is a construct with the temporary file created by server @.tempfile
412
+ #also file[:type] will give us the content-type
413
+ res = s3_client.interface.put(bucket_id, blob_id, data.tempfile, {"Content-Type" => data[:type]})
414
+ #create a new Blob object and return that
415
+ Blob.new( { :id => blob_id,
416
+ :bucket => bucket_id,
417
+ :content_length => data.tempfile.length,
418
+ :content_type => data[:type],
419
+ :last_modified => ''
420
+ }
421
+ )
422
+ end
423
+
424
+ #--
425
+ # Delete Blob
426
+ #--
427
+ def delete_blob(credentials, bucket_id, blob_id, opts=nil)
428
+ s3_client = s3_client(credentials)
429
+ s3_client.interface.delete(bucket_id, blob_id)
430
+ end
431
+
432
+ def load_balancer(credentials, opts={})
433
+ load_balancers(credentials, {
434
+ :load_balancer_names => [opts[:id]]
435
+ }).first
436
+ end
437
+
438
+ def load_balancers(credentials, opts=nil)
439
+ ec2 = new_client( credentials, :elb )
440
+ result = []
441
+ safely do
442
+ loadbalancers = ec2.describe_load_balancers(opts || {})
443
+ return [] unless loadbalancers.DescribeLoadBalancersResult.LoadBalancerDescriptions
444
+ loadbalancers.DescribeLoadBalancersResult.LoadBalancerDescriptions.member.each do |loadbalancer|
445
+ result << convert_load_balancer(credentials, loadbalancer)
446
+ end
447
+ end
448
+ return result
449
+ end
450
+
451
+ def create_load_balancer(credentials, opts={})
452
+ ec2 = new_client( credentials, :elb )
453
+ safely do
454
+ ec2.create_load_balancer({
455
+ :load_balancer_name => opts['name'],
456
+ # TODO: Add possibility to push more listeners/realms in one request
457
+ # Something like 'Hash' in 'Array' parameter
458
+ :availability_zones => [opts['realm_id']],
459
+ :listeners => [{
460
+ :protocol => opts['listener_protocol'],
461
+ :load_balancer_port => opts['listener_balancer_port'],
462
+ :instance_port => opts['listener_instance_port']
463
+ }]
464
+ })
465
+ return load_balancer(credentials, opts['name'])
466
+ end
467
+ end
468
+
469
+ def destroy_load_balancer(credentials, id)
470
+ ec2 = new_client( credentials, :elb )
471
+ safely do
472
+ ec2.delete_load_balancer({
473
+ :load_balancer_name => id
474
+ })
475
+ end
476
+ end
477
+
478
+ def lb_register_instance(credentials, opts={})
479
+ ec2 = new_client( credentials, :elb)
480
+ safely do
481
+ ec2.register_instances_with_load_balancer(:instances => [opts[:instance_id]],
482
+ :load_balancer_name => opts[:id])
483
+ load_balancer(credentials, :id => opts[:id])
484
+ end
485
+ end
486
+
487
+ def lb_unregister_instance(credentials, opts={})
488
+ ec2 = new_client( credentials, :elb)
489
+ safely do
490
+ ec2.deregister_instances_from_load_balancer(:instances => [opts[:instance_id]],
491
+ :load_balancer_name => opts[:id])
492
+ load_balancer(credentials, :id => opts[:id])
493
+ end
494
+ end
495
+
405
496
  private
406
497
 
407
- def new_client(credentials)
498
+ def new_client(credentials, provider_type = :ec2)
408
499
  opts = {
409
500
  :access_key_id => credentials.user,
410
501
  :secret_access_key => credentials.password
411
502
  }
412
503
  opts[:server] = ENV['DCLOUD_EC2_URL'] if ENV['DCLOUD_EC2_URL']
413
504
  safely do
414
- AWS::EC2::Base.new(opts)
505
+ case provider_type
506
+ when :ec2
507
+ AWS::EC2::Base.new(opts)
508
+ when :elb
509
+ AWS::ELB::Base.new(opts)
510
+ end
415
511
  end
416
512
  end
417
513
 
514
+ def convert_load_balancer(credentials, loadbalancer)
515
+ balancer_realms = loadbalancer.AvailabilityZones.member.collect do |m|
516
+ realm(credentials, m)
517
+ end
518
+ balancer = LoadBalancer.new({
519
+ :id => loadbalancer['LoadBalancerName'],
520
+ :created_at => loadbalancer['CreatedTime'],
521
+ :public_addresses => [loadbalancer['DNSName']],
522
+ :realms => balancer_realms
523
+ })
524
+ balancer.listeners = []
525
+ balancer.instances = []
526
+ loadbalancer.Listeners.member.each do |listener|
527
+ balancer.add_listener({
528
+ :protocol => listener['Protocol'],
529
+ :load_balancer_port => listener['LoadBalancerPort'],
530
+ :instance_port => listener['InstancePort']
531
+ })
532
+ end
533
+ loadbalancer.Instances.member.each do |instance|
534
+ balancer.instances << instances(credentials, :id => instance['InstanceId']).first
535
+ end if loadbalancer.Instances
536
+ balancer
537
+ end
538
+
539
+
418
540
  def convert_key(key)
419
541
  Key.new({
420
542
  :id => key['keyName'],
@@ -9,7 +9,7 @@ class GoGridClient
9
9
  apikey='YOUR API KEY',
10
10
  secret='YOUR SHARED SECRET',
11
11
  format='json',
12
- version='1.5')
12
+ version='1.6')
13
13
  @server = server
14
14
  @secret = secret
15
15
  @default_params = {'format'=>format, 'v'=>version,'api_key' => apikey}
@@ -35,12 +35,9 @@ class GoGridClient
35
35
  @default_params['v'] = version
36
36
  else
37
37
  @default_params['v'] = '1.5'
38
- end
39
- begin
40
- JSON::parse(sendAPIRequest(method, params))
41
- rescue Exception => e
42
- STDERR.puts("ERROR: #{e.message}")
43
- end
38
+ end
39
+ request = sendAPIRequest(method, params)
40
+ JSON::parse(request)
44
41
  end
45
42
 
46
43
  def encode_params(params)
@@ -45,7 +45,7 @@ class GogridDriver < Deltacloud::BaseDriver
45
45
 
46
46
  def supported_collections
47
47
  DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
48
- DEFAULT_COLLECTIONS + [ :keys ]
48
+ DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
49
49
  end
50
50
 
51
51
  def images(credentials, opts=nil)
@@ -176,6 +176,88 @@ class GogridDriver < Deltacloud::BaseDriver
176
176
  end
177
177
  end
178
178
 
179
+ def create_load_balancer(credentials, opts={})
180
+ gogrid = new_client(credentials)
181
+ balancer, l_instance = nil, nil
182
+ safely do
183
+ virtip = get_free_ip_from_realm(credentials, opts['realm_id'])
184
+ if opts['instance_id']
185
+ l_instance = instance(credentials, :id => opts['instance_id'])
186
+ real_ip = {
187
+ 'realiplist.0.port' => opts['listener_inst_port'],
188
+ 'realiplist.0.ip' => l_instance ? l_instance.public_addresses.first : ""
189
+ }
190
+ else
191
+ real_ip = false
192
+ end
193
+ request = {
194
+ 'name' => opts['name'],
195
+ 'virtualip.ip' => virtip,
196
+ 'virtualip.port' => opts['listener_lbr_port'],
197
+ }
198
+ request.merge!(real_ip) if real_ip
199
+ balancer = gogrid.request('grid/loadbalancer/add', request)['list'].first
200
+ end
201
+ balancer = convert_load_balancer(credentials, balancer)
202
+ balancer.instances = [l_instance] if l_instance
203
+ balancer
204
+ end
205
+
206
+ def destroy_load_balancer(credentials, id)
207
+ gogrid = new_client(credentials)
208
+ balancer = nil
209
+ safely do
210
+ balancer = gogrid.request('grid/loadbalancer/delete', { 'name' => id })
211
+ balancer = load_balancer(credentials, :id => id) unless balancer
212
+ end
213
+ convert_load_balancer(credentials, balancer)
214
+ end
215
+
216
+ def load_balancers(credentials, opts={})
217
+ gogrid = new_client(credentials)
218
+ balancers = []
219
+ safely do
220
+ balancer = gogrid.request('grid/loadbalancer/list', opts || {})['list'].each do |balancer|
221
+ balancers << balancer
222
+ end
223
+ end
224
+ balancers.collect { |b| convert_load_balancer(credentials, b) }
225
+ end
226
+
227
+ def load_balancer(credentials, opts={})
228
+ gogrid = new_client(credentials)
229
+ balancer = nil
230
+ begin
231
+ balancer = gogrid.request('grid/loadbalancer/get', { 'name' => opts[:id] })['list'].first
232
+ balancer['instances'] = instances(credentials)
233
+ return convert_load_balancer(credentials, balancer)
234
+ rescue OpenURI::HTTPError
235
+ balancer = load_balancers(credentials, :id => opts[:id]).first
236
+ end
237
+ end
238
+
239
+
240
+ def lb_register_instance(credentials, opts={})
241
+ client = new_client(credentials)
242
+ instance = instance(credentials, :id => opts[:instance_id])
243
+ balancer = client.request('grid/loadbalancer/get', { 'name' => opts[:id]})['list'].first
244
+ safely do
245
+ convert_load_balancer(credentials, client.request('grid/loadbalancer/edit', {
246
+ "id" => balancer['id'],
247
+ "realiplist.#{balancer['realiplist'].size}.ip" => instance.public_addresses.first,
248
+ "realiplist.#{balancer['realiplist'].size}.port" => balancer['virtualip']['port']
249
+ }))
250
+ end
251
+ end
252
+
253
+ # Move this to capabilities
254
+ def lb_unregister_instance(credentials, opts={})
255
+ raise Deltacloud::BackendFeatureUnsupported.new('501',
256
+ 'Unregistering instances from load balancer is not supported in GoGrid')
257
+ end
258
+
259
+
260
+
179
261
  def key(credentials, opts=nil)
180
262
  keys(credentials, opts).first
181
263
  end
@@ -213,8 +295,39 @@ class GogridDriver < Deltacloud::BaseDriver
213
295
 
214
296
  def new_client(credentials)
215
297
  GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
298
+ end
216
299
 
300
+ def convert_load_balancer(credentials, loadbalancer)
301
+ if loadbalancer['datacenter']
302
+ b_realm = realm(credentials, :id => loadbalancer['datacenter']['id'])
303
+ else
304
+ # Report first Realm until loadbalancer become ready
305
+ b_realm = realm(credentials, :id => 1)
306
+ end
307
+ balancer = LoadBalancer.new({
308
+ :id => loadbalancer['name'],
309
+ :realms => [b_realm]
310
+ })
311
+ balancer.public_addresses = [loadbalancer['virtualip']['ip']['ip']] if loadbalancer['virtualip'] and loadbalancer['virtualip']['ip']
312
+ balancer.listeners = []
313
+ balancer.instances = []
314
+ instance_ips = []
315
+ loadbalancer['realiplist'].each do |instance_ip|
316
+ balancer.add_listener({
317
+ :protocol => 'TCP',
318
+ :load_balancer_port => loadbalancer['virtualip']['port'],
319
+ :instance_port => instance_ip['port']
320
+ })
321
+ instance_ips << instance_ip['ip']['ip']
322
+ end if loadbalancer['realiplist']
323
+ balancer.instances = get_load_balancer_instances(instance_ips, loadbalancer['instances'])
324
+ return balancer
217
325
  end
326
+
327
+ def get_load_balancer_instances(instance_ips, instances)
328
+ instances.select { |i| instance_ips.include?(i.public_addresses.first) } if instances
329
+ end
330
+
218
331
 
219
332
  def get_login_data(client, instance_id)
220
333
  login_data = {}
@@ -316,11 +429,11 @@ class GogridDriver < Deltacloud::BaseDriver
316
429
  state.eql?('Off') ? 'STOPPED' : 'RUNNING'
317
430
  end
318
431
 
319
- def get_free_ip_from_realm(credentials, realm_id)
432
+ def get_free_ip_from_realm(credentials, realm_id, ip_type = 1)
320
433
  ip = ""
321
434
  safely do
322
435
  ip = new_client(credentials).request('grid/ip/list', {
323
- 'ip.type' => '1',
436
+ 'ip.type' => "#{ip_type}",
324
437
  'ip.state' => '1',
325
438
  'datacenter' => realm_id
326
439
  })['list'].first['ip']