2 Implements what a driver should provide for SFA to work.
4 from datetime import datetime
5 from sfa.util.sfatime import utcparse, datetime_to_string
7 from sfa.util.faults import SliverDoesNotExist, Forbidden
8 from sfa.util.sfalogging import logger
10 from sfa.trust.hierarchy import Hierarchy
11 from sfa.trust.gid import create_uuid
13 from sfa.managers.driver import Driver
14 from sfa.rspecs.version_manager import VersionManager
15 from sfa.rspecs.rspec import RSpec
17 from sfa.cortexlab.cortexlabaggregate import CortexlabAggregate
19 from sfa.cortexlab.cortexlabslices import CortexlabSlices
20 from sfa.cortexlab.cortexlabshell import CortexlabShell
22 from sfa.iotlab.iotlabxrn import IotlabXrn, xrn_object
23 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
25 from sfa.trust.certificate import Keypair, convert_public_key
26 from sfa.trust.credential import Credential
27 from sfa.storage.model import SliverAllocation
29 from sfa.storage.model import RegRecord, RegUser, RegSlice, RegKey
30 from sfa.iotlab.iotlabpostgres import LeaseTableXP
31 from sqlalchemy.orm import joinedload
33 class CortexlabDriver(Driver):
34 """ Cortexlab Driver class inherited from Driver generic class.
36 Contains methods compliant with the SFA standard and the testbed
37 infrastructure (calls to LDAP and scheduler to book the nodes).
39 .. seealso::: Driver class
42 def __init__(self, api):
45 Sets the Cortexlab SFA config parameters,
46 instanciates the testbed api.
48 :param api: SfaApi configuration object. Holds reference to the
50 :type api: SfaApi object
53 Driver.__init__(self, api)
56 self.testbed_shell = CortexlabShell(config)
59 def GetPeers(self, peer_filter=None ):
60 """ Gathers registered authorities in SFA DB and looks for specific peer
61 if peer_filter is specified.
62 :param peer_filter: name of the site authority looked for.
63 :type peer_filter: string
64 :returns: list of records.
69 existing_hrns_by_types = {}
70 logger.debug("CORTEXLAB_API \tGetPeers peer_filter %s " % (peer_filter))
71 query = self.api.dbsession().query(RegRecord)
72 all_records = query.filter(RegRecord.type.like('%authority%')).all()
74 for record in all_records:
75 existing_records[(record.hrn, record.type)] = record
76 if record.type not in existing_hrns_by_types:
77 existing_hrns_by_types[record.type] = [record.hrn]
79 existing_hrns_by_types[record.type].append(record.hrn)
81 logger.debug("CORTEXLAB_API \tGetPeer\texisting_hrns_by_types %s "
82 % (existing_hrns_by_types))
87 records_list.append(existing_records[(peer_filter,
90 for hrn in existing_hrns_by_types['authority']:
91 records_list.append(existing_records[(hrn, 'authority')])
93 logger.debug("CORTEXLAB_API \tGetPeer \trecords_list %s "
99 return_records = records_list
100 logger.debug("CORTEXLAB_API \tGetPeer return_records %s "
102 return return_records
104 def GetKeys(self, key_filter=None):
105 """Returns a dict of dict based on the key string. Each dict entry
106 contains the key id, the ssh key, the user's email and the
108 If key_filter is specified and is an array of key identifiers,
109 only keys matching the filter will be returned.
111 Admin may query all keys. Non-admins may only query their own keys.
114 :returns: dict with ssh key as key and dicts as value.
117 query = self.api.dbsession().query(RegKey)
118 if key_filter is None:
119 keys = query.options(joinedload('reg_user')).all()
121 constraint = RegKey.key.in_(key_filter)
122 keys = query.options(joinedload('reg_user')).filter(constraint).all()
126 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
127 'email': key.reg_user.email,
128 'hrn': key.reg_user.hrn}
130 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
131 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
132 #for user in ldap_rslt)
134 logger.debug("CORTEXLAB_API GetKeys -key_dict %s \r\n " % (key_dict))
137 def AddPerson(self, record):
140 Adds a new account. Any fields specified in records are used,
141 otherwise defaults are used. Creates an appropriate login by calling
144 :param record: dictionary with the sfa user's properties.
145 :returns: a dicitonary with the status. If successful, the dictionary
146 boolean is set to True and there is a 'uid' key with the new login
147 added to LDAP, otherwise the bool is set to False and a key
148 'message' is in the dictionary, with the error message.
152 ret = self.testbed_shell.ldap.LdapAddUser(record)
154 if ret['bool'] is True:
155 record['hrn'] = self.testbed_shell.root_auth + '.' + ret['uid']
156 logger.debug("Cortexlab api AddPerson return code %s record %s "
158 self.__add_person_to_db(record)
161 def __add_person_to_db(self, user_dict):
163 Add a federated user straight to db when the user issues a lease
164 request with nodes and that he has not registered with cortexlab
165 yet (that is he does not have a LDAP entry yet).
166 Uses parts of the routines in CortexlabImport when importing user
168 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 request = self.api.dbsession().query(RegUser)
176 request.filter_by(email = user_dict['email']).first()
178 if not check_if_exists:
179 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
181 hrn = user_dict['hrn']
182 person_urn = hrn_to_urn(hrn, 'user')
183 pubkey = user_dict['pkey']
185 pkey = convert_public_key(pubkey)
187 #key not good. create another pkey
188 logger.warn('__add_person_to_db: unable to convert public \
190 pkey = Keypair(create=True)
193 if pubkey is not None and pkey is not None :
194 hierarchy = Hierarchy()
195 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
197 if user_dict['email']:
198 logger.debug("__add_person_to_db \r\n \r\n \
199 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
200 %(user_dict['email']))
201 person_gid.set_email(user_dict['email'])
203 user_record = RegUser(hrn=hrn , pointer= '-1', \
204 authority=get_authority(hrn), \
205 email=user_dict['email'], gid = person_gid)
206 user_record.reg_keys = [RegKey(user_dict['pkey'])]
207 user_record.just_created()
208 self.api.dbsession().add (user_record)
209 self.api.dbsession().commit()
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_researcher 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()
232 request = self.api.dbsession().query(RegSlice)
233 raw_slicerec = request.options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
234 #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
237 #raw_slicerec.reg_researchers
238 raw_slicerec = raw_slicerec.__dict__
239 logger.debug(" CORTEXLAB_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 request = self.api.dbsession().query(RegUser)
261 raw_slicerec = request.options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
262 #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
263 #Put it in correct order
264 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
265 'classtype', 'authority', 'gid', 'record_id',
266 'date_created', 'type', 'email', 'pointer']
267 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
268 'classtype', 'authority', 'gid', 'record_id',
269 'date_created', 'type', 'pointer']
271 #raw_slicerec.reg_slices_as_researcher
272 raw_slicerec = raw_slicerec.__dict__
275 dict([(k, raw_slicerec[
276 'reg_slices_as_researcher'][0].__dict__[k])
277 for k in slice_needed_fields])
278 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
279 for k in user_needed_fields])
280 #TODO Handle multiple slices for one user SA 10/12/12
281 #for now only take the first slice record associated to the rec user
282 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
283 #del raw_slicerec['reg_slices_as_researcher']
284 #slicerec['reg_researchers'] = raw_slicerec
285 ##del slicerec['_sa_instance_state']
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 sfa 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(" CORTEXLAB_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 experiments for one slice , put the slice record into
397 # each lease information dict
398 for lease in leases_list:
400 logger.debug("CORTEXLAB_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['experiment_id'] = lease['lease_id']
405 #Update lease dict with the slice record
406 if fixed_slicerec_dict:
407 fixed_slicerec_dict['experiment_id'] = []
408 fixed_slicerec_dict['experiment_id'].append(
409 slicerec_dict['experiment_id'])
410 slicerec_dict.update(fixed_slicerec_dict)
412 slicerec_dict['slice_hrn'] = lease['slice_hrn']
413 slicerec_dict['hrn'] = lease['slice_hrn']
414 slicerec_dict['user'] = lease['user']
415 slicerec_dict.update(
417 {'hostname': lease['reserved_nodes']}})
418 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
421 return_slicerec_dictlist.append(slicerec_dict)
424 logger.debug("CORTEXLAB_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("CORTEXLAB_API.PY \tGetSlices RETURN \
431 return_slicerec_dictlist %s"
432 % (return_slicerec_dictlist))
434 return return_slicerec_dictlist
438 #Get all slices from the cortexlab sfa database , get the user info
439 # as well at the same time put them in dict format
440 request = self.api.dbsession().query(RegSlice)
442 request.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 return_slicerec_dictlist.append(tmp)
450 #Get all the experiments reserved nodes
451 leases_list = self.testbed_shell.GetReservedNodes()
453 for fixed_slicerec_dict in return_slicerec_dictlist:
455 #Check if the slice belongs to a cortexlab user
456 if fixed_slicerec_dict['peer_authority'] is None:
457 owner = fixed_slicerec_dict['hrn'].split(
458 ".")[1].split("_")[0]
461 for lease in leases_list:
462 if owner == lease['user']:
463 slicerec_dict['experiment_id'] = lease['lease_id']
465 #for reserved_node in lease['reserved_nodes']:
466 logger.debug("CORTEXLAB_API.PY \tGetSlices lease %s "
468 slicerec_dict.update(fixed_slicerec_dict)
469 slicerec_dict.update({'node_ids':
470 lease['reserved_nodes']})
471 slicerec_dict.update({'list_node_ids':
473 lease['reserved_nodes']}})
476 fixed_slicerec_dict.update(slicerec_dict)
478 logger.debug("CORTEXLAB_API.PY \tGetSlices RETURN \
479 return_slicerec_dictlist %s \t slice_filter %s " \
480 %(return_slicerec_dictlist, slice_filter))
482 return return_slicerec_dictlist
484 def AddLeases(self, hostname_list, slice_record,
485 lease_start_time, lease_duration):
487 """Creates an experiment on the testbed corresponding to the information
488 provided as parameters. Adds the experiment id and the slice hrn in the
489 lease table on the additional sfa database so that we are able to know
490 which slice has which nodes.
492 :param hostname_list: list of nodes' OAR hostnames.
493 :param slice_record: sfa slice record, must contain login and hrn.
494 :param lease_start_time: starting time , unix timestamp format
495 :param lease_duration: duration in minutes
497 :type hostname_list: list
498 :type slice_record: dict
499 :type lease_start_time: integer
500 :type lease_duration: integer
501 :returns: experiment_id, can be None if the job request failed.
504 logger.debug("CORTEXLAB_API \r\n \r\n \t AddLeases hostname_list %s \
505 slice_record %s lease_start_time %s lease_duration %s "\
506 %( hostname_list, slice_record , lease_start_time, \
509 username = slice_record['login']
511 experiment_id = self.testbed_shell.LaunchExperimentOnTestbed(
514 lease_start_time, lease_duration,
516 if experiment_id is not None:
518 datetime.fromtimestamp(int(lease_start_time)).\
519 strftime(self.testbed_shell.time_format)
520 end_time = lease_start_time + lease_duration
523 logger.debug("CORTEXLAB_API \t AddLeases TURN ON LOGGING SQL \
524 %s %s %s "%(slice_record['hrn'], experiment_id, end_time))
527 logger.debug("CORTEXLAB_API \r\n \r\n \t AddLeases %s %s %s " \
528 %(type(slice_record['hrn']), type(experiment_id),
531 testbed_xp_row = LeaseTableXP(slice_hrn=slice_record['hrn'],
532 experiment_id=experiment_id,
535 logger.debug("CORTEXLAB_API \t AddLeases testbed_xp_row %s" \
537 self.api.dbsession().add(testbed_xp_row)
538 self.api.dbsession().commit()
540 logger.debug("CORTEXLAB_API \t AddLeases hostname_list \
541 start_time %s " %(start_time))
546 def GetLeases(self, lease_filter_dict=None, login=None):
548 Get the list of leases from testbed with complete information
549 about which slice owns which jobs and nodes.
551 -Fetch all the experiment from the testbed (running, waiting..)
552 complete the reservation information with slice hrn
553 found in lease_table . If not available in the table,
554 assume it is a iotlab slice.
555 -Updates the iotlab table, deleting jobs when necessary.
557 :returns: reservation_list, list of dictionaries with 'lease_id',
558 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
559 'slice_hrn', 'resource_ids', 't_from', 't_until'
564 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
566 reservation_list = []
567 #Find the slice associated with this user iotlab ldap uid
568 logger.debug(" CORTEXLAB \tGetLeases login %s\
569 unfiltered_reservation_list %s "
570 % (login, unfiltered_reservation_list))
571 #Create user dict first to avoid looking several times for
572 #the same user in LDAP SA 27/07/12
573 experiment_id_list = []
574 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
575 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
576 for row in jobs_psql_query])
577 #jobs_psql_dict = jobs_psql_dict)
578 logger.debug("CORTEXLAB \tGetLeases jobs_psql_dict %s"
580 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
582 for resa in unfiltered_reservation_list:
583 logger.debug("CORTEXLAB \tGetLeases USER %s"
585 #Construct list of jobs (runing, waiting..) from scheduler
586 experiment_id_list.append(resa['lease_id'])
587 #If there is information on the job in IOTLAB DB ]
588 #(slice used and job id)
589 if resa['lease_id'] in jobs_psql_dict:
590 job_info = jobs_psql_dict[resa['lease_id']]
591 logger.debug("CORTEXLAB \tGetLeases job_info %s"
593 resa['slice_hrn'] = job_info['slice_hrn']
594 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
596 #otherwise, assume it is a iotlab slice:
598 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
599 + '.' + resa['user'] + "_slice",
601 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
603 resa['component_id_list'] = []
604 #Transform the hostnames into urns (component ids)
605 for node in resa['reserved_nodes']:
607 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
608 resa['component_id_list'].append(iotlab_xrn.urn)
610 if lease_filter_dict:
611 logger.debug("CORTEXLAB \tGetLeases \
612 \r\n leasefilter %s" % ( lease_filter_dict))
614 # filter_dict_functions = {
615 # 'slice_hrn' : IotlabShell.filter_lease_name,
616 # 't_from' : IotlabShell.filter_lease_start_time
618 reservation_list = list(unfiltered_reservation_list)
619 for filter_type in lease_filter_dict:
620 logger.debug("CORTEXLAB \tGetLeases reservation_list %s" \
621 % (reservation_list))
622 reservation_list = self.testbed_shell.filter_lease(
623 reservation_list,filter_type,
624 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_lease_table(experiment_id_list,
645 logger.debug(" CORTEXLAB.PY \tGetLeases reservation_list %s"
646 % (reservation_list))
647 return reservation_list
649 def update_experiments_in_lease_table(self,
650 experiment_list_from_testbed, experiment_list_in_db):
651 """Cleans the lease_table by deleting expired and cancelled jobs.
653 Compares the list of experiment ids given by the testbed with the
654 experiment ids that are already in the database, deletes the
655 experiments that are no longer in the testbed experiment id list.
657 :param experiment_list_from_testbed: list of experiment ids coming
659 :type experiment_list_from_testbed: list
660 :param experiment_list_in_db: list of experiment ids from the sfa
661 additionnal database.
662 :type experiment_list_in_db: list
666 #Turn the list into a set
667 set_experiment_list_in_db = set(experiment_list_in_db)
669 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
670 logger.debug("\r\n \t update_experiments_in_lease_table \
671 experiment_list_in_db %s \r\n \
672 experiment_list_from_testbed %s \
673 kept_experiments %s "
674 % (set_experiment_list_in_db,
675 experiment_list_from_testbed, kept_experiments))
676 deleted_experiments = set_experiment_list_in_db.difference(
678 deleted_experiments = list(deleted_experiments)
679 if len(deleted_experiments) > 0:
680 request = self.api.dbsession().query(LeaseTableXP)
681 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
682 self.api.dbsession().commit()
686 def AddSlice(self, slice_record, user_record):
689 Add slice to the local cortexlab sfa tables if the slice comes
690 from a federated site and is not yet in the cortexlab sfa DB,
691 although the user has already a LDAP login.
692 Called by verify_slice during lease/sliver creation.
694 :param slice_record: record of slice, must contain hrn, gid, slice_id
695 and authority of the slice.
696 :type slice_record: dictionary
697 :param user_record: record of the user
698 :type user_record: RegUser
702 sfa_record = RegSlice(hrn=slice_record['hrn'],
703 gid=slice_record['gid'],
704 pointer=slice_record['slice_id'],
705 authority=slice_record['authority'])
706 logger.debug("CORTEXLAB_API.PY AddSlice sfa_record %s user_record %s"
707 % (sfa_record, user_record))
708 sfa_record.just_created()
709 self.api.dbsession().add(sfa_record)
710 self.api.dbsession().commit()
711 #Update the reg-researcher dependance table
712 sfa_record.reg_researchers = [user_record]
713 self.api.dbsession().commit()
717 def augment_records_with_testbed_info(self, record_list):
720 Adds specific testbed info to the records.
722 :param record_list: list of sfa dictionaries records
723 :type record_list: list
724 :returns: list of records with extended information in each record
728 return self.fill_record_info(record_list)
730 def fill_record_info(self, record_list):
733 For each SFA record, fill in the iotlab specific and SFA specific
734 fields in the record.
736 :param record_list: list of sfa dictionaries records
737 :type record_list: list
738 :returns: list of records with extended information in each record
741 .. warning:: Should not be modifying record_list directly because modi
742 fication are kept outside the method's scope. Howerver, there is no
743 other way to do it given the way it's called in registry manager.
747 logger.debug("CORTEXLABDRIVER \tfill_record_info records %s "
749 if not isinstance(record_list, list):
750 record_list = [record_list]
753 for record in record_list:
755 if str(record['type']) == 'node':
756 # look for node info using GetNodes
757 # the record is about one node only
758 filter_dict = {'hrn': [record['hrn']]}
759 node_info = self.testbed_shell.GetNodes(filter_dict)
760 # the node_info is about one node only, but it is formatted
762 record.update(node_info[0])
763 logger.debug("CORTEXLABDRIVER.PY \t \
764 fill_record_info NODE" % (record))
766 #If the record is a SFA slice record, then add information
767 #about the user of this slice. This kind of
768 #information is in the Iotlab's DB.
769 if str(record['type']) == 'slice':
770 if 'reg_researchers' in record and isinstance(record
773 record['reg_researchers'] = \
774 record['reg_researchers'][0].__dict__
776 {'PI': [record['reg_researchers']['hrn']],
777 'researcher': [record['reg_researchers']['hrn']],
778 'name': record['hrn'],
781 'person_ids': [record['reg_researchers']
783 # For client_helper.py compatibility
785 # For client_helper.py compatibility
787 # For client_helper.py compatibility
790 #Get slice record and job id if any.
791 recslice_list = self.GetSlices(
792 slice_filter=str(record['hrn']),
793 slice_filter_type='slice_hrn')
795 logger.debug("CORTEXLABDRIVER \tfill_record_info \
796 TYPE SLICE RECUSER record['hrn'] %s record['experiment_id']\
797 %s " % (record['hrn'], record['experiment_id']))
798 del record['reg_researchers']
800 for rec in recslice_list:
801 logger.debug("CORTEXLABDRIVER\r\n \t \
802 fill_record_info experiment_id %s "
803 % (rec['experiment_id']))
805 record['node_ids'] = [self.testbed_shell.root_auth +
806 '.' + hostname for hostname
811 logger.debug("CORTEXLABDRIVER.PY \t fill_record_info SLICE \
812 recslice_list %s \r\n \t RECORD %s \r\n \
813 \r\n" % (recslice_list, record))
815 if str(record['type']) == 'user':
816 #The record is a SFA user record.
817 #Get the information about his slice from Iotlab's DB
818 #and add it to the user record.
819 recslice_list = self.GetSlices(
820 slice_filter=record['record_id'],
821 slice_filter_type='record_id_user')
823 logger.debug("CORTEXLABDRIVER.PY \t fill_record_info \
824 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
825 % (recslice_list, record))
826 #Append slice record in records list,
827 #therefore fetches user and slice info again(one more loop)
828 #Will update PIs and researcher for the slice
830 recuser = recslice_list[0]['reg_researchers']
831 logger.debug("CORTEXLABDRIVER.PY \t fill_record_info USER \
832 recuser %s \r\n \r\n" % (recuser))
834 recslice = recslice_list[0]
836 {'PI': [recuser['hrn']],
837 'researcher': [recuser['hrn']],
838 'name': recuser['hrn'],
841 'person_ids': [recuser['record_id']]})
843 for rec in recslice_list:
844 recslice['experiment_id'].append(rec['experiment_id'])
848 recslice.update({'type': 'slice',
849 'hrn': recslice_list[0]['hrn']})
851 #GetPersons takes [] as filters
852 user_cortexlab = self.testbed_shell.GetPersons([record])
854 record.update(user_cortexlab[0])
855 #For client_helper.py compatibility
860 record_list.append(recslice)
862 logger.debug("CORTEXLABDRIVER.PY \t \
863 fill_record_info ADDING SLICE\
864 INFO TO USER records %s" % (record_list))
866 except TypeError, error:
867 logger.log_exc("CORTEXLABDRIVER \t fill_record_info EXCEPTION %s"
872 def sliver_status(self, slice_urn, slice_hrn):
874 Receive a status request for slice named urn/hrn
875 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
876 shall return a structure as described in
877 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
878 NT : not sure if we should implement this or not, but used by sface.
880 :param slice_urn: slice urn
881 :type slice_urn: string
882 :param slice_hrn: slice hrn
883 :type slice_hrn: string
887 #First get the slice with the slice hrn
888 slice_list = self.GetSlices(slice_filter=slice_hrn,
889 slice_filter_type='slice_hrn')
891 if len(slice_list) == 0:
892 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
894 #Used for fetching the user info witch comes along the slice info
895 one_slice = slice_list[0]
897 #Make a list of all the nodes hostnames in use for this slice
898 slice_nodes_list = []
899 slice_nodes_list = one_slice['node_ids']
900 #Get all the corresponding nodes details
901 nodes_all = self.testbed_shell.GetNodes(
902 {'hostname': slice_nodes_list},
903 ['node_id', 'hostname', 'site', 'boot_state'])
904 nodeall_byhostname = dict([(one_node['hostname'], one_node)
905 for one_node in nodes_all])
907 for single_slice in slice_list:
909 top_level_status = 'empty'
912 ['geni_urn', 'geni_error', 'cortexlab_login', 'geni_status',
913 'geni_resources'], None)
915 # ['geni_urn','geni_error', 'pl_login','geni_status',
916 # 'geni_resources'], None)
917 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
918 result['cortexlab_login'] = one_slice['user']
919 logger.debug("Slabdriver - sliver_status Sliver status \
920 urn %s hrn %s single_slice %s \r\n "
921 % (slice_urn, slice_hrn, single_slice))
923 if 'node_ids' not in single_slice:
925 result['geni_status'] = top_level_status
926 result['geni_resources'] = []
929 top_level_status = 'ready'
931 #A job is running on Iotlab for this slice
932 # report about the local nodes that are in the slice only
934 result['geni_urn'] = slice_urn
937 for node_hostname in single_slice['node_ids']:
939 res['cortexlab_hostname'] = node_hostname
940 res['cortexlab_boot_state'] = \
941 nodeall_byhostname[node_hostname]['boot_state']
944 slice_urn, type='slice',
945 id=nodeall_byhostname[node_hostname]['node_id']).urn
947 res['geni_urn'] = sliver_id
948 #node_name = node['hostname']
949 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
951 res['geni_status'] = 'ready'
953 res['geni_status'] = 'failed'
954 top_level_status = 'failed'
956 res['geni_error'] = ''
958 resources.append(res)
960 result['geni_status'] = top_level_status
961 result['geni_resources'] = resources
962 logger.debug("CORTEXLABDRIVER \tsliver_statusresources %s res %s "
966 def get_user_record(self, hrn):
969 Returns the user record based on the hrn from the SFA DB .
971 :param hrn: user's hrn
973 :returns: user record from SFA database
977 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
979 def testbed_name(self):
982 Returns testbed's name.
983 :returns: testbed authority name.
990 def _get_requested_leases_list(self, rspec):
992 Process leases in rspec depending on the rspec version (format)
993 type. Find the lease requests in the rspec and creates
994 a lease request list with the mandatory information ( nodes,
995 start time and duration) of the valid leases (duration above or
996 equal to the iotlab experiment minimum duration).
998 :param rspec: rspec request received.
1000 :returns: list of lease requests found in the rspec
1003 requested_lease_list = []
1004 for lease in rspec.version.get_leases():
1005 single_requested_lease = {}
1006 logger.debug("CORTEXLABDRIVER.PY \t \
1007 _get_requested_leases_list lease %s " % (lease))
1009 if not lease.get('lease_id'):
1010 if get_authority(lease['component_id']) == \
1011 self.testbed_shell.root_auth:
1012 single_requested_lease['hostname'] = \
1014 lease.get('component_id').strip())
1015 single_requested_lease['start_time'] = \
1016 lease.get('start_time')
1017 single_requested_lease['duration'] = lease.get('duration')
1018 #Check the experiment's duration is valid before adding
1019 #the lease to the requested leases list
1020 duration_in_seconds = \
1021 int(single_requested_lease['duration'])
1022 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1023 requested_lease_list.append(single_requested_lease)
1025 return requested_lease_list
1028 def _group_leases_by_start_time(requested_lease_list):
1030 Create dict of leases by start_time, regrouping nodes reserved
1031 at the same time, for the same amount of time so as to
1032 define one job on OAR.
1034 :param requested_lease_list: list of leases
1035 :type requested_lease_list: list
1036 :returns: Dictionary with key = start time, value = list of leases
1037 with the same start time.
1042 requested_xp_dict = {}
1043 for lease in requested_lease_list:
1045 #In case it is an asap experiment start_time is empty
1046 if lease['start_time'] == '':
1047 lease['start_time'] = '0'
1049 if lease['start_time'] not in requested_xp_dict:
1050 if isinstance(lease['hostname'], str):
1051 lease['hostname'] = [lease['hostname']]
1053 requested_xp_dict[lease['start_time']] = lease
1056 job_lease = requested_xp_dict[lease['start_time']]
1057 if lease['duration'] == job_lease['duration']:
1058 job_lease['hostname'].append(lease['hostname'])
1060 return requested_xp_dict
1063 def _process_requested_xp_dict(self, rspec):
1065 Turns the requested leases and information into a dictionary
1066 of requested jobs, grouped by starting time.
1068 :param rspec: RSpec received
1073 requested_lease_list = self._get_requested_leases_list(rspec)
1074 logger.debug("CORTEXLABDRIVER _process_requested_xp_dict \
1075 requested_lease_list %s" % (requested_lease_list))
1076 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1077 logger.debug("CORTEXLABDRIVER _process_requested_xp_dict xp_dict\
1084 def delete(self, slice_urns, options=None):
1086 Deletes the lease associated with the slice hrn and the credentials
1087 if the slice belongs to iotlab. Answer to DeleteSliver.
1089 :param slice_urn: urn of the slice
1090 :type slice_urn: string
1093 :returns: 1 if the slice to delete was not found on iotlab,
1094 True if the deletion was successful, False otherwise otherwise.
1096 .. note:: Should really be named delete_leases because iotlab does
1097 not have any slivers, but only deals with leases. However,
1098 SFA api only have delete_sliver define so far. SA 13/05/2013
1099 .. note:: creds are unused, and are not used either in the dummy driver
1102 if options is None: options={}
1103 # collect sliver ids so we can update sliver allocation states after
1104 # we remove the slivers.
1105 aggregate = CortexlabAggregate(self)
1106 slivers = aggregate.get_slivers(slice_urns)
1108 # slice_id = slivers[0]['slice_id']
1111 sliver_jobs_dict = {}
1112 for sliver in slivers:
1113 node_ids.append(sliver['node_id'])
1114 sliver_ids.append(sliver['sliver_id'])
1115 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1116 sliver_jobs_dict[job_id] = sliver['sliver_id']
1117 logger.debug("CORTEXLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1118 % (slivers, slice_urns))
1119 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1121 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1122 slice_filter_type='slice_hrn')
1124 if not sfa_slice_list:
1127 #Delete all leases in the slice
1128 for sfa_slice in sfa_slice_list:
1129 logger.debug("CORTEXLABDRIVER.PY delete_sliver slice %s" \
1131 slices = CortexlabSlices(self)
1132 # determine if this is a peer slice
1134 peer = slices.get_peer(slice_hrn)
1136 logger.debug("CORTEXLABDRIVER.PY delete_sliver peer %s \
1137 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1138 testbed_bool_ans = self.testbed_shell.DeleteSliceFromNodes(sfa_slice)
1139 for job_id in testbed_bool_ans:
1140 # if the job has not been successfully deleted
1141 # don't delete the associated sliver
1142 # remove it from the sliver list
1143 if testbed_bool_ans[job_id] is False:
1144 sliver = sliver_jobs_dict[job_id]
1145 sliver_ids.remove(sliver)
1148 dbsession = self.api.dbsession()
1149 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1151 logger.log_exc("CORTEXLABDRIVER.PY delete error ")
1153 # prepare return struct
1155 for sliver in slivers:
1156 geni_slivers.append(
1157 {'geni_sliver_urn': sliver['sliver_id'],
1158 'geni_allocation_status': 'geni_unallocated',
1159 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1162 def list_slices(self, creds, options):
1163 """Answer to ListSlices.
1165 List slices belonging to iotlab, returns slice urns list.
1166 No caching used. Options unused but are defined in the SFA method
1169 :returns: slice urns list
1172 .. note:: creds are unused- SA 12/12/13
1174 # look in cache first
1176 #slices = self.cache.get('slices')
1178 #logger.debug("PlDriver.list_slices returns from cache")
1183 slices = self.GetSlices()
1184 logger.debug("CORTEXLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1186 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1188 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1189 for slice_hrn in slice_hrns]
1193 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1194 #self.cache.add('slices', slice_urns)
1199 def register(self, sfa_record, hrn, pub_key):
1201 Adding new user, slice, node or site should not be handled
1204 ..warnings:: should not be used. Different components are in charge of
1205 doing this task. Adding nodes = OAR
1206 Adding users = LDAP Iotlab
1207 Adding slice = Import from LDAP users
1210 :param sfa_record: record provided by the client of the
1212 :type sfa_record: dict
1213 :param pub_key: public key of the user
1214 :type pub_key: string
1216 .. note:: DOES NOTHING. Returns -1.
1221 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1223 No site or node record update allowed in Iotlab. The only modifications
1224 authorized here are key deletion/addition on an existing user and
1225 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1226 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1227 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1228 user's ssh key should nmodify the slice's GID after an import procedure.
1230 :param old_sfa_record: what is in the db for this hrn
1231 :param new_sfa_record: what was passed to the update call
1232 :param new_key: the new user's public key
1233 :param hrn: the user's sfa hrn
1234 :type old_sfa_record: dict
1235 :type new_sfa_record: dict
1236 :type new_key: string
1240 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1241 since users, keys and slice are managed by the LDAP.
1244 # pointer = old_sfa_record['pointer']
1245 # old_sfa_record_type = old_sfa_record['type']
1247 # # new_key implemented for users only
1248 # if new_key and old_sfa_record_type not in ['user']:
1249 # raise UnknownSfaType(old_sfa_record_type)
1251 # if old_sfa_record_type == "user":
1252 # update_fields = {}
1253 # all_fields = new_sfa_record
1254 # for key in all_fields.keys():
1255 # if key in ['key', 'password']:
1256 # update_fields[key] = all_fields[key]
1259 # # must check this key against the previous one if it exists
1260 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1261 # person = persons[0]
1262 # keys = [person['pkey']]
1263 # #Get all the person's keys
1264 # keys_dict = self.GetKeys(keys)
1266 # # Delete all stale keys, meaning the user has only one key
1268 # #TODO: do we really want to delete all the other keys?
1269 # #Is this a problem with the GID generation to have multiple
1270 # #keys? SA 30/05/13
1271 # key_exists = False
1272 # if key in keys_dict:
1275 # #remove all the other keys
1276 # for key in keys_dict:
1277 # self.testbed_shell.DeleteKey(person, key)
1278 # self.testbed_shell.AddPersonKey(
1279 # person, {'sshPublicKey': person['pkey']},
1280 # {'sshPublicKey': new_key})
1281 logger.warning ("UNDEFINED - Update should be done by the \
1286 def remove(self, sfa_record):
1289 Removes users only. Mark the user as disabled in LDAP. The user and his
1290 slice are then deleted from the db by running an import on the registry.
1292 :param sfa_record: record is the existing sfa record in the db
1293 :type sfa_record: dict
1295 ..warning::As fas as the slice is concerned, here only the leases are
1296 removed from the slice. The slice is record itself is not removed
1301 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1303 TODO: return boolean for the slice part
1305 sfa_record_type = sfa_record['type']
1306 hrn = sfa_record['hrn']
1307 if sfa_record_type == 'user':
1309 #get user from iotlab ldap
1310 person = self.testbed_shell.GetPersons(sfa_record)
1311 #No registering at a given site in Iotlab.
1312 #Once registered to the LDAP, all iotlab sites are
1315 #Mark account as disabled in ldap
1316 return self.testbed_shell.DeletePerson(sfa_record)
1318 elif sfa_record_type == 'slice':
1319 if self.GetSlices(slice_filter=hrn,
1320 slice_filter_type='slice_hrn'):
1321 ret = self.testbed_shell.DeleteSlice(sfa_record)
1324 def check_sliver_credentials(self, creds, urns):
1325 """Check that the sliver urns belongs to the slice specified in the
1328 :param urns: list of sliver urns.
1330 :param creds: slice credentials.
1331 :type creds: Credential object.
1335 # build list of cred object hrns
1336 slice_cred_names = []
1338 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1339 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1340 slice_cred_names.append(slicename)
1342 # look up slice name of slivers listed in urns arg
1346 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1348 slice_ids.append(int(sliver_id_parts[0]))
1353 raise Forbidden("sliver urn not provided")
1355 slices = self.GetSlices(slice_ids)
1356 sliver_names = [single_slice['name'] for single_slice in slices]
1358 # make sure we have a credential for every specified sliver
1359 for sliver_name in sliver_names:
1360 if sliver_name not in slice_cred_names:
1361 msg = "Valid credential not found for target: %s" % sliver_name
1362 raise Forbidden(msg)
1364 ########################################
1365 ########## aggregate oriented
1366 ########################################
1368 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1369 def aggregate_version(self):
1372 Returns the testbed's supported rspec advertisement and request
1374 :returns: rspec versions supported ad a dictionary.
1378 version_manager = VersionManager()
1379 ad_rspec_versions = []
1380 request_rspec_versions = []
1381 for rspec_version in version_manager.versions:
1382 if rspec_version.content_type in ['*', 'ad']:
1383 ad_rspec_versions.append(rspec_version.to_dict())
1384 if rspec_version.content_type in ['*', 'request']:
1385 request_rspec_versions.append(rspec_version.to_dict())
1387 'testbed': self.testbed_name(),
1388 'geni_request_rspec_versions': request_rspec_versions,
1389 'geni_ad_rspec_versions': ad_rspec_versions}
1393 # first 2 args are None in case of resource discovery
1394 def list_resources (self, version=None, options=None):
1395 if options is None: options={}
1396 aggregate = CortexlabAggregate(self)
1397 rspec = aggregate.list_resources(version=version, options=options)
1401 def describe(self, urns, version, options=None):
1402 if options is None: options={}
1403 aggregate = CortexlabAggregate(self)
1404 return aggregate.describe(urns, version=version, options=options)
1406 def status (self, urns, options=None):
1407 if options is None: options={}
1408 aggregate = CortexlabAggregate(self)
1409 desc = aggregate.describe(urns, version='GENI 3')
1410 status = {'geni_urn': desc['geni_urn'],
1411 'geni_slivers': desc['geni_slivers']}
1415 def allocate (self, urn, rspec_string, expiration, options=None):
1416 if options is None: options={}
1418 aggregate = CortexlabAggregate(self)
1420 slices = CortexlabSlices(self)
1421 peer = slices.get_peer(xrn.get_hrn())
1422 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1425 users = options.get('geni_users', [])
1427 sfa_users = options.get('sfa_users', [])
1429 slice_record = sfa_users[0].get('slice_record', [])
1432 rspec = RSpec(rspec_string)
1433 # requested_attributes = rspec.version.get_slice_attributes()
1435 # ensure site record exists
1437 # ensure slice record exists
1439 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1440 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1441 \r\n \r\n current_slice %s" % (current_slice))
1442 # ensure person records exists
1444 # oui c'est degueulasse, le slice_record se retrouve modifie
1445 # dans la methode avec les infos du user, els infos sont propagees
1446 # dans verify_slice_leases
1447 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1449 # ensure slice attributes exists
1450 # slices.verify_slice_attributes(slice, requested_attributes,
1453 # add/remove slice from nodes
1454 requested_xp_dict = self._process_requested_xp_dict(rspec)
1456 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1457 % (requested_xp_dict))
1458 request_nodes = rspec.version.get_nodes_with_slivers()
1460 for start_time in requested_xp_dict:
1461 lease = requested_xp_dict[start_time]
1462 for hostname in lease['hostname']:
1463 nodes_list.append(hostname)
1465 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1466 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1467 % (nodes_list, slice_record))
1470 rspec_requested_leases = rspec.version.get_leases()
1471 leases = slices.verify_slice_leases(slice_record,
1472 requested_xp_dict, peer)
1473 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1474 rspec_requested_leases %s" % (leases,
1475 rspec_requested_leases))
1476 # update sliver allocations
1477 for hostname in nodes_list:
1478 client_id = hostname
1479 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1480 component_id = node_urn
1481 slice_urn = current_slice['reg-urn']
1482 for lease in leases:
1483 if hostname in lease['reserved_nodes']:
1484 index = lease['reserved_nodes'].index(hostname)
1485 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1486 lease['resource_ids'][index] )
1487 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1488 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1489 component_id=component_id,
1490 slice_urn = slice_urn,
1491 allocation_state='geni_allocated')
1492 record.sync(self.api.dbsession())
1494 return aggregate.describe([xrn.get_urn()], version=rspec.version)
1496 def provision(self, urns, options=None):
1497 if options is None: options={}
1499 slices = CortexlabSlices(self)
1500 aggregate = CortexlabAggregate(self)
1501 slivers = aggregate.get_slivers(urns)
1502 current_slice = slivers[0]
1503 peer = slices.get_peer(current_slice['hrn'])
1504 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1505 users = options.get('geni_users', [])
1506 # persons = slices.verify_persons(current_slice['hrn'],
1507 # current_slice, users, peer, sfa_peer, options=options)
1508 # slices.handle_peer(None, None, persons, peer)
1509 # update sliver allocation states and set them to geni_provisioned
1510 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1511 dbsession = self.api.dbsession()
1512 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1514 version_manager = VersionManager()
1515 rspec_version = version_manager.get_version(options[
1516 'geni_rspec_version'])
1517 return self.describe(urns, rspec_version, options=options)