deltacloud-core 0.4.0 → 0.4.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.
@@ -27,7 +27,7 @@ module VSphere
27
27
  # he have to pad the content of the iso file
28
28
  # that mean a limit of 400 kb file since
29
29
  # 1 sector of iso file = 2048 bytes
30
- ISO_SECTORS=200
30
+ ISO_SECTORS=202
31
31
 
32
32
  RbVmomi::VIM::Datastore::class_eval do
33
33
  def soap
@@ -43,7 +43,7 @@ module VSphere
43
43
  end
44
44
 
45
45
  def user_data!(datastore,base64_content,file_name)
46
- command="#{MKISOFS_EXECUTABLE} -stream-file-name #{file_name}.txt -stream-media-size #{ISO_SECTORS}"
46
+ command="#{MKISOFS_EXECUTABLE} -stream-file-name deltacloud-user-data.txt -stream-media-size #{ISO_SECTORS}"
47
47
  iso_file=''
48
48
  Open3::popen3(command) do |stdin, stdout, stderr|
49
49
  stdin.write(base64_content.unpack("m"))
@@ -18,5 +18,6 @@ require 'deltacloud/helpers/application_helper'
18
18
  require 'deltacloud/helpers/json_helper'
19
19
  require 'deltacloud/helpers/conversion_helper'
20
20
  require 'deltacloud/helpers/hardware_profiles_helper'
21
+ require 'deltacloud/helpers/blob_stream'
21
22
 
22
23
  helpers ApplicationHelper, ConversionHelper, HardwareProfilesHelper, JSONHelper
@@ -92,6 +92,7 @@ module ApplicationHelper
92
92
  @benchmark = Benchmark.measure do
93
93
  @element = driver.send(model, credentials, { :id => params[:id]} )
94
94
  end
95
+ headers['X-Backend-Runtime'] = @benchmark.real.to_s
95
96
  instance_variable_set("@#{model}", @element)
96
97
  if @element
97
98
  respond_to do |format|
@@ -152,7 +153,7 @@ module ApplicationHelper
152
153
 
153
154
  def link_to_action(action, url, method)
154
155
  capture_haml do
155
- haml_tag :form, :method => :post, :action => url, :class => [:link, method] do
156
+ haml_tag :form, :method => :post, :action => url, :class => [:link, method], :'data-ajax' => 'false' do
156
157
  haml_tag :input, :type => :hidden, :name => '_method', :value => method
157
158
  haml_tag :button, :type => :submit, :'data-ajax' => 'false', :'data-inline' => "true" do
158
159
  haml_concat action
@@ -258,7 +259,7 @@ module ApplicationHelper
258
259
  def address_type(address)
259
260
  case address
260
261
  when /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/; :ipv4
261
- when /^.*:([\-\d]+)$/; :vnc
262
+ when /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:[\-\d]+)$/; :vnc
262
263
  when /^(\S{1,2}:\S{1,2}:\S{1,2}:\S{1,2}:\S{1,2}:\S{1,2})?$/; :mac
263
264
  else :hostname
264
265
  end
@@ -63,23 +63,6 @@ rescue LoadError => e
63
63
  end
64
64
  end
65
65
 
66
- class Hash
67
-
68
- def gsub_keys(rgx_pattern, replacement)
69
- remove = []
70
- self.each_key do |key|
71
- if key.to_s.match(rgx_pattern)
72
- new_key = key.to_s.gsub(rgx_pattern, replacement).downcase
73
- self[new_key] = self[key]
74
- remove << key
75
- end
76
- end
77
- #remove the original keys
78
- self.delete_if{|k,v| remove.include?(k)}
79
- end
80
-
81
- end
82
-
83
66
  module BlobHelper
84
67
 
85
68
  def self.extract_blob_metadata_hash(env_hash)
@@ -14,16 +14,6 @@
14
14
  # License for the specific language governing permissions and limitations
