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 = None):
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 sliver_allocations is None: sliver_allocations={}
330 if rspec_node['sliver_id'] in sliver_allocations:
331 # set sliver allocation and operational status
332 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
333 if sliver_allocation:
334 allocation_status = sliver_allocation.allocation_state
335 if allocation_status == 'geni_allocated':
336 op_status = 'geni_pending_allocation'
337 elif allocation_status == 'geni_provisioned':
338 op_status = 'geni_ready'
340 op_status = 'geni_unknown'
342 allocation_status = 'geni_unallocated'
344 allocation_status = 'geni_unallocated'
345 op_status = 'geni_failed'
347 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
348 'geni_expires': rspec_node['expires'],
349 'geni_allocation_status' : allocation_status,
350 'geni_operational_status': op_status,
356 def sliver_to_rspec_node(self, sliver, sliver_allocations):
357 """Used by describe to format node information into a rspec compliant
360 Creates a node rspec compliant structure by calling node_to_rspec_node.
361 Adds slivers, if any, to rspec node structure. Returns the updated
364 :param sliver: sliver dictionary. Contains keys: urn, slice_id, hostname
366 :type sliver: dictionary
367 :param sliver_allocations: dictionary of slivers
368 :type sliver_allocations: dict
370 :returns: Node dictionary with all necessary data.
372 .. seealso:: node_to_rspec_node
374 rspec_node = self.node_to_rspec_node(sliver)
375 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
377 logger.debug("IOTLABAGGREGATE api \t sliver_to_rspec_node sliver \
378 %s \r\nsliver_allocations %s" % (sliver,
380 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
381 'name': sliver['slice_id'],
382 'type': 'iotlab-exclusive',
384 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
386 if sliver['urn'] in sliver_allocations:
387 rspec_node['client_id'] = sliver_allocations[
388 sliver['urn']].client_id
389 if sliver_allocations[sliver['urn']].component_id:
390 rspec_node['component_id'] = sliver_allocations[
391 sliver['urn']].component_id
392 rspec_node['slivers'] = [rspec_sliver]
394 # slivers always provide the ssh service
395 login = Login({'authentication': 'ssh-keys',
396 'hostname': sliver['hostname'],
398 'username': sliver['slice_name'],
399 'login': sliver['slice_name']
404 def get_leases(self, slice=None, options=None):
405 if options is None: options={}
408 filter.update({'slice_hrn':slice['slice_hrn']}) # JORDAN: this is = "upmc" !!!
409 #filter.update({'name':slice['slice_name']})
410 #return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
411 leases = self.driver.GetLeases(lease_filter_dict=filter)
412 grain = self.driver.testbed_shell.GetLeaseGranularity()
416 #as many leases as there are nodes in the job
417 for node in lease['reserved_nodes']:
418 rspec_lease = Lease()
419 rspec_lease['lease_id'] = lease['lease_id']
420 #site = node['site_id']
421 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
423 rspec_lease['component_id'] = iotlab_xrn.urn
424 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
425 #site, node['hostname'])
427 rspec_lease['slice_id'] = lease['slice_id']
429 #No info on the slice used in testbed_xp table
431 rspec_lease['start_time'] = lease['t_from']
432 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
434 rspec_leases.append(rspec_lease)
438 def get_all_leases(self, ldap_username):
440 Get list of lease dictionaries which all have the mandatory keys
441 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
442 All the leases running or scheduled are returned.
444 :param ldap_username: if ldap uid is not None, looks for the leases
445 belonging to this user.
446 :type ldap_username: string
447 :returns: rspec lease dictionary with keys lease_id, component_id,
448 slice_id, start_time, duration where the lease_id is the oar job id,
449 component_id is the node's urn, slice_id is the slice urn,
450 start_time is the timestamp starting time and duration is expressed
451 in terms of the testbed's granularity.
454 .. note::There is no filtering of leases within a given time frame.
455 All the running or scheduled leases are returned. options
456 removed SA 15/05/2013
461 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
463 leases = self.driver.GetLeases(login=ldap_username)
464 grain = self.driver.testbed_shell.GetLeaseGranularity()
468 #as many leases as there are nodes in the job
469 for node in lease['reserved_nodes']:
470 rspec_lease = Lease()
471 rspec_lease['lease_id'] = lease['lease_id']
472 #site = node['site_id']
473 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
475 rspec_lease['component_id'] = iotlab_xrn.urn
476 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
477 #site, node['hostname'])
479 rspec_lease['slice_id'] = lease['slice_id']
481 #No info on the slice used in testbed_xp table
483 rspec_lease['start_time'] = lease['t_from']
484 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
486 rspec_leases.append(rspec_lease)
489 def get_rspec(self, slice_xrn=None, login=None, version=None,
493 - a full advertisement rspec with the testbed resources if slice_xrn is
494 not specified.If a lease option is given, also returns the leases
495 scheduled on the testbed.
496 - a manifest Rspec with the leases and nodes in slice's leases if
497 slice_xrn is not None.
499 :param slice_xrn: srn of the slice
500 :type slice_xrn: string
501 :param login: user'uid (ldap login) on iotlab
503 :param version: can be set to sfa or iotlab
504 :type version: RSpecVersion
505 :param options: used to specify if the leases should also be included in
517 version_manager = VersionManager()
518 version = version_manager.get_version(version)
519 logger.debug("IotlabAggregate \t get_rspec ***version %s \
520 version.type %s version.version %s options %s \r\n"
521 % (version, version.type, version.version, options))
523 if slice_xrn is None:
524 rspec_version = version_manager._get_version(version.type,
525 version.version, 'ad')
528 rspec_version = version_manager._get_version(
529 version.type, version.version, 'manifest')
531 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
532 if slice_xrn and slices is not None:
533 #Get user associated with this slice
534 #for one_slice in slices :
535 ldap_username = self.find_ldap_username_from_slice(slices[0])
536 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
537 # # ldap_username = slices[0]['user']
538 # tmp = ldap_username.split('.')
539 # ldap_username = tmp[1]
540 logger.debug("IotlabAggregate \tget_rspec **** \
541 LDAP USERNAME %s \r\n" \
543 #at this point sliver may be empty if no iotlab job
544 #is running for this user/slice.
545 rspec = RSpec(version=rspec_version, user_options=options)
547 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
548 slice_xrn %s slices %s\r\n \r\n"
549 % (slice_xrn, slices))
551 if options is not None:
552 lease_option = options['list_leases']
554 #If no options are specified, at least print the resources
557 #lease_option = 'all'
559 if lease_option in ['all', 'resources']:
560 #if not options.get('list_leases') or options.get('list_leases')
561 #and options['list_leases'] != 'leases':
562 nodes = self.get_nodes()
564 logger.debug("IotlabAggregate \t lease_option %s \
565 get rspec ******* nodes %s"
566 % (lease_option, nodes))
568 sites_set = set([node['location']['site'] for node in nodes])
570 #In case creating a job, slice_xrn is not set to None
571 rspec.version.add_nodes(nodes)
572 if slice_xrn and slices is not None:
573 # #Get user associated with this slice
574 # #for one_slice in slices :
575 # ldap_username = slices[0]['reg_researchers']
576 # # ldap_username = slices[0]['user']
577 # tmp = ldap_username.split('.')
578 # ldap_username = tmp[1]
579 # # ldap_username = tmp[1].split('_')[0]
581 logger.debug("IotlabAggregate \tget_rspec **** \
582 version type %s ldap_ user %s \r\n" \
583 % (version.type, ldap_username))
584 if version.type == "Iotlab":
585 rspec.version.add_connection_information(
586 ldap_username, sites_set)
588 default_sliver = slivers.get('default_sliver', [])
589 if default_sliver and len(nodes) is not 0:
590 #default_sliver_attribs = default_sliver.get('tags', [])
591 logger.debug("IotlabAggregate \tget_rspec **** \
592 default_sliver%s \r\n" % (default_sliver))
593 for attrib in default_sliver:
594 rspec.version.add_default_sliver_attribute(
595 attrib, default_sliver[attrib])
597 if lease_option in ['all','leases']:
598 leases = self.get_all_leases(ldap_username)
599 rspec.version.add_leases(leases)
600 logger.debug("IotlabAggregate \tget_rspec **** \
601 FINAL RSPEC %s \r\n" % (rspec.toxml()))
604 def get_slivers(self, urns, options=None):
605 """Get slivers of the given slice urns. Slivers contains slice, node and
608 For Iotlab, returns the leases with sliver ids and their allocation
611 :param urns: list of slice urns.
612 :type urns: list of strings
613 :param options: unused
614 :type options: unused
616 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
618 # JORDAN using SLICE_KEY for slice_hrn
619 SLICE_KEY = 'slice_hrn' # slice_hrn
620 if options is None: options={}
624 xrn = IotlabXrn(xrn=urn)
625 if xrn.type == 'sliver':
626 # id: slice_id-node_id
628 sliver_id_parts = xrn.get_sliver_id_parts()
629 slice_id = int(sliver_id_parts[0])
630 node_id = int(sliver_id_parts[1])
631 slice_ids.add(slice_id)
632 node_ids.append(node_id)
637 slice_names.add(xrn.hrn)
640 logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
641 node_ids %s\r\n" % (urns, slice_ids, node_ids))
642 logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
643 \r\n" % (xrn, slice_names))
646 filter_sliver[SLICE_KEY] = list(slice_names)
647 slice_hrn = filter_sliver[SLICE_KEY][0]
649 slice_filter_type = SLICE_KEY
652 # filter['slice_id'] = list(slice_ids)
655 #logger.debug("JORDAN SLICE_HRN=%r" % slice_hrn)
656 slices = self.driver.GetSlices(slice_hrn,
658 leases = self.driver.GetLeases({SLICE_KEY:slice_hrn})
659 logger.debug("IotlabAggregate \t get_slivers \
660 slices %s leases %s\r\n" % (slices, leases ))
664 single_slice = slices[0]
666 # XXX LOIC !!! XXX QUICK AND DIRTY - Let's try...
667 logger.debug("LOIC Number of reg_researchers = %s" % len(single_slice['reg_researchers']))
668 if 'reg_researchers' in single_slice and len(single_slice['reg_researchers'])==0:
669 user = {'uid':single_slice['user']}
671 user = single_slice['reg_researchers'][0].__dict__
673 user = single_slice['reg_researchers'][0].__dict__
674 logger.debug("IotlabAggregate \t get_slivers user %s \
677 # construct user key info
678 person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
679 logger.debug("IotlabAggregate \t get_slivers person %s \
681 # name = person['last_name']
682 user['login'] = person['uid']
683 # XXX LOIC !!! if we have more info, let's fill user
685 user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
687 user['keys'] = person['pkey']
691 node_ids = single_slice['node_ids']
692 node_list = self.driver.testbed_shell.GetNodes()
693 # JORDAN REMOVED FILTER so that next check always succeed
694 # {'hostname':single_slice['node_ids']})
695 node_by_hostname = dict([(node['hostname'], node)
696 for node in node_list])
698 logger.warning("\t get_slivers No slivers in slice")
699 # slice['node_ids'] = node_ids
700 # nodes_dict = self.get_slice_nodes(slice, options)
703 for current_lease in leases:
704 for hostname in current_lease['reserved_nodes']:
706 node['slice_id'] = current_lease['slice_id']
707 node['slice_hrn'] = current_lease['slice_hrn']
708 slice_name = current_lease['slice_hrn'].split(".")[1]
709 node['slice_name'] = slice_name
710 index = current_lease['reserved_nodes'].index(hostname)
711 node_id = current_lease['resource_ids'][index]
712 # node['slice_name'] = user['login']
713 # node.update(single_slice)
714 # JORDAN XXX This fails sometimes when hostname not in the list
715 #if hostname in node_by_hostname:
716 more_info = node_by_hostname[hostname]
717 node.update(more_info)
719 # # This can happen when specifying a lease without the resource, then all subsequent calls will fail
720 # logger.debug("Ignored missing hostname for now one")
721 # oar_job_id is the slice_id (lease_id)
722 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
723 current_lease['lease_id'], node_id)
724 node['node_id'] = node_id
725 node['expires'] = current_lease['t_until']
726 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
727 node['urn'] = node['sliver_id']
728 node['services_user'] = [user]
733 def list_resources(self, version = None, options=None):
735 Returns an advertisement Rspec of available resources at this
736 aggregate. This Rspec contains a resource listing along with their
737 description, providing sufficient information for clients to be able to
738 select among available resources.
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}} . The only
743 mandatory options if options is specified is geni_rspec_version.
744 :type options: dictionary
746 :returns: On success, the value field of the return struct will contain
747 a geni.rspec advertisment RSpec
748 :rtype: Rspec advertisement in xml.
750 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
751 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
754 if options is None: options={}
755 version_manager = VersionManager()
756 version = version_manager.get_version(version)
757 rspec_version = version_manager._get_version(version.type,
758 version.version, 'ad')
759 rspec = RSpec(version=rspec_version, user_options=options)
760 # variable ldap_username to be compliant with get_all_leases
761 # prototype. Now unused in geni-v3 since we are getting all the leases
764 if not options.get('list_leases') or options['list_leases'] != 'leases':
766 nodes_dict = self.get_nodes(options)
768 # no interfaces on iotlab nodes
769 # convert nodes to rspec nodes
771 for node_id in nodes_dict:
772 node = nodes_dict[node_id]
773 rspec_node = self.node_to_rspec_node(node)
774 rspec_nodes.append(rspec_node)
775 rspec.version.add_nodes(rspec_nodes)
778 # links = self.get_links(sites, nodes_dict, interfaces)
779 # rspec.version.add_links(links)
781 if not options.get('list_leases') or options.get('list_leases') \
782 and options['list_leases'] != 'resources':
783 leases = self.get_all_leases(ldap_username)
784 rspec.version.add_leases(leases)
789 def describe(self, urns, version=None, options=None):
791 Retrieve a manifest RSpec describing the resources contained by the
792 named entities, e.g. a single slice or a set of the slivers in a slice.
793 This listing and description should be sufficiently descriptive to allow
794 experimenters to use the resources.
796 :param urns: If a slice urn is supplied and there are no slivers in the
797 given slice at this aggregate, then geni_rspec shall be a valid
798 manifest RSpec, containing no node elements - no resources.
799 :type urns: list or strings
800 :param options: various options. the valid options are: {boolean
801 geni_compressed <optional>; struct geni_rspec_version { string type;
802 #case insensitive , string version; # case insensitive}}
803 :type options: dictionary
805 :returns: On success returns the following dictionary {geni_rspec:
806 <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
807 containing slice>, geni_slivers:{ geni_sliver_urn:
808 <string sliver urn>, geni_expires: <dateTime.rfc3339 allocation
809 expiration string, as in geni_expires from SliversStatus>,
810 geni_allocation_status: <string sliver state - e.g. geni_allocated
811 or geni_provisioned >, geni_operational_status:
812 <string sliver operational state>, geni_error: <optional string.
813 The field may be omitted entirely but may not be null/None,
814 explaining any failure for a sliver.>}
816 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
817 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
819 if options is None: options={}
820 version_manager = VersionManager()
821 version = version_manager.get_version(version)
822 rspec_version = version_manager._get_version(
823 version.type, version.version, 'manifest')
824 rspec = RSpec(version=rspec_version, user_options=options)
828 slivers = self.get_slivers(urns, options)
830 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
832 rspec_expires = datetime_to_string(utcparse(time.time()))
833 rspec.xml.set('expires', rspec_expires)
835 # lookup the sliver allocations
837 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
838 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
839 query = self.driver.api.dbsession().query(SliverAllocation)
840 sliver_allocations = query.filter((constraint)).all()
841 sliver_allocation_dict = {}
842 for sliver_allocation in sliver_allocations:
843 geni_urn = sliver_allocation.slice_urn
844 sliver_allocation_dict[sliver_allocation.sliver_id] = \
846 # JORDAN get the option list_leases if we want to have the leases in describe
847 show_leases = options.get('list_leases')
848 if show_leases in ['resources', 'all']:
849 #if not options.get('list_leases') or options['list_leases'] != 'leases':
852 for sliver in slivers:
853 nodes_dict[sliver['node_id']] = sliver
855 for sliver in slivers:
856 rspec_node = self.sliver_to_rspec_node(sliver,
857 sliver_allocation_dict)
858 rspec_nodes.append(rspec_node)
859 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
860 sliver_allocation_dict)
861 geni_slivers.append(geni_sliver)
862 rspec.version.add_nodes(rspec_nodes)
864 if show_leases in ['leases', 'all']:
865 #if not options.get('list_leases') or options['list_leases'] == 'resources':
867 leases = self.get_leases(slice=slivers[0])
868 logger.debug("JORDAN: getting leases from slice: %r" % slivers[0])
869 rspec.version.add_leases(leases)
871 return {'geni_urn': geni_urn,
872 'geni_rspec': rspec.toxml(),
873 'geni_slivers': geni_slivers}