deltacloud-core 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/Rakefile +10 -2
  2. data/bin/deltacloudd +10 -10
  3. data/config.ru +2 -1
  4. data/config/drivers/digitalocean.yaml +3 -0
  5. data/deltacloud-core.gemspec +13 -6
  6. data/lib/cimi/collections.rb +1 -1
  7. data/lib/cimi/collections/address_templates.rb +27 -3
  8. data/lib/cimi/collections/addresses.rb +1 -1
  9. data/lib/cimi/collections/base.rb +1 -0
  10. data/lib/cimi/collections/cloud_entry_point.rb +4 -0
  11. data/lib/cimi/collections/credentials.rb +2 -2
  12. data/lib/cimi/collections/machine_images.rb +20 -0
  13. data/lib/cimi/collections/machine_templates.rb +72 -0
  14. data/lib/cimi/collections/machines.rb +50 -41
  15. data/lib/cimi/collections/network_ports.rb +3 -3
  16. data/lib/cimi/collections/networks.rb +4 -4
  17. data/lib/cimi/collections/resource_metadata.rb +1 -1
  18. data/lib/cimi/collections/volume_configurations.rb +25 -0
  19. data/lib/cimi/collections/volume_images.rb +21 -1
  20. data/lib/cimi/collections/volume_templates.rb +69 -0
  21. data/lib/cimi/collections/volumes.rb +5 -10
  22. data/lib/cimi/dependencies.rb +0 -1
  23. data/lib/cimi/helpers.rb +4 -1
  24. data/lib/cimi/helpers/cimi_helper.rb +62 -0
  25. data/lib/cimi/helpers/database_helper.rb +95 -0
  26. data/lib/cimi/models.rb +15 -1
  27. data/lib/cimi/models/address.rb +10 -5
  28. data/lib/cimi/models/address_template.rb +67 -3
  29. data/lib/cimi/models/base.rb +8 -5
  30. data/lib/cimi/models/cloud_entry_point.rb +6 -1
  31. data/lib/cimi/models/collection.rb +9 -4
  32. data/lib/cimi/models/disk.rb +6 -1
  33. data/lib/cimi/models/errors.rb +8 -0
  34. data/lib/cimi/models/machine.rb +68 -42
  35. data/lib/cimi/models/machine_configuration.rb +2 -2
  36. data/lib/cimi/models/machine_image.rb +41 -6
  37. data/lib/cimi/models/machine_template.rb +58 -0
  38. data/lib/cimi/models/machine_volume.rb +51 -3
  39. data/lib/cimi/models/resource_metadata.rb +88 -25
  40. data/lib/cimi/models/schema.rb +19 -5
  41. data/lib/cimi/models/volume.rb +66 -30
  42. data/lib/cimi/models/volume_configuration.rb +53 -21
  43. data/lib/cimi/models/volume_image.rb +24 -9
  44. data/lib/cimi/models/volume_template.rb +61 -0
  45. data/lib/cimi/server.rb +0 -6
  46. data/lib/db.rb +82 -0
  47. data/lib/db/address_template.rb +15 -0
  48. data/lib/db/entity.rb +22 -0
  49. data/lib/db/machine_template.rb +10 -0
  50. data/lib/db/provider.rb +13 -0
  51. data/lib/db/volume_configuration.rb +10 -0
  52. data/lib/db/volume_template.rb +10 -0
  53. data/lib/deltacloud/collections/addresses.rb +1 -1
  54. data/lib/deltacloud/collections/base.rb +12 -1
  55. data/lib/deltacloud/collections/buckets.rb +41 -8
  56. data/lib/deltacloud/collections/drivers.rb +1 -1
  57. data/lib/deltacloud/collections/firewalls.rb +2 -2
  58. data/lib/deltacloud/collections/images.rb +1 -1
  59. data/lib/deltacloud/collections/instances.rb +7 -1
  60. data/lib/deltacloud/collections/keys.rb +1 -1
  61. data/lib/deltacloud/collections/load_balancers.rb +4 -4
  62. data/lib/deltacloud/collections/storage_snapshots.rb +5 -1
  63. data/lib/deltacloud/collections/storage_volumes.rb +7 -3
  64. data/lib/deltacloud/drivers/base_driver.rb +10 -9
  65. data/lib/deltacloud/drivers/cimi_features.rb +42 -0
  66. data/lib/deltacloud/drivers/digitalocean/digitalocean_driver.rb +307 -0
  67. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +40 -14
  68. data/lib/deltacloud/drivers/exceptions.rb +8 -0
  69. data/lib/deltacloud/drivers/features.rb +19 -2
  70. data/lib/deltacloud/drivers/fgcp/fgcp_client.rb +11 -0
  71. data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +83 -11
  72. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +1 -1
  73. data/lib/deltacloud/drivers/mock/mock_client.rb +2 -4
  74. data/lib/deltacloud/drivers/mock/mock_driver.rb +29 -0
  75. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +153 -36
  76. data/lib/deltacloud/drivers/rackspace/anti_cache_monkey_patch.rb +20 -0
  77. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +1 -0
  78. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +30 -12
  79. data/lib/deltacloud/drivers/sbc/sbc_client.rb +0 -1
  80. data/lib/deltacloud/drivers/sbc/sbc_driver.rb +5 -1
  81. data/lib/deltacloud/drivers/vsphere/vsphere_client.rb +1 -1
  82. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +19 -9
  83. data/lib/deltacloud/helpers/blob_stream_helper.rb +42 -3
  84. data/lib/deltacloud/helpers/deltacloud_helper.rb +31 -14
  85. data/lib/deltacloud/models/address.rb +9 -0
  86. data/lib/deltacloud/models/base_model.rb +4 -0
  87. data/lib/deltacloud/models/blob.rb +12 -0
  88. data/lib/deltacloud/models/bucket.rb +9 -0
  89. data/lib/deltacloud/models/firewall.rb +13 -1
  90. data/lib/deltacloud/models/firewall_rule.rb +14 -0
  91. data/lib/deltacloud/models/hardware_profile.rb +14 -0
  92. data/lib/deltacloud/models/image.rb +15 -0
  93. data/lib/deltacloud/models/instance.rb +40 -1
  94. data/lib/deltacloud/models/instance_address.rb +9 -0
  95. data/lib/deltacloud/models/key.rb +15 -0
  96. data/lib/deltacloud/models/load_balancer.rb +20 -0
  97. data/lib/deltacloud/models/metric.rb +15 -0
  98. data/lib/deltacloud/models/provider.rb +8 -0
  99. data/lib/deltacloud/models/realm.rb +9 -0
  100. data/lib/deltacloud/models/state_machine.rb +8 -0
  101. data/lib/deltacloud/models/storage_snapshot.rb +11 -0
  102. data/lib/deltacloud/models/storage_volume.rb +24 -0
  103. data/lib/deltacloud/server.rb +1 -3
  104. data/lib/deltacloud/version.rb +2 -1
  105. data/lib/deltacloud_rack.rb +1 -1
  106. data/tests/cimi/db/database_helper_test.rb +190 -0
  107. data/tests/cimi/db/db_helper.rb +30 -0
  108. data/tests/cimi/db/schema_test.rb +94 -0
  109. data/tests/cimi/model/collection_spec.rb +0 -1
  110. data/tests/cimi/model/machine_spec.rb +17 -0
  111. data/tests/cimi/spec_helper.rb +3 -2
  112. data/tests/deltacloud/collections/buckets_collection_test.rb +3 -0
  113. data/tests/deltacloud/collections/drivers_collection_test.rb +10 -0
  114. data/tests/deltacloud/collections/hardware_profiles_collection_test.rb +4 -0
  115. data/tests/deltacloud/collections/images_collection_test.rb +4 -0
  116. data/tests/deltacloud/collections/instances_collection_test.rb +14 -1
  117. data/tests/deltacloud/collections/keys_collection_test.rb +4 -0
  118. data/tests/deltacloud/collections/realms_collection_test.rb +47 -0
  119. data/tests/deltacloud/collections/storage_snapshots_collection_test.rb +47 -0
  120. data/tests/deltacloud/collections/storage_volumes_collection_test.rb +47 -0
  121. data/tests/deltacloud/common.rb +15 -0
  122. data/tests/deltacloud/deltacloud_helper_test.rb +0 -4
  123. data/tests/deltacloud/launcher_test.rb +108 -0
  124. data/tests/drivers/ec2/buckets_test.rb +2 -1
  125. data/tests/drivers/mock/buckets_test.rb +27 -0
  126. data/tests/drivers/mock/instances_test.rb +6 -0
  127. data/tests/drivers/openstack/common.rb +1 -1
  128. data/tests/drivers/openstack/hardware_profiles_test.rb +2 -1
  129. data/tests/drivers/openstack/instances_test.rb +18 -17
  130. data/tests/drivers/rhevm/common.rb +1 -0
  131. data/tests/drivers/rhevm/images_test.rb +1 -1
  132. data/tests/drivers/rhevm/instance_test.rb +7 -7
  133. data/tests/helpers/rack/rack_matrix_params_test.rb +0 -2
  134. data/tests/test_helper.rb +2 -1
  135. data/views/errors/403.xml.haml +6 -0
  136. data/views/errors/409.html.haml +47 -0
  137. data/views/errors/409.xml.haml +11 -0
  138. data/views/errors/502.html.haml +6 -5
  139. data/views/images/show.xml.haml +3 -2
  140. data/views/instances/new.html.haml +1 -1
  141. metadata +77 -30
