deltacloud-core 1.1.0 → 1.1.1

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 (112) hide show
  1. data/Rakefile +10 -12
  2. data/config/drivers/{aruba.yaml → arubacloud.yaml} +2 -2
  3. data/deltacloud-core.gemspec +4 -4
  4. data/lib/cimi/collections/address_templates.rb +1 -1
  5. data/lib/cimi/collections/addresses.rb +2 -2
  6. data/lib/cimi/collections/base.rb +1 -0
  7. data/lib/cimi/collections/credentials.rb +1 -1
  8. data/lib/cimi/collections/forwarding_group_templates.rb +1 -1
  9. data/lib/cimi/collections/forwarding_groups.rb +1 -1
  10. data/lib/cimi/collections/machine_configurations.rb +1 -1
  11. data/lib/cimi/collections/machine_images.rb +1 -1
  12. data/lib/cimi/collections/machine_templates.rb +1 -1
  13. data/lib/cimi/collections/machines.rb +2 -2
  14. data/lib/cimi/collections/network_configurations.rb +1 -1
  15. data/lib/cimi/collections/network_port_configurations.rb +1 -1
  16. data/lib/cimi/collections/network_port_templates.rb +1 -1
  17. data/lib/cimi/collections/network_ports.rb +1 -1
  18. data/lib/cimi/collections/network_templates.rb +1 -1
  19. data/lib/cimi/collections/networks.rb +1 -1
  20. data/lib/cimi/collections/volume_configurations.rb +1 -1
  21. data/lib/cimi/collections/volume_images.rb +1 -1
  22. data/lib/cimi/collections/volume_templates.rb +1 -1
  23. data/lib/cimi/collections/volumes.rb +1 -1
  24. data/lib/cimi/helpers/database_helper.rb +16 -61
  25. data/lib/cimi/helpers/filter_helper.rb +41 -0
  26. data/lib/cimi/helpers/select_helper.rb +62 -0
  27. data/lib/cimi/models.rb +21 -2
  28. data/lib/cimi/models/address.rb +9 -7
  29. data/lib/cimi/models/address_template.rb +4 -4
  30. data/lib/cimi/models/base.rb +62 -197
  31. data/lib/cimi/models/collection.rb +78 -70
  32. data/lib/cimi/models/disk.rb +15 -8
  33. data/lib/cimi/models/machine.rb +27 -29
  34. data/lib/cimi/models/machine_image.rb +10 -13
  35. data/lib/cimi/models/machine_template.rb +3 -3
  36. data/lib/cimi/models/resource.rb +190 -0
  37. data/lib/cimi/models/schema.rb +9 -0
  38. data/lib/cimi/models/volume.rb +10 -13
  39. data/lib/cimi/models/volume_configuration.rb +3 -3
  40. data/lib/cimi/models/volume_template.rb +2 -2
  41. data/lib/cimi/server.rb +1 -0
  42. data/lib/db.rb +15 -0
  43. data/lib/db/address_template.rb +15 -0
  44. data/lib/db/entity.rb +55 -0
  45. data/lib/db/machine_template.rb +15 -0
  46. data/lib/db/provider.rb +40 -0
  47. data/lib/db/volume_configuration.rb +15 -0
  48. data/lib/db/volume_template.rb +15 -0
  49. data/lib/deltacloud/collections/base.rb +1 -0
  50. data/lib/deltacloud/collections/instances.rb +2 -1
  51. data/lib/deltacloud/collections/storage_snapshots.rb +3 -1
  52. data/lib/deltacloud/core_ext/array.rb +5 -0
  53. data/lib/deltacloud/drivers/{aruba/aruba_driver.rb → arubacloud/arubacloud_driver.rb} +3 -6
  54. data/lib/deltacloud/drivers/digitalocean/digitalocean_driver.rb +48 -75
  55. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +18 -3
  56. data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +25 -0
  57. data/lib/deltacloud/drivers/fgcp/fgcp_client.rb +1 -1
  58. data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +34 -14
  59. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +2 -0
  60. data/lib/deltacloud/drivers/mock/mock_driver.rb +3 -3
  61. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +93 -33
  62. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +2 -0
  63. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +2 -2
  64. data/lib/deltacloud/helpers/deltacloud_helper.rb +3 -1
  65. data/lib/deltacloud/helpers/rabbit_helper.rb +1 -2
  66. data/lib/deltacloud/models/address.rb +1 -0
  67. data/lib/deltacloud/models/blob.rb +1 -0
  68. data/lib/deltacloud/models/bucket.rb +1 -0
  69. data/lib/deltacloud/models/firewall.rb +1 -0
  70. data/lib/deltacloud/models/hardware_profile.rb +3 -1
  71. data/lib/deltacloud/models/image.rb +7 -0
  72. data/lib/deltacloud/models/instance.rb +12 -3
  73. data/lib/deltacloud/models/key.rb +1 -0
  74. data/lib/deltacloud/models/load_balancer.rb +1 -0
  75. data/lib/deltacloud/models/metric.rb +1 -0
  76. data/lib/deltacloud/models/realm.rb +10 -1
  77. data/lib/deltacloud/models/storage_snapshot.rb +1 -0
  78. data/lib/deltacloud/models/storage_volume.rb +2 -1
  79. data/lib/deltacloud/runner.rb +2 -1
  80. data/lib/deltacloud/server.rb +1 -0
  81. data/lib/deltacloud/version.rb +1 -1
  82. data/lib/deltacloud_rack.rb +4 -0
  83. data/tests/cimi/collections/machines_test.rb +80 -0
  84. data/tests/cimi/db/database_helper_test.rb +54 -99
  85. data/tests/cimi/db/db_helper.rb +2 -0
  86. data/tests/cimi/db/entity_test.rb +29 -0
  87. data/tests/cimi/model/collection_spec.rb +2 -2
  88. data/tests/cimi/model/credential_spec.rb +2 -2
  89. data/tests/cimi/model/machine_configuration_spec.rb +2 -2
  90. data/tests/cimi/model/machine_image_spec.rb +2 -2
  91. data/tests/cimi/model/machine_spec.rb +4 -4
  92. data/tests/cimi/model/machine_template_spec.rb +2 -2
  93. data/tests/cimi/model/volume_configuration_spec.rb +2 -2
  94. data/tests/cimi/model/volume_image_spec.rb +2 -2
  95. data/tests/cimi/model/volume_spec.rb +2 -2
  96. data/tests/cimi/model/volume_template_spec.rb +2 -2
  97. data/tests/cimi/spec_helper.rb +4 -0
  98. data/tests/deltacloud/collections/instances_collection_test.rb +3 -1
  99. data/tests/deltacloud/launcher_test.rb +3 -5
  100. data/tests/drivers/ec2/images_test.rb +7 -0
  101. data/tests/drivers/gogrid/images_test.rb +7 -0
  102. data/tests/drivers/openstack/instances_test.rb +8 -8
  103. data/tests/drivers/openstack/realms_test.rb +13 -13
  104. data/views/errors/403.xml.haml +2 -1
  105. data/views/images/show.html.haml +4 -1
  106. data/views/images/show.xml.haml +1 -0
  107. data/views/instances/new.html.haml +1 -1
  108. data/views/instances/show.html.haml +3 -0
  109. data/views/realms/index.html.haml +2 -0
  110. data/views/realms/show.html.haml +4 -0
  111. data/views/realms/show.xml.haml +3 -0
  112. metadata +19 -14
