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
20 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
21 from sfa.iotlab.iotlabaggregate import IotlabAggregate
22 from sfa.iotlab.iotlabxrn import xrn_to_hostname
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 and the iotlab database.
47 :param config: iotlab SFA configuration object
48 :type config: Config object
51 Driver.__init__(self, api)
54 self.testbed_shell = IotlabShell(config)
57 def GetPeers(self, peer_filter=None ):
58 """ Gathers registered authorities in SFA DB and looks for specific peer
59 if peer_filter is specified.
60 :param peer_filter: name of the site authority looked for.
61 :type peer_filter: string
62 :returns: list of records.
67 existing_hrns_by_types = {}
68 logger.debug("IOTLAB_API \tGetPeers peer_filter %s " % (peer_filter))
69 all_records = self.api.dbsession().query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
71 for record in all_records:
72 existing_records[(record.hrn, record.type)] = record
73 if record.type not in existing_hrns_by_types:
74 existing_hrns_by_types[record.type] = [record.hrn]
76 existing_hrns_by_types[record.type].append(record.hrn)
78 logger.debug("IOTLAB_API \tGetPeer\texisting_hrns_by_types %s "
79 % (existing_hrns_by_types))
84 records_list.append(existing_records[(peer_filter,
87 for hrn in existing_hrns_by_types['authority']:
88 records_list.append(existing_records[(hrn, 'authority')])
90 logger.debug("IOTLAB_API \tGetPeer \trecords_list %s "
96 return_records = records_list
97 logger.debug("IOTLAB_API \tGetPeer return_records %s "
101 def GetKeys(self, key_filter=None):
102 """Returns a dict of dict based on the key string. Each dict entry
103 contains the key id, the ssh key, the user's email and the
105 If key_filter is specified and is an array of key identifiers,
106 only keys matching the filter will be returned.
108 Admin may query all keys. Non-admins may only query their own keys.
111 :returns: dict with ssh key as key and dicts as value.
114 query = self.api.dbsession().query(RegKey)
115 if key_filter is None:
116 keys = query.options(joinedload('reg_user')).all()
118 constraint = RegKey.key.in_(key_filter)
119 keys = query.options(joinedload('reg_user')).filter(constraint).all()
123 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
124 'email': key.reg_user.email,
125 'hrn': key.reg_user.hrn}
127 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
128 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
129 #for user in ldap_rslt)
131 logger.debug("IOTLAB_API GetKeys -key_dict %s \r\n " % (key_dict))
136 def AddPerson(self, record):
139 Adds a new account. Any fields specified in records are used,
140 otherwise defaults are used. Creates an appropriate login by calling
143 :param record: dictionary with the sfa user's properties.
144 :returns: a dicitonary with the status. If successful, the dictionary
145 boolean is set to True and there is a 'uid' key with the new login
146 added to LDAP, otherwise the bool is set to False and a key
147 'message' is in the dictionary, with the error message.
151 ret = self.testbed_shell.ldap.LdapAddUser(record)
153 if ret['bool'] is True:
154 record['hrn'] = self.testbed_shell.root_auth + '.' + ret['uid']
155 logger.debug("IOTLAB_API AddPerson return code %s record %s "
157 self.__add_person_to_db(record)
160 def __add_person_to_db(self, user_dict):
162 Add a federated user straight to db when the user issues a lease
163 request with iotlab nodes and that he has not registered with iotlab
164 yet (that is he does not have a LDAP entry yet).
165 Uses parts of the routines in IotlabImport when importing user from
166 LDAP. Called by AddPerson, right after LdapAddUser.
167 :param user_dict: Must contain email, hrn and pkey to get a GID
168 and be added to the SFA db.
169 :type user_dict: dict
172 query = self.api.dbsession().query(RegUser)
173 check_if_exists = query.filter_by(email = user_dict['email']).first()
175 if not check_if_exists:
176 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
178 hrn = user_dict['hrn']
179 person_urn = hrn_to_urn(hrn, 'user')
180 pubkey = user_dict['pkey']
182 pkey = convert_public_key(pubkey)
184 #key not good. create another pkey
185 logger.warn('__add_person_to_db: unable to convert public \
187 pkey = Keypair(create=True)
190 if pubkey is not None and pkey is not None :
191 hierarchy = Hierarchy()
192 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
194 if user_dict['email']:
195 logger.debug("__add_person_to_db \r\n \r\n \
196 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
197 %(user_dict['email']))
198 person_gid.set_email(user_dict['email'])
200 user_record = RegUser(hrn=hrn , pointer= '-1', \
201 authority=get_authority(hrn), \
202 email=user_dict['email'], gid = person_gid)
203 user_record.reg_keys = [RegKey(user_dict['pkey'])]
204 user_record.just_created()
205 self.api.dbsession().add (user_record)
206 self.api.dbsession().commit()
211 def _sql_get_slice_info(self, slice_filter):
213 Get the slice record based on the slice hrn. Fetch the record of the
214 user associated with the slice by using joinedload based on the
215 reg_researcher relationship.
217 :param slice_filter: the slice hrn we are looking for
218 :type slice_filter: string
219 :returns: the slice record enhanced with the user's information if the
220 slice was found, None it wasn't.
222 :rtype: dict or None.
224 #DO NOT USE RegSlice - reg_researchers to get the hrn
225 #of the user otherwise will mess up the RegRecord in
226 #Resolve, don't know why - SA 08/08/2012
228 #Only one entry for one user = one slice in testbed_xp table
229 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
230 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
231 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
234 #raw_slicerec.reg_researchers
235 raw_slicerec = raw_slicerec.__dict__
236 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
237 raw_slicerec %s" % (slice_filter, raw_slicerec))
238 slicerec = raw_slicerec
239 #only one researcher per slice so take the first one
240 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
241 #del slicerec['reg_researchers']['_sa_instance_state']
247 def _sql_get_slice_info_from_user(self, slice_filter):
249 Get the slice record based on the user recordid by using a joinedload
250 on the relationship reg_slices_as_researcher. Format the sql record
251 into a dict with the mandatory fields for user and slice.
252 :returns: dict with slice record and user record if the record was found
253 based on the user's id, None if not..
254 :rtype:dict or None..
256 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
257 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
258 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
259 #Put it in correct order
260 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
261 'classtype', 'authority', 'gid', 'record_id',
262 'date_created', 'type', 'email', 'pointer']
263 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
264 'classtype', 'authority', 'gid', 'record_id',
265 'date_created', 'type', 'pointer']
267 #raw_slicerec.reg_slices_as_researcher
268 raw_slicerec = raw_slicerec.__dict__
271 dict([(k, raw_slicerec[
272 'reg_slices_as_researcher'][0].__dict__[k])
273 for k in slice_needed_fields])
274 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
275 for k in user_needed_fields])
276 #TODO Handle multiple slices for one user SA 10/12/12
277 #for now only take the first slice record associated to the rec user
278 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
279 #del raw_slicerec['reg_slices_as_researcher']
280 #slicerec['reg_researchers'] = raw_slicerec
281 ##del slicerec['_sa_instance_state']
290 def _get_slice_records(self, slice_filter=None,
291 slice_filter_type=None):
293 Get the slice record depending on the slice filter and its type.
294 :param slice_filter: Can be either the slice hrn or the user's record
296 :type slice_filter: string
297 :param slice_filter_type: describes the slice filter type used, can be
298 slice_hrn or record_id_user
300 :returns: the slice record
302 .. seealso::_sql_get_slice_info_from_user
303 .. seealso:: _sql_get_slice_info
306 #Get list of slices based on the slice hrn
307 if slice_filter_type == 'slice_hrn':
309 #if get_authority(slice_filter) == self.root_auth:
310 #login = slice_filter.split(".")[1].split("_")[0]
312 slicerec = self._sql_get_slice_info(slice_filter)
318 #Get slice based on user id
319 if slice_filter_type == 'record_id_user':
321 slicerec = self._sql_get_slice_info_from_user(slice_filter)
324 fixed_slicerec_dict = slicerec
325 #At this point if there is no login it means
326 #record_id_user filter has been used for filtering
328 ##If theslice record is from iotlab
329 #if fixed_slicerec_dict['peer_authority'] is None:
330 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
331 #return login, fixed_slicerec_dict
332 return fixed_slicerec_dict
338 def GetSlices(self, slice_filter=None, slice_filter_type=None,
340 """Get the slice records from the iotlab db and add lease information
343 :param slice_filter: can be the slice hrn or slice record id in the db
344 depending on the slice_filter_type.
345 :param slice_filter_type: defines the type of the filtering used, Can be
346 either 'slice_hrn' or "record_id'.
347 :type slice_filter: string
348 :type slice_filter_type: string
349 :returns: a slice dict if slice_filter and slice_filter_type
350 are specified and a matching entry is found in the db. The result
351 is put into a list.Or a list of slice dictionnaries if no filters
358 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
359 return_slicerec_dictlist = []
361 #First try to get information on the slice based on the filter provided
362 if slice_filter_type in authorized_filter_types_list:
363 fixed_slicerec_dict = self._get_slice_records(slice_filter,
365 # if the slice was not found in the sfa db
366 if fixed_slicerec_dict is None:
367 return return_slicerec_dictlist
369 slice_hrn = fixed_slicerec_dict['hrn']
371 logger.debug(" IOTLAB_API \tGetSlices login %s \
372 slice record %s slice_filter %s \
373 slice_filter_type %s " % (login,
374 fixed_slicerec_dict, slice_filter,
378 #Now we have the slice record fixed_slicerec_dict, get the
379 #jobs associated to this slice
382 leases_list = self.GetLeases(login=login)
383 #If no job is running or no job scheduled
384 #return only the slice record
385 if leases_list == [] and fixed_slicerec_dict:
386 return_slicerec_dictlist.append(fixed_slicerec_dict)
388 # if the jobs running don't belong to the user/slice we are looking
390 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
391 if slice_hrn not in leases_hrn:
392 return_slicerec_dictlist.append(fixed_slicerec_dict)
393 #If several jobs for one slice , put the slice record into
394 # each lease information dict
395 for lease in leases_list:
397 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
398 \t lease['slice_hrn'] %s"
399 % (slice_filter, lease['slice_hrn']))
400 if lease['slice_hrn'] == slice_hrn:
401 slicerec_dict['oar_job_id'] = lease['lease_id']
402 #Update lease dict with the slice record
403 if fixed_slicerec_dict:
404 fixed_slicerec_dict['oar_job_id'] = []
405 fixed_slicerec_dict['oar_job_id'].append(
406 slicerec_dict['oar_job_id'])
407 slicerec_dict.update(fixed_slicerec_dict)
408 #slicerec_dict.update({'hrn':\
409 #str(fixed_slicerec_dict['slice_hrn'])})
410 slicerec_dict['slice_hrn'] = lease['slice_hrn']
411 slicerec_dict['hrn'] = lease['slice_hrn']
412 slicerec_dict['user'] = lease['user']
413 slicerec_dict.update(
415 {'hostname': lease['reserved_nodes']}})
416 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
420 return_slicerec_dictlist.append(slicerec_dict)
421 logger.debug("IOTLAB_API.PY \tGetSlices \
422 OHOHOHOH %s" %(return_slicerec_dictlist))
424 logger.debug("IOTLAB_API.PY \tGetSlices \
425 slicerec_dict %s return_slicerec_dictlist %s \
426 lease['reserved_nodes'] \
427 %s" % (slicerec_dict, return_slicerec_dictlist,
428 lease['reserved_nodes']))
430 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
431 return_slicerec_dictlist %s"
432 % (return_slicerec_dictlist))
434 return return_slicerec_dictlist
438 #Get all slices from the iotlab sfa database ,
439 #put them in dict format
440 #query_slice_list = dbsession.query(RegRecord).all()
442 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
444 for record in query_slice_list:
445 tmp = record.__dict__
446 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
447 #del tmp['reg_researchers']['_sa_instance_state']
448 return_slicerec_dictlist.append(tmp)
449 #return_slicerec_dictlist.append(record.__dict__)
451 #Get all the jobs reserved nodes
452 leases_list = self.testbed_shell.GetReservedNodes()
454 for fixed_slicerec_dict in return_slicerec_dictlist:
456 #Check if the slice belongs to a iotlab user
457 if fixed_slicerec_dict['peer_authority'] is None:
458 owner = fixed_slicerec_dict['hrn'].split(
459 ".")[1].split("_")[0]
462 for lease in leases_list:
463 if owner == lease['user']:
464 slicerec_dict['oar_job_id'] = lease['lease_id']
466 #for reserved_node in lease['reserved_nodes']:
467 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
469 slicerec_dict.update(fixed_slicerec_dict)
470 slicerec_dict.update({'node_ids':
471 lease['reserved_nodes']})
472 slicerec_dict.update({'list_node_ids':
474 lease['reserved_nodes']}})
476 #slicerec_dict.update({'hrn':\
477 #str(fixed_slicerec_dict['slice_hrn'])})
478 #return_slicerec_dictlist.append(slicerec_dict)
479 fixed_slicerec_dict.update(slicerec_dict)
481 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
482 return_slicerec_dictlist %s \t slice_filter %s " \
483 %(return_slicerec_dictlist, slice_filter))
485 return return_slicerec_dictlist
487 def AddLeases(self, hostname_list, slice_record,
488 lease_start_time, lease_duration):
490 """Creates a job in OAR corresponding to the information provided
491 as parameters. Adds the job id and the slice hrn in the iotlab
492 database so that we are able to know which slice has which nodes.
494 :param hostname_list: list of nodes' OAR hostnames.
495 :param slice_record: sfa slice record, must contain login and hrn.
496 :param lease_start_time: starting time , unix timestamp format
497 :param lease_duration: duration in minutes
499 :type hostname_list: list
500 :type slice_record: dict
501 :type lease_start_time: integer
502 :type lease_duration: integer
503 :returns: job_id, can be None if the job request failed.
506 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
507 slice_record %s lease_start_time %s lease_duration %s "\
508 %( hostname_list, slice_record , lease_start_time, \
511 #tmp = slice_record['reg-researchers'][0].split(".")
512 username = slice_record['login']
513 #username = tmp[(len(tmp)-1)]
514 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
515 slice_record['hrn'], \
516 lease_start_time, lease_duration, \
518 if job_id is not None:
520 datetime.fromtimestamp(int(lease_start_time)).\
521 strftime(self.testbed_shell.time_format)
522 end_time = lease_start_time + lease_duration
525 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
526 %s %s %s "%(slice_record['hrn'], job_id, end_time))
529 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
530 %(type(slice_record['hrn']), type(job_id), type(end_time)))
532 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
533 experiment_id=job_id,
536 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
538 self.api.dbsession().add(iotlab_ex_row)
539 self.api.dbsession().commit()
541 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
546 def GetLeases(self, lease_filter_dict=None, login=None):
549 Get the list of leases from OAR with complete information
550 about which slice owns which jobs and nodes.
552 -Fetch all the jobs from OAR (running, waiting..)
553 complete the reservation information with slice hrn
554 found in testbed_xp table. If not available in the table,
555 assume it is a iotlab slice.
556 -Updates the iotlab table, deleting jobs when necessary.
558 :returns: reservation_list, list of dictionaries with 'lease_id',
559 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
560 'slice_hrn', 'resource_ids', 't_from', 't_until'
565 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
567 reservation_list = []
568 #Find the slice associated with this user iotlab ldap uid
569 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
570 unfiltered_reservation_list %s "
571 % (login, unfiltered_reservation_list))
572 #Create user dict first to avoid looking several times for
573 #the same user in LDAP SA 27/07/12
575 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
576 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
577 for row in jobs_psql_query])
578 #jobs_psql_dict = jobs_psql_dict)
579 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
581 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
583 for resa in unfiltered_reservation_list:
584 logger.debug("IOTLAB_API \tGetLeases USER %s"
586 #Construct list of jobs (runing, waiting..) in oar
587 job_oar_list.append(resa['lease_id'])
588 #If there is information on the job in IOTLAB DB ]
589 #(slice used and job id)
590 if resa['lease_id'] in jobs_psql_dict:
591 job_info = jobs_psql_dict[resa['lease_id']]
592 logger.debug("IOTLAB_API \tGetLeases job_info %s"
594 resa['slice_hrn'] = job_info['slice_hrn']
595 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
597 #otherwise, assume it is a iotlab slice:
599 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
600 + '.' + resa['user'] + "_slice",
602 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
604 resa['component_id_list'] = []
605 #Transform the hostnames into urns (component ids)
606 for node in resa['reserved_nodes']:
608 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
609 resa['component_id_list'].append(iotlab_xrn.urn)
611 if lease_filter_dict:
612 logger.debug("IOTLAB_API \tGetLeases \
613 \r\n leasefilter %s" % ( lease_filter_dict))
615 filter_dict_functions = {
616 'slice_hrn' : IotlabShell.filter_lease_name,
617 't_from' : IotlabShell.filter_lease_start_time
619 reservation_list = list(unfiltered_reservation_list)
620 for filter_type in lease_filter_dict:
621 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
622 % (reservation_list))
623 reservation_list = filter_dict_functions[filter_type](\
624 reservation_list,lease_filter_dict[filter_type] )
626 # Filter the reservation list with a maximum timespan so that the
627 # leases and jobs running after this timestamp do not appear
628 # in the result leases.
629 # if 'start_time' in :
630 # if resa['start_time'] < lease_filter_dict['start_time']:
631 # reservation_list.append(resa)
634 # if 'name' in lease_filter_dict and \
635 # lease_filter_dict['name'] == resa['slice_hrn']:
636 # reservation_list.append(resa)
639 if lease_filter_dict is None:
640 reservation_list = unfiltered_reservation_list
642 self.update_experiments_in_additional_sfa_db(job_oar_list, jobs_psql_id_list)
644 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
645 % (reservation_list))
646 return reservation_list
650 def update_experiments_in_additional_sfa_db(self,
651 experiment_list_from_testbed, experiment_list_in_db):
652 """ Cleans the iotlab db by deleting expired and cancelled jobs.
654 Compares the list of experiment ids given by the testbed with the
655 experiment ids that are already in the database, deletes the
656 experiments that are no longer in the testbed experiment id list.
658 :param experiment_list_from_testbed: list of experiment ids coming
660 :type experiment_list_from_testbed: list
661 :param experiment_list_in_db: list of experiment ids from the sfa
662 additionnal database.
663 :type experiment_list_in_db: list
667 #Turn the list into a set
668 set_experiment_list_in_db = set(experiment_list_in_db)
670 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
671 logger.debug("\r\n \t update_experiments_in_additional_sfa_db \
672 experiment_list_in_db %s \r\n \
673 experiment_list_from_testbed %s \
674 kept_experiments %s "
675 % (set_experiment_list_in_db,
676 experiment_list_from_testbed, kept_experiments))
677 deleted_experiments = set_experiment_list_in_db.difference(
679 deleted_experiments = list(deleted_experiments)
680 if len(deleted_experiments) > 0:
681 self.api.dbsession().query(LeaseTableXP).filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
682 self.api.dbsession().commit()
684 def AddSlice(self, slice_record, user_record):
687 Add slice to the local iotlab sfa tables if the slice comes
688 from a federated site and is not yet in the iotlab sfa DB,
689 although the user has already a LDAP login.
690 Called by verify_slice during lease/sliver creation.
692 :param slice_record: record of slice, must contain hrn, gid, slice_id
693 and authority of the slice.
694 :type slice_record: dictionary
695 :param user_record: record of the user
696 :type user_record: RegUser
700 sfa_record = RegSlice(hrn=slice_record['hrn'],
701 gid=slice_record['gid'],
702 pointer=slice_record['slice_id'],
703 authority=slice_record['authority'])
704 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
705 % (sfa_record, user_record))
706 sfa_record.just_created()
707 self.api.dbsession().add(sfa_record)
708 self.api.dbsession().commit()
709 #Update the reg-researcher dependance table
710 sfa_record.reg_researchers = [user_record]
711 self.api.dbsession().commit()
715 def augment_records_with_testbed_info(self, record_list):
718 Adds specific testbed info to the records.
720 :param record_list: list of sfa dictionaries records
721 :type record_list: list
722 :returns: list of records with extended information in each record
726 return self.fill_record_info(record_list)
728 def fill_record_info(self, record_list):
731 For each SFA record, fill in the iotlab specific and SFA specific
732 fields in the record.
734 :param record_list: list of sfa dictionaries records
735 :type record_list: list
736 :returns: list of records with extended information in each record
739 .. warning:: Should not be modifying record_list directly because modi
740 fication are kept outside the method's scope. Howerver, there is no
741 other way to do it given the way it's called in registry manager.
745 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
747 if not isinstance(record_list, list):
748 record_list = [record_list]
751 for record in record_list:
753 if str(record['type']) == 'node':
754 # look for node info using GetNodes
755 # the record is about one node only
756 filter_dict = {'hrn': [record['hrn']]}
757 node_info = self.testbed_shell.GetNodes(filter_dict)
758 # the node_info is about one node only, but it is formatted
760 record.update(node_info[0])
761 logger.debug("IOTLABDRIVER.PY \t \
762 fill_record_info NODE" % (record))
764 #If the record is a SFA slice record, then add information
765 #about the user of this slice. This kind of
766 #information is in the Iotlab's DB.
767 if str(record['type']) == 'slice':
768 if 'reg_researchers' in record and isinstance(record
771 record['reg_researchers'] = \
772 record['reg_researchers'][0].__dict__
774 {'PI': [record['reg_researchers']['hrn']],
775 'researcher': [record['reg_researchers']['hrn']],
776 'name': record['hrn'],
779 'person_ids': [record['reg_researchers']
781 # For client_helper.py compatibility
783 # For client_helper.py compatibility
785 # For client_helper.py compatibility
788 #Get iotlab slice record and oar job id if any.
789 recslice_list = self.GetSlices(
790 slice_filter=str(record['hrn']),
791 slice_filter_type='slice_hrn')
793 logger.debug("IOTLABDRIVER \tfill_record_info \
794 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
795 %s " % (record['hrn'], record['oar_job_id']))
796 del record['reg_researchers']
798 for rec in recslice_list:
799 logger.debug("IOTLABDRIVER\r\n \t \
800 fill_record_info oar_job_id %s "
801 % (rec['oar_job_id']))
803 record['node_ids'] = [self.testbed_shell.root_auth +
804 '.' + hostname for hostname
809 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
810 recslice_list %s \r\n \t RECORD %s \r\n \
811 \r\n" % (recslice_list, record))
813 if str(record['type']) == 'user':
814 #The record is a SFA user record.
815 #Get the information about his slice from Iotlab's DB
816 #and add it to the user record.
817 recslice_list = self.GetSlices(
818 slice_filter=record['record_id'],
819 slice_filter_type='record_id_user')
821 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
822 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
823 % (recslice_list, record))
824 #Append slice record in records list,
825 #therefore fetches user and slice info again(one more loop)
826 #Will update PIs and researcher for the slice
828 recuser = recslice_list[0]['reg_researchers']
829 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
830 recuser %s \r\n \r\n" % (recuser))
832 recslice = recslice_list[0]
834 {'PI': [recuser['hrn']],
835 'researcher': [recuser['hrn']],
836 'name': record['hrn'],
839 'person_ids': [recuser['record_id']]})
841 for rec in recslice_list:
842 recslice['oar_job_id'].append(rec['oar_job_id'])
846 recslice.update({'type': 'slice',
847 'hrn': recslice_list[0]['hrn']})
849 #GetPersons takes [] as filters
850 user_iotlab = self.testbed_shell.GetPersons([record])
852 record.update(user_iotlab[0])
853 #For client_helper.py compatibility
858 record_list.append(recslice)
860 logger.debug("IOTLABDRIVER.PY \t \
861 fill_record_info ADDING SLICE\
862 INFO TO USER records %s" % (record_list))
864 except TypeError, error:
865 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
870 def sliver_status(self, slice_urn, slice_hrn):
872 Receive a status request for slice named urn/hrn
873 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
874 shall return a structure as described in
875 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
876 NT : not sure if we should implement this or not, but used by sface.
878 :param slice_urn: slice urn
879 :type slice_urn: string
880 :param slice_hrn: slice hrn
881 :type slice_hrn: string
885 #First get the slice with the slice hrn
886 slice_list = self.GetSlices(slice_filter=slice_hrn,
887 slice_filter_type='slice_hrn')
889 if len(slice_list) == 0:
890 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
892 #Used for fetching the user info witch comes along the slice info
893 one_slice = slice_list[0]
895 #Make a list of all the nodes hostnames in use for this slice
896 slice_nodes_list = []
897 slice_nodes_list = one_slice['node_ids']
898 #Get all the corresponding nodes details
899 nodes_all = self.testbed_shell.GetNodes(
900 {'hostname': slice_nodes_list},
901 ['node_id', 'hostname', 'site', 'boot_state'])
902 nodeall_byhostname = dict([(one_node['hostname'], one_node)
903 for one_node in nodes_all])
905 for single_slice in slice_list:
907 top_level_status = 'empty'
910 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
911 'geni_resources'], None)
913 # ['geni_urn','geni_error', 'pl_login','geni_status',
914 # 'geni_resources'], None)
915 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
916 result['iotlab_login'] = one_slice['user']
917 logger.debug("Slabdriver - sliver_status Sliver status \
918 urn %s hrn %s single_slice %s \r\n "
919 % (slice_urn, slice_hrn, single_slice))
921 if 'node_ids' not in single_slice:
923 result['geni_status'] = top_level_status
924 result['geni_resources'] = []
927 top_level_status = 'ready'
929 #A job is running on Iotlab for this slice
930 # report about the local nodes that are in the slice only
932 result['geni_urn'] = slice_urn
935 for node_hostname in single_slice['node_ids']:
937 res['iotlab_hostname'] = node_hostname
938 res['iotlab_boot_state'] = \
939 nodeall_byhostname[node_hostname]['boot_state']
941 #res['pl_hostname'] = node['hostname']
942 #res['pl_boot_state'] = \
943 #nodeall_byhostname[node['hostname']]['boot_state']
944 #res['pl_last_contact'] = strftime(self.time_format, \
945 #gmtime(float(timestamp)))
947 slice_urn, type='slice',
948 id=nodeall_byhostname[node_hostname]['node_id']).urn
950 res['geni_urn'] = sliver_id
951 #node_name = node['hostname']
952 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
954 res['geni_status'] = 'ready'
956 res['geni_status'] = 'failed'
957 top_level_status = 'failed'
959 res['geni_error'] = ''
961 resources.append(res)
963 result['geni_status'] = top_level_status
964 result['geni_resources'] = resources
965 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
969 def get_user_record(self, hrn):
972 Returns the user record based on the hrn from the SFA DB .
974 :param hrn: user's hrn
976 :returns: user record from SFA database
980 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
982 def testbed_name(self):
985 Returns testbed's name.
986 :returns: testbed authority name.
993 def _get_requested_leases_list(self, rspec):
995 Process leases in rspec depending on the rspec version (format)
996 type. Find the lease requests in the rspec and creates
997 a lease request list with the mandatory information ( nodes,
998 start time and duration) of the valid leases (duration above or
999 equal to the iotlab experiment minimum duration).
1001 :param rspec: rspec request received.
1003 :returns: list of lease requests found in the rspec
1006 requested_lease_list = []
1007 for lease in rspec.version.get_leases():
1008 single_requested_lease = {}
1009 logger.debug("IOTLABDRIVER.PY \t \
1010 _get_requested_leases_list lease %s " % (lease))
1012 if not lease.get('lease_id'):
1013 if get_authority(lease['component_id']) == \
1014 self.testbed_shell.root_auth:
1015 single_requested_lease['hostname'] = \
1017 lease.get('component_id').strip())
1018 single_requested_lease['start_time'] = \
1019 lease.get('start_time')
1020 single_requested_lease['duration'] = lease.get('duration')
1021 #Check the experiment's duration is valid before adding
1022 #the lease to the requested leases list
1023 duration_in_seconds = \
1024 int(single_requested_lease['duration'])
1025 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1026 requested_lease_list.append(single_requested_lease)
1028 return requested_lease_list
1031 def _group_leases_by_start_time(requested_lease_list):
1033 Create dict of leases by start_time, regrouping nodes reserved
1034 at the same time, for the same amount of time so as to
1035 define one job on OAR.
1037 :param requested_lease_list: list of leases
1038 :type requested_lease_list: list
1039 :returns: Dictionary with key = start time, value = list of leases
1040 with the same start time.
1045 requested_xp_dict = {}
1046 for lease in requested_lease_list:
1048 #In case it is an asap experiment start_time is empty
1049 if lease['start_time'] == '':
1050 lease['start_time'] = '0'
1052 if lease['start_time'] not in requested_xp_dict:
1053 if isinstance(lease['hostname'], str):
1054 lease['hostname'] = [lease['hostname']]
1056 requested_xp_dict[lease['start_time']] = lease
1059 job_lease = requested_xp_dict[lease['start_time']]
1060 if lease['duration'] == job_lease['duration']:
1061 job_lease['hostname'].append(lease['hostname'])
1063 return requested_xp_dict
1065 def _process_requested_xp_dict(self, rspec):
1067 Turns the requested leases and information into a dictionary
1068 of requested jobs, grouped by starting time.
1070 :param rspec: RSpec received
1075 requested_lease_list = self._get_requested_leases_list(rspec)
1076 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1077 requested_lease_list %s" % (requested_lease_list))
1078 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1079 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1086 def delete(self, slice_urns, options={}):
1088 Deletes the lease associated with the slice hrn and the credentials
1089 if the slice belongs to iotlab. Answer to DeleteSliver.
1091 :param slice_urn: urn of the slice
1092 :type slice_urn: string
1095 :returns: 1 if the slice to delete was not found on iotlab,
1096 True if the deletion was successful, False otherwise otherwise.
1098 .. note:: Should really be named delete_leases because iotlab does
1099 not have any slivers, but only deals with leases. However,
1100 SFA api only have delete_sliver define so far. SA 13/05/2013
1101 .. note:: creds are unused, and are not used either in the dummy driver
1104 # collect sliver ids so we can update sliver allocation states after
1105 # we remove the slivers.
1106 aggregate = IotlabAggregate(self)
1107 slivers = aggregate.get_slivers(slice_urns)
1109 # slice_id = slivers[0]['slice_id']
1112 sliver_jobs_dict = {}
1113 for sliver in slivers:
1114 node_ids.append(sliver['node_id'])
1115 sliver_ids.append(sliver['sliver_id'])
1116 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1117 sliver_jobs_dict[job_id] = sliver['sliver_id']
1118 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1119 % (slivers, slice_urns))
1120 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1122 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1123 slice_filter_type='slice_hrn')
1125 if not sfa_slice_list:
1128 #Delete all leases in the slice
1129 for sfa_slice in sfa_slice_list:
1130 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1131 slices = IotlabSlices(self)
1132 # determine if this is a peer slice
1134 peer = slices.get_peer(slice_hrn)
1136 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1137 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1138 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1140 for job_id in oar_bool_ans:
1141 # if the job has not been successfully deleted
1142 # don't delete the associated sliver
1143 # remove it from the sliver list
1144 if oar_bool_ans[job_id] is False:
1145 sliver = sliver_jobs_dict[job_id]
1146 sliver_ids.remove(sliver)
1149 dbsession = self.api.dbsession()
1150 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1152 logger.log_exc("IOTLABDRIVER.PY delete error ")
1154 # prepare return struct
1156 for sliver in slivers:
1157 geni_slivers.append(
1158 {'geni_sliver_urn': sliver['sliver_id'],
1159 'geni_allocation_status': 'geni_unallocated',
1160 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1163 # def list_resources (self, slice_urn, slice_hrn, creds, options):
1166 # List resources from the iotlab aggregate and returns a Rspec
1167 # advertisement with resources found when slice_urn and slice_hrn are
1168 # None (in case of resource discovery).
1169 # If a slice hrn and urn are provided, list experiment's slice
1170 # nodes in a rspec format. Answer to ListResources.
1173 # :param slice_urn: urn of the slice
1174 # :param slice_hrn: name of the slice
1175 # :param creds: slice credenials
1176 # :type slice_urn: string
1177 # :type slice_hrn: string
1178 # :type creds: ? unused
1179 # :param options: options used when listing resources (list_leases, info,
1181 # :returns: rspec string in xml
1184 # .. note:: creds are unused
1187 # #cached_requested = options.get('cached', True)
1189 # version_manager = VersionManager()
1190 # # get the rspec's return format from options
1192 # version_manager.get_version(options.get('geni_rspec_version'))
1193 # version_string = "rspec_%s" % (rspec_version)
1195 # #panos adding the info option to the caching key (can be improved)
1196 # if options.get('info'):
1197 # version_string = version_string + "_" + \
1198 # options.get('info', 'default')
1200 # # Adding the list_leases option to the caching key
1201 # if options.get('list_leases'):
1202 # version_string = version_string + "_" + \
1203 # options.get('list_leases', 'default')
1205 # # Adding geni_available to caching key
1206 # if options.get('geni_available'):
1207 # version_string = version_string + "_" + \
1208 # str(options.get('geni_available'))
1210 # # look in cache first
1211 # #if cached_requested and self.cache and not slice_hrn:
1212 # #rspec = self.cache.get(version_string)
1214 # #logger.debug("IotlabDriver.ListResources: \
1215 # #returning cached advertisement")
1218 # #panos: passing user-defined options
1219 # aggregate = IotlabAggregate(self)
1221 # rspec = aggregate.get_rspec(slice_xrn=slice_urn,
1222 # version=rspec_version, options=options)
1224 # # cache the result
1225 # #if self.cache and not slice_hrn:
1226 # #logger.debug("Iotlab.ListResources: stores advertisement in cache")
1227 # #self.cache.add(version_string, rspec)
1232 def list_slices(self, creds, options):
1233 """Answer to ListSlices.
1235 List slices belonging to iotlab, returns slice urns list.
1236 No caching used. Options unused but are defined in the SFA method
1239 :returns: slice urns list
1242 .. note:: creds and options are unused - SA 12/12/13
1244 # look in cache first
1246 #slices = self.cache.get('slices')
1248 #logger.debug("PlDriver.list_slices returns from cache")
1253 slices = self.GetSlices()
1254 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1256 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1258 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1259 for slice_hrn in slice_hrns]
1263 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1264 #self.cache.add('slices', slice_urns)
1269 def register(self, sfa_record, hrn, pub_key):
1271 Adding new user, slice, node or site should not be handled
1274 ..warnings:: should not be used. Different components are in charge of
1275 doing this task. Adding nodes = OAR
1276 Adding users = LDAP Iotlab
1277 Adding slice = Import from LDAP users
1280 :param sfa_record: record provided by the client of the
1282 :type sfa_record: dict
1283 :param pub_key: public key of the user
1284 :type pub_key: string
1286 .. note:: DOES NOTHING. Returns -1.
1292 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1294 No site or node record update allowed in Iotlab. The only modifications
1295 authorized here are key deletion/addition on an existing user and
1296 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1297 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1298 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1299 user's ssh key should nmodify the slice's GID after an import procedure.
1301 :param old_sfa_record: what is in the db for this hrn
1302 :param new_sfa_record: what was passed to the update call
1303 :param new_key: the new user's public key
1304 :param hrn: the user's sfa hrn
1305 :type old_sfa_record: dict
1306 :type new_sfa_record: dict
1307 :type new_key: string
1311 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1312 since users, keys and slice are managed by the LDAP.
1315 # pointer = old_sfa_record['pointer']
1316 # old_sfa_record_type = old_sfa_record['type']
1318 # # new_key implemented for users only
1319 # if new_key and old_sfa_record_type not in ['user']:
1320 # raise UnknownSfaType(old_sfa_record_type)
1322 # if old_sfa_record_type == "user":
1323 # update_fields = {}
1324 # all_fields = new_sfa_record
1325 # for key in all_fields.keys():
1326 # if key in ['key', 'password']:
1327 # update_fields[key] = all_fields[key]
1330 # # must check this key against the previous one if it exists
1331 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1332 # person = persons[0]
1333 # keys = [person['pkey']]
1334 # #Get all the person's keys
1335 # keys_dict = self.GetKeys(keys)
1337 # # Delete all stale keys, meaning the user has only one key
1339 # #TODO: do we really want to delete all the other keys?
1340 # #Is this a problem with the GID generation to have multiple
1341 # #keys? SA 30/05/13
1342 # key_exists = False
1343 # if key in keys_dict:
1346 # #remove all the other keys
1347 # for key in keys_dict:
1348 # self.testbed_shell.DeleteKey(person, key)
1349 # self.testbed_shell.AddPersonKey(
1350 # person, {'sshPublicKey': person['pkey']},
1351 # {'sshPublicKey': new_key})
1352 logger.warning ("UNDEFINED - Update should be done by the \
1356 def remove(self, sfa_record):
1359 Removes users only. Mark the user as disabled in LDAP. The user and his
1360 slice are then deleted from the db by running an import on the registry.
1362 :param sfa_record: record is the existing sfa record in the db
1363 :type sfa_record: dict
1365 ..warning::As fas as the slice is concerned, here only the leases are
1366 removed from the slice. The slice is record itself is not removed
1371 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1373 TODO: return boolean for the slice part
1375 sfa_record_type = sfa_record['type']
1376 hrn = sfa_record['hrn']
1377 if sfa_record_type == 'user':
1379 #get user from iotlab ldap
1380 person = self.testbed_shell.GetPersons(sfa_record)
1381 #No registering at a given site in Iotlab.
1382 #Once registered to the LDAP, all iotlab sites are
1385 #Mark account as disabled in ldap
1386 return self.testbed_shell.DeletePerson(sfa_record)
1388 elif sfa_record_type == 'slice':
1389 if self.GetSlices(slice_filter=hrn,
1390 slice_filter_type='slice_hrn'):
1391 ret = self.testbed_shell.DeleteSlice(sfa_record)
1394 def check_sliver_credentials(self, creds, urns):
1395 """Check that the sliver urns belongs to the slice specified in the
1398 :param urns: list of sliver urns.
1400 :param creds: slice credentials.
1401 :type creds: Credential object.
1405 # build list of cred object hrns
1406 slice_cred_names = []
1408 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1409 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1410 slice_cred_names.append(slicename)
1412 # look up slice name of slivers listed in urns arg
1416 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1418 slice_ids.append(int(sliver_id_parts[0]))
1423 raise Forbidden("sliver urn not provided")
1425 slices = self.GetSlices(slice_ids)
1426 sliver_names = [single_slice['name'] for single_slice in slices]
1428 # make sure we have a credential for every specified sliver
1429 for sliver_name in sliver_names:
1430 if sliver_name not in slice_cred_names:
1431 msg = "Valid credential not found for target: %s" % sliver_name
1432 raise Forbidden(msg)
1434 ########################################
1435 ########## aggregate oriented
1436 ########################################
1438 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1439 def aggregate_version(self):
1442 Returns the testbed's supported rspec advertisement and request
1444 :returns: rspec versions supported ad a dictionary.
1448 version_manager = VersionManager()
1449 ad_rspec_versions = []
1450 request_rspec_versions = []
1451 for rspec_version in version_manager.versions:
1452 if rspec_version.content_type in ['*', 'ad']:
1453 ad_rspec_versions.append(rspec_version.to_dict())
1454 if rspec_version.content_type in ['*', 'request']:
1455 request_rspec_versions.append(rspec_version.to_dict())
1457 'testbed': self.testbed_name(),
1458 'geni_request_rspec_versions': request_rspec_versions,
1459 'geni_ad_rspec_versions': ad_rspec_versions}
1461 # first 2 args are None in case of resource discovery
1462 def list_resources (self, version=None, options={}):
1463 aggregate = IotlabAggregate(self)
1464 rspec = aggregate.list_resources(version=version, options=options)
1467 def describe(self, urns, version, options={}):
1468 aggregate = IotlabAggregate(self)
1469 return aggregate.describe(urns, version=version, options=options)
1471 def status (self, urns, options={}):
1472 aggregate = IotlabAggregate(self)
1473 desc = aggregate.describe(urns, version='GENI 3')
1474 status = {'geni_urn': desc['geni_urn'],
1475 'geni_slivers': desc['geni_slivers']}
1479 def allocate (self, urn, rspec_string, expiration, options={}):
1481 aggregate = IotlabAggregate(self)
1483 slices = IotlabSlices(self)
1484 peer = slices.get_peer(xrn.get_hrn())
1485 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1489 users = options.get('geni_users', [])
1491 sfa_users = options.get('sfa_users', [])
1493 slice_record = sfa_users[0].get('slice_record', [])
1496 rspec = RSpec(rspec_string)
1497 # requested_attributes = rspec.version.get_slice_attributes()
1499 # ensure site record exists
1500 # site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
1501 # ensure slice record exists
1503 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1504 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1505 \r\n \r\n current_slice %s" % (current_slice))
1506 # ensure person records exists
1508 # oui c'est degueulasse, le slice_record se retrouve modifie
1509 # dans la methode avec les infos du user, els infos sont propagees
1510 # dans verify_slice_leases
1511 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1513 # ensure slice attributes exists
1514 # slices.verify_slice_attributes(slice, requested_attributes,
1517 # add/remove slice from nodes
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()
1524 for start_time in requested_xp_dict:
1525 lease = requested_xp_dict[start_time]
1526 for hostname in lease['hostname']:
1527 nodes_list.append(hostname)
1529 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1530 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1531 % (nodes_list, slice_record))
1534 rspec_requested_leases = rspec.version.get_leases()
1535 leases = slices.verify_slice_leases(slice_record, requested_xp_dict, peer)
1536 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1537 rspec_requested_leases %s" % (leases,
1538 rspec_requested_leases))
1539 # update sliver allocations
1540 for hostname in nodes_list:
1541 client_id = hostname
1542 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1543 component_id = node_urn
1544 slice_urn = current_slice['reg-urn']
1545 for lease in leases:
1546 if hostname in lease['reserved_nodes']:
1547 index = lease['reserved_nodes'].index(hostname)
1548 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1549 lease['resource_ids'][index] )
1550 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1551 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1552 component_id=component_id,
1553 slice_urn = slice_urn,
1554 allocation_state='geni_allocated')
1555 record.sync(self.api.dbsession())
1557 return aggregate.describe([xrn.get_urn()], version=rspec.version)
1559 def provision(self, urns, options={}):
1561 slices = IotlabSlices(self)
1562 aggregate = IotlabAggregate(self)
1563 slivers = aggregate.get_slivers(urns)
1564 current_slice = slivers[0]
1565 peer = slices.get_peer(current_slice['hrn'])
1566 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1567 users = options.get('geni_users', [])
1568 # persons = slices.verify_persons(current_slice['hrn'],
1569 # current_slice, users, peer, sfa_peer, options=options)
1570 # slices.handle_peer(None, None, persons, peer)
1571 # update sliver allocation states and set them to geni_provisioned
1572 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1573 dbsession = self.api.dbsession()
1574 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1576 version_manager = VersionManager()
1577 rspec_version = version_manager.get_version(options[
1578 'geni_rspec_version'])
1579 return self.describe(urns, rspec_version, options=options)