fixing getslices (sfi show node_ids was empty when done on a slice)
[sfa.git] / sfa / iotlab / iotlabapi.py
1 """
2 File containing the IotlabTestbedAPI, used to interact with nodes, users,
3 slices, leases and keys,  as well as the dedicated iotlab database and table,
4 holding information about which slice is running which job.
5
6 """
7 from datetime import datetime
8
9 from sfa.util.sfalogging import logger
10
11 from sfa.storage.alchemy import dbsession
12 from sqlalchemy.orm import joinedload
13 from sfa.storage.model import RegRecord, RegUser, RegSlice, RegKey
14 from sfa.iotlab.iotlabpostgres import IotlabDB, IotlabXP
15 from sfa.iotlab.OARrestapi import OARrestapi
16 from sfa.iotlab.LDAPapi import LDAPapi
17
18 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority
19
20 from sfa.trust.certificate import Keypair, convert_public_key
21 from sfa.trust.gid import create_uuid
22 from sfa.trust.hierarchy import Hierarchy
23
24 from sfa.iotlab.iotlabaggregate import iotlab_xrn_object
25
26 class IotlabTestbedAPI():
27     """ Class enabled to use LDAP and OAR api calls. """
28
29     _MINIMUM_DURATION = 600
30
31     def __init__(self, config):
32         """Creates an instance of OARrestapi and LDAPapi which will be used to
33         issue calls to OAR or LDAP methods.
34         Set the time format  and the testbed granularity used for OAR
35         reservation and leases.
36
37         :param config: configuration object from sfa.util.config
38         :type config: Config object
39         """
40         self.iotlab_db = IotlabDB(config)
41         self.oar = OARrestapi()
42         self.ldap = LDAPapi()
43         self.time_format = "%Y-%m-%d %H:%M:%S"
44         self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
45         self.grain = 1  # 10 mins lease minimum, 1 sec granularity
46         #import logging, logging.handlers
47         #from sfa.util.sfalogging import _SfaLogger
48         #sql_logger = _SfaLogger(loggername = 'sqlalchemy.engine', \
49                                                     #level=logging.DEBUG)
50         return
51
52     @staticmethod
53     def GetMinExperimentDurationInSec():
54         """ Returns the minimum allowed duration for an experiment on the
55         testbed. In seconds.
56
57         """
58         return IotlabTestbedAPI._MINIMUM_DURATION
59
60     @staticmethod
61     def GetPeers (peer_filter=None ):
62         """ Gathers registered authorities in SFA DB and looks for specific peer
63         if peer_filter is specified.
64         :param peer_filter: name of the site authority looked for.
65         :type peer_filter: string
66         :returns: list of records.
67
68         """
69
70         existing_records = {}
71         existing_hrns_by_types = {}
72         logger.debug("IOTLABDRIVER \tGetPeers peer_filter %s, \
73                     " %(peer_filter))
74         all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
75
76         for record in all_records:
77             existing_records[(record.hrn, record.type)] = record
78             if record.type not in existing_hrns_by_types:
79                 existing_hrns_by_types[record.type] = [record.hrn]
80             else:
81                 existing_hrns_by_types[record.type].append(record.hrn)
82
83
84         logger.debug("IOTLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
85                                              %( existing_hrns_by_types))
86         records_list = []
87
88         try:
89             if peer_filter:
90                 records_list.append(existing_records[(peer_filter,'authority')])
91             else:
92                 for hrn in existing_hrns_by_types['authority']:
93                     records_list.append(existing_records[(hrn,'authority')])
94
95             logger.debug("IOTLABDRIVER \tGetPeer \trecords_list  %s " \
96                                             %(records_list))
97
98         except KeyError:
99             pass
100
101         return_records = records_list
102         logger.debug("IOTLABDRIVER \tGetPeer return_records %s " \
103                                                     %(return_records))
104         return return_records
105
106
107
108     #TODO  : Handling OR request in make_ldap_filters_from_records
109     #instead of the for loop
110     #over the records' list
111     def GetPersons(self, person_filter=None):
112         """
113         Get the enabled users and their properties from Iotlab LDAP.
114         If a filter is specified, looks for the user whose properties match
115         the filter, otherwise returns the whole enabled users'list.
116         :param person_filter: Must be a list of dictionnaries
117         with users properties when not set to None.
118         :param person_filter: list of dict
119         :returns:Returns a list of users whose accounts are enabled
120         found in ldap.
121         :rtype: list of dicts
122
123         """
124         logger.debug("IOTLABDRIVER \tGetPersons person_filter %s" \
125                                                     %(person_filter))
126         person_list = []
127         if person_filter and isinstance(person_filter, list):
128         #If we are looking for a list of users (list of dict records)
129         #Usually the list contains only one user record
130             for searched_attributes in person_filter:
131
132                 #Get only enabled user accounts in iotlab LDAP :
133                 #add a filter for make_ldap_filters_from_record
134                 person = self.ldap.LdapFindUser(searched_attributes, \
135                                 is_user_enabled=True)
136                 #If a person was found, append it to the list
137                 if person:
138                     person_list.append(person)
139
140             #If the list is empty, return None
141             if len(person_list) is 0:
142                 person_list = None
143
144         else:
145             #Get only enabled user accounts in iotlab LDAP :
146             #add a filter for make_ldap_filters_from_record
147             person_list  = self.ldap.LdapFindUser(is_user_enabled=True)
148
149         return person_list
150
151
152     #def GetTimezone(self):
153         #""" Returns the OAR server time and timezone.
154         #Unused SA 30/05/13"""
155         #server_timestamp, server_tz = self.oar.parser.\
156                                             #SendRequest("GET_timezone")
157         #return server_timestamp, server_tz
158
159     def DeleteJobs(self, job_id, username):
160         """
161
162         Deletes the job with the specified job_id and username on OAR by
163             posting a delete request to OAR.
164
165         :param job_id: job id in OAR.
166         :param username: user's iotlab login in LDAP.
167         :type job_id: integer
168         :type username: string
169
170         :returns: dictionary with the job id and if delete has been successful
171             (True) or no (False)
172         :rtype: dict
173
174         """
175         logger.debug("IOTLABDRIVER \tDeleteJobs jobid  %s username %s "
176                      % (job_id, username))
177         if not job_id or job_id is -1:
178             return
179
180         reqdict = {}
181         reqdict['method'] = "delete"
182         reqdict['strval'] = str(job_id)
183
184         answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id',
185                                                   reqdict, username)
186         if answer['status'] == 'Delete request registered':
187             ret = {job_id: True}
188         else:
189             ret = {job_id: False}
190         logger.debug("IOTLABDRIVER \tDeleteJobs jobid  %s \r\n answer %s \
191                                 username %s" % (job_id, answer, username))
192         return ret
193
194
195
196         ##TODO : Unused GetJobsId ? SA 05/07/12
197     #def GetJobsId(self, job_id, username = None ):
198         #"""
199         #Details about a specific job.
200         #Includes details about submission time, jot type, state, events,
201         #owner, assigned ressources, walltime etc...
202
203         #"""
204         #req = "GET_jobs_id"
205         #node_list_k = 'assigned_network_address'
206         ##Get job info from OAR
207         #job_info = self.oar.parser.SendRequest(req, job_id, username)
208
209         #logger.debug("IOTLABDRIVER \t GetJobsId  %s " %(job_info))
210         #try:
211             #if job_info['state'] == 'Terminated':
212                 #logger.debug("IOTLABDRIVER \t GetJobsId job %s TERMINATED"\
213                                                             #%(job_id))
214                 #return None
215             #if job_info['state'] == 'Error':
216                 #logger.debug("IOTLABDRIVER \t GetJobsId ERROR message %s "\
217                                                             #%(job_info))
218                 #return None
219
220         #except KeyError:
221             #logger.error("IOTLABDRIVER \tGetJobsId KeyError")
222             #return None
223
224         #parsed_job_info  = self.get_info_on_reserved_nodes(job_info, \
225                                                             #node_list_k)
226         ##Replaces the previous entry
227         ##"assigned_network_address" / "reserved_resources"
228         ##with "node_ids"
229         #job_info.update({'node_ids':parsed_job_info[node_list_k]})
230         #del job_info[node_list_k]
231         #logger.debug(" \r\nIOTLABDRIVER \t GetJobsId job_info %s " %(job_info))
232         #return job_info
233
234
235     def GetJobsResources(self, job_id, username = None):
236         """ Gets the list of nodes associated with the job_id and username
237         if provided.
238         Transforms the iotlab hostnames to the corresponding
239         SFA nodes hrns.
240         Rertuns dict key :'node_ids' , value : hostnames list
241         :param username: user's LDAP login
242         :paran job_id: job's OAR identifier.
243         :type username: string
244         :type job_id: integer
245
246         :returns: dicionary with nodes' hostnames belonging to the job.
247         :rtype: dict
248         """
249
250         req = "GET_jobs_id_resources"
251
252
253         #Get job resources list from OAR
254         node_id_list = self.oar.parser.SendRequest(req, job_id, username)
255         logger.debug("IOTLABDRIVER \t GetJobsResources  %s " %(node_id_list))
256
257         hostname_list = \
258             self.__get_hostnames_from_oar_node_ids(node_id_list)
259
260
261         #Replaces the previous entry "assigned_network_address" /
262         #"reserved_resources" with "node_ids"
263         job_info = {'node_ids': hostname_list}
264
265         return job_info
266
267
268     #def get_info_on_reserved_nodes(self, job_info, node_list_name):
269         #"""
270         #..warning:unused  SA 23/05/13
271         #"""
272         ##Get the list of the testbed nodes records and make a
273         ##dictionnary keyed on the hostname out of it
274         #node_list_dict = self.GetNodes()
275         ##node_hostname_list = []
276         #node_hostname_list = [node['hostname'] for node in node_list_dict]
277         ##for node in node_list_dict:
278             ##node_hostname_list.append(node['hostname'])
279         #node_dict = dict(zip(node_hostname_list, node_list_dict))
280         #try :
281             #reserved_node_hostname_list = []
282             #for index in range(len(job_info[node_list_name])):
283                ##job_info[node_list_name][k] =
284                 #reserved_node_hostname_list[index] = \
285                         #node_dict[job_info[node_list_name][index]]['hostname']
286
287             #logger.debug("IOTLABDRIVER \t get_info_on_reserved_nodes \
288                         #reserved_node_hostname_list %s" \
289                         #%(reserved_node_hostname_list))
290         #except KeyError:
291             #logger.error("IOTLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
292
293         #return reserved_node_hostname_list
294
295     def GetNodesCurrentlyInUse(self):
296         """Returns a list of all the nodes already involved in an oar running
297         job.
298         :rtype: list of nodes hostnames.
299         """
300         return self.oar.parser.SendRequest("GET_running_jobs")
301
302     def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
303         """Get the hostnames of the nodes from their OAR identifiers.
304         Get the list of nodes dict using GetNodes and find the hostname
305         associated with the identifier.
306         :param resource_id_list: list of nodes identifiers
307         :returns: list of node hostnames.
308         """
309         full_nodes_dict_list = self.GetNodes()
310         #Put the full node list into a dictionary keyed by oar node id
311         oar_id_node_dict = {}
312         for node in full_nodes_dict_list:
313             oar_id_node_dict[node['oar_id']] = node
314
315         hostname_list = []
316         for resource_id in resource_id_list:
317             #Because jobs requested "asap" do not have defined resources
318             if resource_id is not "Undefined":
319                 hostname_list.append(\
320                         oar_id_node_dict[resource_id]['hostname'])
321
322             #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
323         return hostname_list
324
325     def GetReservedNodes(self, username = None):
326         """ Get list of leases. Get the leases for the username if specified,
327         otherwise get all the leases. Finds the nodes hostnames for each
328         OAR node identifier.
329         :param username: user's LDAP login
330         :type username: string
331         :returns: list of reservations dict
332         :rtype: dict list
333         """
334
335         #Get the nodes in use and the reserved nodes
336         reservation_dict_list = \
337                         self.oar.parser.SendRequest("GET_reserved_nodes", \
338                         username = username)
339
340
341         for resa in reservation_dict_list:
342             logger.debug ("GetReservedNodes resa %s"%(resa))
343             #dict list of hostnames and their site
344             resa['reserved_nodes'] = \
345                 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
346
347         #del resa['resource_ids']
348         return reservation_dict_list
349
350     def GetNodes(self, node_filter_dict = None, return_fields_list = None):
351         """
352
353         Make a list of iotlab nodes and their properties from information
354             given by OAR. Search for specific nodes if some filters are
355             specified. Nodes properties returned if no return_fields_list given:
356             'hrn','archi','mobile','hostname','site','boot_state','node_id',
357             'radio','posx','posy','oar_id','posz'.
358
359         :param node_filter_dict: dictionnary of lists with node properties
360         :type node_filter_dict: dict
361         :param return_fields_list: list of specific fields the user wants to be
362             returned.
363         :type return_fields_list: list
364         :returns: list of dictionaries with node properties
365         :rtype: list
366
367         """
368         node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
369         node_dict_list = node_dict_by_id.values()
370         logger.debug (" IOTLABDRIVER GetNodes  node_filter_dict %s \
371             return_fields_list %s "%(node_filter_dict, return_fields_list))
372         #No  filtering needed return the list directly
373         if not (node_filter_dict or return_fields_list):
374             return node_dict_list
375
376         return_node_list = []
377         if node_filter_dict:
378             for filter_key in node_filter_dict:
379                 try:
380                     #Filter the node_dict_list by each value contained in the
381                     #list node_filter_dict[filter_key]
382                     for value in node_filter_dict[filter_key]:
383                         for node in node_dict_list:
384                             if node[filter_key] == value:
385                                 if return_fields_list :
386                                     tmp = {}
387                                     for k in return_fields_list:
388                                         tmp[k] = node[k]
389                                     return_node_list.append(tmp)
390                                 else:
391                                     return_node_list.append(node)
392                 except KeyError:
393                     logger.log_exc("GetNodes KeyError")
394                     return
395
396
397         return return_node_list
398
399
400
401     @staticmethod
402     def AddSlice(slice_record, user_record):
403         """
404
405         Add slice to the local iotlab sfa tables if the slice comes
406             from a federated site and is not yet in the iotlab sfa DB,
407             although the user has already a LDAP login.
408             Called by verify_slice during lease/sliver creation.
409
410         :param slice_record: record of slice, must contain hrn, gid, slice_id
411             and authority of the slice.
412         :type slice_record: dictionary
413         :param user_record: record of the user
414         :type user_record: RegUser
415
416         """
417
418         sfa_record = RegSlice(hrn=slice_record['hrn'],
419                               gid=slice_record['gid'],
420                               pointer=slice_record['slice_id'],
421                               authority=slice_record['authority'])
422         logger.debug("IOTLABDRIVER.PY AddSlice  sfa_record %s user_record %s"
423                      % (sfa_record, user_record))
424         sfa_record.just_created()
425         dbsession.add(sfa_record)
426         dbsession.commit()
427         #Update the reg-researcher dependance table
428         sfa_record.reg_researchers = [user_record]
429         dbsession.commit()
430
431         return
432
433
434     def GetSites(self, site_filter_name_list=None, return_fields_list=None):
435         """Returns the list of Iotlab's sites with the associated nodes and
436         their properties as dictionaries.
437
438         Uses the OAR request GET_sites to find the Iotlab's sites.
439
440         :param site_filter_name_list: used to specify specific sites
441         :param return_fields_list: field that has to be returned
442         :type site_filter_name_list: list
443         :type return_fields_list: list
444
445         .. warning:: unused
446         """
447         site_dict = self.oar.parser.SendRequest("GET_sites")
448         #site_dict : dict where the key is the sit ename
449         return_site_list = []
450         if not (site_filter_name_list or return_fields_list):
451             return_site_list = site_dict.values()
452             return return_site_list
453
454         for site_filter_name in site_filter_name_list:
455             if site_filter_name in site_dict:
456                 if return_fields_list:
457                     for field in return_fields_list:
458                         tmp = {}
459                         try:
460                             tmp[field] = site_dict[site_filter_name][field]
461                         except KeyError:
462                             logger.error("GetSites KeyError %s " % (field))
463                             return None
464                     return_site_list.append(tmp)
465                 else:
466                     return_site_list.append(site_dict[site_filter_name])
467
468         return return_site_list
469
470
471     #TODO : Check rights to delete person
472     def DeletePerson(self, person_record):
473         """Disable an existing account in iotlab LDAP.
474
475         Users and techs can only delete themselves. PIs can only
476             delete themselves and other non-PIs at their sites.
477             ins can delete anyone.
478
479         :param person_record: user's record
480         :type person_record: dict
481         :returns:  True if successful, False otherwise.
482         :rtype: boolean
483
484         .. todo:: CHECK THAT ONLY THE USER OR ADMIN CAN DEL HIMSELF.
485         """
486         #Disable user account in iotlab LDAP
487         ret = self.ldap.LdapMarkUserAsDeleted(person_record)
488         logger.warning("IOTLABDRIVER DeletePerson %s " % (person_record))
489         return ret['bool']
490
491     def DeleteSlice(self, slice_record):
492         """Deletes the specified slice and kills the jobs associated with
493             the slice if any,  using DeleteSliceFromNodes.
494
495         :param slice_record: record of the slice, must contain oar_job_id, user
496         :type slice_record: dict
497         :returns: True if all the jobs in the slice have been deleted,
498             or the list of jobs that could not be deleted otherwise.
499         :rtype: list or boolean
500
501          .. seealso:: DeleteSliceFromNodes
502
503         """
504         ret = self.DeleteSliceFromNodes(slice_record)
505         delete_failed = None
506         for job_id in ret:
507             if False in ret[job_id]:
508                 if delete_failed is None:
509                     delete_failed = []
510                 delete_failed.append(job_id)
511
512         logger.info("IOTLABDRIVER DeleteSlice %s  answer %s"%(slice_record, \
513                     delete_failed))
514         return delete_failed or True
515
516     @staticmethod
517     def __add_person_to_db(user_dict):
518         """
519         Add a federated user straight to db when the user issues a lease
520         request with iotlab nodes and that he has not registered with iotlab
521         yet (that is he does not have a LDAP entry yet).
522         Uses parts of the routines in SlabImport when importing user from LDAP.
523         Called by AddPerson, right after LdapAddUser.
524         :param user_dict: Must contain email, hrn and pkey to get a GID
525         and be added to the SFA db.
526         :type user_dict: dict
527
528         """
529         check_if_exists = \
530         dbsession.query(RegUser).filter_by(email = user_dict['email']).first()
531         #user doesn't exists
532         if not check_if_exists:
533             logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
534                                             " %(user_dict))
535             hrn = user_dict['hrn']
536             person_urn = hrn_to_urn(hrn, 'user')
537             pubkey = user_dict['pkey']
538             try:
539                 pkey = convert_public_key(pubkey)
540             except TypeError:
541                 #key not good. create another pkey
542                 logger.warn('__add_person_to_db: unable to convert public \
543                                     key for %s' %(hrn ))
544                 pkey = Keypair(create=True)
545
546
547             if pubkey is not None and pkey is not None :
548                 hierarchy = Hierarchy()
549                 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
550                                 pkey)
551                 if user_dict['email']:
552                     logger.debug("__add_person_to_db \r\n \r\n \
553                         IOTLAB IMPORTER PERSON EMAIL OK email %s "\
554                         %(user_dict['email']))
555                     person_gid.set_email(user_dict['email'])
556
557             user_record = RegUser(hrn=hrn , pointer= '-1', \
558                                     authority=get_authority(hrn), \
559                                     email=user_dict['email'], gid = person_gid)
560             user_record.reg_keys = [RegKey(user_dict['pkey'])]
561             user_record.just_created()
562             dbsession.add (user_record)
563             dbsession.commit()
564         return
565
566
567     def AddPerson(self, record):
568         """
569
570         Adds a new account. Any fields specified in records are used,
571             otherwise defaults are used. Creates an appropriate login by calling
572             LdapAddUser.
573
574         :param record: dictionary with the sfa user's properties.
575         :returns: The uid of the added person if sucessful, otherwise returns
576             the error message from LDAP.
577         :rtype: interger or string
578
579         """
580         ret = self.ldap.LdapAddUser(record)
581
582         if ret['bool'] is True:
583             record['hrn'] = self.root_auth + '.' + ret['uid']
584             logger.debug("IOTLABDRIVER AddPerson return code %s record %s \r\n "\
585                                                                 %(ret, record))
586             self.__add_person_to_db(record)
587             return ret['uid']
588         else:
589             return ret['message']
590
591
592
593     #TODO AddPersonKey 04/07/2012 SA
594     def AddPersonKey(self, person_uid, old_attributes_dict, new_key_dict):
595         """Adds a new key to the specified account. Adds the key to the
596             iotlab ldap, provided that the person_uid is valid.
597
598         Non-admins can only modify their own keys.
599
600         :param person_uid: user's iotlab login in LDAP
601         :param old_attributes_dict: dict with the user's old sshPublicKey
602         :param new_key_dict: dict with the user's new sshPublicKey
603         :type person_uid: string
604
605
606         :rtype: Boolean
607         :returns: True if the key has been modified, False otherwise.
608
609         """
610         ret = self.ldap.LdapModify(person_uid, old_attributes_dict, \
611                                                                 new_key_dict)
612         logger.warning("IOTLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
613         return ret['bool']
614
615     def DeleteLeases(self, leases_id_list, slice_hrn):
616         """
617
618         Deletes several leases, based on their job ids and the slice
619             they are associated with. Uses DeleteJobs to delete the jobs
620             on OAR. Note that one slice can contain multiple jobs, and in this
621             case all the jobs in the leases_id_list MUST belong to ONE slice,
622             since there is only one slice hrn provided here.
623
624         :param leases_id_list: list of job ids that belong to the slice whose
625             slice hrn is provided.
626         :param slice_hrn: the slice hrn.
627         :type slice_hrn: string
628
629         .. warning:: Does not have a return value since there was no easy
630             way to handle failure when dealing with multiple job delete. Plus,
631             there was no easy way to report it to the user.
632
633         """
634         logger.debug("IOTLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \
635                 \r\n " %(leases_id_list, slice_hrn))
636         for job_id in leases_id_list:
637             self.DeleteJobs(job_id, slice_hrn)
638
639         return
640
641     @staticmethod
642     def _process_walltime(duration):
643         """ Calculates the walltime in seconds from the duration in H:M:S
644             specified in the RSpec.
645
646         """
647         if duration:
648             # Fixing the walltime by adding a few delays.
649             # First put the walltime in seconds oarAdditionalDelay = 20;
650             #  additional delay for /bin/sleep command to
651             # take in account  prologue and epilogue scripts execution
652             # int walltimeAdditionalDelay = 240;  additional delay
653             #for prologue/epilogue execution = $SERVER_PROLOGUE_EPILOGUE_TIMEOUT
654             #in oar.conf
655             # Put the duration in seconds first
656             #desired_walltime = duration * 60
657             desired_walltime = duration
658             total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
659             sleep_walltime = desired_walltime  # 0 sec added Update SA 23/10/12
660             walltime = []
661             #Put the walltime back in str form
662             #First get the hours
663             walltime.append(str(total_walltime / 3600))
664             total_walltime = total_walltime - 3600 * int(walltime[0])
665             #Get the remaining minutes
666             walltime.append(str(total_walltime / 60))
667             total_walltime = total_walltime - 60 * int(walltime[1])
668             #Get the seconds
669             walltime.append(str(total_walltime))
670
671         else:
672             logger.log_exc(" __process_walltime duration null")
673
674         return walltime, sleep_walltime
675
676     @staticmethod
677     def _create_job_structure_request_for_OAR(lease_dict):
678         """ Creates the structure needed for a correct POST on OAR.
679         Makes the timestamp transformation into the appropriate format.
680         Sends the POST request to create the job with the resources in
681         added_nodes.
682
683         """
684
685         nodeid_list = []
686         reqdict = {}
687
688
689         reqdict['workdir'] = '/tmp'
690         reqdict['resource'] = "{network_address in ("
691
692         for node in lease_dict['added_nodes']:
693             logger.debug("\r\n \r\n OARrestapi \t \
694             __create_job_structure_request_for_OAR node %s" %(node))
695
696             # Get the ID of the node
697             nodeid = node
698             reqdict['resource'] += "'" + nodeid + "', "
699             nodeid_list.append(nodeid)
700
701         custom_length = len(reqdict['resource'])- 2
702         reqdict['resource'] = reqdict['resource'][0:custom_length] + \
703                                             ")}/nodes=" + str(len(nodeid_list))
704
705
706         walltime, sleep_walltime = \
707                     IotlabTestbedAPI._process_walltime(\
708                                      int(lease_dict['lease_duration']))
709
710
711         reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
712                             ":" + str(walltime[1]) + ":" + str(walltime[2])
713         reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
714
715         #In case of a scheduled experiment (not immediate)
716         #To run an XP immediately, don't specify date and time in RSpec
717         #They will be set to None.
718         if lease_dict['lease_start_time'] is not '0':
719             #Readable time accepted by OAR
720             start_time = datetime.fromtimestamp( \
721                 int(lease_dict['lease_start_time'])).\
722                 strftime(lease_dict['time_format'])
723             reqdict['reservation'] = start_time
724         #If there is not start time, Immediate XP. No need to add special
725         # OAR parameters
726
727
728         reqdict['type'] = "deploy"
729         reqdict['directory'] = ""
730         reqdict['name'] = "SFA_" + lease_dict['slice_user']
731
732         return reqdict
733
734
735     def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
736                         lease_start_time, lease_duration, slice_user=None):
737
738         """
739         Create a job request structure based on the information provided
740         and post the job on OAR.
741         :param added_nodes: list of nodes that belong to the described lease.
742         :param slice_name: the slice hrn associated to the lease.
743         :param lease_start_time: timestamp of the lease startting time.
744         :param lease_duration: lease durationin minutes
745
746         """
747         lease_dict = {}
748         lease_dict['lease_start_time'] = lease_start_time
749         lease_dict['lease_duration'] = lease_duration
750         lease_dict['added_nodes'] = added_nodes
751         lease_dict['slice_name'] = slice_name
752         lease_dict['slice_user'] = slice_user
753         lease_dict['grain'] = self.GetLeaseGranularity()
754         lease_dict['time_format'] = self.time_format
755
756
757         logger.debug("IOTLABDRIVER.PY \tLaunchExperimentOnOAR slice_user %s\
758                              \r\n "  %(slice_user))
759         #Create the request for OAR
760         reqdict = self._create_job_structure_request_for_OAR(lease_dict)
761          # first step : start the OAR job and update the job
762         logger.debug("IOTLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
763                              \r\n "  %(reqdict))
764
765         answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
766                                                 reqdict, slice_user)
767         logger.debug("IOTLABDRIVER \tLaunchExperimentOnOAR jobid  %s " %(answer))
768         try:
769             jobid = answer['id']
770         except KeyError:
771             logger.log_exc("IOTLABDRIVER \tLaunchExperimentOnOAR \
772                                 Impossible to create job  %s "  %(answer))
773             return None
774
775
776
777
778         if jobid :
779             logger.debug("IOTLABDRIVER \tLaunchExperimentOnOAR jobid %s \
780                     added_nodes %s slice_user %s" %(jobid, added_nodes, \
781                                                             slice_user))
782
783
784         return jobid
785
786
787     def AddLeases(self, hostname_list, slice_record, \
788                                         lease_start_time, lease_duration):
789
790         """Creates a job in OAR corresponding to the information provided
791         as parameters. Adds the job id and the slice hrn in the iotlab
792         database so that we are able to know which slice has which nodes.
793
794         :param hostname_list: list of nodes' OAR hostnames.
795         :param slice_record: sfa slice record, must contain login and hrn.
796         :param lease_start_time: starting time , unix timestamp format
797         :param lease_duration: duration in minutes
798
799         :type hostname_list: list
800         :type slice_record: dict
801         :type lease_start_time: integer
802         :type lease_duration: integer
803
804         """
805         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases hostname_list %s  \
806                 slice_record %s lease_start_time %s lease_duration %s  "\
807                  %( hostname_list, slice_record , lease_start_time, \
808                  lease_duration))
809
810         #tmp = slice_record['reg-researchers'][0].split(".")
811         username = slice_record['login']
812         #username = tmp[(len(tmp)-1)]
813         job_id = self.LaunchExperimentOnOAR(hostname_list, \
814                                     slice_record['hrn'], \
815                                     lease_start_time, lease_duration, \
816                                     username)
817         start_time = \
818                 datetime.fromtimestamp(int(lease_start_time)).\
819                 strftime(self.time_format)
820         end_time = lease_start_time + lease_duration
821
822
823         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
824                         %s %s %s "%(slice_record['hrn'], job_id, end_time))
825
826
827         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases %s %s %s " \
828                 %(type(slice_record['hrn']), type(job_id), type(end_time)))
829
830         iotlab_ex_row = IotlabXP(slice_hrn = slice_record['hrn'], \
831                 job_id = job_id, end_time= end_time)
832
833         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases iotlab_ex_row %s" \
834                 %(iotlab_ex_row))
835         self.iotlab_db.iotlab_session.add(iotlab_ex_row)
836         self.iotlab_db.iotlab_session.commit()
837
838         logger.debug("IOTLABDRIVER \t AddLeases hostname_list start_time %s " \
839                 %(start_time))
840
841         return
842
843
844     #Delete the jobs from job_iotlab table
845     def DeleteSliceFromNodes(self, slice_record):
846         """
847
848         Deletes all the running or scheduled jobs of a given slice
849             given its record.
850
851         :param slice_record: record of the slice, must contain oar_job_id, user
852         :type slice_record: dict
853
854         :returns: dict of the jobs'deletion status. Success= True, Failure=
855             False, for each job id.
856         :rtype: dict
857
858         """
859         logger.debug("IOTLABDRIVER \t  DeleteSliceFromNodes %s "
860                      % (slice_record))
861
862         if isinstance(slice_record['oar_job_id'], list):
863             oar_bool_answer = {}
864             for job_id in slice_record['oar_job_id']:
865                 ret = self.DeleteJobs(job_id, slice_record['user'])
866
867                 oar_bool_answer.update(ret)
868
869         else:
870             oar_bool_answer = [self.DeleteJobs(slice_record['oar_job_id'],
871                                                slice_record['user'])]
872
873         return oar_bool_answer
874
875
876
877     def GetLeaseGranularity(self):
878         """ Returns the granularity of an experiment in the Iotlab testbed.
879         OAR uses seconds for experiments duration , the granulaity is also
880         defined in seconds.
881         Experiments which last less than 10 min (600 sec) are invalid"""
882         return self.grain
883
884
885     # @staticmethod
886     # def update_jobs_in_iotlabdb( job_oar_list, jobs_psql):
887     #     """ Cleans the iotlab db by deleting expired and cancelled jobs.
888     #     Compares the list of job ids given by OAR with the job ids that
889     #     are already in the database, deletes the jobs that are no longer in
890     #     the OAR job id list.
891     #     :param  job_oar_list: list of job ids coming from OAR
892     #     :type job_oar_list: list
893     #     :param job_psql: list of job ids cfrom the database.
894     #     type job_psql: list
895     #     """
896     #     #Turn the list into a set
897     #     set_jobs_psql = set(jobs_psql)
898
899     #     kept_jobs = set(job_oar_list).intersection(set_jobs_psql)
900     #     logger.debug ( "\r\n \t\ update_jobs_in_iotlabdb jobs_psql %s \r\n \t \
901     #         job_oar_list %s kept_jobs %s "%(set_jobs_psql, job_oar_list, kept_jobs))
902     #     deleted_jobs = set_jobs_psql.difference(kept_jobs)
903     #     deleted_jobs = list(deleted_jobs)
904     #     if len(deleted_jobs) > 0:
905     #         self.iotlab_db.iotlab_session.query(IotlabXP).filter(IotlabXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch')
906     #         self.iotlab_db.iotlab_session.commit()
907
908     #     return
909
910
911     def GetLeases(self, lease_filter_dict=None, login=None):
912         """
913
914         Get the list of leases from OAR with complete information
915             about which slice owns which jobs and nodes.
916             Two purposes:
917             -Fetch all the jobs from OAR (running, waiting..)
918             complete the reservation information with slice hrn
919             found in iotlab_xp table. If not available in the table,
920             assume it is a iotlab slice.
921             -Updates the iotlab table, deleting jobs when necessary.
922
923         :returns: reservation_list, list of dictionaries with 'lease_id',
924             'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
925             'slice_hrn', 'resource_ids', 't_from', 't_until'
926         :rtype: list
927
928         """
929
930         unfiltered_reservation_list = self.GetReservedNodes(login)
931
932         reservation_list = []
933         #Find the slice associated with this user iotlab ldap uid
934         logger.debug(" IOTLABDRIVER.PY \tGetLeases login %s\
935                         unfiltered_reservation_list %s "
936                      % (login, unfiltered_reservation_list))
937         #Create user dict first to avoid looking several times for
938         #the same user in LDAP SA 27/07/12
939         job_oar_list = []
940
941         jobs_psql_query = self.iotlab_db.iotlab_session.query(IotlabXP).all()
942         jobs_psql_dict = dict([(row.job_id, row.__dict__)
943                                for row in jobs_psql_query])
944         #jobs_psql_dict = jobs_psql_dict)
945         logger.debug("IOTLABDRIVER \tGetLeases jobs_psql_dict %s"
946                      % (jobs_psql_dict))
947         jobs_psql_id_list = [row.job_id for row in jobs_psql_query]
948
949         for resa in unfiltered_reservation_list:
950             logger.debug("IOTLABDRIVER \tGetLeases USER %s"
951                          % (resa['user']))
952             #Construct list of jobs (runing, waiting..) in oar
953             job_oar_list.append(resa['lease_id'])
954             #If there is information on the job in IOTLAB DB ]
955             #(slice used and job id)
956             if resa['lease_id'] in jobs_psql_dict:
957                 job_info = jobs_psql_dict[resa['lease_id']]
958                 logger.debug("IOTLABDRIVER \tGetLeases job_info %s"
959                              % (job_info))
960                 resa['slice_hrn'] = job_info['slice_hrn']
961                 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
962
963             #otherwise, assume it is a iotlab slice:
964             else:
965                 resa['slice_id'] = hrn_to_urn(self.root_auth + '.' +
966                                               resa['user'] + "_slice", 'slice')
967                 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
968
969             resa['component_id_list'] = []
970             #Transform the hostnames into urns (component ids)
971             for node in resa['reserved_nodes']:
972
973                 iotlab_xrn = iotlab_xrn_object(self.root_auth, node)
974                 resa['component_id_list'].append(iotlab_xrn.urn)
975
976             if lease_filter_dict:
977                 logger.debug("IOTLABDRIVER \tGetLeases resa_ %s \
978                         \r\n leasefilter %s" % (resa, lease_filter_dict))
979
980                 if lease_filter_dict['name'] == resa['slice_hrn']:
981                     reservation_list.append(resa)
982
983         if lease_filter_dict is None:
984             reservation_list = unfiltered_reservation_list
985
986         self.iotlab_db.update_jobs_in_iotlabdb(job_oar_list, jobs_psql_id_list)
987
988         logger.debug(" IOTLABDRIVER.PY \tGetLeases reservation_list %s"
989                      % (reservation_list))
990         return reservation_list
991
992
993
994
995 #TODO FUNCTIONS SECTION 04/07/2012 SA
996
997     ##TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
998     ##04/07/2012 SA
999     #@staticmethod
1000     #def UnBindObjectFromPeer( auth, object_type, object_id, shortname):
1001         #""" This method is a hopefully temporary hack to let the sfa correctly
1002         #detach the objects it creates from a remote peer object. This is
1003         #needed so that the sfa federation link can work in parallel with
1004         #RefreshPeer, as RefreshPeer depends on remote objects being correctly
1005         #marked.
1006         #Parameters:
1007         #auth : struct, API authentication structure
1008             #AuthMethod : string, Authentication method to use
1009         #object_type : string, Object type, among 'site','person','slice',
1010         #'node','key'
1011         #object_id : int, object_id
1012         #shortname : string, peer shortname
1013         #FROM PLC DOC
1014
1015         #"""
1016         #logger.warning("IOTLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1017                         #DO NOTHING \r\n ")
1018         #return
1019
1020     ##TODO Is BindObjectToPeer still necessary ? Currently does nothing
1021     ##04/07/2012 SA
1022     #|| Commented out 28/05/13 SA
1023     #def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1024                                                     #remote_object_id=None):
1025         #"""This method is a hopefully temporary hack to let the sfa correctly
1026         #attach the objects it creates to a remote peer object. This is needed
1027         #so that the sfa federation link can work in parallel with RefreshPeer,
1028         #as RefreshPeer depends on remote objects being correctly marked.
1029         #Parameters:
1030         #shortname : string, peer shortname
1031         #remote_object_id : int, remote object_id, set to 0 if unknown
1032         #FROM PLC API DOC
1033
1034         #"""
1035         #logger.warning("IOTLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1036         #return
1037
1038     ##TODO UpdateSlice 04/07/2012 SA || Commented out 28/05/13 SA
1039     ##Funciton should delete and create another job since oin iotlab slice=job
1040     #def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1041         #"""Updates the parameters of an existing slice with the values in
1042         #slice_fields.
1043         #Users may only update slices of which they are members.
1044         #PIs may update any of the slices at their sites, or any slices of
1045         #which they are members. Admins may update any slice.
1046         #Only PIs and admins may update max_nodes. Slices cannot be renewed
1047         #(by updating the expires parameter) more than 8 weeks into the future.
1048          #Returns 1 if successful, faults otherwise.
1049         #FROM PLC API DOC
1050
1051         #"""
1052         #logger.warning("IOTLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1053         #return
1054
1055     #Unused SA 30/05/13, we only update the user's key or we delete it.
1056     ##TODO UpdatePerson 04/07/2012 SA
1057     #def UpdatePerson(self, iotlab_hrn, federated_hrn, person_fields=None):
1058         #"""Updates a person. Only the fields specified in person_fields
1059         #are updated, all other fields are left untouched.
1060         #Users and techs can only update themselves. PIs can only update
1061         #themselves and other non-PIs at their sites.
1062         #Returns 1 if successful, faults otherwise.
1063         #FROM PLC API DOC
1064
1065         #"""
1066         ##new_row = FederatedToIotlab(iotlab_hrn, federated_hrn)
1067         ##self.iotlab_db.iotlab_session.add(new_row)
1068         ##self.iotlab_db.iotlab_session.commit()
1069
1070         #logger.debug("IOTLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1071         #return
1072
1073     @staticmethod
1074     def GetKeys(key_filter=None):
1075         """Returns a dict of dict based on the key string. Each dict entry
1076         contains the key id, the ssh key, the user's email and the
1077         user's hrn.
1078         If key_filter is specified and is an array of key identifiers,
1079         only keys matching the filter will be returned.
1080
1081         Admin may query all keys. Non-admins may only query their own keys.
1082         FROM PLC API DOC
1083
1084         :returns: dict with ssh key as key and dicts as value.
1085         :rtype: dict
1086         """
1087         if key_filter is None:
1088             keys = dbsession.query(RegKey).options(joinedload('reg_user')).all()
1089         else:
1090             keys = dbsession.query(RegKey).options(joinedload('reg_user')).filter(RegKey.key.in_(key_filter)).all()
1091
1092         key_dict = {}
1093         for key in keys:
1094             key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
1095                                  'email': key.reg_user.email,
1096                                  'hrn': key.reg_user.hrn}
1097
1098         #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
1099         #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
1100                                         #for user in ldap_rslt)
1101
1102         logger.debug("IOTLABDRIVER  GetKeys  -key_dict %s \r\n " % (key_dict))
1103         return key_dict
1104
1105     #TODO : test
1106     def DeleteKey(self, user_record, key_string):
1107         """Deletes a key in the LDAP entry of the specified user.
1108
1109         Removes the key_string from the user's key list and updates the LDAP
1110             user's entry with the new key attributes.
1111
1112         :param key_string: The ssh key to remove
1113         :param user_record: User's record
1114         :type key_string: string
1115         :type user_record: dict
1116         :returns: True if sucessful, False if not.
1117         :rtype: Boolean
1118
1119         """
1120         all_user_keys = user_record['keys']
1121         all_user_keys.remove(key_string)
1122         new_attributes = {'sshPublicKey':all_user_keys}
1123         ret = self.ldap.LdapModifyUser(user_record, new_attributes)
1124         logger.debug("IOTLABDRIVER  DeleteKey  %s- " % (ret))
1125         return ret['bool']
1126
1127
1128
1129
1130     @staticmethod
1131     def _sql_get_slice_info( slice_filter ):
1132         """
1133         Get the slice record based on the slice hrn. Fetch the record of the
1134         user associated with the slice by using joinedload based on the
1135         reg_researcher relationship.
1136
1137         :param slice_filter: the slice hrn we are looking for
1138         :type slice_filter: string
1139         :returns: the slice record enhanced with the user's information if the
1140             slice was found, None it wasn't.
1141
1142         :rtype: dict or None.
1143         """
1144         #DO NOT USE RegSlice - reg_researchers to get the hrn
1145         #of the user otherwise will mess up the RegRecord in
1146         #Resolve, don't know why - SA 08/08/2012
1147
1148         #Only one entry for one user  = one slice in iotlab_xp table
1149         #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1150         raw_slicerec = dbsession.query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
1151         #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1152         if raw_slicerec:
1153             #load_reg_researcher
1154             #raw_slicerec.reg_researchers
1155             raw_slicerec = raw_slicerec.__dict__
1156             logger.debug(" IOTLABDRIVER \t  get_slice_info slice_filter %s  \
1157                             raw_slicerec %s" % (slice_filter, raw_slicerec))
1158             slicerec = raw_slicerec
1159             #only one researcher per slice so take the first one
1160             #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
1161             #del slicerec['reg_researchers']['_sa_instance_state']
1162             return slicerec
1163
1164         else:
1165             return None
1166
1167     @staticmethod
1168     def _sql_get_slice_info_from_user(slice_filter):
1169         """
1170         Get the slice record based on the user recordid by using a joinedload
1171         on the relationship reg_slices_as_researcher. Format the sql record
1172         into a dict with the mandatory fields for user and slice.
1173         :returns: dict with slice record and user record if the record was found
1174         based on the user's id, None if not..
1175         :rtype:dict or None..
1176         """
1177         #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1178         raw_slicerec = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
1179         #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1180         #Put it in correct order
1181         user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1182                               'classtype', 'authority', 'gid', 'record_id',
1183                               'date_created', 'type', 'email', 'pointer']
1184         slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1185                                'classtype', 'authority', 'gid', 'record_id',
1186                                'date_created', 'type', 'pointer']
1187         if raw_slicerec:
1188             #raw_slicerec.reg_slices_as_researcher
1189             raw_slicerec = raw_slicerec.__dict__
1190             slicerec = {}
1191             slicerec = \
1192                 dict([(k, raw_slicerec[
1193                     'reg_slices_as_researcher'][0].__dict__[k])
1194                     for k in slice_needed_fields])
1195             slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
1196                                                 for k in user_needed_fields])
1197              #TODO Handle multiple slices for one user SA 10/12/12
1198                         #for now only take the first slice record associated to the rec user
1199                         ##slicerec  = raw_slicerec['reg_slices_as_researcher'][0].__dict__
1200                         #del raw_slicerec['reg_slices_as_researcher']
1201                         #slicerec['reg_researchers'] = raw_slicerec
1202                         ##del slicerec['_sa_instance_state']
1203
1204             return slicerec
1205
1206         else:
1207             return None
1208
1209     def _get_slice_records(self, slice_filter=None,
1210                            slice_filter_type=None):
1211         """
1212         Get the slice record depending on the slice filter and its type.
1213         :param slice_filter: Can be either the slice hrn or the user's record
1214         id.
1215         :type slice_filter: string
1216         :param slice_filter_type: describes the slice filter type used, can be
1217         slice_hrn or record_id_user
1218         :type: string
1219         :returns: the slice record
1220         :rtype:dict
1221         .. seealso::_sql_get_slice_info_from_user
1222         .. seealso:: _sql_get_slice_info
1223         """
1224
1225         #Get list of slices based on the slice hrn
1226         if slice_filter_type == 'slice_hrn':
1227
1228             #if get_authority(slice_filter) == self.root_auth:
1229                 #login = slice_filter.split(".")[1].split("_")[0]
1230
1231             slicerec = self._sql_get_slice_info(slice_filter)
1232
1233             if slicerec is None:
1234                 return None
1235                 #return login, None
1236
1237         #Get slice based on user id
1238         if slice_filter_type == 'record_id_user':
1239
1240             slicerec = self._sql_get_slice_info_from_user(slice_filter)
1241
1242         if slicerec:
1243             fixed_slicerec_dict = slicerec
1244             #At this point if there is no login it means
1245             #record_id_user filter has been used for filtering
1246             #if login is None :
1247                 ##If theslice record is from iotlab
1248                 #if fixed_slicerec_dict['peer_authority'] is None:
1249                     #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
1250             #return login, fixed_slicerec_dict
1251             return fixed_slicerec_dict
1252
1253
1254     def GetSlices(self, slice_filter=None, slice_filter_type=None,
1255                   login=None):
1256         """Get the slice records from the iotlab db and add lease information
1257             if any.
1258
1259         :param slice_filter: can be the slice hrn or slice record id in the db
1260             depending on the slice_filter_type.
1261         :param slice_filter_type: defines the type of the filtering used, Can be
1262             either 'slice_hrn' or "record_id'.
1263         :type slice_filter: string
1264         :type slice_filter_type: string
1265         :returns: a slice dict if slice_filter  and slice_filter_type
1266             are specified and a matching entry is found in the db. The result
1267             is put into a list.Or a list of slice dictionnaries if no filters
1268             arespecified.
1269
1270         :rtype: list
1271
1272         """
1273         #login = None
1274         authorized_filter_types_list = ['slice_hrn', 'record_id_user']
1275         return_slicerec_dictlist = []
1276
1277         #First try to get information on the slice based on the filter provided
1278         if slice_filter_type in authorized_filter_types_list:
1279             fixed_slicerec_dict = self._get_slice_records(slice_filter,
1280                                                           slice_filter_type)
1281             slice_hrn = fixed_slicerec_dict['hrn']
1282
1283             logger.debug(" IOTLABDRIVER \tGetSlices login %s \
1284                             slice record %s slice_filter %s \
1285                             slice_filter_type %s " % (login,
1286                             fixed_slicerec_dict, slice_filter,
1287                             slice_filter_type))
1288
1289
1290             #Now we have the slice record fixed_slicerec_dict, get the
1291             #jobs associated to this slice
1292             leases_list = []
1293
1294             leases_list = self.GetLeases(login=login)
1295             #If no job is running or no job scheduled
1296             #return only the slice record
1297             if leases_list == [] and fixed_slicerec_dict:
1298                 return_slicerec_dictlist.append(fixed_slicerec_dict)
1299
1300             #If several jobs for one slice , put the slice record into
1301             # each lease information dict
1302
1303             for lease in leases_list:
1304                 slicerec_dict = {}
1305                 logger.debug("IOTLABDRIVER.PY  \tGetSlices slice_filter %s   \
1306                         \t lease['slice_hrn'] %s"
1307                              % (slice_filter, lease['slice_hrn']))
1308                 if lease['slice_hrn'] == slice_hrn:
1309                     #Update lease dict with the slice record
1310                     if fixed_slicerec_dict:
1311                         fixed_slicerec_dict['oar_job_id'] = []
1312                         fixed_slicerec_dict['oar_job_id'].append(
1313                             slicerec_dict['oar_job_id'])
1314                         slicerec_dict.update(fixed_slicerec_dict)
1315                         #slicerec_dict.update({'hrn':\
1316                                         #str(fixed_slicerec_dict['slice_hrn'])})
1317                     slicerec_dict['slice_hrn'] = lease['slice_hrn']
1318                     slicerec_dict['hrn'] = lease['slice_hrn']
1319                     slicerec_dict['user'] = lease['user']
1320                     slicerec_dict['oar_job_id'] = lease['lease_id']
1321                     slicerec_dict.update(
1322                         {'list_node_ids':
1323                         {'hostname': lease['reserved_nodes']}})
1324                     slicerec_dict.update({'node_ids': lease['reserved_nodes']})
1325
1326
1327
1328                     return_slicerec_dictlist.append(slicerec_dict)
1329                     logger.debug("IOTLABDRIVER.PY  \tGetSlices  \
1330                         OHOHOHOH %s" %(return_slicerec_dictlist))
1331
1332                 logger.debug("IOTLABDRIVER.PY  \tGetSlices  \
1333                         slicerec_dict %s return_slicerec_dictlist %s \
1334                         lease['reserved_nodes'] \
1335                         %s" % (slicerec_dict, return_slicerec_dictlist,
1336                                lease['reserved_nodes']))
1337
1338             logger.debug("IOTLABDRIVER.PY  \tGetSlices  RETURN \
1339                         return_slicerec_dictlist  %s"
1340                           % (return_slicerec_dictlist))
1341
1342             return return_slicerec_dictlist
1343
1344
1345         else:
1346             #Get all slices from the iotlab sfa database ,
1347             #put them in dict format
1348             #query_slice_list = dbsession.query(RegRecord).all()
1349             query_slice_list = \
1350                 dbsession.query(RegSlice).options(joinedload('reg_researchers')).all()
1351
1352             for record in query_slice_list:
1353                 tmp = record.__dict__
1354                 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
1355                 #del tmp['reg_researchers']['_sa_instance_state']
1356                 return_slicerec_dictlist.append(tmp)
1357                 #return_slicerec_dictlist.append(record.__dict__)
1358
1359             #Get all the jobs reserved nodes
1360             leases_list = self.GetReservedNodes()
1361
1362             for fixed_slicerec_dict in return_slicerec_dictlist:
1363                 slicerec_dict = {}
1364                 #Check if the slice belongs to a iotlab user
1365                 if fixed_slicerec_dict['peer_authority'] is None:
1366                     owner = fixed_slicerec_dict['hrn'].split(
1367                         ".")[1].split("_")[0]
1368                 else:
1369                     owner = None
1370                 for lease in leases_list:
1371                     if owner == lease['user']:
1372                         slicerec_dict['oar_job_id'] = lease['lease_id']
1373
1374                         #for reserved_node in lease['reserved_nodes']:
1375                         logger.debug("IOTLABDRIVER.PY  \tGetSlices lease %s "
1376                                      % (lease))
1377
1378                         slicerec_dict.update({'node_ids':
1379                                               lease['reserved_nodes']})
1380                         slicerec_dict.update({'list_node_ids':
1381                                              {'hostname':
1382                                              lease['reserved_nodes']}})
1383                         slicerec_dict.update(fixed_slicerec_dict)
1384                         #slicerec_dict.update({'hrn':\
1385                                     #str(fixed_slicerec_dict['slice_hrn'])})
1386                         #return_slicerec_dictlist.append(slicerec_dict)
1387                         fixed_slicerec_dict.update(slicerec_dict)
1388
1389             logger.debug("IOTLABDRIVER.PY  \tGetSlices RETURN \
1390                         return_slicerec_dictlist %s \slice_filter %s " \
1391                         %(return_slicerec_dictlist, slice_filter))
1392
1393         return return_slicerec_dictlist
1394
1395
1396
1397     #Update slice unused, therefore  sfa_fields_to_iotlab_fields unused
1398     #SA 30/05/13
1399     #@staticmethod
1400     #def sfa_fields_to_iotlab_fields(sfa_type, hrn, record):
1401         #"""
1402         #"""
1403
1404         #iotlab_record = {}
1405         ##for field in record:
1406         ##    iotlab_record[field] = record[field]
1407
1408         #if sfa_type == "slice":
1409             ##instantion used in get_slivers ?
1410             #if not "instantiation" in iotlab_record:
1411                 #iotlab_record["instantiation"] = "iotlab-instantiated"
1412             ##iotlab_record["hrn"] = hrn_to_pl_slicename(hrn)
1413             ##Unused hrn_to_pl_slicename because Iotlab's hrn already
1414             ##in the appropriate form SA 23/07/12
1415             #iotlab_record["hrn"] = hrn
1416             #logger.debug("IOTLABDRIVER.PY sfa_fields_to_iotlab_fields \
1417                         #iotlab_record %s  " %(iotlab_record['hrn']))
1418             #if "url" in record:
1419                 #iotlab_record["url"] = record["url"]
1420             #if "description" in record:
1421                 #iotlab_record["description"] = record["description"]
1422             #if "expires" in record:
1423                 #iotlab_record["expires"] = int(record["expires"])
1424
1425         ##nodes added by OAR only and then imported to SFA
1426         ##elif type == "node":
1427             ##if not "hostname" in iotlab_record:
1428                 ##if not "hostname" in record:
1429                     ##raise MissingSfaInfo("hostname")
1430                 ##iotlab_record["hostname"] = record["hostname"]
1431             ##if not "model" in iotlab_record:
1432                 ##iotlab_record["model"] = "geni"
1433
1434         ##One authority only
1435         ##elif type == "authority":
1436             ##iotlab_record["login_base"] = hrn_to_iotlab_login_base(hrn)
1437
1438             ##if not "name" in iotlab_record:
1439                 ##iotlab_record["name"] = hrn
1440
1441             ##if not "abbreviated_name" in iotlab_record:
1442                 ##iotlab_record["abbreviated_name"] = hrn
1443
1444             ##if not "enabled" in iotlab_record:
1445                 ##iotlab_record["enabled"] = True
1446
1447             ##if not "is_public" in iotlab_record:
1448                 ##iotlab_record["is_public"] = True
1449
1450         #return iotlab_record
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460