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 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
196 if user_dict['email']:
197 logger.debug("__add_person_to_db \r\n \r\n \
198 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
199 %(user_dict['email']))
200 person_gid.set_email(user_dict['email'])
202 user_record = RegUser(hrn=hrn , pointer= '-1', \
203 authority=get_authority(hrn), \
204 email=user_dict['email'], gid = person_gid)
205 #user_record.reg_keys = [RegKey(user_dict['pkey'])]
206 user_record.just_created()
207 self.api.dbsession().add (user_record)
208 self.api.dbsession().commit()
213 def _sql_get_slice_info(self, slice_filter):
215 Get the slice record based on the slice hrn. Fetch the record of the
216 user associated with the slice by using joinedload based on the
217 reg_researchers relationship.
219 :param slice_filter: the slice hrn we are looking for
220 :type slice_filter: string
221 :returns: the slice record enhanced with the user's information if the
222 slice was found, None it wasn't.
224 :rtype: dict or None.
226 #DO NOT USE RegSlice - reg_researchers to get the hrn
227 #of the user otherwise will mess up the RegRecord in
228 #Resolve, don't know why - SA 08/08/2012
230 #Only one entry for one user = one slice in testbed_xp table
231 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
233 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
234 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
236 #load_reg_researchers
237 #raw_slicerec.reg_researchers
238 raw_slicerec = raw_slicerec.__dict__
239 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
240 raw_slicerec %s" % (slice_filter, raw_slicerec))
241 slicerec = raw_slicerec
242 #only one researcher per slice so take the first one
243 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
244 #del slicerec['reg_researchers']['_sa_instance_state']
250 def _sql_get_slice_info_from_user(self, slice_filter):
252 Get the slice record based on the user recordid by using a joinedload
253 on the relationship reg_slices_as_researcher. Format the sql record
254 into a dict with the mandatory fields for user and slice.
255 :returns: dict with slice record and user record if the record was found
256 based on the user's id, None if not..
257 :rtype:dict or None..
259 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
260 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
261 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
262 #Put it in correct order
263 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
264 'classtype', 'authority', 'gid', 'record_id',
265 'date_created', 'type', 'email', 'pointer']
266 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
267 'classtype', 'authority', 'gid', 'record_id',
268 'date_created', 'type', 'pointer']
270 #raw_slicerec.reg_slices_as_researcher
271 raw_slicerec = raw_slicerec.__dict__
274 dict([(k, raw_slicerec[
275 'reg_slices_as_researcher'][0].__dict__[k])
276 for k in slice_needed_fields])
277 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
278 for k in user_needed_fields])
279 #TODO Handle multiple slices for one user SA 10/12/12
280 #for now only take the first slice record associated to the rec user
281 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
282 #del raw_slicerec['reg_slices_as_researcher']
283 #slicerec['reg_researchers'] = raw_slicerec
284 ##del slicerec['_sa_instance_state']
293 def _get_slice_records(self, slice_filter=None,
294 slice_filter_type=None):
296 Get the slice record depending on the slice filter and its type.
297 :param slice_filter: Can be either the slice hrn or the user's record
299 :type slice_filter: string
300 :param slice_filter_type: describes the slice filter type used, can be
301 slice_hrn or record_id_user
303 :returns: the slice record
305 .. seealso::_sql_get_slice_info_from_user
306 .. seealso:: _sql_get_slice_info
309 #Get list of slices based on the slice hrn
310 if slice_filter_type == 'slice_hrn':
312 #if get_authority(slice_filter) == self.root_auth:
313 #login = slice_filter.split(".")[1].split("_")[0]
315 slicerec = self._sql_get_slice_info(slice_filter)
321 #Get slice based on user id
322 if slice_filter_type == 'record_id_user':
324 slicerec = self._sql_get_slice_info_from_user(slice_filter)
327 fixed_slicerec_dict = slicerec
328 #At this point if there is no login it means
329 #record_id_user filter has been used for filtering
331 ##If theslice record is from iotlab
332 #if fixed_slicerec_dict['peer_authority'] is None:
333 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
334 #return login, fixed_slicerec_dict
335 return fixed_slicerec_dict
341 def GetSlices(self, slice_filter=None, slice_filter_type=None,
343 """Get the slice records from the iotlab db and add lease information
346 :param slice_filter: can be the slice hrn or slice record id in the db
347 depending on the slice_filter_type.
348 :param slice_filter_type: defines the type of the filtering used, Can be
349 either 'slice_hrn' or "record_id'.
350 :type slice_filter: string
351 :type slice_filter_type: string
352 :returns: a slice dict if slice_filter and slice_filter_type
353 are specified and a matching entry is found in the db. The result
354 is put into a list.Or a list of slice dictionnaries if no filters
361 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
362 return_slicerec_dictlist = []
364 #First try to get information on the slice based on the filter provided
365 if slice_filter_type in authorized_filter_types_list:
366 fixed_slicerec_dict = self._get_slice_records(slice_filter,
368 # if the slice was not found in the sfa db
369 if fixed_slicerec_dict is None:
370 return return_slicerec_dictlist
372 slice_hrn = fixed_slicerec_dict['hrn']
374 logger.debug(" IOTLAB_API \tGetSlices login %s \
375 slice record %s slice_filter %s \
376 slice_filter_type %s " % (login,
377 fixed_slicerec_dict, slice_filter,
381 #Now we have the slice record fixed_slicerec_dict, get the
382 #jobs associated to this slice
385 leases_list = self.GetLeases(login=login)
386 #If no job is running or no job scheduled
387 #return only the slice record
388 if leases_list == [] and fixed_slicerec_dict:
389 return_slicerec_dictlist.append(fixed_slicerec_dict)
391 # if the jobs running don't belong to the user/slice we are looking
393 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
394 if slice_hrn not in leases_hrn:
395 return_slicerec_dictlist.append(fixed_slicerec_dict)
396 #If several jobs for one slice , put the slice record into
397 # each lease information dict
398 for lease in leases_list:
400 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
401 \t lease['slice_hrn'] %s"
402 % (slice_filter, lease['slice_hrn']))
403 if lease['slice_hrn'] == slice_hrn:
404 slicerec_dict['oar_job_id'] = lease['lease_id']
405 #Update lease dict with the slice record
406 if fixed_slicerec_dict:
407 fixed_slicerec_dict['oar_job_id'] = []
408 fixed_slicerec_dict['oar_job_id'].append(
409 slicerec_dict['oar_job_id'])
410 slicerec_dict.update(fixed_slicerec_dict)
411 #slicerec_dict.update({'hrn':\
412 #str(fixed_slicerec_dict['slice_hrn'])})
413 slicerec_dict['slice_hrn'] = lease['slice_hrn']
414 slicerec_dict['hrn'] = lease['slice_hrn']
415 slicerec_dict['user'] = lease['user']
416 slicerec_dict.update(
418 {'hostname': lease['reserved_nodes']}})
419 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
423 return_slicerec_dictlist.append(slicerec_dict)
425 logger.debug("IOTLAB_API.PY \tGetSlices \
426 slicerec_dict %s return_slicerec_dictlist %s \
427 lease['reserved_nodes'] \
428 %s" % (slicerec_dict, return_slicerec_dictlist,
429 lease['reserved_nodes']))
431 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
432 return_slicerec_dictlist %s"
433 % (return_slicerec_dictlist))
435 return return_slicerec_dictlist
439 #Get all slices from the iotlab sfa database ,
440 #put them in dict format
441 #query_slice_list = dbsession.query(RegRecord).all()
443 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
445 for record in query_slice_list:
446 tmp = record.__dict__
447 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
448 #del tmp['reg_researchers']['_sa_instance_state']
449 return_slicerec_dictlist.append(tmp)
450 #return_slicerec_dictlist.append(record.__dict__)
452 #Get all the jobs reserved nodes
453 leases_list = self.testbed_shell.GetReservedNodes()
455 for fixed_slicerec_dict in return_slicerec_dictlist:
457 #Check if the slice belongs to a iotlab user
458 if fixed_slicerec_dict['peer_authority'] is None:
459 owner = fixed_slicerec_dict['hrn'].split(
460 ".")[1].split("_")[0]
463 for lease in leases_list:
464 if owner == lease['user']:
465 slicerec_dict['oar_job_id'] = lease['lease_id']
467 #for reserved_node in lease['reserved_nodes']:
468 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
470 slicerec_dict.update(fixed_slicerec_dict)
471 slicerec_dict.update({'node_ids':
472 lease['reserved_nodes']})
473 slicerec_dict.update({'list_node_ids':
475 lease['reserved_nodes']}})
477 #slicerec_dict.update({'hrn':\
478 #str(fixed_slicerec_dict['slice_hrn'])})
479 #return_slicerec_dictlist.append(slicerec_dict)
480 fixed_slicerec_dict.update(slicerec_dict)
482 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
483 return_slicerec_dictlist %s \t slice_filter %s " \
484 %(return_slicerec_dictlist, slice_filter))
486 return return_slicerec_dictlist
488 def AddLeases(self, hostname_list, slice_record,
489 lease_start_time, lease_duration):
491 """Creates a job in OAR corresponding to the information provided
492 as parameters. Adds the job id and the slice hrn in the iotlab
493 database so that we are able to know which slice has which nodes.
495 :param hostname_list: list of nodes' OAR hostnames.
496 :param slice_record: sfa slice record, must contain login and hrn.
497 :param lease_start_time: starting time , unix timestamp format
498 :param lease_duration: duration in minutes
500 :type hostname_list: list
501 :type slice_record: dict
502 :type lease_start_time: integer
503 :type lease_duration: integer
504 :returns: job_id, can be None if the job request failed.
507 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
508 slice_record %s lease_start_time %s lease_duration %s "\
509 %( hostname_list, slice_record , lease_start_time, \
512 #tmp = slice_record['reg-researchers'][0].split(".")
513 username = slice_record['login']
514 #username = tmp[(len(tmp)-1)]
515 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
516 slice_record['hrn'], \
517 lease_start_time, lease_duration, \
519 if job_id is not None:
521 datetime.fromtimestamp(int(lease_start_time)).\
522 strftime(self.testbed_shell.time_format)
523 end_time = lease_start_time + lease_duration
526 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
527 %s %s %s "%(slice_record['hrn'], job_id, end_time))
530 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
531 %(type(slice_record['hrn']), type(job_id), type(end_time)))
533 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
534 experiment_id=job_id,
537 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
539 self.api.dbsession().add(iotlab_ex_row)
540 self.api.dbsession().commit()
542 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
547 def GetLeases(self, lease_filter_dict=None, login=None):
550 Get the list of leases from OAR with complete information
551 about which slice owns which jobs and nodes.
553 -Fetch all the jobs from OAR (running, waiting..)
554 complete the reservation information with slice hrn
555 found in lease_table . If not available in the table,
556 assume it is a iotlab slice.
557 -Updates the iotlab table, deleting jobs when necessary.
559 :returns: reservation_list, list of dictionaries with 'lease_id',
560 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
561 'slice_hrn', 'resource_ids', 't_from', 't_until'
566 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
568 reservation_list = []
569 #Find the slice associated with this user iotlab ldap uid
570 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
571 unfiltered_reservation_list %s "
572 % (login, unfiltered_reservation_list))
573 #Create user dict first to avoid looking several times for
574 #the same user in LDAP SA 27/07/12
576 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
577 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
578 for row in jobs_psql_query])
579 #jobs_psql_dict = jobs_psql_dict)
580 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
582 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
584 for resa in unfiltered_reservation_list:
585 logger.debug("IOTLAB_API \tGetLeases USER %s"
587 #Construct list of jobs (runing, waiting..) in oar
588 job_oar_list.append(resa['lease_id'])
589 #If there is information on the job in IOTLAB DB ]
590 #(slice used and job id)
591 if resa['lease_id'] in jobs_psql_dict:
592 job_info = jobs_psql_dict[resa['lease_id']]
593 logger.debug("IOTLAB_API \tGetLeases job_info %s"
595 resa['slice_hrn'] = job_info['slice_hrn']
596 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
598 #otherwise, assume it is a iotlab slice:
600 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
601 + '.' + resa['user'] + "_slice",
603 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
605 resa['component_id_list'] = []
606 #Transform the hostnames into urns (component ids)
607 for node in resa['reserved_nodes']:
609 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
610 resa['component_id_list'].append(iotlab_xrn.urn)
612 if lease_filter_dict:
613 logger.debug("IOTLAB_API \tGetLeases \
614 \r\n leasefilter %s" % ( lease_filter_dict))
616 # filter_dict_functions = {
617 # 'slice_hrn' : IotlabShell.filter_lease_name,
618 # 't_from' : IotlabShell.filter_lease_start_time
620 reservation_list = list(unfiltered_reservation_list)
621 for filter_type in lease_filter_dict:
622 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
623 % (reservation_list))
624 reservation_list = self.testbed_shell.filter_lease(
625 reservation_list,filter_type,
626 lease_filter_dict[filter_type] )
628 # Filter the reservation list with a maximum timespan so that the
629 # leases and jobs running after this timestamp do not appear
630 # in the result leases.
631 # if 'start_time' in :
632 # if resa['start_time'] < lease_filter_dict['start_time']:
633 # reservation_list.append(resa)
636 # if 'name' in lease_filter_dict and \
637 # lease_filter_dict['name'] == resa['slice_hrn']:
638 # reservation_list.append(resa)
641 if lease_filter_dict is None:
642 reservation_list = unfiltered_reservation_list
644 self.update_experiments_in_lease_table(job_oar_list, jobs_psql_id_list)
646 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
647 % (reservation_list))
648 return reservation_list
652 def update_experiments_in_lease_table(self,
653 experiment_list_from_testbed, experiment_list_in_db):
654 """ Cleans the lease_table by deleting expired and cancelled jobs.
656 Compares the list of experiment ids given by the testbed with the
657 experiment ids that are already in the database, deletes the
658 experiments that are no longer in the testbed experiment id list.
660 :param experiment_list_from_testbed: list of experiment ids coming
662 :type experiment_list_from_testbed: list
663 :param experiment_list_in_db: list of experiment ids from the sfa
664 additionnal database.
665 :type experiment_list_in_db: list
669 #Turn the list into a set
670 set_experiment_list_in_db = set(experiment_list_in_db)
672 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
673 logger.debug("\r\n \t update_experiments_in_lease_table \
674 experiment_list_in_db %s \r\n \
675 experiment_list_from_testbed %s \
676 kept_experiments %s "
677 % (set_experiment_list_in_db,
678 experiment_list_from_testbed, kept_experiments))
679 deleted_experiments = set_experiment_list_in_db.difference(
681 deleted_experiments = list(deleted_experiments)
682 if len(deleted_experiments) > 0:
683 request = self.api.dbsession().query(LeaseTableXP)
684 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
685 self.api.dbsession().commit()
689 def AddSlice(self, slice_record, user_record):
692 Add slice to the local iotlab sfa tables if the slice comes
693 from a federated site and is not yet in the iotlab sfa DB,
694 although the user has already a LDAP login.
695 Called by verify_slice during lease/sliver creation.
697 :param slice_record: record of slice, must contain hrn, gid, slice_id
698 and authority of the slice.
699 :type slice_record: dictionary
700 :param user_record: record of the user
701 :type user_record: RegUser
705 sfa_record = RegSlice(hrn=slice_record['hrn'],
706 gid=slice_record['gid'],
707 #pointer=slice_record['slice_id'],
708 authority=slice_record['authority'])
709 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
710 % (sfa_record, user_record))
711 sfa_record.just_created()
712 self.api.dbsession().add(sfa_record)
713 self.api.dbsession().commit()
714 #Update the reg-researchers dependency table
715 sfa_record.reg_researchers = [user_record]
716 self.api.dbsession().commit()
720 def augment_records_with_testbed_info(self, record_list):
723 Adds specific testbed info to the records.
725 :param record_list: list of sfa dictionaries records
726 :type record_list: list
727 :returns: list of records with extended information in each record
731 return self.fill_record_info(record_list)
733 def fill_record_info(self, record_list):
736 For each SFA record, fill in the iotlab specific and SFA specific
737 fields in the record.
739 :param record_list: list of sfa dictionaries records
740 :type record_list: list
741 :returns: list of records with extended information in each record
744 .. warning:: Should not be modifying record_list directly because modi
745 fication are kept outside the method's scope. Howerver, there is no
746 other way to do it given the way it's called in registry manager.
750 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
752 if not isinstance(record_list, list):
753 record_list = [record_list]
756 for record in record_list:
758 if str(record['type']) == 'node':
759 # look for node info using GetNodes
760 # the record is about one node only
761 filter_dict = {'hrn': [record['hrn']]}
762 node_info = self.testbed_shell.GetNodes(filter_dict)
763 # the node_info is about one node only, but it is formatted
765 record.update(node_info[0])
766 logger.debug("IOTLABDRIVER.PY \t \
767 fill_record_info NODE" % (record))
769 #If the record is a SFA slice record, then add information
770 #about the user of this slice. This kind of
771 #information is in the Iotlab's DB.
772 if str(record['type']) == 'slice':
773 if 'reg_researchers' in record and isinstance(record
776 record['reg_researchers'] = \
777 record['reg_researchers'][0].__dict__
779 {'PI': [record['reg_researchers']['hrn']],
780 'researcher': [record['reg_researchers']['hrn']],
781 'name': record['hrn'],
784 'person_ids': [record['reg_researchers']
786 # For client_helper.py compatibility
788 # For client_helper.py compatibility
790 # For client_helper.py compatibility
793 #Get iotlab slice record and oar job id if any.
794 recslice_list = self.GetSlices(
795 slice_filter=str(record['hrn']),
796 slice_filter_type='slice_hrn')
798 logger.debug("IOTLABDRIVER \tfill_record_info \
799 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
800 %s " % (record['hrn'], record['oar_job_id']))
801 del record['reg_researchers']
803 for rec in recslice_list:
804 logger.debug("IOTLABDRIVER\r\n \t \
805 fill_record_info oar_job_id %s "
806 % (rec['oar_job_id']))
808 record['node_ids'] = [self.testbed_shell.root_auth +
809 '.' + hostname for hostname
814 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
815 recslice_list %s \r\n \t RECORD %s \r\n \
816 \r\n" % (recslice_list, record))
818 if str(record['type']) == 'user':
819 #The record is a SFA user record.
820 #Get the information about his slice from Iotlab's DB
821 #and add it to the user record.
822 recslice_list = self.GetSlices(
823 slice_filter=record['record_id'],
824 slice_filter_type='record_id_user')
826 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
827 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
828 % (recslice_list, record))
829 #Append slice record in records list,
830 #therefore fetches user and slice info again(one more loop)
831 #Will update PIs and researcher for the slice
833 recuser = recslice_list[0]['reg_researchers']
834 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
835 recuser %s \r\n \r\n" % (recuser))
837 recslice = recslice_list[0]
839 {'PI': [recuser['hrn']],
840 'researcher': [recuser['hrn']],
841 'name': recuser['hrn'],
844 'person_ids': [recuser['record_id']]})
846 for rec in recslice_list:
847 recslice['oar_job_id'].append(rec['oar_job_id'])
851 recslice.update({'type': 'slice',
852 'hrn': recslice_list[0]['hrn']})
854 #GetPersons takes [] as filters
855 user_iotlab = self.testbed_shell.GetPersons([record])
857 record.update(user_iotlab[0])
858 #For client_helper.py compatibility
863 record_list.append(recslice)
865 logger.debug("IOTLABDRIVER.PY \t \
866 fill_record_info ADDING SLICE\
867 INFO TO USER records %s" % (record_list))
869 except TypeError, error:
870 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
875 def sliver_status(self, slice_urn, slice_hrn):
877 Receive a status request for slice named urn/hrn
878 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
879 shall return a structure as described in
880 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
881 NT : not sure if we should implement this or not, but used by sface.
883 :param slice_urn: slice urn
884 :type slice_urn: string
885 :param slice_hrn: slice hrn
886 :type slice_hrn: string
890 #First get the slice with the slice hrn
891 slice_list = self.GetSlices(slice_filter=slice_hrn,
892 slice_filter_type='slice_hrn')
894 if len(slice_list) == 0:
895 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
897 #Used for fetching the user info witch comes along the slice info
898 one_slice = slice_list[0]
900 #Make a list of all the nodes hostnames in use for this slice
901 slice_nodes_list = []
902 slice_nodes_list = one_slice['node_ids']
903 #Get all the corresponding nodes details
904 nodes_all = self.testbed_shell.GetNodes(
905 {'hostname': slice_nodes_list},
906 ['node_id', 'hostname', 'site', 'boot_state'])
907 nodeall_byhostname = dict([(one_node['hostname'], one_node)
908 for one_node in nodes_all])
910 for single_slice in slice_list:
912 top_level_status = 'empty'
915 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
916 'geni_resources'], None)
918 # ['geni_urn','geni_error', 'pl_login','geni_status',
919 # 'geni_resources'], None)
920 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
921 result['iotlab_login'] = one_slice['user']
922 logger.debug("Slabdriver - sliver_status Sliver status \
923 urn %s hrn %s single_slice %s \r\n "
924 % (slice_urn, slice_hrn, single_slice))
926 if 'node_ids' not in single_slice:
928 result['geni_status'] = top_level_status
929 result['geni_resources'] = []
932 top_level_status = 'ready'
934 #A job is running on Iotlab for this slice
935 # report about the local nodes that are in the slice only
937 result['geni_urn'] = slice_urn
940 for node_hostname in single_slice['node_ids']:
942 res['iotlab_hostname'] = node_hostname
943 res['iotlab_boot_state'] = \
944 nodeall_byhostname[node_hostname]['boot_state']
946 #res['pl_hostname'] = node['hostname']
947 #res['pl_boot_state'] = \
948 #nodeall_byhostname[node['hostname']]['boot_state']
949 #res['pl_last_contact'] = strftime(self.time_format, \
950 #gmtime(float(timestamp)))
952 slice_urn, type='slice',
953 id=nodeall_byhostname[node_hostname]['node_id']).urn
955 res['geni_urn'] = sliver_id
956 #node_name = node['hostname']
957 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
959 res['geni_status'] = 'ready'
961 res['geni_status'] = 'failed'
962 top_level_status = 'failed'
964 res['geni_error'] = ''
966 resources.append(res)
968 result['geni_status'] = top_level_status
969 result['geni_resources'] = resources
970 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
974 def get_user_record(self, hrn):
977 Returns the user record based on the hrn from the SFA DB .
979 :param hrn: user's hrn
981 :returns: user record from SFA database
985 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
987 def testbed_name(self):
990 Returns testbed's name.
991 :returns: testbed authority name.
998 def _get_requested_leases_list(self, rspec):
1000 Process leases in rspec depending on the rspec version (format)
1001 type. Find the lease requests in the rspec and creates
1002 a lease request list with the mandatory information ( nodes,
1003 start time and duration) of the valid leases (duration above or
1004 equal to the iotlab experiment minimum duration).
1006 :param rspec: rspec request received.
1008 :returns: list of lease requests found in the rspec
1011 requested_lease_list = []
1012 for lease in rspec.version.get_leases():
1013 single_requested_lease = {}
1014 logger.debug("IOTLABDRIVER.PY \t \
1015 _get_requested_leases_list lease %s " % (lease))
1017 if not lease.get('lease_id'):
1018 if get_authority(lease['component_id']) == \
1019 self.testbed_shell.root_auth:
1020 single_requested_lease['hostname'] = \
1022 lease.get('component_id').strip())
1023 single_requested_lease['start_time'] = \
1024 lease.get('start_time')
1025 single_requested_lease['duration'] = lease.get('duration')
1026 #Check the experiment's duration is valid before adding
1027 #the lease to the requested leases list
1028 duration_in_seconds = \
1029 int(single_requested_lease['duration'])
1030 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1031 requested_lease_list.append(single_requested_lease)
1033 return requested_lease_list
1036 def _group_leases_by_start_time(requested_lease_list):
1038 Create dict of leases by start_time, regrouping nodes reserved
1039 at the same time, for the same amount of time so as to
1040 define one job on OAR.
1042 :param requested_lease_list: list of leases
1043 :type requested_lease_list: list
1044 :returns: Dictionary with key = start time, value = list of leases
1045 with the same start time.
1050 requested_xp_dict = {}
1051 for lease in requested_lease_list:
1053 #In case it is an asap experiment start_time is empty
1054 if lease['start_time'] == '':
1055 lease['start_time'] = '0'
1057 if lease['start_time'] not in requested_xp_dict:
1058 if isinstance(lease['hostname'], str):
1059 lease['hostname'] = [lease['hostname']]
1061 requested_xp_dict[lease['start_time']] = lease
1064 job_lease = requested_xp_dict[lease['start_time']]
1065 if lease['duration'] == job_lease['duration']:
1066 job_lease['hostname'].append(lease['hostname'])
1068 return requested_xp_dict
1070 def _process_requested_xp_dict(self, rspec):
1072 Turns the requested leases and information into a dictionary
1073 of requested jobs, grouped by starting time.
1075 :param rspec: RSpec received
1080 requested_lease_list = self._get_requested_leases_list(rspec)
1081 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1082 requested_lease_list %s" % (requested_lease_list))
1083 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1084 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1091 def delete(self, slice_urns, options=None):
1093 Deletes the lease associated with the slice hrn and the credentials
1094 if the slice belongs to iotlab. Answer to DeleteSliver.
1096 :param slice_urn: urn of the slice
1097 :type slice_urn: string
1100 :returns: 1 if the slice to delete was not found on iotlab,
1101 True if the deletion was successful, False otherwise otherwise.
1103 .. note:: Should really be named delete_leases because iotlab does
1104 not have any slivers, but only deals with leases. However,
1105 SFA api only have delete_sliver define so far. SA 13/05/2013
1106 .. note:: creds are unused, and are not used either in the dummy driver
1109 if options is None: options={}
1110 # collect sliver ids so we can update sliver allocation states after
1111 # we remove the slivers.
1112 aggregate = IotlabAggregate(self)
1113 slivers = aggregate.get_slivers(slice_urns)
1115 # slice_id = slivers[0]['slice_id']
1118 sliver_jobs_dict = {}
1119 for sliver in slivers:
1120 node_ids.append(sliver['node_id'])
1121 sliver_ids.append(sliver['sliver_id'])
1122 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1123 sliver_jobs_dict[job_id] = sliver['sliver_id']
1124 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1125 % (slivers, slice_urns))
1126 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1128 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1129 slice_filter_type='slice_hrn')
1131 if not sfa_slice_list:
1134 #Delete all leases in the slice
1135 for sfa_slice in sfa_slice_list:
1136 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1137 slices = IotlabSlices(self)
1138 # determine if this is a peer slice
1140 peer = slices.get_peer(slice_hrn)
1142 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1143 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1144 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1146 for job_id in oar_bool_ans:
1147 # if the job has not been successfully deleted
1148 # don't delete the associated sliver
1149 # remove it from the sliver list
1150 if oar_bool_ans[job_id] is False:
1151 sliver = sliver_jobs_dict[job_id]
1152 sliver_ids.remove(sliver)
1155 dbsession = self.api.dbsession()
1156 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1158 logger.log_exc("IOTLABDRIVER.PY delete error ")
1160 # prepare return struct
1162 for sliver in slivers:
1163 geni_slivers.append(
1164 {'geni_sliver_urn': sliver['sliver_id'],
1165 'geni_allocation_status': 'geni_unallocated',
1166 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1172 def list_slices(self, creds, options):
1173 """Answer to ListSlices.
1175 List slices belonging to iotlab, returns slice urns list.
1176 No caching used. Options unused but are defined in the SFA method
1179 :returns: slice urns list
1182 .. note:: creds and options are unused - SA 12/12/13
1184 # look in cache first
1186 #slices = self.cache.get('slices')
1188 #logger.debug("PlDriver.list_slices returns from cache")
1193 slices = self.GetSlices()
1194 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1196 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1198 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1199 for slice_hrn in slice_hrns]
1203 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1204 #self.cache.add('slices', slice_urns)
1209 def register(self, sfa_record, hrn, pub_key):
1211 Adding new user, slice, node or site should not be handled
1214 ..warnings:: should not be used. Different components are in charge of
1215 doing this task. Adding nodes = OAR
1216 Adding users = LDAP Iotlab
1217 Adding slice = Import from LDAP users
1220 :param sfa_record: record provided by the client of the
1222 :type sfa_record: dict
1223 :param pub_key: public key of the user
1224 :type pub_key: string
1226 .. note:: DOES NOTHING. Returns -1.
1232 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1234 No site or node record update allowed in Iotlab. The only modifications
1235 authorized here are key deletion/addition on an existing user and
1236 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1237 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1238 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1239 user's ssh key should nmodify the slice's GID after an import procedure.
1241 :param old_sfa_record: what is in the db for this hrn
1242 :param new_sfa_record: what was passed to the update call
1243 :param new_key: the new user's public key
1244 :param hrn: the user's sfa hrn
1245 :type old_sfa_record: dict
1246 :type new_sfa_record: dict
1247 :type new_key: string
1251 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1252 since users, keys and slice are managed by the LDAP.
1255 # pointer = old_sfa_record['pointer']
1256 # old_sfa_record_type = old_sfa_record['type']
1258 # # new_key implemented for users only
1259 # if new_key and old_sfa_record_type not in ['user']:
1260 # raise UnknownSfaType(old_sfa_record_type)
1262 # if old_sfa_record_type == "user":
1263 # update_fields = {}
1264 # all_fields = new_sfa_record
1265 # for key in all_fields.keys():
1266 # if key in ['key', 'password']:
1267 # update_fields[key] = all_fields[key]
1270 # # must check this key against the previous one if it exists
1271 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1272 # person = persons[0]
1273 # keys = [person['pkey']]
1274 # #Get all the person's keys
1275 # keys_dict = self.GetKeys(keys)
1277 # # Delete all stale keys, meaning the user has only one key
1279 # #TODO: do we really want to delete all the other keys?
1280 # #Is this a problem with the GID generation to have multiple
1281 # #keys? SA 30/05/13
1282 # key_exists = False
1283 # if key in keys_dict:
1286 # #remove all the other keys
1287 # for key in keys_dict:
1288 # self.testbed_shell.DeleteKey(person, key)
1289 # self.testbed_shell.AddPersonKey(
1290 # person, {'sshPublicKey': person['pkey']},
1291 # {'sshPublicKey': new_key})
1292 logger.warning ("UNDEFINED - Update should be done by the \
1296 def remove(self, sfa_record):
1299 Removes users only. Mark the user as disabled in LDAP. The user and his
1300 slice are then deleted from the db by running an import on the registry.
1302 :param sfa_record: record is the existing sfa record in the db
1303 :type sfa_record: dict
1305 ..warning::As fas as the slice is concerned, here only the leases are
1306 removed from the slice. The slice is record itself is not removed
1311 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1313 TODO: return boolean for the slice part
1315 sfa_record_type = sfa_record['type']
1316 hrn = sfa_record['hrn']
1317 if sfa_record_type == 'user':
1319 #get user from iotlab ldap
1320 person = self.testbed_shell.GetPersons(sfa_record)
1321 #No registering at a given site in Iotlab.
1322 #Once registered to the LDAP, all iotlab sites are
1325 #Mark account as disabled in ldap
1326 return self.testbed_shell.DeletePerson(sfa_record)
1328 elif sfa_record_type == 'slice':
1329 if self.GetSlices(slice_filter=hrn,
1330 slice_filter_type='slice_hrn'):
1331 ret = self.testbed_shell.DeleteSlice(sfa_record)
1334 def check_sliver_credentials(self, creds, urns):
1335 """Check that the sliver urns belongs to the slice specified in the
1338 :param urns: list of sliver urns.
1340 :param creds: slice credentials.
1341 :type creds: Credential object.
1345 # build list of cred object hrns
1346 slice_cred_names = []
1348 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1349 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1350 slice_cred_names.append(slicename)
1352 # look up slice name of slivers listed in urns arg
1356 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1358 slice_ids.append(int(sliver_id_parts[0]))
1363 raise Forbidden("sliver urn not provided")
1365 slices = self.GetSlices(slice_ids)
1366 sliver_names = [single_slice['name'] for single_slice in slices]
1368 # make sure we have a credential for every specified sliver
1369 for sliver_name in sliver_names:
1370 if sliver_name not in slice_cred_names:
1371 msg = "Valid credential not found for target: %s" % sliver_name
1372 raise Forbidden(msg)
1374 ########################################
1375 ########## aggregate oriented
1376 ########################################
1378 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1379 def aggregate_version(self):
1382 Returns the testbed's supported rspec advertisement and request
1384 :returns: rspec versions supported ad a dictionary.
1388 version_manager = VersionManager()
1389 ad_rspec_versions = []
1390 request_rspec_versions = []
1391 for rspec_version in version_manager.versions:
1392 if rspec_version.content_type in ['*', 'ad']:
1393 ad_rspec_versions.append(rspec_version.to_dict())
1394 if rspec_version.content_type in ['*', 'request']:
1395 request_rspec_versions.append(rspec_version.to_dict())
1397 'testbed': self.testbed_name(),
1398 'geni_request_rspec_versions': request_rspec_versions,
1399 'geni_ad_rspec_versions': ad_rspec_versions}
1401 # first 2 args are None in case of resource discovery
1402 def list_resources (self, version=None, options=None):
1403 if options is None: options={}
1404 aggregate = IotlabAggregate(self)
1405 rspec = aggregate.list_resources(version=version, options=options)
1408 def describe(self, urns, version, options={}):
1409 aggregate = IotlabAggregate(self)
1410 return aggregate.describe(urns, version=version, options=options)
1412 def status (self, urns, options=None):
1413 if options is None: options={}
1414 aggregate = IotlabAggregate(self)
1415 desc = aggregate.describe(urns, version='GENI 3')
1416 status = {'geni_urn': desc['geni_urn'],
1417 'geni_slivers': desc['geni_slivers']}
1421 def allocate (self, urn, rspec_string, expiration, options=None):
1422 if options is None: options={}
1424 aggregate = IotlabAggregate(self)
1426 slices = IotlabSlices(self)
1427 peer = slices.get_peer(xrn.get_hrn())
1428 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1430 caller_hrn = options.get('actual_caller_hrn', [])
1431 caller_xrn = Xrn(caller_hrn)
1432 caller_urn = caller_xrn.get_urn()
1434 logger.debug("IOTLABDRIVER.PY :: Allocate caller = %s" % (caller_urn))
1437 users = options.get('geni_users', [])
1438 sfa_users = options.get('sfa_users', [])
1442 # Looking for the user who actually called the Allocate function in the list of users of the slice
1444 if 'urn' in u and u['urn'] == caller_urn:
1446 logger.debug("user = %s" % u)
1447 # If we find the user in the list we use it, else we take the 1st in the list as before
1449 user_hrn = caller_hrn
1452 # XXX Always empty ??? no slice_record in the Allocate call
1453 #slice_record = sfa_users[0].get('slice_record', [])
1454 user_xrn = Xrn(sfa_users[0]['urn'])
1455 user_hrn = user_xrn.get_hrn()
1457 slice_record = user.get('slice_record', {})
1458 slice_record['user'] = {'keys': user['keys'],
1459 'email': user['email'],
1461 slice_record['authority'] = xrn.get_authority_hrn()
1463 logger.debug("IOTLABDRIVER.PY \t urn %s allocate options %s "
1467 rspec = RSpec(rspec_string)
1468 # requested_attributes = rspec.version.get_slice_attributes()
1470 # ensure site record exists
1472 # ensure person records exists
1474 # XXX LOIC using hrn is a workaround because the function
1475 # Xrn.get_urn returns 'urn:publicid:IDN+onelab:upmc+timur_friedman'
1476 # Instead of this 'urn:publicid:IDN+onelab:upmc+user+timur_friedman'
1477 user['hrn'] = urn_to_hrn(user['urn'])[0]
1478 # XXX LOIC adding the users of the slice to reg-researchers
1479 # reg-researchers is used in iotlabslices.py verify_slice in order to add the slice
1480 if 'reg-researchers' not in slice_record:
1481 slice_record['reg-researchers'] = list()
1482 slice_record['reg-researchers'].append(user['hrn'])
1483 if caller_hrn == user['hrn']:
1484 #hierarchical_user = user['hrn'].split(".")
1485 #user['login'] = hierarchical_user[-1]
1486 #slice_record['login'] = user['login']
1487 slice_record['user']=user
1489 # oui c'est degueulasse, le slice_record se retrouve modifie
1490 # dans la methode avec les infos du user, els infos sont propagees
1491 # dans verify_slice_leases
1492 logger.debug("IOTLABDRIVER.PY BEFORE slices.verify_persons")
1494 # XXX JORDAN XXX slice_record devrait recevoir le caller_xrn...
1495 # LOIC maintenant c'est fait au dessus
1496 logger.debug("LOIC - slice_record[user] = %s" % slice_record['user'])
1497 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1499 logger.debug("IOTLABDRIVER.PY AFTER slices.verify_persons")
1500 logger.debug("LOIC - slice_record[user] = %s" % slice_record['user'])
1502 # ensure slice record exists
1503 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1504 logger.debug("LOIC - AFTER verify_slice - slice_record[user] = %s" % slice_record['user'])
1505 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1506 \r\n \r\n current_slice %s" % (current_slice))
1508 # ensure slice attributes exists
1509 # slices.verify_slice_attributes(slice, requested_attributes,
1512 # add/remove slice from nodes
1513 # XXX JORDAN ensure requested_xp_dict returns a dict with all new leases
1514 requested_xp_dict = self._process_requested_xp_dict(rspec)
1516 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1517 % (requested_xp_dict))
1518 request_nodes = rspec.version.get_nodes_with_slivers()
1521 # JORDAN: nodes_list will contain a list of newly allocated nodes
1523 for start_time in requested_xp_dict:
1524 lease = requested_xp_dict[start_time]
1525 for hostname in lease['hostname']:
1526 nodes_list.append(hostname)
1528 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1529 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1530 % (nodes_list, slice_record))
1533 rspec_requested_leases = rspec.version.get_leases()
1534 leases = slices.verify_slice_leases(slice_record,
1535 requested_xp_dict, peer)
1537 # leases = already in slice
1538 # rspec_requested_leases = newly requested
1539 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1540 rspec_requested_leases %s" % (leases,
1541 rspec_requested_leases))
1542 # update sliver allocations
1543 # JORDAN Here we loop over newly allocated nodes
1544 for hostname in nodes_list:
1545 client_id = hostname
1546 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1547 component_id = node_urn
1548 if 'reg-urn' in current_slice:
1549 slice_urn = current_slice['reg-urn']
1551 slice_urn = current_slice['urn']
1553 # JORDAN: We loop over leases previously in the slice
1554 for lease in leases:
1555 if hostname in lease['reserved_nodes']:
1556 index = lease['reserved_nodes'].index(hostname)
1557 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1558 lease['resource_ids'][index] )
1559 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1560 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1561 component_id=component_id,
1562 slice_urn = slice_urn,
1563 allocation_state='geni_allocated')
1564 record.sync(self.api.dbsession())
1566 # JORDAN : added describe_options which was not specified at all
1567 describe_options = {
1568 'geni_slice_urn': urn,
1569 'list_leases': 'all',
1571 return aggregate.describe([xrn.get_urn()], version=rspec.version, options=describe_options)
1573 def provision(self, urns, options=None):
1574 if options is None: options={}
1576 slices = IotlabSlices(self)
1577 aggregate = IotlabAggregate(self)
1578 slivers = aggregate.get_slivers(urns)
1579 current_slice = slivers[0]
1580 peer = slices.get_peer(current_slice['hrn'])
1581 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1582 users = options.get('geni_users', [])
1583 # persons = slices.verify_persons(current_slice['hrn'],
1584 # current_slice, users, peer, sfa_peer, options=options)
1585 # slices.handle_peer(None, None, persons, peer)
1586 # update sliver allocation states and set them to geni_provisioned
1587 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1588 dbsession = self.api.dbsession()
1589 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1591 version_manager = VersionManager()
1592 rspec_version = version_manager.get_version(options[
1593 'geni_rspec_version'])
1594 # JORDAN : added describe_options instead of options
1595 # urns at the begining ???
1596 describe_options = {
1597 'geni_slice_urn': current_slice['urn'],
1598 'list_leases': 'all',
1600 return self.describe(urns, rspec_version, options=describe_options)