@@ -53,6 +53,7 @@ module Deltacloud
53
53
  memory 613
54
54
  storage 160
55
55
  architecture ['i386','x86_64']
56
+ root_type :persistent
56
57
  end
57
58
 
58
59
  define_hardware_profile('m1.small') do
@@ -301,7 +302,7 @@ module Deltacloud
301
302
  target = instance(credentials, :id => opts[:id])
302
303
  param = {}
303
304
  param[:credentials] = {
304
- :username => 'root', # Default for EC2 Linux instances
305
+ :username => (opts[:username]) ? opts[:username] : 'root', # Default for EC2 Linux instances
305
306
  }
306
307
  param[:port] = opts[:port] || '22'
307
308
  param[:ip] = opts[:ip] || target.public_addresses.first.address
@@ -379,7 +380,11 @@ module Deltacloud
379
380
  def create_key(credentials, opts={})
380
381
  ec2 = new_client(credentials)
381
382
  safely do
382
- convert_key(ec2.create_key_pair(opts[:key_name]))
383
+ if (opts[:public_key] && opts[:public_key].length >0)
384
+ convert_key(ec2.import_key_pair(opts[:key_name], opts[:public_key]))
385
+ else
386
+ convert_key(ec2.create_key_pair(opts[:key_name]))
387
+ end
383
388
  end
