visor-image 0.0.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/visor +423 -0
- data/bin/visor-image +10 -0
- data/config/server.rb +14 -0
- data/lib/image/auth.rb +147 -0
- data/lib/image/cli.rb +397 -0
- data/lib/image/client.rb +490 -0
- data/lib/image/meta.rb +219 -0
- data/lib/image/routes/delete_all_images.rb +40 -0
- data/lib/image/routes/delete_image.rb +62 -0
- data/lib/image/routes/get_image.rb +78 -0
- data/lib/image/routes/get_images.rb +54 -0
- data/lib/image/routes/get_images_detail.rb +54 -0
- data/lib/image/routes/head_image.rb +51 -0
- data/lib/image/routes/post_image.rb +189 -0
- data/lib/image/routes/put_image.rb +205 -0
- data/lib/image/server.rb +307 -0
- data/lib/image/store/cumulus.rb +126 -0
- data/lib/image/store/file_system.rb +119 -0
- data/lib/image/store/hdfs.rb +149 -0
- data/lib/image/store/http.rb +78 -0
- data/lib/image/store/lunacloud.rb +126 -0
- data/lib/image/store/s3.rb +121 -0
- data/lib/image/store/store.rb +39 -0
- data/lib/image/store/walrus.rb +130 -0
- data/lib/image/version.rb +5 -0
- data/lib/visor-image.rb +30 -0
- data/spec/lib/client_spec.rb +0 -0
- data/spec/lib/meta_spec.rb +230 -0
- data/spec/lib/routes/delete_image_spec.rb +98 -0
- data/spec/lib/routes/get_image_spec.rb +78 -0
- data/spec/lib/routes/get_images_detail_spec.rb +104 -0
- data/spec/lib/routes/get_images_spec.rb +104 -0
- data/spec/lib/routes/head_image_spec.rb +51 -0
- data/spec/lib/routes/post_image_spec.rb +112 -0
- data/spec/lib/routes/put_image_spec.rb +109 -0
- data/spec/lib/server_spec.rb +62 -0
- data/spec/lib/store/cumulus_spec.rb +0 -0
- data/spec/lib/store/file_system_spec.rb +32 -0
- data/spec/lib/store/http_spec.rb +56 -0
- data/spec/lib/store/s3_spec.rb +37 -0
- data/spec/lib/store/store_spec.rb +36 -0
- data/spec/lib/store/walrus_spec.rb +0 -0
- metadata +217 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'goliath'
|
2
|
+
|
3
|
+
module Visor
|
4
|
+
module Image
|
5
|
+
|
6
|
+
# Get detailed information about all public images.
|
7
|
+
#
|
8
|
+
class GetImagesDetail < Goliath::API
|
9
|
+
include Visor::Common::Exception
|
10
|
+
include Visor::Common::Util
|
11
|
+
use Goliath::Rack::Render, ['json', 'xml']
|
12
|
+
|
13
|
+
# Pre-process headers as they arrive and load them into a environment variable.
|
14
|
+
#
|
15
|
+
# @param [Object] env The Goliath environment variables.
|
16
|
+
# @param [Object] headers The incoming request HTTP headers.
|
17
|
+
#
|
18
|
+
def on_headers(env, headers)
|
19
|
+
logger.debug "Received headers: #{headers.inspect}"
|
20
|
+
env['headers'] = headers
|
21
|
+
end
|
22
|
+
|
23
|
+
# Query database to retrieve the public images detailed meta and return it in request body.
|
24
|
+
#
|
25
|
+
# @param [Object] env The Goliath environment variables.
|
26
|
+
#
|
27
|
+
# @return [Array] The HTTP response containing the images
|
28
|
+
# metadata or an error code and its messages if anything was raised.
|
29
|
+
#
|
30
|
+
def response(env)
|
31
|
+
access_key = authorize(env, vas)
|
32
|
+
meta = vms.get_images_detail(params, access_key)
|
33
|
+
[200, {}, {images: meta}]
|
34
|
+
rescue Forbidden => e
|
35
|
+
exit_error(403, e.message)
|
36
|
+
rescue NotFound => e
|
37
|
+
exit_error(404, e.message)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Produce an HTTP response with an error code and message.
|
41
|
+
#
|
42
|
+
# @param [Fixnum] code The error code.
|
43
|
+
# @param [String] message The error message.
|
44
|
+
#
|
45
|
+
# @return [Array] The HTTP response containing an error code and its message.
|
46
|
+
#
|
47
|
+
def exit_error(code, message)
|
48
|
+
logger.error message
|
49
|
+
[code, {}, {code: code, message: message}]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'goliath'
|
2
|
+
|
3
|
+
module Visor
|
4
|
+
module Image
|
5
|
+
|
6
|
+
# Head metadata about the image with the given id.
|
7
|
+
#
|
8
|
+
class HeadImage < Goliath::API
|
9
|
+
include Visor::Common::Exception
|
10
|
+
include Visor::Common::Util
|
11
|
+
|
12
|
+
# Pre-process headers as they arrive and load them into a environment variable.
|
13
|
+
#
|
14
|
+
# @param [Object] env The Goliath environment variables.
|
15
|
+
# @param [Object] headers The incoming request HTTP headers.
|
16
|
+
#
|
17
|
+
def on_headers(env, headers)
|
18
|
+
logger.debug "Received headers: #{headers.inspect}"
|
19
|
+
env['headers'] = headers
|
20
|
+
end
|
21
|
+
|
22
|
+
# Query database to retrieve the wanted image meta and return it as HTTP headers.
|
23
|
+
#
|
24
|
+
# @param [Object] env The Goliath environment variables.
|
25
|
+
#
|
26
|
+
def response(env)
|
27
|
+
authorize(env, vas)
|
28
|
+
meta = vms.get_image(params[:id])
|
29
|
+
header = push_meta_into_headers(meta)
|
30
|
+
[200, header, nil]
|
31
|
+
rescue Forbidden => e
|
32
|
+
exit_error(403, e.message)
|
33
|
+
rescue NotFound => e
|
34
|
+
exit_error(404, e.message)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Produce an HTTP response with an error code and message.
|
38
|
+
#
|
39
|
+
# @param [Fixnum] code The error code.
|
40
|
+
# @param [String] message The error message.
|
41
|
+
#
|
42
|
+
# @return [Array] The HTTP response containing an error code and its message.
|
43
|
+
#
|
44
|
+
def exit_error(code, message)
|
45
|
+
logger.error message
|
46
|
+
[code, {'x-error-code' => code.to_s, 'x-error-message' => message}, nil]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'goliath'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module Visor
|
5
|
+
module Image
|
6
|
+
|
7
|
+
# Post image data and metadata and returns the registered metadata.
|
8
|
+
#
|
9
|
+
class PostImage < Goliath::API
|
10
|
+
include Visor::Common::Exception
|
11
|
+
include Visor::Common::Util
|
12
|
+
use Goliath::Rack::Render, ['json', 'xml']
|
13
|
+
|
14
|
+
# Pre-process headers as they arrive and load them into a environment variable.
|
15
|
+
#
|
16
|
+
# @param [Object] env The Goliath environment variables.
|
17
|
+
# @param [Object] headers The incoming request HTTP headers.
|
18
|
+
#
|
19
|
+
def on_headers(env, headers)
|
20
|
+
logger.debug "Received headers: #{headers.inspect}"
|
21
|
+
env['headers'] = headers
|
22
|
+
end
|
23
|
+
|
24
|
+
# Pre-process body as it arrives in streaming chunks and load them into a tempfile.
|
25
|
+
#
|
26
|
+
# @param [Object] env The Goliath environment variables.
|
27
|
+
# @param [Object] data The incoming request HTTP body chunks.
|
28
|
+
#
|
29
|
+
def on_body(env, data)
|
30
|
+
(env['body'] ||= Tempfile.open('visor-image', encoding: 'ascii-8bit')) << data
|
31
|
+
(env['md5'] ||= Digest::MD5.new) << data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Main response method which processes the received headers and body,
|
35
|
+
# managing image metadata and file data.
|
36
|
+
#
|
37
|
+
# @param [Object] env The Goliath environment variables.
|
38
|
+
#
|
39
|
+
# @return [Array] The HTTP response containing the already inserted image
|
40
|
+
# metadata or an error code and its message if anything was raised.
|
41
|
+
#
|
42
|
+
def response(env)
|
43
|
+
begin
|
44
|
+
access_key = authorize(env, vas)
|
45
|
+
rescue Forbidden => e
|
46
|
+
return exit_error(403, e.message)
|
47
|
+
end
|
48
|
+
|
49
|
+
meta = pull_meta_from_headers(env['headers'])
|
50
|
+
meta[:owner] = access_key
|
51
|
+
body = env['body']
|
52
|
+
location = meta[:location]
|
53
|
+
|
54
|
+
if location && body
|
55
|
+
msg = 'When the location header is present no file content can be provided'
|
56
|
+
return exit_error(400, msg)
|
57
|
+
end
|
58
|
+
|
59
|
+
if meta[:store] == 'http' || (location && location.split(':').first == 'http')
|
60
|
+
return exit_error(400, 'Cannot post an image file to a HTTP backend') if body
|
61
|
+
store = Visor::Image::Store::HTTP.new(location)
|
62
|
+
|
63
|
+
exist, meta[:size], meta[:checksum] = store.file_exists?(false)
|
64
|
+
return exit_error(404, "No image file found at #{location}") unless exist
|
65
|
+
end
|
66
|
+
|
67
|
+
# first registers the image meta or raises on error
|
68
|
+
begin
|
69
|
+
image = insert_meta(meta)
|
70
|
+
rescue ArgumentError => e
|
71
|
+
body.close if body
|
72
|
+
body.unlink if body
|
73
|
+
return exit_error(400, e.message)
|
74
|
+
rescue InternalError => e
|
75
|
+
body.close if body
|
76
|
+
body.unlink if body
|
77
|
+
return exit_error(500, e.message)
|
78
|
+
end
|
79
|
+
|
80
|
+
# if has body(image file), upload file and update meta or raise on error
|
81
|
+
begin
|
82
|
+
image = upload_and_update(env['id'], body)
|
83
|
+
rescue UnsupportedStore, ArgumentError => e
|
84
|
+
return exit_error(400, e.message, true)
|
85
|
+
rescue NotFound => e
|
86
|
+
return exit_error(404, e.message, true)
|
87
|
+
rescue Duplicated => e
|
88
|
+
return exit_error(409, e.message, true)
|
89
|
+
ensure
|
90
|
+
body.close
|
91
|
+
body.unlink
|
92
|
+
end unless body.nil?
|
93
|
+
|
94
|
+
[200, {}, {image: image}]
|
95
|
+
end
|
96
|
+
|
97
|
+
# On connection close log a message.
|
98
|
+
#
|
99
|
+
# @param [Object] env The Goliath environment variables.
|
100
|
+
#
|
101
|
+
def on_close(env)
|
102
|
+
logger.info 'Connection closed'
|
103
|
+
end
|
104
|
+
|
105
|
+
# Produce an HTTP response with an error code and message.
|
106
|
+
#
|
107
|
+
# @param [Fixnum] code The error code.
|
108
|
+
# @param [String] message The error message.
|
109
|
+
# @param [True, False] set_status (false) If true, update the image status to 'error'.
|
110
|
+
#
|
111
|
+
# @return [Array] The HTTP response containing an error code and its message.
|
112
|
+
#
|
113
|
+
def exit_error(code, message, set_status=false)
|
114
|
+
logger.error message
|
115
|
+
begin
|
116
|
+
vms.put_image(env['id'], status: 'error') if set_status
|
117
|
+
rescue => e
|
118
|
+
logger.error "Unable to set image #{env['id']} status to 'error': #{e.message}"
|
119
|
+
end
|
120
|
+
[code, {}, {code: code, message: message}]
|
121
|
+
end
|
122
|
+
|
123
|
+
# Insert image metadata on database (which set its status to locked).
|
124
|
+
#
|
125
|
+
# @param [Hash] meta The image metadata.
|
126
|
+
#
|
127
|
+
# @return [Hash] The already inserted image metadata.
|
128
|
+
#
|
129
|
+
def insert_meta(meta)
|
130
|
+
image = vms.post_image(meta)
|
131
|
+
env['id'] = image[:_id]
|
132
|
+
|
133
|
+
if image[:location]
|
134
|
+
logger.debug "Location for image #{env['id']} is #{image[:location]}"
|
135
|
+
logger.debug "Setting image #{env['id']} status to 'available'"
|
136
|
+
vms.put_image(env['id'], status: 'available')
|
137
|
+
else
|
138
|
+
image
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Update image status and launch upload.
|
143
|
+
#
|
144
|
+
# @param [Fixnum] id The image _id.
|
145
|
+
# @param [FIle] body The image body tempfile descriptor.
|
146
|
+
#
|
147
|
+
# @return [Hash] The already updated image metadata.
|
148
|
+
#
|
149
|
+
def upload_and_update(id, body)
|
150
|
+
logger.debug "Setting image #{id} status to 'uploading'"
|
151
|
+
meta = vms.put_image(id, status: 'uploading')
|
152
|
+
checksum = env['md5']
|
153
|
+
location, size = do_upload(id, meta, body)
|
154
|
+
|
155
|
+
logger.debug "Updating image #{id} meta:"
|
156
|
+
logger.debug "Setting status to 'available'"
|
157
|
+
logger.debug "Setting location to '#{location}'"
|
158
|
+
logger.debug "Setting size to '#{size}'"
|
159
|
+
logger.debug "Setting checksum to '#{checksum}'"
|
160
|
+
vms.put_image(id, status: 'available', uploaded_at: Time.now, location: location, size: size, checksum: checksum)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Upload image file to wanted store.
|
164
|
+
#
|
165
|
+
# @param [Fixnum] id The image _id.
|
166
|
+
# @param [Hash] meta The image metadata.
|
167
|
+
# @param [FIle] body The image body tempfile descriptor.
|
168
|
+
#
|
169
|
+
# @return [Array] Image file location URI and size.
|
170
|
+
#
|
171
|
+
# @raise [ArgumentError] If request Content-Type isn't 'application/octet-stream'
|
172
|
+
#
|
173
|
+
def do_upload(id, meta, body)
|
174
|
+
content_type = env['headers']['Content-Type'] || ''
|
175
|
+
store_name = meta[:store] || configs[:default]
|
176
|
+
format = meta[:format] || 'none'
|
177
|
+
|
178
|
+
unless content_type == 'application/octet-stream'
|
179
|
+
raise ArgumentError, 'Request Content-Type must be application/octet-stream'
|
180
|
+
end
|
181
|
+
|
182
|
+
store = Visor::Image::Store.get_backend(store_name, configs)
|
183
|
+
logger.debug "Uploading image #{id} data to #{store_name} store"
|
184
|
+
store.save(id, body, format)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'goliath'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module Visor
|
5
|
+
module Image
|
6
|
+
|
7
|
+
# Put image metadata and/or data for the image with the given id.
|
8
|
+
#
|
9
|
+
class PutImage < Goliath::API
|
10
|
+
include Visor::Common::Exception
|
11
|
+
include Visor::Common::Util
|
12
|
+
use Goliath::Rack::Render, ['json', 'xml']
|
13
|
+
|
14
|
+
# Pre-process headers as they arrive and load them into a environment variable.
|
15
|
+
#
|
16
|
+
# @param [Object] env The Goliath environment variables.
|
17
|
+
# @param [Object] headers The incoming request HTTP headers.
|
18
|
+
#
|
19
|
+
def on_headers(env, headers)
|
20
|
+
logger.debug "Received headers: #{headers.inspect}"
|
21
|
+
env['headers'] = headers
|
22
|
+
end
|
23
|
+
|
24
|
+
# Pre-process body as it arrives in streaming chunks and load them into a tempfile.
|
25
|
+
#
|
26
|
+
# @param [Object] env The Goliath environment variables.
|
27
|
+
# @param [Object] data The incoming request HTTP body chunks.
|
28
|
+
#
|
29
|
+
def on_body(env, data)
|
30
|
+
(env['body'] ||= Tempfile.open('visor-image', encoding: 'ascii-8bit')) << data
|
31
|
+
(env['md5'] ||= Digest::MD5.new) << data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Main response method which processes the received headers and body,
|
35
|
+
# managing image metadata and file data.
|
36
|
+
#
|
37
|
+
# @param [Object] env The Goliath environment variables.
|
38
|
+
#
|
39
|
+
# @return [Array] The HTTP response containing the already inserted image
|
40
|
+
# metadata or an error code and its message if anything was raised.
|
41
|
+
#
|
42
|
+
def response(env)
|
43
|
+
begin
|
44
|
+
authorize(env, vas)
|
45
|
+
rescue Forbidden => e
|
46
|
+
return exit_error(403, e.message)
|
47
|
+
end
|
48
|
+
|
49
|
+
meta = pull_meta_from_headers(env['headers'])
|
50
|
+
body = env['body']
|
51
|
+
id = params[:id]
|
52
|
+
location = meta[:location]
|
53
|
+
|
54
|
+
# a valid update requires the presence of headers and/or body
|
55
|
+
if meta.empty? && body.nil?
|
56
|
+
msg = 'No headers or body found for update'
|
57
|
+
return exit_error(400, msg)
|
58
|
+
end
|
59
|
+
# only the x-image-meta-location header or the body content should be provided
|
60
|
+
if location && body
|
61
|
+
msg = 'When the location header is present no file content can be provided'
|
62
|
+
return exit_error(400, msg)
|
63
|
+
end
|
64
|
+
|
65
|
+
if meta[:store] == 'http' || (location && location.split(':').first == 'http')
|
66
|
+
return exit_error(400, 'Cannot post an image file to a HTTP backend') if body
|
67
|
+
store = Visor::Image::Store::HTTP.new(location)
|
68
|
+
|
69
|
+
exist, meta[:size], meta[:checksum] = store.file_exists?(false)
|
70
|
+
return exit_error(404, "No image file found at #{location}") unless exist
|
71
|
+
end
|
72
|
+
|
73
|
+
# first update the image meta or raises on error
|
74
|
+
begin
|
75
|
+
image = update_meta(id, meta)
|
76
|
+
rescue NotFound => e
|
77
|
+
return exit_error(404, e.message)
|
78
|
+
rescue ArgumentError => e
|
79
|
+
body.close if body
|
80
|
+
body.unlink if body
|
81
|
+
return exit_error(400, e.message)
|
82
|
+
rescue InternalError => e
|
83
|
+
body.close if body
|
84
|
+
body.unlink if body
|
85
|
+
return exit_error(500, e.message)
|
86
|
+
end unless meta.empty?
|
87
|
+
|
88
|
+
# if has body(image file), upload file and update meta or raise on error
|
89
|
+
begin
|
90
|
+
image = upload_and_update(id, body)
|
91
|
+
rescue UnsupportedStore, ArgumentError => e
|
92
|
+
return exit_error(400, e.message, true)
|
93
|
+
rescue NotFound => e
|
94
|
+
return exit_error(404, e.message, true)
|
95
|
+
rescue ConflictError => e
|
96
|
+
return exit_error(409, e.message)
|
97
|
+
rescue Duplicated => e
|
98
|
+
return exit_error(409, e.message, true)
|
99
|
+
ensure
|
100
|
+
body.close
|
101
|
+
body.unlink
|
102
|
+
end unless body.nil?
|
103
|
+
|
104
|
+
[200, {}, {image: image}]
|
105
|
+
end
|
106
|
+
|
107
|
+
# On connection close log a message.
|
108
|
+
#
|
109
|
+
# @param [Object] env The Goliath environment variables.
|
110
|
+
#
|
111
|
+
def on_close(env)
|
112
|
+
logger.info 'Connection closed'
|
113
|
+
end
|
114
|
+
|
115
|
+
# Produce an HTTP response with an error code and message.
|
116
|
+
#
|
117
|
+
# @param [Fixnum] code The error code.
|
118
|
+
# @param [String] message The error message.
|
119
|
+
# @param [True, False] set_status (false) If true, update the image status to 'error'.
|
120
|
+
#
|
121
|
+
# @return [Array] The HTTP response containing an error code and its message.
|
122
|
+
#
|
123
|
+
def exit_error(code, message, set_status=false)
|
124
|
+
logger.error message
|
125
|
+
begin
|
126
|
+
vms.put_image(params[:id], status: 'error') if set_status
|
127
|
+
rescue => e
|
128
|
+
logger.error "Unable to set image #{env['id']} status to 'error': #{e.message}"
|
129
|
+
end
|
130
|
+
[code, {}, {code: code, message: message}]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Update image metadata and set status if needed.
|
134
|
+
#
|
135
|
+
# @param [Hash] meta The image metadata.
|
136
|
+
#
|
137
|
+
# @return [Hash] The already inserted image metadata.
|
138
|
+
#
|
139
|
+
def update_meta(id, meta)
|
140
|
+
logger.debug "Updating image #{id} meta:"
|
141
|
+
logger.debug "#{id} #{meta}"
|
142
|
+
image = vms.put_image(id, meta)
|
143
|
+
image.each { |k, v| logger.debug "#{k.to_s.capitalize} setted to '#{v}'" if v }
|
144
|
+
|
145
|
+
if image[:location]
|
146
|
+
logger.debug "Location for image #{env['id']} is #{image[:location]}"
|
147
|
+
logger.debug "Setting image #{env['id']} status to 'available'"
|
148
|
+
vms.put_image(id, status: 'available')
|
149
|
+
else
|
150
|
+
image
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Update image status and launch upload.
|
155
|
+
#
|
156
|
+
# @param [Fixnum] id The image _id.
|
157
|
+
# @param [FIle] body The image body tempfile descriptor.
|
158
|
+
#
|
159
|
+
# @return [Hash] The already updated image metadata.
|
160
|
+
#
|
161
|
+
def upload_and_update(id, body)
|
162
|
+
meta = vms.get_image(id)
|
163
|
+
checksum = env['md5']
|
164
|
+
valid = (meta[:status] == 'locked' || meta[:status] == 'error')
|
165
|
+
raise ConflictError, 'Can only assign image file to a locked or error image' unless valid
|
166
|
+
|
167
|
+
logger.debug "Setting image #{id} status to 'uploading'"
|
168
|
+
meta = vms.put_image(id, status: 'uploading')
|
169
|
+
location, size = do_upload(id, meta, body)
|
170
|
+
|
171
|
+
logger.debug "Updating image #{id} meta:"
|
172
|
+
logger.debug "Setting status to 'available'"
|
173
|
+
logger.debug "Setting location to '#{location}'"
|
174
|
+
logger.debug "Setting size to '#{size}'"
|
175
|
+
logger.debug "Setting checksum to '#{checksum}'"
|
176
|
+
vms.put_image(id, status: 'available', location: location, size: size, checksum: checksum)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Upload image file to wanted store.
|
180
|
+
#
|
181
|
+
# @param [Fixnum] id The image _id.
|
182
|
+
# @param [Hash] meta The image metadata.
|
183
|
+
# @param [FIle] body The image body tempfile descriptor.
|
184
|
+
#
|
185
|
+
# @return [Array] Image file location URI and size.
|
186
|
+
#
|
187
|
+
# @raise [ArgumentError] If request Content-Type isn't 'application/octet-stream'
|
188
|
+
#
|
189
|
+
def do_upload(id, meta, body)
|
190
|
+
content_type = env['headers']['Content-Type'] || ''
|
191
|
+
store_name = meta[:store] || configs[:default]
|
192
|
+
format = meta[:format] || 'none'
|
193
|
+
|
194
|
+
unless content_type == 'application/octet-stream'
|
195
|
+
raise ArgumentError, 'Request Content-Type must be application/octet-stream'
|
196
|
+
end
|
197
|
+
|
198
|
+
store = Visor::Image::Store.get_backend(store_name, configs)
|
199
|
+
logger.debug "Uploading image #{id} data to #{store_name} store"
|
200
|
+
store.save(id, body, format)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|