@@ -0,0 +1,20 @@
1
+ # This is a copy of code that has been submitted upstream
2
+ # https://github.com/rackspace/ruby-cloudservers/pull/22
3
+ #
4
+ # Once the pull request is merged we can remove this patch
5
+ # Also see https://issues.apache.org/jira/browse/DTACLOUD-319
6
+
7
+ module CloudServers
8
+ class Connection
9
+
10
+ def list_servers_detail(options = {})
11
+ anti_cache_param="cacheid=#{Time.now.to_i}"
12
+ path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/servers/detail?#{anti_cache_param}" : "#{svrmgmtpath}/servers/detail?#{CloudServers.paginate(options)}&#{anti_cache_param}"
13
+ response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
14
+ CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
15
+ CloudServers.symbolize_keys(JSON.parse(response.body)["servers"])
16
+ end
17
+ alias :servers_detail :list_servers_detail
18
+
19
+ end
20
+ end
@@ -17,6 +17,7 @@
17
17
  require 'cloudfiles'
18
18
  require 'cloudservers'
19
19
  require 'base64'
20
+ require_relative 'anti_cache_monkey_patch'
20
21
 
21
22
  module Deltacloud
22
23
  module Drivers
@@ -118,9 +118,7 @@ class RhevmDriver < Deltacloud::BaseDriver
118
118
  def destroy_image(credentials, image_id)
