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 logger.debug("############################################ iotlab AM : single_slice = %s" % single_slice)
692 node_ids = single_slice['node_ids']
693 node_list = self.driver.testbed_shell.GetNodes()
694 logger.debug("############################################ iotlab AM : node_list = %s" % node_list)
695 # JORDAN REMOVED FILTER so that next check always succeed
696 # {'hostname':single_slice['node_ids']})
697 node_by_hostname = dict([(node['hostname'], node)
698 for node in node_list])
700 logger.warning("\t get_slivers No slivers in slice")
701 # slice['node_ids'] = node_ids
702 # nodes_dict = self.get_slice_nodes(slice, options)
705 for current_lease in leases:
706 for hostname in current_lease['reserved_nodes']:
708 node['slice_id'] = current_lease['slice_id']
709 node['slice_hrn'] = current_lease['slice_hrn']
710 slice_name = current_lease['slice_hrn'].split(".")[1]
711 node['slice_name'] = slice_name
712 index = current_lease['reserved_nodes'].index(hostname)
713 node_id = current_lease['resource_ids'][index]
714 # node['slice_name'] = user['login']
715 # node.update(single_slice)
716 # JORDAN XXX This fails sometimes when hostname not in the list
717 #if hostname in node_by_hostname:
718 more_info = node_by_hostname[hostname]
719 node.update(more_info)
721 # # This can happen when specifying a lease without the resource, then all subsequent calls will fail
722 # logger.debug("Ignored missing hostname for now one")
723 # oar_job_id is the slice_id (lease_id)
724 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
725 current_lease['lease_id'], node_id)
726 node['node_id'] = node_id
727 node['expires'] = current_lease['t_until']
728 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
729 node['urn'] = node['sliver_id']
730 node['services_user'] = [user]
735 def list_resources(self, version = None, options=None):
737 Returns an advertisement Rspec of available resources at this
738 aggregate. This Rspec contains a resource listing along with their
739 description, providing sufficient information for clients to be able to
740 select among available resources.
742 :param options: various options. The valid options are: {boolean
743 geni_compressed <optional>; struct geni_rspec_version { string type;
744 #case insensitive , string version; # case insensitive}} . The only
745 mandatory options if options is specified is geni_rspec_version.
746 :type options: dictionary
748 :returns: On success, the value field of the return struct will contain
749 a geni.rspec advertisment RSpec
750 :rtype: Rspec advertisement in xml.
752 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
753 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
756 if options is None: options={}
757 version_manager = VersionManager()
758 version = version_manager.get_version(version)
759 rspec_version = version_manager._get_version(version.type,
760 version.version, 'ad')
761 rspec = RSpec(version=rspec_version, user_options=options)
762 # variable ldap_username to be compliant with get_all_leases
763 # prototype. Now unused in geni-v3 since we are getting all the leases
766 if not options.get('list_leases') or options['list_leases'] != 'leases':
768 nodes_dict = self.get_nodes(options)
770 # no interfaces on iotlab nodes
771 # convert nodes to rspec nodes
773 for node_id in nodes_dict:
774 node = nodes_dict[node_id]
775 rspec_node = self.node_to_rspec_node(node)
776 rspec_nodes.append(rspec_node)
777 rspec.version.add_nodes(rspec_nodes)
780 # links = self.get_links(sites, nodes_dict, interfaces)
781 # rspec.version.add_links(links)
783 if not options.get('list_leases') or options.get('list_leases') \
784 and options['list_leases'] != 'resources':
785 leases = self.get_all_leases(ldap_username)
786 rspec.version.add_leases(leases)
791 def describe(self, urns, version=None, options=None):
793 Retrieve a manifest RSpec describing the resources contained by the
794 named entities, e.g. a single slice or a set of the slivers in a slice.
795 This listing and description should be sufficiently descriptive to allow
796 experimenters to use the resources.
798 :param urns: If a slice urn is supplied and there are no slivers in the
799 given slice at this aggregate, then geni_rspec shall be a valid
800 manifest RSpec, containing no node elements - no resources.
801 :type urns: list or strings
802 :param options: various options. the valid options are: {boolean
803 geni_compressed <optional>; struct geni_rspec_version { string type;
804 #case insensitive , string version; # case insensitive}}
805 :type options: dictionary
807 :returns: On success returns the following dictionary {geni_rspec:
808 <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
809 containing slice>, geni_slivers:{ geni_sliver_urn:
810 <string sliver urn>, geni_expires: <dateTime.rfc3339 allocation
811 expiration string, as in geni_expires from SliversStatus>,
812 geni_allocation_status: <string sliver state - e.g. geni_allocated
813 or geni_provisioned >, geni_operational_status:
814 <string sliver operational state>, geni_error: <optional string.
815 The field may be omitted entirely but may not be null/None,
816 explaining any failure for a sliver.>}
818 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
819 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
821 if options is None: options={}
822 version_manager = VersionManager()
823 version = version_manager.get_version(version)
824 rspec_version = version_manager._get_version(
825 version.type, version.version, 'manifest')
826 rspec = RSpec(version=rspec_version, user_options=options)
830 slivers = self.get_slivers(urns, options)
832 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
834 rspec_expires = datetime_to_string(utcparse(time.time()))
835 rspec.xml.set('expires', rspec_expires)
837 # lookup the sliver allocations
839 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
840 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
841 query = self.driver.api.dbsession().query(SliverAllocation)
842 sliver_allocations = query.filter((constraint)).all()
843 sliver_allocation_dict = {}
844 for sliver_allocation in sliver_allocations:
845 geni_urn = sliver_allocation.slice_urn
846 sliver_allocation_dict[sliver_allocation.sliver_id] = \
848 # JORDAN get the option list_leases if we want to have the leases in describe
849 show_leases = options.get('list_leases')
850 if show_leases in ['resources', 'all']:
851 #if not options.get('list_leases') or options['list_leases'] != 'leases':
854 for sliver in slivers:
855 nodes_dict[sliver['node_id']] = sliver
857 for sliver in slivers:
858 rspec_node = self.sliver_to_rspec_node(sliver,
859 sliver_allocation_dict)
860 rspec_nodes.append(rspec_node)
861 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
862 sliver_allocation_dict)
863 geni_slivers.append(geni_sliver)
864 rspec.version.add_nodes(rspec_nodes)
866 if show_leases in ['leases', 'all']:
867 #if not options.get('list_leases') or options['list_leases'] == 'resources':
869 leases = self.get_leases(slice=slivers[0])
870 logger.debug("JORDAN: getting leases from slice: %r" % slivers[0])
871 rspec.version.add_leases(leases)
873 return {'geni_urn': geni_urn,
874 'geni_rspec': rspec.toxml(),
875 'geni_slivers': geni_slivers}