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.sfatime import utcparse, datetime_to_string
7 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
8 from sfa.iotlab.iotlabxrn import IotlabXrn
9 from sfa.rspecs.rspec import RSpec
10 #from sfa.rspecs.elements.location import Location
11 from sfa.rspecs.elements.hardware_type import HardwareType
12 from sfa.rspecs.elements.login import Login
13 # from sfa.rspecs.elements.services import ServicesElement
14 from sfa.rspecs.elements.sliver import Sliver
15 from sfa.rspecs.elements.lease import Lease
16 from sfa.rspecs.elements.granularity import Granularity
17 from sfa.rspecs.version_manager import VersionManager
18 from sfa.storage.model import SliverAllocation
19 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition, \
20 IotlabNode, IotlabLocation
21 from sfa.iotlab.iotlabxrn import xrn_object
22 from sfa.util.sfalogging import logger
25 class IotlabAggregate:
26 """Aggregate manager class for Iotlab. """
39 def __init__(self, driver):
42 def get_slice_and_slivers(self, slice_xrn, login=None):
44 Get the slices and the associated leases if any from the iotlab
45 testbed. One slice can have mutliple leases.
46 For each slice, get the nodes in the associated lease
47 and create a sliver with the necessary info and insert it into the
48 sliver dictionary, keyed on the node hostnames.
49 Returns a dict of slivers based on the sliver's node_id.
53 :param slice_xrn: xrn of the slice
54 :param login: user's login on iotlab ldap
56 :type slice_xrn: string
58 :returns: a list of slices dict and a list of Sliver object
61 .. note: There is no real slivers in iotlab, only leases. The goal
62 is to be consistent with the SFA standard.
68 return (sfa_slice, slivers)
69 slice_urn = hrn_to_urn(slice_xrn, 'slice')
70 slice_hrn, _ = urn_to_hrn(slice_xrn)
72 # GetSlices always returns a list, even if there is only one element
73 slices = self.driver.GetSlices(slice_filter=str(slice_hrn),
74 slice_filter_type='slice_hrn',
77 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
78 slice_hrn %s \r\n slices %s self.driver.hrn %s"
79 % (slice_hrn, slices, self.driver.hrn))
81 return (sfa_slice, slivers)
83 # sort slivers by node id , if there is a job
84 #and therefore, node allocated to this slice
85 # for sfa_slice in slices:
88 node_ids_list = sfa_slice['node_ids']
90 logger.log_exc("IOTLABAGGREGATE \t \
91 get_slice_and_slivers No nodes in the slice \
96 for node in node_ids_list:
97 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
98 sliver_xrn.set_authority(self.driver.hrn)
99 sliver = Sliver({'sliver_id': sliver_xrn.urn,
100 'name': sfa_slice['hrn'],
101 'type': 'iotlab-node',
104 slivers[node] = sliver
106 #Add default sliver attribute :
107 #connection information for iotlab
108 # if get_authority(sfa_slice['hrn']) == \
109 # self.driver.testbed_shell.root_auth:
110 # tmp = sfa_slice['hrn'].split('.')
111 # ldap_username = tmp[1].split('_')[0]
113 # slivers['default_sliver'] = {'ssh': ssh_access,
114 # 'login': ldap_username}
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("IOTLABAGGREGATE api get_slice_and_slivers slivers %s "
126 return (slices, slivers)
128 def find_ldap_username_from_slice(self, sfa_slice):
130 Gets the ldap username of the user based on the information contained
131 in ist sfa_slice record.
133 :param sfa_slice: the user's slice record. Must contain the
135 :type sfa_slice: dictionary
136 :returns: ldap_username, the ldap user's login.
140 researchers = [sfa_slice['reg_researchers'][0].__dict__]
143 ret = self.driver.testbed_shell.GetPersons(researchers)
145 ldap_username = ret[0]['uid']
151 def get_nodes(self, options=None):
152 # def node_to_rspec_node(self, node, sites, node_tags,
153 # grain=None, options={}):
154 """Returns the nodes in the slice using the rspec format, with all the
157 Fetch the nodes ids in the slices dictionary and get all the nodes
158 properties from OAR. Makes a rspec dicitonary out of this and returns
159 it. If the slice does not have any job running or scheduled, that is
160 it has no reserved nodes, then returns an empty list.
162 :returns: An empty list if the slice has no reserved nodes, a rspec
163 list with all the nodes and their properties (a dict per node)
167 .. seealso:: get_slice_and_slivers
171 # NT: the semantic of this function is not clear to me :
172 # if slice is not defined, then all the nodes should be returned
173 # if slice is defined, we should return only the nodes that
174 # are part of this slice
175 # but what is the role of the slivers parameter ?
176 # So i assume that slice['node_ids'] will be the same as slivers for us
179 geni_available = options.get('geni_available')
180 if geni_available == True:
181 filter_nodes['boot_state'] = ['Alive']
183 # slice_nodes_list = []
184 # if slices is not None:
185 # for one_slice in slices:
187 # slice_nodes_list = one_slice['node_ids']
188 # # if we are dealing with a slice that has no node just
189 # # return an empty list. In iotlab a slice can have multiple
190 # # jobs scheduled, so it either has at least one lease or
195 # get the granularity in second for the reservation system
196 # grain = self.driver.testbed_shell.GetLeaseGranularity()
198 nodes = self.driver.testbed_shell.GetNodes(node_filter_dict =
203 #if slices, this means we got to list all the nodes given to this slice
204 # Make a list of all the nodes in the slice before getting their
208 # logger.debug("IOTLABAGGREGATE api get_nodes slices %s "
211 # reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
212 # logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
213 # % (slice_nodes_list))
215 nodes_dict[node['node_id']] = node
219 def node_to_rspec_node(self, node):
220 """ Creates a rspec node structure with the appropriate information
221 based on the node information that can be found in the node dictionary.
223 :param node: node data. this dict contains information about the node
224 and must have the following keys : mobile, radio, archi, hostname,
225 boot_state, site, x, y ,z (position).
226 :type node: dictionary.
228 :returns: node dictionary containing the following keys : mobile, archi,
229 radio, component_id, component_name, component_manager_id,
230 authority_id, boot_state, exclusive, hardware_types, location,
231 position, granularity, tags.
236 grain = self.driver.testbed_shell.GetLeaseGranularity()
238 rspec_node = IotlabNode()
239 # xxx how to retrieve site['login_base']
240 #site_id=node['site_id']
241 #site=sites_dict[site_id]
243 rspec_node['mobile'] = node['mobile']
244 rspec_node['archi'] = node['archi']
245 rspec_node['radio'] = node['radio']
247 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
249 rspec_node['component_id'] = iotlab_xrn.urn
250 rspec_node['component_name'] = node['hostname']
251 rspec_node['component_manager_id'] = \
252 hrn_to_urn(self.driver.testbed_shell.root_auth,
255 # Iotlab's nodes are federated : there is only one authority
256 # for all Iotlab sites, registered in SFA.
257 # Removing the part including the site
258 # in authority_id SA 27/07/12
259 rspec_node['authority_id'] = rspec_node['component_manager_id']
261 # do not include boot state (<available> element)
262 #in the manifest rspec
265 rspec_node['boot_state'] = node['boot_state']
266 # if node['hostname'] in reserved_nodes:
267 # rspec_node['boot_state'] = "Reserved"
268 rspec_node['exclusive'] = 'true'
269 rspec_node['hardware_types'] = [HardwareType({'name': \
272 location = IotlabLocation({'country':'France', 'site': \
274 rspec_node['location'] = location
277 position = IotlabPosition()
278 for field in position :
280 position[field] = node[field]
281 except KeyError, error :
282 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
283 position %s "% (error))
285 rspec_node['position'] = position
289 granularity = Granularity({'grain': grain})
290 rspec_node['granularity'] = granularity
291 rspec_node['tags'] = []
292 # if node['hostname'] in slivers:
294 # sliver = slivers[node['hostname']]
295 # rspec_node['sliver_id'] = sliver['sliver_id']
296 # rspec_node['client_id'] = node['hostname']
297 # rspec_node['slivers'] = [sliver]
299 # # slivers always provide the ssh service
300 # login = Login({'authentication': 'ssh-keys', \
301 # 'hostname': node['hostname'], 'port':'22', \
302 # 'username': sliver['name']})
303 # service = Services({'login': login})
304 # rspec_node['services'] = [service]
309 def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
310 """Makes a geni sliver structure from all the nodes allocated
311 to slivers in the sliver_allocations dictionary. Returns the states
314 :param rspec_node: Node information contained in a rspec data structure
316 :type rspec_node: dictionary
317 :param sliver_allocations:
318 :type sliver_allocations: dictionary
320 :returns: Dictionary with the following keys: geni_sliver_urn,
321 geni_expires, geni_allocation_status, geni_operational_status,
326 .. seealso:: node_to_rspec_node
329 if rspec_node['sliver_id'] in sliver_allocations:
330 # set sliver allocation and operational status
331 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
332 if sliver_allocation:
333 allocation_status = sliver_allocation.allocation_state
334 if allocation_status == 'geni_allocated':
335 op_status = 'geni_pending_allocation'
336 elif allocation_status == 'geni_provisioned':
337 op_status = 'geni_ready'
339 op_status = 'geni_unknown'
341 allocation_status = 'geni_unallocated'
343 allocation_status = 'geni_unallocated'
344 op_status = 'geni_failed'
346 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
347 'geni_expires': rspec_node['expires'],
348 'geni_allocation_status' : allocation_status,
349 'geni_operational_status': op_status,
355 def sliver_to_rspec_node(self, sliver, sliver_allocations):
356 """Used by describe to format node information into a rspec compliant
359 Creates a node rspec compliant structure by calling node_to_rspec_node.
360 Adds slivers, if any, to rspec node structure. Returns the updated
363 :param sliver: sliver dictionary. Contains keys: urn, slice_id, hostname
365 :type sliver: dictionary
366 :param sliver_allocations: dictionary of slivers
367 :type sliver_allocations: dict
369 :returns: Node dictionary with all necessary data.
371 .. seealso:: node_to_rspec_node
373 rspec_node = self.node_to_rspec_node(sliver)
374 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
376 logger.debug("IOTLABAGGREGATE api \t sliver_to_rspec_node sliver \
377 %s \r\nsliver_allocations %s" % (sliver,
379 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
380 'name': sliver['slice_id'],
381 'type': 'iotlab-exclusive',
383 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
385 if sliver['urn'] in sliver_allocations:
386 rspec_node['client_id'] = sliver_allocations[
387 sliver['urn']].client_id
388 if sliver_allocations[sliver['urn']].component_id:
389 rspec_node['component_id'] = sliver_allocations[
390 sliver['urn']].component_id
391 rspec_node['slivers'] = [rspec_sliver]
393 # slivers always provide the ssh service
394 login = Login({'authentication': 'ssh-keys',
395 'hostname': sliver['hostname'],
397 'username': sliver['slice_name'],
398 'login': sliver['slice_name']
403 def get_leases(self, slice=None, options={}):
406 filter.update({'name':slice['slice_name']})
407 #return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
408 leases = self.driver.GetLeases(lease_filter_dict=filter)
409 grain = self.driver.GetLeaseGranularity()
413 #as many leases as there are nodes in the job
414 for node in lease['reserved_nodes']:
415 rspec_lease = Lease()
416 rspec_lease['lease_id'] = lease['lease_id']
417 #site = node['site_id']
418 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
420 rspec_lease['component_id'] = iotlab_xrn.urn
421 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
422 #site, node['hostname'])
424 rspec_lease['slice_id'] = lease['slice_id']
426 #No info on the slice used in testbed_xp table
428 rspec_lease['start_time'] = lease['t_from']
429 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
431 rspec_leases.append(rspec_lease)
435 def get_all_leases(self, ldap_username):
437 Get list of lease dictionaries which all have the mandatory keys
438 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
439 All the leases running or scheduled are returned.
441 :param ldap_username: if ldap uid is not None, looks for the leases
442 belonging to this user.
443 :type ldap_username: string
444 :returns: rspec lease dictionary with keys lease_id, component_id,
445 slice_id, start_time, duration where the lease_id is the oar job id,
446 component_id is the node's urn, slice_id is the slice urn,
447 start_time is the timestamp starting time and duration is expressed
448 in terms of the testbed's granularity.
451 .. note::There is no filtering of leases within a given time frame.
452 All the running or scheduled leases are returned. options
453 removed SA 15/05/2013
458 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
460 leases = self.driver.GetLeases(login=ldap_username)
461 grain = self.driver.testbed_shell.GetLeaseGranularity()
465 #as many leases as there are nodes in the job
466 for node in lease['reserved_nodes']:
467 rspec_lease = Lease()
468 rspec_lease['lease_id'] = lease['lease_id']
469 #site = node['site_id']
470 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
472 rspec_lease['component_id'] = iotlab_xrn.urn
473 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
474 #site, node['hostname'])
476 rspec_lease['slice_id'] = lease['slice_id']
478 #No info on the slice used in testbed_xp table
480 rspec_lease['start_time'] = lease['t_from']
481 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
483 rspec_leases.append(rspec_lease)
486 def get_rspec(self, slice_xrn=None, login=None, version=None,
490 - a full advertisement rspec with the testbed resources if slice_xrn is
491 not specified.If a lease option is given, also returns the leases
492 scheduled on the testbed.
493 - a manifest Rspec with the leases and nodes in slice's leases if
494 slice_xrn is not None.
496 :param slice_xrn: srn of the slice
497 :type slice_xrn: string
498 :param login: user'uid (ldap login) on iotlab
500 :param version: can be set to sfa or iotlab
501 :type version: RSpecVersion
502 :param options: used to specify if the leases should also be included in
514 version_manager = VersionManager()
515 version = version_manager.get_version(version)
516 logger.debug("IotlabAggregate \t get_rspec ***version %s \
517 version.type %s version.version %s options %s \r\n"
518 % (version, version.type, version.version, options))
520 if slice_xrn is None:
521 rspec_version = version_manager._get_version(version.type,
522 version.version, 'ad')
525 rspec_version = version_manager._get_version(
526 version.type, version.version, 'manifest')
528 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
529 if slice_xrn and slices is not None:
530 #Get user associated with this slice
531 #for one_slice in slices :
532 ldap_username = self.find_ldap_username_from_slice(slices[0])
533 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
534 # # ldap_username = slices[0]['user']
535 # tmp = ldap_username.split('.')
536 # ldap_username = tmp[1]
537 logger.debug("IotlabAggregate \tget_rspec **** \
538 LDAP USERNAME %s \r\n" \
540 #at this point sliver may be empty if no iotlab job
541 #is running for this user/slice.
542 rspec = RSpec(version=rspec_version, user_options=options)
544 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
545 slice_xrn %s slices %s\r\n \r\n"
546 % (slice_xrn, slices))
548 if options is not None:
549 lease_option = options['list_leases']
551 #If no options are specified, at least print the resources
554 #lease_option = 'all'
556 if lease_option in ['all', 'resources']:
557 #if not options.get('list_leases') or options.get('list_leases')
558 #and options['list_leases'] != 'leases':
559 nodes = self.get_nodes()
561 logger.debug("IotlabAggregate \t lease_option %s \
562 get rspec ******* nodes %s"
563 % (lease_option, nodes))
565 sites_set = set([node['location']['site'] for node in nodes])
567 #In case creating a job, slice_xrn is not set to None
568 rspec.version.add_nodes(nodes)
569 if slice_xrn and slices is not None:
570 # #Get user associated with this slice
571 # #for one_slice in slices :
572 # ldap_username = slices[0]['reg_researchers']
573 # # ldap_username = slices[0]['user']
574 # tmp = ldap_username.split('.')
575 # ldap_username = tmp[1]
576 # # ldap_username = tmp[1].split('_')[0]
578 logger.debug("IotlabAggregate \tget_rspec **** \
579 version type %s ldap_ user %s \r\n" \
580 % (version.type, ldap_username))
581 if version.type == "Iotlab":
582 rspec.version.add_connection_information(
583 ldap_username, sites_set)
585 default_sliver = slivers.get('default_sliver', [])
586 if default_sliver and len(nodes) is not 0:
587 #default_sliver_attribs = default_sliver.get('tags', [])
588 logger.debug("IotlabAggregate \tget_rspec **** \
589 default_sliver%s \r\n" % (default_sliver))
590 for attrib in default_sliver:
591 rspec.version.add_default_sliver_attribute(
592 attrib, default_sliver[attrib])
594 if lease_option in ['all','leases']:
595 leases = self.get_all_leases(ldap_username)
596 rspec.version.add_leases(leases)
597 logger.debug("IotlabAggregate \tget_rspec **** \
598 FINAL RSPEC %s \r\n" % (rspec.toxml()))
601 def get_slivers(self, urns, options={}):
602 """Get slivers of the given slice urns. Slivers contains slice, node and
605 For Iotlab, returns the leases with sliver ids and their allocation
608 :param urns: list of slice urns.
609 :type urns: list of strings
610 :param options: unused
611 :type options: unused
613 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
620 xrn = IotlabXrn(xrn=urn)
621 if xrn.type == 'sliver':
622 # id: slice_id-node_id
624 sliver_id_parts = xrn.get_sliver_id_parts()
625 slice_id = int(sliver_id_parts[0])
626 node_id = int(sliver_id_parts[1])
627 slice_ids.add(slice_id)
628 node_ids.append(node_id)
633 slice_names.add(xrn.hrn)
636 logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
637 node_ids %s\r\n" % (urns, slice_ids, node_ids))
638 logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
639 \r\n" % (xrn, slice_names))
642 filter_sliver['slice_hrn'] = list(slice_names)
643 slice_hrn = filter_sliver['slice_hrn'][0]
645 slice_filter_type = 'slice_hrn'
648 # filter['slice_id'] = list(slice_ids)
651 slices = self.driver.GetSlices(slice_hrn,
653 leases = self.driver.GetLeases({'slice_hrn':slice_hrn})
654 logger.debug("IotlabAggregate \t get_slivers \
655 slices %s leases %s\r\n" % (slices, leases ))
659 single_slice = slices[0]
661 user = single_slice['reg_researchers'][0].__dict__
662 logger.debug("IotlabAggregate \t get_slivers user %s \
665 # construct user key info
666 person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
667 logger.debug("IotlabAggregate \t get_slivers person %s \
669 # name = person['last_name']
670 user['login'] = person['uid']
671 user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
672 user['keys'] = person['pkey']
676 node_ids = single_slice['node_ids']
677 node_list = self.driver.testbed_shell.GetNodes(
678 {'hostname':single_slice['node_ids']})
679 node_by_hostname = dict([(node['hostname'], node)
680 for node in node_list])
682 logger.warning("\t get_slivers No slivers in slice")
683 # slice['node_ids'] = node_ids
684 # nodes_dict = self.get_slice_nodes(slice, options)
687 for current_lease in leases:
688 for hostname in current_lease['reserved_nodes']:
690 node['slice_id'] = current_lease['slice_id']
691 node['slice_hrn'] = current_lease['slice_hrn']
692 slice_name = current_lease['slice_hrn'].split(".")[1]
693 node['slice_name'] = slice_name
694 index = current_lease['reserved_nodes'].index(hostname)
695 node_id = current_lease['resource_ids'][index]
696 # node['slice_name'] = user['login']
697 # node.update(single_slice)
698 more_info = node_by_hostname[hostname]
699 node.update(more_info)
700 # oar_job_id is the slice_id (lease_id)
701 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
702 current_lease['lease_id'], node_id)
703 node['node_id'] = node_id
704 node['expires'] = current_lease['t_until']
705 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
706 node['urn'] = node['sliver_id']
707 node['services_user'] = [user]
712 def list_resources(self, version = None, options={}):
714 Returns an advertisement Rspec of available resources at this
715 aggregate. This Rspec contains a resource listing along with their
716 description, providing sufficient information for clients to be able to
717 select among available resources.
719 :param options: various options. The valid options are: {boolean
720 geni_compressed <optional>; struct geni_rspec_version { string type;
721 #case insensitive , string version; # case insensitive}} . The only
722 mandatory options if options is specified is geni_rspec_version.
723 :type options: dictionary
725 :returns: On success, the value field of the return struct will contain
726 a geni.rspec advertisment RSpec
727 :rtype: Rspec advertisement in xml.
729 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
730 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
733 version_manager = VersionManager()
734 version = version_manager.get_version(version)
735 rspec_version = version_manager._get_version(version.type,
736 version.version, 'ad')
737 rspec = RSpec(version=rspec_version, user_options=options)
738 # variable ldap_username to be compliant with get_all_leases
739 # prototype. Now unused in geni-v3 since we are getting all the leases
742 if not options.get('list_leases') or options['list_leases'] != 'leases':
744 nodes_dict = self.get_nodes(options)
746 # no interfaces on iotlab nodes
747 # convert nodes to rspec nodes
749 for node_id in nodes_dict:
750 node = nodes_dict[node_id]
751 rspec_node = self.node_to_rspec_node(node)
752 rspec_nodes.append(rspec_node)
753 rspec.version.add_nodes(rspec_nodes)
756 # links = self.get_links(sites, nodes_dict, interfaces)
757 # rspec.version.add_links(links)
759 if not options.get('list_leases') or options.get('list_leases') \
760 and options['list_leases'] != 'resources':
761 leases = self.get_all_leases(ldap_username)
762 rspec.version.add_leases(leases)
767 def describe(self, urns, version=None, options={}):
769 Retrieve a manifest RSpec describing the resources contained by the
770 named entities, e.g. a single slice or a set of the slivers in a slice.
771 This listing and description should be sufficiently descriptive to allow
772 experimenters to use the resources.
774 :param urns: If a slice urn is supplied and there are no slivers in the
775 given slice at this aggregate, then geni_rspec shall be a valid
776 manifest RSpec, containing no node elements - no resources.
777 :type urns: list or strings
778 :param options: various options. the valid options are: {boolean
779 geni_compressed <optional>; struct geni_rspec_version { string type;
780 #case insensitive , string version; # case insensitive}}
781 :type options: dictionary
783 :returns: On success returns the following dictionary {geni_rspec:
784 <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
785 containing slice>, geni_slivers:{ geni_sliver_urn:
786 <string sliver urn>, geni_expires: <dateTime.rfc3339 allocation
787 expiration string, as in geni_expires from SliversStatus>,
788 geni_allocation_status: <string sliver state - e.g. geni_allocated
789 or geni_provisioned >, geni_operational_status:
790 <string sliver operational state>, geni_error: <optional string.
791 The field may be omitted entirely but may not be null/None,
792 explaining any failure for a sliver.>}
794 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
795 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
797 version_manager = VersionManager()
798 version = version_manager.get_version(version)
799 rspec_version = version_manager._get_version(
800 version.type, version.version, 'manifest')
801 rspec = RSpec(version=rspec_version, user_options=options)
805 slivers = self.get_slivers(urns, options)
807 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
809 rspec_expires = datetime_to_string(utcparse(time.time()))
810 rspec.xml.set('expires', rspec_expires)
812 # lookup the sliver allocations
814 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
815 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
816 query = self.driver.api.dbsession().query(SliverAllocation)
817 sliver_allocations = query.filter((constraint)).all()
818 sliver_allocation_dict = {}
819 for sliver_allocation in sliver_allocations:
820 geni_urn = sliver_allocation.slice_urn
821 sliver_allocation_dict[sliver_allocation.sliver_id] = \
823 if not options.get('list_leases') or options['list_leases'] != 'leases':
826 for sliver in slivers:
827 nodes_dict[sliver['node_id']] = sliver
829 for sliver in slivers:
830 rspec_node = self.sliver_to_rspec_node(sliver,
831 sliver_allocation_dict)
832 rspec_nodes.append(rspec_node)
833 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
834 sliver_allocation_dict)
835 geni_slivers.append(geni_sliver)
836 rspec.version.add_nodes(rspec_nodes)
838 if not options.get('list_leases') or options['list_leases'] == 'resources':
840 leases = self.get_leases(slivers[0])
841 rspec.version.add_leases(leases)
843 return {'geni_urn': geni_urn,
844 'geni_rspec': rspec.toxml(),
845 'geni_slivers': geni_slivers}