occi-api 4.1.1 → 4.2.0.beta.2

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.
Files changed (43) hide show
  1. data/Gemfile +9 -0
  2. data/README.md +37 -11
  3. data/Rakefile +2 -9
  4. data/examples/dsl_example.rb +2 -2
  5. data/examples/x509auth_example.rb +9 -9
  6. data/lib/occi-api.rb +0 -1
  7. data/lib/occi/api/client/client_base.rb +102 -92
  8. data/lib/occi/api/client/client_http.rb +6 -6
  9. data/lib/occi/api/client/http/authn_plugins/keystone.rb +27 -11
  10. data/lib/occi/api/dsl.rb +7 -3
  11. data/lib/occi/api/version.rb +1 -1
  12. data/occi-api.gemspec +2 -14
  13. data/{features/cassettes/Create_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml → spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_all_available_mixins.yml} +125 -147
  14. data/{features/cassettes/Miscellaneous_operation_on_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml → spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/looks_up_a_mixin_type_identifier_for_os_tpl.yml} +126 -148
  15. data/{features/cassettes/Delete_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml → spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/looks_up_a_mixin_type_identifier_for_resource_tpl.yml} +126 -148
  16. data/spec/occi/api/client/client_http_spec.rb +52 -28
  17. data/spec/occi/api/dsl_spec.rb +0 -6
  18. data/spec/spec_helper.rb +4 -1
  19. metadata +31 -200
  20. checksums.yaml +0 -7
  21. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__application_json_200_.yml +0 -333
  22. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__text_plain_200_.yml +0 -529
  23. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__text_plain_200_action_.yml +0 -288
  24. data/features/cassettes/Read_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +0 -288
  25. data/features/cassettes/Update_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +0 -288
  26. data/features/common/step_definitions/common_steps.rb +0 -32
  27. data/features/occi/core/create/create.feature +0 -18
  28. data/features/occi/core/create/step_definitions/create_steps.rb +0 -0
  29. data/features/occi/core/delete/delete.feature +0 -18
  30. data/features/occi/core/delete/step_definitions/delete_steps.rb +0 -0
  31. data/features/occi/core/discovery_interface/discovery_interface.feature +0 -37
  32. data/features/occi/core/discovery_interface/step_definitions/discovery_interface_steps.rb +0 -19
  33. data/features/occi/core/miscellaneous/miscellaneous.feature +0 -18
  34. data/features/occi/core/miscellaneous/step_definitions/miscellaneous_steps.rb +0 -0
  35. data/features/occi/core/read/read.feature +0 -18
  36. data/features/occi/core/read/step_definitions/read_steps.rb +0 -0
  37. data/features/occi/core/update/step_definitions/update_steps.rb +0 -0
  38. data/features/occi/core/update/update.feature +0 -18
  39. data/features/occi/infrastructure/create/create.feature +0 -18
  40. data/features/occi/infrastructure/create/step_definitions/create_steps.rb +0 -0
  41. data/features/support/env.rb +0 -16
  42. data/lib/occi/api/client/client_amqp.rb +0 -766
  43. data/spec/occi/api/client/client_amqp_spec.rb +0 -158
