omf_sfa 0.1.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.
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