visor-meta 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-meta +8 -0
- data/lib/meta/backends/base.rb +302 -0
- data/lib/meta/backends/mongo_db.rb +195 -0
- data/lib/meta/backends/mysql_db.rb +235 -0
- data/lib/meta/cli.rb +333 -0
- data/lib/meta/client.rb +313 -0
- data/lib/meta/server.rb +295 -0
- data/lib/meta/version.rb +5 -0
- data/lib/visor-meta.rb +12 -0
- data/spec/lib/backends/base_spec.rb +209 -0
- data/spec/lib/backends/mongo_db_spec.rb +152 -0
- data/spec/lib/backends/mysql_db_spec.rb +164 -0
- data/spec/lib/client_spec.rb +179 -0
- data/spec/lib/server_spec.rb +214 -0
- metadata +209 -0
data/lib/meta/client.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Visor
|
7
|
+
module Meta
|
8
|
+
|
9
|
+
# The Client API for the VISoR Meta. This class supports all image metadata manipulation
|
10
|
+
# operations through a programmatically interface.
|
11
|
+
#
|
12
|
+
# After Instantiate a Client object its possible to directly interact with the meta server and its
|
13
|
+
# database backend.
|
14
|
+
#
|
15
|
+
class Client
|
16
|
+
|
17
|
+
include Visor::Common::Exception
|
18
|
+
|
19
|
+
configs = Common::Config.load_config :visor_meta
|
20
|
+
|
21
|
+
DEFAULT_HOST = configs[:bind_host] || '0.0.0.0'
|
22
|
+
DEFAULT_PORT = configs[:bind_port] || 4567
|
23
|
+
|
24
|
+
attr_reader :host, :port, :ssl
|
25
|
+
|
26
|
+
# Initializes a new new VISoR Meta Client.
|
27
|
+
#
|
28
|
+
# @option opts [String] :host (DEFAULT_HOST) The host address where VISoR meta server resides.
|
29
|
+
# @option opts [String] :port (DEFAULT_PORT) The host port where VISoR meta server resides.
|
30
|
+
# @option opts [String] :ssl (false) If the connection should be made through HTTPS (SSL).
|
31
|
+
#
|
32
|
+
# @example Instantiate a client with default values:
|
33
|
+
# client = Visor::Meta::Client.new
|
34
|
+
#
|
35
|
+
# @example Instantiate a client with default values and SSL enabled:
|
36
|
+
# client = Visor::Meta::Client.new(ssl: true)
|
37
|
+
#
|
38
|
+
# @example Instantiate a client with custom host and port:
|
39
|
+
# client = Visor::Meta::Client.new(host: '127.0.0.1', port: 3000)
|
40
|
+
#
|
41
|
+
def initialize(opts = {})
|
42
|
+
@host = opts[:host] || DEFAULT_HOST
|
43
|
+
@port = opts[:port] || DEFAULT_PORT
|
44
|
+
@ssl = opts[:ssl] || false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Retrieves brief metadata of all public images.
|
48
|
+
# Options for filtering the returned results can be passed in.
|
49
|
+
#
|
50
|
+
# @option query [String] :attribute The image attribute value to filter returned results.
|
51
|
+
# @option query [String] :sort ("_id") The image attribute to sort returned results.
|
52
|
+
# @option query [String] :dir ("asc") The direction to sort results ("asc"/"desc").
|
53
|
+
#
|
54
|
+
# @example Retrieve all public images brief metadata:
|
55
|
+
# client.get_images
|
56
|
+
#
|
57
|
+
# # returns:
|
58
|
+
# [<all images brief metadata>]
|
59
|
+
#
|
60
|
+
# @example Retrieve all public 32bit images brief metadata:
|
61
|
+
# client.get_images(architecture: 'i386')
|
62
|
+
#
|
63
|
+
# # returns something like:
|
64
|
+
# [
|
65
|
+
# {:_id => "28f94e15...", :architecture => "i386", :name => "Fedora 16"},
|
66
|
+
# {:_id => "8cb55bb6...", :architecture => "i386", :name => "Ubuntu 11.10 Desktop"}
|
67
|
+
# ]
|
68
|
+
#
|
69
|
+
# @example Retrieve all public 64bit images brief metadata, descending sorted by their name:
|
70
|
+
# client.get_images(architecture: 'x86_64', sort: 'name', dir: 'desc')
|
71
|
+
#
|
72
|
+
# # returns something like:
|
73
|
+
# [
|
74
|
+
# {:_id => "5e47a41e...", :architecture => "x86_64", :name => "Ubuntu 10.04 Server"},
|
75
|
+
# {:_id => "069320f0...", :architecture => "x86_64", :name => "CentOS 6"}
|
76
|
+
# ]
|
77
|
+
#
|
78
|
+
# @return [Array] All public images brief metadata.
|
79
|
+
# Just {Visor::Meta::Backends::Base::BRIEF BRIEF} fields are returned.
|
80
|
+
#
|
81
|
+
# @raise [NotFound] If there are no public images registered on the server.
|
82
|
+
#
|
83
|
+
def get_images(query = {})
|
84
|
+
str = build_query(query)
|
85
|
+
request = Net::HTTP::Get.new("/images#{str}")
|
86
|
+
do_request(request)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Retrieves detailed metadata of all public images.
|
90
|
+
#
|
91
|
+
# Filtering and querying works the same as with {#get_images}. The only difference is the number
|
92
|
+
# of disclosed attributes.
|
93
|
+
#
|
94
|
+
# @option query [String] :attribute The image attribute value to filter returned results.
|
95
|
+
# @option query [String] :sort ("_id") The image attribute to sort returned results.
|
96
|
+
# @option query [String] :dir ("asc") The direction to sort results ("asc"/"desc").
|
97
|
+
#
|
98
|
+
# @example Retrieve all public images detailed metadata:
|
99
|
+
# # request for it
|
100
|
+
# client.get_images_detail
|
101
|
+
# # returns an array of hashes with all public images metadata.
|
102
|
+
#
|
103
|
+
# @return [Array] All public images detailed metadata.
|
104
|
+
# The {Visor::Meta::Backends::Base::DETAIL_EXC DETAIL_EXC} fields are excluded from results.
|
105
|
+
#
|
106
|
+
# @raise [NotFound] If there are no public images registered on the server.
|
107
|
+
#
|
108
|
+
def get_images_detail(query = {})
|
109
|
+
str = build_query(query)
|
110
|
+
request = Net::HTTP::Get.new("/images/detail#{str}")
|
111
|
+
do_request(request)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Retrieves detailed image metadata of the image with the given id.
|
115
|
+
#
|
116
|
+
# @param id [String] The wanted image's _id.
|
117
|
+
#
|
118
|
+
# @example Retrieve the image metadata with _id value:
|
119
|
+
# # wanted image _id
|
120
|
+
# id = "5e47a41e-7b94-4f65-824e-28f94e15bc6a"
|
121
|
+
# # ask for that image metadata
|
122
|
+
# client.get_image(id)
|
123
|
+
#
|
124
|
+
# # return example:
|
125
|
+
# {
|
126
|
+
# :_id => "2cceffc6-ebc5-4741-9653-745524e7ac30",
|
127
|
+
# :name => "Ubuntu 10.10",
|
128
|
+
# :architecture => "x86_64",
|
129
|
+
# :access => "public",
|
130
|
+
# :uri => "http://0.0.0.0:4567/images/2cceffc6-ebc5-4741-9653-745524e7ac30",
|
131
|
+
# :format => "iso",
|
132
|
+
# :status => "available",
|
133
|
+
# :store => "file"
|
134
|
+
# }
|
135
|
+
#
|
136
|
+
# @return [Hash] The requested image metadata.
|
137
|
+
#
|
138
|
+
# @raise [NotFound] If image not found.
|
139
|
+
#
|
140
|
+
def get_image(id)
|
141
|
+
request = Net::HTTP::Get.new("/images/#{id}")
|
142
|
+
do_request(request)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Register a new image on the server with the given metadata and returns its metadata.
|
146
|
+
#
|
147
|
+
# @param meta [Hash] The image metadata.
|
148
|
+
#
|
149
|
+
# @example Insert a sample image metadata:
|
150
|
+
# # sample image metadata
|
151
|
+
# meta = {name: 'example', architecture: 'i386', access: 'public'}
|
152
|
+
# # insert the new image metadata
|
153
|
+
# client.post_image(meta)
|
154
|
+
#
|
155
|
+
# # returns:
|
156
|
+
# { :_id=>"2373c3e5-b302-4529-8e23-c4ffc85e7613",
|
157
|
+
# :name=>"example",
|
158
|
+
# :architecture=>"i386",
|
159
|
+
# :access=>"public",
|
160
|
+
# :uri=>"http://0.0.0.0:4567/images/2373c3e5-b302-4529-8e23-c4ffc85e7613",
|
161
|
+
# :status=>"locked",
|
162
|
+
# :created_at=>"2011-12-13 19:19:26 UTC" }
|
163
|
+
#
|
164
|
+
# @return [Hash] The already inserted image metadata.
|
165
|
+
#
|
166
|
+
# @raise [Invalid] If image meta validation fails.
|
167
|
+
#
|
168
|
+
def post_image(meta)
|
169
|
+
request = Net::HTTP::Post.new('/images')
|
170
|
+
request.body = prepare_body(meta)
|
171
|
+
do_request(request)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Updates an image record with the given metadata and returns its metadata.
|
175
|
+
#
|
176
|
+
# @param id [String] The image's _id which will be updated.
|
177
|
+
# @param meta [Hash] The image metadata.
|
178
|
+
#
|
179
|
+
# @example Update a sample image metadata:
|
180
|
+
# # wanted image _id
|
181
|
+
# id = "2373c3e5-b302-4529-8e23-c4ffc85e7613"
|
182
|
+
# # update the image metadata with some new values
|
183
|
+
# client.put_image(id, name: 'update example')
|
184
|
+
#
|
185
|
+
# # returns:
|
186
|
+
# { :_id=>"2373c3e5-b302-4529-8e23-c4ffc85e7613",
|
187
|
+
# :name=>"update example",
|
188
|
+
# :architecture=>"i386",
|
189
|
+
# :access=>"public",
|
190
|
+
# :uri=>"http://0.0.0.0:4567/images/2373c3e5-b302-4529-8e23-c4ffc85e7613",
|
191
|
+
# :status=>"locked",
|
192
|
+
# :created_at=>"2011-12-13 19:19:26 UTC",
|
193
|
+
# :updated_at=>"2011-12-13 19:24:37 +0000" }
|
194
|
+
#
|
195
|
+
# @return [Hash] The already updated image metadata.
|
196
|
+
#
|
197
|
+
# @raise [Invalid] If image meta validation fails.
|
198
|
+
# @raise [NotFound] If required image was not found.
|
199
|
+
#
|
200
|
+
def put_image(id, meta)
|
201
|
+
request = Net::HTTP::Put.new("/images/#{id}")
|
202
|
+
request.body = prepare_body(meta)
|
203
|
+
do_request(request)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Removes an image record based on its _id and returns its metadata.
|
207
|
+
#
|
208
|
+
# @param id [String] The image's _id which will be deleted.
|
209
|
+
#
|
210
|
+
# @example Delete an image metadata:
|
211
|
+
# # wanted image _id
|
212
|
+
# id = "2373c3e5-b302-4529-8e23-c4ffc85e7613"
|
213
|
+
# # delete the image metadata, which returns it as it was before deletion
|
214
|
+
# client.delete_image(id)
|
215
|
+
#
|
216
|
+
# @return [Hash] The already deleted image metadata. This is useful for recover on accidental delete.
|
217
|
+
#
|
218
|
+
# @raise [NotFound] If required image was not found.
|
219
|
+
#
|
220
|
+
def delete_image(id)
|
221
|
+
request = Net::HTTP::Delete.new("/images/#{id}")
|
222
|
+
do_request(request)
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
# Parses a response body with the JSON parser and extracts and returns a single
|
228
|
+
# key value from it if defined, otherwise returns all the body.
|
229
|
+
#
|
230
|
+
# @param key (nil) [Symbol] The hash key to extract the wanted value.
|
231
|
+
# @param response [Net::HTTPResponse] The response which contains the body to parse.
|
232
|
+
#
|
233
|
+
# @return [String, Hash] If key is provided and exists on the response body, them return
|
234
|
+
# its value, otherwise return all the body hash.
|
235
|
+
#
|
236
|
+
def parse(key=nil, response)
|
237
|
+
parsed = JSON.parse(response.body, symbolize_names: true)
|
238
|
+
key ? parsed[key] : parsed
|
239
|
+
end
|
240
|
+
|
241
|
+
# Generate a valid URI query string from key/value pairs of the given hash.
|
242
|
+
#
|
243
|
+
# @param opts [Hash] The hash with the key/value pairs to generate query from.
|
244
|
+
#
|
245
|
+
# @return [String] The generated query in the form of "?k=v&k1=v1".
|
246
|
+
#
|
247
|
+
def build_query(opts)
|
248
|
+
opts.empty? ? '' : '?' + URI.encode_www_form(opts)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Fill common header keys before each request. This sets the 'User-Agent' and 'Accept'
|
252
|
+
# headers for every request and additionally sets the 'content-type' header
|
253
|
+
# for POST and PUT requests.
|
254
|
+
#
|
255
|
+
# @param request [Net::HTTPResponse] The request which will be modified in its headers.
|
256
|
+
#
|
257
|
+
def prepare_headers(request)
|
258
|
+
request['User-Agent'] = 'VISoR meta server'
|
259
|
+
request['Accept'] = 'application/json'
|
260
|
+
request['content-type'] = 'application/json' if ['POST', 'PUT'].include?(request.method)
|
261
|
+
end
|
262
|
+
|
263
|
+
# Generate a valid JSON request body for POST and PUT requests.
|
264
|
+
# It generates a JSON object encapsulated inside a :image key and then returns it.
|
265
|
+
#
|
266
|
+
# @param hash [Hash] The hash with the key/value pairs to generate a JSON object from.
|
267
|
+
#
|
268
|
+
# @return [Hash] If an :image key is already present in the hash, it just returns the plain
|
269
|
+
# JSON object, otherwise, encapsulate the hash inside a :image key and returns it.
|
270
|
+
#
|
271
|
+
def prepare_body(hash)
|
272
|
+
hash.has_key?(:image) ? meta.to_json : {image: hash}.to_json
|
273
|
+
end
|
274
|
+
|
275
|
+
# Process requests by preparing its headers, launch them and assert or raise their response.
|
276
|
+
#
|
277
|
+
# @param request [Net::HTTPResponse] The request which will be launched.
|
278
|
+
#
|
279
|
+
# @return [String, Hash] If an error is raised, then it parses and returns its message,
|
280
|
+
# otherwise it properly parse and return the response body.
|
281
|
+
#
|
282
|
+
# @raise [NotFound] If required image was not found (on a GET, PUT or DELETE request).
|
283
|
+
# @raise [Invalid] If image meta validation fails (on a POST or PUT request).
|
284
|
+
#
|
285
|
+
def do_request(request)
|
286
|
+
prepare_headers(request)
|
287
|
+
response = http_or_https.request(request)
|
288
|
+
case response
|
289
|
+
when Net::HTTPNotFound then
|
290
|
+
raise NotFound, parse(:message, response)
|
291
|
+
when Net::HTTPBadRequest then
|
292
|
+
raise Invalid, parse(:message, response)
|
293
|
+
else
|
294
|
+
parse(:image, response) or parse(:images, response)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Generate a new HTTP or HTTPS connection based on initialization parameters.
|
299
|
+
#
|
300
|
+
# @return [Net::HTTP] A HTTP or HTTPS (not done yet) connection ready to use.
|
301
|
+
#
|
302
|
+
def http_or_https
|
303
|
+
if @ssl
|
304
|
+
#TODO: ssl connection
|
305
|
+
#https://github.com/augustl/net-http-cheat-sheet/blob/master/ssl_and_https.rb
|
306
|
+
else
|
307
|
+
Net::HTTP.new(@host, @port)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
data/lib/meta/server.rb
ADDED
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Visor
|
6
|
+
module Meta
|
7
|
+
|
8
|
+
# The VISoR Meta Server class. This class supports all image metadata manipulation
|
9
|
+
# operations through the VISoR REST API implemented along the following routes.
|
10
|
+
#
|
11
|
+
# After initialize the Server its possible to directly interact with the meta backend.
|
12
|
+
#
|
13
|
+
class Server < Sinatra::Base
|
14
|
+
include Visor::Common::Exception
|
15
|
+
include Visor::Common::Config
|
16
|
+
|
17
|
+
# Configuration
|
18
|
+
#
|
19
|
+
configure do
|
20
|
+
backend_map = {'mongodb' => Visor::Meta::Backends::MongoDB,
|
21
|
+
'mysql' => Visor::Meta::Backends::MySQL}
|
22
|
+
|
23
|
+
conf = Visor::Common::Config.load_config(:visor_meta)
|
24
|
+
log = Visor::Common::Config.build_logger(:visor_meta)
|
25
|
+
|
26
|
+
DB = backend_map[conf[:backend].split(':').first].connect uri: conf[:backend]
|
27
|
+
|
28
|
+
#enable :threaded
|
29
|
+
disable :show_exceptions, :logging #, :protection
|
30
|
+
|
31
|
+
use Rack::CommonLogger, log
|
32
|
+
end
|
33
|
+
|
34
|
+
#configure :development do
|
35
|
+
#require 'sinatra/reloader'
|
36
|
+
#register Sinatra::Reloader
|
37
|
+
#end
|
38
|
+
|
39
|
+
# Helpers
|
40
|
+
#
|
41
|
+
helpers do
|
42
|
+
def json_error(code, message)
|
43
|
+
error code, {code: code, message: message}.to_json
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Filters
|
48
|
+
#
|
49
|
+
before do
|
50
|
+
@parse_opts = {symbolize_names: true}
|
51
|
+
content_type :json
|
52
|
+
end
|
53
|
+
|
54
|
+
# Routes
|
55
|
+
#
|
56
|
+
|
57
|
+
# @method get_all_brief
|
58
|
+
# @overload get '/images'
|
59
|
+
#
|
60
|
+
# Get brief information about all public images.
|
61
|
+
#
|
62
|
+
# { "images": [{
|
63
|
+
# "_id":<_id>,
|
64
|
+
# "uri":<uri>,
|
65
|
+
# "name":<name>,
|
66
|
+
# "architecture":<architecture>,
|
67
|
+
# "type":<type>,
|
68
|
+
# "format":<format>,
|
69
|
+
# "store":<type>,
|
70
|
+
# "size":<size>,
|
71
|
+
# "created_at":<creation timestamp>
|
72
|
+
# }, ...]}
|
73
|
+
#
|
74
|
+
# The following options can be passed as query parameters, plus any other additional
|
75
|
+
# image attribute not defined in the schema.
|
76
|
+
#
|
77
|
+
# @param [String] name The image name.
|
78
|
+
# @param [String] architecture The image architecture.
|
79
|
+
# @param [String] type The image type.
|
80
|
+
# @param [String] format The image format.
|
81
|
+
# @param [String] store The image store.
|
82
|
+
# @param [Fixnum] size The image size.
|
83
|
+
# @param [Date] created_at The image creation timestamp.
|
84
|
+
# @param [String] sort ('_id') The image attribute to sort results.
|
85
|
+
# @param [String] dir ('asc') The sorting order ('asc'/'desc').
|
86
|
+
#
|
87
|
+
# @return [JSON] The public images brief metadata.
|
88
|
+
#
|
89
|
+
# @raise [HTTP Error 404] If there is no public images.
|
90
|
+
#
|
91
|
+
get '/images' do
|
92
|
+
begin
|
93
|
+
images = DB.get_public_images(true, params)
|
94
|
+
{images: images}.to_json
|
95
|
+
rescue NotFound => e
|
96
|
+
json_error 404, e.message
|
97
|
+
rescue => e
|
98
|
+
json_error 500, e.message
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @method get_all_detail
|
103
|
+
# @overload get '/images/detail'
|
104
|
+
#
|
105
|
+
# Get detailed information about all public images.
|
106
|
+
#
|
107
|
+
# {"images": [{
|
108
|
+
# "_id":<_id>,
|
109
|
+
# "uri":<uri>,
|
110
|
+
# "name":<name>,
|
111
|
+
# "architecture":<architecture>,
|
112
|
+
# "access":<access>,
|
113
|
+
# "status":<status>,
|
114
|
+
# "size":<size>,
|
115
|
+
# "type":<type>,
|
116
|
+
# "format":<format>,
|
117
|
+
# "store":<store>,
|
118
|
+
# "created_at":<timestamp>
|
119
|
+
# "updated_at":<timestamp>,
|
120
|
+
# "kernel":<associated kernel>,
|
121
|
+
# "ramdisk":<associated ramdisk>,
|
122
|
+
# ...
|
123
|
+
# }, ...]}
|
124
|
+
#
|
125
|
+
# The following options can be passed as query parameters, plus any other additional
|
126
|
+
# image attribute not defined in the schema.
|
127
|
+
#
|
128
|
+
# @param [String] name The image name.
|
129
|
+
# @param [String] architecture The image architecture.
|
130
|
+
# @param [String] access The image access permission.
|
131
|
+
# @param [String] type The image type.
|
132
|
+
# @param [String] format The image format.
|
133
|
+
# @param [String] store The image store.
|
134
|
+
# @param [Fixnum] size The image size.
|
135
|
+
# @param [Date] created_at The image creation timestamp.
|
136
|
+
# @param [Date] updated_at The image update timestamp.
|
137
|
+
# @param [String] kernel The image associated kernel image's _id.
|
138
|
+
# @param [String] ramdisk The image associated kernel image's _id.
|
139
|
+
# @param [String] sort (_id) The image attribute to sort results.
|
140
|
+
# @param [String] dir ('asc') The sorting order ('asc'/'desc').
|
141
|
+
#
|
142
|
+
# @return [JSON] The public images detailed metadata.
|
143
|
+
#
|
144
|
+
# @raise [HTTP Error 404] If there is no public images.
|
145
|
+
#
|
146
|
+
get '/images/detail' do
|
147
|
+
begin
|
148
|
+
images = DB.get_public_images(false, params)
|
149
|
+
{images: images}.to_json
|
150
|
+
rescue NotFound => e
|
151
|
+
json_error 404, e.message
|
152
|
+
rescue => e
|
153
|
+
json_error 500, e.message
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# @method get_detail
|
158
|
+
# @overload get '/images/:id'
|
159
|
+
#
|
160
|
+
# Get detailed information about a specific image.
|
161
|
+
#
|
162
|
+
# {"image": {
|
163
|
+
# "_id":<_id>,
|
164
|
+
# "uri":<uri>,
|
165
|
+
# "name":<name>,
|
166
|
+
# "architecture":<architecture>,
|
167
|
+
# "access":<access>,
|
168
|
+
# "status":<status>,
|
169
|
+
# "size":<size>,
|
170
|
+
# "type":<type>,
|
171
|
+
# "format":<format>,
|
172
|
+
# "store":<type>,
|
173
|
+
# "created_at":<creation timestamp>
|
174
|
+
# "updated_at":<update timestamp>,
|
175
|
+
# "kernel":<associated kernel>,
|
176
|
+
# "ramdisk":<associated ramdisk>,
|
177
|
+
# ...
|
178
|
+
# }}
|
179
|
+
#
|
180
|
+
# @param [String] id The wanted image _id.
|
181
|
+
#
|
182
|
+
# @return [JSON] The image detailed metadata.
|
183
|
+
#
|
184
|
+
# @raise [HTTP Error 404] If image not found.
|
185
|
+
#
|
186
|
+
get '/images/:id' do |id|
|
187
|
+
begin
|
188
|
+
image = DB.get_image(id)
|
189
|
+
{image: image}.to_json
|
190
|
+
rescue NotFound => e
|
191
|
+
json_error 404, e.message
|
192
|
+
rescue => e
|
193
|
+
json_error 500, e.message
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# @method post
|
198
|
+
# @overload post '/images'
|
199
|
+
#
|
200
|
+
# Create a new image metadata and returns it.
|
201
|
+
#
|
202
|
+
# @param [JSON] http-body The image metadata.
|
203
|
+
#
|
204
|
+
# @return [JSON] The already created image detailed metadata.
|
205
|
+
#
|
206
|
+
# @raise [HTTP Error 400] Image metadata validation errors.
|
207
|
+
#
|
208
|
+
post '/images' do
|
209
|
+
begin
|
210
|
+
meta = JSON.parse(request.body.read, @parse_opts)
|
211
|
+
image = DB.post_image(meta[:image])
|
212
|
+
{image: image}.to_json
|
213
|
+
rescue NotFound => e
|
214
|
+
json_error 404, e.message
|
215
|
+
rescue ArgumentError => e
|
216
|
+
json_error 400, e.message
|
217
|
+
rescue => e
|
218
|
+
json_error 500, e.message
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# @method put
|
223
|
+
# @overload put '/images/:id'
|
224
|
+
#
|
225
|
+
# Update an existing image metadata and return it.
|
226
|
+
#
|
227
|
+
# @param [String] id The wanted image _id.
|
228
|
+
# @param [JSON] http-body The image metadata.
|
229
|
+
#
|
230
|
+
# @return [JSON] The already updated image detailed metadata.
|
231
|
+
#
|
232
|
+
# @raise [HTTP Error 400] Image metadata update validation errors.
|
233
|
+
#
|
234
|
+
put '/images/:id' do |id|
|
235
|
+
begin
|
236
|
+
meta = JSON.parse(request.body.read, @parse_opts)
|
237
|
+
image = DB.put_image(id, meta[:image])
|
238
|
+
{image: image}.to_json
|
239
|
+
rescue NotFound => e
|
240
|
+
json_error 404, e.message
|
241
|
+
rescue ArgumentError => e
|
242
|
+
json_error 400, e.message
|
243
|
+
rescue => e
|
244
|
+
json_error 500, e.message
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# @method delete
|
249
|
+
# @overload delete '/images/:id'
|
250
|
+
#
|
251
|
+
# Delete an image metadata and returns it.
|
252
|
+
#
|
253
|
+
# @param [String] id The image _id to delete.
|
254
|
+
#
|
255
|
+
# @return [JSON] The already deleted image detailed metadata.
|
256
|
+
#
|
257
|
+
# @raise [HTTP Error 404] If image not found.
|
258
|
+
#
|
259
|
+
delete '/images/:id' do
|
260
|
+
begin
|
261
|
+
image = DB.delete_image(params[:id])
|
262
|
+
{image: image}.to_json
|
263
|
+
rescue NotFound => e
|
264
|
+
json_error 404, e.message
|
265
|
+
rescue => e
|
266
|
+
json_error 500, e.message
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# misc handlers: error, not_found, etc.
|
271
|
+
get "*" do
|
272
|
+
json_error 404, 'Invalid operation or path.'
|
273
|
+
end
|
274
|
+
|
275
|
+
put "*" do
|
276
|
+
json_error 404, 'Invalid operation or path.'
|
277
|
+
end
|
278
|
+
|
279
|
+
post "*" do
|
280
|
+
json_error 404, 'Invalid operation or path.'
|
281
|
+
end
|
282
|
+
|
283
|
+
delete "*" do
|
284
|
+
json_error 404, 'Invalid operation or path.'
|
285
|
+
end
|
286
|
+
|
287
|
+
error do
|
288
|
+
json_error 500, env['sinatra.error'].message
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
|
data/lib/meta/version.rb
ADDED
data/lib/visor-meta.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'visor-common'
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
4
|
+
require 'meta/version'
|
5
|
+
require 'meta/backends/base'
|
6
|
+
require 'meta/backends/mongo_db'
|
7
|
+
require 'meta/backends/mysql_db'
|
8
|
+
require 'meta/server'
|
9
|
+
require 'meta/client'
|
10
|
+
require 'meta/cli'
|
11
|
+
|
12
|
+
|