119
119
  client = new_client(credentials)
120
120
  safely do
121
- unless client.destroy_template(image_id)
122
- raise "ERROR: Unable to remove image"
123
- end
121
+ client.destroy_template(image_id)
124
122
  end
125
123
  end
126
124
 
@@ -208,8 +206,13 @@ class RhevmDriver < Deltacloud::BaseDriver
208
206
  def new_client(credentials)
209
207
  safely do
210
208
  raise 'No API provider set for this request.' unless api_provider
211
- url, datacenter = api_provider.split(';')
212
- OVIRT::Client.new(credentials.user, credentials.password, url, datacenter)
209
+ url, datacenter, filtered = api_provider.split(';')
210
+ if filtered.nil?
211
+ OVIRT::Client.new(credentials.user, credentials.password, url, datacenter)
212
+ else
213
+ filtered_api = filtered.upcase == 'USER'
214
+ OVIRT::Client.new(credentials.user, credentials.password, url, datacenter, nil, filtered_api)
215
+ end
213
216
  end
214
217
  end
215
218
 
@@ -244,14 +247,25 @@ class RhevmDriver < Deltacloud::BaseDriver
244
247
  ip = confserver_ip(inst.id)
245
248
  public_addresses = [ InstanceAddress.new(ip) ]
246
249
  end
