occi 2.0.0 → 2.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/.travis.yml +1 -0
- data/README.md +3 -37
- data/lib/occi/version.rb +1 -1
- metadata +1 -22
- data/lib/OpenNebula/Acl.rb +0 -256
- data/lib/OpenNebula/AclPool.rb +0 -53
- data/lib/OpenNebula/Group.rb +0 -147
- data/lib/OpenNebula/GroupPool.rb +0 -54
- data/lib/OpenNebula/Host.rb +0 -143
- data/lib/OpenNebula/HostPool.rb +0 -55
- data/lib/OpenNebula/Image.rb +0 -256
- data/lib/OpenNebula/ImagePool.rb +0 -74
- data/lib/OpenNebula/OpenNebula.rb +0 -137
- data/lib/OpenNebula/Pool.rb +0 -285
- data/lib/OpenNebula/Template.rb +0 -173
- data/lib/OpenNebula/TemplatePool.rb +0 -74
- data/lib/OpenNebula/User.rb +0 -157
- data/lib/OpenNebula/UserPool.rb +0 -53
- data/lib/OpenNebula/VirtualMachine.rb +0 -319
- data/lib/OpenNebula/VirtualMachinePool.rb +0 -120
- data/lib/OpenNebula/VirtualNetwork.rb +0 -229
- data/lib/OpenNebula/VirtualNetworkPool.rb +0 -74
- data/lib/OpenNebula/XMLUtils.rb +0 -337
- data/lib/occi/configuration.rb +0 -118
- data/lib/occi/server.rb +0 -594
data/lib/occi/server.rb
DELETED
@@ -1,594 +0,0 @@
|
|
1
|
-
##############################################################################
|
2
|
-
# Copyright 2011 Service Computing group, TU Dortmund
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
##############################################################################
|
16
|
-
|
17
|
-
##############################################################################
|
18
|
-
# Description: OCCI RESTful Web Service
|
19
|
-
# Author(s): Hayati Bice, Florian Feldhaus, Piotr Kasprzak
|
20
|
-
##############################################################################
|
21
|
-
|
22
|
-
##############################################################################
|
23
|
-
# Require Ruby Gems
|
24
|
-
|
25
|
-
# gems
|
26
|
-
require 'rubygems'
|
27
|
-
|
28
|
-
# sinatra
|
29
|
-
require 'sinatra'
|
30
|
-
require 'sinatra/multi_route'
|
31
|
-
require 'sinatra/cross_origin'
|
32
|
-
require 'sinatra/respond_with'
|
33
|
-
|
34
|
-
# Ruby standard library
|
35
|
-
require 'uri'
|
36
|
-
require 'fileutils'
|
37
|
-
|
38
|
-
# Server configuration
|
39
|
-
require 'occi/configuration'
|
40
|
-
|
41
|
-
# Active support notifications
|
42
|
-
require 'active_support/notifications'
|
43
|
-
|
44
|
-
# Active support for xml rendering
|
45
|
-
require 'active_support/core_ext'
|
46
|
-
|
47
|
-
##############################################################################
|
48
|
-
# Require OCCI classes
|
49
|
-
|
50
|
-
# Exceptions
|
51
|
-
require 'occi/exceptions'
|
52
|
-
|
53
|
-
# Category registry
|
54
|
-
require 'occi/registry'
|
55
|
-
|
56
|
-
# OCCI Core classes
|
57
|
-
require 'occi/core/action'
|
58
|
-
require 'occi/core/category'
|
59
|
-
require 'occi/core/entity'
|
60
|
-
require 'occi/core/kind'
|
61
|
-
require 'occi/core/link'
|
62
|
-
require 'occi/core/mixin'
|
63
|
-
require 'occi/core/resource'
|
64
|
-
|
65
|
-
# OCCI parser
|
66
|
-
require 'occi/parse'
|
67
|
-
|
68
|
-
# Backend support
|
69
|
-
require 'occi/backend/manager'
|
70
|
-
|
71
|
-
##############################################################################
|
72
|
-
# Sinatra methods for handling HTTP requests
|
73
|
-
|
74
|
-
module OCCI
|
75
|
-
class Server < Sinatra::Application
|
76
|
-
|
77
|
-
register Sinatra::MultiRoute
|
78
|
-
register Sinatra::CrossOrigin
|
79
|
-
register Sinatra::RespondWith
|
80
|
-
|
81
|
-
enable cross_origin
|
82
|
-
|
83
|
-
# Read configuration file
|
84
|
-
def self.config
|
85
|
-
@@config ||= OCCI::Configuration.new('etc/occi-server.conf')
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.location
|
89
|
-
OCCI::Server.config[:server].chomp('/')
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.port
|
93
|
-
OCCI::Server.config[:port]
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.uri
|
97
|
-
self.port.nil? ? self.location : self.location + ':' + self.port
|
98
|
-
end
|
99
|
-
|
100
|
-
def initialize(config = {})
|
101
|
-
# create logger
|
102
|
-
config[:log_dest] ||= STDOUT
|
103
|
-
config[:log_level] ||= Logger::INFO
|
104
|
-
config[:log_level] = case OCCI::Server.config[:log_level]
|
105
|
-
when "debug"
|
106
|
-
Logger::DEBUG
|
107
|
-
when "info"
|
108
|
-
Logger::INFO
|
109
|
-
when "warn"
|
110
|
-
Logger::WARN
|
111
|
-
when "error"
|
112
|
-
Logger::ERROR
|
113
|
-
when "fatal"
|
114
|
-
Logger::FATAL
|
115
|
-
else
|
116
|
-
Logger::INFO
|
117
|
-
end
|
118
|
-
|
119
|
-
@logger = Logger.new(config[:log_dest])
|
120
|
-
@logger.level = config[:log_level]
|
121
|
-
|
122
|
-
# subscribe to log messages and send to logger
|
123
|
-
@log_subscriber = ActiveSupport::Notifications.subscribe("log") do |name, start, finish, id, payload|
|
124
|
-
@logger.log(payload[:level], payload[:message])
|
125
|
-
end
|
126
|
-
|
127
|
-
# Configuration of HTTP Authentication
|
128
|
-
if OCCI::Server.config['username'] != nil and OCCI::Server.config['password'] != nil
|
129
|
-
use Rack::Auth::Basic, "Restricted Area" do |username, password|
|
130
|
-
[username, password] == [OCCI::Server.config['username'], OCCI::Server.config['password']]
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
OCCI::Server.initialize_core_model
|
135
|
-
OCCI::Server.initialize_model(OCCI::Server.config['occi_model_path'])
|
136
|
-
|
137
|
-
# set views explicitly
|
138
|
-
set :views, File.dirname(__FILE__) + "/../../views"
|
139
|
-
|
140
|
-
super
|
141
|
-
end
|
142
|
-
|
143
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
144
|
-
|
145
|
-
def self.initialize_core_model
|
146
|
-
OCCI::Log.info("### Initializing OCCI Core Model ###")
|
147
|
-
OCCI::Core::Entity.register
|
148
|
-
OCCI::Core::Resource.register
|
149
|
-
OCCI::Core::Link.register
|
150
|
-
end
|
151
|
-
|
152
|
-
def self.initialize_model(path)
|
153
|
-
OCCI::Log.info("### Initializing OCCI Model from #{path} ###")
|
154
|
-
Dir.glob(path + '/**/*.json').each do |file|
|
155
|
-
collection = Hashie::Mash.new(JSON.parse(File.read(file)))
|
156
|
-
# add location of service provider to scheme if it has a relative location
|
157
|
-
collection.kinds.collect { |kind| kind.scheme = self.location + kind.scheme if kind.scheme.start_with? '/' } if collection.kinds
|
158
|
-
collection.mixins.collect { |mixin| mixin.scheme = self.location + mixin.scheme if mixin.scheme.start_with? '/' } if collection.mixins
|
159
|
-
collection.actions.collect { |action| action.scheme = self.location + action.scheme if action.scheme.start_with? '/' } if collection.actions
|
160
|
-
# register categories
|
161
|
-
collection.kinds.each { |kind| OCCI::Registry.register(OCCI::Core::Kind.new(kind)) } if collection.kinds
|
162
|
-
collection.mixins.each { |mixin| OCCI::Registry.register(OCCI::Core::Mixin.new(mixin)) } if collection.mixins
|
163
|
-
collection.actions.each { |action| OCCI::Registry.register(OCCI::Core::Action.new(action)) } if collection.actions
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
168
|
-
def initialize_backend(auth)
|
169
|
-
|
170
|
-
if auth.provided? && auth.basic? && auth.credentials
|
171
|
-
user, password = auth.credentials
|
172
|
-
else
|
173
|
-
user, password = [OCCI::Server.config['one_user'], OCCI::Server.config['one_password']]
|
174
|
-
logger.debug("No basic auth data provided: using defaults from config (user = '#{user}')")
|
175
|
-
end
|
176
|
-
|
177
|
-
@backend = case OCCI::Server.config["backend"]
|
178
|
-
when "opennebula"
|
179
|
-
require 'occi/backend/opennebula/opennebula'
|
180
|
-
OCCI::Server.initialize_model('etc/backend/opennebula')
|
181
|
-
OCCI::Backend::Manager.register_backend(OCCI::Backend::OpenNebula::OpenNebula, OCCI::Backend::OpenNebula::OpenNebula::OPERATIONS)
|
182
|
-
OCCI::Backend::OpenNebula::OpenNebula.new(user, password)
|
183
|
-
when "ec2"
|
184
|
-
require 'occi/backend/ec2/ec2'
|
185
|
-
Bundler.require(:ec2)
|
186
|
-
OCCI::Server.initialize_model('etc/backend/ec2')
|
187
|
-
OCCI::Backend::Manager.register_backend(OCCI::Backend::EC2::EC2, OCCI::Backend::EC2::EC2::OPERATIONS)
|
188
|
-
OCCI::Backend::EC2::EC2.new(user, password)
|
189
|
-
when "dummy" then
|
190
|
-
require 'occi/backend/dummy'
|
191
|
-
OCCI::Backend::Manager.register_backend(OCCI::Backend::Dummy, OCCI::Backend::Dummy::OPERATIONS)
|
192
|
-
OCCI::Backend::Dummy.new()
|
193
|
-
else
|
194
|
-
raise "Backend '" + OCCI::Server.config["backend"] + "' not found"
|
195
|
-
end
|
196
|
-
|
197
|
-
|
198
|
-
end
|
199
|
-
|
200
|
-
# Parses a Rack/Sinatra Request and extract OCCI relevant information
|
201
|
-
def parse(request)
|
202
|
-
OCCI::Log.debug('### Parsing request data to OCCI data structure ###')
|
203
|
-
body = request.body.read
|
204
|
-
header = request.env
|
205
|
-
collection = OCCI::Core::Collection.new
|
206
|
-
locations = []
|
207
|
-
# always check headers
|
208
|
-
locations = OCCI::Parse.header_locations(header)
|
209
|
-
if locations.empty?
|
210
|
-
if request.path_info.include?('/-/')
|
211
|
-
collection = OCCI::Parse.header_categories(header)
|
212
|
-
else
|
213
|
-
collection = OCCI::Parse.header_entity(header)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
case request.media_type
|
218
|
-
when 'text/uri-list'
|
219
|
-
body.each_line do |line|
|
220
|
-
locations << URI.parse(line)
|
221
|
-
end
|
222
|
-
when 'text/plain', nil
|
223
|
-
locations = OCCI::Parse.text_locations(body)
|
224
|
-
if locations.empty?
|
225
|
-
if request.path_info.include?('/-/')
|
226
|
-
collection = OCCI::Parse.text_categories(body)
|
227
|
-
else
|
228
|
-
collection = OCCI::Parse.text_entity(body)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
when 'application/occi+json', 'application/json'
|
232
|
-
collection = OCCI::Parse.json(body)
|
233
|
-
when 'application/occi+xml', 'application/xml'
|
234
|
-
collection = OCCI::Parse.xml(body)
|
235
|
-
else
|
236
|
-
raise OCCI::ContentTypeNotSupported
|
237
|
-
end
|
238
|
-
return locations, collection
|
239
|
-
end
|
240
|
-
|
241
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
242
|
-
|
243
|
-
# GET request
|
244
|
-
|
245
|
-
# tasks to be executed before the request is handled
|
246
|
-
before do
|
247
|
-
OCCI::Log.debug('--------------------------------------------------------------------')
|
248
|
-
OCCI::Log.debug("### Client IP: #{request.ip}")
|
249
|
-
OCCI::Log.debug("### Client Accept: #{request.accept}")
|
250
|
-
OCCI::Log.debug("### Client User Agent: #{request.user_agent}")
|
251
|
-
OCCI::Log.debug("### Client Request URL: #{request.url}")
|
252
|
-
OCCI::Log.debug("### Client Request method: #{request.request_method}")
|
253
|
-
OCCI::Log.debug("### Client Request Media Type: #{request.media_type}")
|
254
|
-
OCCI::Log.debug('--------------------------------------------------------------------')
|
255
|
-
|
256
|
-
OCCI::Log.debug('### Prepare response ###')
|
257
|
-
response['Accept'] = "application/occi+json,application/json,text/plain,text/uri-list,application/xml,text/xml,application/occi+xml"
|
258
|
-
response['Server'] = "rOCCI/#{VERSION_NUMBER} OCCI/1.1"
|
259
|
-
OCCI::Log.debug('### Initialize response OCCI collection ###')
|
260
|
-
@collection = Hashie::Mash.new(:kinds => [], :mixins => [], :actions => [], :resources => [], :links => [])
|
261
|
-
@locations = Array.new
|
262
|
-
OCCI::Log.debug('### Preparing authentication handling ###')
|
263
|
-
authentication = Rack::Auth::Basic::Request.new(request.env)
|
264
|
-
OCCI::Log.debug('### Initializing backend ###')
|
265
|
-
initialize_backend(authentication)
|
266
|
-
OCCI::Log.debug('### Reset OCCI model ###')
|
267
|
-
OCCI::Registry.reset
|
268
|
-
@request_locations, @request_collection = parse(request)
|
269
|
-
OCCI::Log.debug('### Fill OCCI model with entities from backend ###')
|
270
|
-
@backend.register_existing_resources
|
271
|
-
end
|
272
|
-
|
273
|
-
after do
|
274
|
-
# OCCI::Log.debug((@collection.resources.to_a + @collection.links.to_a).collect {|entity| entity.location}.join("\n"))
|
275
|
-
OCCI::Log.debug('### Rendering response ###')
|
276
|
-
@collection.delete_if { |k, v| v.empty? } # remove empty entries
|
277
|
-
respond_to do |f|
|
278
|
-
f.txt { erb :collection, :locals => {:collection => @collection, :locations => @locations} }
|
279
|
-
f.on('*/*') { erb :collection, :locals => {:collection => @collection, :locations => @locations} }
|
280
|
-
# f.html { haml :collection, :locals => {:collection => @collection} }
|
281
|
-
f.json { @collection.to_json }
|
282
|
-
f.on('application/occi+json') { @collection.to_json }
|
283
|
-
f.xml { @collection.to_xml(:root => "collection") }
|
284
|
-
f.on('application/occi+xml') { @collection.to_xml(:root => "collection") }
|
285
|
-
f.on('text/uri-list') { @locations.join("\n") }
|
286
|
-
end
|
287
|
-
OCCI::Log.debug('### Successfully rendered ###')
|
288
|
-
end
|
289
|
-
|
290
|
-
# discovery interface
|
291
|
-
# returns all kinds, mixins and actions registered for the server
|
292
|
-
get '/-/', '/.well-known/org/ogf/occi/-/' do
|
293
|
-
OCCI::Log.info("### Listing all kinds, mixins and actions ###")
|
294
|
-
@collection = OCCI::Registry.get(@request_collection.categories)
|
295
|
-
status 200
|
296
|
-
end
|
297
|
-
|
298
|
-
# Resource retrieval
|
299
|
-
# returns entities either below a certain path or belonging to a certain kind or mixin
|
300
|
-
get '*' do
|
301
|
-
if request.path_info.end_with?('/')
|
302
|
-
if request.path_info == '/'
|
303
|
-
kinds = OCCI::Registry.get.kinds
|
304
|
-
else
|
305
|
-
kinds = [OCCI::Registry.get_by_location(request.path_info)]
|
306
|
-
end
|
307
|
-
|
308
|
-
kinds.each do |kind|
|
309
|
-
OCCI::Log.info("### Listing all entities of kind #{kind.type_identifier} ###")
|
310
|
-
@collection.resources.concat kind.entities if kind.entity_type == OCCI::Core::Resource.name
|
311
|
-
@collection.links.concat kind.entities if kind.entity_type == OCCI::Core::Link.name
|
312
|
-
@locations.concat kind.entities.collect { |entity| OCCI::Server.uri + entity.location }
|
313
|
-
end
|
314
|
-
else
|
315
|
-
kind = OCCI::Registry.get_by_location(request.path_info.rpartition('/').first + '/')
|
316
|
-
uuid = request.path_info.rpartition('/').last
|
317
|
-
error 404 if kind.nil? or uuid.nil?
|
318
|
-
OCCI::Log.info("### Listing entity with uuid #{uuid} ###")
|
319
|
-
@collection.resources = kind.entities.select { |entity| entity.id == uuid } if kind.entity_type == OCCI::Core::Resource.name
|
320
|
-
@collection.links = kind.entities.select { |entity| entity.id == uuid } if kind.entity_type == OCCI::Core::Link.name
|
321
|
-
end
|
322
|
-
status 200
|
323
|
-
end
|
324
|
-
|
325
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
326
|
-
# POST request
|
327
|
-
post '/-/', '/.well-known/org/ogf/occi/-/' do
|
328
|
-
logger.info("## Creating user defined mixin ###")
|
329
|
-
raise OCCI::MixinAlreadyExistsError, "Mixin already exists!" if OCCI::Registry.get(@request_collection.mixins)
|
330
|
-
@request_collection.mixins.each do |mixin|
|
331
|
-
OCCI::CategoryRegistry.register(mixin)
|
332
|
-
# TODO: inform backend about new mixin
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# Create an instance appropriate to category field and optionally link an instance to another one
|
337
|
-
post '*' do
|
338
|
-
|
339
|
-
category = OCCI::Registry.get_by_location(request.path_info.rpartition('/').first + '/')
|
340
|
-
|
341
|
-
if category.nil?
|
342
|
-
OCCI::Log.debug("### No category found for request location #{request.path_info} ###")
|
343
|
-
status 404
|
344
|
-
end
|
345
|
-
|
346
|
-
# if action
|
347
|
-
if params[:action]
|
348
|
-
if @request_collection.actions.any?
|
349
|
-
action = @request_collection.actions.first
|
350
|
-
params[:method] ||= action.attributes!.method if action
|
351
|
-
else
|
352
|
-
action = OCCI::Registry.get_by_id(category.actions.select { |action| action.split('#').last == params[:action] }.first)
|
353
|
-
end
|
354
|
-
|
355
|
-
category.entities.each do |entity|
|
356
|
-
OCCI::Backend::Manager.delegate_action(@backend, action, params, entity)
|
357
|
-
status 200
|
358
|
-
end
|
359
|
-
elsif category.kind_of?(OCCI::Core::Kind)
|
360
|
-
@request_collection.resources.each do |resource|
|
361
|
-
OCCI::Log.debug("Deploying resource with title #{resource.title} in backend #{@backend.class.name}")
|
362
|
-
OCCI::Backend::Manager.signal_resource(@backend, OCCI::Backend::RESOURCE_DEPLOY, resource)
|
363
|
-
@locations << OCCI::Server.uri + resource.location
|
364
|
-
status 201
|
365
|
-
end
|
366
|
-
elsif category.kind_of?(OCCI::Core::Mixin)
|
367
|
-
@request_collection.locations.each do |location|
|
368
|
-
OCCI::Log.debug("Attaching resource #{resource.title} to mixin #{mixin.type_identifier} in backend #{@backend.class.name}")
|
369
|
-
# TODO: let backend carry out tasks related to the added mixin
|
370
|
-
category.entities << OCCI::Rendering::HTTP::LocationRegistry.get_object(location)
|
371
|
-
status 200
|
372
|
-
end
|
373
|
-
else
|
374
|
-
status 400
|
375
|
-
end
|
376
|
-
|
377
|
-
end
|
378
|
-
|
379
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
380
|
-
# PUT request
|
381
|
-
|
382
|
-
put '*' do
|
383
|
-
|
384
|
-
# Add an resource instance to a mixin
|
385
|
-
unless @occi_request.mixins.empty?
|
386
|
-
mixin = OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info)
|
387
|
-
|
388
|
-
@occi_request.locations.each do |location|
|
389
|
-
entity = OCCI::Rendering::HTTP::LocationRegistry.get_object(URI.parse(location).path)
|
390
|
-
|
391
|
-
raise "No entity found at location: #{entity_location}" if entity == nil
|
392
|
-
raise "Object referenced by uri [#{entity_location}] is not a OCCI::Core::Resource instance!" if !entity.kind_of?(OCCI::Core::Resource)
|
393
|
-
|
394
|
-
logger.debug("Associating entity [#{entity}] at location #{entity_location} with mixin #{mixin}")
|
395
|
-
|
396
|
-
entity.mixins << mixin
|
397
|
-
end
|
398
|
-
break
|
399
|
-
end
|
400
|
-
|
401
|
-
# Update resource instance(s) at the given location
|
402
|
-
unless OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info).nil?
|
403
|
-
entities = []
|
404
|
-
# Determine set of resources to be updated
|
405
|
-
if OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info).kind_of?(OCCI::Core::Resource)
|
406
|
-
entities = [OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info)]
|
407
|
-
elsif not OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info).kind_of?(OCCI::Core::Category)
|
408
|
-
entities = OCCI::Rendering::HTTP::LocationRegistry.get_resources_below_location(request.path_info, OCCI::CategoryRegistry.get_all)
|
409
|
-
elsif OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info).kind_of?(OCCI::Core::Category)
|
410
|
-
object = OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info)
|
411
|
-
@occi_request.locations.each do |loc|
|
412
|
-
entities << OCCI::Rendering::HTTP::LocationRegistry.get_object(URI.parse(loc.chomp('"').reverse.chomp('"').reverse).path)
|
413
|
-
end
|
414
|
-
end
|
415
|
-
logger.info("Full update for [#{entities.size}] entities...")
|
416
|
-
|
417
|
-
# full update of mixins
|
418
|
-
object.entities.each do |entity|
|
419
|
-
entity.mixins.delete(object)
|
420
|
-
object.entities.delete(entity)
|
421
|
-
end if object.kind_of?(OCCI::Core::Mixin)
|
422
|
-
|
423
|
-
entities.each do |entity|
|
424
|
-
logger.debug("Adding entity: #{entity.get_location} to mixin #{object.type_identifier}")
|
425
|
-
entity.mixins.push(object).uniq!
|
426
|
-
object.entities.push(entity).uniq!
|
427
|
-
end if object.kind_of?(OCCI::Core::Mixin)
|
428
|
-
|
429
|
-
# full update of attributes
|
430
|
-
entities.each do |entity|
|
431
|
-
# Refresh information from backend for entities of type resource
|
432
|
-
# TODO: full update
|
433
|
-
entity.attributes.merge!(@occi_request.attributes)
|
434
|
-
# TODO: update entity in backend
|
435
|
-
end unless @occi_request.attributes.empty?
|
436
|
-
|
437
|
-
# full update of links
|
438
|
-
# TODO: full update e.g. delete old links first
|
439
|
-
@occi_request.links.each do |link_data|
|
440
|
-
logger.debug("Extracted link data: #{link_data}")
|
441
|
-
raise "Mandatory information missing (related | target | category)!" unless link_data.related != nil && link_data.target != nil && link_data.category != nil
|
442
|
-
|
443
|
-
link_mixins = []
|
444
|
-
link_kind = nil
|
445
|
-
link_data.category.split(' ').each do |link_category|
|
446
|
-
begin
|
447
|
-
cat = OCCI::CategoryRegistry.get_by_id(link_category)
|
448
|
-
rescue OCCI::CategoryNotFoundException => e
|
449
|
-
logger.info("Category #{link_category} not found")
|
450
|
-
next
|
451
|
-
end
|
452
|
-
link_kind = cat if cat.kind_of?(OCCI::Core::Kind)
|
453
|
-
link_mixins << cat if cat.kind_of?(OCCI::Core::Mixin)
|
454
|
-
end
|
455
|
-
|
456
|
-
raise "No kind for link category #{link_data.category} found" if link_kind.nil?
|
457
|
-
|
458
|
-
target_location = link_data.target_attr
|
459
|
-
target = OCCI::Rendering::HTTP::LocationRegistry.get_object(target_location)
|
460
|
-
|
461
|
-
entities.each do |entity|
|
462
|
-
|
463
|
-
source_location = OCCI::Rendering::HTTP::LocationRegistry.get_location_of_object(entity)
|
464
|
-
|
465
|
-
link_attributes = link_data.attributes.clone
|
466
|
-
link_attributes["occi.core.target"] = target_location.chomp('"').reverse.chomp('"').reverse
|
467
|
-
link_attributes["occi.core.source"] = source_location
|
468
|
-
|
469
|
-
link = link_kind.entity_type.new(link_attributes, link_mixins)
|
470
|
-
OCCI::Rendering::HTTP::LocationRegistry.register_location(link.get_location(), link)
|
471
|
-
|
472
|
-
target.links << link
|
473
|
-
entity.links << link
|
474
|
-
end
|
475
|
-
end
|
476
|
-
break
|
477
|
-
end
|
478
|
-
|
479
|
-
response.status = OCCI::Rendering::HTTP::Response::HTTP_NOT_FOUND
|
480
|
-
# Create resource instance at the given location
|
481
|
-
raise "Creating resources with method 'put' is currently not possible!"
|
482
|
-
|
483
|
-
# This must be the last statement in this block, so that sinatra does not try to respond with random body content
|
484
|
-
# (or fail utterly while trying to do that!)
|
485
|
-
nil
|
486
|
-
|
487
|
-
end
|
488
|
-
|
489
|
-
# ---------------------------------------------------------------------------------------------------------------------
|
490
|
-
# DELETE request
|
491
|
-
|
492
|
-
delete '/-/', '/.well-known/org/ogf/occi/-/' do
|
493
|
-
# Location references query interface => delete provided mixin
|
494
|
-
raise OCCI::CategoryMissingException if @request_collection.mixins.nil?
|
495
|
-
mixins = OCCI::Registry.get(@request_collection.mixins)
|
496
|
-
raise OCCI::MixinNotFoundException if mixins.nil?
|
497
|
-
mixins.each do |mixin|
|
498
|
-
OCCI::Log.debug("### Deleting mixin #{mixin.type_identifier} ###")
|
499
|
-
mixin.entities.each do |entity|
|
500
|
-
entity.mixins.delete(mixin)
|
501
|
-
end
|
502
|
-
# TODO: Notify backend to delete mixin and unassociate entities
|
503
|
-
OCCI::Registry.unregister(mixin)
|
504
|
-
end
|
505
|
-
status 200
|
506
|
-
end
|
507
|
-
|
508
|
-
delete '*' do
|
509
|
-
|
510
|
-
# unassociate resources specified by URI in payload from mixin specified by request location
|
511
|
-
if request.path_info == '/'
|
512
|
-
categories = OCCI::Registry.get.kinds
|
513
|
-
else
|
514
|
-
categories = [OCCI::Registry.get_by_location(request.path_info.rpartition('/').first + '/')]
|
515
|
-
end
|
516
|
-
|
517
|
-
categories.each do |category|
|
518
|
-
case category
|
519
|
-
when OCCI::Core::Mixin
|
520
|
-
mixin = category
|
521
|
-
OCCI::Log.debug("### Deleting entities from mixin #{mixin.type_identifier} ###")
|
522
|
-
@request_collection.locations.each do |location|
|
523
|
-
uuid = location.to_s.rpartition('/').last
|
524
|
-
mixin.entities.delete_if { |entity| entity.id == uuid }
|
525
|
-
end
|
526
|
-
when OCCI::Core::Kind
|
527
|
-
kind = category
|
528
|
-
if request.path_info.end_with?('/')
|
529
|
-
if @request_collection.mixins.any?
|
530
|
-
@request_collection.mixins.each do |mixin|
|
531
|
-
OCCI::Log.debug("### Deleting entities from kind #{kind.type_identifier} with mixin #{mixin.type_identifier} ###")
|
532
|
-
kind.entities.each { |entity| OCCI::Backend::Manager.signal_resource(@backend, OCCI::Backend::RESOURCE_DELETE, entity) if mixin.include?(entity) }
|
533
|
-
kind.entities.delete_if? { |entity| mixin.include?(entity) }
|
534
|
-
# TODO: links
|
535
|
-
end
|
536
|
-
else
|
537
|
-
# TODO: links
|
538
|
-
OCCI::Log.debug("### Deleting entities from kind #{kind.type_identifier} ###")
|
539
|
-
kind.entities.each { |resource| OCCI::Backend::Manager.signal_resource(@backend, OCCI::Backend::RESOURCE_DELETE, resource) }
|
540
|
-
kind.entities.clear
|
541
|
-
end
|
542
|
-
else
|
543
|
-
uuid = request.path_info.rpartition('/').last
|
544
|
-
OCCI::Log.debug("### Deleting entity with id #{uuid} from kind #{kind.type_identifier} ###")
|
545
|
-
OCCI::Backend::Manager.signal_resource(@backend, OCCI::Backend::RESOURCE_DELETE, entity)
|
546
|
-
kind.entities.delete_if? { |entity| entity.id == uuid }
|
547
|
-
end
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
# delete entities
|
552
|
-
|
553
|
-
|
554
|
-
# # Location references a mixin => unassociate all provided resources (by X_OCCI_LOCATION) from it
|
555
|
-
# object = OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info)
|
556
|
-
# if object != nil && object.kind_of?(OCCI::Core::Mixin)
|
557
|
-
# mixin = OCCI::Rendering::HTTP::LocationRegistry.get_object(request.path_info)
|
558
|
-
# logger.info("Unassociating entities from mixin: #{mixin}")
|
559
|
-
#
|
560
|
-
# @occi_request.locations.each do |loc|
|
561
|
-
# entity = OCCI::Rendering::HTTP::LocationRegistry.get_object(URI.parse(loc.chomp('"').reverse.chomp('"').reverse).path)
|
562
|
-
# mixin.entities.delete(entity)
|
563
|
-
# entity.mixins.delete(mixin)
|
564
|
-
# end
|
565
|
-
# break
|
566
|
-
# end
|
567
|
-
#
|
568
|
-
# entities = OCCI::Rendering::HTTP::LocationRegistry.get_resources_below_location(request.path_info, @occi_request.categories)
|
569
|
-
#
|
570
|
-
# unless entities.nil?
|
571
|
-
# entities.each do |entity|
|
572
|
-
# location = entity.get_location
|
573
|
-
# OCCI::Backend::Manager.signal_resource(@backend, OCCI::Backend::RESOURCE_DELETE, entity) if entity.kind_of? OCCI::Core::Resource
|
574
|
-
# # TODO: delete links in backend!
|
575
|
-
# entity.delete
|
576
|
-
# OCCI::Rendering::HTTP::LocationRegistry.unregister(location)
|
577
|
-
# end
|
578
|
-
# break
|
579
|
-
# end
|
580
|
-
#
|
581
|
-
# response.status = OCCI::Rendering::HTTP::Response::HTTP_NOT_FOUND
|
582
|
-
# # This must be the last statement in this block, so that sinatra does not try to respond with random body content
|
583
|
-
# # (or fail utterly while trying to do that!)
|
584
|
-
# nil
|
585
|
-
|
586
|
-
end
|
587
|
-
|
588
|
-
error do
|
589
|
-
OCCI::Log.error(sinatra.error)
|
590
|
-
'Sorry there was a nasty error - ' + env['sinatra.error'].name
|
591
|
-
end
|
592
|
-
|
593
|
-
end
|
594
|
-
end
|