384
389
  end
385
390
 
@@ -938,10 +943,15 @@ module Deltacloud
938
943
  :owner_id => image[:aws_owner],
939
944
  :architecture => image[:aws_architecture],
940
945
  :hardware_profiles => image_profiles(image, profiles),
941
- :state => image[:aws_state]
946
+ :state => image[:aws_state],
947
+ :root_type => convert_root_type(image[:aws_root_device_type])
942
948
  )
943
949
  end
944
950
 
951
+ def convert_root_type(type)
952
+ type == 'ebs' ? 'persistent' : 'transient'
953
+ end
954
+
945
955
  def convert_instance(instance)
946
956
  can_create_image = 'ebs'.eql?(instance[:root_device_type]) and 'RUNNING'.eql?(convert_state(instance[:aws_state]))
947
957
  inst_profile_opts={}
@@ -1146,6 +1156,11 @@ module Deltacloud
1146
1156
  end
1147
1157
 
1148
1158
  exceptions do
1159
+
1160
+ on /root device is not supported for the instance/ do
1161
+ status 400
1162
+ end
1163
+
1149
1164
  on /(AuthFailure|InvalidAccessKeyId)/ do
1150
1165
  status 401
1151
1166
  end
@@ -118,6 +118,31 @@ module Deltacloud
118
118
  "Loadbalancer not supported in Eucalyptus", "")
119
119
  end
120
120
 
121
+ #override ec2 driver realms - euca API doesn't support vpc/subnet concepts
122
+ #http://docs.aws.amazon.com/AWSEC2/2009-04-04/DeveloperGuide/
123
+ def realms(credentials, opts={})
124
+ ec2 = new_client(credentials)
125
+ realms = []
126
+ safely do
127
+ if opts[:id] and !opts[:id].empty?
128
+ begin
129
+ ec2.describe_availability_zones([opts[:id]]).collect do |realm|
130
+ realms << convert_realm(realm) unless realm.empty?
131
+ end
132
+ rescue => e
133
+ raise e unless e.message =~ /Invalid availability zone/
134
+ realms = []
135
+ end
136
+ else
137
+ realms = ec2.describe_availability_zones.collect do |realm|
138
+ convert_realm(realm) unless realm.empty?
139
+ end
140
+ end
141
+ end
142
+ realms
143
+ end
144
+
145
+
121
146
  # override EC2 implementation; Eucalyptus implements the older definition of EC2 security group;
122
147
  # http://docs.amazonwebservices.com/AWSEC2/2009-07-15/APIReference/index.html?ApiReference-query-AuthorizeSecurityGroupIngress.html
123
148
  # if the rule specifies a source group, port&protocol will be ignored. And source group and cidr range can't be mixed in a request
@@ -167,7 +167,7 @@ class FgcpClient
167
167
  <description>#{description}</description>
168
168
  </locale>
169
169
  <locale>
170
- <lcid>jp</lcid>
170
+ <lcid>ja</lcid>
171
171
  <name>#{name}</name>
172
172
  <description>#{description}</description>
173
173
  </locale>
@@ -60,6 +60,7 @@ class FgcpDriver < Deltacloud::BaseDriver
60
60
  stopping.to( :stopped ) .automatically # stopping an instance does not automatically destroy it
61
61
  stopped.to(:running) .on( :start ) # obvious
62
62
  stopped.to(:finish) .on( :destroy ) # only destroy removes an instance, and it has to be stopped first
63
+ error.from( :pending, :running, :stopping) # not including STOP_ERROR and START_ERROR as they are as :running and :stopped
63
64
  end
