Allocate, Describe, Provision now working for iotlab.
[sfa.git] / sfa / iotlab / iotlabaggregate.py
1 """
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.
5 """
6 from sfa.util.sfatime import utcparse, datetime_to_string
7 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, get_authority
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
23 import time
24
25 class IotlabAggregate:
26     """Aggregate manager class for Iotlab. """
27
28     sites = {}
29     nodes = {}
30     api = None
31     interfaces = {}
32     links = {}
33     node_tags = {}
34
35     prepared = False
36
37     user_options = {}
38
39     def __init__(self, driver):
40         self.driver = driver
41
42     def get_slice_and_slivers(self, slice_xrn, login=None):
43         """
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.
50             Called by get_rspec.
51
52
53         :param slice_xrn: xrn of the slice
54         :param login: user's login on iotlab ldap
55
56         :type slice_xrn: string
57         :type login: string
58         :returns: a list of slices dict and a list of Sliver object
59         :rtype: (list, list)
60
61         .. note: There is no real slivers in iotlab, only leases. The goal
62             is to be consistent with the SFA standard.
63
64         """
65         slivers = {}
66         sfa_slice = None
67         if slice_xrn is None:
68             return (sfa_slice, slivers)
69         slice_urn = hrn_to_urn(slice_xrn, 'slice')
70         slice_hrn, _ = urn_to_hrn(slice_xrn)
71         slice_name = slice_hrn
72
73         # GetSlices always returns a list, even if there is only one element
74         slices = self.driver.testbed_shell.GetSlices(slice_filter=str(slice_name),
75                                                   slice_filter_type='slice_hrn',
76                                                   login=login)
77
78         logger.debug("IotlabAggregate api \tget_slice_and_slivers \
79                       slice_hrn %s \r\n slices %s self.driver.hrn %s"
80                      % (slice_hrn, slices, self.driver.hrn))
81         if slices == []:
82             return (sfa_slice, slivers)
83
84         # sort slivers by node id , if there is a job
85         #and therefore, node allocated to this slice
86         # for sfa_slice in slices:
87         sfa_slice = slices[0]
88         try:
89             node_ids_list = sfa_slice['node_ids']
90         except KeyError:
91             logger.log_exc("IOTLABAGGREGATE \t \
92                         get_slice_and_slivers No nodes in the slice \
93                         - KeyError ")
94             node_ids_list = []
95             # continue
96
97         for node in node_ids_list:
98             sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
99             sliver_xrn.set_authority(self.driver.hrn)
100             sliver = Sliver({'sliver_id': sliver_xrn.urn,
101                             'name': sfa_slice['hrn'],
102                             'type': 'iotlab-node',
103                             'tags': []})
104
105             slivers[node] = sliver
106
107         #Add default sliver attribute :
108         #connection information for iotlab
109         # if get_authority(sfa_slice['hrn']) == self.driver.testbed_shell.root_auth:
110         #     tmp = sfa_slice['hrn'].split('.')
111         #     ldap_username = tmp[1].split('_')[0]
112         #     ssh_access = None
113         #     slivers['default_sliver'] = {'ssh': ssh_access,
114         #                                  'login': ldap_username}
115         # look in ldap:
116         ldap_username = self.find_ldap_username_from_slice(sfa_slice)
117
118         if ldap_username is not None:
119             ssh_access = None
120             slivers['default_sliver'] = {'ssh': ssh_access,
121                                              'login': ldap_username}
122
123
124         logger.debug("IOTLABAGGREGATE api get_slice_and_slivers  slivers %s "
125                      % (slivers))
126         return (slices, slivers)
127
128     def find_ldap_username_from_slice(self, sfa_slice):
129         researchers = [sfa_slice['reg_researchers'][0].__dict__]
130         # look in ldap:
131         ldap_username = None
132         ret =  self.driver.testbed_shell.GetPersons(researchers)
133         if len(ret) != 0:
134             ldap_username = ret[0]['uid']
135
136         return ldap_username
137
138
139
140     def get_nodes(self, slices=None, slivers=[], options=None):
141     # def node_to_rspec_node(self, node, sites, node_tags,
142     #     grain=None, options={}):
143         """Returns the nodes in the slice using the rspec format, with all the
144         nodes' properties.
145
146         Fetch the nodes ids in the slices dictionary and get all the nodes
147         properties from OAR. Makes a rspec dicitonary out of this and returns
148         it. If the slice does not have any job running or scheduled, that is
149         it has no reserved nodes, then returns an empty list.
150
151         :param slices: list of slices (record dictionaries)
152         :param slivers: the list of slivers in all the slices
153         :type slices: list of dicts
154         :type slivers: list of Sliver object (dictionaries)
155         :returns: An empty list if the slice has no reserved nodes, a rspec
156             list with all the nodes and their properties (a dict per node)
157             otherwise.
158         :rtype: list
159
160         .. seealso:: get_slice_and_slivers
161
162         """
163
164         # NT: the semantic of this function is not clear to me :
165         # if slice is not defined, then all the nodes should be returned
166         # if slice is defined, we should return only the nodes that
167         # are part of this slice
168         # but what is the role of the slivers parameter ?
169         # So i assume that slice['node_ids'] will be the same as slivers for us
170         filter_nodes = None
171         if options:
172             geni_available = options.get('geni_available')
173             if geni_available == True:
174                 filter_nodes['boot_state'] = ['Alive']
175
176         # slice_nodes_list = []
177         # if slices is not None:
178         #     for one_slice in slices:
179         #         try:
180         #             slice_nodes_list = one_slice['node_ids']
181         #              # if we are dealing with a slice that has no node just
182         #              # return an empty list. In iotlab a slice can have multiple
183         #              # jobs scheduled, so it either has at least one lease or
184         #              # not at all.
185         #         except KeyError:
186         #             return []
187
188         # get the granularity in second for the reservation system
189         # grain = self.driver.testbed_shell.GetLeaseGranularity()
190
191         nodes = self.driver.testbed_shell.GetNodes()
192
193         nodes_dict = {}
194
195         #if slices, this means we got to list all the nodes given to this slice
196         # Make a list of all the nodes in the slice before getting their
197         #attributes
198         # rspec_nodes = []
199
200         # logger.debug("IOTLABAGGREGATE api get_nodes slices  %s "
201                      # % (slices))
202
203         # reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
204         # logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list  %s "
205                      # % (slice_nodes_list))
206         for node in nodes:
207             nodes_dict[node['node_id']] = node
208             # if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
209
210             #     rspec_node = IotlabNode()
211             #     # xxx how to retrieve site['login_base']
212             #     #site_id=node['site_id']
213             #     #site=sites_dict[site_id]
214
215             #     rspec_node['mobile'] = node['mobile']
216             #     rspec_node['archi'] = node['archi']
217             #     rspec_node['radio'] = node['radio']
218
219             #     iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
220             #                                    node['hostname'])
221             #     rspec_node['component_id'] = iotlab_xrn.urn
222             #     rspec_node['component_name'] = node['hostname']
223             #     rspec_node['component_manager_id'] = \
224             #                     hrn_to_urn(self.driver.testbed_shell.root_auth,
225             #                     'authority+sa')
226
227             #     # Iotlab's nodes are federated : there is only one authority
228             #     # for all Iotlab sites, registered in SFA.
229             #     # Removing the part including the site
230             #     # in authority_id SA 27/07/12
231             #     rspec_node['authority_id'] = rspec_node['component_manager_id']
232
233             #     # do not include boot state (<available> element)
234             #     #in the manifest rspec
235
236
237             #     rspec_node['boot_state'] = node['boot_state']
238             #     if node['hostname'] in reserved_nodes:
239             #         rspec_node['boot_state'] = "Reserved"
240             #     rspec_node['exclusive'] = 'true'
241             #     rspec_node['hardware_types'] = [HardwareType({'name': \
242             #                                     'iotlab-node'})]
243
244
245             #     location = IotlabLocation({'country':'France', 'site': \
246             #                                 node['site']})
247             #     rspec_node['location'] = location
248
249
250             #     position = IotlabPosition()
251             #     for field in position :
252             #         try:
253             #             position[field] = node[field]
254             #         except KeyError, error :
255             #             logger.log_exc("IOTLABAGGREGATE\t get_nodes \
256             #                                             position %s "% (error))
257
258             #     rspec_node['position'] = position
259             #     #rspec_node['interfaces'] = []
260
261             #     # Granularity
262             #     granularity = Granularity({'grain': grain})
263             #     rspec_node['granularity'] = granularity
264             #     rspec_node['tags'] = []
265             #     if node['hostname'] in slivers:
266             #         # add sliver info
267             #         sliver = slivers[node['hostname']]
268             #         rspec_node['sliver_id'] = sliver['sliver_id']
269             #         rspec_node['client_id'] = node['hostname']
270             #         rspec_node['slivers'] = [sliver]
271
272             #         # slivers always provide the ssh service
273             #         login = Login({'authentication': 'ssh-keys', \
274             #                 'hostname': node['hostname'], 'port':'22', \
275             #                 'username': sliver['name']})
276             #         service = Services({'login': login})
277             #         rspec_node['services'] = [service]
278             #     rspec_nodes.append(rspec_node)
279
280         # return (rspec_nodes)
281         return nodes_dict
282
283     def node_to_rspec_node(self, node):
284
285         grain = self.driver.testbed_shell.GetLeaseGranularity()
286
287         rspec_node = IotlabNode()
288         # xxx how to retrieve site['login_base']
289         #site_id=node['site_id']
290         #site=sites_dict[site_id]
291
292         rspec_node['mobile'] = node['mobile']
293         rspec_node['archi'] = node['archi']
294         rspec_node['radio'] = node['radio']
295
296         iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
297                                        node['hostname'])
298         rspec_node['component_id'] = iotlab_xrn.urn
299         rspec_node['component_name'] = node['hostname']
300         rspec_node['component_manager_id'] = \
301                         hrn_to_urn(self.driver.testbed_shell.root_auth,
302                         'authority+sa')
303
304         # Iotlab's nodes are federated : there is only one authority
305         # for all Iotlab sites, registered in SFA.
306         # Removing the part including the site
307         # in authority_id SA 27/07/12
308         rspec_node['authority_id'] = rspec_node['component_manager_id']
309
310         # do not include boot state (<available> element)
311         #in the manifest rspec
312
313
314         rspec_node['boot_state'] = node['boot_state']
315         # if node['hostname'] in reserved_nodes:
316         #     rspec_node['boot_state'] = "Reserved"
317         rspec_node['exclusive'] = 'true'
318         rspec_node['hardware_types'] = [HardwareType({'name': \
319                                         'iotlab-node'})]
320
321         location = IotlabLocation({'country':'France', 'site': \
322                                     node['site']})
323         rspec_node['location'] = location
324
325
326         position = IotlabPosition()
327         for field in position :
328             try:
329                 position[field] = node[field]
330             except KeyError, error :
331                 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
332                                                 position %s "% (error))
333
334         rspec_node['position'] = position
335
336
337         # Granularity
338         granularity = Granularity({'grain': grain})
339         rspec_node['granularity'] = granularity
340         rspec_node['tags'] = []
341         # if node['hostname'] in slivers:
342         #     # add sliver info
343         #     sliver = slivers[node['hostname']]
344         #     rspec_node['sliver_id'] = sliver['sliver_id']
345         #     rspec_node['client_id'] = node['hostname']
346         #     rspec_node['slivers'] = [sliver]
347
348         #     # slivers always provide the ssh service
349         #     login = Login({'authentication': 'ssh-keys', \
350         #             'hostname': node['hostname'], 'port':'22', \
351         #             'username': sliver['name']})
352         #     service = Services({'login': login})
353         #     rspec_node['services'] = [service]
354
355         return rspec_node
356
357
358     def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
359         if rspec_node['sliver_id'] in sliver_allocations:
360             # set sliver allocation and operational status
361             sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
362             if sliver_allocation:
363                 allocation_status = sliver_allocation.allocation_state
364                 if allocation_status == 'geni_allocated':
365                     op_status =  'geni_pending_allocation'
366                 elif allocation_status == 'geni_provisioned':
367                     op_status = 'geni_ready'
368                 else:
369                     op_status = 'geni_unknown'
370             else:
371                 allocation_status = 'geni_unallocated'
372         else:
373             allocation_status = 'geni_unallocated'
374             op_status = 'geni_failed'
375         # required fields
376         geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
377                        'geni_expires': rspec_node['expires'],
378                        'geni_allocation_status' : allocation_status,
379                        'geni_operational_status': op_status,
380                        'geni_error': '',
381                        }
382         return geni_sliver
383
384
385     def sliver_to_rspec_node(self, sliver, sliver_allocations):
386         rspec_node = self.node_to_rspec_node(sliver)
387         rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
388         # add sliver info
389         logger.debug("IOTLABAGGREGATE api \t  sliver_to_rspec_node sliverr  %s \r\nsliver_allocations %s"
390                       % (sliver, sliver_allocations))
391         rspec_sliver = Sliver({'sliver_id': sliver['urn'],
392                          'name': sliver['slice_id'],
393                          'type': 'iotlab-exclusive',
394                          'tags': []})
395         rspec_node['sliver_id'] = rspec_sliver['sliver_id']
396         if sliver['urn'] in sliver_allocations:
397             rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
398             if sliver_allocations[sliver['urn']].component_id:
399                 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
400         rspec_node['slivers'] = [rspec_sliver]
401
402         # slivers always provide the ssh service
403         login = Login({'authentication': 'ssh-keys',
404                        'hostname': sliver['hostname'],
405                        'port':'22',
406                        'username': sliver['slice_name'],
407                        'login': sliver['slice_name']
408                       })
409         return rspec_node
410
411
412     def get_all_leases(self, ldap_username):
413         """
414
415         Get list of lease dictionaries which all have the mandatory keys
416         ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
417         All the leases running or scheduled are returned.
418
419         :param ldap_username: if ldap uid is not None, looks for the leases
420         belonging to this user.
421         :type ldap_username: string
422         :returns: rspec lease dictionary with keys lease_id, component_id,
423             slice_id, start_time, duration.
424         :rtype: dict
425
426         .. note::There is no filtering of leases within a given time frame.
427             All the running or scheduled leases are returned. options
428             removed SA 15/05/2013
429
430
431         """
432
433         #now = int(time.time())
434         #lease_filter = {'clip': now }
435
436         #if slice_record:
437             #lease_filter.update({'name': slice_record['name']})
438
439         #leases = self.driver.testbed_shell.GetLeases(lease_filter)
440
441         logger.debug("IOTLABAGGREGATE  get_all_leases ldap_username %s "
442                      % (ldap_username))
443         leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
444         grain = self.driver.testbed_shell.GetLeaseGranularity()
445         # site_ids = []
446         rspec_leases = []
447         for lease in leases:
448             #as many leases as there are nodes in the job
449             for node in lease['reserved_nodes']:
450                 rspec_lease = Lease()
451                 rspec_lease['lease_id'] = lease['lease_id']
452                 #site = node['site_id']
453                 iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
454                                                node)
455                 rspec_lease['component_id'] = iotlab_xrn.urn
456                 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
457                                         #site, node['hostname'])
458                 try:
459                     rspec_lease['slice_id'] = lease['slice_id']
460                 except KeyError:
461                     #No info on the slice used in testbed_xp table
462                     pass
463                 rspec_lease['start_time'] = lease['t_from']
464                 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
465                      / grain
466                 rspec_leases.append(rspec_lease)
467         return rspec_leases
468
469     def get_rspec(self, slice_xrn=None, login=None, version=None,
470                   options=None):
471         """
472         Returns xml rspec:
473         - a full advertisement rspec with the testbed resources if slice_xrn is
474         not specified.If a lease option is given, also returns the leases
475         scheduled on the testbed.
476         - a manifest Rspec with the leases and nodes in slice's leases if
477         slice_xrn is not None.
478
479         :param slice_xrn: srn of the slice
480         :type slice_xrn: string
481         :param login: user'uid (ldap login) on iotlab
482         :type login: string
483         :param version: can be set to sfa or iotlab
484         :type version: RSpecVersion
485         :param options: used to specify if the leases should also be included in
486             the returned rspec.
487         :type options: dict
488
489         :returns: Xml Rspec.
490         :rtype: XML
491
492
493         """
494
495         ldap_username= None
496         rspec = None
497         version_manager = VersionManager()
498         version = version_manager.get_version(version)
499         logger.debug("IotlabAggregate \t get_rspec ***version %s \
500                     version.type %s  version.version %s options %s \r\n"
501                      % (version, version.type, version.version, options))
502
503         if slice_xrn is None:
504             rspec_version = version_manager._get_version(version.type,
505                                                          version.version, 'ad')
506
507         else:
508             rspec_version = version_manager._get_version(
509                 version.type, version.version, 'manifest')
510
511         slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
512         if slice_xrn and slices is not None:
513             #Get user associated with this slice
514             #for one_slice in slices :
515             ldap_username = self.find_ldap_username_from_slice(slices[0])
516             # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
517             #  # ldap_username = slices[0]['user']
518             # tmp = ldap_username.split('.')
519             # ldap_username = tmp[1]
520             logger.debug("IotlabAggregate \tget_rspec **** \
521                     LDAP USERNAME %s \r\n" \
522                     % (ldap_username))
523         #at this point sliver may be empty if no iotlab job
524         #is running for this user/slice.
525         rspec = RSpec(version=rspec_version, user_options=options)
526
527         logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
528                       slice_xrn %s slices  %s\r\n \r\n"
529                      % (slice_xrn, slices))
530
531         if options is not None:
532             lease_option = options['list_leases']
533         else:
534             #If no options are specified, at least print the resources
535             lease_option = 'all'
536            #if slice_xrn :
537                #lease_option = 'all'
538
539         if lease_option in ['all', 'resources']:
540         #if not options.get('list_leases') or options.get('list_leases')
541         #and options['list_leases'] != 'leases':
542             nodes = self.get_nodes(slices, slivers)
543             logger.debug("\r\n")
544             logger.debug("IotlabAggregate \t lease_option %s \
545                           get rspec  ******* nodes %s"
546                          % (lease_option, nodes))
547
548             sites_set = set([node['location']['site'] for node in nodes])
549
550             #In case creating a job,  slice_xrn is not set to None
551             rspec.version.add_nodes(nodes)
552             if slice_xrn and slices is not None:
553             #     #Get user associated with this slice
554             #     #for one_slice in slices :
555             #     ldap_username = slices[0]['reg_researchers']
556             #      # ldap_username = slices[0]['user']
557             #     tmp = ldap_username.split('.')
558             #     ldap_username = tmp[1]
559             #      # ldap_username = tmp[1].split('_')[0]
560
561                 logger.debug("IotlabAggregate \tget_rspec **** \
562                         version type %s ldap_ user %s \r\n" \
563                         % (version.type, ldap_username))
564                 if version.type == "Iotlab":
565                     rspec.version.add_connection_information(
566                         ldap_username, sites_set)
567
568             default_sliver = slivers.get('default_sliver', [])
569             if default_sliver and len(nodes) is not 0:
570                 #default_sliver_attribs = default_sliver.get('tags', [])
571                 logger.debug("IotlabAggregate \tget_rspec **** \
572                         default_sliver%s \r\n" % (default_sliver))
573                 for attrib in default_sliver:
574                     rspec.version.add_default_sliver_attribute(
575                         attrib, default_sliver[attrib])
576
577         if lease_option in ['all','leases']:
578             leases = self.get_all_leases(ldap_username)
579             rspec.version.add_leases(leases)
580             logger.debug("IotlabAggregate \tget_rspec **** \
581                        FINAL RSPEC %s \r\n" % (rspec.toxml()))
582         return rspec.toxml()
583
584     def get_slivers(self, urns, options={}):
585         """
586
587         """
588
589
590         slice_ids = set()
591         node_ids = []
592         for urn in urns:
593             xrn = IotlabXrn(xrn=urn)
594             if xrn.type == 'sliver':
595                  # id: slice_id-node_id
596                 try:
597                     sliver_id_parts = xrn.get_sliver_id_parts()
598                     slice_id = int(sliver_id_parts[0])
599                     node_id = int(sliver_id_parts[1])
600                     slice_ids.add(slice_id)
601                     node_ids.append(node_id)
602                 except ValueError:
603                     pass
604             else:
605                 slice_names = set()
606                 slice_names.add(xrn.hrn)
607
608
609         logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
610                        node_ids %s\r\n" % (urns, slice_ids, node_ids))
611         logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
612                        \r\n" % (xrn, slice_names))
613         filter = {}
614         if slice_names:
615             filter['slice_hrn'] = list(slice_names)
616             slice_hrn = filter['slice_hrn'][0]
617
618             slice_filter_type = 'slice_hrn'
619             logger.debug("IotlabAggregate \t get_slivers  slice_hrn%s \
620                        \r\n" % (slice_hrn ))
621         # if slice_ids:
622         #     filter['slice_id'] = list(slice_ids)
623         # # get slices
624         if slice_hrn:
625             slices = self.driver.testbed_shell.GetSlices(slice_hrn,
626                 slice_filter_type)
627             leases = self.driver.testbed_shell.GetLeases(
628                                                 {'slice_hrn':slice_hrn})
629         logger.debug("IotlabAggregate \t get_slivers \
630                        slices %s leases %s\r\n" % (slices, leases ))
631         if not slices:
632             return []
633         # slice = slices[0]
634         # slice['hrn'] = DummyXrn(auth=self.driver.hrn, slicename=slice['slice_name']).hrn
635         single_slice = slices[0]
636         # get sliver users
637         # users = []
638         # user_ids = []
639         # for slice in slices:
640         #     user_ids.extend(slice['user_ids'])
641         # if user_ids:
642         #     users = self.driver.shell.GetUsers({'user_ids': user_ids})
643
644         user = single_slice['reg_researchers'][0].__dict__
645         logger.debug("IotlabAggregate \t get_slivers user %s \
646                        \r\n" % (user))
647
648         # construct user key info
649         # users_list = []
650         # for user in users:
651         person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
652         logger.debug("IotlabAggregate \t get_slivers person %s \
653                        \r\n" % (person))
654         name = person['last_name']
655         user['login'] = person['uid']
656         user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
657         user['keys'] = person['pkey']
658             # name = user['email'][0:user['email'].index('@')]
659             # user = {
660             #     'login': slice['slice_name'],
661             #     'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
662             #     'keys': user['keys']
663             # }
664             # users_list.append(user)
665
666         try:
667             node_ids = single_slice['node_ids']
668             node_list = self.driver.testbed_shell.GetNodes(
669                     {'hostname':single_slice['node_ids']})
670             node_by_hostname = dict([(node['hostname'], node) for node in node_list])
671         except KeyError:
672             logger.warning("\t get_slivers No slivers in slice")
673             # slice['node_ids'] = node_ids
674         # nodes_dict = self.get_slice_nodes(slice, options)
675         logger.debug("IotlabAggregate \t get_slivers  node_by_hostname%s \
676                        \r\n" % (node_by_hostname))
677         slivers = []
678         for current_lease in leases:
679             for hostname in current_lease['reserved_nodes']:
680                 node = {}
681                 node['slice_id'] = current_lease['slice_id']
682                 node['slice_hrn'] = current_lease['slice_hrn']
683                 slice_name = current_lease['slice_hrn'].split(".")[1]
684                 node['slice_name'] = slice_name
685                 index = current_lease['reserved_nodes'].index(hostname)
686                 node_id = current_lease['resource_ids'][index]
687                 # node['slice_name'] = user['login']
688                 # node.update(single_slice)
689                 more_info = node_by_hostname[hostname]
690                 node.update(more_info)
691                 # oar_job_id is the slice_id (lease_id)
692                 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
693                             current_lease['lease_id'], node_id)
694                 node['node_id'] = node_id
695                 node['expires'] = current_lease['t_until']
696                 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
697                 node['urn'] = node['sliver_id']
698                 node['services_user'] = [user]
699                 logger.debug("IotlabAggregate \t get_slivers node %s current_lease %s\
700                        \r\n more_info %s" % (node, current_lease, more_info))
701                 slivers.append(node)
702         return slivers
703
704     def list_resources(self, version = None, options={}):
705
706         version_manager = VersionManager()
707         version = version_manager.get_version(version)
708         rspec_version = version_manager._get_version(version.type, version.version, 'ad')
709         rspec = RSpec(version=rspec_version, user_options=options)
710         # variable ldap_username to be compliant with the get_all_leases
711         # prototype. Now unused in geni-v3 since we are getting all the leases
712         # here
713         ldap_username = None
714         if not options.get('list_leases') or options['list_leases'] != 'leases':
715             # get nodes
716             nodes_dict  = self.get_nodes(options)
717             # site_ids = []
718             # interface_ids = []
719             # tag_ids = []
720             # nodes_dict = {}
721             # for node in nodes:
722             #     site_ids.append(node['site_id'])
723             #     interface_ids.extend(node['interface_ids'])
724             #     tag_ids.extend(node['node_tag_ids'])
725             #     nodes_dict[node['node_id']] = node
726             # sites = self.get_sites({'site_id': site_ids})
727             # interfaces = self.get_interfaces({'interface_id':interface_ids})
728             # node_tags = self.get_node_tags({'node_tag_id': tag_ids})
729             # pl_initscripts = self.get_pl_initscripts()
730             # convert nodes to rspec nodes
731             rspec_nodes = []
732             for node_id in nodes_dict:
733                 node = nodes_dict[node_id]
734                 # rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
735                 rspec_node = self.node_to_rspec_node(node)
736                 rspec_nodes.append(rspec_node)
737             rspec.version.add_nodes(rspec_nodes)
738
739             # add links
740             # links = self.get_links(sites, nodes_dict, interfaces)
741             # rspec.version.add_links(links)
742
743         if not options.get('list_leases') or options.get('list_leases') \
744             and options['list_leases'] != 'resources':
745             leases = self.get_all_leases(ldap_username)
746             rspec.version.add_leases(leases)
747
748         return rspec.toxml()
749
750
751     def describe(self, urns, version=None, options={}):
752         """
753         Retrieve a manifest RSpec describing the resources contained by the
754         named entities, e.g. a single slice or a set of the slivers in a slice.
755         This listing and description should be sufficiently descriptive to allow
756         experimenters to use the resources.
757
758         returns: On success returns the following struct:
759         {
760            geni_rspec: <geni.rspec, a Manifest RSpec>
761            geni_urn: <string slice urn of the containing slice>
762            geni_slivers:{
763                           geni_sliver_urn: <string sliver urn>
764                           geni_expires:  <dateTime.rfc3339
765                           allocation expiration string, as in geni_expires
766                           from SliversStatus>,
767                           geni_allocation_status: <string sliver state -
768                           e.g. geni_allocated or geni_provisioned >,
769                           geni_operational_status: <string sliver operational
770                           state>,
771                           geni_error: <optional string. The field may be omitted
772                            entirely but may not be null/None, explaining any
773                            failure for a sliver.>
774                        },
775                  ]}
776         .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
777         """
778         version_manager = VersionManager()
779         version = version_manager.get_version(version)
780         rspec_version = version_manager._get_version(
781                                     version.type, version.version, 'manifest')
782         rspec = RSpec(version=rspec_version, user_options=options)
783
784         # get slivers
785         geni_slivers = []
786         slivers = self.get_slivers(urns, options)
787         if slivers:
788             rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
789         else:
790             rspec_expires = datetime_to_string(utcparse(time.time()))
791         rspec.xml.set('expires',  rspec_expires)
792
793         # lookup the sliver allocations
794         geni_urn = urns[0]
795         sliver_ids = [sliver['sliver_id'] for sliver in slivers]
796         logger.debug(" IOTLAB_API.PY \tDescribe  sliver_ids %s "
797                      % (sliver_ids))
798         constraint = SliverAllocation.sliver_id.in_(sliver_ids)
799         logger.debug(" IOTLAB_API.PY \tDescribe  constraint %s "
800                      % (constraint))
801         sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).filter((constraint)).all()
802         logger.debug(" IOTLAB_API.PY \tDescribe  sliver_allocations %s "
803                      % (sliver_allocations))
804         sliver_allocation_dict = {}
805         for sliver_allocation in sliver_allocations:
806             geni_urn = sliver_allocation.slice_urn
807             sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
808
809         # add slivers
810         nodes_dict = {}
811         for sliver in slivers:
812             nodes_dict[sliver['node_id']] = sliver
813         rspec_nodes = []
814         for sliver in slivers:
815             rspec_node = self.sliver_to_rspec_node(sliver, sliver_allocation_dict)
816             rspec_nodes.append(rspec_node)
817             logger.debug(" IOTLAB_API.PY \tDescribe  sliver_allocation_dict %s "
818                      % (sliver_allocation_dict))
819             geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
820             geni_slivers.append(geni_sliver)
821
822         logger.debug(" IOTLAB_API.PY \tDescribe rspec_nodes %s\
823                         rspec %s "
824                      % (rspec_nodes, rspec))
825         rspec.version.add_nodes(rspec_nodes)
826
827         return {'geni_urn': geni_urn,
828                 'geni_rspec': rspec.toxml(),
829                 'geni_slivers': geni_slivers}