247
- # If IP retrieval failed, fallback to VNC and MAC address
248
- if public_addresses.empty?
249
- public_addresses = inst.interfaces.map { |interface| InstanceAddress.new(interface.mac, :type => :mac) }
250
- end
250
+
251
+ public_addresses += inst.interfaces.map { |interface| InstanceAddress.new(interface.mac, :type => :mac) }
252
+
251
253
  if inst.vnc
252
254
  public_addresses << InstanceAddress.new(inst.vnc[:address], :port => inst.vnc[:port], :type => :vnc)
253
255
  end
256
+
257
+ # Remove 'destroy' operation from list of actions when RHEV-M instance
258
+ # is suspended or paused.
259
+ if state == 'PAUSED'
260
+ actions = instance_actions_for(state = 'STOPPED')
261
+ actions.delete(:destroy)
262
+ else
263
+ actions = instance_actions_for(state)
264
+ can_create_image = true
265
+ end
266
+
254
267
  Instance.new(
268
+ :actions=>actions,
255
269
  :id => inst.id,
256
270
  :name => inst.name,
257
271
  :state => state,
@@ -261,10 +275,9 @@ class RhevmDriver < Deltacloud::BaseDriver
261
275
  :launch_time => inst.creation_time,
262
276
  :instance_profile => profile,
263
277
  :hardware_profile_id => profile.id,
264
- :actions=>instance_actions_for( state ),
265
278
  :public_addresses => public_addresses,
266
279
  :private_addresses => [],
267
- :create_image => true
280
+ :create_image => can_create_image || false
268
281
  )
269
282
  end
270
283
 
@@ -283,9 +296,10 @@ class RhevmDriver < Deltacloud::BaseDriver
283
296
  return 'PENDING' if ['WAIT_FOR_LAUNCH', 'REBOOT_IN_PROGRESS', 'SAVING_STATE',
284
297
  'RESTORING_STATE', 'POWERING_UP', 'IMAGE_LOCKED', 'SAVING_STATE'].include? state
285
298
  return 'STOPPING' if state == 'POWERING_DOWN'