64
65
 
65
66
  ######################################################################
@@ -108,6 +109,13 @@ class FgcpDriver < Deltacloud::BaseDriver
108
109
  if xml['diskimages'] # not likely to not be so, but just in case
109
110
  xml['diskimages'][0]['diskimage'].each do |img|
110
111
 
112
+ # 32bit CentOS/RHEL images are refused on hwps > 16GB (i.e. w_high, quad_high)
113
+ os_arch = img['osName'][0].to_s =~ /.*32.?bit.*/ ? 'i386' : 'x86_64'
114
+ os_centos_rhel = img['osName'][0] =~ /(CentOS|Red Hat).*/
115
+ allowed_hwps = hwps.select do |hwp|
116
+ hwp.memory.default.to_i < 16000 or os_arch == 'x86_64' or not os_centos_rhel
117
+ end
118
+
111
119
  images << Image.new(
112
120
  :id => img['diskimageId'][0],
113
121
  :name => img['diskimageName'][0].to_s,
@@ -117,8 +125,8 @@ class FgcpDriver < Deltacloud::BaseDriver
117
125
  # This will determine image architecture using OS name.
118
126
  # Usually the OS name includes '64bit' or '32bit'. If not,
119
127
  # it will fall back to 64 bit.
120
- :architecture => img['osName'][0].to_s =~ /.*32.?bit.*/ ? 'i386' : 'x86_64',
121
- :hardware_profiles => hwps
128
+ :architecture => os_arch,
129
+ :hardware_profiles => allowed_hwps
122
130
  ) if opts[:id].nil? or opts[:id] == img['diskimageId'][0]
123
131
  end
124
132
  end
@@ -138,7 +146,7 @@ class FgcpDriver < Deltacloud::BaseDriver
138
146
  if opts[:name].nil?
139
147
  # default to instance name
140
148
  instance = client.get_vserver_attributes(opts[:id])
141
- opts[:name] ||= instance['vserver'][0]['vserverName']
149
+ opts[:name] = instance['vserver'][0]['vserverName']
142
150
  opts[:description] ||= opts[:name]
143
151
  end
144
152
 
@@ -449,7 +457,9 @@ class FgcpDriver < Deltacloud::BaseDriver
449
457
  end
450
458
  state = client.get_vdisk_status(opts[:id])['vdiskStatus'][0]
451
459
  actions = []
452
- if state == 'NORMAL'
460
+ #align with EC2, cimi
461
+ case state
462
+ when 'NORMAL'
453
463
  if vdisk['attachedTo'].nil?
454
464
  state = 'AVAILABLE'
455
465
  actions = [:attach, :destroy]
@@ -457,6 +467,10 @@ class FgcpDriver < Deltacloud::BaseDriver
457
467
  state = 'IN-USE'
458
468
  actions = [:detach]
459
469
  end
470
+ when 'DEPLOYING'
471
+ state = 'CREATING'
472
+ when 'BACKUP_ING'
473
+ state = 'CAPTURING'
460
474
  end
461
475
 
462
476
  volumes << StorageVolume.new(
@@ -490,7 +504,7 @@ class FgcpDriver < Deltacloud::BaseDriver
490
504
  :realm_id => client.extract_vsys_id(vdisk['vdiskId'][0]),
491
505
  # aligning with rhevm, which returns 'system' or 'data'
492
506
  :kind => determine_storage_type(vdisk['vdiskId'][0]),
493
- :state => vdisk['attachedTo'].nil? ? nil : 'IN-USE'
507
+ :state => vdisk['attachedTo'].nil? ? 'AVAILABLE' : 'IN-USE'
494
508
  )
495
509
  end
496
510
  end
@@ -502,7 +516,7 @@ class FgcpDriver < Deltacloud::BaseDriver
502
516
 
503
517
  def create_storage_volume(credentials, opts={})
504
518
  opts ||= {}
505
- opts[:name] ||= Time.now.to_s
519
+ opts[:name] = Time.now.to_s unless opts[:name] and not opts[:name].empty?
506
520
  opts[:capacity] ||= '1' # DC default
507
521
  #size has to be a multiple of 10: round up.