15
15
  # under the License.
16
16
 
17
- $:.unshift File.join(File.dirname(__FILE__), 'lib')
18
-
19
- require 'drivers'
20
-
21
- require 'deltacloud/core_ext'
22
-
23
- require 'deltacloud/base_driver'
24
- require 'deltacloud/hardware_profile'
25
- require 'deltacloud/state_machine'
26
- require 'deltacloud/helpers'
27
17
  require 'deltacloud/models/base_model'
28
18
  require 'deltacloud/models/realm'
29
19
  require 'deltacloud/models/image'
@@ -38,6 +28,3 @@ require 'deltacloud/models/blob'
38
28
  require 'deltacloud/models/load_balancer'
39
29
  require 'deltacloud/models/firewall'
40
30
  require 'deltacloud/models/firewall_rule'
41
-
42
- require 'deltacloud/validation'
43
- require 'deltacloud/runner'
@@ -59,7 +59,8 @@ module Sinatra
59
59
  def initialize(coll, name, opts, &block)
60
60
  @name = name.to_sym
61
61
  opts = STANDARD[@name].merge(opts) if standard?
62
- @collection = coll
62
+ @path_generator = opts[:path_generator]
63
+ @collection, @standard = coll, opts[:standard]
63
64
  raise "No method for operation #{name}" unless opts[:method]
64
65
  @method = opts[:method].to_sym
65
66
  @member = opts[:member]
@@ -74,7 +75,7 @@ module Sinatra
74
75
  end
75
76
 
76
77
  def standard?
77
- STANDARD.keys.include?(name)
78
+ STANDARD.keys.include?(name) || @standard
78
79
  end
79
80
 
80
81
  def form?
@@ -125,8 +126,17 @@ module Sinatra
125
126
  end
126
127
  end
127
128
 
129
+ def member?
130
+ if standard?
131
+ @member || STANDARD[name][:member]
132
+ else
133
+ @member
134
+ end
135
+ end
136
+
128
137
  def path(args = {})
129
- if @member
138
+ return @path_generator.call(self) if @path_generator
139
+ if member?
130
140
  if standard?
131
141
  "#{@collection.name}/:id"
132
142
  else
@@ -190,12 +200,12 @@ module Sinatra
190
200
  end
191
201
 
192
202
  class Collection
193
- attr_reader :name, :operations
203
+ attr_reader :name, :operations, :subcollections
194
204
 
195
205
  def initialize(name, &block)
196
206
  @name = name
197
207
  @description = ""
198
- @operations = {}
208
+ @operations, @subcollections = {}, {}
199
209
  @global = false
200
210
  instance_eval(&block) if block_given?
201
211
  generate_documentation
@@ -203,6 +213,10 @@ module Sinatra
203
213
  generate_options
204
214
  end
205
215
 
216
+ def subcollection?
217
+ self.class == SubCollection
218
+ end
219
+
206
220
  # Set/Return description for collection
207
221
  # If first parameter is not present, full description will be
208
222
  # returned.
@@ -280,13 +294,21 @@ module Sinatra
280
294
  @operations[name] = Operation.new(self, name, opts, &block)
281
295
  end
282
296
 
297
+ def collection(name, opts={}, &block)
298
+ if subcollections.keys.include?(name)
299
+ raise DuplicateOperationException::new(500, "DuplicateSubcollection", "Subcollection #{name} is already defined", [])
300
+ end
301
+ subcollections[name] = SubCollection.new(self, name, opts, &block)
302
+ subcollections[name].generate
303
+ end
304
+
283
305
  def generate
284
306
  operations.values.reject { |op| op.member }.each { |o| o.generate }
285
307
  operations.values.select { |op| op.member }.each { |o| o.generate }
286
308
  app = ::Sinatra::Application
287
309
  collname = name # Work around Ruby's weird scoping/capture
288
310
  app.send(:define_method, "#{name.to_s.singularize}_url") do |id|
