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.
7 from datetime import datetime
9 from sfa.util.sfalogging import logger
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 TestbedAdditionalSfaDB, LeaseTableXP
15 from sfa.iotlab.OARrestapi import OARrestapi
16 from sfa.iotlab.LDAPapi import LDAPapi
18 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority
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
24 from sfa.iotlab.iotlabaggregate import iotlab_xrn_object
26 class IotlabTestbedAPI():
27 """ Class enabled to use LDAP and OAR api calls. """
29 _MINIMUM_DURATION = 10 # 10 units of granularity 60 s, 10 mins
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.
37 :param config: configuration object from sfa.util.config
38 :type config: Config object
40 self.iotlab_db = TestbedAdditionalSfaDB(config)
41 self.oar = OARrestapi()
43 self.time_format = "%Y-%m-%d %H:%M:%S"
44 self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
45 self.grain = 60 # 10 mins lease minimum, 60 sec granularity
46 #import logging, logging.handlers
47 #from sfa.util.sfalogging import _SfaLogger
48 #sql_logger = _SfaLogger(loggername = 'sqlalchemy.engine', \
53 def GetMinExperimentDurationInGranularity():
54 """ Returns the minimum allowed duration for an experiment on the
58 return IotlabTestbedAPI._MINIMUM_DURATION
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.
71 existing_hrns_by_types = {}
72 logger.debug("IOTLAB_API \tGetPeers peer_filter %s " % (peer_filter))
73 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
75 for record in all_records:
76 existing_records[(record.hrn, record.type)] = record
77 if record.type not in existing_hrns_by_types:
78 existing_hrns_by_types[record.type] = [record.hrn]
80 existing_hrns_by_types[record.type].append(record.hrn)
82 logger.debug("IOTLAB_API \tGetPeer\texisting_hrns_by_types %s "
83 % (existing_hrns_by_types))
88 records_list.append(existing_records[(peer_filter,
91 for hrn in existing_hrns_by_types['authority']:
92 records_list.append(existing_records[(hrn, 'authority')])
94 logger.debug("IOTLAB_API \tGetPeer \trecords_list %s "
100 return_records = records_list
101 logger.debug("IOTLAB_API \tGetPeer return_records %s "
103 return return_records
105 #TODO : Handling OR request in make_ldap_filters_from_records
106 #instead of the for loop
107 #over the records' list
108 def GetPersons(self, person_filter=None):
110 Get the enabled users and their properties from Iotlab LDAP.
111 If a filter is specified, looks for the user whose properties match
112 the filter, otherwise returns the whole enabled users'list.
114 :param person_filter: Must be a list of dictionnaries with users
115 properties when not set to None.
116 :type person_filter: list of dict
118 :returns: Returns a list of users whose accounts are enabled
120 :rtype: list of dicts
123 logger.debug("IOTLAB_API \tGetPersons person_filter %s"
126 if person_filter and isinstance(person_filter, list):
127 #If we are looking for a list of users (list of dict records)
128 #Usually the list contains only one user record
129 for searched_attributes in person_filter:
131 #Get only enabled user accounts in iotlab LDAP :
132 #add a filter for make_ldap_filters_from_record
133 person = self.ldap.LdapFindUser(searched_attributes,
134 is_user_enabled=True)
135 #If a person was found, append it to the list
137 person_list.append(person)
139 #If the list is empty, return None
140 if len(person_list) is 0:
144 #Get only enabled user accounts in iotlab LDAP :
145 #add a filter for make_ldap_filters_from_record
146 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
151 #def GetTimezone(self):
152 #""" Returns the OAR server time and timezone.
153 #Unused SA 30/05/13"""
154 #server_timestamp, server_tz = self.oar.parser.\
155 #SendRequest("GET_timezone")
156 #return server_timestamp, server_tz
158 def DeleteJobs(self, job_id, username):
161 Deletes the job with the specified job_id and username on OAR by
162 posting a delete request to OAR.
164 :param job_id: job id in OAR.
165 :param username: user's iotlab login in LDAP.
166 :type job_id: integer
167 :type username: string
169 :returns: dictionary with the job id and if delete has been successful
174 logger.debug("IOTLAB_API \tDeleteJobs jobid %s username %s "
175 % (job_id, username))
176 if not job_id or job_id is -1:
180 reqdict['method'] = "delete"
181 reqdict['strval'] = str(job_id)
183 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id',
185 if answer['status'] == 'Delete request registered':
188 ret = {job_id: False}
189 logger.debug("IOTLAB_API \tDeleteJobs jobid %s \r\n answer %s \
190 username %s" % (job_id, answer, username))
195 ##TODO : Unused GetJobsId ? SA 05/07/12
196 #def GetJobsId(self, job_id, username = None ):
198 #Details about a specific job.
199 #Includes details about submission time, jot type, state, events,
200 #owner, assigned ressources, walltime etc...
204 #node_list_k = 'assigned_network_address'
205 ##Get job info from OAR
206 #job_info = self.oar.parser.SendRequest(req, job_id, username)
208 #logger.debug("IOTLAB_API \t GetJobsId %s " %(job_info))
210 #if job_info['state'] == 'Terminated':
211 #logger.debug("IOTLAB_API \t GetJobsId job %s TERMINATED"\
214 #if job_info['state'] == 'Error':
215 #logger.debug("IOTLAB_API \t GetJobsId ERROR message %s "\
220 #logger.error("IOTLAB_API \tGetJobsId KeyError")
223 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
225 ##Replaces the previous entry
226 ##"assigned_network_address" / "reserved_resources"
228 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
229 #del job_info[node_list_k]
230 #logger.debug(" \r\nIOTLAB_API \t GetJobsId job_info %s " %(job_info))
234 def GetJobsResources(self, job_id, username = None):
235 """ Gets the list of nodes associated with the job_id and username
237 Transforms the iotlab hostnames to the corresponding
239 Rertuns dict key :'node_ids' , value : hostnames list
240 :param username: user's LDAP login
241 :paran job_id: job's OAR identifier.
242 :type username: string
243 :type job_id: integer
245 :returns: dicionary with nodes' hostnames belonging to the job.
247 .. warning: Unused. SA 16/10/13
250 req = "GET_jobs_id_resources"
253 #Get job resources list from OAR
254 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
255 logger.debug("IOTLAB_API \t GetJobsResources %s " %(node_id_list))
258 self.__get_hostnames_from_oar_node_ids(node_id_list)
261 #Replaces the previous entry "assigned_network_address" /
262 #"reserved_resources" with "node_ids"
263 job_info = {'node_ids': hostname_list}
268 #def get_info_on_reserved_nodes(self, job_info, node_list_name):
270 #..warning:unused SA 23/05/13
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))
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']
287 #logger.debug("IOTLAB_API \t get_info_on_reserved_nodes \
288 #reserved_node_hostname_list %s" \
289 #%(reserved_node_hostname_list))
291 #logger.error("IOTLAB_API \t get_info_on_reserved_nodes KEYERROR " )
293 #return reserved_node_hostname_list
295 def GetNodesCurrentlyInUse(self):
296 """Returns a list of all the nodes already involved in an oar running
298 :rtype: list of nodes hostnames.
300 return self.oar.parser.SendRequest("GET_running_jobs")
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.
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
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'])
322 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
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
329 :param username: user's LDAP login
330 :type username: string
331 :returns: list of reservations dict
335 #Get the nodes in use and the reserved nodes
336 reservation_dict_list = \
337 self.oar.parser.SendRequest("GET_reserved_nodes", \
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'])
347 #del resa['resource_ids']
348 return reservation_dict_list
350 def GetNodes(self, node_filter_dict=None, return_fields_list=None):
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'.
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
365 :type return_fields_list: list
366 :returns: list of dictionaries with node properties
370 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
371 node_dict_list = node_dict_by_id.values()
372 logger.debug (" IOTLAB_API 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
378 return_node_list = []
380 for filter_key in node_filter_dict:
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:
389 for k in return_fields_list:
391 return_node_list.append(tmp)
393 return_node_list.append(node)
395 logger.log_exc("GetNodes KeyError")
399 return return_node_list
404 def AddSlice(slice_record, user_record):
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.
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
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("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
425 % (sfa_record, user_record))
426 sfa_record.just_created()
427 dbsession.add(sfa_record)
429 #Update the reg-researcher dependance table
430 sfa_record.reg_researchers = [user_record]
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 the sites' properties as dictionaries.
441 ['address_ids', 'slice_ids', 'name', 'node_ids', 'url', 'person_ids',
442 'site_tag_ids', 'enabled', 'site', 'longitude', 'pcu_ids',
443 'max_slivers', 'max_slices', 'ext_consortium_id', 'date_created',
444 'latitude', 'is_public', 'peer_site_id', 'peer_id', 'abbreviated_name']
445 Uses the OAR request GET_sites to find the Iotlab's sites.
447 :param site_filter_name_list: used to specify specific sites
448 :param return_fields_list: field that has to be returned
449 :type site_filter_name_list: list
450 :type return_fields_list: list
454 site_dict = self.oar.parser.SendRequest("GET_sites")
455 #site_dict : dict where the key is the sit ename
456 return_site_list = []
457 if not (site_filter_name_list or return_fields_list):
458 return_site_list = site_dict.values()
459 return return_site_list
461 for site_filter_name in site_filter_name_list:
462 if site_filter_name in site_dict:
463 if return_fields_list:
464 for field in return_fields_list:
467 tmp[field] = site_dict[site_filter_name][field]
469 logger.error("GetSites KeyError %s " % (field))
471 return_site_list.append(tmp)
473 return_site_list.append(site_dict[site_filter_name])
475 return return_site_list
478 #TODO : Check rights to delete person
479 def DeletePerson(self, person_record):
480 """Disable an existing account in iotlab LDAP.
482 Users and techs can only delete themselves. PIs can only
483 delete themselves and other non-PIs at their sites.
484 ins can delete anyone.
486 :param person_record: user's record
487 :type person_record: dict
488 :returns: True if successful, False otherwise.
491 .. todo:: CHECK THAT ONLY THE USER OR ADMIN CAN DEL HIMSELF.
493 #Disable user account in iotlab LDAP
494 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
495 logger.warning("IOTLAB_API DeletePerson %s " % (person_record))
498 def DeleteSlice(self, slice_record):
499 """Deletes the specified slice and kills the jobs associated with
500 the slice if any, using DeleteSliceFromNodes.
502 :param slice_record: record of the slice, must contain oar_job_id, user
503 :type slice_record: dict
504 :returns: True if all the jobs in the slice have been deleted,
505 or the list of jobs that could not be deleted otherwise.
506 :rtype: list or boolean
508 .. seealso:: DeleteSliceFromNodes
511 ret = self.DeleteSliceFromNodes(slice_record)
514 if False in ret[job_id]:
515 if delete_failed is None:
517 delete_failed.append(job_id)
519 logger.info("IOTLAB_API DeleteSlice %s answer %s"%(slice_record, \
521 return delete_failed or True
524 def __add_person_to_db(user_dict):
526 Add a federated user straight to db when the user issues a lease
527 request with iotlab nodes and that he has not registered with iotlab
528 yet (that is he does not have a LDAP entry yet).
529 Uses parts of the routines in IotlabImport when importing user from LDAP.
530 Called by AddPerson, right after LdapAddUser.
531 :param user_dict: Must contain email, hrn and pkey to get a GID
532 and be added to the SFA db.
533 :type user_dict: dict
537 dbsession.query(RegUser).filter_by(email = user_dict['email']).first()
539 if not check_if_exists:
540 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
542 hrn = user_dict['hrn']
543 person_urn = hrn_to_urn(hrn, 'user')
544 pubkey = user_dict['pkey']
546 pkey = convert_public_key(pubkey)
548 #key not good. create another pkey
549 logger.warn('__add_person_to_db: unable to convert public \
551 pkey = Keypair(create=True)
554 if pubkey is not None and pkey is not None :
555 hierarchy = Hierarchy()
556 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
558 if user_dict['email']:
559 logger.debug("__add_person_to_db \r\n \r\n \
560 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
561 %(user_dict['email']))
562 person_gid.set_email(user_dict['email'])
564 user_record = RegUser(hrn=hrn , pointer= '-1', \
565 authority=get_authority(hrn), \
566 email=user_dict['email'], gid = person_gid)
567 user_record.reg_keys = [RegKey(user_dict['pkey'])]
568 user_record.just_created()
569 dbsession.add (user_record)
574 def AddPerson(self, record):
577 Adds a new account. Any fields specified in records are used,
578 otherwise defaults are used. Creates an appropriate login by calling
581 :param record: dictionary with the sfa user's properties.
582 :returns: a dicitonary with the status. If successful, the dictionary
583 boolean is set to True and there is a 'uid' key with the new login
584 added to LDAP, otherwise the bool is set to False and a key
585 'message' is in the dictionary, with the error message.
589 ret = self.ldap.LdapAddUser(record)
591 if ret['bool'] is True:
592 record['hrn'] = self.root_auth + '.' + ret['uid']
593 logger.debug("IOTLAB_API AddPerson return code %s record %s "
595 self.__add_person_to_db(record)
602 #TODO AddPersonKey 04/07/2012 SA
603 def AddPersonKey(self, person_uid, old_attributes_dict, new_key_dict):
604 """Adds a new key to the specified account. Adds the key to the
605 iotlab ldap, provided that the person_uid is valid.
607 Non-admins can only modify their own keys.
609 :param person_uid: user's iotlab login in LDAP
610 :param old_attributes_dict: dict with the user's old sshPublicKey
611 :param new_key_dict: dict with the user's new sshPublicKey
612 :type person_uid: string
616 :returns: True if the key has been modified, False otherwise.
619 ret = self.ldap.LdapModify(person_uid, old_attributes_dict, \
621 logger.warning("IOTLAB_API AddPersonKey EMPTY - DO NOTHING \r\n ")
624 def DeleteLeases(self, leases_id_list, slice_hrn):
627 Deletes several leases, based on their job ids and the slice
628 they are associated with. Uses DeleteJobs to delete the jobs
629 on OAR. Note that one slice can contain multiple jobs, and in this
630 case all the jobs in the leases_id_list MUST belong to ONE slice,
631 since there is only one slice hrn provided here.
633 :param leases_id_list: list of job ids that belong to the slice whose
634 slice hrn is provided.
635 :param slice_hrn: the slice hrn.
636 :type slice_hrn: string
638 .. warning:: Does not have a return value since there was no easy
639 way to handle failure when dealing with multiple job delete. Plus,
640 there was no easy way to report it to the user.
643 logger.debug("IOTLAB_API DeleteLeases leases_id_list %s slice_hrn %s \
644 \r\n " %(leases_id_list, slice_hrn))
645 for job_id in leases_id_list:
646 self.DeleteJobs(job_id, slice_hrn)
651 def _process_walltime(duration):
652 """ Calculates the walltime in seconds from the duration in H:M:S
653 specified in the RSpec.
657 # Fixing the walltime by adding a few delays.
658 # First put the walltime in seconds oarAdditionalDelay = 20;
659 # additional delay for /bin/sleep command to
660 # take in account prologue and epilogue scripts execution
661 # int walltimeAdditionalDelay = 240; additional delay
662 #for prologue/epilogue execution = $SERVER_PROLOGUE_EPILOGUE_TIMEOUT
664 # Put the duration in seconds first
665 #desired_walltime = duration * 60
666 desired_walltime = duration
667 total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
668 sleep_walltime = desired_walltime # 0 sec added Update SA 23/10/12
670 #Put the walltime back in str form
672 walltime.append(str(total_walltime / 3600))
673 total_walltime = total_walltime - 3600 * int(walltime[0])
674 #Get the remaining minutes
675 walltime.append(str(total_walltime / 60))
676 total_walltime = total_walltime - 60 * int(walltime[1])
678 walltime.append(str(total_walltime))
681 logger.log_exc(" __process_walltime duration null")
683 return walltime, sleep_walltime
686 def _create_job_structure_request_for_OAR(lease_dict):
687 """ Creates the structure needed for a correct POST on OAR.
688 Makes the timestamp transformation into the appropriate format.
689 Sends the POST request to create the job with the resources in
698 reqdict['workdir'] = '/tmp'
699 reqdict['resource'] = "{network_address in ("
701 for node in lease_dict['added_nodes']:
702 logger.debug("\r\n \r\n OARrestapi \t \
703 __create_job_structure_request_for_OAR node %s" %(node))
705 # Get the ID of the node
707 reqdict['resource'] += "'" + nodeid + "', "
708 nodeid_list.append(nodeid)
710 custom_length = len(reqdict['resource'])- 2
711 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
712 ")}/nodes=" + str(len(nodeid_list))
715 walltime, sleep_walltime = \
716 IotlabTestbedAPI._process_walltime(\
717 int(lease_dict['lease_duration']))
720 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
721 ":" + str(walltime[1]) + ":" + str(walltime[2])
722 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
724 #In case of a scheduled experiment (not immediate)
725 #To run an XP immediately, don't specify date and time in RSpec
726 #They will be set to None.
727 if lease_dict['lease_start_time'] is not '0':
728 #Readable time accepted by OAR
729 start_time = datetime.fromtimestamp( \
730 int(lease_dict['lease_start_time'])).\
731 strftime(lease_dict['time_format'])
732 reqdict['reservation'] = start_time
733 #If there is not start time, Immediate XP. No need to add special
737 reqdict['type'] = "deploy"
738 reqdict['directory'] = ""
739 reqdict['name'] = "SFA_" + lease_dict['slice_user']
744 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
745 lease_start_time, lease_duration, slice_user=None):
748 Create a job request structure based on the information provided
749 and post the job on OAR.
750 :param added_nodes: list of nodes that belong to the described lease.
751 :param slice_name: the slice hrn associated to the lease.
752 :param lease_start_time: timestamp of the lease startting time.
753 :param lease_duration: lease durationin minutes
757 lease_dict['lease_start_time'] = lease_start_time
758 lease_dict['lease_duration'] = lease_duration
759 lease_dict['added_nodes'] = added_nodes
760 lease_dict['slice_name'] = slice_name
761 lease_dict['slice_user'] = slice_user
762 lease_dict['grain'] = self.GetLeaseGranularity()
763 lease_dict['time_format'] = self.time_format
766 logger.debug("IOTLAB_API.PY \tLaunchExperimentOnOAR slice_user %s\
767 \r\n " %(slice_user))
768 #Create the request for OAR
769 reqdict = self._create_job_structure_request_for_OAR(lease_dict)
770 # first step : start the OAR job and update the job
771 logger.debug("IOTLAB_API.PY \tLaunchExperimentOnOAR reqdict %s\
774 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
776 logger.debug("IOTLAB_API \tLaunchExperimentOnOAR jobid %s " %(answer))
780 logger.log_exc("IOTLAB_API \tLaunchExperimentOnOAR \
781 Impossible to create job %s " %(answer))
788 logger.debug("IOTLAB_API \tLaunchExperimentOnOAR jobid %s \
789 added_nodes %s slice_user %s" %(jobid, added_nodes, \
796 def AddLeases(self, hostname_list, slice_record,
797 lease_start_time, lease_duration):
799 """Creates a job in OAR corresponding to the information provided
800 as parameters. Adds the job id and the slice hrn in the iotlab
801 database so that we are able to know which slice has which nodes.
803 :param hostname_list: list of nodes' OAR hostnames.
804 :param slice_record: sfa slice record, must contain login and hrn.
805 :param lease_start_time: starting time , unix timestamp format
806 :param lease_duration: duration in minutes
808 :type hostname_list: list
809 :type slice_record: dict
810 :type lease_start_time: integer
811 :type lease_duration: integer
814 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
815 slice_record %s lease_start_time %s lease_duration %s "\
816 %( hostname_list, slice_record , lease_start_time, \
819 #tmp = slice_record['reg-researchers'][0].split(".")
820 username = slice_record['login']
821 #username = tmp[(len(tmp)-1)]
822 job_id = self.LaunchExperimentOnOAR(hostname_list, \
823 slice_record['hrn'], \
824 lease_start_time, lease_duration, \
827 datetime.fromtimestamp(int(lease_start_time)).\
828 strftime(self.time_format)
829 end_time = lease_start_time + lease_duration
832 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
833 %s %s %s "%(slice_record['hrn'], job_id, end_time))
836 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
837 %(type(slice_record['hrn']), type(job_id), type(end_time)))
839 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'], job_id=job_id,
842 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
844 self.iotlab_db.testbed_session.add(iotlab_ex_row)
845 self.iotlab_db.testbed_session.commit()
847 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s " \
853 #Delete the jobs from job_iotlab table
854 def DeleteSliceFromNodes(self, slice_record):
857 Deletes all the running or scheduled jobs of a given slice
860 :param slice_record: record of the slice, must contain oar_job_id, user
861 :type slice_record: dict
863 :returns: dict of the jobs'deletion status. Success= True, Failure=
864 False, for each job id.
868 logger.debug("IOTLAB_API \t DeleteSliceFromNodes %s "
871 if isinstance(slice_record['oar_job_id'], list):
873 for job_id in slice_record['oar_job_id']:
874 ret = self.DeleteJobs(job_id, slice_record['user'])
876 oar_bool_answer.update(ret)
879 oar_bool_answer = [self.DeleteJobs(slice_record['oar_job_id'],
880 slice_record['user'])]
882 return oar_bool_answer
886 def GetLeaseGranularity(self):
887 """ Returns the granularity of an experiment in the Iotlab testbed.
888 OAR uses seconds for experiments duration , the granulaity is also
890 Experiments which last less than 10 min (600 sec) are invalid"""
895 # def update_experiments_in_additional_sfa_db( job_oar_list, jobs_psql):
896 # """ Cleans the iotlab db by deleting expired and cancelled jobs.
897 # Compares the list of job ids given by OAR with the job ids that
898 # are already in the database, deletes the jobs that are no longer in
899 # the OAR job id list.
900 # :param job_oar_list: list of job ids coming from OAR
901 # :type job_oar_list: list
902 # :param job_psql: list of job ids cfrom the database.
903 # type job_psql: list
905 # #Turn the list into a set
906 # set_jobs_psql = set(jobs_psql)
908 # kept_jobs = set(job_oar_list).intersection(set_jobs_psql)
909 # logger.debug ( "\r\n \t\ update_experiments_in_additional_sfa_db jobs_psql %s \r\n \t \
910 # job_oar_list %s kept_jobs %s "%(set_jobs_psql, job_oar_list, kept_jobs))
911 # deleted_jobs = set_jobs_psql.difference(kept_jobs)
912 # deleted_jobs = list(deleted_jobs)
913 # if len(deleted_jobs) > 0:
914 # self.iotlab_db.testbed_session.query(LeaseTableXP).filter(LeaseTableXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch')
915 # self.iotlab_db.testbed_session.commit()
920 def filter_lease_name(reservation_list, filter_value):
921 filtered_reservation_list = list(reservation_list)
922 logger.debug("IOTLAB_API \t filter_lease_name reservation_list %s" \
923 % (reservation_list))
924 for reservation in reservation_list:
925 if 'slice_hrn' in reservation and \
926 reservation['slice_hrn'] != filter_value:
927 filtered_reservation_list.remove(reservation)
929 logger.debug("IOTLAB_API \t filter_lease_name filtered_reservation_list %s" \
930 % (filtered_reservation_list))
931 return filtered_reservation_list
934 def filter_lease_start_time(reservation_list, filter_value):
935 filtered_reservation_list = list(reservation_list)
937 for reservation in reservation_list:
938 if 't_from' in reservation and \
939 reservation['t_from'] > filter_value:
940 filtered_reservation_list.remove(reservation)
942 return filtered_reservation_list
944 def GetLeases(self, lease_filter_dict=None, login=None):
947 Get the list of leases from OAR with complete information
948 about which slice owns which jobs and nodes.
950 -Fetch all the jobs from OAR (running, waiting..)
951 complete the reservation information with slice hrn
952 found in testbed_xp table. If not available in the table,
953 assume it is a iotlab slice.
954 -Updates the iotlab table, deleting jobs when necessary.
956 :returns: reservation_list, list of dictionaries with 'lease_id',
957 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
958 'slice_hrn', 'resource_ids', 't_from', 't_until'
963 unfiltered_reservation_list = self.GetReservedNodes(login)
965 reservation_list = []
966 #Find the slice associated with this user iotlab ldap uid
967 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
968 unfiltered_reservation_list %s "
969 % (login, unfiltered_reservation_list))
970 #Create user dict first to avoid looking several times for
971 #the same user in LDAP SA 27/07/12
974 jobs_psql_query = self.iotlab_db.testbed_session.query(LeaseTableXP).all()
975 jobs_psql_dict = dict([(row.job_id, row.__dict__)
976 for row in jobs_psql_query])
977 #jobs_psql_dict = jobs_psql_dict)
978 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
980 jobs_psql_id_list = [row.job_id for row in jobs_psql_query]
982 for resa in unfiltered_reservation_list:
983 logger.debug("IOTLAB_API \tGetLeases USER %s"
985 #Construct list of jobs (runing, waiting..) in oar
986 job_oar_list.append(resa['lease_id'])
987 #If there is information on the job in IOTLAB DB ]
988 #(slice used and job id)
989 if resa['lease_id'] in jobs_psql_dict:
990 job_info = jobs_psql_dict[resa['lease_id']]
991 logger.debug("IOTLAB_API \tGetLeases job_info %s"
993 resa['slice_hrn'] = job_info['slice_hrn']
994 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
996 #otherwise, assume it is a iotlab slice:
998 resa['slice_id'] = hrn_to_urn(self.root_auth + '.' +
999 resa['user'] + "_slice", 'slice')
1000 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
1002 resa['component_id_list'] = []
1003 #Transform the hostnames into urns (component ids)
1004 for node in resa['reserved_nodes']:
1006 iotlab_xrn = iotlab_xrn_object(self.root_auth, node)
1007 resa['component_id_list'].append(iotlab_xrn.urn)
1009 if lease_filter_dict:
1010 logger.debug("IOTLAB_API \tGetLeases \
1011 \r\n leasefilter %s" % ( lease_filter_dict))
1013 filter_dict_functions = {
1014 'slice_hrn' : IotlabTestbedAPI.filter_lease_name,
1015 't_from' : IotlabTestbedAPI.filter_lease_start_time
1017 reservation_list = list(unfiltered_reservation_list)
1018 for filter_type in lease_filter_dict:
1019 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
1020 % (reservation_list))
1021 reservation_list = filter_dict_functions[filter_type](\
1022 reservation_list,lease_filter_dict[filter_type] )
1024 # Filter the reservation list with a maximum timespan so that the
1025 # leases and jobs running after this timestamp do not appear
1026 # in the result leases.
1027 # if 'start_time' in :
1028 # if resa['start_time'] < lease_filter_dict['start_time']:
1029 # reservation_list.append(resa)
1032 # if 'name' in lease_filter_dict and \
1033 # lease_filter_dict['name'] == resa['slice_hrn']:
1034 # reservation_list.append(resa)
1037 if lease_filter_dict is None:
1038 reservation_list = unfiltered_reservation_list
1040 self.iotlab_db.update_experiments_in_additional_sfa_db(job_oar_list, jobs_psql_id_list)
1042 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
1043 % (reservation_list))
1044 return reservation_list
1049 #TODO FUNCTIONS SECTION 04/07/2012 SA
1051 ##TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1054 #def UnBindObjectFromPeer( auth, object_type, object_id, shortname):
1055 #""" This method is a hopefully temporary hack to let the sfa correctly
1056 #detach the objects it creates from a remote peer object. This is
1057 #needed so that the sfa federation link can work in parallel with
1058 #RefreshPeer, as RefreshPeer depends on remote objects being correctly
1061 #auth : struct, API authentication structure
1062 #AuthMethod : string, Authentication method to use
1063 #object_type : string, Object type, among 'site','person','slice',
1065 #object_id : int, object_id
1066 #shortname : string, peer shortname
1070 #logger.warning("IOTLAB_API \tUnBindObjectFromPeer EMPTY-\
1074 ##TODO Is BindObjectToPeer still necessary ? Currently does nothing
1076 #|| Commented out 28/05/13 SA
1077 #def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1078 #remote_object_id=None):
1079 #"""This method is a hopefully temporary hack to let the sfa correctly
1080 #attach the objects it creates to a remote peer object. This is needed
1081 #so that the sfa federation link can work in parallel with RefreshPeer,
1082 #as RefreshPeer depends on remote objects being correctly marked.
1084 #shortname : string, peer shortname
1085 #remote_object_id : int, remote object_id, set to 0 if unknown
1089 #logger.warning("IOTLAB_API \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1092 ##TODO UpdateSlice 04/07/2012 SA || Commented out 28/05/13 SA
1093 ##Funciton should delete and create another job since oin iotlab slice=job
1094 #def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1095 #"""Updates the parameters of an existing slice with the values in
1097 #Users may only update slices of which they are members.
1098 #PIs may update any of the slices at their sites, or any slices of
1099 #which they are members. Admins may update any slice.
1100 #Only PIs and admins may update max_nodes. Slices cannot be renewed
1101 #(by updating the expires parameter) more than 8 weeks into the future.
1102 #Returns 1 if successful, faults otherwise.
1106 #logger.warning("IOTLAB_API UpdateSlice EMPTY - DO NOTHING \r\n ")
1109 #Unused SA 30/05/13, we only update the user's key or we delete it.
1110 ##TODO UpdatePerson 04/07/2012 SA
1111 #def UpdatePerson(self, iotlab_hrn, federated_hrn, person_fields=None):
1112 #"""Updates a person. Only the fields specified in person_fields
1113 #are updated, all other fields are left untouched.
1114 #Users and techs can only update themselves. PIs can only update
1115 #themselves and other non-PIs at their sites.
1116 #Returns 1 if successful, faults otherwise.
1120 ##new_row = FederatedToIotlab(iotlab_hrn, federated_hrn)
1121 ##self.iotlab_db.testbed_session.add(new_row)
1122 ##self.iotlab_db.testbed_session.commit()
1124 #logger.debug("IOTLAB_API UpdatePerson EMPTY - DO NOTHING \r\n ")
1128 def GetKeys(key_filter=None):
1129 """Returns a dict of dict based on the key string. Each dict entry
1130 contains the key id, the ssh key, the user's email and the
1132 If key_filter is specified and is an array of key identifiers,
1133 only keys matching the filter will be returned.
1135 Admin may query all keys. Non-admins may only query their own keys.
1138 :returns: dict with ssh key as key and dicts as value.
1141 if key_filter is None:
1142 keys = dbsession.query(RegKey).options(joinedload('reg_user')).all()
1144 keys = dbsession.query(RegKey).options(joinedload('reg_user')).filter(RegKey.key.in_(key_filter)).all()
1148 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
1149 'email': key.reg_user.email,
1150 'hrn': key.reg_user.hrn}
1152 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
1153 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
1154 #for user in ldap_rslt)
1156 logger.debug("IOTLAB_API GetKeys -key_dict %s \r\n " % (key_dict))
1160 def DeleteKey(self, user_record, key_string):
1161 """Deletes a key in the LDAP entry of the specified user.
1163 Removes the key_string from the user's key list and updates the LDAP
1164 user's entry with the new key attributes.
1166 :param key_string: The ssh key to remove
1167 :param user_record: User's record
1168 :type key_string: string
1169 :type user_record: dict
1170 :returns: True if sucessful, False if not.
1174 all_user_keys = user_record['keys']
1175 all_user_keys.remove(key_string)
1176 new_attributes = {'sshPublicKey':all_user_keys}
1177 ret = self.ldap.LdapModifyUser(user_record, new_attributes)
1178 logger.debug("IOTLAB_API DeleteKey %s- " % (ret))
1185 def _sql_get_slice_info(slice_filter):
1187 Get the slice record based on the slice hrn. Fetch the record of the
1188 user associated with the slice by using joinedload based on the
1189 reg_researcher relationship.
1191 :param slice_filter: the slice hrn we are looking for
1192 :type slice_filter: string
1193 :returns: the slice record enhanced with the user's information if the
1194 slice was found, None it wasn't.
1196 :rtype: dict or None.
1198 #DO NOT USE RegSlice - reg_researchers to get the hrn
1199 #of the user otherwise will mess up the RegRecord in
1200 #Resolve, don't know why - SA 08/08/2012
1202 #Only one entry for one user = one slice in testbed_xp table
1203 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1204 raw_slicerec = dbsession.query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
1205 #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
1207 #load_reg_researcher
1208 #raw_slicerec.reg_researchers
1209 raw_slicerec = raw_slicerec.__dict__
1210 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
1211 raw_slicerec %s" % (slice_filter, raw_slicerec))
1212 slicerec = raw_slicerec
1213 #only one researcher per slice so take the first one
1214 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
1215 #del slicerec['reg_researchers']['_sa_instance_state']
1222 def _sql_get_slice_info_from_user(slice_filter):
1224 Get the slice record based on the user recordid by using a joinedload
1225 on the relationship reg_slices_as_researcher. Format the sql record
1226 into a dict with the mandatory fields for user and slice.
1227 :returns: dict with slice record and user record if the record was found
1228 based on the user's id, None if not..
1229 :rtype:dict or None..
1231 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1232 raw_slicerec = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
1233 #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
1234 #Put it in correct order
1235 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1236 'classtype', 'authority', 'gid', 'record_id',
1237 'date_created', 'type', 'email', 'pointer']
1238 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
1239 'classtype', 'authority', 'gid', 'record_id',
1240 'date_created', 'type', 'pointer']
1242 #raw_slicerec.reg_slices_as_researcher
1243 raw_slicerec = raw_slicerec.__dict__
1246 dict([(k, raw_slicerec[
1247 'reg_slices_as_researcher'][0].__dict__[k])
1248 for k in slice_needed_fields])
1249 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
1250 for k in user_needed_fields])
1251 #TODO Handle multiple slices for one user SA 10/12/12
1252 #for now only take the first slice record associated to the rec user
1253 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
1254 #del raw_slicerec['reg_slices_as_researcher']
1255 #slicerec['reg_researchers'] = raw_slicerec
1256 ##del slicerec['_sa_instance_state']
1263 def _get_slice_records(self, slice_filter=None,
1264 slice_filter_type=None):
1266 Get the slice record depending on the slice filter and its type.
1267 :param slice_filter: Can be either the slice hrn or the user's record
1269 :type slice_filter: string
1270 :param slice_filter_type: describes the slice filter type used, can be
1271 slice_hrn or record_id_user
1273 :returns: the slice record
1275 .. seealso::_sql_get_slice_info_from_user
1276 .. seealso:: _sql_get_slice_info
1279 #Get list of slices based on the slice hrn
1280 if slice_filter_type == 'slice_hrn':
1282 #if get_authority(slice_filter) == self.root_auth:
1283 #login = slice_filter.split(".")[1].split("_")[0]
1285 slicerec = self._sql_get_slice_info(slice_filter)
1287 if slicerec is None:
1291 #Get slice based on user id
1292 if slice_filter_type == 'record_id_user':
1294 slicerec = self._sql_get_slice_info_from_user(slice_filter)
1297 fixed_slicerec_dict = slicerec
1298 #At this point if there is no login it means
1299 #record_id_user filter has been used for filtering
1301 ##If theslice record is from iotlab
1302 #if fixed_slicerec_dict['peer_authority'] is None:
1303 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
1304 #return login, fixed_slicerec_dict
1305 return fixed_slicerec_dict
1310 def GetSlices(self, slice_filter=None, slice_filter_type=None,
1312 """Get the slice records from the iotlab db and add lease information
1315 :param slice_filter: can be the slice hrn or slice record id in the db
1316 depending on the slice_filter_type.
1317 :param slice_filter_type: defines the type of the filtering used, Can be
1318 either 'slice_hrn' or "record_id'.
1319 :type slice_filter: string
1320 :type slice_filter_type: string
1321 :returns: a slice dict if slice_filter and slice_filter_type
1322 are specified and a matching entry is found in the db. The result
1323 is put into a list.Or a list of slice dictionnaries if no filters
1330 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
1331 return_slicerec_dictlist = []
1333 #First try to get information on the slice based on the filter provided
1334 if slice_filter_type in authorized_filter_types_list:
1335 fixed_slicerec_dict = self._get_slice_records(slice_filter,
1337 # if the slice was not found in the sfa db
1338 if fixed_slicerec_dict is None:
1339 return return_slicerec_dictlist
1341 slice_hrn = fixed_slicerec_dict['hrn']
1343 logger.debug(" IOTLAB_API \tGetSlices login %s \
1344 slice record %s slice_filter %s \
1345 slice_filter_type %s " % (login,
1346 fixed_slicerec_dict, slice_filter,
1350 #Now we have the slice record fixed_slicerec_dict, get the
1351 #jobs associated to this slice
1354 leases_list = self.GetLeases(login=login)
1355 #If no job is running or no job scheduled
1356 #return only the slice record
1357 if leases_list == [] and fixed_slicerec_dict:
1358 return_slicerec_dictlist.append(fixed_slicerec_dict)
1360 # if the jobs running don't belong to the user/slice we are looking
1362 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
1363 if slice_hrn not in leases_hrn:
1364 return_slicerec_dictlist.append(fixed_slicerec_dict)
1365 #If several jobs for one slice , put the slice record into
1366 # each lease information dict
1367 for lease in leases_list:
1369 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
1370 \t lease['slice_hrn'] %s"
1371 % (slice_filter, lease['slice_hrn']))
1372 if lease['slice_hrn'] == slice_hrn:
1373 slicerec_dict['oar_job_id'] = lease['lease_id']
1374 #Update lease dict with the slice record
1375 if fixed_slicerec_dict:
1376 fixed_slicerec_dict['oar_job_id'] = []
1377 fixed_slicerec_dict['oar_job_id'].append(
1378 slicerec_dict['oar_job_id'])
1379 slicerec_dict.update(fixed_slicerec_dict)
1380 #slicerec_dict.update({'hrn':\
1381 #str(fixed_slicerec_dict['slice_hrn'])})
1382 slicerec_dict['slice_hrn'] = lease['slice_hrn']
1383 slicerec_dict['hrn'] = lease['slice_hrn']
1384 slicerec_dict['user'] = lease['user']
1385 slicerec_dict.update(
1387 {'hostname': lease['reserved_nodes']}})
1388 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
1392 return_slicerec_dictlist.append(slicerec_dict)
1393 logger.debug("IOTLAB_API.PY \tGetSlices \
1394 OHOHOHOH %s" %(return_slicerec_dictlist))
1396 logger.debug("IOTLAB_API.PY \tGetSlices \
1397 slicerec_dict %s return_slicerec_dictlist %s \
1398 lease['reserved_nodes'] \
1399 %s" % (slicerec_dict, return_slicerec_dictlist,
1400 lease['reserved_nodes']))
1402 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
1403 return_slicerec_dictlist %s"
1404 % (return_slicerec_dictlist))
1406 return return_slicerec_dictlist
1410 #Get all slices from the iotlab sfa database ,
1411 #put them in dict format
1412 #query_slice_list = dbsession.query(RegRecord).all()
1413 query_slice_list = \
1414 dbsession.query(RegSlice).options(joinedload('reg_researchers')).all()
1416 for record in query_slice_list:
1417 tmp = record.__dict__
1418 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
1419 #del tmp['reg_researchers']['_sa_instance_state']
1420 return_slicerec_dictlist.append(tmp)
1421 #return_slicerec_dictlist.append(record.__dict__)
1423 #Get all the jobs reserved nodes
1424 leases_list = self.GetReservedNodes()
1426 for fixed_slicerec_dict in return_slicerec_dictlist:
1428 #Check if the slice belongs to a iotlab user
1429 if fixed_slicerec_dict['peer_authority'] is None:
1430 owner = fixed_slicerec_dict['hrn'].split(
1431 ".")[1].split("_")[0]
1434 for lease in leases_list:
1435 if owner == lease['user']:
1436 slicerec_dict['oar_job_id'] = lease['lease_id']
1438 #for reserved_node in lease['reserved_nodes']:
1439 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
1441 slicerec_dict.update(fixed_slicerec_dict)
1442 slicerec_dict.update({'node_ids':
1443 lease['reserved_nodes']})
1444 slicerec_dict.update({'list_node_ids':
1446 lease['reserved_nodes']}})
1448 #slicerec_dict.update({'hrn':\
1449 #str(fixed_slicerec_dict['slice_hrn'])})
1450 #return_slicerec_dictlist.append(slicerec_dict)
1451 fixed_slicerec_dict.update(slicerec_dict)
1453 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
1454 return_slicerec_dictlist %s \slice_filter %s " \
1455 %(return_slicerec_dictlist, slice_filter))
1457 return return_slicerec_dictlist
1461 #Update slice unused, therefore sfa_fields_to_iotlab_fields unused
1464 #def sfa_fields_to_iotlab_fields(sfa_type, hrn, record):
1469 ##for field in record:
1470 ## iotlab_record[field] = record[field]
1472 #if sfa_type == "slice":
1473 ##instantion used in get_slivers ?
1474 #if not "instantiation" in iotlab_record:
1475 #iotlab_record["instantiation"] = "iotlab-instantiated"
1476 ##iotlab_record["hrn"] = hrn_to_pl_slicename(hrn)
1477 ##Unused hrn_to_pl_slicename because Iotlab's hrn already
1478 ##in the appropriate form SA 23/07/12
1479 #iotlab_record["hrn"] = hrn
1480 #logger.debug("IOTLAB_API.PY sfa_fields_to_iotlab_fields \
1481 #iotlab_record %s " %(iotlab_record['hrn']))
1482 #if "url" in record:
1483 #iotlab_record["url"] = record["url"]
1484 #if "description" in record:
1485 #iotlab_record["description"] = record["description"]
1486 #if "expires" in record:
1487 #iotlab_record["expires"] = int(record["expires"])
1489 ##nodes added by OAR only and then imported to SFA
1490 ##elif type == "node":
1491 ##if not "hostname" in iotlab_record:
1492 ##if not "hostname" in record:
1493 ##raise MissingSfaInfo("hostname")
1494 ##iotlab_record["hostname"] = record["hostname"]
1495 ##if not "model" in iotlab_record:
1496 ##iotlab_record["model"] = "geni"
1498 ##One authority only
1499 ##elif type == "authority":
1500 ##iotlab_record["login_base"] = hrn_to_iotlab_login_base(hrn)
1502 ##if not "name" in iotlab_record:
1503 ##iotlab_record["name"] = hrn
1505 ##if not "abbreviated_name" in iotlab_record:
1506 ##iotlab_record["abbreviated_name"] = hrn
1508 ##if not "enabled" in iotlab_record:
1509 ##iotlab_record["enabled"] = True
1511 ##if not "is_public" in iotlab_record:
1512 ##iotlab_record["is_public"] = True
1514 #return iotlab_record