508
522
  opts[:capacity] = ((opts[:capacity].to_f / 10.0).ceil * 10.0).to_s
@@ -528,7 +542,8 @@ class FgcpDriver < Deltacloud::BaseDriver
528
542
  :capacity => opts[:capacity],
529
543
  :realm_id => client.extract_vsys_id(opts[:realm_id]),
530
544
  :instance_id => nil,
531
- :state => 'DEPLOYING',
545
+ # aligning with ec2, cimi (instead of fgcp's DEPLOYING)
546
+ :state => 'CREATING',
532
547
  # aligning with rhevm, which returns 'system' or 'data'
533
548
  :kind => 'data',
534
549
  :actions => []
@@ -577,7 +592,7 @@ class FgcpDriver < Deltacloud::BaseDriver
577
592
 
578
593
  snapshots << StorageSnapshot.new(
579
594
  :id => opts[:id],
580
- #:state => ?,
595
+ :state => 'AVAILABLE',
581
596
  :storage_volume_id => vdisk_id,
582
597
  :created => backup['backupTime'][0]
583
598
  ) if backup_id = backup['backupId'][0]
@@ -603,7 +618,7 @@ class FgcpDriver < Deltacloud::BaseDriver
603
618
 
604
619
  snapshots << StorageSnapshot.new(
605
620
  :id => generate_snapshot_id(vdisk['vdiskId'][0], backup['backupId'][0]),
606
- #:state => ?,
621
+ :state => 'AVAILABLE',
607
622
  :storage_volume_id => vdisk['vdiskId'][0],
608
623
  :created => backup['backupTime'][0]
609
624
  )
@@ -626,7 +641,7 @@ class FgcpDriver < Deltacloud::BaseDriver
626
641
 
627
642
  StorageSnapshot.new(
628
643
  :id => "PENDING-#{opts[:volume_id]}", # don't know id until backup completed
629
- :state => 'PENDING', # OK to make up a state like that?
644
+ :state => 'CREATING',
630
645
  :storage_volume_id => opts[:volume_id],
631
646
  :created => Time.now.to_s
632
647
  )
@@ -1443,6 +1458,11 @@ eofwopxml
1443
1458
  status 404 # Not Found
1444
1459
  end
1445
1460
 
1461
+ # trying to create an image that has never been booted
1462
+ on /NEVER_BOOTED/ do
1463
+ status 409 # Conflict
1464
+ end
1465
+
1446
1466
  # reached maximum number of attempts while polling for an update
1447
1467
  on /Server did not include public IP address in FW NAT rules/ do
1448
1468
  status 504 # Gateway Timeout
@@ -1629,7 +1649,7 @@ eofwopxml
1629
1649
  :firewalls => server != 'FW' ? [client.extract_vsys_id(vserver['vserverId'][0]) + '-S-0001'] : nil,
1630
1650
  :owner_id => vserver['creator'][0]
1631
1651
  }
1632
- instance.merge!( {'create_image' => false}) if not server == 'vserver'
1652
+ instance.merge!( {'create_image' => false}) if server != 'vserver' or state_data[:state] != 'STOPPED'
1633
1653
  instance.merge! state_data
1634
1654
 
1635
1655
  Instance::new(instance)
@@ -1705,9 +1725,9 @@ eofwopxml
1705
1725
  'UNEXPECTED_STOP' => 'STOPPED',
1706
1726
  'RESTORING' => 'PENDING',
1707
1727
  'BACKUP_ING' => 'PENDING',
1708
- 'ERROR' => 'STOPPED',
1709
- 'START_ERROR' => 'STOPPED', # not sure about this one
1710
- 'STOP_ERROR' => 'STOPPING',
1728
+ 'ERROR' => 'ERROR', # allowed actions limited
1729
+ 'START_ERROR' => 'STOPPED', # allowed actions are same as for STOPPED
1730
+ 'STOP_ERROR' => 'RUNNING', # allowed actions are same as for RUNNING
1711
1731
  'REGISTERING' => 'PENDING',
1712
1732
  'CHANGE_TYPE' => 'PENDING'
1713
1733
  }
@@ -86,6 +86,8 @@ module Deltacloud
86
86
  end