289
- api_url_for "#{collname}/#{id}", :full
311
+ api_url_for "#{collname}/#{id}", :full
290
312
  end
291
313
  if index_op = operations[:index]
292
314
  app.send(:define_method, "#{name}_url") do
@@ -296,12 +318,66 @@ module Sinatra
296
318
  end
297
319
 
298
320
  def check_supported(driver)
299
- unless global? || driver.has_collection?(@name)
321
+ unless global? || driver.has_collection?(@name) || self.kind_of?(Sinatra::Rabbit::SubCollection)
300
322
  raise UnsupportedCollectionException
301
323
  end
302
324
  end
303
325
  end
304
326
 
327
+ class SubCollection < Collection
328
+
329
+ attr_accessor :parent
330
+
331
+ def initialize(parent, name, opts={}, &block)
332
+ self.parent = parent
333
+ super(name, &block)
334
+ end
335
+
336
+ def operation(name, opts = {}, &block)
337
+ if @operations.keys.include?(name)
338
+ raise DuplicateOperationException::new(500, "DuplicateOperation", "Operation #{name} is already defined", [])
339
+ end
340
+ # Preserve self as local variable to workaround Ruby namespace
341
+ # weirdness
342
+ c = self
343
+ path_generator = Proc.new do |obj|
344
+ if obj.member?
345
+ if obj.standard?
346
+ "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}"
347
+ else
348
+ "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}/#{name}"
349
+ end
350
+ else
351
+ if obj.form?
352
+ "#{parent.name}/:id/:#{parent.name.to_s.singularize}/#{obj.name}"
353
+ else
354
+ "#{parent.name}/:#{parent.name.to_s.singularize}"
355
+ end
356
+ end
357
+ end
358
+ opts.merge!({
359
+ :path_generator => path_generator
360
+ })
361
+ @operations[name] = Operation.new(self, name, opts, &block)
362
+ end
363
+
364
+ def generate
365
+ operations.values.reject { |op| op.member }.each { |o| o.generate }
366
+ operations.values.select { |op| op.member }.each { |o| o.generate }
367
+ app = ::Sinatra::Application
368
+ collname = name # Work around Ruby's weird scoping/capture
369
+ app.send(:define_method, "#{parent.name.to_s}_#{name.to_s.singularize}_url") do |id, subid|
370
+ api_url_for "#{collname}/#{id}/#{subid}", :full
371
+ end
372
+ if index_op = operations[:index]
373
+ app.send(:define_method, "#{parent.name.to_s}_#{name}_url") do
374
+ api_url_for index_op.path.gsub(/\/\?$/,''), :full
375
+ end
376
+ end
377
+ end
378
+
379
+ end
380
+
305
381
  def collections
306
382
  @collections ||= {}
307
383
  end
