deltacloud-core 0.4.0 → 0.4.1

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