87
87
  end
88
88
  end
89
+ profiles = hardware_profiles(credentials)
90
+ imgs.each { |img| img.hardware_profiles = profiles }
89
91
  imgs = filter_on( imgs, :architecture, opts )
90
92
  imgs.sort_by{|e| [e.owner_id, e.description]}
91
93
  end
@@ -205,11 +205,11 @@ module Deltacloud::Drivers::Mock
205
205
  hwp ||= find_hardware_profile(credentials, 'm1-small', image_id)
206
206
 
207
207
  name = opts[:name] || "i-#{Time.now.to_i}"
208
-
208
+ initial_state = opts[:initial_state] || "RUNNING"
209
209
  instance = {
210
210
  :id => next_id,
211
211
  :name=>name,
212
- :state=>'RUNNING',
212
+ :state=> (initial_state == "STARTED" ? "RUNNING" : initial_state),
213
213
  :keyname => opts[:keyname],
214
214
  :image_id=>image_id,
215
215
  :owner_id=>credentials.user,
@@ -218,7 +218,7 @@ module Deltacloud::Drivers::Mock
218
218
  :instance_profile => InstanceProfile.new(hwp.name, opts),
219
219
  :realm_id=>realm_id,
220
220
  :create_image=>true,
221
- :actions=>instance_actions_for( 'RUNNING' ),
221
+ :actions=>instance_actions_for((initial_state == "STARTED" ? "RUNNING" : initial_state)),
222
222
  :user_data => opts[:user_data] ? Base64::decode64(opts[:user_data]) : nil
223
223
  }
224
224
  @client.store(:instances, instance)
@@ -16,7 +16,6 @@
16
16
 
17
17
  require 'openstack'
18
18
  require 'tempfile'
19
- require 'base64'
20
19
 
21
20
  module Deltacloud
22
21
  module Drivers
@@ -44,20 +43,11 @@ module Deltacloud
44
43
  end
45
44
 
46
45
  define_hardware_profile('default')
47
-
48
46
  def supported_collections(credentials)
49
47
  #get the collections as defined by 'capability' and 'respond_to?' blocks
50
48
  super_collections = super
51
- begin
52
- new_client(credentials, "object-store")
53
- rescue Deltacloud::Exceptions::NotImplemented #OpenStack::Exception::NotImplemented...
54
- super_collections = super_collections - [Sinatra::Rabbit::BucketsCollection]
55
- end
56
- begin
57
- new_client(credentials, "volume")
58
- rescue Deltacloud::Exceptions::NotImplemented
59
- super_collections = super_collections - [Sinatra::Rabbit::StorageVolumesCollection]
60
- end
49
+ super_collections = super_collections - [Sinatra::Rabbit::BucketsCollection] if regions_for(credentials, "object-store").empty?
50
+ super_collections = super_collections - [Sinatra::Rabbit::StorageVolumesCollection] if regions_for(credentials, "volume").empty?
61
51
  super_collections
62
52
  end
63
53
 
@@ -127,21 +117,42 @@ module Deltacloud
127
117
 
128
118
  def realms(credentials, opts={})
129
119
  os = new_client(credentials)
130
- limits = ""
131
- safely do
132
- lim = os.limits
133
- limits << "ABSOLUTE >> Max. Instances: #{lim[:absolute][:maxTotalInstances]} Max. RAM: #{lim[:absolute][:maxTotalRAMSize]} || "
134
- lim[:rate].each do |rate|
135
- if rate[:regex] =~ /servers/
136
- limits << "SERVERS >> Total: #{rate[:limit].first[:value]} Remaining: #{rate[:limit].first[:remaining]} Time Unit: per #{rate[:limit].first[:unit]}"
137
- end
138
- end
120
+ realms = []
121
+ if opts[:id]
122
+ resource_types = []
123
+ (os.connection.regions_list[opts[:id]] || []).each do |service|
124
+ resource_types << service[:service] if ["compute", "volume", "object-store"].include?(service[:service])
125
+ realms << Realm.new( { :id => opts[:id],
126
+ :name => opts[:id],
127
+ :state =>'AVAILABLE',
128
+ :resource_types => resource_types}) unless resource_types.empty?
129
+ end
130
+ else
131
+ os.connection.regions_list.each_pair do |region, services|
132
+ resource_types = services.inject([]){|res, cur| res << cur[:service] if ["compute", "volume", "object-store"].include?(cur[:service]); res }
133
+ next if resource_types.empty? #nothing here deltacloud manages
134
+ realms << Realm.new( { :id => region,
135
+ :name => region,
136
+ :state =>'AVAILABLE',
137
+ :resource_types => resource_types})
138
+ end
139
139
  end
