Correcting fill_record_info to add information on
[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. For
360             instance, if you want to look for a specific node with its hrn,
361             the node_filter_dict should be {'hrn': [hrn_of_the_node]}
362         :type node_filter_dict: dict
363         :param return_fields_list: list of specific fields the user wants to be
364             returned.
365         :type return_fields_list: list
366         :returns: list of dictionaries with node properties
367         :rtype: list
368
369         """
370         node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
371         node_dict_list = node_dict_by_id.values()
372         logger.debug (" IOTLABDRIVER GetNodes  node_filter_dict %s \
373             return_fields_list %s " % (node_filter_dict, return_fields_list))
374         #No  filtering needed return the list directly
375         if not (node_filter_dict or return_fields_list):
376             return node_dict_list
377
378         return_node_list = []
379         if node_filter_dict:
380             for filter_key in node_filter_dict:
381                 try:
382                     #Filter the node_dict_list by each value contained in the
383                     #list node_filter_dict[filter_key]
384                     for value in node_filter_dict[filter_key]:
385                         for node in node_dict_list:
386                             if node[filter_key] == value:
387                                 if return_fields_list:
388                                     tmp = {}
389                                     for k in return_fields_list:
390                                         tmp[k] = node[k]
391                                     return_node_list.append(tmp)
392                                 else:
393                                     return_node_list.append(node)
394                 except KeyError:
395                     logger.log_exc("GetNodes KeyError")
396                     return
397
398
399         return return_node_list
400
401
402
403     @staticmethod
404     def AddSlice(slice_record, user_record):
405         """
406
407         Add slice to the local iotlab sfa tables if the slice comes
408             from a federated site and is not yet in the iotlab sfa DB,
409             although the user has already a LDAP login.
410             Called by verify_slice during lease/sliver creation.
411
412         :param slice_record: record of slice, must contain hrn, gid, slice_id
413             and authority of the slice.
414         :type slice_record: dictionary
415         :param user_record: record of the user
416         :type user_record: RegUser
417
418         """
419
420         sfa_record = RegSlice(hrn=slice_record['hrn'],
421                               gid=slice_record['gid'],
422                               pointer=slice_record['slice_id'],
423                               authority=slice_record['authority'])
424         logger.debug("IOTLABDRIVER.PY AddSlice  sfa_record %s user_record %s"
425                      % (sfa_record, user_record))
426         sfa_record.just_created()
427         dbsession.add(sfa_record)
428         dbsession.commit()
429         #Update the reg-researcher dependance table
430         sfa_record.reg_researchers = [user_record]
431         dbsession.commit()
432
433         return
434
435
436     def GetSites(self, site_filter_name_list=None, return_fields_list=None):
437         """Returns the list of Iotlab's sites with the associated nodes and
438         their properties as dictionaries.
439
440         Uses the OAR request GET_sites to find the Iotlab's sites.
441
442         :param site_filter_name_list: used to specify specific sites
443         :param return_fields_list: field that has to be returned
444         :type site_filter_name_list: list
445         :type return_fields_list: list
446
447         .. warning:: unused
448         """
449         site_dict = self.oar.parser.SendRequest("GET_sites")
450         #site_dict : dict where the key is the sit ename
451         return_site_list = []
452         if not (site_filter_name_list or return_fields_list):
453             return_site_list = site_dict.values()
454             return return_site_list
455
456         for site_filter_name in site_filter_name_list:
457             if site_filter_name in site_dict:
458                 if return_fields_list:
459                     for field in return_fields_list:
460                         tmp = {}
461                         try:
462                             tmp[field] = site_dict[site_filter_name][field]
463                         except KeyError:
464                             logger.error("GetSites KeyError %s " % (field))
465                             return None
466                     return_site_list.append(tmp)
467                 else:
468                     return_site_list.append(site_dict[site_filter_name])
469
470         return return_site_list
471
472
473     #TODO : Check rights to delete person
474     def DeletePerson(self, person_record):
475         """Disable an existing account in iotlab LDAP.
476
477         Users and techs can only delete themselves. PIs can only
478             delete themselves and other non-PIs at their sites.
479             ins can delete anyone.
480
481         :param person_record: user's record
482         :type person_record: dict
483         :returns:  True if successful, False otherwise.
484         :rtype: boolean
485
486         .. todo:: CHECK THAT ONLY THE USER OR ADMIN CAN DEL HIMSELF.
487         """
488         #Disable user account in iotlab LDAP
489         ret = self.ldap.LdapMarkUserAsDeleted(person_record)
490         logger.warning("IOTLABDRIVER DeletePerson %s " % (person_record))
491         return ret['bool']
492
493     def DeleteSlice(self, slice_record):
494         """Deletes the specified slice and kills the jobs associated with
495             the slice if any,  using DeleteSliceFromNodes.
496
497         :param slice_record: record of the slice, must contain oar_job_id, user
498         :type slice_record: dict
499         :returns: True if all the jobs in the slice have been deleted,
500             or the list of jobs that could not be deleted otherwise.
501         :rtype: list or boolean
502
503          .. seealso:: DeleteSliceFromNodes
504
505         """
506         ret = self.DeleteSliceFromNodes(slice_record)
507         delete_failed = None
508         for job_id in ret:
509             if False in ret[job_id]:
510                 if delete_failed is None:
511                     delete_failed = []
512                 delete_failed.append(job_id)
513
514         logger.info("IOTLABDRIVER DeleteSlice %s  answer %s"%(slice_record, \
515                     delete_failed))
516         return delete_failed or True
517
518     @staticmethod
519     def __add_person_to_db(user_dict):
520         """
521         Add a federated user straight to db when the user issues a lease
522         request with iotlab nodes and that he has not registered with iotlab
523         yet (that is he does not have a LDAP entry yet).
524         Uses parts of the routines in SlabImport when importing user from LDAP.
525         Called by AddPerson, right after LdapAddUser.
526         :param user_dict: Must contain email, hrn and pkey to get a GID
527         and be added to the SFA db.
528         :type user_dict: dict
529
530         """
531         check_if_exists = \
532         dbsession.query(RegUser).filter_by(email = user_dict['email']).first()
533         #user doesn't exists
534         if not check_if_exists:
535             logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
536                                             " %(user_dict))
537             hrn = user_dict['hrn']
538             person_urn = hrn_to_urn(hrn, 'user')
539             pubkey = user_dict['pkey']
540             try:
541                 pkey = convert_public_key(pubkey)
542             except TypeError:
543                 #key not good. create another pkey
544                 logger.warn('__add_person_to_db: unable to convert public \
545                                     key for %s' %(hrn ))
546                 pkey = Keypair(create=True)
547
548
549             if pubkey is not None and pkey is not None :
550                 hierarchy = Hierarchy()
551                 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
552                                 pkey)
553                 if user_dict['email']:
554                     logger.debug("__add_person_to_db \r\n \r\n \
555                         IOTLAB IMPORTER PERSON EMAIL OK email %s "\
556                         %(user_dict['email']))
557                     person_gid.set_email(user_dict['email'])
558
559             user_record = RegUser(hrn=hrn , pointer= '-1', \
560                                     authority=get_authority(hrn), \
561                                     email=user_dict['email'], gid = person_gid)
562             user_record.reg_keys = [RegKey(user_dict['pkey'])]
563             user_record.just_created()
564             dbsession.add (user_record)
565             dbsession.commit()
566         return
567
568
569     def AddPerson(self, record):
570         """
571
572         Adds a new account. Any fields specified in records are used,
573             otherwise defaults are used. Creates an appropriate login by calling
574             LdapAddUser.
575
576         :param record: dictionary with the sfa user's properties.
577         :returns: The uid of the added person if sucessful, otherwise returns
578             the error message from LDAP.
579         :rtype: interger or string
580
581         """
582         ret = self.ldap.LdapAddUser(record)
583
584         if ret['bool'] is True:
585             record['hrn'] = self.root_auth + '.' + ret['uid']
586             logger.debug("IOTLABDRIVER AddPerson return code %s record %s \r\n "\
587                                                                 %(ret, record))
588             self.__add_person_to_db(record)
589             return ret['uid']
590         else:
591             return ret['message']
592
593
594
595     #TODO AddPersonKey 04/07/2012 SA
596     def AddPersonKey(self, person_uid, old_attributes_dict, new_key_dict):
597         """Adds a new key to the specified account. Adds the key to the
598             iotlab ldap, provided that the person_uid is valid.
599
600         Non-admins can only modify their own keys.
601
602         :param person_uid: user's iotlab login in LDAP
603         :param old_attributes_dict: dict with the user's old sshPublicKey
604         :param new_key_dict: dict with the user's new sshPublicKey
605         :type person_uid: string
606
607
608         :rtype: Boolean
609         :returns: True if the key has been modified, False otherwise.
610
611         """
612         ret = self.ldap.LdapModify(person_uid, old_attributes_dict, \
613                                                                 new_key_dict)
614         logger.warning("IOTLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
615         return ret['bool']
616
617     def DeleteLeases(self, leases_id_list, slice_hrn):
618         """
619
620         Deletes several leases, based on their job ids and the slice
621             they are associated with. Uses DeleteJobs to delete the jobs
622             on OAR. Note that one slice can contain multiple jobs, and in this
623             case all the jobs in the leases_id_list MUST belong to ONE slice,
624             since there is only one slice hrn provided here.
625
626         :param leases_id_list: list of job ids that belong to the slice whose
627             slice hrn is provided.
628         :param slice_hrn: the slice hrn.
629         :type slice_hrn: string
630
631         .. warning:: Does not have a return value since there was no easy
632             way to handle failure when dealing with multiple job delete. Plus,
633             there was no easy way to report it to the user.
634
635         """
636         logger.debug("IOTLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \
637                 \r\n " %(leases_id_list, slice_hrn))
638         for job_id in leases_id_list:
639             self.DeleteJobs(job_id, slice_hrn)
640
641         return
642
643     @staticmethod
644     def _process_walltime(duration):
645         """ Calculates the walltime in seconds from the duration in H:M:S
646             specified in the RSpec.
647
648         """
649         if duration:
650             # Fixing the walltime by adding a few delays.
651             # First put the walltime in seconds oarAdditionalDelay = 20;
652             #  additional delay for /bin/sleep command to
653             # take in account  prologue and epilogue scripts execution
654             # int walltimeAdditionalDelay = 240;  additional delay
655             #for prologue/epilogue execution = $SERVER_PROLOGUE_EPILOGUE_TIMEOUT
656             #in oar.conf
657             # Put the duration in seconds first
658             #desired_walltime = duration * 60
659             desired_walltime = duration
660             total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
661             sleep_walltime = desired_walltime  # 0 sec added Update SA 23/10/12
662             walltime = []
663             #Put the walltime back in str form
664             #First get the hours
665             walltime.append(str(total_walltime / 3600))
666             total_walltime = total_walltime - 3600 * int(walltime[0])
667             #Get the remaining minutes
668             walltime.append(str(total_walltime / 60))
669             total_walltime = total_walltime - 60 * int(walltime[1])
670             #Get the seconds
671             walltime.append(str(total_walltime))
672
673         else:
674             logger.log_exc(" __process_walltime duration null")
675
676         return walltime, sleep_walltime
677
678     @staticmethod
679     def _create_job_structure_request_for_OAR(lease_dict):
680         """ Creates the structure needed for a correct POST on OAR.
681         Makes the timestamp transformation into the appropriate format.
682         Sends the POST request to create the job with the resources in
683         added_nodes.
684
685         """
686
687         nodeid_list = []
688         reqdict = {}
689
690
691         reqdict['workdir'] = '/tmp'
692         reqdict['resource'] = "{network_address in ("
693
694         for node in lease_dict['added_nodes']:
695             logger.debug("\r\n \r\n OARrestapi \t \
696             __create_job_structure_request_for_OAR node %s" %(node))
697
698             # Get the ID of the node
699             nodeid = node
700             reqdict['resource'] += "'" + nodeid + "', "
701             nodeid_list.append(nodeid)
702
703         custom_length = len(reqdict['resource'])- 2
704         reqdict['resource'] = reqdict['resource'][0:custom_length] + \
705                                             ")}/nodes=" + str(len(nodeid_list))
706
707
708         walltime, sleep_walltime = \
709                     IotlabTestbedAPI._process_walltime(\
710                                      int(lease_dict['lease_duration']))
711
712
713         reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
714                             ":" + str(walltime[1]) + ":" + str(walltime[2])
715         reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
716
717         #In case of a scheduled experiment (not immediate)
718         #To run an XP immediately, don't specify date and time in RSpec
719         #They will be set to None.
720         if lease_dict['lease_start_time'] is not '0':
721             #Readable time accepted by OAR
722             start_time = datetime.fromtimestamp( \
723                 int(lease_dict['lease_start_time'])).\
724                 strftime(lease_dict['time_format'])
725             reqdict['reservation'] = start_time
726         #If there is not start time, Immediate XP. No need to add special
727         # OAR parameters
728
729
730         reqdict['type'] = "deploy"
731         reqdict['directory'] = ""
732         reqdict['name'] = "SFA_" + lease_dict['slice_user']
733
734         return reqdict
735
736
737     def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
738                         lease_start_time, lease_duration, slice_user=None):
739
740         """
741         Create a job request structure based on the information provided
742         and post the job on OAR.
743         :param added_nodes: list of nodes that belong to the described lease.
744         :param slice_name: the slice hrn associated to the lease.
745         :param lease_start_time: timestamp of the lease startting time.
746         :param lease_duration: lease durationin minutes
747
748         """
749         lease_dict = {}
750         lease_dict['lease_start_time'] = lease_start_time
751         lease_dict['lease_duration'] = lease_duration
752         lease_dict['added_nodes'] = added_nodes
753         lease_dict['slice_name'] = slice_name
754         lease_dict['slice_user'] = slice_user
755         lease_dict['grain'] = self.GetLeaseGranularity()
756         lease_dict['time_format'] = self.time_format
757
758
759         logger.debug("IOTLABDRIVER.PY \tLaunchExperimentOnOAR slice_user %s\
760                              \r\n "  %(slice_user))
761         #Create the request for OAR
762         reqdict = self._create_job_structure_request_for_OAR(lease_dict)
763          # first step : start the OAR job and update the job
764         logger.debug("IOTLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
765                              \r\n "  %(reqdict))
766
767         answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
768                                                 reqdict, slice_user)
769         logger.debug("IOTLABDRIVER \tLaunchExperimentOnOAR jobid  %s " %(answer))
770         try:
771             jobid = answer['id']
772         except KeyError:
773             logger.log_exc("IOTLABDRIVER \tLaunchExperimentOnOAR \
774                                 Impossible to create job  %s "  %(answer))
775             return None
776
777
778
779
780         if jobid :
781             logger.debug("IOTLABDRIVER \tLaunchExperimentOnOAR jobid %s \
782                     added_nodes %s slice_user %s" %(jobid, added_nodes, \
783                                                             slice_user))
784
785
786         return jobid
787
788
789     def AddLeases(self, hostname_list, slice_record, \
790                                         lease_start_time, lease_duration):
791
792         """Creates a job in OAR corresponding to the information provided
793         as parameters. Adds the job id and the slice hrn in the iotlab
794         database so that we are able to know which slice has which nodes.
795
796         :param hostname_list: list of nodes' OAR hostnames.
797         :param slice_record: sfa slice record, must contain login and hrn.
798         :param lease_start_time: starting time , unix timestamp format
799         :param lease_duration: duration in minutes
800
801         :type hostname_list: list
802         :type slice_record: dict
803         :type lease_start_time: integer
804         :type lease_duration: integer
805
806         """
807         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases hostname_list %s  \
808                 slice_record %s lease_start_time %s lease_duration %s  "\
809                  %( hostname_list, slice_record , lease_start_time, \
810                  lease_duration))
811
812         #tmp = slice_record['reg-researchers'][0].split(".")
813         username = slice_record['login']
814         #username = tmp[(len(tmp)-1)]
815         job_id = self.LaunchExperimentOnOAR(hostname_list, \
816                                     slice_record['hrn'], \
817                                     lease_start_time, lease_duration, \
818                                     username)
819         start_time = \
820                 datetime.fromtimestamp(int(lease_start_time)).\
821                 strftime(self.time_format)
822         end_time = lease_start_time + lease_duration
823
824
825         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
826                         %s %s %s "%(slice_record['hrn'], job_id, end_time))
827
828
829         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases %s %s %s " \
830                 %(type(slice_record['hrn']), type(job_id), type(end_time)))
831
832         iotlab_ex_row = IotlabXP(slice_hrn = slice_record['hrn'], \
833                 job_id = job_id, end_time= end_time)
834
835         logger.debug("IOTLABDRIVER \r\n \r\n \t AddLeases iotlab_ex_row %s" \
836                 %(iotlab_ex_row))
837         self.iotlab_db.iotlab_session.add(iotlab_ex_row)
838         self.iotlab_db.iotlab_session.commit()
839
840         logger.debug("IOTLABDRIVER \t AddLeases hostname_list start_time %s " \
841                 %(start_time))
842
843         return
844
845
846     #Delete the jobs from job_iotlab table
847     def DeleteSliceFromNodes(self, slice_record):
848         """
849
850         Deletes all the running or scheduled jobs of a given slice
851             given its record.
852
853         :param slice_record: record of the slice, must contain oar_job_id, user
854         :type slice_record: dict
855
856         :returns: dict of the jobs'deletion status. Success= True, Failure=
857             False, for each job id.
858         :rtype: dict
859
860         """
861         logger.debug("IOTLABDRIVER \t  DeleteSliceFromNodes %s "
862                      % (slice_record))
863
864         if isinstance(slice_record['oar_job_id'], list):
865             oar_bool_answer = {}
866             for job_id in slice_record['oar_job_id']:
867                 ret = self.DeleteJobs(job_id, slice_record['user'])
868
869                 oar_bool_answer.update(ret)
870
871         else:
872             oar_bool_answer = [self.DeleteJobs(slice_record['oar_job_id'],
873                                                slice_record['user'])]
874
875         return oar_bool_answer
876
877
878
879     def GetLeaseGranularity(self):
880         """ Returns the granularity of an experiment in the Iotlab testbed.
881         OAR uses seconds for experiments duration , the granulaity is also
882         defined in seconds.
883         Experiments which last less than 10 min (600 sec) are invalid"""
884         return self.grain
885
886
887     # @staticmethod
888     # def update_jobs_in_iotlabdb( job_oar_list, jobs_psql):
889     #     """ Cleans the iotlab db by deleting expired and cancelled jobs.
890     #     Compares the list of job ids given by OAR with the job ids that
891     #     are already in the database, deletes the jobs that are no longer in
892     #     the OAR job id list.
893     #     :param  job_oar_list: list of job ids coming from OAR
894     #     :type job_oar_list: list
895     #     :param job_psql: list of job ids cfrom the database.
896     #     type job_psql: list
897     #     """
898     #     #Turn the list into a set
899     #     set_jobs_psql = set(jobs_psql)
900
901     #     kept_jobs = set(job_oar_list).intersection(set_jobs_psql)
902     #     logger.debug ( "\r\n \t\ update_jobs_in_iotlabdb jobs_psql %s \r\n \t \
903     #         job_oar_list %s kept_jobs %s "%(set_jobs_psql, job_oar_list, kept_jobs))
904     #     deleted_jobs = set_jobs_psql.difference(kept_jobs)
905     #     deleted_jobs = list(deleted_jobs)
906     #     if len(deleted_jobs) > 0:
907     #         self.iotlab_db.iotlab_session.query(IotlabXP).filter(IotlabXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch')
908     #         self.iotlab_db.iotlab_session.commit()
909
910     #     return
911
912
913     def GetLeases(self, lease_filter_dict=None, login=None):
914         """
915
916         Get the list of leases from OAR with complete information
917             about which slice owns which jobs and nodes.
918             Two purposes:
919             -Fetch all the jobs from OAR (running, waiting..)
920             complete the reservation information with slice hrn
921             found in iotlab_xp table. If not available in the table,
922             assume it is a iotlab slice.
923             -Updates the iotlab table, deleting jobs when necessary.
924
925         :returns: reservation_list, list of dictionaries with 'lease_id',
926             'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
927             'slice_hrn', 'resource_ids', 't_from', 't_until'
928         :rtype: list
929
930         """
931
932         unfiltered_reservation_list = self.GetReservedNodes(login)
933
934         reservation_list = []
935         #Find the slice associated with this user iotlab ldap uid
936         logger.debug(" IOTLABDRIVER.PY \tGetLeases login %s\
937                         unfiltered_reservation_list %s "
938                      % (login, unfiltered_reservation_list))
939         #Create user dict first to avoid looking several times for
940         #the same user in LDAP SA 27/07/12
941         job_oar_list = []
942
943         jobs_psql_query = self.iotlab_db.iotlab_session.query(IotlabXP).all()
944         jobs_psql_dict = dict([(row.job_id, row.__dict__)
945                                for row in jobs_psql_query])
946         #jobs_psql_dict = jobs_psql_dict)
947         logger.debug("IOTLABDRIVER \tGetLeases jobs_psql_dict %s"
948                      % (jobs_psql_dict))
949         jobs_psql_id_list = [row.job_id for row in jobs_psql_query]
950
951         for resa in unfiltered_reservation_list:
952             logger.debug("IOTLABDRIVER \tGetLeases USER %s"
953                          % (resa['user']))
954             #Construct list of jobs (runing, waiting..) in oar
955             job_oar_list.append(resa['lease_id'])
956             #If there is information on the job in IOTLAB DB ]
957             #(slice used and job id)
958             if resa['lease_id'] in jobs_psql_dict:
959                 job_info = jobs_psql_dict[resa['lease_id']]
960                 logger.debug("IOTLABDRIVER \tGetLeases job_info %s"
961                              % (job_info))
962                 resa['slice_hrn'] = job_info['slice_hrn']
963                 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
964
965             #otherwise, assume it is a iotlab slice:
966             else:
967                 resa['slice_id'] = hrn_to_urn(self.root_auth + '.' +
968                                               resa['user'] + "_slice", 'slice')
969                 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
970
971             resa['component_id_list'] = []
972             #Transform the hostnames into urns (component ids)
973             for node in resa['reserved_nodes']:
974
975                 iotlab_xrn = iotlab_xrn_object(self.root_auth, node)
976                 resa['component_id_list'].append(iotlab_xrn.urn)
977
978             if lease_filter_dict:
979                 logger.debug("IOTLABDRIVER \tGetLeases resa_ %s \
980                         \r\n leasefilter %s" % (resa, lease_filter_dict))
981
982                 if lease_filter_dict['name'] == resa['slice_hrn']:
983                     reservation_list.append(resa)
984
985         if lease_filter_dict is None:
986             reservation_list = unfiltered_reservation_list
987
988         self.iotlab_db.update_jobs_in_iotlabdb(job_oar_list, jobs_psql_id_list)
989
990         logger.debug(" IOTLABDRIVER.PY \tGetLeases reservation_list %s"
991                      % (reservation_list))
992         return reservation_list
993
994
995
996
997 #TODO FUNCTIONS SECTION 04/07/2012 SA
998
999     ##TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1000     ##04/07/2012 SA
1001     #@staticmethod
1002     #def UnBindObjectFromPeer( auth, object_type, object_id, shortname):
1003         #""" This method is a hopefully temporary hack to let the sfa correctly
1004         #detach the objects it creates from a remote peer object. This is
1005         #needed so that the sfa federation link can work in parallel with
1006         #RefreshPeer, as RefreshPeer depends on remote objects being correctly
1007         #marked.
1008         #Parameters:
1009         #auth : struct, API authentication structure
1010             #AuthMethod : string, Authentication method to use
1011         #object_type : string, Object type, among 'site','person','slice',
1012         #'node','key'
1013         #object_id : int, object_id
1014         #shortname : string, peer shortname
1015         #FROM PLC DOC
1016
1017         #"""
1018         #logger.warning("IOTLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1019                         #DO NOTHING \r\n ")
1020         #return
1021
1022     ##TODO Is BindObjectToPeer still necessary ? Currently does nothing
1023     ##04/07/2012 SA
1024     #|| Commented out 28/05/13 SA
1025     #def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1026                                                     #remote_object_id=None):
1027         #"""This method is a hopefully temporary hack to let the sfa correctly
1028         #attach the objects it creates to a remote peer object. This is needed
1029         #so that the sfa federation link can work in parallel with RefreshPeer,
1030         #as RefreshPeer depends on remote objects being correctly marked.
1031         #Parameters:
1032         #shortname : string, peer shortname
1033         #remote_object_id : int, remote object_id, set to 0 if unknown
1034         #FROM PLC API DOC
1035
1036         #"""
1037         #logger.warning("IOTLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1038         #return
1039
1040     ##TODO UpdateSlice 04/07/2012 SA || Commented out 28/05/13 SA
1041     ##Funciton should delete and create another job since oin iotlab slice=job
1042     #def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1043         #"""Updates the parameters of an existing slice with the values in
1044         #slice_fields.
1045         #Users may only update slices of which they are members.
1046         #PIs may update any of the slices at their sites, or any slices of
1047         #which they are members. Admins may update any slice.
1048         #Only PIs and admins may update max_nodes. Slices cannot be renewed
1049         #(by updating the expires parameter) more than 8 weeks into the future.
1050          #Returns 1 if successful, faults otherwise.
1051         #FROM PLC API DOC
1052
1053         #"""
1054         #logger.warning("IOTLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1055         #return
1056
1057     #Unused SA 30/05/13, we only update the user's key or we delete it.
1058     ##TODO UpdatePerson 04/07/2012 SA
1059     #def UpdatePerson(self, iotlab_hrn, federated_hrn, person_fields=None):
1060         #"""Updates a person. Only the fields specified in person_fields
1061         #are updated, all other fields are left untouched.
1062         #Users and techs can only update themselves. PIs can only update
1063         #themselves and other non-PIs at their sites.
1064         #Returns 1 if successful, faults otherwise.
1065         #FROM PLC API DOC
1066
1067         #"""
1068         ##new_row = FederatedToIotlab(iotlab_hrn, federated_hrn)
1069         ##self.iotlab_db.iotlab_session.add(new_row)
1070         ##self.iotlab_db.iotlab_session.commit()
1071
1072         #logger.debug("IOTLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1073         #return
1074
1075     @staticmethod
1076     def GetKeys(key_filter=None):
1077         """Returns a dict of dict based on the key string. Each dict entry
1078         contains the key id, the ssh key, the user's email and the
1079         user's hrn.
1080         If key_filter is specified and is an array of key identifiers,
1081         only keys matching the filter will be returned.
1082
1083         Admin may query all keys. Non-admins may only query their own keys.
1084         FROM PLC API DOC
1085
1086         :returns: dict with ssh key as key and dicts as value.
1087         :rtype: dict
1088         """
1089         if key_filter is None:
1090             keys = dbsession.query(RegKey).options(joinedload('reg_user')).all()
1091         else:
1092             keys = dbsession.query(RegKey).options(joinedload('reg_user')).filter(RegKey.key.in_(key_filter)).all()
1093
1094         key_dict = {}
1095         for key in keys:
1096             key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
1097                                  'email': key.reg_user.email,
1098                                  'hrn': key.reg_user.hrn}
1099
1100         #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
1101         #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
1102                                         #for user in ldap_rslt)
1103
1104         logger.debug("IOTLABDRIVER  GetKeys  -key_dict %s \r\n " % (key_dict))
1105         return key_dict
1106
1107     #TODO : test
1108     def DeleteKey(self, user_record, key_string):
1109         """Deletes a key in the LDAP entry of the specified user.
1110
1111         Removes the key_string from the user's key list and updates the LDAP
1112             user's entry with the new key attributes.
1113
1114         :param key_string: The ssh key to remove
1115         :param user_record: User's record
1116         :type key_string: string
1117         :type user_record: dict
1118         :returns: True if sucessful, False if not.
1119         :rtype: Boolean
1120
1121         """
1122         all_user_keys = user_record['keys']
1123         all_user_keys.remove(key_string)
1124         new_attributes = {'sshPublicKey':all_user_keys}
1125         ret = self.ldap.LdapModifyUser(user_record, new_attributes)
1126         logger.debug("IOTLABDRIVER  DeleteKey  %s- " % (ret))
1127         return ret['bool']
1128
1129
1130
1131
1132     @staticmethod
1133     def _sql_get_slice_info( slice_filter ):
1134         """
1135         Get the slice record based on the slice hrn. Fetch the record of the
1136         user associated with the slice by using joinedload based on the
1137         reg_researcher relationship.
1138
1139         :param slice_filter: the slice hrn we are looking for
1140         :type slice_filter: string
1141         :returns: the slice record enhanced with the user's information if the
1142             slice was found, None it wasn't.
1143
1144         :rtype: dict or None.
1145         """
1146         #DO NOT USE RegSlice - reg_researchers to get the hrn
1147         #of the user otherwise will mess up the RegRecord in
1148         #Resolve, don't know why - SA 08/08/2012
1149
1150         #Only one entry for one user  = one slice in iotlab_xp table
1151         #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1152         raw_slicerec = dbsession.query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
1153         #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1154         if raw_slicerec:
1155             #load_reg_researcher
1156             #raw_slicerec.reg_researchers
1157             raw_slicerec = raw_slicerec.__dict__
1158             logger.debug(" IOTLABDRIVER \t  get_slice_info slice_filter %s  \
1159                             raw_slicerec %s" % (slice_filter, raw_slicerec))
1160             slicerec = raw_slicerec
1161             #only one researcher per slice so take the first one
1162             #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
1163             #del slicerec['reg_researchers']['_sa_instance_state']
1164             return slicerec
1165
1166         else:
1167             return None
1168
1169     @staticmethod
1170     def _sql_get_slice_info_from_user(slice_filter):
1171         """
1172         Get the slice record based on the user recordid by using a joinedload
1173         on the relationship reg_slices_as_researcher. Format the sql record
1174         into a dict with the mandatory fields for user and slice.
1175         :returns: dict with slice record and user record if the record was found
1176         based on the user's id, None if not..
1177         :rtype:dict or None..
1178         """
1179         #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1180         raw_slicerec = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
1181         #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1182         #Put it in correct order
1183         user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1184                               'classtype', 'authority', 'gid', 'record_id',
1185                               'date_created', 'type', 'email', 'pointer']
1186         slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1187                                'classtype', 'authority', 'gid', 'record_id',
1188                                'date_created', 'type', 'pointer']
1189         if raw_slicerec:
1190             #raw_slicerec.reg_slices_as_researcher
1191             raw_slicerec = raw_slicerec.__dict__
1192             slicerec = {}
1193             slicerec = \
1194                 dict([(k, raw_slicerec[
1195                     'reg_slices_as_researcher'][0].__dict__[k])
1196                     for k in slice_needed_fields])
1197             slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
1198                                                 for k in user_needed_fields])
1199              #TODO Handle multiple slices for one user SA 10/12/12
1200                         #for now only take the first slice record associated to the rec user
1201                         ##slicerec  = raw_slicerec['reg_slices_as_researcher'][0].__dict__
1202                         #del raw_slicerec['reg_slices_as_researcher']
1203                         #slicerec['reg_researchers'] = raw_slicerec
1204                         ##del slicerec['_sa_instance_state']
1205
1206             return slicerec
1207
1208         else:
1209             return None
1210
1211     def _get_slice_records(self, slice_filter=None,
1212                            slice_filter_type=None):
1213         """
1214         Get the slice record depending on the slice filter and its type.
1215         :param slice_filter: Can be either the slice hrn or the user's record
1216         id.
1217         :type slice_filter: string
1218         :param slice_filter_type: describes the slice filter type used, can be
1219         slice_hrn or record_id_user
1220         :type: string
1221         :returns: the slice record
1222         :rtype:dict
1223         .. seealso::_sql_get_slice_info_from_user
1224         .. seealso:: _sql_get_slice_info
1225         """
1226
1227         #Get list of slices based on the slice hrn
1228         if slice_filter_type == 'slice_hrn':
1229
1230             #if get_authority(slice_filter) == self.root_auth:
1231                 #login = slice_filter.split(".")[1].split("_")[0]
1232
1233             slicerec = self._sql_get_slice_info(slice_filter)
1234
1235             if slicerec is None:
1236                 return None
1237                 #return login, None
1238
1239         #Get slice based on user id
1240         if slice_filter_type == 'record_id_user':
1241
1242             slicerec = self._sql_get_slice_info_from_user(slice_filter)
1243
1244         if slicerec:
1245             fixed_slicerec_dict = slicerec
1246             #At this point if there is no login it means
1247             #record_id_user filter has been used for filtering
1248             #if login is None :
1249                 ##If theslice record is from iotlab
1250                 #if fixed_slicerec_dict['peer_authority'] is None:
1251                     #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
1252             #return login, fixed_slicerec_dict
1253             return fixed_slicerec_dict
1254
1255
1256     def GetSlices(self, slice_filter=None, slice_filter_type=None,
1257                   login=None):
1258         """Get the slice records from the iotlab db and add lease information
1259             if any.
1260
1261         :param slice_filter: can be the slice hrn or slice record id in the db
1262             depending on the slice_filter_type.
1263         :param slice_filter_type: defines the type of the filtering used, Can be
1264             either 'slice_hrn' or "record_id'.
1265         :type slice_filter: string
1266         :type slice_filter_type: string
1267         :returns: a slice dict if slice_filter  and slice_filter_type
1268             are specified and a matching entry is found in the db. The result
1269             is put into a list.Or a list of slice dictionnaries if no filters
1270             arespecified.
1271
1272         :rtype: list
1273
1274         """
1275         #login = None
1276         authorized_filter_types_list = ['slice_hrn', 'record_id_user']
1277         return_slicerec_dictlist = []
1278
1279         #First try to get information on the slice based on the filter provided
1280         if slice_filter_type in authorized_filter_types_list:
1281             fixed_slicerec_dict = self._get_slice_records(slice_filter,
1282                                                           slice_filter_type)
1283             slice_hrn = fixed_slicerec_dict['hrn']
1284
1285             logger.debug(" IOTLABDRIVER \tGetSlices login %s \
1286                             slice record %s slice_filter %s \
1287                             slice_filter_type %s " % (login,
1288                             fixed_slicerec_dict, slice_filter,
1289                             slice_filter_type))
1290
1291
1292             #Now we have the slice record fixed_slicerec_dict, get the
1293             #jobs associated to this slice
1294             leases_list = []
1295
1296             leases_list = self.GetLeases(login=login)
1297             #If no job is running or no job scheduled
1298             #return only the slice record
1299             if leases_list == [] and fixed_slicerec_dict:
1300                 return_slicerec_dictlist.append(fixed_slicerec_dict)
1301
1302             #If several jobs for one slice , put the slice record into
1303             # each lease information dict
1304
1305             for lease in leases_list:
1306                 slicerec_dict = {}
1307                 logger.debug("IOTLABDRIVER.PY  \tGetSlices slice_filter %s   \
1308                         \t lease['slice_hrn'] %s"
1309                              % (slice_filter, lease['slice_hrn']))
1310                 if lease['slice_hrn'] == slice_hrn:
1311                     slicerec_dict['oar_job_id'] = lease['lease_id']
1312                     #Update lease dict with the slice record
1313                     if fixed_slicerec_dict:
1314                         fixed_slicerec_dict['oar_job_id'] = []
1315                         fixed_slicerec_dict['oar_job_id'].append(
1316                             slicerec_dict['oar_job_id'])
1317                         slicerec_dict.update(fixed_slicerec_dict)
1318                         #slicerec_dict.update({'hrn':\
1319                                         #str(fixed_slicerec_dict['slice_hrn'])})
1320                     slicerec_dict['slice_hrn'] = lease['slice_hrn']
1321                     slicerec_dict['hrn'] = lease['slice_hrn']
1322                     slicerec_dict['user'] = lease['user']
1323                     slicerec_dict.update(
1324                         {'list_node_ids':
1325                         {'hostname': lease['reserved_nodes']}})
1326                     slicerec_dict.update({'node_ids': lease['reserved_nodes']})
1327
1328
1329
1330                     return_slicerec_dictlist.append(slicerec_dict)
1331                     logger.debug("IOTLABDRIVER.PY  \tGetSlices  \
1332                         OHOHOHOH %s" %(return_slicerec_dictlist))
1333
1334                 logger.debug("IOTLABDRIVER.PY  \tGetSlices  \
1335                         slicerec_dict %s return_slicerec_dictlist %s \
1336                         lease['reserved_nodes'] \
1337                         %s" % (slicerec_dict, return_slicerec_dictlist,
1338                                lease['reserved_nodes']))
1339
1340             logger.debug("IOTLABDRIVER.PY  \tGetSlices  RETURN \
1341                         return_slicerec_dictlist  %s"
1342                           % (return_slicerec_dictlist))
1343
1344             return return_slicerec_dictlist
1345
1346
1347         else:
1348             #Get all slices from the iotlab sfa database ,
1349             #put them in dict format
1350             #query_slice_list = dbsession.query(RegRecord).all()
1351             query_slice_list = \
1352                 dbsession.query(RegSlice).options(joinedload('reg_researchers')).all()
1353
1354             for record in query_slice_list:
1355                 tmp = record.__dict__
1356                 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
1357                 #del tmp['reg_researchers']['_sa_instance_state']
1358                 return_slicerec_dictlist.append(tmp)
1359                 #return_slicerec_dictlist.append(record.__dict__)
1360
1361             #Get all the jobs reserved nodes
1362             leases_list = self.GetReservedNodes()
1363
1364             for fixed_slicerec_dict in return_slicerec_dictlist:
1365                 slicerec_dict = {}
1366                 #Check if the slice belongs to a iotlab user
1367                 if fixed_slicerec_dict['peer_authority'] is None:
1368                     owner = fixed_slicerec_dict['hrn'].split(
1369                         ".")[1].split("_")[0]
1370                 else:
1371                     owner = None
1372                 for lease in leases_list:
1373                     if owner == lease['user']:
1374                         slicerec_dict['oar_job_id'] = lease['lease_id']
1375
1376                         #for reserved_node in lease['reserved_nodes']:
1377                         logger.debug("IOTLABDRIVER.PY  \tGetSlices lease %s "
1378                                      % (lease))
1379                         slicerec_dict.update(fixed_slicerec_dict)
1380                         slicerec_dict.update({'node_ids':
1381                                               lease['reserved_nodes']})
1382                         slicerec_dict.update({'list_node_ids':
1383                                              {'hostname':
1384                                              lease['reserved_nodes']}})
1385
1386                         #slicerec_dict.update({'hrn':\
1387                                     #str(fixed_slicerec_dict['slice_hrn'])})
1388                         #return_slicerec_dictlist.append(slicerec_dict)
1389                         fixed_slicerec_dict.update(slicerec_dict)
1390
1391             logger.debug("IOTLABDRIVER.PY  \tGetSlices RETURN \
1392                         return_slicerec_dictlist %s \slice_filter %s " \
1393                         %(return_slicerec_dictlist, slice_filter))
1394
1395         return return_slicerec_dictlist
1396
1397
1398
1399     #Update slice unused, therefore  sfa_fields_to_iotlab_fields unused
1400     #SA 30/05/13
1401     #@staticmethod
1402     #def sfa_fields_to_iotlab_fields(sfa_type, hrn, record):
1403         #"""
1404         #"""
1405
1406         #iotlab_record = {}
1407         ##for field in record:
1408         ##    iotlab_record[field] = record[field]
1409
1410         #if sfa_type == "slice":
1411             ##instantion used in get_slivers ?
1412             #if not "instantiation" in iotlab_record:
1413                 #iotlab_record["instantiation"] = "iotlab-instantiated"
1414             ##iotlab_record["hrn"] = hrn_to_pl_slicename(hrn)
1415             ##Unused hrn_to_pl_slicename because Iotlab's hrn already
1416             ##in the appropriate form SA 23/07/12
1417             #iotlab_record["hrn"] = hrn
1418             #logger.debug("IOTLABDRIVER.PY sfa_fields_to_iotlab_fields \
1419                         #iotlab_record %s  " %(iotlab_record['hrn']))
1420             #if "url" in record:
1421                 #iotlab_record["url"] = record["url"]
1422             #if "description" in record:
1423                 #iotlab_record["description"] = record["description"]
1424             #if "expires" in record:
1425                 #iotlab_record["expires"] = int(record["expires"])
1426
1427         ##nodes added by OAR only and then imported to SFA
1428         ##elif type == "node":
1429             ##if not "hostname" in iotlab_record:
1430                 ##if not "hostname" in record:
1431                     ##raise MissingSfaInfo("hostname")
1432                 ##iotlab_record["hostname"] = record["hostname"]
1433             ##if not "model" in iotlab_record:
1434                 ##iotlab_record["model"] = "geni"
1435
1436         ##One authority only
1437         ##elif type == "authority":
1438             ##iotlab_record["login_base"] = hrn_to_iotlab_login_base(hrn)
1439
1440             ##if not "name" in iotlab_record:
1441                 ##iotlab_record["name"] = hrn
1442
1443             ##if not "abbreviated_name" in iotlab_record:
1444                 ##iotlab_record["abbreviated_name"] = hrn
1445
1446             ##if not "enabled" in iotlab_record:
1447                 ##iotlab_record["enabled"] = True
1448
1449             ##if not "is_public" in iotlab_record:
1450                 ##iotlab_record["is_public"] = True
1451
1452         #return iotlab_record
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462