@@ -0,0 +1,73 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one or more
3
+ # contributor license agreements. See the NOTICE file distributed with
4
+ # this work for additional information regarding copyright ownership. The
5
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance with the
7
+ # License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations
15
+ # under the License.
16
+
17
+ require 'sinatra/base'
18
+
19
+ module Sinatra
20
+ module VerboseLogger
21
+
22
+ module Helpers
23
+
24
+ def info(message)
25
+ puts sprintf("\033[1;34m[INFO: #{caller_method_name}]\033[0m: %s", message.inspect)
26
+ end
27
+
28
+ alias :debug :info
29
+
30
+ def warn(message)
31
+ puts sprintf("\033[1;31m[WARN: #{caller_method_name}]\033[0m: %s", message.inspect)
32
+ end
33
+
34
+ private
35
+
36
+ def caller_method_name
37
+ caller(2).first
38
+ end
39
+
40
+ end
41
+
42
+ def enable_verbose_logging!
43
+ disable :logging
44
+ before {
45
+ puts sprintf("\n\033[1;29mProcessing %s\033[0m (for %s at #{Time.now}) [%s] [\033[1;29m%s\033[0m]",
46
+ request.path_info, request.ip, request.request_method, driver_name)
47
+ puts "Parameters: #{params.inspect}"
48
+ if provider=Thread::current[:provider] || ENV['API_PROVIDER']
49
+ puts "Provider: #{provider}"
50
+ end
51
+ puts "Authentication: #{request.env['HTTP_AUTHORIZATION'].split(' ').first}" if request.env['HTTP_AUTHORIZATION']
52
+ puts "Server: #{request.env['SERVER_SOFTWARE']}"
53
+ puts "Accept: #{request.env['HTTP_ACCEPT']}"
54
+ puts
55
+ }
56
+ after {
57
+ puts sprintf("\nCompleted in \033[1;29m%4f\033[0m | %4f | %s | \033[1;36m%s\033[0m | %s\n",
58
+ response.header['X-Backend-Runtime'] || 0, response.header['X-Runtime'] || 0, response.status, response.content_type, request.url)
59
+ }
60
+ end
61
+
62
+ def self.registered(app)
63
+ app.helpers VerboseLogger::Helpers
64
+ app.enable_verbose_logging! if ENV['API_VERBOSE']
65
+ end
66
+ end
67
+ end
68
+
69
+ Sinatra::Application.register Sinatra::VerboseLogger
70
+
71
+ Deltacloud::BaseDriver.class_eval do
72
+ include Sinatra::VerboseLogger::Helpers
73
+ end
@@ -59,15 +59,21 @@ module Sinatra
59
59
  when :path_only
60
60
  base = request.script_name
61
61
  when :full
