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