2 Implements what a driver should provide for SFA to work.
4 from datetime import datetime
5 from sfa.util.faults import SliverDoesNotExist, Forbidden
6 from sfa.util.sfalogging import logger
8 from sfa.storage.model import RegRecord, RegUser, RegSlice, RegKey
9 from sfa.util.sfatime import utcparse, datetime_to_string
10 from sfa.trust.certificate import Keypair, convert_public_key
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.trust.gid import create_uuid
15 from sfa.managers.driver import Driver
16 from sfa.rspecs.version_manager import VersionManager
17 from sfa.rspecs.rspec import RSpec
19 from sfa.iotlab.iotlabxrn import IotlabXrn, xrn_object
20 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
21 from sfa.iotlab.iotlabaggregate import IotlabAggregate
22 from sfa.iotlab.iotlabxrn import xrn_to_hostname
23 from sfa.iotlab.iotlabslices import IotlabSlices
25 from sfa.trust.credential import Credential
26 from sfa.storage.model import SliverAllocation
28 from sfa.iotlab.iotlabshell import IotlabShell
29 from sqlalchemy.orm import joinedload
30 from sfa.iotlab.iotlabpostgres import LeaseTableXP
32 class IotlabDriver(Driver):
33 """ Iotlab Driver class inherited from Driver generic class.
35 Contains methods compliant with the SFA standard and the testbed
36 infrastructure (calls to LDAP and OAR).
38 .. seealso::: Driver class
41 def __init__(self, api):
44 Sets the iotlab SFA config parameters,
45 instanciates the testbed api and the iotlab database.
47 :param config: iotlab SFA configuration object
48 :type config: Config object
51 Driver.__init__(self, api)
54 self.testbed_shell = IotlabShell(config)
57 def GetPeers(self, peer_filter=None ):
58 """ Gathers registered authorities in SFA DB and looks for specific peer
59 if peer_filter is specified.
60 :param peer_filter: name of the site authority looked for.
61 :type peer_filter: string
62 :returns: list of records.
67 existing_hrns_by_types = {}
68 logger.debug("IOTLAB_API \tGetPeers peer_filter %s " % (peer_filter))
69 query = self.api.dbsession().query(RegRecord)
70 all_records = query.filter(RegRecord.type.like('%authority%')).all()
72 for record in all_records:
73 existing_records[(record.hrn, record.type)] = record
74 if record.type not in existing_hrns_by_types:
75 existing_hrns_by_types[record.type] = [record.hrn]
77 existing_hrns_by_types[record.type].append(record.hrn)
79 logger.debug("IOTLAB_API \tGetPeer\texisting_hrns_by_types %s "
80 % (existing_hrns_by_types))
85 records_list.append(existing_records[(peer_filter,
88 for hrn in existing_hrns_by_types['authority']:
89 records_list.append(existing_records[(hrn, 'authority')])
91 logger.debug("IOTLAB_API \tGetPeer \trecords_list %s "
97 return_records = records_list
98 logger.debug("IOTLAB_API \tGetPeer return_records %s "
100 return return_records
102 def GetKeys(self, key_filter=None):
103 """Returns a dict of dict based on the key string. Each dict entry
104 contains the key id, the ssh key, the user's email and the
106 If key_filter is specified and is an array of key identifiers,
107 only keys matching the filter will be returned.
109 Admin may query all keys. Non-admins may only query their own keys.
112 :returns: dict with ssh key as key and dicts as value.
115 query = self.api.dbsession().query(RegKey)
116 if key_filter is None:
117 keys = query.options(joinedload('reg_user')).all()
119 constraint = RegKey.key.in_(key_filter)
120 keys = query.options(joinedload('reg_user')).filter(constraint).all()
124 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
125 'email': key.reg_user.email,
126 'hrn': key.reg_user.hrn}
128 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
129 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
130 #for user in ldap_rslt)
132 logger.debug("IOTLAB_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("IOTLAB_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 iotlab nodes and that he has not registered with iotlab
165 yet (that is he does not have a LDAP entry yet).
166 Uses parts of the routines in IotlabImport when importing user from
167 LDAP. Called by AddPerson, right after LdapAddUser.
168 :param user_dict: Must contain email, hrn and pkey to get a GID
169 and be added to the SFA db.
170 :type user_dict: dict
173 query = self.api.dbsession().query(RegUser)
174 check_if_exists = query.filter_by(email = user_dict['email']).first()
176 if not check_if_exists:
177 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
179 hrn = user_dict['hrn']
180 person_urn = hrn_to_urn(hrn, 'user')
181 pubkey = user_dict['pkey']
183 pkey = convert_public_key(pubkey)
185 #key not good. create another pkey
186 logger.warn('__add_person_to_db: unable to convert public \
188 pkey = Keypair(create=True)
191 if pubkey is not None and pkey is not None :
192 hierarchy = Hierarchy()
193 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
195 if user_dict['email']:
196 logger.debug("__add_person_to_db \r\n \r\n \
197 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
198 %(user_dict['email']))
199 person_gid.set_email(user_dict['email'])
201 user_record = RegUser(hrn=hrn , pointer= '-1', \
202 authority=get_authority(hrn), \
203 email=user_dict['email'], gid = person_gid)
204 user_record.reg_keys = [RegKey(user_dict['pkey'])]
205 user_record.just_created()
206 self.api.dbsession().add (user_record)
207 self.api.dbsession().commit()
212 def _sql_get_slice_info(self, slice_filter):
214 Get the slice record based on the slice hrn. Fetch the record of the
215 user associated with the slice by using joinedload based on the
216 reg_researcher relationship.
218 :param slice_filter: the slice hrn we are looking for
219 :type slice_filter: string
220 :returns: the slice record enhanced with the user's information if the
221 slice was found, None it wasn't.
223 :rtype: dict or None.
225 #DO NOT USE RegSlice - reg_researchers to get the hrn
226 #of the user otherwise will mess up the RegRecord in
227 #Resolve, don't know why - SA 08/08/2012
229 #Only one entry for one user = one slice in testbed_xp table
230 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
232 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
233 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
236 #raw_slicerec.reg_researchers
237 raw_slicerec = raw_slicerec.__dict__
238 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
239 raw_slicerec %s" % (slice_filter, raw_slicerec))
240 slicerec = raw_slicerec
241 #only one researcher per slice so take the first one
242 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
243 #del slicerec['reg_researchers']['_sa_instance_state']
249 def _sql_get_slice_info_from_user(self, slice_filter):
251 Get the slice record based on the user recordid by using a joinedload
252 on the relationship reg_slices_as_researcher. Format the sql record
253 into a dict with the mandatory fields for user and slice.
254 :returns: dict with slice record and user record if the record was found
255 based on the user's id, None if not..
256 :rtype:dict or None..
258 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
259 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
260 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
261 #Put it in correct order
262 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
263 'classtype', 'authority', 'gid', 'record_id',
264 'date_created', 'type', 'email', 'pointer']
265 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
266 'classtype', 'authority', 'gid', 'record_id',
267 'date_created', 'type', 'pointer']
269 #raw_slicerec.reg_slices_as_researcher
270 raw_slicerec = raw_slicerec.__dict__
273 dict([(k, raw_slicerec[
274 'reg_slices_as_researcher'][0].__dict__[k])
275 for k in slice_needed_fields])
276 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
277 for k in user_needed_fields])
278 #TODO Handle multiple slices for one user SA 10/12/12
279 #for now only take the first slice record associated to the rec user
280 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
281 #del raw_slicerec['reg_slices_as_researcher']
282 #slicerec['reg_researchers'] = raw_slicerec
283 ##del slicerec['_sa_instance_state']
292 def _get_slice_records(self, slice_filter=None,
293 slice_filter_type=None):
295 Get the slice record depending on the slice filter and its type.
296 :param slice_filter: Can be either the slice hrn or the user's record
298 :type slice_filter: string
299 :param slice_filter_type: describes the slice filter type used, can be
300 slice_hrn or record_id_user
302 :returns: the slice record
304 .. seealso::_sql_get_slice_info_from_user
305 .. seealso:: _sql_get_slice_info
308 #Get list of slices based on the slice hrn
309 if slice_filter_type == 'slice_hrn':
311 #if get_authority(slice_filter) == self.root_auth:
312 #login = slice_filter.split(".")[1].split("_")[0]
314 slicerec = self._sql_get_slice_info(slice_filter)
320 #Get slice based on user id
321 if slice_filter_type == 'record_id_user':
323 slicerec = self._sql_get_slice_info_from_user(slice_filter)
326 fixed_slicerec_dict = slicerec
327 #At this point if there is no login it means
328 #record_id_user filter has been used for filtering
330 ##If theslice record is from iotlab
331 #if fixed_slicerec_dict['peer_authority'] is None:
332 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
333 #return login, fixed_slicerec_dict
334 return fixed_slicerec_dict
340 def GetSlices(self, slice_filter=None, slice_filter_type=None,
342 """Get the slice records from the iotlab db and add lease information
345 :param slice_filter: can be the slice hrn or slice record id in the db
346 depending on the slice_filter_type.
347 :param slice_filter_type: defines the type of the filtering used, Can be
348 either 'slice_hrn' or "record_id'.
349 :type slice_filter: string
350 :type slice_filter_type: string
351 :returns: a slice dict if slice_filter and slice_filter_type
352 are specified and a matching entry is found in the db. The result
353 is put into a list.Or a list of slice dictionnaries if no filters
360 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
361 return_slicerec_dictlist = []
363 #First try to get information on the slice based on the filter provided
364 if slice_filter_type in authorized_filter_types_list:
365 fixed_slicerec_dict = self._get_slice_records(slice_filter,
367 # if the slice was not found in the sfa db
368 if fixed_slicerec_dict is None:
369 return return_slicerec_dictlist
371 slice_hrn = fixed_slicerec_dict['hrn']
373 logger.debug(" IOTLAB_API \tGetSlices login %s \
374 slice record %s slice_filter %s \
375 slice_filter_type %s " % (login,
376 fixed_slicerec_dict, slice_filter,
380 #Now we have the slice record fixed_slicerec_dict, get the
381 #jobs associated to this slice
384 leases_list = self.GetLeases(login=login)
385 #If no job is running or no job scheduled
386 #return only the slice record
387 if leases_list == [] and fixed_slicerec_dict:
388 return_slicerec_dictlist.append(fixed_slicerec_dict)
390 # if the jobs running don't belong to the user/slice we are looking
392 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
393 if slice_hrn not in leases_hrn:
394 return_slicerec_dictlist.append(fixed_slicerec_dict)
395 #If several jobs for one slice , put the slice record into
396 # each lease information dict
397 for lease in leases_list:
399 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
400 \t lease['slice_hrn'] %s"
401 % (slice_filter, lease['slice_hrn']))
402 if lease['slice_hrn'] == slice_hrn:
403 slicerec_dict['oar_job_id'] = lease['lease_id']
404 #Update lease dict with the slice record
405 if fixed_slicerec_dict:
406 fixed_slicerec_dict['oar_job_id'] = []
407 fixed_slicerec_dict['oar_job_id'].append(
408 slicerec_dict['oar_job_id'])
409 slicerec_dict.update(fixed_slicerec_dict)
410 #slicerec_dict.update({'hrn':\
411 #str(fixed_slicerec_dict['slice_hrn'])})
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']})
422 return_slicerec_dictlist.append(slicerec_dict)
423 logger.debug("IOTLAB_API.PY \tGetSlices \
424 OHOHOHOH %s" %(return_slicerec_dictlist))
426 logger.debug("IOTLAB_API.PY \tGetSlices \
427 slicerec_dict %s return_slicerec_dictlist %s \
428 lease['reserved_nodes'] \
429 %s" % (slicerec_dict, return_slicerec_dictlist,
430 lease['reserved_nodes']))
432 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
433 return_slicerec_dictlist %s"
434 % (return_slicerec_dictlist))
436 return return_slicerec_dictlist
440 #Get all slices from the iotlab sfa database ,
441 #put them in dict format
442 #query_slice_list = dbsession.query(RegRecord).all()
444 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
446 for record in query_slice_list:
447 tmp = record.__dict__
448 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
449 #del tmp['reg_researchers']['_sa_instance_state']
450 return_slicerec_dictlist.append(tmp)
451 #return_slicerec_dictlist.append(record.__dict__)
453 #Get all the jobs reserved nodes
454 leases_list = self.testbed_shell.GetReservedNodes()
456 for fixed_slicerec_dict in return_slicerec_dictlist:
458 #Check if the slice belongs to a iotlab user
459 if fixed_slicerec_dict['peer_authority'] is None:
460 owner = fixed_slicerec_dict['hrn'].split(
461 ".")[1].split("_")[0]
464 for lease in leases_list:
465 if owner == lease['user']:
466 slicerec_dict['oar_job_id'] = lease['lease_id']
468 #for reserved_node in lease['reserved_nodes']:
469 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
471 slicerec_dict.update(fixed_slicerec_dict)
472 slicerec_dict.update({'node_ids':
473 lease['reserved_nodes']})
474 slicerec_dict.update({'list_node_ids':
476 lease['reserved_nodes']}})
478 #slicerec_dict.update({'hrn':\
479 #str(fixed_slicerec_dict['slice_hrn'])})
480 #return_slicerec_dictlist.append(slicerec_dict)
481 fixed_slicerec_dict.update(slicerec_dict)
483 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
484 return_slicerec_dictlist %s \t slice_filter %s " \
485 %(return_slicerec_dictlist, slice_filter))
487 return return_slicerec_dictlist
489 def AddLeases(self, hostname_list, slice_record,
490 lease_start_time, lease_duration):
492 """Creates a job in OAR corresponding to the information provided
493 as parameters. Adds the job id and the slice hrn in the iotlab
494 database so that we are able to know which slice has which nodes.
496 :param hostname_list: list of nodes' OAR hostnames.
497 :param slice_record: sfa slice record, must contain login and hrn.
498 :param lease_start_time: starting time , unix timestamp format
499 :param lease_duration: duration in minutes
501 :type hostname_list: list
502 :type slice_record: dict
503 :type lease_start_time: integer
504 :type lease_duration: integer
505 :returns: job_id, can be None if the job request failed.
508 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
509 slice_record %s lease_start_time %s lease_duration %s "\
510 %( hostname_list, slice_record , lease_start_time, \
513 #tmp = slice_record['reg-researchers'][0].split(".")
514 username = slice_record['login']
515 #username = tmp[(len(tmp)-1)]
516 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
517 slice_record['hrn'], \
518 lease_start_time, lease_duration, \
520 if job_id is not None:
522 datetime.fromtimestamp(int(lease_start_time)).\
523 strftime(self.testbed_shell.time_format)
524 end_time = lease_start_time + lease_duration
527 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
528 %s %s %s "%(slice_record['hrn'], job_id, end_time))
531 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
532 %(type(slice_record['hrn']), type(job_id), type(end_time)))
534 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
535 experiment_id=job_id,
538 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
540 self.api.dbsession().add(iotlab_ex_row)
541 self.api.dbsession().commit()
543 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
548 def GetLeases(self, lease_filter_dict=None, login=None):
551 Get the list of leases from OAR with complete information
552 about which slice owns which jobs and nodes.
554 -Fetch all the jobs from OAR (running, waiting..)
555 complete the reservation information with slice hrn
556 found in testbed_xp table. If not available in the table,
557 assume it is a iotlab slice.
558 -Updates the iotlab table, deleting jobs when necessary.
560 :returns: reservation_list, list of dictionaries with 'lease_id',
561 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
562 'slice_hrn', 'resource_ids', 't_from', 't_until'
567 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
569 reservation_list = []
570 #Find the slice associated with this user iotlab ldap uid
571 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
572 unfiltered_reservation_list %s "
573 % (login, unfiltered_reservation_list))
574 #Create user dict first to avoid looking several times for
575 #the same user in LDAP SA 27/07/12
577 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
578 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
579 for row in jobs_psql_query])
580 #jobs_psql_dict = jobs_psql_dict)
581 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
583 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
585 for resa in unfiltered_reservation_list:
586 logger.debug("IOTLAB_API \tGetLeases USER %s"
588 #Construct list of jobs (runing, waiting..) in oar
589 job_oar_list.append(resa['lease_id'])
590 #If there is information on the job in IOTLAB DB ]
591 #(slice used and job id)
592 if resa['lease_id'] in jobs_psql_dict:
593 job_info = jobs_psql_dict[resa['lease_id']]
594 logger.debug("IOTLAB_API \tGetLeases job_info %s"
596 resa['slice_hrn'] = job_info['slice_hrn']
597 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
599 #otherwise, assume it is a iotlab slice:
601 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
602 + '.' + resa['user'] + "_slice",
604 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
606 resa['component_id_list'] = []
607 #Transform the hostnames into urns (component ids)
608 for node in resa['reserved_nodes']:
610 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
611 resa['component_id_list'].append(iotlab_xrn.urn)
613 if lease_filter_dict:
614 logger.debug("IOTLAB_API \tGetLeases \
615 \r\n leasefilter %s" % ( lease_filter_dict))
617 # filter_dict_functions = {
618 # 'slice_hrn' : IotlabShell.filter_lease_name,
619 # 't_from' : IotlabShell.filter_lease_start_time
621 reservation_list = list(unfiltered_reservation_list)
622 for filter_type in lease_filter_dict:
623 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
624 % (reservation_list))
625 reservation_list = self.testbed_shell.filter_lease(
626 reservation_list,filter_type,
627 lease_filter_dict[filter_type] )
629 # Filter the reservation list with a maximum timespan so that the
630 # leases and jobs running after this timestamp do not appear
631 # in the result leases.
632 # if 'start_time' in :
633 # if resa['start_time'] < lease_filter_dict['start_time']:
634 # reservation_list.append(resa)
637 # if 'name' in lease_filter_dict and \
638 # lease_filter_dict['name'] == resa['slice_hrn']:
639 # reservation_list.append(resa)
642 if lease_filter_dict is None:
643 reservation_list = unfiltered_reservation_list
645 self.update_experiments_in_additional_sfa_db(job_oar_list, jobs_psql_id_list)
647 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
648 % (reservation_list))
649 return reservation_list
653 def update_experiments_in_additional_sfa_db(self,
654 experiment_list_from_testbed, experiment_list_in_db):
655 """ Cleans the iotlab db by deleting expired and cancelled jobs.
657 Compares the list of experiment ids given by the testbed with the
658 experiment ids that are already in the database, deletes the
659 experiments that are no longer in the testbed experiment id list.
661 :param experiment_list_from_testbed: list of experiment ids coming
663 :type experiment_list_from_testbed: list
664 :param experiment_list_in_db: list of experiment ids from the sfa
665 additionnal database.
666 :type experiment_list_in_db: list
670 #Turn the list into a set
671 set_experiment_list_in_db = set(experiment_list_in_db)
673 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
674 logger.debug("\r\n \t update_experiments_in_additional_sfa_db \
675 experiment_list_in_db %s \r\n \
676 experiment_list_from_testbed %s \
677 kept_experiments %s "
678 % (set_experiment_list_in_db,
679 experiment_list_from_testbed, kept_experiments))
680 deleted_experiments = set_experiment_list_in_db.difference(
682 deleted_experiments = list(deleted_experiments)
683 if len(deleted_experiments) > 0:
684 request = self.api.dbsession().query(LeaseTableXP)
685 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
686 self.api.dbsession().commit()
688 def AddSlice(self, slice_record, user_record):
691 Add slice to the local iotlab sfa tables if the slice comes
692 from a federated site and is not yet in the iotlab sfa DB,
693 although the user has already a LDAP login.
694 Called by verify_slice during lease/sliver creation.
696 :param slice_record: record of slice, must contain hrn, gid, slice_id
697 and authority of the slice.
698 :type slice_record: dictionary
699 :param user_record: record of the user
700 :type user_record: RegUser
704 sfa_record = RegSlice(hrn=slice_record['hrn'],
705 gid=slice_record['gid'],
706 pointer=slice_record['slice_id'],
707 authority=slice_record['authority'])
708 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
709 % (sfa_record, user_record))
710 sfa_record.just_created()
711 self.api.dbsession().add(sfa_record)
712 self.api.dbsession().commit()
713 #Update the reg-researcher dependance table
714 sfa_record.reg_researchers = [user_record]
715 self.api.dbsession().commit()
719 def augment_records_with_testbed_info(self, record_list):
722 Adds specific testbed info to the records.
724 :param record_list: list of sfa dictionaries records
725 :type record_list: list
726 :returns: list of records with extended information in each record
730 return self.fill_record_info(record_list)
732 def fill_record_info(self, record_list):
735 For each SFA record, fill in the iotlab specific and SFA specific
736 fields in the record.
738 :param record_list: list of sfa dictionaries records
739 :type record_list: list
740 :returns: list of records with extended information in each record
743 .. warning:: Should not be modifying record_list directly because modi
744 fication are kept outside the method's scope. Howerver, there is no
745 other way to do it given the way it's called in registry manager.
749 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
751 if not isinstance(record_list, list):
752 record_list = [record_list]
755 for record in record_list:
757 if str(record['type']) == 'node':
758 # look for node info using GetNodes
759 # the record is about one node only
760 filter_dict = {'hrn': [record['hrn']]}
761 node_info = self.testbed_shell.GetNodes(filter_dict)
762 # the node_info is about one node only, but it is formatted
764 record.update(node_info[0])
765 logger.debug("IOTLABDRIVER.PY \t \
766 fill_record_info NODE" % (record))
768 #If the record is a SFA slice record, then add information
769 #about the user of this slice. This kind of
770 #information is in the Iotlab's DB.
771 if str(record['type']) == 'slice':
772 if 'reg_researchers' in record and isinstance(record
775 record['reg_researchers'] = \
776 record['reg_researchers'][0].__dict__
778 {'PI': [record['reg_researchers']['hrn']],
779 'researcher': [record['reg_researchers']['hrn']],
780 'name': record['hrn'],
783 'person_ids': [record['reg_researchers']
785 # For client_helper.py compatibility
787 # For client_helper.py compatibility
789 # For client_helper.py compatibility
792 #Get iotlab slice record and oar job id if any.
793 recslice_list = self.GetSlices(
794 slice_filter=str(record['hrn']),
795 slice_filter_type='slice_hrn')
797 logger.debug("IOTLABDRIVER \tfill_record_info \
798 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
799 %s " % (record['hrn'], record['oar_job_id']))
800 del record['reg_researchers']
802 for rec in recslice_list:
803 logger.debug("IOTLABDRIVER\r\n \t \
804 fill_record_info oar_job_id %s "
805 % (rec['oar_job_id']))
807 record['node_ids'] = [self.testbed_shell.root_auth +
808 '.' + hostname for hostname
813 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
814 recslice_list %s \r\n \t RECORD %s \r\n \
815 \r\n" % (recslice_list, record))
817 if str(record['type']) == 'user':
818 #The record is a SFA user record.
819 #Get the information about his slice from Iotlab's DB
820 #and add it to the user record.
821 recslice_list = self.GetSlices(
822 slice_filter=record['record_id'],
823 slice_filter_type='record_id_user')
825 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
826 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
827 % (recslice_list, record))
828 #Append slice record in records list,
829 #therefore fetches user and slice info again(one more loop)
830 #Will update PIs and researcher for the slice
832 recuser = recslice_list[0]['reg_researchers']
833 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
834 recuser %s \r\n \r\n" % (recuser))
836 recslice = recslice_list[0]
838 {'PI': [recuser['hrn']],
839 'researcher': [recuser['hrn']],
840 'name': recuser['hrn'],
843 'person_ids': [recuser['record_id']]})
845 for rec in recslice_list:
846 recslice['oar_job_id'].append(rec['oar_job_id'])
850 recslice.update({'type': 'slice',
851 'hrn': recslice_list[0]['hrn']})
853 #GetPersons takes [] as filters
854 user_iotlab = self.testbed_shell.GetPersons([record])
856 record.update(user_iotlab[0])
857 #For client_helper.py compatibility
862 record_list.append(recslice)
864 logger.debug("IOTLABDRIVER.PY \t \
865 fill_record_info ADDING SLICE\
866 INFO TO USER records %s" % (record_list))
868 except TypeError, error:
869 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
874 def sliver_status(self, slice_urn, slice_hrn):
876 Receive a status request for slice named urn/hrn
877 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
878 shall return a structure as described in
879 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
880 NT : not sure if we should implement this or not, but used by sface.
882 :param slice_urn: slice urn
883 :type slice_urn: string
884 :param slice_hrn: slice hrn
885 :type slice_hrn: string
889 #First get the slice with the slice hrn
890 slice_list = self.GetSlices(slice_filter=slice_hrn,
891 slice_filter_type='slice_hrn')
893 if len(slice_list) == 0:
894 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
896 #Used for fetching the user info witch comes along the slice info
897 one_slice = slice_list[0]
899 #Make a list of all the nodes hostnames in use for this slice
900 slice_nodes_list = []
901 slice_nodes_list = one_slice['node_ids']
902 #Get all the corresponding nodes details
903 nodes_all = self.testbed_shell.GetNodes(
904 {'hostname': slice_nodes_list},
905 ['node_id', 'hostname', 'site', 'boot_state'])
906 nodeall_byhostname = dict([(one_node['hostname'], one_node)
907 for one_node in nodes_all])
909 for single_slice in slice_list:
911 top_level_status = 'empty'
914 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
915 'geni_resources'], None)
917 # ['geni_urn','geni_error', 'pl_login','geni_status',
918 # 'geni_resources'], None)
919 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
920 result['iotlab_login'] = one_slice['user']
921 logger.debug("Slabdriver - sliver_status Sliver status \
922 urn %s hrn %s single_slice %s \r\n "
923 % (slice_urn, slice_hrn, single_slice))
925 if 'node_ids' not in single_slice:
927 result['geni_status'] = top_level_status
928 result['geni_resources'] = []
931 top_level_status = 'ready'
933 #A job is running on Iotlab for this slice
934 # report about the local nodes that are in the slice only
936 result['geni_urn'] = slice_urn
939 for node_hostname in single_slice['node_ids']:
941 res['iotlab_hostname'] = node_hostname
942 res['iotlab_boot_state'] = \
943 nodeall_byhostname[node_hostname]['boot_state']
945 #res['pl_hostname'] = node['hostname']
946 #res['pl_boot_state'] = \
947 #nodeall_byhostname[node['hostname']]['boot_state']
948 #res['pl_last_contact'] = strftime(self.time_format, \
949 #gmtime(float(timestamp)))
951 slice_urn, type='slice',
952 id=nodeall_byhostname[node_hostname]['node_id']).urn
954 res['geni_urn'] = sliver_id
955 #node_name = node['hostname']
956 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
958 res['geni_status'] = 'ready'
960 res['geni_status'] = 'failed'
961 top_level_status = 'failed'
963 res['geni_error'] = ''
965 resources.append(res)
967 result['geni_status'] = top_level_status
968 result['geni_resources'] = resources
969 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
973 def get_user_record(self, hrn):
976 Returns the user record based on the hrn from the SFA DB .
978 :param hrn: user's hrn
980 :returns: user record from SFA database
984 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
986 def testbed_name(self):
989 Returns testbed's name.
990 :returns: testbed authority name.
997 def _get_requested_leases_list(self, rspec):
999 Process leases in rspec depending on the rspec version (format)
1000 type. Find the lease requests in the rspec and creates
1001 a lease request list with the mandatory information ( nodes,
1002 start time and duration) of the valid leases (duration above or
1003 equal to the iotlab experiment minimum duration).
1005 :param rspec: rspec request received.
1007 :returns: list of lease requests found in the rspec
1010 requested_lease_list = []
1011 for lease in rspec.version.get_leases():
1012 single_requested_lease = {}
1013 logger.debug("IOTLABDRIVER.PY \t \
1014 _get_requested_leases_list lease %s " % (lease))
1016 if not lease.get('lease_id'):
1017 if get_authority(lease['component_id']) == \
1018 self.testbed_shell.root_auth:
1019 single_requested_lease['hostname'] = \
1021 lease.get('component_id').strip())
1022 single_requested_lease['start_time'] = \
1023 lease.get('start_time')
1024 single_requested_lease['duration'] = lease.get('duration')
1025 #Check the experiment's duration is valid before adding
1026 #the lease to the requested leases list
1027 duration_in_seconds = \
1028 int(single_requested_lease['duration'])
1029 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1030 requested_lease_list.append(single_requested_lease)
1032 return requested_lease_list
1035 def _group_leases_by_start_time(requested_lease_list):
1037 Create dict of leases by start_time, regrouping nodes reserved
1038 at the same time, for the same amount of time so as to
1039 define one job on OAR.
1041 :param requested_lease_list: list of leases
1042 :type requested_lease_list: list
1043 :returns: Dictionary with key = start time, value = list of leases
1044 with the same start time.
1049 requested_xp_dict = {}
1050 for lease in requested_lease_list:
1052 #In case it is an asap experiment start_time is empty
1053 if lease['start_time'] == '':
1054 lease['start_time'] = '0'
1056 if lease['start_time'] not in requested_xp_dict:
1057 if isinstance(lease['hostname'], str):
1058 lease['hostname'] = [lease['hostname']]
1060 requested_xp_dict[lease['start_time']] = lease
1063 job_lease = requested_xp_dict[lease['start_time']]
1064 if lease['duration'] == job_lease['duration']:
1065 job_lease['hostname'].append(lease['hostname'])
1067 return requested_xp_dict
1069 def _process_requested_xp_dict(self, rspec):
1071 Turns the requested leases and information into a dictionary
1072 of requested jobs, grouped by starting time.
1074 :param rspec: RSpec received
1079 requested_lease_list = self._get_requested_leases_list(rspec)
1080 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1081 requested_lease_list %s" % (requested_lease_list))
1082 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1083 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1090 def delete(self, slice_urns, options={}):
1092 Deletes the lease associated with the slice hrn and the credentials
1093 if the slice belongs to iotlab. Answer to DeleteSliver.
1095 :param slice_urn: urn of the slice
1096 :type slice_urn: string
1099 :returns: 1 if the slice to delete was not found on iotlab,
1100 True if the deletion was successful, False otherwise otherwise.
1102 .. note:: Should really be named delete_leases because iotlab does
1103 not have any slivers, but only deals with leases. However,
1104 SFA api only have delete_sliver define so far. SA 13/05/2013
1105 .. note:: creds are unused, and are not used either in the dummy driver
1108 # collect sliver ids so we can update sliver allocation states after
1109 # we remove the slivers.
1110 aggregate = IotlabAggregate(self)
1111 slivers = aggregate.get_slivers(slice_urns)
1113 # slice_id = slivers[0]['slice_id']
1116 sliver_jobs_dict = {}
1117 for sliver in slivers:
1118 node_ids.append(sliver['node_id'])
1119 sliver_ids.append(sliver['sliver_id'])
1120 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1121 sliver_jobs_dict[job_id] = sliver['sliver_id']
1122 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1123 % (slivers, slice_urns))
1124 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1126 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1127 slice_filter_type='slice_hrn')
1129 if not sfa_slice_list:
1132 #Delete all leases in the slice
1133 for sfa_slice in sfa_slice_list:
1134 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1135 slices = IotlabSlices(self)
1136 # determine if this is a peer slice
1138 peer = slices.get_peer(slice_hrn)
1140 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1141 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1142 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1144 for job_id in oar_bool_ans:
1145 # if the job has not been successfully deleted
1146 # don't delete the associated sliver
1147 # remove it from the sliver list
1148 if oar_bool_ans[job_id] is False:
1149 sliver = sliver_jobs_dict[job_id]
1150 sliver_ids.remove(sliver)
1153 dbsession = self.api.dbsession()
1154 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1156 logger.log_exc("IOTLABDRIVER.PY delete error ")
1158 # prepare return struct
1160 for sliver in slivers:
1161 geni_slivers.append(
1162 {'geni_sliver_urn': sliver['sliver_id'],
1163 'geni_allocation_status': 'geni_unallocated',
1164 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1170 def list_slices(self, creds, options):
1171 """Answer to ListSlices.
1173 List slices belonging to iotlab, returns slice urns list.
1174 No caching used. Options unused but are defined in the SFA method
1177 :returns: slice urns list
1180 .. note:: creds and options are unused - SA 12/12/13
1182 # look in cache first
1184 #slices = self.cache.get('slices')
1186 #logger.debug("PlDriver.list_slices returns from cache")
1191 slices = self.GetSlices()
1192 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1194 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1196 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1197 for slice_hrn in slice_hrns]
1201 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1202 #self.cache.add('slices', slice_urns)
1207 def register(self, sfa_record, hrn, pub_key):
1209 Adding new user, slice, node or site should not be handled
1212 ..warnings:: should not be used. Different components are in charge of
1213 doing this task. Adding nodes = OAR
1214 Adding users = LDAP Iotlab
1215 Adding slice = Import from LDAP users
1218 :param sfa_record: record provided by the client of the
1220 :type sfa_record: dict
1221 :param pub_key: public key of the user
1222 :type pub_key: string
1224 .. note:: DOES NOTHING. Returns -1.
1230 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1232 No site or node record update allowed in Iotlab. The only modifications
1233 authorized here are key deletion/addition on an existing user and
1234 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1235 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1236 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1237 user's ssh key should nmodify the slice's GID after an import procedure.
1239 :param old_sfa_record: what is in the db for this hrn
1240 :param new_sfa_record: what was passed to the update call
1241 :param new_key: the new user's public key
1242 :param hrn: the user's sfa hrn
1243 :type old_sfa_record: dict
1244 :type new_sfa_record: dict
1245 :type new_key: string
1249 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1250 since users, keys and slice are managed by the LDAP.
1253 # pointer = old_sfa_record['pointer']
1254 # old_sfa_record_type = old_sfa_record['type']
1256 # # new_key implemented for users only
1257 # if new_key and old_sfa_record_type not in ['user']:
1258 # raise UnknownSfaType(old_sfa_record_type)
1260 # if old_sfa_record_type == "user":
1261 # update_fields = {}
1262 # all_fields = new_sfa_record
1263 # for key in all_fields.keys():
1264 # if key in ['key', 'password']:
1265 # update_fields[key] = all_fields[key]
1268 # # must check this key against the previous one if it exists
1269 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1270 # person = persons[0]
1271 # keys = [person['pkey']]
1272 # #Get all the person's keys
1273 # keys_dict = self.GetKeys(keys)
1275 # # Delete all stale keys, meaning the user has only one key
1277 # #TODO: do we really want to delete all the other keys?
1278 # #Is this a problem with the GID generation to have multiple
1279 # #keys? SA 30/05/13
1280 # key_exists = False
1281 # if key in keys_dict:
1284 # #remove all the other keys
1285 # for key in keys_dict:
1286 # self.testbed_shell.DeleteKey(person, key)
1287 # self.testbed_shell.AddPersonKey(
1288 # person, {'sshPublicKey': person['pkey']},
1289 # {'sshPublicKey': new_key})
1290 logger.warning ("UNDEFINED - Update should be done by the \
1294 def remove(self, sfa_record):
1297 Removes users only. Mark the user as disabled in LDAP. The user and his
1298 slice are then deleted from the db by running an import on the registry.
1300 :param sfa_record: record is the existing sfa record in the db
1301 :type sfa_record: dict
1303 ..warning::As fas as the slice is concerned, here only the leases are
1304 removed from the slice. The slice is record itself is not removed
1309 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1311 TODO: return boolean for the slice part
1313 sfa_record_type = sfa_record['type']
1314 hrn = sfa_record['hrn']
1315 if sfa_record_type == 'user':
1317 #get user from iotlab ldap
1318 person = self.testbed_shell.GetPersons(sfa_record)
1319 #No registering at a given site in Iotlab.
1320 #Once registered to the LDAP, all iotlab sites are
1323 #Mark account as disabled in ldap
1324 return self.testbed_shell.DeletePerson(sfa_record)
1326 elif sfa_record_type == 'slice':
1327 if self.GetSlices(slice_filter=hrn,
1328 slice_filter_type='slice_hrn'):
1329 ret = self.testbed_shell.DeleteSlice(sfa_record)
1332 def check_sliver_credentials(self, creds, urns):
1333 """Check that the sliver urns belongs to the slice specified in the
1336 :param urns: list of sliver urns.
1338 :param creds: slice credentials.
1339 :type creds: Credential object.
1343 # build list of cred object hrns
1344 slice_cred_names = []
1346 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1347 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1348 slice_cred_names.append(slicename)
1350 # look up slice name of slivers listed in urns arg
1354 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1356 slice_ids.append(int(sliver_id_parts[0]))
1361 raise Forbidden("sliver urn not provided")
1363 slices = self.GetSlices(slice_ids)
1364 sliver_names = [single_slice['name'] for single_slice in slices]
1366 # make sure we have a credential for every specified sliver
1367 for sliver_name in sliver_names:
1368 if sliver_name not in slice_cred_names:
1369 msg = "Valid credential not found for target: %s" % sliver_name
1370 raise Forbidden(msg)
1372 ########################################
1373 ########## aggregate oriented
1374 ########################################
1376 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1377 def aggregate_version(self):
1380 Returns the testbed's supported rspec advertisement and request
1382 :returns: rspec versions supported ad a dictionary.
1386 version_manager = VersionManager()
1387 ad_rspec_versions = []
1388 request_rspec_versions = []
1389 for rspec_version in version_manager.versions:
1390 if rspec_version.content_type in ['*', 'ad']:
1391 ad_rspec_versions.append(rspec_version.to_dict())
1392 if rspec_version.content_type in ['*', 'request']:
1393 request_rspec_versions.append(rspec_version.to_dict())
1395 'testbed': self.testbed_name(),
1396 'geni_request_rspec_versions': request_rspec_versions,
1397 'geni_ad_rspec_versions': ad_rspec_versions}
1399 # first 2 args are None in case of resource discovery
1400 def list_resources (self, version=None, options={}):
1401 aggregate = IotlabAggregate(self)
1402 rspec = aggregate.list_resources(version=version, options=options)
1405 def describe(self, urns, version, options={}):
1406 aggregate = IotlabAggregate(self)
1407 return aggregate.describe(urns, version=version, options=options)
1409 def status (self, urns, options={}):
1410 aggregate = IotlabAggregate(self)
1411 desc = aggregate.describe(urns, version='GENI 3')
1412 status = {'geni_urn': desc['geni_urn'],
1413 'geni_slivers': desc['geni_slivers']}
1417 def allocate (self, urn, rspec_string, expiration, options={}):
1419 aggregate = IotlabAggregate(self)
1421 slices = IotlabSlices(self)
1422 peer = slices.get_peer(xrn.get_hrn())
1423 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1427 users = options.get('geni_users', [])
1429 sfa_users = options.get('sfa_users', [])
1431 slice_record = sfa_users[0].get('slice_record', [])
1434 rspec = RSpec(rspec_string)
1435 # requested_attributes = rspec.version.get_slice_attributes()
1437 # ensure site record exists
1439 # ensure slice record exists
1441 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1442 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1443 \r\n \r\n current_slice %s" % (current_slice))
1444 # ensure person records exists
1446 # oui c'est degueulasse, le slice_record se retrouve modifie
1447 # dans la methode avec les infos du user, els infos sont propagees
1448 # dans verify_slice_leases
1449 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1451 # ensure slice attributes exists
1452 # slices.verify_slice_attributes(slice, requested_attributes,
1455 # add/remove slice from nodes
1456 requested_xp_dict = self._process_requested_xp_dict(rspec)
1458 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1459 % (requested_xp_dict))
1460 request_nodes = rspec.version.get_nodes_with_slivers()
1462 for start_time in requested_xp_dict:
1463 lease = requested_xp_dict[start_time]
1464 for hostname in lease['hostname']:
1465 nodes_list.append(hostname)
1467 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1468 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1469 % (nodes_list, slice_record))
1472 rspec_requested_leases = rspec.version.get_leases()
1473 leases = slices.verify_slice_leases(slice_record,
1474 requested_xp_dict, peer)
1475 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1476 rspec_requested_leases %s" % (leases,
1477 rspec_requested_leases))
1478 # update sliver allocations
1479 for hostname in nodes_list:
1480 client_id = hostname
1481 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1482 component_id = node_urn
1483 slice_urn = current_slice['reg-urn']
1484 for lease in leases:
1485 if hostname in lease['reserved_nodes']:
1486 index = lease['reserved_nodes'].index(hostname)
1487 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1488 lease['resource_ids'][index] )
1489 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1490 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1491 component_id=component_id,
1492 slice_urn = slice_urn,
1493 allocation_state='geni_allocated')
1494 record.sync(self.api.dbsession())
1496 return aggregate.describe([xrn.get_urn()], version=rspec.version)
1498 def provision(self, urns, options={}):
1500 slices = IotlabSlices(self)
1501 aggregate = IotlabAggregate(self)
1502 slivers = aggregate.get_slivers(urns)
1503 current_slice = slivers[0]
1504 peer = slices.get_peer(current_slice['hrn'])
1505 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1506 users = options.get('geni_users', [])
1507 # persons = slices.verify_persons(current_slice['hrn'],
1508 # current_slice, users, peer, sfa_peer, options=options)
1509 # slices.handle_peer(None, None, persons, peer)
1510 # update sliver allocation states and set them to geni_provisioned
1511 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1512 dbsession = self.api.dbsession()
1513 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1515 version_manager = VersionManager()
1516 rspec_version = version_manager.get_version(options[
1517 'geni_rspec_version'])
1518 return self.describe(urns, rspec_version, options=options)