deltacloud-core 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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)