140
- return [] if opts[:id] and opts[:id] != 'default'
141
- [ Realm.new( { :id=>'default',
142
- :name=>'default',
143
- :limit => limits,
144
- :state=>'AVAILABLE' })]
140
+ realms
141
+ # limits = ""
142
+ # safely do
143
+ # lim = os.limits
144
+ # limits << "ABSOLUTE >> Max. Instances: #{lim[:absolute][:maxTotalInstances]} Max. RAM: #{lim[:absolute][:maxTotalRAMSize]} || "
145
+ # lim[:rate].each do |rate|
146
+ # if rate[:regex] =~ /servers/
147
+ # limits << "SERVERS >> Total: #{rate[:limit].first[:value]} Remaining: #{rate[:limit].first[:remaining]} Time Unit: per #{rate[:limit].first[:unit]}"
148
+ # end
149
+ # end
150
+ # end
151
+ # return [] if opts[:id] and opts[:id] != 'default'
152
+ # [ Realm.new( { :id=>'default',
153
+ # :name=>'default',
154
+ # :limit => limits,
155
+ # :state=>'AVAILABLE' })]
145
156
  end
146
157
 
147
158
  def instances(credentials, opts={})
@@ -167,7 +178,13 @@ module Deltacloud
167
178
  end
168
179
 
169
180
  def create_instance(credentials, image_id, opts)
170
- os = new_client( credentials )
181
+ if opts[:realm_id] && opts[:realm_id].length > 0
182
+ os = new_client( credentials, "compute", opts[:realm_id])
183
+ else
184
+ #choose a random realm:
185
+ available_realms = regions_for(credentials, "compute")
186
+ os = new_client(credentials, "compute", available_realms.sample.id)
187
+ end
171
188
  result = nil
172
189
  #opts[:personality]: path1='server_path1'. content1='contents1', path2='server_path2', content2='contents2' etc
173
190
  params = {}
@@ -183,15 +200,16 @@ module Deltacloud
183
200
  params[:key_name]=opts[:keyname]
184
201
  end
185
202
  if opts[:user_data] && opts[:user_data].length > 0
186
- params[:user_data]=Base64.encode64(opts[:user_data])
203
+ params[:user_data]=opts[:user_data]
187
204
  end
188
205
  safely do
189
206
  server = os.create_server(params)
190
- result = convert_from_server(server, os.connection.authuser, get_attachments(server.id, os))
207
+ result = convert_from_server(server, os.connection.authuser, get_attachments(server.id, os), os.connection.region)
191
208
  end
192
209
  result
193
210
  end
194
211
 
212
+
195
213
  def reboot_instance(credentials, instance_id)
196
214
  os = new_client(credentials)
197
215
  safely do
@@ -435,26 +453,48 @@ module Deltacloud
435
453
 
436
454
  def storage_snapshots(credentials, opts={})
437
455
  vs = new_client(credentials, "volume")
456
+ snapshots = []
438
457
  safely do
458
+ if opts[:id]
459
+ snapshots << convert_snapshot(vs.get_snapshot(opts[:id]))
460
+ else
461
+ vs.snapshots.each do |snap|
462
+ snapshots << convert_snapshot(snap)
463
+ end
464
+ end
439
465
  end
466
+ snapshots
440
467
  end
441
468
 
442
469
  def create_storage_snapshot(credentials, opts={})
443
470
  vs = new_client(credentials, "volume")
444
471
  safely do
