deltacloud-core 0.0.9 → 0.1.0

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 (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']