2 File providing methods to generate valid RSpecs for the Iotlab testbed.
3 Contains methods to get information on slice, slivers, nodes and leases,
4 formatting them and turn it into a RSpec.
6 from sfa.util.xrn import hrn_to_urn, urn_to_hrn
7 from sfa.util.sfatime import utcparse, datetime_to_string
9 from sfa.iotlab.iotlabxrn import IotlabXrn, xrn_object
10 from sfa.rspecs.rspec import RSpec
12 #from sfa.rspecs.elements.location import Location
13 from sfa.rspecs.elements.hardware_type import HardwareType
14 from sfa.rspecs.elements.node import NodeElement
15 from sfa.rspecs.elements.login import Login
16 from sfa.rspecs.elements.sliver import Sliver
17 from sfa.rspecs.elements.lease import Lease
18 from sfa.rspecs.elements.granularity import Granularity
19 from sfa.rspecs.version_manager import VersionManager
20 from sfa.storage.model import SliverAllocation
21 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition, \
24 from sfa.util.sfalogging import logger
25 from sfa.util.xrn import Xrn
29 class CortexlabAggregate:
30 """Aggregate manager class for cortexlab. """
43 def __init__(self, driver):
46 def get_slice_and_slivers(self, slice_xrn, login=None):
48 Get the slices and the associated leases if any, from the cortexlab
49 testbed. One slice can have mutliple leases.
50 For each slice, get the nodes in the associated lease
51 and create a sliver with the necessary info and insert it into the
52 sliver dictionary, keyed on the node hostnames.
53 Returns a dict of slivers based on the sliver's node_id.
57 :param slice_xrn: xrn of the slice
58 :param login: user's login on cortexlab ldap
60 :type slice_xrn: string
62 :returns: a list of slices dict and a list of Sliver object
65 .. note: There is no real slivers in cortexlab, only leases. The goal
66 is to be consistent with the SFA standard.
74 return (sfa_slice, slivers)
75 slice_urn = hrn_to_urn(slice_xrn, 'slice')
76 slice_hrn, _ = urn_to_hrn(slice_xrn)
78 # GetSlices always returns a list, even if there is only one element
79 slices = self.driver.GetSlices(slice_filter=str(slice_hrn),
80 slice_filter_type='slice_hrn',
83 logger.debug("CortexlabAggregate api \tget_slice_and_slivers \
84 slice_hrn %s \r\n slices %s self.driver.hrn %s"
85 % (slice_hrn, slices, self.driver.hrn))
87 return (sfa_slice, slivers)
89 # sort slivers by node id , if there is a job
90 #and therefore, node allocated to this slice
91 # for sfa_slice in slices:
94 node_ids_list = sfa_slice['node_ids']
96 logger.log_exc("CORTEXLABAGGREGATE \t \
97 get_slice_and_slivers No nodes in the slice \
102 for node in node_ids_list:
103 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
104 sliver_xrn.set_authority(self.driver.hrn)
105 sliver = Sliver({'sliver_id': sliver_xrn.urn,
106 'name': sfa_slice['hrn'],
107 'type': 'cortexlab-node',
110 slivers[node] = sliver
112 #Add default sliver attribute :
113 #connection information for cortexlab, assuming it is the same ssh
116 ldap_username = self.find_ldap_username_from_slice(sfa_slice)
118 if ldap_username is not None:
120 slivers['default_sliver'] = {'ssh': ssh_access,
121 'login': ldap_username}
124 logger.debug("CORTEXLABAGGREGATE api get_slice_and_slivers slivers %s "
126 return (slices, slivers)
129 def find_ldap_username_from_slice(self, sfa_slice):
131 Gets the ldap username of the user based on the information contained
132 in ist sfa_slice record.
134 :param sfa_slice: the user's slice record. Must contain the
136 :type sfa_slice: dictionary
137 :returns: ldap_username, the ldap user's login.
141 researchers = [sfa_slice['reg_researchers'][0].__dict__]
144 ret = self.driver.testbed_shell.GetPersons(researchers)
146 ldap_username = ret[0]['uid']
152 def get_nodes(self, options=None):
153 """Returns the nodes in the slice using the rspec format, with all the
156 Fetch the nodes ids in the slices dictionary and get all the nodes
157 properties from OAR. Makes a rspec dicitonary out of this and returns
158 it. If the slice does not have any job running or scheduled, that is
159 it has no reserved nodes, then returns an empty list.
161 :returns: An empty list if the slice has no reserved nodes, a rspec
162 list with all the nodes and their properties (a dict per node)
166 .. seealso:: get_slice_and_slivers
171 geni_available = options.get('geni_available')
172 if geni_available == True:
173 filter_nodes['boot_state'] = ['Alive']
175 # slice_nodes_list = []
176 # if slices is not None:
177 # for one_slice in slices:
179 # slice_nodes_list = one_slice['node_ids']
180 # # if we are dealing with a slice that has no node just
181 # # return an empty list. In iotlab a slice can have multiple
182 # # jobs scheduled, so it either has at least one lease or
187 # get the granularity in second for the reservation system
188 # grain = self.driver.testbed_shell.GetLeaseGranularity()
190 nodes = self.driver.testbed_shell.GetNodes(node_filter_dict =
195 #if slices, this means we got to list all the nodes given to this slice
196 # Make a list of all the nodes in the slice before getting their
200 nodes_dict[node['node_id']] = node
205 def node_to_rspec_node(self, node):
206 """ Creates a rspec node structure with the appropriate information
207 based on the node information that can be found in the node dictionary.
209 :param node: node data. this dict contains information about the node
210 and must have the following keys : mobile, radio, archi, hostname,
211 boot_state, site, x, y ,z (position).
212 :type node: dictionary.
214 :returns: node dictionary containing the following keys : mobile, archi,
215 radio, component_id, component_name, component_manager_id,
216 authority_id, boot_state, exclusive, hardware_types, location,
217 position, granularity, tags.
222 grain = self.driver.testbed_shell.GetLeaseGranularity()
223 rspec_node = NodeElement()
225 # xxx how to retrieve site['login_base']
226 #site_id=node['site_id']
227 #site=sites_dict[site_id]
229 rspec_node['mobile'] = node['mobile']
230 rspec_node['archi'] = node['archi']
231 rspec_node['radio'] = node['radio']
232 cortexlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
235 rspec_node['component_id'] = cortexlab_xrn.urn
236 rspec_node['component_name'] = node['hostname']
237 rspec_node['component_manager_id'] = \
238 hrn_to_urn(self.driver.testbed_shell.root_auth,
241 # Iotlab's nodes are federated : there is only one authority
242 # for all Iotlab sites, registered in SFA.
243 # Removing the part including the site
244 # in authority_id SA 27/07/12
245 rspec_node['authority_id'] = rspec_node['component_manager_id']
247 # do not include boot state (<available> element)
248 #in the manifest rspec
251 rspec_node['boot_state'] = node['boot_state']
252 # if node['hostname'] in reserved_nodes:
253 # rspec_node['boot_state'] = "Reserved"
254 rspec_node['exclusive'] = 'true'
255 rspec_node['hardware_types'] = [HardwareType({'name': \
258 location = IotlabLocation({'country':'France', 'site': \
260 rspec_node['location'] = location
263 position = IotlabPosition()
264 for field in position :
266 position[field] = node[field]
267 except KeyError, error :
268 logger.log_exc("Cortexlabaggregate\t node_to_rspec_node \
269 position %s "% (error))
271 rspec_node['position'] = position
275 granularity = Granularity({'grain': grain})
276 rspec_node['granularity'] = granularity
277 rspec_node['tags'] = []
278 # if node['hostname'] in slivers:
280 # sliver = slivers[node['hostname']]
281 # rspec_node['sliver_id'] = sliver['sliver_id']
282 # rspec_node['client_id'] = node['hostname']
283 # rspec_node['slivers'] = [sliver]
285 # # slivers always provide the ssh service
286 # login = Login({'authentication': 'ssh-keys', \
287 # 'hostname': node['hostname'], 'port':'22', \
288 # 'username': sliver['name']})
289 # service = Services({'login': login})
290 # rspec_node['services'] = [service]
295 def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations=None):
296 """Makes a geni sliver structure from all the nodes allocated
297 to slivers in the sliver_allocations dictionary. Returns the states
300 :param rspec_node: Node information contained in a rspec data structure
302 :type rspec_node: dictionary
303 :param sliver_allocations:
304 :type sliver_allocations: dictionary
306 :returns: Dictionary with the following keys: geni_sliver_urn,
307 geni_expires, geni_allocation_status, geni_operational_status,
312 .. seealso:: node_to_rspec_node
315 if sliver_allocations is None: sliver_allocations={}
317 if rspec_node['sliver_id'] in sliver_allocations:
318 # set sliver allocation and operational status
319 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
320 if sliver_allocation:
321 allocation_status = sliver_allocation.allocation_state
322 if allocation_status == 'geni_allocated':
323 op_status = 'geni_pending_allocation'
324 elif allocation_status == 'geni_provisioned':
325 op_status = 'geni_ready'
327 op_status = 'geni_unknown'
329 allocation_status = 'geni_unallocated'
331 allocation_status = 'geni_unallocated'
332 op_status = 'geni_failed'
334 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
335 'geni_expires': rspec_node['expires'],
336 'geni_allocation_status' : allocation_status,
337 'geni_operational_status': op_status,
342 def sliver_to_rspec_node(self, sliver, sliver_allocations):
343 """Used by describe to format node information into a rspec compliant
346 Creates a node rspec compliant structure by calling node_to_rspec_node.
347 Adds slivers, if any, to rspec node structure. Returns the updated
350 :param sliver: sliver dictionary. Contains keys: urn, slice_id, hostname
352 :type sliver: dictionary
353 :param sliver_allocations: dictionary of slivers
354 :type sliver_allocations: dict
356 :returns: Node dictionary with all necessary data.
358 .. seealso:: node_to_rspec_node
360 rspec_node = self.node_to_rspec_node(sliver)
361 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
363 logger.debug("CORTEXLABAGGREGATE api \t sliver_to_rspec_node sliver \
364 %s \r\nsliver_allocations %s" % (sliver,
366 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
367 'name': sliver['slice_id'],
368 'type': 'iotlab-exclusive',
370 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
372 if sliver['urn'] in sliver_allocations:
373 rspec_node['client_id'] = sliver_allocations[
374 sliver['urn']].client_id
375 if sliver_allocations[sliver['urn']].component_id:
376 rspec_node['component_id'] = sliver_allocations[
377 sliver['urn']].component_id
378 rspec_node['slivers'] = [rspec_sliver]
380 # slivers always provide the ssh service
381 login = Login({'authentication': 'ssh-keys',
382 'hostname': sliver['hostname'],
384 'username': sliver['slice_name'],
385 'login': sliver['slice_name']
390 def get_all_leases(self, ldap_username):
393 Get list of lease dictionaries which all have the mandatory keys
394 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
395 All the leases running or scheduled are returned.
397 :param ldap_username: if ldap uid is not None, looks for the leases
398 belonging to this user.
399 :type ldap_username: string
400 :returns: rspec lease dictionary with keys lease_id, component_id,
401 slice_id, start_time, duration where the lease_id is the oar job id,
402 component_id is the node's urn, slice_id is the slice urn,
403 start_time is the timestamp starting time and duration is expressed
404 in terms of the testbed's granularity.
407 .. note::There is no filtering of leases within a given time frame.
408 All the running or scheduled leases are returned. options
409 removed SA 15/05/2013
414 logger.debug("CortexlabAggregate get_all_leases ldap_username %s "
416 leases = self.driver.driver.GetLeases(login=ldap_username)
417 grain = self.driver.testbed_shell.GetLeaseGranularity()
421 #as many leases as there are nodes in the job
422 for node in lease['reserved_nodes']:
423 rspec_lease = Lease()
424 rspec_lease['lease_id'] = lease['lease_id']
426 cortexlab_xrn = xrn_object(
427 self.driver.testbed_shell.root_auth, node)
428 rspec_lease['component_id'] = cortexlab_xrn.urn
429 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
430 #site, node['hostname'])
432 rspec_lease['slice_id'] = lease['slice_id']
434 #No info on the slice used in cortexlab_xp table
436 rspec_lease['start_time'] = lease['t_from']
437 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
439 rspec_leases.append(rspec_lease)
442 def get_rspec(self, slice_xrn=None, login=None, version=None,
446 - a full advertisement rspec with the testbed resources if slice_xrn is
447 not specified.If a lease option is given, also returns the leases
448 scheduled on the testbed.
449 - a manifest Rspec with the leases and nodes in slice's leases if
450 slice_xrn is not None.
452 :param slice_xrn: srn of the slice
453 :type slice_xrn: string
454 :param login: user'uid (ldap login) on cortexlab
456 :param version: can be set to sfa or cortexlab
457 :type version: RSpecVersion
458 :param options: used to specify if the leases should also be included in
470 version_manager = VersionManager()
471 version = version_manager.get_version(version)
472 logger.debug("CortexlabAggregate \t get_rspec ***version %s \
473 version.type %s version.version %s options %s \r\n"
474 % (version, version.type, version.version, options))
476 if slice_xrn is None:
477 rspec_version = version_manager._get_version(version.type,
478 version.version, 'ad')
481 rspec_version = version_manager._get_version(
482 version.type, version.version, 'manifest')
484 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
485 if slice_xrn and slices is not None:
486 #Get user associated with this slice
487 #for one_slice in slices :
488 ldap_username = self.find_ldap_username_from_slice(slices[0])
489 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
490 # # ldap_username = slices[0]['user']
491 # tmp = ldap_username.split('.')
492 # ldap_username = tmp[1]
493 logger.debug("CortexlabAggregate \tget_rspec **** \
494 LDAP USERNAME %s \r\n" \
496 #at this point sliver may be empty if no cortexlab job
497 #is running for this user/slice.
498 rspec = RSpec(version=rspec_version, user_options=options)
500 logger.debug("\r\n \r\n CortexlabAggregate \tget_rspec *** \
501 slice_xrn %s slices %s\r\n \r\n"
502 % (slice_xrn, slices))
504 if options is not None :
505 lease_option = options['list_leases']
507 #If no options are specified, at least print the resources
510 #lease_option = 'all'
512 if lease_option in ['all', 'resources']:
513 #if not options.get('list_leases') or options.get('list_leases')
514 #and options['list_leases'] != 'leases':
515 nodes = self.get_nodes()
517 logger.debug("CortexlabAggregate \t lease_option %s \
518 get rspec ******* nodes %s"
519 % (lease_option, nodes))
521 sites_set = set([node['location']['site'] for node in nodes])
523 #In case creating a job, slice_xrn is not set to None
524 rspec.version.add_nodes(nodes)
525 if slice_xrn and slices is not None:
526 # #Get user associated with this slice
527 # #for one_slice in slices :
528 # ldap_username = slices[0]['reg_researchers']
529 # # ldap_username = slices[0]['user']
530 # tmp = ldap_username.split('.')
531 # ldap_username = tmp[1]
532 # # ldap_username = tmp[1].split('_')[0]
534 logger.debug("CortexlabAggregate \tget_rspec **** \
535 version type %s ldap_ user %s \r\n" \
536 % (version.type, ldap_username))
537 #TODO : Change the version of Rspec here in case of pbm -SA 09/01/14
538 if version.type in ["Cortexlab", "Iotlab"]:
539 rspec.version.add_connection_information(
540 ldap_username, sites_set)
542 default_sliver = slivers.get('default_sliver', [])
543 if default_sliver and len(nodes) is not 0:
544 #default_sliver_attribs = default_sliver.get('tags', [])
545 logger.debug("CortexlabAggregate \tget_rspec **** \
546 default_sliver%s \r\n" % (default_sliver))
547 for attrib in default_sliver:
548 rspec.version.add_default_sliver_attribute(
549 attrib, default_sliver[attrib])
551 if lease_option in ['all','leases']:
552 leases = self.get_all_leases(ldap_username)
553 rspec.version.add_leases(leases)
554 logger.debug("CortexlabAggregate \tget_rspec **** \
555 FINAL RSPEC %s \r\n" % (rspec.toxml()))
560 def get_slivers(self, urns, options=None):
561 """Get slivers of the given slice urns. Slivers contains slice, node and
564 For Iotlab, returns the leases with sliver ids and their allocation
567 :param urns: list of slice urns.
568 :type urns: list of strings
569 :param options: unused
570 :type options: unused
572 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
574 if options is None: options={}
579 xrn = IotlabXrn(xrn=urn)
580 if xrn.type == 'sliver':
581 # id: slice_id-node_id
583 sliver_id_parts = xrn.get_sliver_id_parts()
584 slice_id = int(sliver_id_parts[0])
585 node_id = int(sliver_id_parts[1])
586 slice_ids.add(slice_id)
587 node_ids.append(node_id)
592 slice_names.add(xrn.hrn)
595 logger.debug("CortexlabAggregate \t get_slivers urns %s slice_ids %s \
596 node_ids %s\r\n" % (urns, slice_ids, node_ids))
597 logger.debug("CortexlabAggregate \t get_slivers xrn %s slice_names %s \
598 \r\n" % (xrn, slice_names))
601 filter_sliver['slice_hrn'] = list(slice_names)
602 slice_hrn = filter_sliver['slice_hrn'][0]
604 slice_filter_type = 'slice_hrn'
607 # filter['slice_id'] = list(slice_ids)
610 slices = self.driver.GetSlices(slice_hrn,
612 leases = self.driver.GetLeases({'slice_hrn':slice_hrn})
613 logger.debug("CortexlabAggregate \t get_slivers \
614 slices %s leases %s\r\n" % (slices, leases ))
618 single_slice = slices[0]
620 user = single_slice['reg_researchers'][0].__dict__
621 logger.debug("CortexlabAggregate \t get_slivers user %s \
624 # construct user key info
625 person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
626 logger.debug("CortexlabAggregate \t get_slivers person %s \
628 # name = person['last_name']
629 user['login'] = person['uid']
630 user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
631 user['keys'] = person['pkey']
635 node_ids = single_slice['node_ids']
636 node_list = self.driver.testbed_shell.GetNodes(
637 {'hostname':single_slice['node_ids']})
638 node_by_hostname = dict([(node['hostname'], node)
639 for node in node_list])
641 logger.warning("\t get_slivers No slivers in slice")
642 # slice['node_ids'] = node_ids
643 # nodes_dict = self.get_slice_nodes(slice, options)
646 for current_lease in leases:
647 for hostname in current_lease['reserved_nodes']:
649 node['slice_id'] = current_lease['slice_id']
650 node['slice_hrn'] = current_lease['slice_hrn']
651 slice_name = current_lease['slice_hrn'].split(".")[1]
652 node['slice_name'] = slice_name
653 index = current_lease['reserved_nodes'].index(hostname)
654 node_id = current_lease['resource_ids'][index]
655 # node['slice_name'] = user['login']
656 # node.update(single_slice)
657 more_info = node_by_hostname[hostname]
658 node.update(more_info)
659 # oar_job_id is the slice_id (lease_id)
660 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
661 current_lease['lease_id'], node_id)
662 node['node_id'] = node_id
663 node['expires'] = current_lease['t_until']
664 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
665 node['urn'] = node['sliver_id']
666 node['services_user'] = [user]
672 def list_resources(self, version = None, options=None):
674 Returns an advertisement Rspec of available resources at this
675 aggregate. This Rspec contains a resource listing along with their
676 description, providing sufficient information for clients to be able to
677 select among available resources.
679 :param options: various options. The valid options are: {boolean
680 geni_compressed <optional>; struct geni_rspec_version { string type;
681 #case insensitive , string version; # case insensitive}} . The only
682 mandatory options if options is specified is geni_rspec_version.
683 :type options: dictionary
685 :returns: On success, the value field of the return struct will contain
686 a geni.rspec advertisment RSpec
687 :rtype: Rspec advertisement in xml.
689 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
690 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
693 if options is None: options={}
695 version_manager = VersionManager()
696 version = version_manager.get_version(version)
697 rspec_version = version_manager._get_version(version.type,
698 version.version, 'ad')
699 rspec = RSpec(version=rspec_version, user_options=options)
700 # variable ldap_username to be compliant with get_all_leases
701 # prototype. Now unused in geni-v3 since we are getting all the leases
704 if not options.get('list_leases') or options['list_leases'] != 'leases':
706 nodes_dict = self.get_nodes(options)
708 # no interfaces on iotlab nodes
709 # convert nodes to rspec nodes
711 for node_id in nodes_dict:
712 node = nodes_dict[node_id]
713 rspec_node = self.node_to_rspec_node(node)
714 rspec_nodes.append(rspec_node)
715 rspec.version.add_nodes(rspec_nodes)
718 # links = self.get_links(sites, nodes_dict, interfaces)
719 # rspec.version.add_links(links)
721 if not options.get('list_leases') or options.get('list_leases') \
722 and options['list_leases'] != 'resources':
723 leases = self.get_all_leases(ldap_username)
724 rspec.version.add_leases(leases)
729 def describe(self, urns, version=None, options=None):
731 Retrieve a manifest RSpec describing the resources contained by the
732 named entities, e.g. a single slice or a set of the slivers in a slice.
733 This listing and description should be sufficiently descriptive to allow
734 experimenters to use the resources.
736 :param urns: If a slice urn is supplied and there are no slivers in the
737 given slice at this aggregate, then geni_rspec shall be a valid
738 manifest RSpec, containing no node elements - no resources.
739 :type urns: list or strings
740 :param options: various options. the valid options are: {boolean
741 geni_compressed <optional>; struct geni_rspec_version { string type;
742 #case insensitive , string version; # case insensitive}}
743 :type options: dictionary
745 :returns: On success returns the following dictionary {geni_rspec:
746 <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
747 containing slice>, geni_slivers:{ geni_sliver_urn:
748 <string sliver urn>, geni_expires: <dateTime.rfc3339 allocation
749 expiration string, as in geni_expires from SliversStatus>,
750 geni_allocation_status: <string sliver state - e.g. geni_allocated
751 or geni_provisioned >, geni_operational_status:
752 <string sliver operational state>, geni_error: <optional string.
753 The field may be omitted entirely but may not be null/None,
754 explaining any failure for a sliver.>}
756 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
757 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
759 if options is None: options={}
760 version_manager = VersionManager()
761 version = version_manager.get_version(version)
762 rspec_version = version_manager._get_version(
763 version.type, version.version, 'manifest')
764 rspec = RSpec(version=rspec_version, user_options=options)
768 slivers = self.get_slivers(urns, options)
770 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
772 rspec_expires = datetime_to_string(utcparse(time.time()))
773 rspec.xml.set('expires', rspec_expires)
775 # lookup the sliver allocations
777 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
778 logger.debug(" Cortexlabaggregate.PY \tDescribe sliver_ids %s "
780 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
781 query = self.driver.api.dbsession().query(SliverAllocation)
782 sliver_allocations = query.filter((constraint)).all()
783 logger.debug(" Cortexlabaggregate.PY \tDescribe sliver_allocations %s "
784 % (sliver_allocations))
785 sliver_allocation_dict = {}
786 for sliver_allocation in sliver_allocations:
787 geni_urn = sliver_allocation.slice_urn
788 sliver_allocation_dict[sliver_allocation.sliver_id] = \
793 for sliver in slivers:
794 nodes_dict[sliver['node_id']] = sliver
796 for sliver in slivers:
797 rspec_node = self.sliver_to_rspec_node(sliver,
798 sliver_allocation_dict)
799 rspec_nodes.append(rspec_node)
800 logger.debug(" Cortexlabaggregate.PY \tDescribe sliver_allocation_dict %s "
801 % (sliver_allocation_dict))
802 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
803 sliver_allocation_dict)
804 geni_slivers.append(geni_sliver)
806 logger.debug(" Cortexlabaggregate.PY \tDescribe rspec_nodes %s\
808 % (rspec_nodes, rspec))
809 rspec.version.add_nodes(rspec_nodes)
811 return {'geni_urn': geni_urn,
812 'geni_rspec': rspec.toxml(),
813 'geni_slivers': geni_slivers}