472
+ name = opts[:name] || "snapshot_#{Time.now.to_i}"
473
+ description = opts[:description] || "snapshot from volume #{opts[:volume_id]}"
474
+ params = {:volume_id => opts[:volume_id], :display_name=>name, :display_description=>description}
475
+ convert_snapshot(vs.create_snapshot(params))
445
476
  end
446
477
  end
447
478
 
448
479
  def destroy_storage_snapshot(credentials, opts={})
449
480
  vs = new_client(credentials, "volume")
450
481
  safely do
482
+ vs.delete_snapshot(opts[:id])
451
483
  end
452
484
  end
453
485
 
454
486
  private
455
487
 
488
+ def region_specified?
489
+ api_provider.split(";").last
490
+ end
491
+
492
+ def regions_for(credentials, service="compute")
493
+ realms(credentials).select{|region| region.resource_types.include?(service)}
494
+ end
495
+
456
496
  #for v2 authentication credentials.name == "username+tenant_name"
457
- def new_client(credentials, type = "compute")
497
+ def new_client(credentials, type="compute", realm_id=nil)
458
498
  tokens = credentials.user.split("+")
459
499
  if credentials.user.empty?
460
500
  raise AuthenticationFailure.new(Exception.new("Error: you must supply the username"))
@@ -464,10 +504,18 @@ private
464
504
  else
465
505
  user_name, tenant_name = tokens.first, tokens.last
466
506
  end
507
+ #check if region specified with provider:
508
+ provider = api_provider
509
+ if (realm_id || provider.include?(";"))
510
+ region = realm_id || provider.split(";").last
511
+ provider = provider.chomp(";#{region}")
512
+ end
513
+ connection_params = {:username => user_name, :api_key => credentials.password, :authtenant => tenant_name, :auth_url => provider, :service_type => type}
514
+ connection_params.merge!({:region => region}) if region
467
515
  safely do
468
516
  raise ValidationFailure.new(Exception.new("Error: tried to initialise Openstack connection using" +
469
517
  " an unknown service_type: #{type}")) unless ["volume", "compute", "object-store"].include? type
470
- OpenStack::Connection.create(:username => user_name, :api_key => credentials.password, :authtenant => tenant_name, :auth_url => api_provider, :service_type => type)
518
+ OpenStack::Connection.create(connection_params)
471
519
  end
472
520
  end
473
521
 
@@ -500,7 +548,7 @@ private
500
548
  })
501
549
  end
502
550
 
503
- def convert_from_server(server, owner, attachments=[])
551
+ def convert_from_server(server, owner, attachments=[], region=nil)
504
552
  op = (server.class == Hash)? :fetch : :send
505
553
  image = server.send(op, :image)
506
554
  flavor = server.send(op, :flavor)
@@ -511,7 +559,7 @@ private
511
559
  end
512
560
  inst = Instance.new(
513
561
  :id => server.send(op, :id).to_s,
514
- :realm_id => 'default',
562
+ :realm_id => region || "n/a",
515
563
  :owner_id => owner,
516
564
  :description => server.send(op, :name),
517
565
  :name => server.send(op, :name),
@@ -524,6 +572,7 @@ private
524
572
  :username => 'root',
525
573
  :password => password,
526
574
  :keyname => server.send(op, :key_name),
575
+ :launch_time => server.send(op, :created),
527
576
  :storage_volumes => attachments.inject([]){|res, cur| res << {cur[:volumeId] => cur[:device]} ;res}
528
577
  )
529
578
  inst.actions = instance_actions_for(inst.state)
@@ -607,6 +656,17 @@ private
607
656
  })
608
657
  end
609
658
 
659
+ def convert_snapshot(snapshot)
660
+ StorageSnapshot.new(
661
+ :id => snapshot.id,
662
+ :name => snapshot.display_name,
663
+ :description => snapshot.display_description || snapshot.display_name,
664
+ :state => snapshot.status,
665
+ :storage_volume_id => snapshot.volume_id,
666
+ :created => snapshot.created_at
667
+ )
668
+ end
669
+
610
670
  #IN: path1='server_path1'. content1='contents1', path2='server_path2', content2='contents2' etc
611
671
  #OUT:{local_path=>server_path, local_path1=>server_path2 etc}
612
672
  def extract_personality(opts)