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):
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.
153 ret = self.testbed_shell.ldap.LdapAddUser(record)
155 if ret['bool'] is True:
156 #record['hrn'] = self.testbed_shell.root_auth + '.' + ret['uid']
157 logger.debug("IOTLAB_API AddPerson return code %s record %s "
159 #self.__add_person_to_db(record)
162 def add_person_to_db(self, user_dict):
164 Add a federated user straight to db when the user issues a lease
165 request with iotlab nodes and that he has not registered with iotlab
166 yet (that is he does not have a LDAP entry yet).
167 Uses parts of the routines in IotlabImport when importing user from
168 LDAP. Called by AddPerson, right after LdapAddUser.
169 :param user_dict: Must contain email, hrn and pkey to get a GID
170 and be added to the SFA db.
171 :type user_dict: dict
174 query = self.api.dbsession().query(RegUser)
175 check_if_exists = query.filter_by(email = user_dict['email']).first()
177 if not check_if_exists:
178 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
180 hrn = user_dict['hrn']
181 person_urn = hrn_to_urn(hrn, 'user')
183 pubkey = user_dict['pkey']
184 pkey = convert_public_key(pubkey)
186 #key not good. create another pkey
187 logger.warn('__add_person_to_db: no public key or unable to convert public \
189 pkey = Keypair(create=True)
192 if pubkey is not None and pkey is not None :
193 hierarchy = Hierarchy()
194 # We fake the parent in order to be able to create a valid GID
195 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
196 pkey, force_parent='iotlab')
197 if user_dict['email']:
198 logger.debug("__add_person_to_db \r\n \r\n \
199 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
200 %(user_dict['email']))
201 person_gid.set_email(user_dict['email'])
203 user_record = RegUser(hrn=hrn , pointer= '-1', \
204 authority=get_authority(hrn), \
205 email=user_dict['email'], gid = person_gid)
206 #user_record.reg_keys = [RegKey(user_dict['pkey'])]
207 user_record.just_created()
208 self.api.dbsession().add (user_record)
209 self.api.dbsession().commit()
214 def _sql_get_slice_info(self, slice_filter):
216 Get the slice record based on the slice hrn. Fetch the record of the
217 user associated with the slice by using joinedload based on the
218 reg_researchers relationship.
220 :param slice_filter: the slice hrn we are looking for
221 :type slice_filter: string
222 :returns: the slice record enhanced with the user's information if the
223 slice was found, None it wasn't.
225 :rtype: dict or None.
227 #DO NOT USE RegSlice - reg_researchers to get the hrn
228 #of the user otherwise will mess up the RegRecord in
229 #Resolve, don't know why - SA 08/08/2012
231 #Only one entry for one user = one slice in testbed_xp table
232 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
234 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
235 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
237 #load_reg_researchers
238 #raw_slicerec.reg_researchers
239 raw_slicerec = raw_slicerec.__dict__
240 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
241 raw_slicerec %s" % (slice_filter, raw_slicerec))
242 slicerec = raw_slicerec
243 #only one researcher per slice so take the first one
244 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
245 #del slicerec['reg_researchers']['_sa_instance_state']
251 def _sql_get_slice_info_from_user(self, slice_filter):
253 Get the slice record based on the user recordid by using a joinedload
254 on the relationship reg_slices_as_researcher. Format the sql record
255 into a dict with the mandatory fields for user and slice.
256 :returns: dict with slice record and user record if the record was found
257 based on the user's id, None if not..
258 :rtype:dict or None..
260 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
261 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
262 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
263 #Put it in correct order
264 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
265 'classtype', 'authority', 'gid', 'record_id',
266 'date_created', 'type', 'email', 'pointer']
267 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
268 'classtype', 'authority', 'gid', 'record_id',
269 'date_created', 'type', 'pointer']
271 #raw_slicerec.reg_slices_as_researcher
272 raw_slicerec = raw_slicerec.__dict__
275 dict([(k, raw_slicerec[
276 'reg_slices_as_researcher'][0].__dict__[k])
277 for k in slice_needed_fields])
278 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
279 for k in user_needed_fields])
280 #TODO Handle multiple slices for one user SA 10/12/12
281 #for now only take the first slice record associated to the rec user
282 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
283 #del raw_slicerec['reg_slices_as_researcher']
284 #slicerec['reg_researchers'] = raw_slicerec
285 ##del slicerec['_sa_instance_state']
294 def _get_slice_records(self, slice_filter=None,
295 slice_filter_type=None):
297 Get the slice record depending on the slice filter and its type.
298 :param slice_filter: Can be either the slice hrn or the user's record
300 :type slice_filter: string
301 :param slice_filter_type: describes the slice filter type used, can be
302 slice_hrn or record_id_user
304 :returns: the slice record
306 .. seealso::_sql_get_slice_info_from_user
307 .. seealso:: _sql_get_slice_info
310 #Get list of slices based on the slice hrn
311 if slice_filter_type == 'slice_hrn':
313 #if get_authority(slice_filter) == self.root_auth:
314 #login = slice_filter.split(".")[1].split("_")[0]
316 slicerec = self._sql_get_slice_info(slice_filter)
322 #Get slice based on user id
323 if slice_filter_type == 'record_id_user':
325 slicerec = self._sql_get_slice_info_from_user(slice_filter)
328 fixed_slicerec_dict = slicerec
329 #At this point if there is no login it means
330 #record_id_user filter has been used for filtering
332 ##If theslice record is from iotlab
333 #if fixed_slicerec_dict['peer_authority'] is None:
334 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
335 #return login, fixed_slicerec_dict
336 return fixed_slicerec_dict
342 def GetSlices(self, slice_filter=None, slice_filter_type=None,
344 """Get the slice records from the iotlab db and add lease information
347 :param slice_filter: can be the slice hrn or slice record id in the db
348 depending on the slice_filter_type.
349 :param slice_filter_type: defines the type of the filtering used, Can be
350 either 'slice_hrn' or "record_id'.
351 :type slice_filter: string
352 :type slice_filter_type: string
353 :returns: a slice dict if slice_filter and slice_filter_type
354 are specified and a matching entry is found in the db. The result
355 is put into a list.Or a list of slice dictionnaries if no filters
362 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
363 return_slicerec_dictlist = []
365 #First try to get information on the slice based on the filter provided
366 if slice_filter_type in authorized_filter_types_list:
367 fixed_slicerec_dict = self._get_slice_records(slice_filter,
369 # if the slice was not found in the sfa db
370 if fixed_slicerec_dict is None:
371 return return_slicerec_dictlist
373 slice_hrn = fixed_slicerec_dict['hrn']
375 logger.debug(" IOTLAB_API \tGetSlices login %s \
376 slice record %s slice_filter %s \
377 slice_filter_type %s " % (login,
378 fixed_slicerec_dict, slice_filter,
382 #Now we have the slice record fixed_slicerec_dict, get the
383 #jobs associated to this slice
386 leases_list = self.GetLeases(login=login)
387 #If no job is running or no job scheduled
388 #return only the slice record
389 if leases_list == [] and fixed_slicerec_dict:
390 return_slicerec_dictlist.append(fixed_slicerec_dict)
392 # if the jobs running don't belong to the user/slice we are looking
394 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
395 if slice_hrn not in leases_hrn:
396 return_slicerec_dictlist.append(fixed_slicerec_dict)
397 #If several jobs for one slice , put the slice record into
398 # each lease information dict
399 for lease in leases_list:
401 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
402 \t lease['slice_hrn'] %s"
403 % (slice_filter, lease['slice_hrn']))
404 if lease['slice_hrn'] == slice_hrn:
405 slicerec_dict['oar_job_id'] = lease['lease_id']
406 #Update lease dict with the slice record
407 if fixed_slicerec_dict:
408 fixed_slicerec_dict['oar_job_id'] = []
409 fixed_slicerec_dict['oar_job_id'].append(
410 slicerec_dict['oar_job_id'])
411 slicerec_dict.update(fixed_slicerec_dict)
412 #slicerec_dict.update({'hrn':\
413 #str(fixed_slicerec_dict['slice_hrn'])})
414 slicerec_dict['slice_hrn'] = lease['slice_hrn']
415 slicerec_dict['hrn'] = lease['slice_hrn']
416 slicerec_dict['user'] = lease['user']
417 slicerec_dict.update(
419 {'hostname': lease['reserved_nodes']}})
420 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
424 return_slicerec_dictlist.append(slicerec_dict)
426 logger.debug("IOTLAB_API.PY \tGetSlices \
427 slicerec_dict %s return_slicerec_dictlist %s \
428 lease['reserved_nodes'] \
429 %s" % (slicerec_dict, return_slicerec_dictlist,
430 lease['reserved_nodes']))
432 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
433 return_slicerec_dictlist %s"
434 % (return_slicerec_dictlist))
436 return return_slicerec_dictlist
440 #Get all slices from the iotlab sfa database ,
441 #put them in dict format
442 #query_slice_list = dbsession.query(RegRecord).all()
444 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
446 for record in query_slice_list:
447 tmp = record.__dict__
448 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
449 #del tmp['reg_researchers']['_sa_instance_state']
450 return_slicerec_dictlist.append(tmp)
451 #return_slicerec_dictlist.append(record.__dict__)
453 #Get all the jobs reserved nodes
454 leases_list = self.testbed_shell.GetReservedNodes()
456 for fixed_slicerec_dict in return_slicerec_dictlist:
458 #Check if the slice belongs to a iotlab user
459 if fixed_slicerec_dict['peer_authority'] is None:
460 owner = fixed_slicerec_dict['hrn'].split(
461 ".")[1].split("_")[0]
464 for lease in leases_list:
465 if owner == lease['user']:
466 slicerec_dict['oar_job_id'] = lease['lease_id']
468 #for reserved_node in lease['reserved_nodes']:
469 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
471 slicerec_dict.update(fixed_slicerec_dict)
472 slicerec_dict.update({'node_ids':
473 lease['reserved_nodes']})
474 slicerec_dict.update({'list_node_ids':
476 lease['reserved_nodes']}})
478 #slicerec_dict.update({'hrn':\
479 #str(fixed_slicerec_dict['slice_hrn'])})
480 #return_slicerec_dictlist.append(slicerec_dict)
481 fixed_slicerec_dict.update(slicerec_dict)
483 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
484 return_slicerec_dictlist %s \t slice_filter %s " \
485 %(return_slicerec_dictlist, slice_filter))
487 return return_slicerec_dictlist
489 def AddLeases(self, hostname_list, slice_record,
490 lease_start_time, lease_duration):
492 """Creates a job in OAR corresponding to the information provided
493 as parameters. Adds the job id and the slice hrn in the iotlab
494 database so that we are able to know which slice has which nodes.
496 :param hostname_list: list of nodes' OAR hostnames.
497 :param slice_record: sfa slice record, must contain login and hrn.
498 :param lease_start_time: starting time , unix timestamp format
499 :param lease_duration: duration in minutes
501 :type hostname_list: list
502 :type slice_record: dict
503 :type lease_start_time: integer
504 :type lease_duration: integer
505 :returns: job_id, can be None if the job request failed.
508 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
509 slice_record %s lease_start_time %s lease_duration %s "\
510 %( hostname_list, slice_record , lease_start_time, \
513 #tmp = slice_record['reg-researchers'][0].split(".")
514 username = slice_record['login']
515 #username = tmp[(len(tmp)-1)]
516 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
517 slice_record['hrn'], \
518 lease_start_time, lease_duration, \
520 if job_id is not None:
522 datetime.fromtimestamp(int(lease_start_time)).\
523 strftime(self.testbed_shell.time_format)
524 end_time = lease_start_time + lease_duration
527 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
528 %s %s %s "%(slice_record['hrn'], job_id, end_time))
531 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
532 %(type(slice_record['hrn']), type(job_id), type(end_time)))
534 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
535 experiment_id=job_id,
538 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
540 self.api.dbsession().add(iotlab_ex_row)
541 self.api.dbsession().commit()
543 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
548 def GetLeases(self, lease_filter_dict=None, login=None):
551 Get the list of leases from OAR with complete information
552 about which slice owns which jobs and nodes.
554 -Fetch all the jobs from OAR (running, waiting..)
555 complete the reservation information with slice hrn
556 found in lease_table . If not available in the table,
557 assume it is a iotlab slice.
558 -Updates the iotlab table, deleting jobs when necessary.
560 :returns: reservation_list, list of dictionaries with 'lease_id',
561 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
562 'slice_hrn', 'resource_ids', 't_from', 't_until'
567 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
569 reservation_list = []
570 #Find the slice associated with this user iotlab ldap uid
571 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
572 unfiltered_reservation_list %s "
573 % (login, unfiltered_reservation_list))
574 #Create user dict first to avoid looking several times for
575 #the same user in LDAP SA 27/07/12
577 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
578 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
579 for row in jobs_psql_query])
580 #jobs_psql_dict = jobs_psql_dict)
581 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
583 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
585 for resa in unfiltered_reservation_list:
586 logger.debug("IOTLAB_API \tGetLeases USER %s"
588 #Construct list of jobs (runing, waiting..) in oar
589 job_oar_list.append(resa['lease_id'])
590 #If there is information on the job in IOTLAB DB ]
591 #(slice used and job id)
592 if resa['lease_id'] in jobs_psql_dict:
593 job_info = jobs_psql_dict[resa['lease_id']]
594 logger.debug("IOTLAB_API \tGetLeases job_info %s"
596 resa['slice_hrn'] = job_info['slice_hrn']
597 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
599 #otherwise, assume it is a iotlab slice:
601 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
602 + '.' + resa['user'] + "_slice",
604 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
606 resa['component_id_list'] = []
607 #Transform the hostnames into urns (component ids)
608 for node in resa['reserved_nodes']:
610 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
611 resa['component_id_list'].append(iotlab_xrn.urn)
613 if lease_filter_dict:
614 logger.debug("IOTLAB_API \tGetLeases \
615 \r\n leasefilter %s" % ( lease_filter_dict))
617 # filter_dict_functions = {
618 # 'slice_hrn' : IotlabShell.filter_lease_name,
619 # 't_from' : IotlabShell.filter_lease_start_time
621 reservation_list = list(unfiltered_reservation_list)
622 for filter_type in lease_filter_dict:
623 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
624 % (reservation_list))
625 reservation_list = self.testbed_shell.filter_lease(
626 reservation_list,filter_type,
627 lease_filter_dict[filter_type] )
629 # Filter the reservation list with a maximum timespan so that the
630 # leases and jobs running after this timestamp do not appear
631 # in the result leases.
632 # if 'start_time' in :
633 # if resa['start_time'] < lease_filter_dict['start_time']:
634 # reservation_list.append(resa)
637 # if 'name' in lease_filter_dict and \
638 # lease_filter_dict['name'] == resa['slice_hrn']:
639 # reservation_list.append(resa)
642 if lease_filter_dict is None:
643 reservation_list = unfiltered_reservation_list
645 self.update_experiments_in_lease_table(job_oar_list, jobs_psql_id_list)
647 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
648 % (reservation_list))
649 return reservation_list
653 def update_experiments_in_lease_table(self,
654 experiment_list_from_testbed, experiment_list_in_db):
655 """ Cleans the lease_table by deleting expired and cancelled jobs.
657 Compares the list of experiment ids given by the testbed with the
658 experiment ids that are already in the database, deletes the
659 experiments that are no longer in the testbed experiment id list.
661 :param experiment_list_from_testbed: list of experiment ids coming
663 :type experiment_list_from_testbed: list
664 :param experiment_list_in_db: list of experiment ids from the sfa
665 additionnal database.
666 :type experiment_list_in_db: list
670 #Turn the list into a set
671 set_experiment_list_in_db = set(experiment_list_in_db)
673 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
674 logger.debug("\r\n \t update_experiments_in_lease_table \
675 experiment_list_in_db %s \r\n \
676 experiment_list_from_testbed %s \
677 kept_experiments %s "
678 % (set_experiment_list_in_db,
679 experiment_list_from_testbed, kept_experiments))
680 deleted_experiments = set_experiment_list_in_db.difference(
682 deleted_experiments = list(deleted_experiments)
683 if len(deleted_experiments) > 0:
684 request = self.api.dbsession().query(LeaseTableXP)
685 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
686 self.api.dbsession().commit()
690 def AddSlice(self, slice_record, user_record):
693 Add slice to the local iotlab sfa tables if the slice comes
694 from a federated site and is not yet in the iotlab sfa DB,
695 although the user has already a LDAP login.
696 Called by verify_slice during lease/sliver creation.
698 :param slice_record: record of slice, must contain hrn, gid, slice_id
699 and authority of the slice.
700 :type slice_record: dictionary
701 :param user_record: record of the user
702 :type user_record: RegUser
706 sfa_record = RegSlice(hrn=slice_record['hrn'],
707 gid=slice_record['gid'],
708 #pointer=slice_record['slice_id'],
709 authority=slice_record['authority'])
710 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
711 % (sfa_record, user_record))
712 sfa_record.just_created()
713 self.api.dbsession().add(sfa_record)
714 self.api.dbsession().commit()
715 #Update the reg-researchers dependency table
716 sfa_record.reg_researchers = [user_record]
717 self.api.dbsession().commit()
721 def augment_records_with_testbed_info(self, record_list):
724 Adds specific testbed info to the records.
726 :param record_list: list of sfa dictionaries records
727 :type record_list: list
728 :returns: list of records with extended information in each record
732 return self.fill_record_info(record_list)
734 def fill_record_info(self, record_list):
737 For each SFA record, fill in the iotlab specific and SFA specific
738 fields in the record.
740 :param record_list: list of sfa dictionaries records
741 :type record_list: list
742 :returns: list of records with extended information in each record
745 .. warning:: Should not be modifying record_list directly because modi
746 fication are kept outside the method's scope. Howerver, there is no
747 other way to do it given the way it's called in registry manager.
751 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
753 if not isinstance(record_list, list):
754 record_list = [record_list]
757 for record in record_list:
759 if str(record['type']) == 'node':
760 # look for node info using GetNodes
761 # the record is about one node only
762 filter_dict = {'hrn': [record['hrn']]}
763 node_info = self.testbed_shell.GetNodes(filter_dict)
764 # the node_info is about one node only, but it is formatted
766 record.update(node_info[0])
767 logger.debug("IOTLABDRIVER.PY \t \
768 fill_record_info NODE" % (record))
770 #If the record is a SFA slice record, then add information
771 #about the user of this slice. This kind of
772 #information is in the Iotlab's DB.
773 if str(record['type']) == 'slice':
774 if 'reg_researchers' in record and isinstance(record
777 record['reg_researchers'] = \
778 record['reg_researchers'][0].__dict__
780 {'PI': [record['reg_researchers']['hrn']],
781 'researcher': [record['reg_researchers']['hrn']],
782 'name': record['hrn'],
785 'person_ids': [record['reg_researchers']
787 # For client_helper.py compatibility
789 # For client_helper.py compatibility
791 # For client_helper.py compatibility
794 #Get iotlab slice record and oar job id if any.
795 recslice_list = self.GetSlices(
796 slice_filter=str(record['hrn']),
797 slice_filter_type='slice_hrn')
799 logger.debug("IOTLABDRIVER \tfill_record_info \
800 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
801 %s " % (record['hrn'], record['oar_job_id']))
802 del record['reg_researchers']
804 for rec in recslice_list:
805 logger.debug("IOTLABDRIVER\r\n \t \
806 fill_record_info oar_job_id %s "
807 % (rec['oar_job_id']))
809 record['node_ids'] = [self.testbed_shell.root_auth +
810 '.' + hostname for hostname
815 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
816 recslice_list %s \r\n \t RECORD %s \r\n \
817 \r\n" % (recslice_list, record))
819 if str(record['type']) == 'user':
820 #The record is a SFA user record.
821 #Get the information about his slice from Iotlab's DB
822 #and add it to the user record.
823 recslice_list = self.GetSlices(
824 slice_filter=record['record_id'],
825 slice_filter_type='record_id_user')
827 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
828 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
829 % (recslice_list, record))
830 #Append slice record in records list,
831 #therefore fetches user and slice info again(one more loop)
832 #Will update PIs and researcher for the slice
834 recuser = recslice_list[0]['reg_researchers']
835 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
836 recuser %s \r\n \r\n" % (recuser))
838 recslice = recslice_list[0]
840 {'PI': [recuser['hrn']],
841 'researcher': [recuser['hrn']],
842 'name': recuser['hrn'],
845 'person_ids': [recuser['record_id']]})
847 for rec in recslice_list:
848 recslice['oar_job_id'].append(rec['oar_job_id'])
852 recslice.update({'type': 'slice',
853 'hrn': recslice_list[0]['hrn']})
855 #GetPersons takes [] as filters
856 user_iotlab = self.testbed_shell.GetPersons([record])
858 record.update(user_iotlab[0])
859 #For client_helper.py compatibility
864 record_list.append(recslice)
866 logger.debug("IOTLABDRIVER.PY \t \
867 fill_record_info ADDING SLICE\
868 INFO TO USER records %s" % (record_list))
870 except TypeError, error:
871 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
876 def sliver_status(self, slice_urn, slice_hrn):
878 Receive a status request for slice named urn/hrn
879 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
880 shall return a structure as described in
881 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
882 NT : not sure if we should implement this or not, but used by sface.
884 :param slice_urn: slice urn
885 :type slice_urn: string
886 :param slice_hrn: slice hrn
887 :type slice_hrn: string
891 #First get the slice with the slice hrn
892 slice_list = self.GetSlices(slice_filter=slice_hrn,
893 slice_filter_type='slice_hrn')
895 if len(slice_list) == 0:
896 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
898 #Used for fetching the user info witch comes along the slice info
899 one_slice = slice_list[0]
901 #Make a list of all the nodes hostnames in use for this slice
902 slice_nodes_list = []
903 slice_nodes_list = one_slice['node_ids']
904 #Get all the corresponding nodes details
905 nodes_all = self.testbed_shell.GetNodes(
906 {'hostname': slice_nodes_list},
907 ['node_id', 'hostname', 'site', 'boot_state'])
908 nodeall_byhostname = dict([(one_node['hostname'], one_node)
909 for one_node in nodes_all])
911 for single_slice in slice_list:
913 top_level_status = 'empty'
916 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
917 'geni_resources'], None)
919 # ['geni_urn','geni_error', 'pl_login','geni_status',
920 # 'geni_resources'], None)
921 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
922 result['iotlab_login'] = one_slice['user']
923 logger.debug("Slabdriver - sliver_status Sliver status \
924 urn %s hrn %s single_slice %s \r\n "
925 % (slice_urn, slice_hrn, single_slice))
927 if 'node_ids' not in single_slice:
929 result['geni_status'] = top_level_status
930 result['geni_resources'] = []
933 top_level_status = 'ready'
935 #A job is running on Iotlab for this slice
936 # report about the local nodes that are in the slice only
938 result['geni_urn'] = slice_urn
941 for node_hostname in single_slice['node_ids']:
943 res['iotlab_hostname'] = node_hostname
944 res['iotlab_boot_state'] = \
945 nodeall_byhostname[node_hostname]['boot_state']
947 #res['pl_hostname'] = node['hostname']
948 #res['pl_boot_state'] = \
949 #nodeall_byhostname[node['hostname']]['boot_state']
950 #res['pl_last_contact'] = strftime(self.time_format, \
951 #gmtime(float(timestamp)))
953 slice_urn, type='slice',
954 id=nodeall_byhostname[node_hostname]['node_id']).urn
956 res['geni_urn'] = sliver_id
957 #node_name = node['hostname']
958 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
960 res['geni_status'] = 'ready'
962 res['geni_status'] = 'failed'
963 top_level_status = 'failed'
965 res['geni_error'] = ''
967 resources.append(res)
969 result['geni_status'] = top_level_status
970 result['geni_resources'] = resources
971 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
975 def get_user_record(self, hrn):
978 Returns the user record based on the hrn from the SFA DB .
980 :param hrn: user's hrn
982 :returns: user record from SFA database
986 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
988 def testbed_name(self):
991 Returns testbed's name.
992 :returns: testbed authority name.
999 def _get_requested_leases_list(self, rspec):
1001 Process leases in rspec depending on the rspec version (format)
1002 type. Find the lease requests in the rspec and creates
1003 a lease request list with the mandatory information ( nodes,
1004 start time and duration) of the valid leases (duration above or
1005 equal to the iotlab experiment minimum duration).
1007 :param rspec: rspec request received.
1009 :returns: list of lease requests found in the rspec
1012 requested_lease_list = []
1013 for lease in rspec.version.get_leases():
1014 single_requested_lease = {}
1015 logger.debug("IOTLABDRIVER.PY \t \
1016 _get_requested_leases_list lease %s " % (lease))
1018 if not lease.get('lease_id'):
1019 if get_authority(lease['component_id']) == \
1020 self.testbed_shell.root_auth:
1021 single_requested_lease['hostname'] = \
1023 lease.get('component_id').strip())
1024 single_requested_lease['start_time'] = \
1025 lease.get('start_time')
1026 single_requested_lease['duration'] = lease.get('duration')
1027 #Check the experiment's duration is valid before adding
1028 #the lease to the requested leases list
1029 duration_in_seconds = \
1030 int(single_requested_lease['duration'])
1031 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1032 requested_lease_list.append(single_requested_lease)
1034 return requested_lease_list
1037 def _group_leases_by_start_time(requested_lease_list):
1039 Create dict of leases by start_time, regrouping nodes reserved
1040 at the same time, for the same amount of time so as to
1041 define one job on OAR.
1043 :param requested_lease_list: list of leases
1044 :type requested_lease_list: list
1045 :returns: Dictionary with key = start time, value = list of leases
1046 with the same start time.
1051 requested_xp_dict = {}
1052 for lease in requested_lease_list:
1054 #In case it is an asap experiment start_time is empty
1055 if lease['start_time'] == '':
1056 lease['start_time'] = '0'
1058 if lease['start_time'] not in requested_xp_dict:
1059 if isinstance(lease['hostname'], str):
1060 lease['hostname'] = [lease['hostname']]
1062 requested_xp_dict[lease['start_time']] = lease
1065 job_lease = requested_xp_dict[lease['start_time']]
1066 if lease['duration'] == job_lease['duration']:
1067 job_lease['hostname'].append(lease['hostname'])
1069 return requested_xp_dict
1071 def _process_requested_xp_dict(self, rspec):
1073 Turns the requested leases and information into a dictionary
1074 of requested jobs, grouped by starting time.
1076 :param rspec: RSpec received
1081 requested_lease_list = self._get_requested_leases_list(rspec)
1082 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1083 requested_lease_list %s" % (requested_lease_list))
1084 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1085 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1092 def delete(self, slice_urns, options=None):
1094 Deletes the lease associated with the slice hrn and the credentials
1095 if the slice belongs to iotlab. Answer to DeleteSliver.
1097 :param slice_urn: urn of the slice
1098 :type slice_urn: string
1101 :returns: 1 if the slice to delete was not found on iotlab,
1102 True if the deletion was successful, False otherwise otherwise.
1104 .. note:: Should really be named delete_leases because iotlab does
1105 not have any slivers, but only deals with leases. However,
1106 SFA api only have delete_sliver define so far. SA 13/05/2013
1107 .. note:: creds are unused, and are not used either in the dummy driver
1110 if options is None: options={}
1111 # collect sliver ids so we can update sliver allocation states after
1112 # we remove the slivers.
1113 aggregate = IotlabAggregate(self)
1114 slivers = aggregate.get_slivers(slice_urns)
1116 # slice_id = slivers[0]['slice_id']
1119 sliver_jobs_dict = {}
1120 for sliver in slivers:
1121 node_ids.append(sliver['node_id'])
1122 sliver_ids.append(sliver['sliver_id'])
1123 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1124 sliver_jobs_dict[job_id] = sliver['sliver_id']
1125 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1126 % (slivers, slice_urns))
1127 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1129 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1130 slice_filter_type='slice_hrn')
1132 if not sfa_slice_list:
1135 #Delete all leases in the slice
1136 for sfa_slice in sfa_slice_list:
1137 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1138 slices = IotlabSlices(self)
1139 # determine if this is a peer slice
1141 peer = slices.get_peer(slice_hrn)
1143 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1144 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1145 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1147 for job_id in oar_bool_ans:
1148 # if the job has not been successfully deleted
1149 # don't delete the associated sliver
1150 # remove it from the sliver list
1151 if oar_bool_ans[job_id] is False:
1152 sliver = sliver_jobs_dict[job_id]
1153 sliver_ids.remove(sliver)
1156 dbsession = self.api.dbsession()
1157 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1159 logger.log_exc("IOTLABDRIVER.PY delete error ")
1161 # prepare return struct
1163 for sliver in slivers:
1164 geni_slivers.append(
1165 {'geni_sliver_urn': sliver['sliver_id'],
1166 'geni_allocation_status': 'geni_unallocated',
1167 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1173 def list_slices(self, creds, options):
1174 """Answer to ListSlices.
1176 List slices belonging to iotlab, returns slice urns list.
1177 No caching used. Options unused but are defined in the SFA method
1180 :returns: slice urns list
1183 .. note:: creds and options are unused - SA 12/12/13
1185 # look in cache first
1187 #slices = self.cache.get('slices')
1189 #logger.debug("PlDriver.list_slices returns from cache")
1194 slices = self.GetSlices()
1195 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1197 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1199 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1200 for slice_hrn in slice_hrns]
1204 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1205 #self.cache.add('slices', slice_urns)
1210 def register(self, sfa_record, hrn, pub_key):
1212 Adding new user, slice, node or site should not be handled
1215 ..warnings:: should not be used. Different components are in charge of
1216 doing this task. Adding nodes = OAR
1217 Adding users = LDAP Iotlab
1218 Adding slice = Import from LDAP users
1221 :param sfa_record: record provided by the client of the
1223 :type sfa_record: dict
1224 :param pub_key: public key of the user
1225 :type pub_key: string
1227 .. note:: DOES NOTHING. Returns -1.
1233 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1235 No site or node record update allowed in Iotlab. The only modifications
1236 authorized here are key deletion/addition on an existing user and
1237 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1238 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1239 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1240 user's ssh key should nmodify the slice's GID after an import procedure.
1242 :param old_sfa_record: what is in the db for this hrn
1243 :param new_sfa_record: what was passed to the update call
1244 :param new_key: the new user's public key
1245 :param hrn: the user's sfa hrn
1246 :type old_sfa_record: dict
1247 :type new_sfa_record: dict
1248 :type new_key: string
1252 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1253 since users, keys and slice are managed by the LDAP.
1256 # pointer = old_sfa_record['pointer']
1257 # old_sfa_record_type = old_sfa_record['type']
1259 # # new_key implemented for users only
1260 # if new_key and old_sfa_record_type not in ['user']:
1261 # raise UnknownSfaType(old_sfa_record_type)
1263 # if old_sfa_record_type == "user":
1264 # update_fields = {}
1265 # all_fields = new_sfa_record
1266 # for key in all_fields.keys():
1267 # if key in ['key', 'password']:
1268 # update_fields[key] = all_fields[key]
1271 # # must check this key against the previous one if it exists
1272 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1273 # person = persons[0]
1274 # keys = [person['pkey']]
1275 # #Get all the person's keys
1276 # keys_dict = self.GetKeys(keys)
1278 # # Delete all stale keys, meaning the user has only one key
1280 # #TODO: do we really want to delete all the other keys?
1281 # #Is this a problem with the GID generation to have multiple
1282 # #keys? SA 30/05/13
1283 # key_exists = False
1284 # if key in keys_dict:
1287 # #remove all the other keys
1288 # for key in keys_dict:
1289 # self.testbed_shell.DeleteKey(person, key)
1290 # self.testbed_shell.AddPersonKey(
1291 # person, {'sshPublicKey': person['pkey']},
1292 # {'sshPublicKey': new_key})
1293 logger.warning ("UNDEFINED - Update should be done by the \
1297 def remove(self, sfa_record):
1300 Removes users only. Mark the user as disabled in LDAP. The user and his
1301 slice are then deleted from the db by running an import on the registry.
1303 :param sfa_record: record is the existing sfa record in the db
1304 :type sfa_record: dict
1306 ..warning::As fas as the slice is concerned, here only the leases are
1307 removed from the slice. The slice is record itself is not removed
1312 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1314 TODO: return boolean for the slice part
1316 sfa_record_type = sfa_record['type']
1317 hrn = sfa_record['hrn']
1318 if sfa_record_type == 'user':
1320 #get user from iotlab ldap
1321 person = self.testbed_shell.GetPersons(sfa_record)
1322 #No registering at a given site in Iotlab.
1323 #Once registered to the LDAP, all iotlab sites are
1326 #Mark account as disabled in ldap
1327 return self.testbed_shell.DeletePerson(sfa_record)
1329 elif sfa_record_type == 'slice':
1330 if self.GetSlices(slice_filter=hrn,
1331 slice_filter_type='slice_hrn'):
1332 ret = self.testbed_shell.DeleteSlice(sfa_record)
1335 def check_sliver_credentials(self, creds, urns):
1336 """Check that the sliver urns belongs to the slice specified in the
1339 :param urns: list of sliver urns.
1341 :param creds: slice credentials.
1342 :type creds: Credential object.
1346 # build list of cred object hrns
1347 slice_cred_names = []
1349 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1350 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1351 slice_cred_names.append(slicename)
1353 # look up slice name of slivers listed in urns arg
1357 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1359 slice_ids.append(int(sliver_id_parts[0]))
1364 raise Forbidden("sliver urn not provided")
1366 slices = self.GetSlices(slice_ids)
1367 sliver_names = [single_slice['name'] for single_slice in slices]
1369 # make sure we have a credential for every specified sliver
1370 for sliver_name in sliver_names:
1371 if sliver_name not in slice_cred_names:
1372 msg = "Valid credential not found for target: %s" % sliver_name
1373 raise Forbidden(msg)
1375 ########################################
1376 ########## aggregate oriented
1377 ########################################
1379 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1380 def aggregate_version(self):
1383 Returns the testbed's supported rspec advertisement and request
1385 :returns: rspec versions supported ad a dictionary.
1389 version_manager = VersionManager()
1390 ad_rspec_versions = []
1391 request_rspec_versions = []
1392 for rspec_version in version_manager.versions:
1393 if rspec_version.content_type in ['*', 'ad']:
1394 ad_rspec_versions.append(rspec_version.to_dict())
1395 if rspec_version.content_type in ['*', 'request']:
1396 request_rspec_versions.append(rspec_version.to_dict())
1398 'testbed': self.testbed_name(),
1399 'geni_request_rspec_versions': request_rspec_versions,
1400 'geni_ad_rspec_versions': ad_rspec_versions}
1402 # first 2 args are None in case of resource discovery
1403 def list_resources (self, version=None, options=None):
1404 if options is None: options={}
1405 aggregate = IotlabAggregate(self)
1406 rspec = aggregate.list_resources(version=version, options=options)
1409 def describe(self, urns, version, options={}):
1410 aggregate = IotlabAggregate(self)
1411 return aggregate.describe(urns, version=version, options=options)
1413 def status (self, urns, options=None):
1414 if options is None: options={}
1415 aggregate = IotlabAggregate(self)
1416 desc = aggregate.describe(urns, version='GENI 3')
1417 status = {'geni_urn': desc['geni_urn'],
1418 'geni_slivers': desc['geni_slivers']}
1422 def allocate (self, urn, rspec_string, expiration, options=None):
1423 if options is None: options={}
1425 aggregate = IotlabAggregate(self)
1427 slices = IotlabSlices(self)
1428 peer = slices.get_peer(xrn.get_hrn())
1429 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1431 caller_hrn = options.get('actual_caller_hrn', [])
1432 caller_xrn = Xrn(caller_hrn)
1433 caller_urn = caller_xrn.get_urn()
1435 logger.debug("IOTLABDRIVER.PY :: Allocate caller = %s" % (caller_urn))
1438 users = options.get('geni_users', [])
1439 sfa_users = options.get('sfa_users', [])
1443 # Looking for the user who actually called the Allocate function in the list of users of the slice
1445 if 'urn' in u and u['urn'] == caller_urn:
1447 logger.debug("user = %s" % u)
1448 # If we find the user in the list we use it, else we take the 1st in the list as before
1450 user_hrn = caller_hrn
1453 # XXX Always empty ??? no slice_record in the Allocate call
1454 #slice_record = sfa_users[0].get('slice_record', [])
1455 user_xrn = Xrn(sfa_users[0]['urn'])
1456 user_hrn = user_xrn.get_hrn()
1458 slice_record = user.get('slice_record', {})
1459 slice_record['user'] = {'keys': user['keys'],
1460 'email': user['email'],
1462 slice_record['authority'] = xrn.get_authority_hrn()
1464 logger.debug("IOTLABDRIVER.PY \t urn %s allocate options %s "
1468 rspec = RSpec(rspec_string)
1469 # requested_attributes = rspec.version.get_slice_attributes()
1471 # ensure site record exists
1473 # ensure person records exists
1475 # XXX LOIC using hrn is a workaround because the function
1476 # Xrn.get_urn returns 'urn:publicid:IDN+onelab:upmc+timur_friedman'
1477 # Instead of this 'urn:publicid:IDN+onelab:upmc+user+timur_friedman'
1478 user['hrn'] = urn_to_hrn(user['urn'])[0]
1479 # XXX LOIC adding the users of the slice to reg-researchers
1480 # reg-researchers is used in iotlabslices.py verify_slice in order to add the slice
1481 if 'reg-researchers' not in slice_record:
1482 slice_record['reg-researchers'] = list()
1483 slice_record['reg-researchers'].append(user['hrn'])
1484 if caller_hrn == user['hrn']:
1485 #hierarchical_user = user['hrn'].split(".")
1486 #user['login'] = hierarchical_user[-1]
1487 #slice_record['login'] = user['login']
1488 slice_record['user']=user
1490 # oui c'est degueulasse, le slice_record se retrouve modifie
1491 # dans la methode avec les infos du user, els infos sont propagees
1492 # dans verify_slice_leases
1493 logger.debug("IOTLABDRIVER.PY BEFORE slices.verify_persons")
1495 # XXX JORDAN XXX slice_record devrait recevoir le caller_xrn...
1496 # LOIC maintenant c'est fait au dessus
1497 logger.debug("IOTLABDRIVER.PY - LOIC - slice_record[user][hrn] = %s" % slice_record['user']['hrn'])
1498 logger.debug("IOTLABDRIVER.PY - LOIC - slice_record[reg-researchers] = %s" % slice_record['reg-researchers'])
1499 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1501 logger.debug("IOTLABDRIVER.PY AFTER slices.verify_persons")
1502 logger.debug("LOIC - slice_record[user] = %s" % slice_record['user'])
1503 logger.debug("IOTLABDRIVER.PY - LOIC - slice_record[reg-researchers] = %s" % slice_record['reg-researchers'])
1505 # ensure slice record exists
1506 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1507 logger.debug("LOIC - AFTER verify_slice - slice_record[user] = %s" % slice_record['user'])
1508 logger.debug("IOTLABDRIVER.PY - LOIC - slice_record[reg-researchers] = %s" % slice_record['reg-researchers'])
1509 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1510 \r\n \r\n current_slice %s" % (current_slice))
1512 # ensure slice attributes exists
1513 # slices.verify_slice_attributes(slice, requested_attributes,
1516 # add/remove slice from nodes
1517 # XXX JORDAN ensure requested_xp_dict returns a dict with all new leases
1518 requested_xp_dict = self._process_requested_xp_dict(rspec)
1520 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1521 % (requested_xp_dict))
1522 request_nodes = rspec.version.get_nodes_with_slivers()
1525 # JORDAN: nodes_list will contain a list of newly allocated nodes
1527 for start_time in requested_xp_dict:
1528 lease = requested_xp_dict[start_time]
1529 for hostname in lease['hostname']:
1530 nodes_list.append(hostname)
1532 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1533 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1534 % (nodes_list, slice_record))
1537 rspec_requested_leases = rspec.version.get_leases()
1538 leases = slices.verify_slice_leases(slice_record,
1539 requested_xp_dict, peer)
1541 # leases = already in slice
1542 # rspec_requested_leases = newly requested
1543 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1544 rspec_requested_leases %s" % (leases,
1545 rspec_requested_leases))
1546 # update sliver allocations
1547 # JORDAN Here we loop over newly allocated nodes
1548 for hostname in nodes_list:
1549 client_id = hostname
1550 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1551 component_id = node_urn
1552 if 'reg-urn' in current_slice:
1553 slice_urn = current_slice['reg-urn']
1555 slice_urn = current_slice['urn']
1557 # JORDAN: We loop over leases previously in the slice
1558 for lease in leases:
1559 if hostname in lease['reserved_nodes']:
1560 index = lease['reserved_nodes'].index(hostname)
1561 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1562 lease['resource_ids'][index] )
1563 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1564 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1565 component_id=component_id,
1566 slice_urn = slice_urn,
1567 allocation_state='geni_allocated')
1568 record.sync(self.api.dbsession())
1570 # JORDAN : added describe_options which was not specified at all
1571 describe_options = {
1572 'geni_slice_urn': urn,
1573 'list_leases': 'all',
1575 return aggregate.describe([xrn.get_urn()], version=rspec.version, options=describe_options)
1577 def provision(self, urns, options=None):
1578 if options is None: options={}
1580 slices = IotlabSlices(self)
1581 aggregate = IotlabAggregate(self)
1582 slivers = aggregate.get_slivers(urns)
1583 current_slice = slivers[0]
1584 peer = slices.get_peer(current_slice['hrn'])
1585 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1586 users = options.get('geni_users', [])
1587 # persons = slices.verify_persons(current_slice['hrn'],
1588 # current_slice, users, peer, sfa_peer, options=options)
1589 # slices.handle_peer(None, None, persons, peer)
1590 # update sliver allocation states and set them to geni_provisioned
1591 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1592 dbsession = self.api.dbsession()
1593 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1595 version_manager = VersionManager()
1596 rspec_version = version_manager.get_version(options[
1597 'geni_rspec_version'])
1598 # JORDAN : added describe_options instead of options
1599 # urns at the begining ???
1600 describe_options = {
1601 'geni_slice_urn': current_slice['urn'],
1602 'list_leases': 'all',
1604 return self.describe(urns, rspec_version, options=describe_options)