62
- scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || request.scheme
63
- port = request.env['HTTP_X_FORWARDED_PORT'] || request.port
64
- if ((scheme == 'http' && port.to_s == '80') ||
62
+ scheme = request.scheme
63
+ port = request.port
64
+ request_host = request.host
65
+ if request.env['HTTP_X_FORWARDED_FOR']
66
+ scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
67
+ port = request.env['HTTP_X_FORWARDED_PORT']
68
+ request_host = request.env['HTTP_X_FORWARDED_HOST']
69
+ end
70
+ if (port.nil? || port == "" ||
71
+ (scheme == 'http' && port.to_s == '80') ||
65
72
  (scheme == 'https' && port.to_s == '443'))
66
73
  port = ""
67
74
  else
68
75
  port = ":#{port}"
69
76
  end
70
- request_host = HOSTNAME ? HOSTNAME : request.host
71
77
  base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
72
78
  else
73
79
  raise TypeError, "Unknown url_for mode #{mode}"
data/server.rb CHANGED
@@ -15,7 +15,6 @@
15
15
 
16
16
  require 'sinatra'
17
17
  require 'deltacloud'
18
- require 'drivers'
19
18
  require 'json'
20
19
  require 'sinatra/rack_accept'
21
20
  require 'sinatra/static_assets'
@@ -24,7 +23,7 @@ require 'sinatra/lazy_auth'
24
23
  require 'erb'
25
24
  require 'haml'
26
25
  require 'open3'
27
- require 'lib/deltacloud/helpers/blob_stream'
26
+ require 'sinatra/sinatra_verbose'
28
27
  require 'sinatra/rack_driver_select'
29
28
  require 'sinatra/rack_runtime'
30
29
  require 'sinatra/rack_etag'
@@ -32,7 +31,7 @@ require 'sinatra/rack_date'
32
31
  require 'sinatra/rack_matrix_params'
33
32
  require 'sinatra/rack_syslog'
34
33
 
35
- set :version, '0.4.0'
34
+ set :version, '0.4.1'
36
35
 
37
36
  include Deltacloud::Drivers
38
37
  set :drivers, Proc.new { driver_config }
@@ -48,7 +47,7 @@ use Rack::Date
48
47
 
49
48
  configure do
50
49
  set :views, File.dirname(__FILE__) + '/views'
51
- set :public, File.dirname(__FILE__) + '/public'
50
+ set :public_folder, File.dirname(__FILE__) + '/public'
52
51
  # Try to load the driver on startup to fail early if there are issues
53
52
  driver
54
53
  end
@@ -78,6 +77,15 @@ error do
78
77
  report_error
79
78
  end
80
79
 
80
+ before do
81
+ # Respond with 400, If we don't get a http Host header,
82
+ halt 400, "Unable to find HTTP Host header" if @env['HTTP_HOST'] == nil
83
+ end
84
+
85
+ after do
86
+ headers 'Server' => 'Apache-Deltacloud/' + settings.version
87
+ end
88
+
81
89
  # Redirect to /api
82
90
  get '/' do redirect root_url, 301; end
83
91
 
@@ -753,39 +761,6 @@ collection :keys do
753
761
 
754
762
  end
755
763
 
756
- #create a new blob using PUT - streams through deltacloud
757
- put "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob" do
758
- if(env["BLOB_SUCCESS"]) #ie got a 200ok after putting blob
759
- content_type = env["CONTENT_TYPE"]
760
- content_type ||= ""
761
- @blob = driver.blob(credentials, {:id => params[:blob],
762
- 'bucket' => params[:bucket]})
763
- respond_to do |format|
764
- format.xml { haml :"blobs/show" }
765
- format.html { haml :"blobs/show" }
766
- format.json { convert_to_json(:blob, @blob) }
767
- end
768
- elsif(env["BLOB_FAIL"])
769
- report_error(500) #OK?
770
- else # small blobs - < 112kb dont hit the streaming monkey patch - use 'normal' create_blob
771
- # also, if running under webrick don't hit the streaming patch (Thin specific)
772
- bucket_id = params[:bucket]
773
- blob_id = params[:blob]
774
- temp_file = Tempfile.new("temp_blob_file")
775
- temp_file.write(env['rack.input'].read)
776
- temp_file.flush
777
- content_type = env['CONTENT_TYPE'] || ""
778
- blob_data = {:tempfile => temp_file, :type => content_type}
779
- user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
780
- @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
781
- temp_file.delete
782
- respond_to do |format|
783
- format.xml { haml :"blobs/show" }
784
- format.html { haml :"blobs/show"}
785
- end
786
- end
787
- end
788
-
789
764
  #get html form for creating a new blob
790
765
 
791
766
  # The URL for getting the new blob form for the HTML UI looks like the URL
@@ -801,107 +776,160 @@ get "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/#{NEW_BLOB_FOR
801
776
  end
802
777
  end
803
778
 
804
- #create a new blob using html interface - NON STREAMING (i.e. browser POST http form data)
805
- post "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket" do
806
- bucket_id = params[:bucket]
807
- blob_id = params['blob_id'] || params['blob'] #keep 'blob' just in case
808
- blob_data = params['blob_data']
809
- user_meta = {}
810
- #metadata from params (i.e., passed by http form post, e.g. browser)
811
- max = params[:meta_params]
812
- if(max)
813
- (1..max.to_i).each do |i|
814
- key = params[:"meta_name#{i}"]
815
- key = "HTTP_X_Deltacloud_Blobmeta_#{key}"
816
- value = params[:"meta_value#{i}"]
817
- user_meta[key] = value
779
+ collection :buckets do
780
+ description "Cloud Storage buckets - aka buckets|directories|folders"
781
+
782
+ collection :blobs do
783
+ description "Blobs associated with given bucket"
784
+
785
+ operation :show do
786
+ description "Display blob"
787
+ control do
788
+ @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
789
+ if @blob
790
+ respond_to do |format|
791
+ format.xml { haml :"blobs/show" }
792
+ format.html { haml :"blobs/show" }
793
+ format.json { convert_to_json(:blob, @blob) }
794
+ end
795
+ else
796
+ report_error(404)
797
+ end
798
+ end
799
+
818
800
  end
819
- end
820
- @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
821
- respond_to do |format|
822
- format.xml { haml :"blobs/show" }
823
- format.html { haml :"blobs/show"}
824
- end
825
- end
826
801
 
827
- #delete a blob
828
- delete "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob" do
829
- bucket_id = params[:bucket]
830
- blob_id = params[:blob]
831
- driver.delete_blob(credentials, bucket_id, blob_id)
832
- status 204
833
- respond_to do |format|
834
- format.xml
835
- format.json
836
- format.html { redirect(bucket_url(bucket_id)) }
837
- end
838
- end
802
+ operation :create do
803
+ description "Create new blob"
804
+ control do
805
+ bucket_id = params[:bucket]
806
+ blob_id = params['blob_id']
807
+ blob_data = params['blob_data']
808
+ user_meta = {}
809
+ #metadata from params (i.e., passed by http form post, e.g. browser)
810
+ max = params[:meta_params]
811
+ if(max)
812
+ (1..max.to_i).each do |i|
813
+ key = params[:"meta_name#{i}"]
814
+ key = "HTTP_X_Deltacloud_Blobmeta_#{key}"
815
+ value = params[:"meta_value#{i}"]
816
+ user_meta[key] = value
817
+ end
818
+ end
819
+ @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
820
+ respond_to do |format|
821
+ format.xml { haml :"blobs/show" }
822
+ format.html { haml :"blobs/show"}
823
+ end
824
+ end
825
+ end
839
826
 
840
- #get blob metadata
841
- head "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob" do
842
- @blob_id = params[:blob]
843
- @blob_metadata = driver.blob_metadata(credentials, {:id => params[:blob], 'bucket' => params[:bucket]})
844
- if @blob_metadata
845
- @blob_metadata.each do |k,v|
846
- headers["X-Deltacloud-Blobmeta-#{k}"] = v
827
+ operation :destroy do
828
+ description "Destroy given blob"
829
+ control do
830
+ bucket_id = params[:bucket]
831
+ blob_id = params[:blob]
832
+ driver.delete_blob(credentials, bucket_id, blob_id)
833
+ status 204
834
+ respond_to do |format|
835
+ format.xml
836
+ format.json
837
+ format.html { redirect(bucket_url(bucket_id)) }
838
+ end
847
839
  end
848
- status 204
849
- respond_to do |format|
850
- format.xml
851
- format.json
840
+ end
841
+
842
+ operation :stream, :member => true, :standard => true, :method => :put do
843
+ description "Stream new blob data into the blob"
844
+ control do
845
+ if(env["BLOB_SUCCESS"]) #ie got a 200ok after putting blob
846
+ content_type = env["CONTENT_TYPE"]
847
+ content_type ||= ""
848
+ @blob = driver.blob(credentials, {:id => params[:blob],
849
+ 'bucket' => params[:bucket]})
850
+ respond_to do |format|
851
+ format.xml { haml :"blobs/show" }
852
+ format.html { haml :"blobs/show" }
853
+ format.json { convert_to_json(:blob, @blob) }
854
+ end
855
+ elsif(env["BLOB_FAIL"])
856
+ report_error(500) #OK?
857
+ else # small blobs - < 112kb dont hit the streaming monkey patch - use 'normal' create_blob
858
+ # also, if running under webrick don't hit the streaming patch (Thin specific)
859
+ bucket_id = params[:bucket]
860
+ blob_id = params[:blob]
861
+ temp_file = Tempfile.new("temp_blob_file")
862
+ temp_file.write(env['rack.input'].read)
863
+ temp_file.flush
864
+ content_type = env['CONTENT_TYPE'] || ""
865
+ blob_data = {:tempfile => temp_file, :type => content_type}
866
+ user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
867
+ @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
868
+ temp_file.delete
869
+ respond_to do |format|
870
+ format.xml { haml :"blobs/show" }
871
+ format.html { haml :"blobs/show"}
872
+ end
873
+ end
852
874
  end
853
- else
854
- report_error(404)
855
- end
856
- end
875
+ end
857
876
 
858
- #update blob metadata
859
- post "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob" do
860
- meta_hash = BlobHelper::extract_blob_metadata_hash(request.env)
861
- success = driver.update_blob_metadata(credentials, {'bucket'=>params[:bucket], :id =>params[:blob], 'meta_hash' => meta_hash})
862
- if(success)
863
- meta_hash.each do |k,v|
864
- headers["X-Deltacloud-Blobmeta-#{k}"] = v
877
+ operation :metadata, :member => true, :standard => true, :method => :head do
878
+ description "Get blob metadata"
879
+ control do
880
+ @blob_id = params[:blob]
881
+ @blob_metadata = driver.blob_metadata(credentials, {:id => params[:blob], 'bucket' => params[:bucket]})
882
+ if @blob_metadata
883
+ @blob_metadata.each do |k,v|
884
+ headers["X-Deltacloud-Blobmeta-#{k}"] = v
885
+ end
886
+ status 204
887
+ respond_to do |format|
888
+ format.xml
889
+ format.json
890
+ end
891
+ else
892
+ report_error(404)
893
+ end
894
+ end
865
895
  end
866
- status 204
867
- respond_to do |format|
868
- format.xml
869
- format.json
896
+
897
+ operation :update, :member => true, :method => :post do
898
+ description "Update blob metadata"
899
+ control do
900
+ meta_hash = BlobHelper::extract_blob_metadata_hash(request.env)
901
+ success = driver.update_blob_metadata(credentials, {'bucket'=>params[:bucket], :id =>params[:blob], 'meta_hash' => meta_hash})
902
+ if(success)
903
+ meta_hash.each do |k,v|
904
+ headers["X-Deltacloud-Blobmeta-#{k}"] = v
905
+ end
906
+ status 204
907
+ respond_to do |format|
908
+ format.xml
909
+ format.json
910
+ end
911
+ else
912
+ report_error(404) #FIXME is this the right error code?
913
+ end
914
+ end
870
915
  end
871
- else
872
- report_error(404) #FIXME is this the right error code?
873
- end
874
- end
875
916
 
876
- #Get a particular blob's particulars (not actual blob data)
877
- get "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob" do
878
- @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
879
- if @blob
880
- respond_to do |format|
881
- format.xml { haml :"blobs/show" }
882
- format.html { haml :"blobs/show" }
883
- format.json { convert_to_json(:blob, @blob) }
917
+ operation :content, :member => true, :method => :get do
918
+ description "Download blob content"
919
+ control do
920
+ @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
921
+ if @blob
922
+ params['content_length'] = @blob.content_length
923
+ params['content_type'] = @blob.content_type
924
+ params['content_disposition'] = "attachment; filename=#{@blob.id}"
925
+ BlobStream.call(env, credentials, params)
926
+ else
927
+ report_error(404)
928
+ end
884
929
  end
885
- else
886
- report_error(404)
887
- end
888
- end
930
+ end
889
931
 
890
- #get the content of a particular blob
891
- get "#{Sinatra::UrlForHelper::DEFAULT_URI_PREFIX}/buckets/:bucket/:blob/content" do
892
- @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
893
- if @blob
894
- params['content_length'] = @blob.content_length
895
- params['content_type'] = @blob.content_type
896
- params['content_disposition'] = "attachment; filename=#{@blob.id}"
897
- BlobStream.call(env, credentials, params)
898
- else
899
- report_error(404)
900
932
  end
901
- end
902
-
903
- collection :buckets do
904
- description "Cloud Storage buckets - aka buckets|directories|folders"
905
933
 
906
934
  operation :new do
907
935
  description "A form to create a new bucket resource"