omf_sfa 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +6 -0
  3. data/README.md +211 -0
  4. data/Rakefile +23 -0
  5. data/bin/parse_rspec.rb +167 -0
  6. data/etc/omf-sfa/omf-sfa-am.yaml +12 -0
  7. data/examples/exogeni5nodemanifest.rspec +105 -0
  8. data/examples/instageni5nodemanifest.rspec +150 -0
  9. data/lib/omf-sfa/am/am-rest/REST_API.md +301 -0
  10. data/lib/omf-sfa/am/am-rest/account_handler.rb +145 -0
  11. data/lib/omf-sfa/am/am-rest/am_rest_server.rb +255 -0
  12. data/lib/omf-sfa/am/am-rest/api_template.html +48 -0
  13. data/lib/omf-sfa/am/am-rest/config.ru +110 -0
  14. data/lib/omf-sfa/am/am-rest/resource_handler.rb +178 -0
  15. data/lib/omf-sfa/am/am-rest/rest_handler.rb +573 -0
  16. data/lib/omf-sfa/am/am-rest/session_authenticator.rb +130 -0
  17. data/lib/omf-sfa/am/am-rpc/abstract_rpc_service.rb +60 -0
  18. data/lib/omf-sfa/am/am-rpc/am_authorizer.rb +161 -0
  19. data/lib/omf-sfa/am/am-rpc/am_rpc_api.rb +450 -0
  20. data/lib/omf-sfa/am/am-rpc/am_rpc_service.rb +402 -0
  21. data/lib/omf-sfa/am/am_liaison.rb +93 -0
  22. data/lib/omf-sfa/am/am_manager.rb +859 -0
  23. data/lib/omf-sfa/am/am_runner.rb +108 -0
  24. data/lib/omf-sfa/am/am_scheduler.rb +146 -0
  25. data/lib/omf-sfa/am/am_server.rb +194 -0
  26. data/lib/omf-sfa/am/config.ru +122 -0
  27. data/lib/omf-sfa/am/credential.rb +145 -0
  28. data/lib/omf-sfa/am/default_authorizer.rb +44 -0
  29. data/lib/omf-sfa/am/privilege_credential.rb +76 -0
  30. data/lib/omf-sfa/am/signature.rb +37 -0
  31. data/lib/omf-sfa/am/user_credential.rb +56 -0
  32. data/lib/omf-sfa/am.rb +7 -0
  33. data/lib/omf-sfa/model/abstract_prop_description.rb +87 -0
  34. data/lib/omf-sfa/model/model_class_description.rb +145 -0
  35. data/lib/omf-sfa/model/model_data_prop_description.rb +28 -0
  36. data/lib/omf-sfa/model/model_obj_prop_description.rb +49 -0
  37. data/lib/omf-sfa/model/ontology.rb +169 -0
  38. data/lib/omf-sfa/resource/README.md +24 -0
  39. data/lib/omf-sfa/resource/channel.rb +49 -0
  40. data/lib/omf-sfa/resource/comp_group.rb +41 -0
  41. data/lib/omf-sfa/resource/component_lease.rb +10 -0
  42. data/lib/omf-sfa/resource/constants.rb +24 -0
  43. data/lib/omf-sfa/resource/group_component.rb +35 -0
  44. data/lib/omf-sfa/resource/group_membership.rb +17 -0
  45. data/lib/omf-sfa/resource/gurn.rb +187 -0
  46. data/lib/omf-sfa/resource/interface.rb +78 -0
  47. data/lib/omf-sfa/resource/ip.rb +48 -0
  48. data/lib/omf-sfa/resource/link.rb +29 -0
  49. data/lib/omf-sfa/resource/node.rb +75 -0
  50. data/lib/omf-sfa/resource/oaccount.rb +94 -0
  51. data/lib/omf-sfa/resource/ocomponent.rb +134 -0
  52. data/lib/omf-sfa/resource/ogroup.rb +106 -0
  53. data/lib/omf-sfa/resource/olease.rb +61 -0
  54. data/lib/omf-sfa/resource/oproperty.rb +178 -0
  55. data/lib/omf-sfa/resource/oreference.rb +15 -0
  56. data/lib/omf-sfa/resource/oresource.rb +491 -0
  57. data/lib/omf-sfa/resource/project.rb +28 -0
  58. data/lib/omf-sfa/resource/project_membership.rb +13 -0
  59. data/lib/omf-sfa/resource/sfa_base.rb +544 -0
  60. data/lib/omf-sfa/resource/user.rb +25 -0
  61. data/lib/omf-sfa/resource.rb +20 -0
  62. data/lib/omf-sfa/util/create_sample_testbed.rb +68 -0
  63. data/lib/omf-sfa/util/load_from_sfa_xml.rb +65 -0
  64. data/lib/omf-sfa/version.rb +4 -0
  65. data/lib/omf_sfa.rb +5 -0
  66. data/omf_sfa.gemspec +46 -0
  67. data/owl/README +3 -0
  68. data/owl/ben-6509.rdf +1377 -0
  69. data/owl/ben-dell.rdf +586 -0
  70. data/owl/ben-dtn.rdf +1698 -0
  71. data/owl/ben.rdf +1335 -0
  72. data/owl/collections.owl +309 -0
  73. data/owl/compute.owl +1486 -0
  74. data/owl/domain.owl +444 -0
  75. data/owl/dtn.owl +1165 -0
  76. data/owl/ec2.owl +385 -0
  77. data/owl/ethernet.owl +466 -0
  78. data/owl/eucalyptus.owl +431 -0
  79. data/owl/id-mp-Request1.rdf +247 -0
  80. data/owl/itu-grid.owl +147 -0
  81. data/owl/kansei.owl +511 -0
  82. data/owl/layer.owl +645 -0
  83. data/owl/location.owl +117 -0
  84. data/owl/mass.rdf +608 -0
  85. data/owl/nlr.rdf +901 -0
  86. data/owl/orca.owl +181 -0
  87. data/owl/planetlab.owl +124 -0
  88. data/owl/protogeni.owl +467 -0
  89. data/owl/request-6509-2.rdf +150 -0
  90. data/owl/request-6509-3.rdf +158 -0
  91. data/owl/request-6509.rdf +199 -0
  92. data/owl/request.owl +222 -0
  93. data/owl/storage.owl +511 -0
  94. data/owl/topology.owl +608 -0
  95. data/schema/rspec-v3/ad-common.xsd +269 -0
  96. data/schema/rspec-v3/ad-reservation.rnc +12 -0
  97. data/schema/rspec-v3/ad-reservation.rng +28 -0
  98. data/schema/rspec-v3/ad-reservation.xsd +13 -0
  99. data/schema/rspec-v3/ad.rnc +151 -0
  100. data/schema/rspec-v3/ad.xsd +77 -0
  101. data/schema/rspec-v3/any-extension-schema.xsd +38 -0
  102. data/schema/rspec-v3/any-extension.rnc +30 -0
  103. data/schema/rspec-v3/common.rnc +185 -0
  104. data/schema/rspec-v3/manifest-common.xsd +244 -0
  105. data/schema/rspec-v3/manifest-request.xsd +95 -0
  106. data/schema/rspec-v3/manifest.rnc +62 -0
  107. data/schema/rspec-v3/manifest.xsd +34 -0
  108. data/schema/rspec-v3/request-common.xsd +219 -0
  109. data/schema/rspec-v3/request-reservation.rnc +12 -0
  110. data/schema/rspec-v3/request-reservation.xsd +13 -0
  111. data/schema/rspec-v3/request.rnc +118 -0
  112. data/schema/rspec-v3/request.xsd +94 -0
  113. data/share/assets/css/default.css +147 -0
  114. data/share/assets/css/rest_api.css +0 -0
  115. data/share/assets/network.html +28 -0
  116. data/share/assets/network.js +82 -0
  117. data/spec/am/am-rest/common.rb +29 -0
  118. data/spec/am/am-rest/resource_group_handler_XspecX.rb +97 -0
  119. data/spec/am/am-rest/resource_handler_spec.rb +204 -0
  120. data/spec/am/am-rpc/sfa_methods_spec.rb +150 -0
  121. data/spec/am/am_manager_spec.rb +307 -0
  122. data/spec/am/am_scheduler_spec.rb +57 -0
  123. data/spec/am/common.rb +24 -0
  124. data/spec/resource/common.rb +31 -0
  125. data/spec/resource/node_spec.rb +171 -0
  126. data/spec/resource/oaccount_spec.rb +92 -0
  127. data/spec/resource/ocomponent_spec.rb +225 -0
  128. data/spec/resource/ogroup_spec.rb +93 -0
  129. data/spec/resource/oresource_spec.rb +208 -0
  130. data/spec/resource_and_leases_spec.rb +377 -0
  131. data/test/OLD_FILES/assertion1.xml +117 -0
  132. data/test/OLD_FILES/greeter_spec.rb +15 -0
  133. data/test/OLD_FILES/mongo_test.rb +45 -0
  134. data/test/OLD_FILES/req-sfa-2.xml +6 -0
  135. data/test/OLD_FILES/req-sfa-g.xml +8 -0
  136. data/test/OLD_FILES/req-sfa-g2.xml +10 -0
  137. data/test/OLD_FILES/req-sfa-g3.xml +14 -0
  138. data/test/OLD_FILES/req-sfa.xml +6 -0
  139. data/test/OLD_FILES/req1.xml +22 -0
  140. data/test/OLD_FILES/req1b.xml +15 -0
  141. data/test/OLD_FILES/rspec-test.xml +1867 -0
  142. data/test/OLD_FILES/test.rb +67 -0
  143. data/test/OLD_FILES/test2.rb +32 -0
  144. data/test/am/am_manager_rspec_tests.rb +378 -0
  145. data/test/am/am_manager_tests.rb +518 -0
  146. data/test/am/am_scheduler_tests.rb +173 -0
  147. data/test/resource/olease_test.rb +74 -0
  148. data/test/sfa_requests/request.xml +5 -0
  149. data/test/sfa_requests/request1.xml +5 -0
  150. data/test/sfa_requests/request2.xml +5 -0
  151. data/test/sfa_requests/request3.xml +5 -0
  152. metadata +601 -0
