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.
- data/bin/deltacloudd +6 -7
- data/config.ru +4 -2
- data/deltacloud-core.gemspec +22 -7
- data/lib/deltacloud.rb +27 -0
- data/lib/deltacloud/core_ext.rb +1 -0
- data/lib/deltacloud/core_ext/hash.rb +29 -0
- data/lib/{drivers.rb → deltacloud/drivers.rb} +2 -1
- data/lib/deltacloud/drivers/condor/condor_driver.rb +2 -2
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +13 -11
- data/lib/deltacloud/drivers/mock/mock_driver.rb +2 -1
- data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +64 -2
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +7 -2
- data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +14 -6
- data/lib/deltacloud/drivers/vsphere/vsphere_filemanager.rb +2 -2
- data/lib/deltacloud/helpers.rb +1 -0
- data/lib/deltacloud/helpers/application_helper.rb +3 -2
- data/lib/deltacloud/helpers/blob_stream.rb +0 -17
- data/{deltacloud.rb → lib/deltacloud/models.rb} +0 -13
- data/lib/sinatra/rabbit.rb +83 -7
- data/lib/sinatra/sinatra_verbose.rb +73 -0
- data/lib/sinatra/url_for.rb +10 -4
- data/server.rb +154 -126
- data/support/fedora/deltacloud-core-config +20 -18
- data/support/fedora/{deltacloud-core → deltacloud-core.init} +11 -14
- data/support/fedora/deltacloud-core.spec +57 -76
- data/tests/rabbit_test.rb +1 -1
- data/views/instances/new.html.haml +5 -4
- data/views/storage_volumes/show.html.haml +6 -3
- metadata +255 -215
- data/public/javascripts/jquery-1.4.2.min.js +0 -154
@@ -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=
|
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
|
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"))
|
data/lib/deltacloud/helpers.rb
CHANGED
@@ -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
|
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'
|
data/lib/sinatra/rabbit.rb
CHANGED
@@ -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
|
-
@
|
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 @
|
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
|
-
|
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
|
data/lib/sinatra/url_for.rb
CHANGED
@@ -59,15 +59,21 @@ module Sinatra
|
|
59
59
|
when :path_only
|
60
60
|
base = request.script_name
|
61
61
|
when :full
|
62
|
-
scheme = request.
|
63
|
-
port = request.
|
64
|
-
|
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 '
|
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.
|
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 :
|
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
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
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
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
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
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
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
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
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
|
-
|
854
|
-
report_error(404)
|
855
|
-
end
|
856
|
-
end
|
875
|
+
end
|
857
876
|
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
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
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
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
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
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
|
-
|
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"
|