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']}) # JORDAN: this is = "upmc" !!!
407 filter.update({'slice_hrn':slice['slice_hrn']}) # JORDAN: this is = "upmc" !!!
408 # slice_hrn = "ple.upmc.myslicedemo
409 #return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
410 leases = self.driver.GetLeases(lease_filter_dict=filter)
411 grain = self.driver.testbed_shell.GetLeaseGranularity()
415 #as many leases as there are nodes in the job
416 for node in lease['reserved_nodes']:
417 rspec_lease = Lease()
418 rspec_lease['lease_id'] = lease['lease_id']
419 #site = node['site_id']
420 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
422 rspec_lease['component_id'] = iotlab_xrn.urn
423 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
424 #site, node['hostname'])
426 rspec_lease['slice_id'] = lease['slice_id']
428 #No info on the slice used in testbed_xp table
430 rspec_lease['start_time'] = lease['t_from']
431 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
433 rspec_leases.append(rspec_lease)
437 def get_all_leases(self, ldap_username):
439 Get list of lease dictionaries which all have the mandatory keys
440 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
441 All the leases running or scheduled are returned.
443 :param ldap_username: if ldap uid is not None, looks for the leases
444 belonging to this user.
445 :type ldap_username: string
446 :returns: rspec lease dictionary with keys lease_id, component_id,
447 slice_id, start_time, duration where the lease_id is the oar job id,
448 component_id is the node's urn, slice_id is the slice urn,
449 start_time is the timestamp starting time and duration is expressed
450 in terms of the testbed's granularity.
453 .. note::There is no filtering of leases within a given time frame.
454 All the running or scheduled leases are returned. options
455 removed SA 15/05/2013
460 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
462 leases = self.driver.GetLeases(login=ldap_username)
463 grain = self.driver.testbed_shell.GetLeaseGranularity()
467 #as many leases as there are nodes in the job
468 for node in lease['reserved_nodes']:
469 rspec_lease = Lease()
470 rspec_lease['lease_id'] = lease['lease_id']
471 #site = node['site_id']
472 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
474 rspec_lease['component_id'] = iotlab_xrn.urn
475 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
476 #site, node['hostname'])
478 rspec_lease['slice_id'] = lease['slice_id']
480 #No info on the slice used in testbed_xp table
482 rspec_lease['start_time'] = lease['t_from']
483 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
485 rspec_leases.append(rspec_lease)
488 def get_rspec(self, slice_xrn=None, login=None, version=None,
492 - a full advertisement rspec with the testbed resources if slice_xrn is
493 not specified.If a lease option is given, also returns the leases
494 scheduled on the testbed.
495 - a manifest Rspec with the leases and nodes in slice's leases if
496 slice_xrn is not None.
498 :param slice_xrn: srn of the slice
499 :type slice_xrn: string
500 :param login: user'uid (ldap login) on iotlab
502 :param version: can be set to sfa or iotlab
503 :type version: RSpecVersion
504 :param options: used to specify if the leases should also be included in
516 version_manager = VersionManager()
517 version = version_manager.get_version(version)
518 logger.debug("IotlabAggregate \t get_rspec ***version %s \
519 version.type %s version.version %s options %s \r\n"
520 % (version, version.type, version.version, options))
522 if slice_xrn is None:
523 rspec_version = version_manager._get_version(version.type,
524 version.version, 'ad')
527 rspec_version = version_manager._get_version(
528 version.type, version.version, 'manifest')
530 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
531 if slice_xrn and slices is not None:
532 #Get user associated with this slice
533 #for one_slice in slices :
534 ldap_username = self.find_ldap_username_from_slice(slices[0])
535 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
536 # # ldap_username = slices[0]['user']
537 # tmp = ldap_username.split('.')
538 # ldap_username = tmp[1]
539 logger.debug("IotlabAggregate \tget_rspec **** \
540 LDAP USERNAME %s \r\n" \
542 #at this point sliver may be empty if no iotlab job
543 #is running for this user/slice.
544 rspec = RSpec(version=rspec_version, user_options=options)
546 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
547 slice_xrn %s slices %s\r\n \r\n"
548 % (slice_xrn, slices))
550 if options is not None:
551 lease_option = options['list_leases']
553 #If no options are specified, at least print the resources
556 #lease_option = 'all'
558 if lease_option in ['all', 'resources']:
559 #if not options.get('list_leases') or options.get('list_leases')
560 #and options['list_leases'] != 'leases':
561 nodes = self.get_nodes()
563 logger.debug("IotlabAggregate \t lease_option %s \
564 get rspec ******* nodes %s"
565 % (lease_option, nodes))
567 sites_set = set([node['location']['site'] for node in nodes])
569 #In case creating a job, slice_xrn is not set to None
570 rspec.version.add_nodes(nodes)
571 if slice_xrn and slices is not None:
572 # #Get user associated with this slice
573 # #for one_slice in slices :
574 # ldap_username = slices[0]['reg_researchers']
575 # # ldap_username = slices[0]['user']
576 # tmp = ldap_username.split('.')
577 # ldap_username = tmp[1]
578 # # ldap_username = tmp[1].split('_')[0]
580 logger.debug("IotlabAggregate \tget_rspec **** \
581 version type %s ldap_ user %s \r\n" \
582 % (version.type, ldap_username))
583 if version.type == "Iotlab":
584 rspec.version.add_connection_information(
585 ldap_username, sites_set)
587 default_sliver = slivers.get('default_sliver', [])
588 if default_sliver and len(nodes) is not 0:
589 #default_sliver_attribs = default_sliver.get('tags', [])
590 logger.debug("IotlabAggregate \tget_rspec **** \
591 default_sliver%s \r\n" % (default_sliver))
592 for attrib in default_sliver:
593 rspec.version.add_default_sliver_attribute(
594 attrib, default_sliver[attrib])
596 if lease_option in ['all','leases']:
597 leases = self.get_all_leases(ldap_username)
598 rspec.version.add_leases(leases)
599 logger.debug("IotlabAggregate \tget_rspec **** \
600 FINAL RSPEC %s \r\n" % (rspec.toxml()))
603 def get_slivers(self, urns, options={}):
604 """Get slivers of the given slice urns. Slivers contains slice, node and
607 For Iotlab, returns the leases with sliver ids and their allocation
610 :param urns: list of slice urns.
611 :type urns: list of strings
612 :param options: unused
613 :type options: unused
615 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
618 SLICE_KEY = 'slice_hrn' # slice_hrn
622 xrn = IotlabXrn(xrn=urn)
623 if xrn.type == 'sliver':
624 # id: slice_id-node_id
626 sliver_id_parts = xrn.get_sliver_id_parts()
627 slice_id = int(sliver_id_parts[0])
628 node_id = int(sliver_id_parts[1])
629 slice_ids.add(slice_id)
630 node_ids.append(node_id)
635 slice_names.add(xrn.hrn)
638 logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
639 node_ids %s\r\n" % (urns, slice_ids, node_ids))
640 logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
641 \r\n" % (xrn, slice_names))
644 filter_sliver[SLICE_KEY] = list(slice_names)
645 slice_hrn = filter_sliver[SLICE_KEY][0]
647 slice_filter_type = SLICE_KEY
650 # filter['slice_id'] = list(slice_ids)
653 logger.debug("JORDAN SLICE_HRN=%r" % slice_hrn)
654 slices = self.driver.GetSlices(slice_hrn,
656 leases = self.driver.GetLeases({SLICE_KEY:slice_hrn})
657 logger.debug("IotlabAggregate \t get_slivers \
658 slices %s leases %s\r\n" % (slices, leases ))
662 logger.debug("LOIC SLICES = %r" % slices)
663 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__
672 logger.debug("IotlabAggregate \t get_slivers user %s \
675 # construct user key info
676 person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
677 logger.debug("IotlabAggregate \t get_slivers person %s \
679 # name = person['last_name']
680 user['login'] = person['uid']
682 # XXX LOIC !!! if we have more info, let's fill user
684 user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
686 user['keys'] = person['pkey']
690 node_ids = single_slice['node_ids']
691 node_list = self.driver.testbed_shell.GetNodes()
692 # JORDAN REMOVED FILTER so that next check always succeed
693 # {'hostname':single_slice['node_ids']})
694 node_by_hostname = dict([(node['hostname'], node)
695 for node in node_list])
697 logger.warning("\t get_slivers No slivers in slice")
698 # slice['node_ids'] = node_ids
699 # nodes_dict = self.get_slice_nodes(slice, options)
702 for current_lease in leases:
703 for hostname in current_lease['reserved_nodes']:
705 node['slice_id'] = current_lease['slice_id']
706 node['slice_hrn'] = current_lease['slice_hrn']
707 slice_name = current_lease['slice_hrn'].split(".")[1]
708 node['slice_name'] = slice_name
709 index = current_lease['reserved_nodes'].index(hostname)
710 node_id = current_lease['resource_ids'][index]
711 # node['slice_name'] = user['login']
712 # node.update(single_slice)
713 # JORDAN XXX This fails sometimes when hostname not in the list
714 #if hostname in node_by_hostname:
715 more_info = node_by_hostname[hostname]
716 node.update(more_info)
718 # # This can happen when specifying a lease without the resource, then all subsequent calls will fail
719 # logger.debug("Ignored missing hostname for now one")
720 # oar_job_id is the slice_id (lease_id)
721 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
722 current_lease['lease_id'], node_id)
723 node['node_id'] = node_id
724 node['expires'] = current_lease['t_until']
725 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
726 node['urn'] = node['sliver_id']
727 node['services_user'] = [user]
732 def list_resources(self, version = None, options={}):
734 Returns an advertisement Rspec of available resources at this
735 aggregate. This Rspec contains a resource listing along with their
736 description, providing sufficient information for clients to be able to
737 select among available resources.
739 :param options: various options. The valid options are: {boolean
740 geni_compressed <optional>; struct geni_rspec_version { string type;
741 #case insensitive , string version; # case insensitive}} . The only
742 mandatory options if options is specified is geni_rspec_version.
743 :type options: dictionary
745 :returns: On success, the value field of the return struct will contain
746 a geni.rspec advertisment RSpec
747 :rtype: Rspec advertisement in xml.
749 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
750 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
753 version_manager = VersionManager()
754 version = version_manager.get_version(version)
755 rspec_version = version_manager._get_version(version.type,
756 version.version, 'ad')
757 rspec = RSpec(version=rspec_version, user_options=options)
758 # variable ldap_username to be compliant with get_all_leases
759 # prototype. Now unused in geni-v3 since we are getting all the leases
762 if not options.get('list_leases') or options['list_leases'] != 'leases':
764 nodes_dict = self.get_nodes(options)
766 # no interfaces on iotlab nodes
767 # convert nodes to rspec nodes
769 for node_id in nodes_dict:
770 node = nodes_dict[node_id]
771 rspec_node = self.node_to_rspec_node(node)
772 rspec_nodes.append(rspec_node)
773 rspec.version.add_nodes(rspec_nodes)
776 # links = self.get_links(sites, nodes_dict, interfaces)
777 # rspec.version.add_links(links)
779 if not options.get('list_leases') or options.get('list_leases') \
780 and options['list_leases'] != 'resources':
781 leases = self.get_all_leases(ldap_username)
782 rspec.version.add_leases(leases)
787 def describe(self, urns, version=None, options={}):
789 Retrieve a manifest RSpec describing the resources contained by the
790 named entities, e.g. a single slice or a set of the slivers in a slice.
791 This listing and description should be sufficiently descriptive to allow
792 experimenters to use the resources.
794 :param urns: If a slice urn is supplied and there are no slivers in the
795 given slice at this aggregate, then geni_rspec shall be a valid
796 manifest RSpec, containing no node elements - no resources.
797 :type urns: list or strings
798 :param options: various options. the valid options are: {boolean
799 geni_compressed <optional>; struct geni_rspec_version { string type;
800 #case insensitive , string version; # case insensitive}}
801 :type options: dictionary
803 :returns: On success returns the following dictionary {geni_rspec:
804 <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
805 containing slice>, geni_slivers:{ geni_sliver_urn:
806 <string sliver urn>, geni_expires: <dateTime.rfc3339 allocation
807 expiration string, as in geni_expires from SliversStatus>,
808 geni_allocation_status: <string sliver state - e.g. geni_allocated
809 or geni_provisioned >, geni_operational_status:
810 <string sliver operational state>, geni_error: <optional string.
811 The field may be omitted entirely but may not be null/None,
812 explaining any failure for a sliver.>}
814 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
815 .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
817 version_manager = VersionManager()
818 version = version_manager.get_version(version)
819 rspec_version = version_manager._get_version(
820 version.type, version.version, 'manifest')
821 rspec = RSpec(version=rspec_version, user_options=options)
825 slivers = self.get_slivers(urns, options)
826 logger.debug("SLIVERS=%r" % slivers)
828 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
830 rspec_expires = datetime_to_string(utcparse(time.time()))
831 rspec.xml.set('expires', rspec_expires)
833 # lookup the sliver allocations
835 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
836 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
837 query = self.driver.api.dbsession().query(SliverAllocation)
838 sliver_allocations = query.filter((constraint)).all()
839 sliver_allocation_dict = {}
840 for sliver_allocation in sliver_allocations:
841 geni_urn = sliver_allocation.slice_urn
842 sliver_allocation_dict[sliver_allocation.sliver_id] = \
844 show_leases = options.get('list_leases')
845 if show_leases in ['resources', 'all']:
846 #if not options.get('list_leases') or options['list_leases'] != 'leases':
849 for sliver in slivers:
850 nodes_dict[sliver['node_id']] = sliver
852 for sliver in slivers:
853 rspec_node = self.sliver_to_rspec_node(sliver,
854 sliver_allocation_dict)
855 rspec_nodes.append(rspec_node)
856 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
857 sliver_allocation_dict)
858 geni_slivers.append(geni_sliver)
859 rspec.version.add_nodes(rspec_nodes)
861 logger.debug("SHOW LEASES = %r" % show_leases)
862 if show_leases in ['leases', 'all']:
863 #if not options.get('list_leases') or options['list_leases'] == 'resources':
865 leases = self.get_leases(slice=slivers[0])
866 logger.debug("JORDAN: getting leases from slice: %r" % slivers[0])
867 rspec.version.add_leases(leases)
869 return {'geni_urn': geni_urn,
870 'geni_rspec': rspec.toxml(),
871 'geni_slivers': geni_slivers}