@@ -1,18 +0,0 @@
1
- Feature:
2
- In order to update an OCCI Resource on the OCCI Server
3
- As an OCCI Client
4
- I want to get an success report of the update operation
5
-
6
- @vcr_record
7
- Scenario Outline: Update an OCCI Resource
8
- Given endpoint : <endpoint>
9
- And transfer_protocol : <protocol>
10
- And accept type : <accept_type>
11
- And have an initialize Client
12
- When the Client makes an update request
13
- Then the Client should have the response code <response_code>
14
-
15
- @vcr_record
16
- Scenarios:
17
- | protocol | endpoint | accept_type | response_code |
18
- | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,18 +0,0 @@
1
- Feature:
2
- In order to create an OCCI Resource on the OCCI Server
3
- As an OCCI Client
4
- I want to get an success report of the create operation and receive the URI of the new Resource by the OCCI Server
5
-
6
- @vcr_record
7
- Scenario Outline: Create an OCCI Resource
8
- Given endpoint : <endpoint>
9
- And transfer_protocol : <protocol>
10
- And accept type : <accept_type>
11
- And have an initialize Client
12
- When the Client makes a create request
13
- Then the Client should have the response code <response_code>
14
-
15
- @vcr_record
16
- Scenarios:
17
- | protocol | endpoint | accept_type | response_code |
18
- | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,16 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../../lib')
2
-
3
- require 'rubygems'
4
- require 'occi-api'
5
-
6
- require 'vcr'
7
-
8
- VCR.configure do |c|
9
- c.hook_into :webmock
10
- c.cassette_library_dir = 'features/cassettes'
11
- end
12
-
13
- VCR.cucumber_tags do |t|
14
- t.tags '@vcr_ignore', :record => :none
15
- t.tag '@vcr_record', {:use_scenario_name => true, :record => :new_episodes}
16
- end
@@ -1,766 +0,0 @@
1
- require "amqp"
2
- require "json"
3
-
4
- module Occi
5
- module Api
6
- module Client
7
-
8
- class ClientAmqp
9
- attr_reader :endpoint, :auth_options, :connected, :last_response_status
10
- attr_accessor :media_type, :model
11
-
12
- CONNECTION_SETTING = {
13
- :host => 'localhost', #IP of the MessageBroker (RabbitMQ)
14
- :port => 5672,
15
- :vhost => '/' ,
16
- :password => 'password'
17
- }
18
-
19
- # hash mapping HTTP response codes to human-readable messages
20
- HTTP_CODES = {
21
- "100" => "Continue",
22
- "101" => "Switching Protocols",
23
- "200" => "OK",
24
- "201" => "Created",
25
- "202" => "Accepted",
26
- "203" => "Non-Authoritative Information",
27
- "204" => "No Content",
28
- "205" => "Reset Content",
29
- "206" => "Partial Content",
30
- "300" => "Multiple Choices",
31
- "301" => "Moved Permanently",
32
- "302" => "Found",
33
- "303" => "See Other",
34
- "304" => "Not Modified",
35
- "305" => "Use Proxy",
36
- "307" => "Temporary Redirect",
37
- "400" => "Bad Request",
38
- "401" => "Unauthorized",
39
- "402" => "Payment Required",
40
- "403" => "Forbidden",
41
- "404" => "Not Found",
42
- "405" => "Method Not Allowed",
43
- "406" => "Not Acceptable",
44
- "407" => "Proxy Authentication Required",
45
- "408" => "Request Time-out",
46
- "409" => "Conflict",
47
- "410" => "Gone",
48
- "411" => "Length Required",
49
- "412" => "Precondition Failed",
50
- "413" => "Request Entity Too Large",
51
- "414" => "Request-URI Too Large",
52
- "415" => "Unsupported Media Type",
53
- "416" => "Requested range not satisfiable",
54
- "417" => "Expectation Failed",
55
- "500" => "Internal Server Error",
56
- "501" => "Not Implemented",
57
- "502" => "Bad Gateway",
58
- "503" => "Service Unavailable",
59
- "504" => "Gateway Time-out",
60
- "505" => "HTTP Version not supported"
61
- }
62
-
63
- #TODO Should a client have some kind of timeout
64
-
65
- # Initializes client data structures and retrieves OCCI model
66
- # from the server.
67
- #
68
- # @example
69
- # options = {
70
- # :endpoint => "http://localhost:3300/",
71
- # :auth => {:type => "none"},
72
- # :log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
73
- # :media_type => "text/plain"
74
- # }
75
- #
76
- # Occi::Api::Client::ClientAmqp.new options # => #<Occi::Api::Client::ClientAmqp>
77
- #
78
- # @param [Hash] options, for available options and defaults see examples
79
- # @return [Occi::Api::Client::ClientAmqp] client instance
80
- def initialize(options = {})
81
-
82
- defaults = {
83
- :endpoint => "http://localhost:3300/",
84
- :auth => {:type => "none"},
85
- :log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
86
- :media_type => "text/plain"
87
- }
88
-
89
- options = options.marshal_dump if options.is_a? OpenStruct
90
- options = defaults.merge options
91
-
92
- # check the validity and canonize the endpoint URI
93
- prepare_endpoint options[:endpoint]
94
-
95
- # set Occi::Log
96
- set_logger options[:log]
97
-
98
- # pass auth options to HTTParty
99
- change_auth options[:auth]
100
-
101
- @media_type = options[:media_type]
102
-
103
- Occi::Log.debug("Media Type: #{@media_type}")
104
-
105
- @connected = false
106
-
107
- Thread.new { run }
108
-
109
- Occi::Log.debug("Waiting for connection amqp ...")
110
-
111
- #TODO find a better solution for the thread issue
112
- while(!@thread_error && !@connected)
113
- #dont use sleep - it blocks the eventmachine
114
- end
115
-
116
- # get model information from the endpoint
117
- # and create Occi::Model instance
118
- set_model unless @thread_error
119
- end
120
-
121
- # @describe Retrieves available resources represented by resource locations (URIs).
122
- # If no type identifier is specified, all available resource are listed.
123
- # Type identifier can be specified in its shortened format (e.g. "compute",
124
- # "storage", "network").
125
- #
126
- # @example
127
- # client.list
128
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
129
- # # "http://localhost:3300/network/kh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
130
- # # "http://localhost:3300/storage/lh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
131
- # client.list "compute"
132
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
133
- # client.list "http://schemas.ogf.org/occi/infrastructure#compute"
134
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
135
- #
136
- # @param [String] resource type identifier or just type name
137
- # @return [Array<String>] list of links
138
- def list(resource_type_identifier = nil, is_wait = true, is_parse_response = true)
139
-
140
- if resource_type_identifier
141
- # convert type to type identifier
142
- resource_type_identifier = @model.kinds.select {
143
- |kind| kind.term == resource_type_identifier
144
- }.first.type_identifier if @model.kinds.select {
145
- |kind| kind.term == resource_type_identifier
146
- }.any?
147
-
148
- # check some basic pre-conditions
149
- raise "Endpoint is not connected!" unless @connected
150
- raise "Unkown resource type identifier! [#{resource_type_identifier}]" unless @model.get_by_id resource_type_identifier
151
-
152
- # split the type identifier and get the most important part
153
- uri_part = resource_type_identifier.split('#').last
154
-
155
- # request uri-list from the server
156
- path = uri_part + '/'
157
- else
158
- path = '/'
159
- end
160
-
161
- message_id = get(path, true)
162
-
163
- return response_value(message_id, is_wait, is_parse_response)
164
- end
165
-
166
- # @describe Retrieves descriptions for available resources specified by a type
167
- # identifier or resource location. If no type identifier or location
168
- # is specified, all available resources in all available resource types
169
- # will be described.
170
- #
171
- # @example
172
- # client.describe
173
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
174
- # client.describe "compute"
175
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
176
- # client.describe "http://schemas.ogf.org/occi/infrastructure#compute"
177
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
178
- # client.describe "http://localhost:3300/compute/j5hk1234jk2524-2j3j2k34jjh234-adfaf1234"
179
- # # => [#<Occi::Collection>]
180
- #
181
- # @param [String] resource type identifier, type name or resource location
182
- # @return [Array<Occi::Collection>] list of resource descriptions
183
- def describe(resource_type_identifier=nil, is_wait = true, is_parse_response = true)
184
-
185
- raise "Endpoint is not connected!" unless @connected
186
-
187
- # convert type to type identifier
188
- resource_type_identifier = @model.kinds.select {
189
- |kind| kind.term == resource_type_identifier
190
- }.first.type_identifier if @model.kinds.select {
191
- |kind| kind.term == resource_type_identifier
192
- }.any?
193
-
194
- descriptions = []
195
-
196
- if resource_type_identifier.nil?
197
- descriptions << response_value(get('/'), is_wait, is_parse_response)
198
- elsif @model.get_by_id resource_type_identifier
199
- # we got type identifier
200
- # get all available resources of this type
201
- locations = list resource_type_identifier
202
-
203
- # make the requests
204
- locations.each do |location|
205
- descriptions << response_value(get(sanitize_resource_link(location)), is_wait, is_parse_response)
206
- end
207
- elsif resource_type_identifier.start_with? @endpoint
208
- # we got resource link
209
- # make the request
210
- descriptions << response_value(get(sanitize_resource_link(resource_type_identifier)), is_wait, is_parse_response)
211
- else
212
- raise "Unkown resource type identifier! [#{resource_type_identifier}]"
213
- end
214
-
215
- descriptions
216
- end
217
-
218
- # Creates a new resource on the server. Resource must be provided
219
- # as an instance of Occi::Core::Entity, e.g. instantiated using
220
- # the get_resource method.
221
- #
222
- # @example
223
- # res = client.get_resource "compute"
224
- #
225
- # res.title = "MyComputeResource1"
226
- # res.mixins << client.find_mixin('small', "resource_tpl")
227
- # res.mixins << client.find_mixin('debian6', "os_tpl")
228
- #
229
- # client.create res # => "http://localhost:3300/compute/df7698...f987fa"
230
- #
231
- def create(entity, is_wait = true, is_parse_response = true)
232
-
233
- # check some basic pre-conditions
234
- raise "Endpoint is not connected!" unless @connected
235
- raise "#{entity} not an entity" unless entity.kind_of? Occi::Core::Entity
236
-
237
- # is this entity valid?
238
- entity.model = @model
239
- entity.check
240
- kind = entity.kind
241
- raise "No kind found for #{entity}" unless kind
242
-
243
- # get location for this kind of entity
244
- location = entity.kind.location
245
- collection = Occi::Collection.new
246
-
247
- # is this entity a Resource or a Link?
248
- collection.resources << entity if entity.kind_of? Occi::Core::Resource
249
- collection.links << entity if entity.kind_of? Occi::Core::Link
250
-
251
- # make the request
252
- response_value(post(location, collection), is_wait, is_parse_response)
253
- end
254
-
255
- # Deletes a resource or all resource of a certain resource type
256
- # from the server.
257
- #
258
- # @example
259
- # client.delete "compute" # => true
260
- # client.delete "http://schemas.ogf.org/occi/infrastructure#compute" # => true
261
- # client.delete "http://localhost:3300/compute/245j42594...98s9df8s9f" # => true
262
- #
263
- # @param [String] resource type identifier, type name or location
264
- # @return [Boolean] status
265
- def delete(resource_type_identifier, is_wait = true, is_parse_response = true)
266
- # convert type to type identifier
267
- resource_type_identifier = @model.kinds.select {
268
- |kind| kind.term == resource_type_identifier
269
- }.first.type_identifier if @model.kinds.select {
270
- |kind| kind.term == resource_type_identifier
271
- }.any?
272
-
273
- # check some basic pre-conditions
274
- raise "Endpoint is not connected!" unless @connected
275
-
276
- if resource_type_identifier.nil? || resource_type_identifier == "/"
277
- path = "/"
278
- else
279
- raise "Unknown resource identifier! #{resource_type_identifier}" unless resource_type_identifier.start_with? @endpoint
280
- path = sanitize_resource_link(resource_type_identifier)
281
- end
282
-
283
- # make the request
284
- response_value(del(path), is_wait, is_parse_response)
285
- end
286
-
287
- # Triggers given action on a specific resource.
288
- #
289
- # @example
290
- # TODO: add examples
291
- #
292
- # @param [String] resource location
293
- # @param [String] type of action
294
- # @return [String] resource location
295
- def trigger(resource_type_identifier, action, is_wait = true, is_parse_response = true)
296
-
297
- # TODO: not tested
298
- resource_type_identifier = @model.kinds.select {
299
- |kind| kind.term == resource_type_identifier
300
- }.first.type_identifier if @model.kinds.select {
301
- |kind| kind.term == resource_type_identifier
302
- }.any?
303
-
304
- # check some basic pre-conditions
305
- raise "Endpoint is not connected!" unless @connected
306
-
307
- if resource_type_identifier.nil? || resource_type_identifier == "/"
308
- path = "/"
309
- else
310
- raise "Unknown resource identifier! #{resource_type_identifier}" unless resource_type_identifier.start_with? @endpoint
311
- path = sanitize_resource_link(resource_type_identifier)
312
- end
313
-
314
- # encapsulate the acion in a collection
315
- collection = Occi::Collection.new
316
- scheme, term = action.split('#')
317
- collection.actions << Occi::Core::Action.new(scheme + '#', term)
318
-
319
- #@media_type = "text/plain"
320
-
321
- # make the request
322
- path = path + '?action=' + term
323
- response_value(post(path, collection))
324
- end
325
-
326
- def parse_message(message_id, delete_response = true)
327
- raise "message is empty for message_id(#{ message_id })" if @response_messages.nil? || @response_messages[message_id].nil?
328
-
329
- payload = @response_messages[message_id][:payload]
330
- type = @response_messages[message_id][:type]
331
- metadata = @response_messages[message_id][:metadata]
332
-
333
- @last_response_status = metadata.headers["status_code"]
334
-
335
- @response_messages.delete(message_id) if delete_response
336
-
337
- raise "OCCI-Server raise error: #{ payload } server status: #{ @last_response_status }" if metadata.headers["is_error"]
338
-
339
- begin
340
- return method("parse_#{ type }").call(payload, metadata)
341
- rescue Exception => e
342
- error_msg = e.message + "\n" + e.backtrace.to_s
343
- Occi::Log.error error_msg
344
- raise "Can not parse #{ type } payload: #{ payload } metadata: #{ metadata.inspect }"
345
- end
346
- end
347
-
348
- # Looks up a mixin using its name and, optionally, a type as well.
349
- # Will return mixin's full location (a link) or a description.
350
- #
351
- # @example
352
- # client.find_mixin "debian6"
353
- # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
354
- # client.find_mixin "debian6", "os_tpl"
355
- # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
356
- # client.find_mixin "large", "resource_tpl"
357
- # # => "http://my.occi.service/occi/infrastructure/resource_tpl#large"
358
- # client.find_mixin "debian6", "resource_tpl" # => nil
359
- #
360
- # @param [String] name of the mixin
361
- # @param [String] type of the mixin
362
- # @param [Boolean] should we describe the mixin or return its link?
363
- # @return [String, Occi::Collection, nil] link, mixin description or nothing found
364
- def find_mixin(name, type = nil, describe = false)
365
-
366
- Occi::Log.debug("Looking for mixin #{name} + #{type} + #{describe}")
367
-
368
- # is type valid?
369
- if type
370
- raise "Unknown mixin type! [#{type}]" unless @mixins.has_key? type.to_sym
371
- end
372
-
373
- # TODO: extend this code to support multiple matches and regex filters
374
- # should we look for links or descriptions?
375
- if describe
376
- # we are looking for descriptions
377
- if type
378
- # get the first match from either os_tpls or resource_tpls
379
- case
380
- when type == "os_tpl"
381
- get_os_templates.select { |mixin| mixin.term == name }.first
382
- when type == "resource_tpl"
383
- get_resource_templates.select { |template| template.term == name }.first
384
- else
385
- nil
386
- end
387
- else
388
- # try in os_tpls first
389
- found = get_os_templates.select { |os| os.term == name }.first
390
-
391
- # then try in resource_tpls
392
- found = get_resource_templates.select {
393
- |template| template.term == name
394
- }.first unless found
395
-
396
- found
397
- end
398
- else
399
- # we are looking for links
400
- # prefix mixin name with '#' to simplify the search
401
- name = "#" + name
402
- if type
403
- # return the first match with the selected type
404
- @mixins[type.to_sym].select {
405
- |mixin| mixin.to_s.reverse.start_with? name.reverse
406
- }.first
407
- else
408
- # there is no type preference, return first global match
409
- @mixins.flatten(2).select {
410
- |mixin| mixin.to_s.reverse.start_with? name.reverse
411
- }.first
412
- end
413
- end
414
- end
415
-
416
- # Creates a new resource instance, resource should be specified
417
- # by its name or identifier.
418
- #
419
- # @example
420
- # client.get_resource "compute" # => Occi::Core::Resource
421
- # client.get_resource "storage" # => Occi::Core::Resource
422
- # client.get_resource "http://schemas.ogf.org/occi/infrastructure#network"
423
- # # => Occi::Core::Resource
424
- #
425
- # @param [String] resource name or resource identifier
426
- # @return [Occi::Core::Resource] new resource instance
427
- def get_resource(resource_type)
428
-
429
- Occi::Log.debug("Instantiating #{resource_type} ...")
430
-
431
- if @model.get_by_id resource_type
432
- # we got a resource type identifier
433
- Occi::Core::Resource.new resource_type
434
- elsif @model.kinds.select { |kind| kind.term == resource_type }.any?
435
- # we got a resource type name
436
- Occi::Core::Resource.new @model.kinds.select {
437
- |kind| kind.term == resource_type
438
- }.first.type_identifier
439
- else
440
- raise "Unknown resource type! [#{resource_type}]"
441
- end
442
-
443
- end
444
-
445
- # Retrieves available os_tpls from the model.
446
- #
447
- # @example
448
- # get_os_templates # => #<Occi::Collection>
449
- #
450
- # @return [Occi::Collection] collection containing all registered OS templates
451
- def get_os_templates
452
- @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'os_tpl' }.any? }
453
- end
454
-
455
- # Retrieves available resource_tpls from the model.
456
- #
457
- # @example
458
- # get_resource_templates # => #<Occi::Collection>
459
- #
460
- # @return [Occi::Collection] collection containing all registered resource templates
461
- def get_resource_templates
462
- @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'resource_tpl' }.any? }
463
- end
464
-
465
- # Refreshes the Occi::Model used inside the client. Useful for
466
- # updating the model without creating a new instance or
467
- # reconnecting. Saves a lot of time in an interactive mode.
468
- #
469
- # @example
470
- # client.refresh
471
- def refresh
472
- # re-download the model from the server
473
- set_model
474
- end
475
-
476
- # private stuff --------------------------------------------------------------------------------------------------
477
- private
478
-
479
- def parse_get(payload, metadata)
480
- if metadata.content_type == "text/uri-list"
481
- return payload.split("\n")
482
- else
483
- path = metadata.headers["path_info"]
484
- kind = @model.get_by_location(('/' + path).match(/\/.*\//).to_s) if @model
485
- kind ? entity_type = kind.entity_type : entity_type = nil
486
- collection = Occi::Parser.parse(metadata.content_type, payload, path.include?("/-/"), entity_type)
487
- return collection
488
- end
489
- end
490
-
491
- def parse_post(payload, metadata)
492
- return URI.parse(payload).to_s
493
- end
494
-
495
- def parse_delete(payload, metadata)
496
- return true
497
- end
498
-
499
- def run
500
- begin
501
- AMQP.start(CONNECTION_SETTING) do |connection, open_ok|
502
- @channel = AMQP::Channel.new(connection)
503
- @exchange = @channel.default_exchange
504
-
505
- @channel.on_error(&method(:handle_channel_exception))
506
-
507
- @replies_queue = @channel.queue(Time.now.to_f.to_s + Kernel.rand().to_s, :exclusive => true)
508
- @replies_queue.subscribe(&method(:handle_message))
509
-
510
- @connected = true;
511
- end
512
- rescue Exception => e
513
- @thread_error = true
514
- Occi::Log.error "Amqp Thread get an Error: #{e.message} \n #{e.backtrace.join("\n")}"
515
- end
516
- end
517
-
518
- def handle_message(metadata, payload)
519
-
520
- correlation_id = metadata.correlation_id
521
-
522
- unless correlation_id.size > 0
523
- raise "Message has no correlation_id (message_id)"
524
- end
525
-
526
- @response_messages = Hash.new if @response_messages.nil?
527
- raise "Double Response Message ID: (#{ correlation_id })" if @response_messages.has_key?(correlation_id)
528
-
529
- #save responses message
530
- @response_messages[correlation_id] = {:payload => payload, :metadata => metadata, :type => @response_waiting[correlation_id][:options][:type]}
531
-
532
- #delete message_id from waiting stack
533
- @response_waiting.delete(correlation_id) unless @response_waiting.nil?
534
- end
535
-
536
- def set_model
537
- collection = response_value(get('/-/'))
538
- @model = Occi::Model.new(collection)
539
-
540
- @mixins = {
541
- :os_tpl => [],
542
- :resource_tpl => [],
543
- :simulation => []
544
- }
545
-
546
- #
547
- get_os_templates.each do |os_tpl|
548
- @mixins[:os_tpl] << os_tpl.type_identifier unless os_tpl.nil? or os_tpl.type_identifier.nil?
549
- end
550
-
551
- #
552
- get_resource_templates.each do |res_tpl|
553
- @mixins[:resource_tpl] << res_tpl.type_identifier unless res_tpl.nil? or res_tpl.type_identifier.nil?
554
- end
555
- end
556
-
557
- # Extracts the resource path from a resource link. It will remove the leading @endpoint
558
- # and replace it with a slash.
559
- #
560
- # @example
561
- # sanitize_resource_link "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
562
- # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
563
- #
564
- # @param [String] string containing the full resource link
565
- # @return [String] extracted path, with a leading slash
566
- def sanitize_resource_link(resource_link)
567
- raise "Resource link #{resource_link} is not valid!" unless resource_link.start_with? @endpoint
568
-
569
- resource_link.gsub @endpoint, '/'
570
- end
571
-
572
- #TODO filter
573
- def get(path='', is_uri_list = false, filter=nil)
574
- raise "OCCI AMQP is not connected!" if !@connected
575
-
576
- options = {
577
- :routing_key => @endpoint_queue,
578
- :type => "get",
579
- :content_type => "text/plain",
580
- :reply_to => reply_queue_name,
581
- :message_id => next_message_id,
582
- :headers => {
583
- :accept => is_uri_list ? "text/uri-list" : @media_type,
584
- :path_info => "/" + path.gsub(/\A\//, '')
585
- }
586
- }
587
-
588
- publish('', options)
589
-
590
- return options[:message_id]
591
- end
592
-
593
- #@description
594
- #@param [String] path path to the resource
595
- #@param [OCCI::Collection] collection
596
- def post(path, collection=nil)
597
- path = path.reverse.chomp('/').reverse
598
-
599
- if @media_type == 'application/occi+json'
600
- message = collection.to_json
601
- content_type = 'application/occi+json'
602
- else
603
- message = collection.to_text
604
- content_type = 'text/plain'
605
- end
606
-
607
- options = {
608
- :routing_key => @endpoint_queue,
609
- :content_type => content_type,
610
- :type => "post",
611
- :reply_to => reply_queue_name, #queue for response from the rOCCI
612
- :message_id => next_message_id, #Identifier for message so that the client can match the answer from the rOCCI
613
- :headers => {
614
- :accept => "text/uri-list",
615
- :path_info => "/#{ path }",
616
- :auth => {
617
- :type => "basic",
618
- :username => "user",
619
- :password => "mypass",
620
- },
621
- }
622
- }
623
-
624
- publish(message, options)
625
-
626
- return options[:message_id]
627
- end
628
-
629
- # Performs DELETE requests and returns True on success.
630
- #
631
- # @example
632
- # del "/compute/65sf4g65sf4g-sf6g54sf5g-sfgsf32g3" # => true
633
- #
634
- # @param [String] path for the DELETE request
635
- # @param [Occi::Collection] collection of filters (currently NOT used)
636
- # @return [Boolean] status
637
- def del(path, filter=nil)
638
- # remove the leading slash
639
- path.gsub!(/\A\//, '')
640
-
641
- options = {
642
- :routing_key => @endpoint_queue,
643
- :content_type => "text/plain",
644
- :type => "delete",
645
- :reply_to => reply_queue_name, #queue for response from the rOCCI
646
- :message_id => next_message_id, #Identifier for message so that the client can match the answer from the rOCCI
647
- :headers => {
648
- :accept => @media_type,
649
- :path_info => "/#{ path }",
650
- :auth => {
651
- :type => "basic",
652
- :username => "user",
653
- :password => "mypass",
654
- },
655
- }
656
- }
657
-
658
- publish('', options)
659
-
660
- return options[:message_id]
661
- end
662
-
663
- def response_value(message_id, is_wait = true, is_parse_response = true)
664
- waiting_for_response(message_id) if is_wait || is_parse_response
665
-
666
- if is_parse_response
667
- value = parse_message(message_id)
668
- else
669
- value = message_id
670
- end
671
-
672
- return value
673
- end
674
-
675
- # @param [String] message_id '' == all
676
- def waiting_for_response(message_id = '')
677
- return if @response_waiting.nil?
678
-
679
- if message_id.size > 0
680
- while !@response_waiting[message_id].nil?
681
- sleep(0.1)
682
- end
683
- else
684
- while size(@response_waiting) > 0
685
- sleep(0.1)
686
- end
687
- end
688
- end
689
-
690
- def publish(message, options = {})
691
- raise "No Message Id found" if options[:message_id] == nil?
692
-
693
- @exchange.publish(message, options)
694
-
695
- @response_waiting = Hash.new if @response_waiting.nil?
696
- @response_waiting[options[:message_id]] = {:options => options, :message => message}
697
- end
698
-
699
- def reply_queue_name
700
- @replies_queue.name
701
- end
702
-
703
- def next_message_id
704
- @message_id = 0 if @message_id.nil?
705
- @message_id += 1
706
- @message_id.to_s;
707
- end
708
-
709
- # Sets auth method and appropriate httparty attributes. Supported auth methods
710
- # are: ["none"] and nil
711
- #
712
- # @example
713
- # change_auth { :type => "none" }
714
- #
715
- # @param [Hash] authentication options
716
- def change_auth(auth_options)
717
- @auth_options = auth_options
718
-
719
- case @auth_options[:type]
720
- when "none", nil
721
- # do nothing
722
- else
723
- raise ArgumentError, "Unknown AUTH method [#{@auth_options[:type]}]!"
724
- end
725
- end
726
-
727
- def handle_channel_exception(channel, channel_close)
728
- Occi::Log.error "OCCI/AMQP: Channel-level exception [ code = #{channel_close.reply_code}, message = #{channel_close.reply_text} ]"
729
- end
730
-
731
- # Sets the logger and log levels. This allows users to pass existing logger
732
- # instances to the rOCCI client.
733
- #
734
- # @example
735
- # set_logger { :out => STDERR, :level => Occi::Log::WARN, :logger => nil }
736
- #
737
- # @param [Hash] logger options
738
- def set_logger(log_options)
739
- if log_options[:logger].nil? or (not log_options[:logger].kind_of? Occi::Log)
740
- logger = Occi::Log.new(log_options[:out])
741
- logger.level = log_options[:level]
742
- end
743
-
744
- self.class.debug_output $stderr if log_options[:level] == Occi::Log::DEBUG
745
- end
746
-
747
- # Checks whether the given endpoint URI is valid and adds a trailing
748
- # slash if necessary.
749
- #
750
- # @example
751
- # prepare_endpoint "http://localhost:3300" # => "http://localhost:3300/"
752
- #
753
- # @param [String] endpoint URI in a non-canonical string
754
- # @return [String] canonical endpoint URI in a string, with a trailing slash
755
- def prepare_endpoint(endpoint)
756
- raise 'Endpoint not a valid URI' if (endpoint =~ URI::ABS_URI).nil?
757
-
758
- @endpoint = endpoint.chomp('/') + '/'
759
- @endpoint_queue = "amqp.occi.#{@endpoint}"
760
- end
761
-
762
- end
763
-
764
- end
765
- end
766
- end