2 Implements what a driver should provide for SFA to work.
4 from datetime import datetime
5 from sfa.util.faults import SliverDoesNotExist, Forbidden
6 from sfa.util.sfalogging import logger
8 from sfa.storage.model import RegRecord, RegUser, RegSlice, RegKey
9 from sfa.util.sfatime import utcparse, datetime_to_string
10 from sfa.trust.certificate import Keypair, convert_public_key
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.trust.gid import create_uuid
15 from sfa.managers.driver import Driver
16 from sfa.rspecs.version_manager import VersionManager
17 from sfa.rspecs.rspec import RSpec
19 from sfa.iotlab.iotlabxrn import IotlabXrn, xrn_object, xrn_to_hostname
20 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
21 from sfa.iotlab.iotlabaggregate import IotlabAggregate
23 from sfa.iotlab.iotlabslices import IotlabSlices
25 from sfa.trust.credential import Credential
26 from sfa.storage.model import SliverAllocation
28 from sfa.iotlab.iotlabshell import IotlabShell
29 from sqlalchemy.orm import joinedload
30 from sfa.iotlab.iotlabpostgres import LeaseTableXP
32 class IotlabDriver(Driver):
33 """ Iotlab Driver class inherited from Driver generic class.
35 Contains methods compliant with the SFA standard and the testbed
36 infrastructure (calls to LDAP and OAR).
38 .. seealso::: Driver class
41 def __init__(self, api):
44 Sets the iotlab SFA config parameters,
45 instanciates the testbed api .
47 :param api: SfaApi configuration object. Holds reference to the
49 :type api: SfaApi object
52 Driver.__init__(self, api)
55 self.testbed_shell = IotlabShell(config)
58 def GetPeers(self, peer_filter=None ):
59 """ Gathers registered authorities in SFA DB and looks for specific peer
60 if peer_filter is specified.
61 :param peer_filter: name of the site authority looked for.
62 :type peer_filter: string
63 :returns: list of records.
68 existing_hrns_by_types = {}
69 logger.debug("IOTLAB_API \tGetPeers peer_filter %s " % (peer_filter))
70 query = self.api.dbsession().query(RegRecord)
71 all_records = query.filter(RegRecord.type.like('%authority%')).all()
73 for record in all_records:
74 existing_records[(record.hrn, record.type)] = record
75 if record.type not in existing_hrns_by_types:
76 existing_hrns_by_types[record.type] = [record.hrn]
78 existing_hrns_by_types[record.type].append(record.hrn)
80 logger.debug("IOTLAB_API \tGetPeer\texisting_hrns_by_types %s "
81 % (existing_hrns_by_types))
86 records_list.append(existing_records[(peer_filter,
89 for hrn in existing_hrns_by_types['authority']:
90 records_list.append(existing_records[(hrn, 'authority')])
92 logger.debug("IOTLAB_API \tGetPeer \trecords_list %s "
98 return_records = records_list
99 logger.debug("IOTLAB_API \tGetPeer return_records %s "
101 return return_records
103 def GetKeys(self, key_filter=None):
104 """Returns a dict of dict based on the key string. Each dict entry
105 contains the key id, the ssh key, the user's email and the
107 If key_filter is specified and is an array of key identifiers,
108 only keys matching the filter will be returned.
110 Admin may query all keys. Non-admins may only query their own keys.
113 :returns: dict with ssh key as key and dicts as value.
116 query = self.api.dbsession().query(RegKey)
117 if key_filter is None:
118 keys = query.options(joinedload('reg_user')).all()
120 constraint = RegKey.key.in_(key_filter)
121 keys = query.options(joinedload('reg_user')).filter(constraint).all()
125 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
126 'email': key.reg_user.email,
127 'hrn': key.reg_user.hrn}
129 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
130 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
131 #for user in ldap_rslt)
133 logger.debug("IOTLAB_API GetKeys -key_dict %s \r\n " % (key_dict))
138 def AddPerson(self, record, add_to_ldap = True):
141 Adds a new account. Any fields specified in records are used,
142 otherwise defaults are used. Creates an appropriate login by calling
145 :param record: dictionary with the sfa user's properties.
146 :returns: a dicitonary with the status. If successful, the dictionary
147 boolean is set to True and there is a 'uid' key with the new login
148 added to LDAP, otherwise the bool is set to False and a key
149 'message' is in the dictionary, with the error message.
154 ret = self.__add_person_to_db(record)
157 ret = self.testbed_shell.ldap.LdapAddUser(record)
159 if ret['bool'] is True:
160 record['hrn'] = self.testbed_shell.root_auth + '.' + ret['uid']
161 logger.debug("IOTLAB_API AddPerson return code %s record %s "
163 self.__add_person_to_db(record)
166 def __add_person_to_db(self, user_dict):
168 Add a federated user straight to db when the user issues a lease
169 request with iotlab nodes and that he has not registered with iotlab
170 yet (that is he does not have a LDAP entry yet).
171 Uses parts of the routines in IotlabImport when importing user from
172 LDAP. Called by AddPerson, right after LdapAddUser.
173 :param user_dict: Must contain email, hrn and pkey to get a GID
174 and be added to the SFA db.
175 :type user_dict: dict
178 query = self.api.dbsession().query(RegUser)
179 check_if_exists = query.filter_by(email = user_dict['email']).first()
180 logger.debug("LOIC __add_person_to_db %s" % check_if_exists)
182 if not check_if_exists:
183 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
185 hrn = user_dict['hrn']
186 person_urn = hrn_to_urn(hrn, 'user')
188 pubkey = user_dict['pkey']
189 pkey = convert_public_key(pubkey)
191 #key not good. create another pkey
192 logger.warn('__add_person_to_db: no public key or unable to convert public \
194 pkey = Keypair(create=True)
197 if pubkey is not None and pkey is not None :
198 hierarchy = Hierarchy()
199 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
201 if user_dict['email']:
202 logger.debug("__add_person_to_db \r\n \r\n \
203 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
204 %(user_dict['email']))
205 person_gid.set_email(user_dict['email'])
207 user_record = RegUser(hrn=hrn , pointer= '-1', \
208 authority=get_authority(hrn), \
209 email=user_dict['email'], gid = person_gid)
210 #user_record.reg_keys = [RegKey(user_dict['pkey'])]
211 user_record.just_created()
212 self.api.dbsession().add (user_record)
213 self.api.dbsession().commit()
218 def _sql_get_slice_info(self, slice_filter):
220 Get the slice record based on the slice hrn. Fetch the record of the
221 user associated with the slice by using joinedload based on the
222 reg_researchers relationship.
224 :param slice_filter: the slice hrn we are looking for
225 :type slice_filter: string
226 :returns: the slice record enhanced with the user's information if the
227 slice was found, None it wasn't.
229 :rtype: dict or None.
231 #DO NOT USE RegSlice - reg_researchers to get the hrn
232 #of the user otherwise will mess up the RegRecord in
233 #Resolve, don't know why - SA 08/08/2012
235 #Only one entry for one user = one slice in testbed_xp table
236 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
238 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
239 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
241 #load_reg_researchers
242 #raw_slicerec.reg_researchers
243 raw_slicerec = raw_slicerec.__dict__
244 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
245 raw_slicerec %s" % (slice_filter, raw_slicerec))
246 slicerec = raw_slicerec
247 #only one researcher per slice so take the first one
248 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
249 #del slicerec['reg_researchers']['_sa_instance_state']
255 def _sql_get_slice_info_from_user(self, slice_filter):
257 Get the slice record based on the user recordid by using a joinedload
258 on the relationship reg_slices_as_researcher. Format the sql record
259 into a dict with the mandatory fields for user and slice.
260 :returns: dict with slice record and user record if the record was found
261 based on the user's id, None if not..
262 :rtype:dict or None..
264 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
265 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
266 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
267 #Put it in correct order
268 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
269 'classtype', 'authority', 'gid', 'record_id',
270 'date_created', 'type', 'email', 'pointer']
271 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
272 'classtype', 'authority', 'gid', 'record_id',
273 'date_created', 'type', 'pointer']
275 #raw_slicerec.reg_slices_as_researcher
276 raw_slicerec = raw_slicerec.__dict__
279 dict([(k, raw_slicerec[
280 'reg_slices_as_researcher'][0].__dict__[k])
281 for k in slice_needed_fields])
282 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
283 for k in user_needed_fields])
284 #TODO Handle multiple slices for one user SA 10/12/12
285 #for now only take the first slice record associated to the rec user
286 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
287 #del raw_slicerec['reg_slices_as_researcher']
288 #slicerec['reg_researchers'] = raw_slicerec
289 ##del slicerec['_sa_instance_state']
298 def _get_slice_records(self, slice_filter=None,
299 slice_filter_type=None):
301 Get the slice record depending on the slice filter and its type.
302 :param slice_filter: Can be either the slice hrn or the user's record
304 :type slice_filter: string
305 :param slice_filter_type: describes the slice filter type used, can be
306 slice_hrn or record_id_user
308 :returns: the slice record
310 .. seealso::_sql_get_slice_info_from_user
311 .. seealso:: _sql_get_slice_info
313 logger.debug("JORDAN get_slice_records slice_filter=%r slice_filter_type=%r" % (slice_filter, slice_filter_type))
315 #Get list of slices based on the slice hrn
316 if slice_filter_type == 'slice_hrn':
318 #if get_authority(slice_filter) == self.root_auth:
319 #login = slice_filter.split(".")[1].split("_")[0]
321 slicerec = self._sql_get_slice_info(slice_filter)
327 #Get slice based on user id
328 if slice_filter_type == 'record_id_user':
330 slicerec = self._sql_get_slice_info_from_user(slice_filter)
333 fixed_slicerec_dict = slicerec
334 #At this point if there is no login it means
335 #record_id_user filter has been used for filtering
337 ##If theslice record is from iotlab
338 #if fixed_slicerec_dict['peer_authority'] is None:
339 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
340 #return login, fixed_slicerec_dict
341 return fixed_slicerec_dict
347 def GetSlices(self, slice_filter=None, slice_filter_type=None,
349 """Get the slice records from the iotlab db and add lease information
352 :param slice_filter: can be the slice hrn or slice record id in the db
353 depending on the slice_filter_type.
354 :param slice_filter_type: defines the type of the filtering used, Can be
355 either 'slice_hrn' or "record_id'.
356 :type slice_filter: string
357 :type slice_filter_type: string
358 :returns: a slice dict if slice_filter and slice_filter_type
359 are specified and a matching entry is found in the db. The result
360 is put into a list.Or a list of slice dictionnaries if no filters
367 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
368 return_slicerec_dictlist = []
370 #First try to get information on the slice based on the filter provided
371 if slice_filter_type in authorized_filter_types_list:
372 logger.debug("JORDAN GET SLICES 1")
373 fixed_slicerec_dict = self._get_slice_records(slice_filter,
375 logger.debug("JORDAN GET SLICE RECORDS %r" % fixed_slicerec_dict)
376 # if the slice was not found in the sfa db
377 if fixed_slicerec_dict is None:
378 return return_slicerec_dictlist
380 slice_hrn = fixed_slicerec_dict['hrn']
382 logger.debug(" IOTLAB_API \tGetSlices login %s \
383 slice record %s slice_filter %s \
384 slice_filter_type %s " % (login,
385 fixed_slicerec_dict, slice_filter,
389 #Now we have the slice record fixed_slicerec_dict, get the
390 #jobs associated to this slice
393 leases_list = self.GetLeases(login=login)
394 #If no job is running or no job scheduled
395 #return only the slice record
396 if leases_list == [] and fixed_slicerec_dict:
397 logger.debug("JORDAN CASE 1")
398 return_slicerec_dictlist.append(fixed_slicerec_dict)
400 # if the jobs running don't belong to the user/slice we are looking
402 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
403 if slice_hrn not in leases_hrn:
404 logger.debug("JORDAN CASE 2")
405 return_slicerec_dictlist.append(fixed_slicerec_dict)
406 #If several jobs for one slice , put the slice record into
407 # each lease information dict
408 for lease in leases_list:
410 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
411 \t lease['slice_hrn'] %s"
412 % (slice_filter, lease['slice_hrn']))
413 if lease['slice_hrn'] == slice_hrn:
414 slicerec_dict['oar_job_id'] = lease['lease_id']
415 #Update lease dict with the slice record
416 if fixed_slicerec_dict:
417 fixed_slicerec_dict['oar_job_id'] = []
418 fixed_slicerec_dict['oar_job_id'].append(
419 slicerec_dict['oar_job_id'])
420 slicerec_dict.update(fixed_slicerec_dict)
421 #slicerec_dict.update({'hrn':\
422 #str(fixed_slicerec_dict['slice_hrn'])})
423 slicerec_dict['slice_hrn'] = lease['slice_hrn']
424 slicerec_dict['hrn'] = lease['slice_hrn']
425 slicerec_dict['user'] = lease['user']
426 slicerec_dict.update(
428 {'hostname': lease['reserved_nodes']}})
429 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
433 return_slicerec_dictlist.append(slicerec_dict)
435 logger.debug("IOTLAB_API.PY \tGetSlices \
436 slicerec_dict %s return_slicerec_dictlist %s \
437 lease['reserved_nodes'] \
438 %s" % (slicerec_dict, return_slicerec_dictlist,
439 lease['reserved_nodes']))
441 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
442 return_slicerec_dictlist %s"
443 % (return_slicerec_dictlist))
445 return return_slicerec_dictlist
449 logger.debug("JORDAN GET SLICES 2")
450 #Get all slices from the iotlab sfa database ,
451 #put them in dict format
452 #query_slice_list = dbsession.query(RegRecord).all()
454 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
456 for record in query_slice_list:
457 tmp = record.__dict__
458 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
459 #del tmp['reg_researchers']['_sa_instance_state']
460 return_slicerec_dictlist.append(tmp)
461 #return_slicerec_dictlist.append(record.__dict__)
463 #Get all the jobs reserved nodes
464 leases_list = self.testbed_shell.GetReservedNodes()
466 for fixed_slicerec_dict in return_slicerec_dictlist:
468 #Check if the slice belongs to a iotlab user
469 if fixed_slicerec_dict['peer_authority'] is None:
470 owner = fixed_slicerec_dict['hrn'].split(
471 ".")[1].split("_")[0]
474 for lease in leases_list:
475 if owner == lease['user']:
476 slicerec_dict['oar_job_id'] = lease['lease_id']
478 #for reserved_node in lease['reserved_nodes']:
479 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
481 slicerec_dict.update(fixed_slicerec_dict)
482 slicerec_dict.update({'node_ids':
483 lease['reserved_nodes']})
484 slicerec_dict.update({'list_node_ids':
486 lease['reserved_nodes']}})
488 #slicerec_dict.update({'hrn':\
489 #str(fixed_slicerec_dict['slice_hrn'])})
490 #return_slicerec_dictlist.append(slicerec_dict)
491 fixed_slicerec_dict.update(slicerec_dict)
493 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
494 return_slicerec_dictlist %s \t slice_filter %s " \
495 %(return_slicerec_dictlist, slice_filter))
497 return return_slicerec_dictlist
499 def AddLeases(self, hostname_list, slice_record,
500 lease_start_time, lease_duration):
502 """Creates a job in OAR corresponding to the information provided
503 as parameters. Adds the job id and the slice hrn in the iotlab
504 database so that we are able to know which slice has which nodes.
506 :param hostname_list: list of nodes' OAR hostnames.
507 :param slice_record: sfa slice record, must contain login and hrn.
508 :param lease_start_time: starting time , unix timestamp format
509 :param lease_duration: duration in minutes
511 :type hostname_list: list
512 :type slice_record: dict
513 :type lease_start_time: integer
514 :type lease_duration: integer
515 :returns: job_id, can be None if the job request failed.
518 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
519 slice_record %s lease_start_time %s lease_duration %s "\
520 %( hostname_list, slice_record , lease_start_time, \
523 #tmp = slice_record['reg-researchers'][0].split(".")
524 username = slice_record['login']
525 #username = tmp[(len(tmp)-1)]
526 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
527 slice_record['hrn'], \
528 lease_start_time, lease_duration, \
530 if job_id is not None:
532 datetime.fromtimestamp(int(lease_start_time)).\
533 strftime(self.testbed_shell.time_format)
534 end_time = lease_start_time + lease_duration
537 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
538 %s %s %s "%(slice_record['hrn'], job_id, end_time))
541 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
542 %(type(slice_record['hrn']), type(job_id), type(end_time)))
544 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
545 experiment_id=job_id,
548 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
550 self.api.dbsession().add(iotlab_ex_row)
551 self.api.dbsession().commit()
553 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
558 def GetLeases(self, lease_filter_dict=None, login=None):
561 Get the list of leases from OAR with complete information
562 about which slice owns which jobs and nodes.
564 -Fetch all the jobs from OAR (running, waiting..)
565 complete the reservation information with slice hrn
566 found in lease_table . If not available in the table,
567 assume it is a iotlab slice.
568 -Updates the iotlab table, deleting jobs when necessary.
570 :returns: reservation_list, list of dictionaries with 'lease_id',
571 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
572 'slice_hrn', 'resource_ids', 't_from', 't_until'
577 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
579 reservation_list = []
580 #Find the slice associated with this user iotlab ldap uid
581 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
582 unfiltered_reservation_list %s "
583 % (login, unfiltered_reservation_list))
584 #Create user dict first to avoid looking several times for
585 #the same user in LDAP SA 27/07/12
587 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
588 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
589 for row in jobs_psql_query])
590 #jobs_psql_dict = jobs_psql_dict)
591 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
593 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
595 for resa in unfiltered_reservation_list:
596 logger.debug("IOTLAB_API \tGetLeases USER %s"
598 #Construct list of jobs (runing, waiting..) in oar
599 job_oar_list.append(resa['lease_id'])
600 #If there is information on the job in IOTLAB DB ]
601 #(slice used and job id)
602 if resa['lease_id'] in jobs_psql_dict:
603 job_info = jobs_psql_dict[resa['lease_id']]
604 logger.debug("IOTLAB_API \tGetLeases job_info %s"
606 resa['slice_hrn'] = job_info['slice_hrn']
607 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
609 #otherwise, assume it is a iotlab slice:
611 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
612 + '.' + resa['user'] + "_slice",
614 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
616 resa['component_id_list'] = []
617 #Transform the hostnames into urns (component ids)
618 for node in resa['reserved_nodes']:
620 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
621 resa['component_id_list'].append(iotlab_xrn.urn)
623 if lease_filter_dict:
624 logger.debug("IOTLAB_API \tGetLeases \
625 \r\n leasefilter %s" % ( lease_filter_dict))
627 # filter_dict_functions = {
628 # 'slice_hrn' : IotlabShell.filter_lease_name,
629 # 't_from' : IotlabShell.filter_lease_start_time
631 reservation_list = list(unfiltered_reservation_list)
632 for filter_type in lease_filter_dict:
633 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
634 % (reservation_list))
635 reservation_list = self.testbed_shell.filter_lease(
636 reservation_list,filter_type,
637 lease_filter_dict[filter_type] )
639 # Filter the reservation list with a maximum timespan so that the
640 # leases and jobs running after this timestamp do not appear
641 # in the result leases.
642 # if 'start_time' in :
643 # if resa['start_time'] < lease_filter_dict['start_time']:
644 # reservation_list.append(resa)
647 # if 'name' in lease_filter_dict and \
648 # lease_filter_dict['name'] == resa['slice_hrn']:
649 # reservation_list.append(resa)
652 if lease_filter_dict is None:
653 reservation_list = unfiltered_reservation_list
655 self.update_experiments_in_lease_table(job_oar_list, jobs_psql_id_list)
657 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
658 % (reservation_list))
659 return reservation_list
663 def update_experiments_in_lease_table(self,
664 experiment_list_from_testbed, experiment_list_in_db):
665 """ Cleans the lease_table by deleting expired and cancelled jobs.
667 Compares the list of experiment ids given by the testbed with the
668 experiment ids that are already in the database, deletes the
669 experiments that are no longer in the testbed experiment id list.
671 :param experiment_list_from_testbed: list of experiment ids coming
673 :type experiment_list_from_testbed: list
674 :param experiment_list_in_db: list of experiment ids from the sfa
675 additionnal database.
676 :type experiment_list_in_db: list
680 #Turn the list into a set
681 set_experiment_list_in_db = set(experiment_list_in_db)
683 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
684 logger.debug("\r\n \t update_experiments_in_lease_table \
685 experiment_list_in_db %s \r\n \
686 experiment_list_from_testbed %s \
687 kept_experiments %s "
688 % (set_experiment_list_in_db,
689 experiment_list_from_testbed, kept_experiments))
690 deleted_experiments = set_experiment_list_in_db.difference(
692 deleted_experiments = list(deleted_experiments)
693 if len(deleted_experiments) > 0:
694 request = self.api.dbsession().query(LeaseTableXP)
695 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
696 self.api.dbsession().commit()
700 def AddSlice(self, slice_record, user_record):
703 Add slice to the local iotlab sfa tables if the slice comes
704 from a federated site and is not yet in the iotlab sfa DB,
705 although the user has already a LDAP login.
706 Called by verify_slice during lease/sliver creation.
708 :param slice_record: record of slice, must contain hrn, gid, slice_id
709 and authority of the slice.
710 :type slice_record: dictionary
711 :param user_record: record of the user
712 :type user_record: RegUser
716 sfa_record = RegSlice(hrn=slice_record['hrn'],
717 gid=slice_record['gid'],
718 #pointer=slice_record['slice_id'],
719 authority=slice_record['authority'])
720 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
721 % (sfa_record, user_record))
722 sfa_record.just_created()
723 self.api.dbsession().add(sfa_record)
724 self.api.dbsession().commit()
725 #Update the reg-researchers dependency table
726 if user_record is not None:
727 sfa_record.reg_researchers = [user_record]
729 sfa_record.reg_researchers = slice_record['reg-researchers']
730 self.api.dbsession().commit()
734 def augment_records_with_testbed_info(self, record_list):
737 Adds specific testbed info to the records.
739 :param record_list: list of sfa dictionaries records
740 :type record_list: list
741 :returns: list of records with extended information in each record
745 return self.fill_record_info(record_list)
747 def fill_record_info(self, record_list):
750 For each SFA record, fill in the iotlab specific and SFA specific
751 fields in the record.
753 :param record_list: list of sfa dictionaries records
754 :type record_list: list
755 :returns: list of records with extended information in each record
758 .. warning:: Should not be modifying record_list directly because modi
759 fication are kept outside the method's scope. Howerver, there is no
760 other way to do it given the way it's called in registry manager.
764 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
766 if not isinstance(record_list, list):
767 record_list = [record_list]
770 for record in record_list:
772 if str(record['type']) == 'node':
773 # look for node info using GetNodes
774 # the record is about one node only
775 filter_dict = {'hrn': [record['hrn']]}
776 node_info = self.testbed_shell.GetNodes(filter_dict)
777 # the node_info is about one node only, but it is formatted
779 record.update(node_info[0])
780 logger.debug("IOTLABDRIVER.PY \t \
781 fill_record_info NODE" % (record))
783 #If the record is a SFA slice record, then add information
784 #about the user of this slice. This kind of
785 #information is in the Iotlab's DB.
786 if str(record['type']) == 'slice':
787 if 'reg_researchers' in record and isinstance(record
790 record['reg_researchers'] = \
791 record['reg_researchers'][0].__dict__
793 {'PI': [record['reg_researchers']['hrn']],
794 'researcher': [record['reg_researchers']['hrn']],
795 'name': record['hrn'],
798 'person_ids': [record['reg_researchers']
800 # For client_helper.py compatibility
802 # For client_helper.py compatibility
804 # For client_helper.py compatibility
807 #Get iotlab slice record and oar job id if any.
808 recslice_list = self.GetSlices(
809 slice_filter=str(record['hrn']),
810 slice_filter_type='slice_hrn')
812 logger.debug("IOTLABDRIVER \tfill_record_info \
813 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
814 %s " % (record['hrn'], record['oar_job_id']))
815 del record['reg_researchers']
817 for rec in recslice_list:
818 logger.debug("IOTLABDRIVER\r\n \t \
819 fill_record_info oar_job_id %s "
820 % (rec['oar_job_id']))
822 record['node_ids'] = [self.testbed_shell.root_auth +
823 '.' + hostname for hostname
828 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
829 recslice_list %s \r\n \t RECORD %s \r\n \
830 \r\n" % (recslice_list, record))
832 if str(record['type']) == 'user':
833 #The record is a SFA user record.
834 #Get the information about his slice from Iotlab's DB
835 #and add it to the user record.
836 recslice_list = self.GetSlices(
837 slice_filter=record['record_id'],
838 slice_filter_type='record_id_user')
840 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
841 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
842 % (recslice_list, record))
843 #Append slice record in records list,
844 #therefore fetches user and slice info again(one more loop)
845 #Will update PIs and researcher for the slice
847 recuser = recslice_list[0]['reg_researchers']
848 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
849 recuser %s \r\n \r\n" % (recuser))
851 recslice = recslice_list[0]
853 {'PI': [recuser['hrn']],
854 'researcher': [recuser['hrn']],
855 'name': recuser['hrn'],
858 'person_ids': [recuser['record_id']]})
860 for rec in recslice_list:
861 recslice['oar_job_id'].append(rec['oar_job_id'])
865 recslice.update({'type': 'slice',
866 'hrn': recslice_list[0]['hrn']})
868 #GetPersons takes [] as filters
869 user_iotlab = self.testbed_shell.GetPersons([record])
871 record.update(user_iotlab[0])
872 #For client_helper.py compatibility
877 record_list.append(recslice)
879 logger.debug("IOTLABDRIVER.PY \t \
880 fill_record_info ADDING SLICE\
881 INFO TO USER records %s" % (record_list))
883 except TypeError, error:
884 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
889 def sliver_status(self, slice_urn, slice_hrn):
891 Receive a status request for slice named urn/hrn
892 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
893 shall return a structure as described in
894 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
895 NT : not sure if we should implement this or not, but used by sface.
897 :param slice_urn: slice urn
898 :type slice_urn: string
899 :param slice_hrn: slice hrn
900 :type slice_hrn: string
904 #First get the slice with the slice hrn
905 slice_list = self.GetSlices(slice_filter=slice_hrn,
906 slice_filter_type='slice_hrn')
908 if len(slice_list) == 0:
909 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
911 #Used for fetching the user info witch comes along the slice info
912 one_slice = slice_list[0]
914 #Make a list of all the nodes hostnames in use for this slice
915 slice_nodes_list = []
916 slice_nodes_list = one_slice['node_ids']
917 #Get all the corresponding nodes details
918 nodes_all = self.testbed_shell.GetNodes(
919 {'hostname': slice_nodes_list},
920 ['node_id', 'hostname', 'site', 'boot_state'])
921 nodeall_byhostname = dict([(one_node['hostname'], one_node)
922 for one_node in nodes_all])
924 for single_slice in slice_list:
926 top_level_status = 'empty'
929 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
930 'geni_resources'], None)
932 # ['geni_urn','geni_error', 'pl_login','geni_status',
933 # 'geni_resources'], None)
934 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
935 result['iotlab_login'] = one_slice['user']
936 logger.debug("Slabdriver - sliver_status Sliver status \
937 urn %s hrn %s single_slice %s \r\n "
938 % (slice_urn, slice_hrn, single_slice))
940 if 'node_ids' not in single_slice:
942 result['geni_status'] = top_level_status
943 result['geni_resources'] = []
946 top_level_status = 'ready'
948 #A job is running on Iotlab for this slice
949 # report about the local nodes that are in the slice only
951 result['geni_urn'] = slice_urn
954 for node_hostname in single_slice['node_ids']:
956 res['iotlab_hostname'] = node_hostname
957 res['iotlab_boot_state'] = \
958 nodeall_byhostname[node_hostname]['boot_state']
960 #res['pl_hostname'] = node['hostname']
961 #res['pl_boot_state'] = \
962 #nodeall_byhostname[node['hostname']]['boot_state']
963 #res['pl_last_contact'] = strftime(self.time_format, \
964 #gmtime(float(timestamp)))
966 slice_urn, type='slice',
967 id=nodeall_byhostname[node_hostname]['node_id']).urn
969 res['geni_urn'] = sliver_id
970 #node_name = node['hostname']
971 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
973 res['geni_status'] = 'ready'
975 res['geni_status'] = 'failed'
976 top_level_status = 'failed'
978 res['geni_error'] = ''
980 resources.append(res)
982 result['geni_status'] = top_level_status
983 result['geni_resources'] = resources
984 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
988 def get_user_record(self, hrn):
991 Returns the user record based on the hrn from the SFA DB .
993 :param hrn: user's hrn
995 :returns: user record from SFA database
999 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
1001 def testbed_name(self):
1004 Returns testbed's name.
1005 :returns: testbed authority name.
1012 def _get_requested_leases_list(self, rspec):
1014 Process leases in rspec depending on the rspec version (format)
1015 type. Find the lease requests in the rspec and creates
1016 a lease request list with the mandatory information ( nodes,
1017 start time and duration) of the valid leases (duration above or
1018 equal to the iotlab experiment minimum duration).
1020 :param rspec: rspec request received.
1022 :returns: list of lease requests found in the rspec
1025 requested_lease_list = []
1026 for lease in rspec.version.get_leases():
1027 single_requested_lease = {}
1028 logger.debug("IOTLABDRIVER.PY \t \
1029 _get_requested_leases_list lease %s " % (lease))
1031 if not lease.get('lease_id'):
1032 if get_authority(lease['component_id']) == \
1033 self.testbed_shell.root_auth:
1034 single_requested_lease['hostname'] = \
1036 lease.get('component_id').strip())
1037 single_requested_lease['start_time'] = \
1038 lease.get('start_time')
1039 single_requested_lease['duration'] = lease.get('duration')
1040 #Check the experiment's duration is valid before adding
1041 #the lease to the requested leases list
1042 duration_in_seconds = \
1043 int(single_requested_lease['duration'])
1044 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1045 requested_lease_list.append(single_requested_lease)
1047 return requested_lease_list
1050 def _group_leases_by_start_time(requested_lease_list):
1052 Create dict of leases by start_time, regrouping nodes reserved
1053 at the same time, for the same amount of time so as to
1054 define one job on OAR.
1056 :param requested_lease_list: list of leases
1057 :type requested_lease_list: list
1058 :returns: Dictionary with key = start time, value = list of leases
1059 with the same start time.
1064 requested_xp_dict = {}
1065 for lease in requested_lease_list:
1067 #In case it is an asap experiment start_time is empty
1068 if lease['start_time'] == '':
1069 lease['start_time'] = '0'
1071 if lease['start_time'] not in requested_xp_dict:
1072 if isinstance(lease['hostname'], str):
1073 lease['hostname'] = [lease['hostname']]
1075 requested_xp_dict[lease['start_time']] = lease
1078 job_lease = requested_xp_dict[lease['start_time']]
1079 if lease['duration'] == job_lease['duration']:
1080 job_lease['hostname'].append(lease['hostname'])
1082 return requested_xp_dict
1084 def _process_requested_xp_dict(self, rspec):
1086 Turns the requested leases and information into a dictionary
1087 of requested jobs, grouped by starting time.
1089 :param rspec: RSpec received
1094 requested_lease_list = self._get_requested_leases_list(rspec)
1095 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1096 requested_lease_list %s" % (requested_lease_list))
1097 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1098 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1105 def delete(self, slice_urns, options={}):
1107 Deletes the lease associated with the slice hrn and the credentials
1108 if the slice belongs to iotlab. Answer to DeleteSliver.
1110 :param slice_urn: urn of the slice
1111 :type slice_urn: string
1114 :returns: 1 if the slice to delete was not found on iotlab,
1115 True if the deletion was successful, False otherwise otherwise.
1117 .. note:: Should really be named delete_leases because iotlab does
1118 not have any slivers, but only deals with leases. However,
1119 SFA api only have delete_sliver define so far. SA 13/05/2013
1120 .. note:: creds are unused, and are not used either in the dummy driver
1123 # collect sliver ids so we can update sliver allocation states after
1124 # we remove the slivers.
1125 aggregate = IotlabAggregate(self)
1126 slivers = aggregate.get_slivers(slice_urns)
1128 # slice_id = slivers[0]['slice_id']
1131 sliver_jobs_dict = {}
1132 for sliver in slivers:
1133 node_ids.append(sliver['node_id'])
1134 sliver_ids.append(sliver['sliver_id'])
1135 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1136 sliver_jobs_dict[job_id] = sliver['sliver_id']
1137 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1138 % (slivers, slice_urns))
1139 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1141 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1142 slice_filter_type='slice_hrn')
1144 if not sfa_slice_list:
1147 #Delete all leases in the slice
1148 for sfa_slice in sfa_slice_list:
1149 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1150 slices = IotlabSlices(self)
1151 # determine if this is a peer slice
1153 peer = slices.get_peer(slice_hrn)
1155 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1156 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1157 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1159 for job_id in oar_bool_ans:
1160 # if the job has not been successfully deleted
1161 # don't delete the associated sliver
1162 # remove it from the sliver list
1163 if oar_bool_ans[job_id] is False:
1164 sliver = sliver_jobs_dict[job_id]
1165 sliver_ids.remove(sliver)
1168 dbsession = self.api.dbsession()
1169 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1171 logger.log_exc("IOTLABDRIVER.PY delete error ")
1173 # prepare return struct
1175 for sliver in slivers:
1176 geni_slivers.append(
1177 {'geni_sliver_urn': sliver['sliver_id'],
1178 'geni_allocation_status': 'geni_unallocated',
1179 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1185 def list_slices(self, creds, options):
1186 """Answer to ListSlices.
1188 List slices belonging to iotlab, returns slice urns list.
1189 No caching used. Options unused but are defined in the SFA method
1192 :returns: slice urns list
1195 .. note:: creds and options are unused - SA 12/12/13
1197 # look in cache first
1199 #slices = self.cache.get('slices')
1201 #logger.debug("PlDriver.list_slices returns from cache")
1206 slices = self.GetSlices()
1207 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1209 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1211 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1212 for slice_hrn in slice_hrns]
1216 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1217 #self.cache.add('slices', slice_urns)
1222 def register(self, sfa_record, hrn, pub_key):
1224 Adding new user, slice, node or site should not be handled
1227 ..warnings:: should not be used. Different components are in charge of
1228 doing this task. Adding nodes = OAR
1229 Adding users = LDAP Iotlab
1230 Adding slice = Import from LDAP users
1233 :param sfa_record: record provided by the client of the
1235 :type sfa_record: dict
1236 :param pub_key: public key of the user
1237 :type pub_key: string
1239 .. note:: DOES NOTHING. Returns -1.
1245 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1247 No site or node record update allowed in Iotlab. The only modifications
1248 authorized here are key deletion/addition on an existing user and
1249 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1250 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1251 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1252 user's ssh key should nmodify the slice's GID after an import procedure.
1254 :param old_sfa_record: what is in the db for this hrn
1255 :param new_sfa_record: what was passed to the update call
1256 :param new_key: the new user's public key
1257 :param hrn: the user's sfa hrn
1258 :type old_sfa_record: dict
1259 :type new_sfa_record: dict
1260 :type new_key: string
1264 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1265 since users, keys and slice are managed by the LDAP.
1268 # pointer = old_sfa_record['pointer']
1269 # old_sfa_record_type = old_sfa_record['type']
1271 # # new_key implemented for users only
1272 # if new_key and old_sfa_record_type not in ['user']:
1273 # raise UnknownSfaType(old_sfa_record_type)
1275 # if old_sfa_record_type == "user":
1276 # update_fields = {}
1277 # all_fields = new_sfa_record
1278 # for key in all_fields.keys():
1279 # if key in ['key', 'password']:
1280 # update_fields[key] = all_fields[key]
1283 # # must check this key against the previous one if it exists
1284 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1285 # person = persons[0]
1286 # keys = [person['pkey']]
1287 # #Get all the person's keys
1288 # keys_dict = self.GetKeys(keys)
1290 # # Delete all stale keys, meaning the user has only one key
1292 # #TODO: do we really want to delete all the other keys?
1293 # #Is this a problem with the GID generation to have multiple
1294 # #keys? SA 30/05/13
1295 # key_exists = False
1296 # if key in keys_dict:
1299 # #remove all the other keys
1300 # for key in keys_dict:
1301 # self.testbed_shell.DeleteKey(person, key)
1302 # self.testbed_shell.AddPersonKey(
1303 # person, {'sshPublicKey': person['pkey']},
1304 # {'sshPublicKey': new_key})
1305 logger.warning ("UNDEFINED - Update should be done by the \
1309 def remove(self, sfa_record):
1312 Removes users only. Mark the user as disabled in LDAP. The user and his
1313 slice are then deleted from the db by running an import on the registry.
1315 :param sfa_record: record is the existing sfa record in the db
1316 :type sfa_record: dict
1318 ..warning::As fas as the slice is concerned, here only the leases are
1319 removed from the slice. The slice is record itself is not removed
1324 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1326 TODO: return boolean for the slice part
1328 sfa_record_type = sfa_record['type']
1329 hrn = sfa_record['hrn']
1330 if sfa_record_type == 'user':
1332 #get user from iotlab ldap
1333 person = self.testbed_shell.GetPersons(sfa_record)
1334 #No registering at a given site in Iotlab.
1335 #Once registered to the LDAP, all iotlab sites are
1338 #Mark account as disabled in ldap
1339 return self.testbed_shell.DeletePerson(sfa_record)
1341 elif sfa_record_type == 'slice':
1342 if self.GetSlices(slice_filter=hrn,
1343 slice_filter_type='slice_hrn'):
1344 ret = self.testbed_shell.DeleteSlice(sfa_record)
1347 def check_sliver_credentials(self, creds, urns):
1348 """Check that the sliver urns belongs to the slice specified in the
1351 :param urns: list of sliver urns.
1353 :param creds: slice credentials.
1354 :type creds: Credential object.
1358 # build list of cred object hrns
1359 slice_cred_names = []
1361 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1362 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1363 slice_cred_names.append(slicename)
1365 # look up slice name of slivers listed in urns arg
1369 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1371 slice_ids.append(int(sliver_id_parts[0]))
1376 raise Forbidden("sliver urn not provided")
1378 slices = self.GetSlices(slice_ids)
1379 sliver_names = [single_slice['name'] for single_slice in slices]
1381 # make sure we have a credential for every specified sliver
1382 for sliver_name in sliver_names:
1383 if sliver_name not in slice_cred_names:
1384 msg = "Valid credential not found for target: %s" % sliver_name
1385 raise Forbidden(msg)
1387 ########################################
1388 ########## aggregate oriented
1389 ########################################
1391 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1392 def aggregate_version(self):
1395 Returns the testbed's supported rspec advertisement and request
1397 :returns: rspec versions supported ad a dictionary.
1401 version_manager = VersionManager()
1402 ad_rspec_versions = []
1403 request_rspec_versions = []
1404 for rspec_version in version_manager.versions:
1405 if rspec_version.content_type in ['*', 'ad']:
1406 ad_rspec_versions.append(rspec_version.to_dict())
1407 if rspec_version.content_type in ['*', 'request']:
1408 request_rspec_versions.append(rspec_version.to_dict())
1410 'testbed': self.testbed_name(),
1411 'geni_request_rspec_versions': request_rspec_versions,
1412 'geni_ad_rspec_versions': ad_rspec_versions}
1414 # first 2 args are None in case of resource discovery
1415 def list_resources (self, version=None, options={}):
1416 aggregate = IotlabAggregate(self)
1417 rspec = aggregate.list_resources(version=version, options=options)
1420 def describe(self, urns, version, options={}):
1421 aggregate = IotlabAggregate(self)
1422 return aggregate.describe(urns, version=version, options=options)
1424 def status (self, urns, options={}):
1425 aggregate = IotlabAggregate(self)
1426 desc = aggregate.describe(urns, version='GENI 3')
1427 status = {'geni_urn': desc['geni_urn'],
1428 'geni_slivers': desc['geni_slivers']}
1432 def allocate (self, urn, rspec_string, expiration, options={}):
1434 aggregate = IotlabAggregate(self)
1436 slices = IotlabSlices(self)
1437 peer = slices.get_peer(xrn.get_hrn())
1438 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1440 caller_hrn = options.get('actual_caller_hrn', [])
1441 caller_xrn = Xrn(caller_hrn)
1442 caller_urn = caller_xrn.get_urn()
1444 logger.debug("IOTLABDRIVER.PY :: Allocate caller = %s" % (caller_urn))
1447 users = options.get('geni_users', [])
1448 sfa_users = options.get('sfa_users', [])
1452 # Looking for the user who actually called the Allocate function in the list of users of the slice
1454 if 'urn' in u and u['urn'] == caller_urn:
1456 logger.debug("user = %s" % u)
1457 # If we find the user in the list we use it, else we take the 1st in the list as before
1459 user_hrn = caller_hrn
1462 # XXX Always empty ??? no slice_record in the Allocate call
1463 #slice_record = sfa_users[0].get('slice_record', [])
1464 user_xrn = Xrn(sfa_users[0]['urn'])
1465 user_hrn = user_xrn.get_hrn()
1467 slice_record = user.get('slice_record', {})
1468 slice_record['user'] = {'keys': user['keys'],
1469 'email': user['email'],
1471 slice_record['authority'] = xrn.get_authority_hrn()
1473 logger.debug("IOTLABDRIVER.PY \t urn %s allocate options %s "
1477 rspec = RSpec(rspec_string)
1478 # requested_attributes = rspec.version.get_slice_attributes()
1480 # ensure site record exists
1482 # ensure person records exists
1484 # oui c'est degueulasse, le slice_record se retrouve modifie
1485 # dans la methode avec les infos du user, els infos sont propagees
1486 # dans verify_slice_leases
1487 logger.debug("IOTLABDRIVER.PY BEFORE slices.verify_persons")
1488 # XXX JORDAN XXX slice_record devrait recevoir le caller_xrn...
1489 logger.debug("LOIC users = %r" % users)
1490 # XXX LOIC XXX Trying here to bypass the verify_persons function
1491 # But it doesn't work, It seems we have to add users in LDAP anyway...
1493 # XXX LOIC using hrn is a workaround because the function
1494 # Xrn.get_urn returns 'urn:publicid:IDN+onelab:upmc+timur_friedman'
1495 # Instead of this 'urn:publicid:IDN+onelab:upmc+user+timur_friedman'
1496 user['hrn'] = urn_to_hrn(user['urn'])[0]
1497 # XXX LOIC adding the users of the slice to reg-researchers
1498 # reg-researchers is used in iotlabslices.py verify_slice in order to add the slice
1499 if 'reg-researchers' not in slice_record:
1500 slice_record['reg-researchers'] = list()
1501 slice_record['reg-researchers'].append(user['hrn'])
1502 if caller_hrn == user['hrn']:
1503 #hierarchical_user = user['hrn'].split(".")
1504 #user['login'] = hierarchical_user[-1]
1505 #slice_record['login'] = user['login']
1506 slice_record['user']=user
1508 # XXX LOIC XXX Need to re-activate this function and understand exactly what is required
1510 persons = slices.verify_persons(xrn.hrn, slice_record, [slice_record['user']], options=options)
1511 logger.debug("IOTLABDRIVER.PY AFTER slices.verify_persons")
1512 logger.debug("LOIC - IOTLABDRIVER.PY - AFTER slices.verify_persons slice_record = %r" % slice_record)
1513 # ensure slice attributes exists
1514 # XXX LOIC XXX This method doesn't exist !!!
1515 #slices.verify_slice_attributes(slice, requested_attributes, options=options)
1517 # XXX LOIC !!! Essayons d'inverser : d'abord verify_persons ensuite verify_slice
1519 # ensure slice record exists
1520 # XXX LOIC !!! verify_slice uniquement pour iotlab - les slices externes ne doivent pas être vérifiés = Ils ne sont pas dans le registry IOTLAB
1521 current_slice = None
1522 #current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1523 #logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1524 # \r\n \r\n current_slice %s" % (current_slice))
1526 # add/remove slice from nodes
1527 # XXX JORDAN ensure requested_xp_dict returns a dict with all new leases
1528 requested_xp_dict = self._process_requested_xp_dict(rspec)
1530 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1531 % (requested_xp_dict))
1532 request_nodes = rspec.version.get_nodes_with_slivers()
1534 # JORDAN: nodes_list will contain a list of newly allocated nodes
1536 for start_time in requested_xp_dict:
1537 lease = requested_xp_dict[start_time]
1538 for hostname in lease['hostname']:
1539 nodes_list.append(hostname)
1541 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1542 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1543 % (nodes_list, slice_record))
1546 rspec_requested_leases = rspec.version.get_leases()
1547 leases = slices.verify_slice_leases(slice_record,
1548 requested_xp_dict, peer)
1550 # leases = already in slice
1551 # rspec_requested_leases = newly requested
1552 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1553 rspec_requested_leases %s" % (leases,
1554 rspec_requested_leases))
1556 # XXX LOIC !!! What is in the slice_record?
1557 # Where is affected reg_researchers value???
1558 logger.debug("LOIC - IOTLABDRIVER.PY - After verify_slice_leases slice_record = %r" %slice_record)
1559 # update sliver allocations
1560 # JORDAN Here we loop over newly allocated nodes
1561 for hostname in nodes_list:
1562 logger.debug("FORLOOP JORDAN hostname=%r" % hostname)
1563 client_id = hostname
1564 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1565 component_id = node_urn
1566 if current_slice is not None:
1567 if 'reg-urn' in current_slice:
1568 slice_urn = current_slice['reg-urn']
1570 slice_urn = current_slice['urn']
1572 slice_urn = slice_record['urn']
1573 # JORDAN: We loop over leases previously in the slice
1574 for lease in leases: # rspec_requested_leases ?????? XXX
1575 logger.debug("FOR LEASE LOOP JORDAN lease=%r" % lease)
1576 logger.debug("JORDAN hostname=%r lease['reserved_nodes']=%r, bool=%r" % (hostname, lease['reserved_nodes'], hostname in lease['reserved_nodes']))
1577 if hostname in lease['reserved_nodes']:
1578 logger.debug("JORDAN IF OK")
1579 index = lease['reserved_nodes'].index(hostname)
1580 logger.debug("JORDAN index=%r" % index)
1581 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1582 lease['resource_ids'][index] )
1584 logger.debug("LOIC sliver_hrn=%r" % sliver_hrn)
1585 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1587 logger.debug("LOIC sliver_id=%r" % sliver_id)
1588 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1589 component_id=component_id,
1590 slice_urn = slice_urn,
1591 allocation_state='geni_allocated')
1592 record.sync(self.api.dbsession())
1594 # JORDAN : added describe_options which was not specified at all
1595 describe_options = {
1596 'geni_slice_urn': urn,
1597 'list_leases': 'all',
1599 return aggregate.describe([xrn.get_urn()], version=rspec.version, options=describe_options)
1601 def provision(self, urns, options={}):
1603 slices = IotlabSlices(self)
1604 aggregate = IotlabAggregate(self)
1605 slivers = aggregate.get_slivers(urns)
1606 current_slice = slivers[0]
1607 logger.debug("Provision current slice: %r" % (current_slice,))
1608 peer = slices.get_peer(current_slice['hrn'])
1609 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1610 users = options.get('geni_users', [])
1611 # persons = slices.verify_persons(current_slice['hrn'],
1612 # current_slice, users, peer, sfa_peer, options=options)
1613 # slices.handle_peer(None, None, persons, peer)
1614 # update sliver allocation states and set them to geni_provisioned
1615 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1616 dbsession = self.api.dbsession()
1617 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1619 version_manager = VersionManager()
1620 rspec_version = version_manager.get_version(options[
1621 'geni_rspec_version'])
1622 # JORDAN : added describe_options instead of options
1623 # urns at the begining ???
1624 describe_options = {
1625 'geni_slice_urn': current_slice['urn'],
1626 'list_leases': 'all',
1628 return self.describe(urns, rspec_version, options=describe_options)