@@ -0,0 +1,859 @@
1
+
2
+ require 'omf_base/lobject'
3
+ require 'omf-sfa/resource'
4
+ require 'omf-sfa/resource/comp_group'
5
+ require 'nokogiri'
6
+
7
+
8
+ module OMF::SFA::AM
9
+
10
+ class AMManagerException < Exception; end
11
+ class UnknownResourceException < AMManagerException; end
12
+ class UnavailableResourceException < AMManagerException; end
13
+ class UnknownAccountException < AMManagerException; end
14
+ class FormatException < AMManagerException; end
15
+ class ClosedAccountException < AMManagerException; end
16
+ class InsufficientPrivilegesException < AMManagerException; end
17
+ class UnavailablePropertiesException < AMManagerException; end
18
+ class MissingImplementationException < Exception; end
19
+ class UknownLeaseException < Exception; end
20
+
21
+ OL_NAMESPACE = "http://nitlab.inf.uth.gr/schema/sfa/rspec/1"
22
+
23
+ # The manager is where all the AM related policies and
24
+ # resource management is concentrated. Testbeds with their own
25
+ # ways of dealing with resources and components should only
26
+ # need to extend this class.
27
+ #
28
+ class AMManager < OMF::Base::LObject
29
+
30
+ # Create an instance of this manager
31
+ #
32
+ # @param [Scheduler] scheduler to use for creating new resource
33
+ #
34
+ def initialize(scheduler)
35
+ @scheduler = scheduler
36
+ end
37
+
38
+ ### MANAGEMENT INTERFACE: adding and removing from the AM's control
39
+
40
+ # Register a resource to be managed by this AM.
41
+ #
42
+ # @param [OResource] resource to have managed by this manager
43
+ #
44
+ def manage_resource(resource)
45
+ unless resource.is_a?(OMF::SFA::Resource::OResource)
46
+ raise "Resource '#{resource}' needs to be of type 'OResource', but is '#{resource.class}'"
47
+ end
48
+
49
+ null_account = _get_nil_account
50
+ resource.account = null_account
51
+ resource.save
52
+ # rg = get_root_group_for_account(def_account)
53
+ # rg.contains_resources << resource
54
+ # rg.save
55
+ resource
56
+ end
57
+
58
+ # Register an array of resources to be managed by this AM.
59
+ #
60
+ # @param [Array] array of resources
61
+ #
62
+ def manage_resources(resources)
63
+ resources.map {|r| manage_resource(r) }
64
+ end
65
+
66
+ ### ACCOUNTS: creating, finding, and releasing accounts
67
+
68
+ # Return the account described by +account_descr+. Create if it doesn't exist.
69
+ #
70
+ # @param [Hash] properties of account
71
+ # @param [Authorizer] Defines context for authorization decisions
72
+ # @return [OAccount] The requested account
73
+ # @raise [UnknownResourceException] if requested account cannot be created
74
+ # @raise [InsufficientPrivilegesException] if permission is not granted
75
+ #
76
+ def find_or_create_account(account_descr, authorizer)
77
+ debug "find_or_create_account: '#{account_descr.inspect}'"
78
+ begin
79
+ return find_account(account_descr, authorizer)
80
+ rescue UnavailableResourceException
81
+ end
82
+ authorizer.can_create_account?
83
+ account = OMF::SFA::Resource::OAccount.create(account_descr)
84
+ # We have an 1-to-1 relationship between account and project for the moment
85
+ project = OMF::SFA::Resource::Project.create
86
+ account.project = project
87
+ account.save
88
+ raise UnavailableResourceException.new "Cannot create '#{account_descr.inspect}'" unless account
89
+ account
90
+ end
91
+
92
+ # Return the account described by +account_descr+. Create if it doesn't exist.
93
+ #
94
+ # @param [Hash] properties of account
95
+ # @param [Authorizer] Defines context for authorization decisions
96
+ # @return [OAccount] The requested account
97
+ # @raise [UnknownResourceException] if requested account cannot be found
98
+ # @raise [InsufficientPrivilegesException] if permission is not granted
99
+ #
100
+ def find_account(account_descr, authorizer)
101
+ unless account = OMF::SFA::Resource::OAccount.first(account_descr)
102
+ raise UnavailableResourceException.new "Unknown account '#{account_descr.inspect}'"
103
+ end
104
+ authorizer.can_view_account?(account)
105
+ account
106
+ end
107
+
108
+ # Return all accounts visible to the requesting user
109
+ #
110
+ # @param [Authorizer] Defines context for authorization decisions
111
+ # @return [Array<OAccount>] The visible accounts (maybe empty)
112
+ #
113
+ def find_all_accounts(authorizer)
114
+ accounts = OMF::SFA::Resource::OAccount.all()
115
+ nil_account = _get_nil_account()
116
+ accounts.map do |a|
117
+ next if a == nil_account
118
+ begin
119
+ authorizer.can_view_account?(a)
120
+ a
121
+ rescue InsufficientPrivilegesException
122
+ nil
123
+ end
124
+ end.compact
125
+ end
126
+
127
+ # Return the account described by +account_descr+ if it is active.
128
+ #
129
+ # @param [Hash] properties of account
130
+ # @param [Authorizer] Defines context for authorization decisions
131
+ # @return [OAccount] The requested account
132
+ # @raise [UnknownResourceException] if requested account cannot be found
133
+ # @raise [UnavailableResourceException] if requested account is closed
134
+ # @raise [InsufficientPrivilegesException] if permission is not granted
135
+ #
136
+ def find_active_account(account_descr, authorizer)
137
+ account = find_account(account_descr, authorizer)
138
+ if account.closed?
139
+ raise UnavailableResourceException.new "Account '#{account.inspect}' is closed"
140
+ end
141
+ account
142
+ end
143
+
144
+ # Renew account described by +account_descr+ hash until +expiration_time+.
145
+ # ALready closed or expired accounts can't be renewed.
146
+ #
147
+ # @param [Hash] properties of account
148
+ # @param [Time] time until account should remain valid
149
+ # @param [Authorizer] Defines context for authorization decisions
150
+ # @return [OAccount] The requested account
151
+ # @raise [UnknownResourceException] if requested account cannot be found
152
+ # @raise [UnavailableResourceException] if requested account is closed
153
+ # @raise [InsufficientPrivilegesException] if permission is not granted
154
+ #
155
+ def renew_account_until(account_descr, expiration_time, authorizer)
156
+ account = find_active_account(account_descr, authorizer)
157
+ authorizer.can_renew_account?(account, expiration_time)
158
+ account.valid_until = expiration_time
159
+ account.save
160
+ account
161
+ end
162
+
163
+ # Close the account described by +account+ hash.
164
+ #
165
+ # Make sure that all associated resources are freed as well
166
+ #
167
+ # @param [Hash] properties of account
168
+ # @param [Authorizer] Defines context for authorization decisions
169
+ # @return [OAccount] The closed account
170
+ # @raise [UnknownResourceException] if requested account cannot be found
171
+ # @raise [UnavailableResourceException] if requested account is closed
172
+ # @raise [InsufficientPrivilegesException] if permission is not granted
173
+ #
174
+ def close_account(account_descr, authorizer)
175
+ account = find_account(account_descr, authorizer)
176
+ authorizer.can_close_account?(account)
177
+ # TODO: Free all resources associated with this account!!!!
178
+ # OMF::SFA::Resource::OComponent.all(:account => account).each do |c|
179
+ # c.account = def_account
180
+ # c.save
181
+ # end
182
+ account.close
183
+ account.save
184
+ account
185
+ end
186
+
187
+ ### USERS
188
+
189
+ # Return the user described by +user_descr+. Create if it doesn't exist.
190
+ #
191
+ # Note: This is an unprivileged operation as creating a user doesn't imply anything
192
+ # else beyond opening a record.
193
+ #
194
+ # @param [Hash] properties of user
195
+ # @return [User] The requested user
196
+ # @raise [UnknownResourceException] if requested user cannot be created
197
+ #
198
+ def find_or_create_user(user_descr)
199
+ debug "find_or_create_user: '#{user_descr.inspect}'"
200
+ begin
201
+ return find_user(user_descr)
202
+ rescue UnavailableResourceException
203
+ end
204
+ user = OMF::SFA::Resource::User.create(user_descr)
205
+ raise UnavailableResourceException.new "Cannot create '#{user_descr.inspect}'" unless user
206
+ user
207
+ end
208
+
209
+ # Return the user described by +user_descr+.
210
+ #
211
+ # Note: This is an unprivileged operation as creating a user doesn't imply anything
212
+ # else beyond opening a record.
213
+ #
214
+ # @param [Hash] properties of user
215
+ # @return [User] The requested user
216
+ # @raise [UnknownResourceException] if requested user cannot be found
217
+ #
218
+ def find_user(user_descr)
219
+ unless user = OMF::SFA::Resource::User.first(user_descr)
220
+ raise UnavailableResourceException.new "Unknown user '#{user_descr.inspect}'"
221
+ end
222
+ user
223
+ end
224
+
225
+ ### LEASES: creating, finding, and releasing leases
226
+
227
+ # Return the lease described by +lease_descr+. Create if it doesn't exist.
228
+ #
229
+ # @param [Hash] lease_descr properties of lease
230
+ # @param [Hash] lease oproperties like ":valid_from" and ":valid_until"
231
+ # @param [Authorizer] Defines context for authorization decisions
232
+ # @return [OLease] The requested lease
233
+ # @raise [UnknownResourceException] if requested lease cannot be created
234
+ # @raise [InsufficientPrivilegesException] if permission is not granted
235
+ #
236
+ def find_or_create_lease(lease_descr, lease_oproperties, authorizer)
237
+ debug "find_or_create_lease: '#{lease_descr.inspect}', '#{lease_oproperties.inspect}'"
238
+ begin
239
+ return find_lease(lease_descr, lease_oproperties, authorizer)
240
+ rescue UnavailableResourceException
241
+ end
242
+ unless lease_oproperties.has_key?(:valid_from) && lease_oproperties.has_key?(:valid_until)
243
+ raise UnavailablePropertiesException.new "Cannot create lease without ':valid_from' and 'valid_until' oproperties #{lease_oproperties.inspect}"
244
+ end
245
+ lease = create_resource(lease_descr, 'OLease', lease_oproperties, authorizer)
246
+ end
247
+
248
+ # Return the lease described by +lease_descr+.
249
+ #
250
+ # @param [Hash] properties of lease
251
+ # @param [Hash] lease oproperties like ":valid_from" and ":valid_until"
252
+ # @param [Authorizer] Defines context for authorization decisions
253
+ # @return [OLease] The requested lease
254
+ # @raise [UnknownResourceException] if requested lease cannot be found
255
+ # @raise [InsufficientPrivilegesException] if permission is not granted
256
+ #
257
+ def find_lease(lease_descr, lease_oproperties, authorizer)
258
+ if lease_oproperties.empty?
259
+ lease = OMF::SFA::Resource::OLease.first(lease_descr)
260
+ raise UnavailableResourceException.new "Unknown lease '#{lease_descr.inspect}'" if lease.nil?
261
+ authorizer.can_view_lease?(lease)
262
+ return lease
263
+ end
264
+ leases = OMF::SFA::Resource::OLease.all(lease_descr)
265
+ leases.each do |l|
266
+ if (l[:valid_from] == lease_oproperties[:valid_from] &&
267
+ l[:valid_until] == lease_oproperties[:valid_until])
268
+ authorizer.can_view_lease?(l)
269
+ return l
270
+ end
271
+ end
272
+ raise UnavailableResourceException.new "Unknown lease '#{lease_descr.inspect}'"
273
+ end
274
+
275
+ # Return all leases of the specified account
276
+ #
277
+ # @param [OAccount] Account for which to find all associated leases
278
+ # @param [Authorizer] Defines context for authorization decisions
279
+ # @return [Array<OLease>] The account's leases (maybe empty)
280
+ #
281
+ def find_all_leases_for_account(account, authorizer)
282
+ debug "find_all_leases_for_account: account:'#{account.inspect}' authorizer:'#{authorizer.inspect}'"
283
+ leases = OMF::SFA::Resource::OLease.all(:account => account)
284
+ leases.map do |l|
285
+ begin
286
+ authorizer.can_view_lease?(l)
287
+ l
288
+ rescue InsufficientPrivilegesException
289
+ nil
290
+ end
291
+ end.compact
292
+ end
293
+
294
+ def find_all_leases(authorizer)
295
+ leases = OMF::SFA::Resource::OLease.all
296
+ leases.map do |l|
297
+ begin
298
+ authorizer.can_view_lease?(l)
299
+ l
300
+ rescue InsufficientPrivilegesException
301
+ nil
302
+ end
303
+ end.compact
304
+ end
305
+
306
+ # Modify lease described by +lease_descr+ hash
307
+ #
308
+ # @param [Hash] lease oproperties like ":valid_from" and ":valid_until"
309
+ # @param [OLease] lease to modify
310
+ # @param [Authorizer] Authorization context
311
+ # @return [OLease] The requested lease
312
+ #
313
+ def modify_lease(lease_oproperties, lease, authorizer)
314
+ authorizer.can_modify_lease?(lease)
315
+ lease.valid_from = lease_oproperties[:valid_from]
316
+ lease.valid_until = lease_oproperties[:valid_until]
317
+ lease.save
318
+ lease
319
+ end
320
+
321
+ # cancel +lease+
322
+ #
323
+ # This implementation simply frees the lease record.
324
+ #
325
+ # @param [OLease] lease to release
326
+ # @param [Authorizer] Authorization context
327
+ #
328
+ def release_lease(lease, authorizer)
329
+ debug "release_lease: lease:'#{lease.inspect}' authorizer:'#{authorizer.inspect}'"
330
+ authorizer.can_release_lease?(lease)
331
+
332
+ lease.component_leases.each do |l|
333
+ l.destroy # unlink the lease with the corresponding components
334
+ end
335
+ lease.status = :cancelled
336
+ end
337
+
338
+ #
339
+ # Create or Modify leases through RSpecs
340
+ #
341
+ # When a uuid is provided, then the corresponding lease is modified. Otherwise a new
342
+ # lease is created with the properties described in the RSpecs.
343
+ #
344
+ # @param [Nokogiri::XML::Node] RSpec fragment describing lease and its properties
345
+ # @param [Authorizer] Defines context for authorization decisions
346
+ # @return [OLease] The requested lease
347
+ # @raise [UnavailableResourceException] if no matching resource can be found or created
348
+ # @raise [FormatException] if RSpec elements are not known
349
+ #
350
+ def update_lease_from_rspec(lease_el, authorizer)
351
+
352
+ lease_properties = {:valid_from => Time.parse(lease_el[:valid_from]), :valid_until => Time.parse(lease_el[:valid_until])}
353
+
354
+ begin
355
+ raise UnavailableResourceException unless UUID.validate(lease_el[:id])
356
+ lease = find_lease({:uuid => lease_el[:id]}, {}, authorizer)
357
+ if lease.valid_from != lease_properties[:valid_from] || lease.valid_until != lease_properties[:valid_until]
358
+ lease = modify_lease(lease_properties, lease, authorizer)
359
+ return { lease_el[:id] => lease }
360
+ else
361
+ return { lease_el[:id] => lease }
362
+ end
363
+ rescue UnavailableResourceException
364
+ lease_descr = {:name => authorizer.account.name}
365
+ lease = find_or_create_lease(lease_descr, lease_properties, authorizer)
366
+ return { lease_el[:id] => lease }
367
+ end
368
+
369
+ #unless lease_el[:uuid].nil?
370
+ # lease = find_lease({:uuid => lease_el[:uuid]}, {}, authorizer)
371
+ # raise UnavailableResourceException.new "Unknown lease uuid'#{lease_el[:uuid]}'" unless lease
372
+ # if lease.valid_from != lease_properties[:valid_from] || lease.valid_until != lease_properties[:valid_until]
373
+ # lease = modify_lease(lease_properties, lease, authorizer)
374
+ # { lease_el[:leaseID] => lease }
375
+ # else
376
+ # { lease_el[:leaseID] => lease }
377
+ # end
378
+ #else
379
+ # lease_descr = {:name => authorizer.account.name}
380
+ # lease = find_or_create_lease(lease_descr, lease_properties, authorizer)
381
+ # { lease_el[:leaseID] => lease }
382
+ #end
383
+ end
384
+
385
+ # Update the leases described in +leases+. Any lease not already assigned to the
386
+ # requesting account will be added. If +clean_state+ is true, the state of all described leases
387
+ # is set to the state described with all other properties set to their default values. Any leases
388
+ # not mentioned are canceled. Returns the list
389
+ # of leases requested or throw an error if ANY of the requested leases isn't available.
390
+ #
391
+ # @param [Element] RSpec fragment describing leases and their properties
392
+ # @param [Authorizer] Defines context for authorization decisions
393
+ # @return [Hash{String => OLease}] The leases requested
394
+ # @raise [UnknownResourceException] if no matching lease can be found
395
+ # @raise [FormatException] if RSpec elements are not known
396
+ #
397
+ def update_leases_from_rspec(leases, authorizer)
398
+ debug "update_leases_from_rspec: leases:'#{leases.inspect}' authorizer:'#{authorizer.inspect}'"
399
+ leases_hash = {}
400
+ unless leases.empty?
401
+ leases.each do |lease|
402
+ l = update_lease_from_rspec(lease, authorizer)
403
+ leases_hash.merge!(l)
404
+ end
405
+ end
406
+ leases_hash
407
+ end
408
+
409
+
410
+ ### RESOURCES creating, finding, and releasing resources
411
+
412
+
413
+ # Find a resource. If it doesn't exist throws +UnknownResourceException+
414
+ # If it's not visible to requester throws +InsufficientPrivilegesException+
415
+ #
416
+ # @param [Hash, String, OResource] describing properties of the requested resource, or the
417
+ # resource's UUID
418
+ # @param [Boolean] If true, throw exception if not already assigned to requester
419
+ # @param [Authorizer] Defines context for authorization decisions
420
+ # @return [OResource] The resource requested
421
+ # @raise [UnknownResourceException] if no matching resource can be found
422
+ # @raise [FormatException] if the resource description is not String, UUID or OResource class/subclass
423
+ # @raise [InsufficientPrivilegesException] if the resource is not visible to the requester
424
+ #
425
+ # @note This will assign the resource automatically to the requesting account
426
+ #
427
+ def find_resource(resource_descr, authorizer)
428
+ debug "find_resource: descr: '#{resource_descr.inspect}'"
429
+ if resource_descr.kind_of? OMF::SFA::Resource::OResource
430
+ resource = resource_descr
431
+ elsif resource_descr.kind_of? Hash
432
+ resource = OMF::SFA::Resource::OResource.first(resource_descr)
433
+ elsif resource_descr.kind_of? String
434
+ # assume to be UUID
435
+ begin
436
+ uuid = UUIDTools::UUID.parse(resource_descr)
437
+ descr = {:uuid => uuid}
438
+ rescue ArgumentError
439
+ # doesn't seem to be a UUID, try it as a name - be aware of non-uniqueness
440
+ descr = {:name => resource_descr}
441
+ end
442
+ resource = OMF::SFA::Resource::OResource.first(descr)
443
+ else
444
+ raise FormatException.new "Unknown resource description type '#{resource_descr.class}' (#{resource_descr})"
445
+ end
446
+ unless resource
447
+ raise UnknownResourceException.new "Resource '#{resource_descr.inspect}' is not available or doesn't exist"
448
+ end
449
+ authorizer.can_view_resource?(resource)
450
+ resource
451
+ end
452
+
453
+ # Find a resource which has been assigned to the authorizer's account.
454
+ # If it doesn't exist, or is not visible to requester
455
+ # throws +UnknownResourceException+.
456
+ #
457
+ # @param [Hash, String] describing properties of the requested resource, or the
458
+ # resource's UUID
459
+ # @param [Authorizer] Defines context for authorization decisions
460
+ # @return [OResource] The resource requested
461
+ # @raise [UnknownResourceException] if no matching resource can be found
462
+ #
463
+ # @note This will assign the resource automatically to the requesting account
464
+ #
465
+ def find_resource_for_account(resource_descr, authorizer)
466
+ rdescr = resource_descr.dup
467
+ rdescr[:account] = authorizer.account
468
+ find_resource(rdescr, authorizer)
469
+ end
470
+
471
+
472
+ # Find all resources for a specific account.
473
+ #
474
+ # @param [OAccount] Account for which to find all associated resources
475
+ # @param [Authorizer] Defines context for authorization decisions
476
+ # @return [Array<OResource>] The resource requested
477
+ #
478
+ def find_all_resources_for_account(account = _get_nil_account, authorizer)
479
+ debug "find_all_resources_for_account: #{account.inspect}"
480
+ res = OMF::SFA::Resource::OResource.all(:account => account)
481
+ res.map do |r|
482
+ begin
483
+ authorizer.can_view_resource?(r)
484
+ r
485
+ rescue InsufficientPrivilegesException
486
+ nil
487
+ end
488
+ end.compact
489
+ end
490
+
491
+ # Find all components for a specific account.
492
+ #
493
+ # @param [OAccount] Account for which to find all associated component
494
+ # @param [Authorizer] Defines context for authorization decisions
495
+ # @return [Array<OComponent>] The component requested
496
+ #
497
+ def find_all_components_for_account(account, authorizer)
498
+ res = OMF::SFA::Resource::OComponent.all(:account => account)
499
+ res.map do |r|
500
+ begin
501
+ authorizer.can_view_resource?(r)
502
+ r
503
+ rescue InsufficientPrivilegesException
504
+ nil
505
+ end
506
+ end.compact
507
+ end
508
+
509
+ # Find all components
510
+ #
511
+ # @return [Array<OComponent>] The components requested
512
+ #
513
+ #def find_all_components
514
+ # res = OMF::SFA::Resource::OComponent.all
515
+ # res
516
+ #end
517
+
518
+ def find_or_create_resource(resource_descr, type_to_create, oproperties, authorizer)
519
+ debug "find_or_create_resource: resource '#{resource_descr.inspect}' type: '#{type_to_create}'"
520
+ unless resource_descr.is_a? Hash
521
+ raise FormatException.new "Unknown resource description '#{resource_descr.inspect}'"
522
+ end
523
+
524
+ begin
525
+ return find_resource(resource_descr, authorizer)
526
+ rescue UnknownResourceException
527
+ end
528
+ create_resource(resource_descr, type_to_create, oproperties, authorizer)
529
+ end
530
+
531
+ # Create a resource
532
+ #
533
+ # @param [Hash] Describing properties of the requested resource
534
+ # @param [String] Type to create
535
+ # @param [Hash] A hash with all the OProperty values of the requested resource
536
+ # @param [Authorizer] Defines context for authorization decisions
537
+ # @return [OResource] The resource requested
538
+ # @raise [UnknownResourceException] if no resource can be created
539
+ #
540
+ def create_resource(resource_descr, type_to_create, oproperties, authorizer)
541
+ authorizer.can_create_resource?(resource_descr, type_to_create)
542
+ unless resource = @scheduler.create_resource(resource_descr, type_to_create, oproperties, authorizer)
543
+ raise UnknownResourceException.new "Resource '#{resource_descr.inspect}' cannot be created"
544
+ end
545
+ resource
546
+ end
547
+
548
+ # Find or create a resource for authorizer's account. If it doesn't exist,
549
+ # is already assigned to
550
+ # someone else, or cannot be created, throws +UnknownResourceException+.
551
+ #
552
+ # @param [Hash] describing properties of the requested resource
553
+ # @param [String] Type to create if not already exist
554
+ # @param [Hash] A hash with all the OProperty values of the requested resource
555
+ # @param [Authorizer] Defines context for authorization decisions
556
+ # @return [OResource] The resource requested
557
+ # @raise [UnknownResourceException] if no matching resource can be found
558
+ #
559
+ def find_or_create_resource_for_account(resource_descr, type_to_create, oproperties, authorizer)
560
+ debug "find_or_create_resource_for_account: r_descr:'#{resource_descr}' type:'#{type_to_create}' authorizer:'#{authorizer.inspect}'"
561
+ rdescr = resource_descr.dup
562
+ rdescr[:account] = authorizer.account
563
+ find_or_create_resource(rdescr, type_to_create, oproperties, authorizer)
564
+ end
565
+
566
+ # def _create_resource(resource_descr, type_to_create, authorizer)
567
+ # # OK, let's check if a group was requested. They are cheap to make
568
+ # #
569
+ # # if type_to_create == 'group'
570
+ # # copts = resource_descr.kind_of?(Hash) ? resource_descr : {}
571
+ # # copts[:account] ||= authorizer.account
572
+ # # debug "_create_resource:create group: description '#{copts.keys.inspect}'"
573
+ # # return create_group_resource(copts)
574
+ # # end
575
+ #
576
+ # # Let's see if this is a basic resource in which case we create a copy
577
+ # #
578
+ # # begin
579
+ # # #resource_descr[:account] = _get_nil_account()
580
+ # # #r = find_resource(resource_descr, false, authorizer)
581
+ # # return @scheduler.create_resource(resource_descr, authorizer)
582
+ # # rescue UnknownResourceException
583
+ # # end
584
+ # unless @scheduler.create_resource(resource_descr, type_to_create, authorizer)
585
+ # raise UnknownResourceException.new "Resource '#{resource_descr.inspect}' cannot be created"
586
+ # end
587
+ # end
588
+
589
+
590
+ # Update the resources described in +resource_el+. Any resource not already assigned to the
591
+ # requesting account will be added. If +clean_state+ is true, the state of all described resources
592
+ # is set to the state described with all other properties set to their default values. Any resources
593
+ # not mentioned are released. Returns the list
594
+ # of resources requested or throw an error if ANY of the requested resources isn't available.
595
+ #
596
+ # Find or create a resource. If it doesn't exist, is already assigned to
597
+ # someone else, or cannot be created, throws +UnknownResourceException+.
598
+ #
599
+ # @param [Element] RSpec fragment describing resource and their properties
600
+ # @param [Boolean] Set all properties not mentioned to their defaults
601
+ # @param [Authorizer] Defines context for authorization decisions
602
+ # @return [OResource] The resource requested
603
+ # @raise [UnknownResourceException] if no matching resource can be found
604
+ # @raise [FormatException] if RSpec elements are not known
605
+ #
606
+ # @note Throws exception if a contained resource doesn't exist, but will not roll back any
607
+ # already performed modifications performed on other resources.
608
+ #
609
+ def update_resources_from_rspec(descr_el, clean_state, authorizer)
610
+ debug "update_resources_from_rspec: descr_el:'#{descr_el}' clean_state:'#{clean_state}' authorizer:'#{authorizer}'"
611
+ if !descr_el.nil? && descr_el.name.downcase == 'rspec'
612
+ xsd_path = File.join(File.dirname(__FILE__), '../../../schema/rspec-v3', 'request.xsd')
613
+ schema = Nokogiri::XML::Schema(File.open(xsd_path))
614
+
615
+ res = schema.validate(descr_el.document)
616
+ raise FormatException.new("RSpec format is not valid: '#{res}'") unless res.empty?
617
+
618
+ unless descr_el.xpath('//ol:*', 'ol' => OL_NAMESPACE).empty?
619
+ #TODO: make proper schemas and validate them
620
+ #lease_xsd_path = File.join(File.dirname(__FILE__), '../../../schema/rspec-v3', 'request-reservation.xsd')
621
+ #lease_rng_path = File.join(File.dirname(__FILE__), '../../../schema/rspec-v3', 'request-reservation.rng')
622
+ #lease_schema = Nokogiri::XML::Schema(File.open(lease_xsd_path))
623
+ #lease_schema = Nokogiri::XML::RelaxNG(File.open(lease_rng_path))
624
+
625
+ #res = lease_schema.validate(descr_el.document)
626
+ #raise FormatException.new("RSpec format is not valid: '#{res}'") unless res.empty?
627
+ end
628
+
629
+
630
+ if descr_el.namespaces.values.include?(OL_NAMESPACE)
631
+ #leases = descr_el.xpath('/rspec//ol:lease', 'ol' => OL_NAMESPACE)
632
+ leases = descr_el.xpath('/xmlns:rspec/ol:lease', 'ol' => OL_NAMESPACE, 'xmlns' => "http://www.geni.net/resources/rspec/3")
633
+ leases = update_leases_from_rspec(leases, authorizer)
634
+ end
635
+
636
+
637
+ resources = descr_el.xpath('//xmlns:node').collect do |el|
638
+ #debug "create_resources_from_xml::EL: #{el.inspect}"
639
+ if el.kind_of?(Nokogiri::XML::Element)
640
+ # ignore any text elements
641
+ #if el[:lease_name].nil?
642
+ # update_resource_from_rspec(el, nil, clean_state, authorizer)
643
+ #else # This node has a lease
644
+ # lease = leases.find { |l| l[:name].eql?(el[:lease_name]) }
645
+ #leases = el.xpath('child::ol:lease', 'ol' => OL_NAMESPACE)
646
+ #leases = update_leases_from_rspec(leases, authorizer)
647
+ update_resource_from_rspec(el, leases, clean_state, authorizer)
648
+ #end
649
+ end
650
+ end.compact
651
+
652
+ # channel reservation
653
+ #resources = descr_el.xpath('/xmlns:rspec/ol:channel', 'ol' => OL_NAMESPACE, 'xmlns' => "http://www.geni.net/resources/rspec/3").collect do |el|
654
+ # update_resource_from_rspec(el, leases, clean_state, authorizer)
655
+ #end.compact
656
+
657
+ # TODO: release the unused leases. The leases we have created but we never managed
658
+ # to attach them to a resource because the scheduler denied it.
659
+ if clean_state
660
+ # Now free any leases owned by this account but not contained in +leases+
661
+ all_leases = Set.new
662
+ #leases = descr_el.xpath('//ol:lease', 'ol' => OL_NAMESPACE).collect do |l|
663
+ # update_leases_from_rspec(leases, authorizer)
664
+ #end.compact
665
+
666
+ leases.each {|l| l.all_resources(all_leases)}
667
+ unused = find_all_leases_for_account(authorizer.account, authorizer).to_set - all_leases
668
+ unused.each do |u|
669
+ release_lease(u, authorizer)
670
+ end
671
+ # Now free any resources owned by this account but not contained in +resources+
672
+ rspec_resources = Set.new
673
+ resources.each {|r| r.all_resources(rspec_resources)}
674
+ all_components = find_all_components_for_account(authorizer.account, authorizer)
675
+ unused = all_components.to_set - rspec_resources
676
+ release_resources(unused, authorizer)
677
+ end
678
+ return resources
679
+ else
680
+ raise FormatException.new "Unknown resources description root '#{descr_el}'"
681
+ end
682
+ end
683
+
684
+ # Update a single resource described in +resource_el+. The respective account is
685
+ # extracted from +opts+. Any mentioned resources not already available to the requesting account
686
+ # will be created. If +clean_state+ is set to true, all state of a resource not specifically described
687
+ # will be reset to it's default value. Returns the resource updated.
688
+ #
689
+ def update_resource_from_rspec(resource_el, leases, clean_state, authorizer)
690
+ if uuid_attr = (resource_el.attributes['uuid'] || resource_el.attributes['idref'])
691
+ uuid = UUIDTools::UUID.parse(uuid_attr.value)
692
+ resource = find_resource({:uuid => uuid}, authorizer) # wouldn't know what to create
693
+ elsif comp_id_attr = resource_el.attributes['component_id']
694
+ comp_id = comp_id_attr.value
695
+ comp_gurn = OMF::SFA::Resource::GURN.parse(comp_id)
696
+ #if uuid = comp_gurn.uuid
697
+ # resource_descr = {:uuid => uuid}
698
+ #else
699
+ # resource_descr = {:name => comp_gurn.short_name}
700
+ #end
701
+ resource_descr = {:urn => comp_gurn}
702
+ resource = find_or_create_resource_for_account(resource_descr, comp_gurn.type, {}, authorizer)
703
+ unless resource
704
+ raise UnknownResourceException.new "Resource '#{resource_el.to_s}' is not available or doesn't exist"
705
+ end
706
+ elsif name_attr = resource_el.attributes['component_name']
707
+ # the only resource we can find by a name attribute is a group
708
+ # TODO: Not sure about the 'group' assumption
709
+ name = name_attr.value
710
+ resource = find_or_create_resource_for_account({:name => name}, 'unknown', {}, authorizer)
711
+ else
712
+ raise FormatException.new "Unknown resource description '#{resource_el.attributes.inspect}"
713
+ end
714
+
715
+ leases_el = resource_el.xpath('child::ol:lease_ref', 'ol' => OL_NAMESPACE)
716
+ leases_el.each do |lease_el|
717
+ #TODO: provide the scheduler with the resource and the lease to attach them according to its policy.
718
+ # if the scheduler refuses to attach the lease to the resource, we should release both of them.
719
+ lease_id = lease_el['id_ref']
720
+ lease = leases[lease_id]
721
+ @scheduler.lease_component(lease, resource)
722
+ end
723
+
724
+ if resource.group?
725
+ members = resource_el.children.collect do |el|
726
+ if el.kind_of?(Nokogiri::XML::Element)
727
+ # ignore any text elements
728
+ update_resource_from_rspec(el, clean_state, authorizer)
729
+ end
730
+ end.compact
731
+ debug "update_resource_from_rspec: Creating members '#{members}' for group '#{resource}'"
732
+
733
+ if clean_state
734
+ resource.members = members
735
+ else
736
+ resource.add_members(members)
737
+ end
738
+ else
739
+ if clean_state
740
+ # Set state to what's described in +resource_el+ ONLY
741
+ resource.create_from_xml(resource_el, authorizer)
742
+ else
743
+ resource.update_from_xml(resource_el, authorizer)
744
+ end
745
+ end
746
+ resource.save
747
+ resource
748
+ end
749
+
750
+ # Release an array of resources.
751
+ #
752
+ # @param [Array<OResource>] Resources to release
753
+ # @param [Authorizer] Authorization context
754
+ def release_resources(resources, authorizer)
755
+ resources.each do |r|
756
+ release_resource(r, authorizer)
757
+ end
758
+ end
759
+
760
+ # Release 'resource'.
761
+ #
762
+ # This implementation simply frees the resource record.
763
+ #
764
+ # @param [OResource] Resource to release
765
+ # @param [Authorizer] Authorization context
766
+ #
767
+ def release_resource(resource, authorizer)
768
+ authorizer.can_release_resource?(resource)
769
+ @scheduler.release_resource(resource, authorizer)
770
+ #resource.remove_from_all_groups
771
+
772
+ # if r.kind_of? OMF::SFA::Resource::CompGroup
773
+ # # groups don't go back in the pool, they are created per account
774
+ # r.destroy
775
+ # else
776
+ # r.account = def_account
777
+ # r.save
778
+ # end
779
+ #resource.destroy
780
+ end
781
+
782
+ #
783
+ # This method finds all the components of the specific account and
784
+ # detaches them.
785
+ #
786
+ # @param [OAccount] Account who owns the components
787
+ # @param [Authorizer] Authorization context
788
+ #
789
+ def release_all_components_for_account(account, authorizer)
790
+ components = find_all_components_for_account(account, authorizer)
791
+ release_resources(components, authorizer)
792
+ end
793
+
794
+
795
+ # This methods deletes components, or more broadly defined, removes them
796
+ # from a slice.
797
+ #
798
+ # Currently, we simply transfer components to the +default_sliver+
799
+ #
800
+ # def delete_resource(resource_descr, authorizer)
801
+ # resource = find_resource(resource_descr, false, authorizer)
802
+ # if resource.kind_of? OMF::SFA::Resource::OComponent
803
+ # resource.account = _get_nil_account
804
+ # resource.remove_from_all_groups
805
+ # resource.save
806
+ # else
807
+ # resource.destroy
808
+ # end
809
+ # end
810
+
811
+ # This methods deletes components, or more broadly defined, removes them
812
+ # from a slice.
813
+ #
814
+ # Currently, we simply transfer components to the +default_sliver+
815
+ #
816
+ # def delete_resource(resource_descr, opts)
817
+ # resource = find_resource(resource_descr, false, opts)
818
+ # if resource.kind_of? OMF::SFA::Resource::OComponent
819
+ # resource.account = _get_nil_account
820
+ # resource.remove_from_all_groups
821
+ # resource.save
822
+ # else
823
+ # resource.destroy
824
+ # end
825
+ # end
826
+
827
+ # Return the account identified by 'uuid'.
828
+ #
829
+ # @param [String, UUID] UUID of account
830
+ # @return [OAccount]
831
+ #
832
+ # def get_account(uuid, authorizer)
833
+ # unless account = OAccount.first(:uuid => uuid)
834
+ # raise UnknownAccountException.new "Unknown account with uuid '#{uuid}'"
835
+ # end
836
+ # if account.closed?
837
+ # raise ClosedAccountException.new
838
+ # end
839
+ # end
840
+
841
+ # Return a list of resources for a particular +account+. If
842
+ # +account+ is null, return all the resources available at this
843
+ # AM.
844
+ #
845
+ # @param [OAccount] Account for which to find resources
846
+ # @param [Authorizer] Authoization context
847
+ #
848
+ #def get_resources_for_account(account, authorizer)
849
+ # OMF::SFA::Resource::OComponent.all(:account => account)
850
+ #end
851
+
852
+
853
+ def _get_nil_account()
854
+ @scheduler.get_nil_account()
855
+ end
856
+
857
+ end # class
858
+
859
+ end # OMF::SFA::AM