286
- return 'STOPPED' if ['UNASSIGNED', 'DOWN', 'PAUSED', 'NOT_RESPONDING', 'SUSPENDED',
299
+ return 'STOPPED' if ['UNASSIGNED', 'DOWN', 'NOT_RESPONDING',
287
300
  'IMAGE_ILLEGAL', 'UNKNOWN'].include? state
288
301
  return 'RUNNING' if ['UP', 'MIGRATING_TO', 'MIGRATING_FROM'].include? state
302
+ return 'PAUSED' if ['PAUSED', 'SUSPENDED'].include? state
289
303
  raise "Unexpected state '#{state}'"
290
304
  end
291
305
 
@@ -342,6 +356,10 @@ class RhevmDriver < Deltacloud::BaseDriver
342
356
  status 404
343
357
  end
344
358
 
359
+ on /(Cannot delete Template. Template is being used)/ do
360
+ status 409
361
+ end
362
+
345
363
  on /(RestClient|RHEVM|OVIRT)/ do
346
364
  status 500
347
365
  end
@@ -16,7 +16,6 @@
16
16
 
17
17
  require 'base64'
18
18
  require 'net/https'
19
- require 'json'
20
19
  require 'digest/md5'
21
20
 
22
21
  module Deltacloud
@@ -87,7 +87,11 @@ class SbcDriver < Deltacloud::BaseDriver
87
87
  # Map DeltaCloud keywords to SBC
88
88
  body['imageID'] = opts[:image_id]
89
89
  body['location'] = opts[:realm_id] || @last_image['location']
90
- body['instanceType'] = opts[:hwp_id].gsub('-', '/') || @last_image['supportedInstanceTypes'][0]['id']
90
+ if opts[:hwp_id]
91
+ body['instanceType'] = opts[:hwp_id].gsub('-', '/')
92
+ else
93
+ body['instanceType'] = @last_image['supportedInstanceTypes'][0]['id']
94
+ end
91
95
 
92
96
  if not body['name']
93
97
  body['name'] = Time.now.to_i.to_s
@@ -45,7 +45,7 @@ module Deltacloud::Drivers::VSphere
45
45
  end
46
46
  end
47
47
  end
48
- break if [:datastore]
48
+ break if vm[:datastore]
49
49
  end
50
50
  vm
51
51
  end
@@ -162,6 +162,7 @@ module Deltacloud::Drivers::Vsphere
162
162
  # instance.
163
163
  template_id = vm.config[:extraConfig].select { |k| k.key == 'template_id' }
164
164
  template_id = template_id.first.value unless template_id.empty?
165
+
165
166
  properties = {
166
167
  :memory => config[:memorySizeMB],
167
168
  :cpus => config[:numCpu],
@@ -177,17 +178,15 @@ module Deltacloud::Drivers::Vsphere
177
178
  # We're getting IP address from 'vmware guest tools'.
178
179
  # If guest tools are not installed, we return list of MAC addresses
179
180
  # assigned to this instance.
180
- public_addresses = []
181
- if vm.guest[:net].empty?
182
- public_addresses = vm.macs.values.collect { |mac_address| InstanceAddress.new(mac_address, :type => :mac) }
183
- else
184
- public_addresses = [InstanceAddress.new(vm.guest[:net].first[:ipAddress].first)]
181
+ public_addresses = vm.macs.values.collect { |mac_address| InstanceAddress.new(mac_address, :type => :mac) }
182
+ if !vm.guest[:net].empty? and ip_address = vm.guest[:net].first[:ipAddress].first
183
+ public_addresses += [InstanceAddress.new(ip_address)]
185
184
  end
186
185
  Instance.new(
187
186
  :id => properties[:name],
188
187
  :name => properties[:name],
189
188
  :owner_id => credentials.user,
190
- :image_id => template_id,
189
+ :image_id => template_id.empty? ? nil : template_id,
191
190
  :description => properties[:full_name],
192
191
  :realm_id => realm_id,
193
192
  :state => instance_state,
@@ -215,7 +214,7 @@ module Deltacloud::Drivers::Vsphere
215
214
  if opts[:hwp_cpu]
216
215
  raise "Invalid CPU value. Must be in integer format" unless valid_cpu_value?(opts[:hwp_cpu])
217
216
  end
218
- vm = find_vm(credentials, opts[:image_id])
217
+ vm = find_vm(credentials, image_id)
219
218
  raise "ERROR: Could not find the image in given datacenter" unless vm[:instance]
220
219
  # New instance need valid resource pool and datastore to be placed.
221
220
  # For this reason, realm_id **needs** to be set.
@@ -291,7 +290,7 @@ module Deltacloud::Drivers::Vsphere
291
290
  :config => RbVmomi::VIM.VirtualMachineConfigSpec(machine_config)
292
291
  )
293
292
  instance_profile = InstanceProfile::new('default', :hwp_memory => opts[:hwp_memory], :hwp_cpu => opts[:hwp_cpu])
294
- task = vm[:instance].CloneVM_Task(:folder => vm[:instance].parent, :name => opts[:name], :spec => spec)
293
+ task = vm[:instance].CloneVM_Task(:folder => vm[:instance].parent, :name => opts[:name] || "inst#{Time.now.to_i}", :spec => spec)
295
294
  new_instance = Instance::new(
296
295
  :id => opts[:name],
297
296
  :name => opts[:name],
@@ -381,6 +380,10 @@ module Deltacloud::Drivers::Vsphere
381
380
  status 504
382
381
  end
383
382
 
383
+ on /missing required parameter name/ do
384
+ status 400
385
+ end
386
+
384
387
  on /Invalid/ do
385
388
  status 400
386
389
  end
@@ -410,7 +413,14 @@ module Deltacloud::Drivers::Vsphere
410
413
  end
411
414
 
412
415
  def host_endpoint
413
- endpoint = api_provider
416
+ endpoint = "#{api_provider}"
417
+ # We need to have the 'hostname' form in API_PROVIDER, but to be
418
+ # compatible with other drivers, we allow 'https://vsphere/api' format.
419
+ # The 'http' and '/.*' parts are however stripped.
420
+ if endpoint =~ /^http/
421
+ endpoint.gsub!(/^http(s?):\/\//, '')
422
+ endpoint.gsub!(/\/.*$/, '')
423
+ end
414
424
  endpoint || Deltacloud::Drivers::driver_config[:vsphere][:entrypoints]['default']['default']
415
425
  end
416
426
 
@@ -77,6 +77,43 @@ DELTACLOUD_BLOBMETA_HEADER = /HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i
77
77
  metadata.gsub_keys(DELTACLOUD_BLOBMETA_HEADER, rename_to)
78
78
  end
79
79
 
80
+ #in the following segment* methods, using context.env["QUERY_STRING"] rather than context.params so it works for both Thin and Sinatra request objects (streaming)
81
+ def self.segmented_blob(request_context)
82
+ return true if (request_context.env["HTTP_X_DELTACLOUD_BLOBTYPE"] == 'segmented' || request_context.env["QUERY_STRING"].match(/blob_type=segmented/))
83
+ false
84
+ end
85
+
86
+ def self.segment_order(request_context)
87
+ (request_context.env["HTTP_X_DELTACLOUD_SEGMENTORDER"] || request_context.env["QUERY_STRING"].match(/segment_order=(\w)*/){|m| m[0].split("=").pop})
88
+ end
89
+
90
+ def self.segmented_blob_id(request_context)
91
+ (request_context.env["HTTP_X_DELTACLOUD_SEGMENTEDBLOB"] || request_context.env["QUERY_STRING"].match(/segmented_blob=(\w)*/){|m| m[0].split("=").pop})
92
+ end
93
+
94
+ def self.segmented_blob_op_type(request_context)
95
+ is_segmented = segmented_blob(request_context)
96
+ blob_id = segmented_blob_id(request_context)
97
+ segment_order = segment_order(request_context)
98
+ #if blob_type=segmented AND segmented_blob_id AND segment_order then it is a "SEGMENT"
99
+ #if blob_type=segmented AND segmented_blob_id then it is a "FINALIZE"
100
+ #if blob_type=segmented then it is "INIT"
101
+ return "segment" if (is_segmented && blob_id && segment_order)
102
+ return "finalize" if (is_segmented && blob_id)
103
+ return "init" if is_segmented
104
+ nil # should explode something instead
105
+ end
106
+
107
+ #in "1=abc , 2=def , 3=ghi"
108
+ #out {"1"=>"abc", "2"=>"def", "3"=>"ghi"}
109
+ def self.extract_segmented_blob_manifest(request)
110
+ manifest_hash = request.body.read.split(",").inject({}) do |res,current|
111
+ k,v=current.strip.split("=")
112
+ res[k]=v
113
+ res
114
+ end
115
+ end
116
+
80
117
  end
81
118
 
82
119
  #Monkey patch for streaming blobs:
@@ -158,11 +195,10 @@ class BlobStreamIO
158
195
  @content_length = request.env['CONTENT_LENGTH']
159
196
  @http, provider_request = Deltacloud::API.driver.blob_stream_connection({:user=>user,
160
197
  :password=>password, :bucket=>bucket, :blob=>blob, :metadata=> user_meta,
161
- :content_type=>content_type, :content_length=>@content_length })
198
+ :content_type=>content_type, :content_length=>@content_length, :context=>request })
162
199
  @content_length = @content_length.to_i #for comparison of size in '<< (data)'
163
200
  @sock = @http.request(provider_request, nil, true)
164
201
  end
165
-
166
202
  def << (data)
167
203
  @sock.write(data)
168
204
  @size += data.length
@@ -170,6 +206,9 @@ class BlobStreamIO
170
206
  result = @http.end_request
171
207
  if result.is_a?(Net::HTTPSuccess)
172
208
  @client_request.env["BLOB_SUCCESS"] = "true"
209
+ if BlobHelper.segmented_blob_op_type(@client_request) == "segment"
210
+ @client_request.env["BLOB_SEGMENT_ID"] = Deltacloud::API.driver.blob_segment_id(@client_request, result)
211
+ end
173
212
  else
174
213
  @client_request.env["BLOB_FAIL"] = result.body
175
214
  end
@@ -195,7 +234,7 @@ class BlobStreamIO
195
234
  private
196
235
 
197
236
  def parse_bucket_blob(request_string)
198
- array = request_string.split("/")
237
+ array = request_string.gsub(/(&\w*=\w*)*$/, "").split("/")
199
238
  blob = array.pop
200
239
  bucket = array.pop
201
240
  return bucket, blob
@@ -18,6 +18,31 @@ module Deltacloud::Helpers
18
18
 
19
19
  require 'benchmark'
20
20
 
21
+ def collections_to_json(collections)
22
+ r = {
23
+ :version => settings.version,
24
+ :driver => driver_symbol,
25
+ :provider => Thread.current[:provider] || ENV['API_PROVIDER'],
26
+ :links => collections.map { |c|
27
+ {
28
+ :rel => c.collection_name,
29
+ :href => self.send(:"#{c.collection_name}_url"),
30
+ :features => c.features.select { |f| driver.class.has_feature?(c.collection_name, f.name) }.map { |f|
31
+ f.operations.map { |o|
32
+ { :name => f.name, :rel => o.name, :params => o.params_array, :constraints => constraints_hash_for(c.collection_name, f.name) }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ r[:provider] ||= 'default'
39
+ JSON::dump(:api => r)
40
+ end
41
+
42
+ def constraints_hash_for(collection_name, feature_name)
43
+ driver.class.constraints(:collection => collection_name, :feature => feature_name).inject({}) { |r, v| r[v[0]]=v[1];r }
44
+ end
45
+
21
46
  def request_headers
22
47
  env.inject({}){|acc, (k,v)| acc[$1.downcase] = v if k =~ /^http_(.*)/i; acc}
23
48
  end
@@ -48,22 +73,13 @@ module Deltacloud::Helpers
48
73
  respond_to do |format|
49
74
  format.html { haml :"#{model}/index" }
50
75
  format.xml { haml :"#{model}/index" }
51
- format.json { @media_type=:xml; to_json(haml(:"#{model}/index")) }
76
+ format.json { JSON::dump({ model => @elements.map { |el| el.to_hash(self) }}) }
52
77
  end
53
78
  else
54
79
  report_error(@exception.respond_to?(:code) ? @exception.code : 500)
55
80
  end
56
81
  end
57
82
 
58
- def xml_to_json(model)
59
- @media_type = :xml
60
- to_json(haml(:"#{model}"))
61
- end
62
-
63
- def to_json(xml)
64
- Crack::XML.parse(xml).to_json
65
- end
66
-
67
83
  def show(model)
68
84
  @benchmark = Benchmark.measure do
69
85
  @element = driver.send(model, credentials, { :id => params[:id]} )
@@ -74,7 +90,7 @@ module Deltacloud::Helpers
74
90
  respond_to do |format|
75
91
  format.html { haml :"#{model.to_s.pluralize}/show" }
76
92
  format.xml { haml :"#{model.to_s.pluralize}/show" }
77
- format.json { @media_type=:xml; to_json(haml(:"#{model.to_s.pluralize}/show")) }
93
+ format.json { JSON::dump(model => @element.to_hash(self)) }
78
94
  end
79
95
  else
80
96
  report_error(404)
@@ -101,7 +117,7 @@ module Deltacloud::Helpers
101
117
  response.status = @code
102
118
 
103
119
  backtrace = (@error.respond_to?(:backtrace) and !@error.backtrace.nil?) ?
104
- "\n\n#{@error.backtrace[0..10].join("\n")}\n\n" : ''
120
+ "\n\n#{@error.backtrace[0..20].join("\n")}\n\n" : ''
105
121
 
106
122
  if @code.to_s =~ /5(\d+)/
107
123
  log.error(@code.to_s) { "[#{@error.class.to_s}] #{message}#{backtrace}" }
@@ -109,7 +125,7 @@ module Deltacloud::Helpers
109
125
 
110
126
  respond_to do |format|
111
127
  format.xml { haml :"errors/#{@code || @error.code}", :layout => false }
112
- format.json { xml_to_json("errors/#{@code || @error.code}") }
128
+ format.json { JSON::dump({ :code => @code || @error.code, :message => message, :error => @error.class.name }) }
113
129
  format.html {
114
130
  begin
115
131
  haml :"errors/#{@code || @error.code}", :layout => :error
@@ -151,7 +167,7 @@ module Deltacloud::Helpers
151
167
  response = respond_to do |format|
152
168
  format.xml { haml :"instances/show" }
153
169
  format.html { haml :"instances/show" }
154
- format.json { xml_to_json("instances/show") }
170
+ format.json { JSON::dump(@instance.to_hash(self)) }
155
171
  end
156
172
  halt 202, response
157
173
  end
@@ -245,6 +261,7 @@ module Deltacloud::Helpers
245
261
  when 404; { :message => "Not Found" }
246
262
  when 405; { :message => "Method Not Allowed" }
247
263
  when 406; { :message => "Not Acceptable" }
264
+ when 409; { :message => "Resource Conflict" }
248
265
  when 500; { :message => "Internal Server Error" }
249
266
  when 502; { :message => "Backend Server Error" }
250
267
  when 504; { :message => "Gateway Timeout" }
@@ -25,4 +25,13 @@ class Address < BaseModel
25
25
  !self.instance_id.nil?
26
26
  end
27
27
 
28
+ def to_hash(context)
29
+ r = {
30
+ :id => self.id,
31
+ :associated => associated?
32
+ }
33
+ r[:instance_id] = instance_id if associated?
34
+ r
35
+ end
36
+
28
37
  end
@@ -44,4 +44,8 @@ class BaseModel
44
44
  @id
45
45
  end
46
46
 
47
+ def to_entity
48
+ self.class.name.downcase
49
+ end
50
+
47
51
  end
@@ -24,4 +24,16 @@ class Blob < BaseModel
24
24
  attr_accessor :content
25
25
  attr_accessor :user_metadata
26
26
 
27
+ def to_hash(context)
28
+ {
29
+ :id => self.id,
30
+ :bucket => { :rel => :bucket, :href => context.bucket_url(bucket), :id => bucket },
31
+ :content_length => content_length,
32
+ :content_type => content_type,
33
+ :last_modified => last_modified,
34
+ :content => content,
35
+ :user_metadata => user_metadata
36
+ }
37
+ end
38
+
27
39
  end
@@ -24,4 +24,13 @@ class Bucket < BaseModel
24
24
  @blob_list || []
25
25
  end
26
26
 
27
+ def to_hash(context)
28
+ {
29
+ :id => self.id,
30
+ :name => name,
31
+ :size => size,
32
+ :blob_list => blob_list.map { |b| { :rel => :blob, :href => context.url("/buckets/#{self.id}/#{b}"), :id => b }}
33
+ }
34
+ end
35
+
27
36
  end