2 Implements what a driver should provide for SFA to work.
4 from datetime import datetime
5 from sfa.util.faults import SliverDoesNotExist, Forbidden
6 from sfa.util.sfalogging import logger
8 from sfa.storage.model import RegRecord, RegUser, RegSlice, RegKey
9 from sfa.util.sfatime import utcparse, datetime_to_string
10 from sfa.trust.certificate import Keypair, convert_public_key
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.trust.gid import create_uuid
15 from sfa.managers.driver import Driver
16 from sfa.rspecs.version_manager import VersionManager
17 from sfa.rspecs.rspec import RSpec
19 from sfa.iotlab.iotlabxrn import IotlabXrn, xrn_object, xrn_to_hostname
20 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
21 from sfa.iotlab.iotlabaggregate import IotlabAggregate
23 from sfa.iotlab.iotlabslices import IotlabSlices
25 from sfa.trust.credential import Credential
26 from sfa.storage.model import SliverAllocation
28 from sfa.iotlab.iotlabshell import IotlabShell
29 from sqlalchemy.orm import joinedload
30 from sfa.iotlab.iotlabpostgres import LeaseTableXP
32 class IotlabDriver(Driver):
33 """ Iotlab Driver class inherited from Driver generic class.
35 Contains methods compliant with the SFA standard and the testbed
36 infrastructure (calls to LDAP and OAR).
38 .. seealso::: Driver class
41 def __init__(self, api):
44 Sets the iotlab SFA config parameters,
45 instanciates the testbed api .
47 :param api: SfaApi configuration object. Holds reference to the
49 :type api: SfaApi object
52 Driver.__init__(self, api)
55 self.testbed_shell = IotlabShell(config)
58 def GetPeers(self, peer_filter=None ):
59 """ Gathers registered authorities in SFA DB and looks for specific peer
60 if peer_filter is specified.
61 :param peer_filter: name of the site authority looked for.
62 :type peer_filter: string
63 :returns: list of records.
68 existing_hrns_by_types = {}
69 logger.debug("IOTLAB_API \tGetPeers peer_filter %s " % (peer_filter))
70 query = self.api.dbsession().query(RegRecord)
71 all_records = query.filter(RegRecord.type.like('%authority%')).all()
73 for record in all_records:
74 existing_records[(record.hrn, record.type)] = record
75 if record.type not in existing_hrns_by_types:
76 existing_hrns_by_types[record.type] = [record.hrn]
78 existing_hrns_by_types[record.type].append(record.hrn)
80 logger.debug("IOTLAB_API \tGetPeer\texisting_hrns_by_types %s "
81 % (existing_hrns_by_types))
86 records_list.append(existing_records[(peer_filter,
89 for hrn in existing_hrns_by_types['authority']:
90 records_list.append(existing_records[(hrn, 'authority')])
92 logger.debug("IOTLAB_API \tGetPeer \trecords_list %s "
98 return_records = records_list
99 logger.debug("IOTLAB_API \tGetPeer return_records %s "
101 return return_records
103 def GetKeys(self, key_filter=None):
104 """Returns a dict of dict based on the key string. Each dict entry
105 contains the key id, the ssh key, the user's email and the
107 If key_filter is specified and is an array of key identifiers,
108 only keys matching the filter will be returned.
110 Admin may query all keys. Non-admins may only query their own keys.
113 :returns: dict with ssh key as key and dicts as value.
116 query = self.api.dbsession().query(RegKey)
117 if key_filter is None:
118 keys = query.options(joinedload('reg_user')).all()
120 constraint = RegKey.key.in_(key_filter)
121 keys = query.options(joinedload('reg_user')).filter(constraint).all()
125 key_dict[key.key] = {'key_id': key.key_id, 'key': key.key,
126 'email': key.reg_user.email,
127 'hrn': key.reg_user.hrn}
129 #ldap_rslt = self.ldap.LdapSearch({'enabled']=True})
130 #user_by_email = dict((user[1]['mail'][0], user[1]['sshPublicKey']) \
131 #for user in ldap_rslt)
133 logger.debug("IOTLAB_API GetKeys -key_dict %s \r\n " % (key_dict))
138 def AddPerson(self, record):
141 Adds a new account. Any fields specified in records are used,
142 otherwise defaults are used. Creates an appropriate login by calling
145 :param record: dictionary with the sfa user's properties.
146 :returns: a dicitonary with the status. If successful, the dictionary
147 boolean is set to True and there is a 'uid' key with the new login
148 added to LDAP, otherwise the bool is set to False and a key
149 'message' is in the dictionary, with the error message.
153 ret = self.testbed_shell.ldap.LdapAddUser(record)
155 if ret['bool'] is True:
156 record['hrn'] = self.testbed_shell.root_auth + '.' + ret['uid']
157 logger.debug("IOTLAB_API AddPerson return code %s record %s "
159 self.__add_person_to_db(record)
162 def __add_person_to_db(self, user_dict):
164 Add a federated user straight to db when the user issues a lease
165 request with iotlab nodes and that he has not registered with iotlab
166 yet (that is he does not have a LDAP entry yet).
167 Uses parts of the routines in IotlabImport when importing user from
168 LDAP. Called by AddPerson, right after LdapAddUser.
169 :param user_dict: Must contain email, hrn and pkey to get a GID
170 and be added to the SFA db.
171 :type user_dict: dict
174 query = self.api.dbsession().query(RegUser)
175 check_if_exists = query.filter_by(email = user_dict['email']).first()
177 if not check_if_exists:
178 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
180 hrn = user_dict['hrn']
181 person_urn = hrn_to_urn(hrn, 'user')
183 pubkey = user_dict['pkey']
184 pkey = convert_public_key(pubkey)
186 #key not good. create another pkey
187 logger.warn('__add_person_to_db: no public key or unable to convert public \
189 pkey = Keypair(create=True)
192 if pubkey is not None and pkey is not None :
193 hierarchy = Hierarchy()
194 person_gid = hierarchy.create_gid(person_urn, create_uuid(), \
196 if user_dict['email']:
197 logger.debug("__add_person_to_db \r\n \r\n \
198 IOTLAB IMPORTER PERSON EMAIL OK email %s "\
199 %(user_dict['email']))
200 person_gid.set_email(user_dict['email'])
202 user_record = RegUser(hrn=hrn , pointer= '-1', \
203 authority=get_authority(hrn), \
204 email=user_dict['email'], gid = person_gid)
205 #user_record.reg_keys = [RegKey(user_dict['pkey'])]
206 user_record.just_created()
207 self.api.dbsession().add (user_record)
208 self.api.dbsession().commit()
213 def _sql_get_slice_info(self, slice_filter):
215 Get the slice record based on the slice hrn. Fetch the record of the
216 user associated with the slice by using joinedload based on the
217 reg_researchers relationship.
219 :param slice_filter: the slice hrn we are looking for
220 :type slice_filter: string
221 :returns: the slice record enhanced with the user's information if the
222 slice was found, None it wasn't.
224 :rtype: dict or None.
226 #DO NOT USE RegSlice - reg_researchers to get the hrn
227 #of the user otherwise will mess up the RegRecord in
228 #Resolve, don't know why - SA 08/08/2012
230 #Only one entry for one user = one slice in testbed_xp table
231 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
233 raw_slicerec = self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn=slice_filter).first()
234 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(hrn = slice_filter).first()
236 #load_reg_researchers
237 #raw_slicerec.reg_researchers
238 raw_slicerec = raw_slicerec.__dict__
239 logger.debug(" IOTLAB_API \t _sql_get_slice_info slice_filter %s \
240 raw_slicerec %s" % (slice_filter, raw_slicerec))
241 slicerec = raw_slicerec
242 #only one researcher per slice so take the first one
243 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
244 #del slicerec['reg_researchers']['_sa_instance_state']
250 def _sql_get_slice_info_from_user(self, slice_filter):
252 Get the slice record based on the user recordid by using a joinedload
253 on the relationship reg_slices_as_researcher. Format the sql record
254 into a dict with the mandatory fields for user and slice.
255 :returns: dict with slice record and user record if the record was found
256 based on the user's id, None if not..
257 :rtype:dict or None..
259 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
260 raw_slicerec = self.api.dbsession().query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id=slice_filter).first()
261 #raw_slicerec = self.api.dbsession().query(RegRecord).filter_by(record_id = slice_filter).first()
262 #Put it in correct order
263 user_needed_fields = ['peer_authority', 'hrn', 'last_updated',
264 'classtype', 'authority', 'gid', 'record_id',
265 'date_created', 'type', 'email', 'pointer']
266 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated',
267 'classtype', 'authority', 'gid', 'record_id',
268 'date_created', 'type', 'pointer']
270 #raw_slicerec.reg_slices_as_researcher
271 raw_slicerec = raw_slicerec.__dict__
274 dict([(k, raw_slicerec[
275 'reg_slices_as_researcher'][0].__dict__[k])
276 for k in slice_needed_fields])
277 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k])
278 for k in user_needed_fields])
279 #TODO Handle multiple slices for one user SA 10/12/12
280 #for now only take the first slice record associated to the rec user
281 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
282 #del raw_slicerec['reg_slices_as_researcher']
283 #slicerec['reg_researchers'] = raw_slicerec
284 ##del slicerec['_sa_instance_state']
293 def _get_slice_records(self, slice_filter=None,
294 slice_filter_type=None):
296 Get the slice record depending on the slice filter and its type.
297 :param slice_filter: Can be either the slice hrn or the user's record
299 :type slice_filter: string
300 :param slice_filter_type: describes the slice filter type used, can be
301 slice_hrn or record_id_user
303 :returns: the slice record
305 .. seealso::_sql_get_slice_info_from_user
306 .. seealso:: _sql_get_slice_info
309 #Get list of slices based on the slice hrn
310 if slice_filter_type == 'slice_hrn':
312 #if get_authority(slice_filter) == self.root_auth:
313 #login = slice_filter.split(".")[1].split("_")[0]
315 slicerec = self._sql_get_slice_info(slice_filter)
321 #Get slice based on user id
322 if slice_filter_type == 'record_id_user':
324 slicerec = self._sql_get_slice_info_from_user(slice_filter)
327 fixed_slicerec_dict = slicerec
328 #At this point if there is no login it means
329 #record_id_user filter has been used for filtering
331 ##If theslice record is from iotlab
332 #if fixed_slicerec_dict['peer_authority'] is None:
333 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
334 #return login, fixed_slicerec_dict
335 return fixed_slicerec_dict
341 def GetSlices(self, slice_filter=None, slice_filter_type=None,
343 """Get the slice records from the iotlab db and add lease information
346 :param slice_filter: can be the slice hrn or slice record id in the db
347 depending on the slice_filter_type.
348 :param slice_filter_type: defines the type of the filtering used, Can be
349 either 'slice_hrn' or "record_id'.
350 :type slice_filter: string
351 :type slice_filter_type: string
352 :returns: a slice dict if slice_filter and slice_filter_type
353 are specified and a matching entry is found in the db. The result
354 is put into a list.Or a list of slice dictionnaries if no filters
361 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
362 return_slicerec_dictlist = []
364 #First try to get information on the slice based on the filter provided
365 if slice_filter_type in authorized_filter_types_list:
366 fixed_slicerec_dict = self._get_slice_records(slice_filter,
368 # if the slice was not found in the sfa db
369 if fixed_slicerec_dict is None:
370 return return_slicerec_dictlist
372 slice_hrn = fixed_slicerec_dict['hrn']
374 logger.debug(" IOTLAB_API \tGetSlices login %s \
375 slice record %s slice_filter %s \
376 slice_filter_type %s " % (login,
377 fixed_slicerec_dict, slice_filter,
381 #Now we have the slice record fixed_slicerec_dict, get the
382 #jobs associated to this slice
385 leases_list = self.GetLeases(login=login)
386 #If no job is running or no job scheduled
387 #return only the slice record
388 if leases_list == [] and fixed_slicerec_dict:
389 return_slicerec_dictlist.append(fixed_slicerec_dict)
391 # if the jobs running don't belong to the user/slice we are looking
393 leases_hrn = [lease['slice_hrn'] for lease in leases_list]
394 if slice_hrn not in leases_hrn:
395 return_slicerec_dictlist.append(fixed_slicerec_dict)
396 #If several jobs for one slice , put the slice record into
397 # each lease information dict
398 for lease in leases_list:
400 logger.debug("IOTLAB_API.PY \tGetSlices slice_filter %s \
401 \t lease['slice_hrn'] %s"
402 % (slice_filter, lease['slice_hrn']))
403 if lease['slice_hrn'] == slice_hrn:
404 slicerec_dict['oar_job_id'] = lease['lease_id']
405 #Update lease dict with the slice record
406 if fixed_slicerec_dict:
407 fixed_slicerec_dict['oar_job_id'] = []
408 fixed_slicerec_dict['oar_job_id'].append(
409 slicerec_dict['oar_job_id'])
410 slicerec_dict.update(fixed_slicerec_dict)
411 #slicerec_dict.update({'hrn':\
412 #str(fixed_slicerec_dict['slice_hrn'])})
413 slicerec_dict['slice_hrn'] = lease['slice_hrn']
414 slicerec_dict['hrn'] = lease['slice_hrn']
415 slicerec_dict['user'] = lease['user']
416 slicerec_dict.update(
418 {'hostname': lease['reserved_nodes']}})
419 slicerec_dict.update({'node_ids': lease['reserved_nodes']})
423 return_slicerec_dictlist.append(slicerec_dict)
425 logger.debug("IOTLAB_API.PY \tGetSlices \
426 slicerec_dict %s return_slicerec_dictlist %s \
427 lease['reserved_nodes'] \
428 %s" % (slicerec_dict, return_slicerec_dictlist,
429 lease['reserved_nodes']))
431 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
432 return_slicerec_dictlist %s"
433 % (return_slicerec_dictlist))
435 return return_slicerec_dictlist
439 #Get all slices from the iotlab sfa database ,
440 #put them in dict format
441 #query_slice_list = dbsession.query(RegRecord).all()
443 self.api.dbsession().query(RegSlice).options(joinedload('reg_researchers')).all()
445 for record in query_slice_list:
446 tmp = record.__dict__
447 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
448 #del tmp['reg_researchers']['_sa_instance_state']
449 return_slicerec_dictlist.append(tmp)
450 #return_slicerec_dictlist.append(record.__dict__)
452 #Get all the jobs reserved nodes
453 leases_list = self.testbed_shell.GetReservedNodes()
455 for fixed_slicerec_dict in return_slicerec_dictlist:
457 #Check if the slice belongs to a iotlab user
458 if fixed_slicerec_dict['peer_authority'] is None:
459 owner = fixed_slicerec_dict['hrn'].split(
460 ".")[1].split("_")[0]
463 for lease in leases_list:
464 if owner == lease['user']:
465 slicerec_dict['oar_job_id'] = lease['lease_id']
467 #for reserved_node in lease['reserved_nodes']:
468 logger.debug("IOTLAB_API.PY \tGetSlices lease %s "
470 slicerec_dict.update(fixed_slicerec_dict)
471 slicerec_dict.update({'node_ids':
472 lease['reserved_nodes']})
473 slicerec_dict.update({'list_node_ids':
475 lease['reserved_nodes']}})
477 #slicerec_dict.update({'hrn':\
478 #str(fixed_slicerec_dict['slice_hrn'])})
479 #return_slicerec_dictlist.append(slicerec_dict)
480 fixed_slicerec_dict.update(slicerec_dict)
482 logger.debug("IOTLAB_API.PY \tGetSlices RETURN \
483 return_slicerec_dictlist %s \t slice_filter %s " \
484 %(return_slicerec_dictlist, slice_filter))
486 return return_slicerec_dictlist
488 def AddLeases(self, hostname_list, slice_record,
489 lease_start_time, lease_duration):
491 """Creates a job in OAR corresponding to the information provided
492 as parameters. Adds the job id and the slice hrn in the iotlab
493 database so that we are able to know which slice has which nodes.
495 :param hostname_list: list of nodes' OAR hostnames.
496 :param slice_record: sfa slice record, must contain login and hrn.
497 :param lease_start_time: starting time , unix timestamp format
498 :param lease_duration: duration in minutes
500 :type hostname_list: list
501 :type slice_record: dict
502 :type lease_start_time: integer
503 :type lease_duration: integer
504 :returns: job_id, can be None if the job request failed.
507 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases hostname_list %s \
508 slice_record %s lease_start_time %s lease_duration %s "\
509 %( hostname_list, slice_record , lease_start_time, \
512 #tmp = slice_record['reg-researchers'][0].split(".")
513 username = slice_record['login']
514 #username = tmp[(len(tmp)-1)]
515 job_id = self.testbed_shell.LaunchExperimentOnOAR(hostname_list, \
516 slice_record['hrn'], \
517 lease_start_time, lease_duration, \
519 if job_id is not None:
521 datetime.fromtimestamp(int(lease_start_time)).\
522 strftime(self.testbed_shell.time_format)
523 end_time = lease_start_time + lease_duration
526 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases TURN ON LOGGING SQL \
527 %s %s %s "%(slice_record['hrn'], job_id, end_time))
530 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases %s %s %s " \
531 %(type(slice_record['hrn']), type(job_id), type(end_time)))
533 iotlab_ex_row = LeaseTableXP(slice_hrn = slice_record['hrn'],
534 experiment_id=job_id,
537 logger.debug("IOTLAB_API \r\n \r\n \t AddLeases iotlab_ex_row %s" \
539 self.api.dbsession().add(iotlab_ex_row)
540 self.api.dbsession().commit()
542 logger.debug("IOTLAB_API \t AddLeases hostname_list start_time %s "
547 def GetLeases(self, lease_filter_dict=None, login=None):
550 Get the list of leases from OAR with complete information
551 about which slice owns which jobs and nodes.
553 -Fetch all the jobs from OAR (running, waiting..)
554 complete the reservation information with slice hrn
555 found in lease_table . If not available in the table,
556 assume it is a iotlab slice.
557 -Updates the iotlab table, deleting jobs when necessary.
559 :returns: reservation_list, list of dictionaries with 'lease_id',
560 'reserved_nodes','slice_id', 'state', 'user', 'component_id_list',
561 'slice_hrn', 'resource_ids', 't_from', 't_until'
566 unfiltered_reservation_list = self.testbed_shell.GetReservedNodes(login)
568 reservation_list = []
569 #Find the slice associated with this user iotlab ldap uid
570 logger.debug(" IOTLAB_API.PY \tGetLeases login %s\
571 unfiltered_reservation_list %s "
572 % (login, unfiltered_reservation_list))
573 #Create user dict first to avoid looking several times for
574 #the same user in LDAP SA 27/07/12
576 jobs_psql_query = self.api.dbsession().query(LeaseTableXP).all()
577 jobs_psql_dict = dict([(row.experiment_id, row.__dict__)
578 for row in jobs_psql_query])
579 #jobs_psql_dict = jobs_psql_dict)
580 logger.debug("IOTLAB_API \tGetLeases jobs_psql_dict %s"
582 jobs_psql_id_list = [row.experiment_id for row in jobs_psql_query]
584 for resa in unfiltered_reservation_list:
585 logger.debug("IOTLAB_API \tGetLeases USER %s"
587 #Construct list of jobs (runing, waiting..) in oar
588 job_oar_list.append(resa['lease_id'])
589 #If there is information on the job in IOTLAB DB ]
590 #(slice used and job id)
591 if resa['lease_id'] in jobs_psql_dict:
592 job_info = jobs_psql_dict[resa['lease_id']]
593 logger.debug("IOTLAB_API \tGetLeases job_info %s"
595 resa['slice_hrn'] = job_info['slice_hrn']
596 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
598 #otherwise, assume it is a iotlab slice:
600 resa['slice_id'] = hrn_to_urn(self.testbed_shell.root_auth \
601 + '.' + resa['user'] + "_slice",
603 resa['slice_hrn'] = Xrn(resa['slice_id']).get_hrn()
605 resa['component_id_list'] = []
606 #Transform the hostnames into urns (component ids)
607 for node in resa['reserved_nodes']:
609 iotlab_xrn = xrn_object(self.testbed_shell.root_auth, node)
610 resa['component_id_list'].append(iotlab_xrn.urn)
612 if lease_filter_dict:
613 logger.debug("IOTLAB_API \tGetLeases \
614 \r\n leasefilter %s" % ( lease_filter_dict))
616 # filter_dict_functions = {
617 # 'slice_hrn' : IotlabShell.filter_lease_name,
618 # 't_from' : IotlabShell.filter_lease_start_time
620 reservation_list = list(unfiltered_reservation_list)
621 for filter_type in lease_filter_dict:
622 logger.debug("IOTLAB_API \tGetLeases reservation_list %s" \
623 % (reservation_list))
624 reservation_list = self.testbed_shell.filter_lease(
625 reservation_list,filter_type,
626 lease_filter_dict[filter_type] )
628 # Filter the reservation list with a maximum timespan so that the
629 # leases and jobs running after this timestamp do not appear
630 # in the result leases.
631 # if 'start_time' in :
632 # if resa['start_time'] < lease_filter_dict['start_time']:
633 # reservation_list.append(resa)
636 # if 'name' in lease_filter_dict and \
637 # lease_filter_dict['name'] == resa['slice_hrn']:
638 # reservation_list.append(resa)
641 if lease_filter_dict is None:
642 reservation_list = unfiltered_reservation_list
644 self.update_experiments_in_lease_table(job_oar_list, jobs_psql_id_list)
646 logger.debug(" IOTLAB_API.PY \tGetLeases reservation_list %s"
647 % (reservation_list))
648 return reservation_list
652 def update_experiments_in_lease_table(self,
653 experiment_list_from_testbed, experiment_list_in_db):
654 """ Cleans the lease_table by deleting expired and cancelled jobs.
656 Compares the list of experiment ids given by the testbed with the
657 experiment ids that are already in the database, deletes the
658 experiments that are no longer in the testbed experiment id list.
660 :param experiment_list_from_testbed: list of experiment ids coming
662 :type experiment_list_from_testbed: list
663 :param experiment_list_in_db: list of experiment ids from the sfa
664 additionnal database.
665 :type experiment_list_in_db: list
669 #Turn the list into a set
670 set_experiment_list_in_db = set(experiment_list_in_db)
672 kept_experiments = set(experiment_list_from_testbed).intersection(set_experiment_list_in_db)
673 logger.debug("\r\n \t update_experiments_in_lease_table \
674 experiment_list_in_db %s \r\n \
675 experiment_list_from_testbed %s \
676 kept_experiments %s "
677 % (set_experiment_list_in_db,
678 experiment_list_from_testbed, kept_experiments))
679 deleted_experiments = set_experiment_list_in_db.difference(
681 deleted_experiments = list(deleted_experiments)
682 if len(deleted_experiments) > 0:
683 request = self.api.dbsession().query(LeaseTableXP)
684 request.filter(LeaseTableXP.experiment_id.in_(deleted_experiments)).delete(synchronize_session='fetch')
685 self.api.dbsession().commit()
689 def AddSlice(self, slice_record, user_record):
692 Add slice to the local iotlab sfa tables if the slice comes
693 from a federated site and is not yet in the iotlab sfa DB,
694 although the user has already a LDAP login.
695 Called by verify_slice during lease/sliver creation.
697 :param slice_record: record of slice, must contain hrn, gid, slice_id
698 and authority of the slice.
699 :type slice_record: dictionary
700 :param user_record: record of the user
701 :type user_record: RegUser
705 sfa_record = RegSlice(hrn=slice_record['hrn'],
706 gid=slice_record['gid'],
707 pointer=slice_record['slice_id'],
708 authority=slice_record['authority'])
709 logger.debug("IOTLAB_API.PY AddSlice sfa_record %s user_record %s"
710 % (sfa_record, user_record))
711 sfa_record.just_created()
712 self.api.dbsession().add(sfa_record)
713 self.api.dbsession().commit()
714 #Update the reg-researchers dependency table
715 sfa_record.reg_researchers = [user_record]
716 self.api.dbsession().commit()
720 def augment_records_with_testbed_info(self, record_list):
723 Adds specific testbed info to the records.
725 :param record_list: list of sfa dictionaries records
726 :type record_list: list
727 :returns: list of records with extended information in each record
731 return self.fill_record_info(record_list)
733 def fill_record_info(self, record_list):
736 For each SFA record, fill in the iotlab specific and SFA specific
737 fields in the record.
739 :param record_list: list of sfa dictionaries records
740 :type record_list: list
741 :returns: list of records with extended information in each record
744 .. warning:: Should not be modifying record_list directly because modi
745 fication are kept outside the method's scope. Howerver, there is no
746 other way to do it given the way it's called in registry manager.
750 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
752 if not isinstance(record_list, list):
753 record_list = [record_list]
756 for record in record_list:
758 if str(record['type']) == 'node':
759 # look for node info using GetNodes
760 # the record is about one node only
761 filter_dict = {'hrn': [record['hrn']]}
762 node_info = self.testbed_shell.GetNodes(filter_dict)
763 # the node_info is about one node only, but it is formatted
765 record.update(node_info[0])
766 logger.debug("IOTLABDRIVER.PY \t \
767 fill_record_info NODE" % (record))
769 #If the record is a SFA slice record, then add information
770 #about the user of this slice. This kind of
771 #information is in the Iotlab's DB.
772 if str(record['type']) == 'slice':
773 if 'reg_researchers' in record and isinstance(record
776 record['reg_researchers'] = \
777 record['reg_researchers'][0].__dict__
779 {'PI': [record['reg_researchers']['hrn']],
780 'researcher': [record['reg_researchers']['hrn']],
781 'name': record['hrn'],
784 'person_ids': [record['reg_researchers']
786 # For client_helper.py compatibility
788 # For client_helper.py compatibility
790 # For client_helper.py compatibility
793 #Get iotlab slice record and oar job id if any.
794 recslice_list = self.GetSlices(
795 slice_filter=str(record['hrn']),
796 slice_filter_type='slice_hrn')
798 logger.debug("IOTLABDRIVER \tfill_record_info \
799 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
800 %s " % (record['hrn'], record['oar_job_id']))
801 del record['reg_researchers']
803 for rec in recslice_list:
804 logger.debug("IOTLABDRIVER\r\n \t \
805 fill_record_info oar_job_id %s "
806 % (rec['oar_job_id']))
808 record['node_ids'] = [self.testbed_shell.root_auth +
809 '.' + hostname for hostname
814 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
815 recslice_list %s \r\n \t RECORD %s \r\n \
816 \r\n" % (recslice_list, record))
818 if str(record['type']) == 'user':
819 #The record is a SFA user record.
820 #Get the information about his slice from Iotlab's DB
821 #and add it to the user record.
822 recslice_list = self.GetSlices(
823 slice_filter=record['record_id'],
824 slice_filter_type='record_id_user')
826 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
827 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
828 % (recslice_list, record))
829 #Append slice record in records list,
830 #therefore fetches user and slice info again(one more loop)
831 #Will update PIs and researcher for the slice
833 recuser = recslice_list[0]['reg_researchers']
834 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
835 recuser %s \r\n \r\n" % (recuser))
837 recslice = recslice_list[0]
839 {'PI': [recuser['hrn']],
840 'researcher': [recuser['hrn']],
841 'name': recuser['hrn'],
844 'person_ids': [recuser['record_id']]})
846 for rec in recslice_list:
847 recslice['oar_job_id'].append(rec['oar_job_id'])
851 recslice.update({'type': 'slice',
852 'hrn': recslice_list[0]['hrn']})
854 #GetPersons takes [] as filters
855 user_iotlab = self.testbed_shell.GetPersons([record])
857 record.update(user_iotlab[0])
858 #For client_helper.py compatibility
863 record_list.append(recslice)
865 logger.debug("IOTLABDRIVER.PY \t \
866 fill_record_info ADDING SLICE\
867 INFO TO USER records %s" % (record_list))
869 except TypeError, error:
870 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
875 def sliver_status(self, slice_urn, slice_hrn):
877 Receive a status request for slice named urn/hrn
878 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
879 shall return a structure as described in
880 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
881 NT : not sure if we should implement this or not, but used by sface.
883 :param slice_urn: slice urn
884 :type slice_urn: string
885 :param slice_hrn: slice hrn
886 :type slice_hrn: string
890 #First get the slice with the slice hrn
891 slice_list = self.GetSlices(slice_filter=slice_hrn,
892 slice_filter_type='slice_hrn')
894 if len(slice_list) == 0:
895 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
897 #Used for fetching the user info witch comes along the slice info
898 one_slice = slice_list[0]
900 #Make a list of all the nodes hostnames in use for this slice
901 slice_nodes_list = []
902 slice_nodes_list = one_slice['node_ids']
903 #Get all the corresponding nodes details
904 nodes_all = self.testbed_shell.GetNodes(
905 {'hostname': slice_nodes_list},
906 ['node_id', 'hostname', 'site', 'boot_state'])
907 nodeall_byhostname = dict([(one_node['hostname'], one_node)
908 for one_node in nodes_all])
910 for single_slice in slice_list:
912 top_level_status = 'empty'
915 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
916 'geni_resources'], None)
918 # ['geni_urn','geni_error', 'pl_login','geni_status',
919 # 'geni_resources'], None)
920 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
921 result['iotlab_login'] = one_slice['user']
922 logger.debug("Slabdriver - sliver_status Sliver status \
923 urn %s hrn %s single_slice %s \r\n "
924 % (slice_urn, slice_hrn, single_slice))
926 if 'node_ids' not in single_slice:
928 result['geni_status'] = top_level_status
929 result['geni_resources'] = []
932 top_level_status = 'ready'
934 #A job is running on Iotlab for this slice
935 # report about the local nodes that are in the slice only
937 result['geni_urn'] = slice_urn
940 for node_hostname in single_slice['node_ids']:
942 res['iotlab_hostname'] = node_hostname
943 res['iotlab_boot_state'] = \
944 nodeall_byhostname[node_hostname]['boot_state']
946 #res['pl_hostname'] = node['hostname']
947 #res['pl_boot_state'] = \
948 #nodeall_byhostname[node['hostname']]['boot_state']
949 #res['pl_last_contact'] = strftime(self.time_format, \
950 #gmtime(float(timestamp)))
952 slice_urn, type='slice',
953 id=nodeall_byhostname[node_hostname]['node_id']).urn
955 res['geni_urn'] = sliver_id
956 #node_name = node['hostname']
957 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
959 res['geni_status'] = 'ready'
961 res['geni_status'] = 'failed'
962 top_level_status = 'failed'
964 res['geni_error'] = ''
966 resources.append(res)
968 result['geni_status'] = top_level_status
969 result['geni_resources'] = resources
970 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
974 def get_user_record(self, hrn):
977 Returns the user record based on the hrn from the SFA DB .
979 :param hrn: user's hrn
981 :returns: user record from SFA database
985 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
987 def testbed_name(self):
990 Returns testbed's name.
991 :returns: testbed authority name.
998 def _get_requested_leases_list(self, rspec):
1000 Process leases in rspec depending on the rspec version (format)
1001 type. Find the lease requests in the rspec and creates
1002 a lease request list with the mandatory information ( nodes,
1003 start time and duration) of the valid leases (duration above or
1004 equal to the iotlab experiment minimum duration).
1006 :param rspec: rspec request received.
1008 :returns: list of lease requests found in the rspec
1011 requested_lease_list = []
1012 for lease in rspec.version.get_leases():
1013 single_requested_lease = {}
1014 logger.debug("IOTLABDRIVER.PY \t \
1015 _get_requested_leases_list lease %s " % (lease))
1017 if not lease.get('lease_id'):
1018 if get_authority(lease['component_id']) == \
1019 self.testbed_shell.root_auth:
1020 single_requested_lease['hostname'] = \
1022 lease.get('component_id').strip())
1023 single_requested_lease['start_time'] = \
1024 lease.get('start_time')
1025 single_requested_lease['duration'] = lease.get('duration')
1026 #Check the experiment's duration is valid before adding
1027 #the lease to the requested leases list
1028 duration_in_seconds = \
1029 int(single_requested_lease['duration'])
1030 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
1031 requested_lease_list.append(single_requested_lease)
1033 return requested_lease_list
1036 def _group_leases_by_start_time(requested_lease_list):
1038 Create dict of leases by start_time, regrouping nodes reserved
1039 at the same time, for the same amount of time so as to
1040 define one job on OAR.
1042 :param requested_lease_list: list of leases
1043 :type requested_lease_list: list
1044 :returns: Dictionary with key = start time, value = list of leases
1045 with the same start time.
1050 requested_xp_dict = {}
1051 for lease in requested_lease_list:
1053 #In case it is an asap experiment start_time is empty
1054 if lease['start_time'] == '':
1055 lease['start_time'] = '0'
1057 if lease['start_time'] not in requested_xp_dict:
1058 if isinstance(lease['hostname'], str):
1059 lease['hostname'] = [lease['hostname']]
1061 requested_xp_dict[lease['start_time']] = lease
1064 job_lease = requested_xp_dict[lease['start_time']]
1065 if lease['duration'] == job_lease['duration']:
1066 job_lease['hostname'].append(lease['hostname'])
1068 return requested_xp_dict
1070 def _process_requested_xp_dict(self, rspec):
1072 Turns the requested leases and information into a dictionary
1073 of requested jobs, grouped by starting time.
1075 :param rspec: RSpec received
1080 requested_lease_list = self._get_requested_leases_list(rspec)
1081 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
1082 requested_lease_list %s" % (requested_lease_list))
1083 xp_dict = self._group_leases_by_start_time(requested_lease_list)
1084 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
1091 def delete(self, slice_urns, options={}):
1093 Deletes the lease associated with the slice hrn and the credentials
1094 if the slice belongs to iotlab. Answer to DeleteSliver.
1096 :param slice_urn: urn of the slice
1097 :type slice_urn: string
1100 :returns: 1 if the slice to delete was not found on iotlab,
1101 True if the deletion was successful, False otherwise otherwise.
1103 .. note:: Should really be named delete_leases because iotlab does
1104 not have any slivers, but only deals with leases. However,
1105 SFA api only have delete_sliver define so far. SA 13/05/2013
1106 .. note:: creds are unused, and are not used either in the dummy driver
1109 # collect sliver ids so we can update sliver allocation states after
1110 # we remove the slivers.
1111 aggregate = IotlabAggregate(self)
1112 slivers = aggregate.get_slivers(slice_urns)
1114 # slice_id = slivers[0]['slice_id']
1117 sliver_jobs_dict = {}
1118 for sliver in slivers:
1119 node_ids.append(sliver['node_id'])
1120 sliver_ids.append(sliver['sliver_id'])
1121 job_id = sliver['sliver_id'].split('+')[-1].split('-')[0]
1122 sliver_jobs_dict[job_id] = sliver['sliver_id']
1123 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
1124 % (slivers, slice_urns))
1125 slice_hrn = urn_to_hrn(slice_urns[0])[0]
1127 sfa_slice_list = self.GetSlices(slice_filter=slice_hrn,
1128 slice_filter_type='slice_hrn')
1130 if not sfa_slice_list:
1133 #Delete all leases in the slice
1134 for sfa_slice in sfa_slice_list:
1135 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
1136 slices = IotlabSlices(self)
1137 # determine if this is a peer slice
1139 peer = slices.get_peer(slice_hrn)
1141 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
1142 \r\n \t sfa_slice %s " % (peer, sfa_slice))
1143 oar_bool_ans = self.testbed_shell.DeleteSliceFromNodes(
1145 for job_id in oar_bool_ans:
1146 # if the job has not been successfully deleted
1147 # don't delete the associated sliver
1148 # remove it from the sliver list
1149 if oar_bool_ans[job_id] is False:
1150 sliver = sliver_jobs_dict[job_id]
1151 sliver_ids.remove(sliver)
1154 dbsession = self.api.dbsession()
1155 SliverAllocation.delete_allocations(sliver_ids, dbsession)
1157 logger.log_exc("IOTLABDRIVER.PY delete error ")
1159 # prepare return struct
1161 for sliver in slivers:
1162 geni_slivers.append(
1163 {'geni_sliver_urn': sliver['sliver_id'],
1164 'geni_allocation_status': 'geni_unallocated',
1165 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
1171 def list_slices(self, creds, options):
1172 """Answer to ListSlices.
1174 List slices belonging to iotlab, returns slice urns list.
1175 No caching used. Options unused but are defined in the SFA method
1178 :returns: slice urns list
1181 .. note:: creds and options are unused - SA 12/12/13
1183 # look in cache first
1185 #slices = self.cache.get('slices')
1187 #logger.debug("PlDriver.list_slices returns from cache")
1192 slices = self.GetSlices()
1193 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
1195 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
1197 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
1198 for slice_hrn in slice_hrns]
1202 #logger.debug ("IotlabDriver.list_slices stores value in cache")
1203 #self.cache.add('slices', slice_urns)
1208 def register(self, sfa_record, hrn, pub_key):
1210 Adding new user, slice, node or site should not be handled
1213 ..warnings:: should not be used. Different components are in charge of
1214 doing this task. Adding nodes = OAR
1215 Adding users = LDAP Iotlab
1216 Adding slice = Import from LDAP users
1219 :param sfa_record: record provided by the client of the
1221 :type sfa_record: dict
1222 :param pub_key: public key of the user
1223 :type pub_key: string
1225 .. note:: DOES NOTHING. Returns -1.
1231 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
1233 No site or node record update allowed in Iotlab. The only modifications
1234 authorized here are key deletion/addition on an existing user and
1235 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
1236 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
1237 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
1238 user's ssh key should nmodify the slice's GID after an import procedure.
1240 :param old_sfa_record: what is in the db for this hrn
1241 :param new_sfa_record: what was passed to the update call
1242 :param new_key: the new user's public key
1243 :param hrn: the user's sfa hrn
1244 :type old_sfa_record: dict
1245 :type new_sfa_record: dict
1246 :type new_key: string
1250 .. warning:: SA 12/12/13 - Removed. should be done in iotlabimporter
1251 since users, keys and slice are managed by the LDAP.
1254 # pointer = old_sfa_record['pointer']
1255 # old_sfa_record_type = old_sfa_record['type']
1257 # # new_key implemented for users only
1258 # if new_key and old_sfa_record_type not in ['user']:
1259 # raise UnknownSfaType(old_sfa_record_type)
1261 # if old_sfa_record_type == "user":
1262 # update_fields = {}
1263 # all_fields = new_sfa_record
1264 # for key in all_fields.keys():
1265 # if key in ['key', 'password']:
1266 # update_fields[key] = all_fields[key]
1269 # # must check this key against the previous one if it exists
1270 # persons = self.testbed_shell.GetPersons([old_sfa_record])
1271 # person = persons[0]
1272 # keys = [person['pkey']]
1273 # #Get all the person's keys
1274 # keys_dict = self.GetKeys(keys)
1276 # # Delete all stale keys, meaning the user has only one key
1278 # #TODO: do we really want to delete all the other keys?
1279 # #Is this a problem with the GID generation to have multiple
1280 # #keys? SA 30/05/13
1281 # key_exists = False
1282 # if key in keys_dict:
1285 # #remove all the other keys
1286 # for key in keys_dict:
1287 # self.testbed_shell.DeleteKey(person, key)
1288 # self.testbed_shell.AddPersonKey(
1289 # person, {'sshPublicKey': person['pkey']},
1290 # {'sshPublicKey': new_key})
1291 logger.warning ("UNDEFINED - Update should be done by the \
1295 def remove(self, sfa_record):
1298 Removes users only. Mark the user as disabled in LDAP. The user and his
1299 slice are then deleted from the db by running an import on the registry.
1301 :param sfa_record: record is the existing sfa record in the db
1302 :type sfa_record: dict
1304 ..warning::As fas as the slice is concerned, here only the leases are
1305 removed from the slice. The slice is record itself is not removed
1310 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
1312 TODO: return boolean for the slice part
1314 sfa_record_type = sfa_record['type']
1315 hrn = sfa_record['hrn']
1316 if sfa_record_type == 'user':
1318 #get user from iotlab ldap
1319 person = self.testbed_shell.GetPersons(sfa_record)
1320 #No registering at a given site in Iotlab.
1321 #Once registered to the LDAP, all iotlab sites are
1324 #Mark account as disabled in ldap
1325 return self.testbed_shell.DeletePerson(sfa_record)
1327 elif sfa_record_type == 'slice':
1328 if self.GetSlices(slice_filter=hrn,
1329 slice_filter_type='slice_hrn'):
1330 ret = self.testbed_shell.DeleteSlice(sfa_record)
1333 def check_sliver_credentials(self, creds, urns):
1334 """Check that the sliver urns belongs to the slice specified in the
1337 :param urns: list of sliver urns.
1339 :param creds: slice credentials.
1340 :type creds: Credential object.
1344 # build list of cred object hrns
1345 slice_cred_names = []
1347 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
1348 slicename = IotlabXrn(xrn=slice_cred_hrn).iotlab_slicename()
1349 slice_cred_names.append(slicename)
1351 # look up slice name of slivers listed in urns arg
1355 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
1357 slice_ids.append(int(sliver_id_parts[0]))
1362 raise Forbidden("sliver urn not provided")
1364 slices = self.GetSlices(slice_ids)
1365 sliver_names = [single_slice['name'] for single_slice in slices]
1367 # make sure we have a credential for every specified sliver
1368 for sliver_name in sliver_names:
1369 if sliver_name not in slice_cred_names:
1370 msg = "Valid credential not found for target: %s" % sliver_name
1371 raise Forbidden(msg)
1373 ########################################
1374 ########## aggregate oriented
1375 ########################################
1377 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1378 def aggregate_version(self):
1381 Returns the testbed's supported rspec advertisement and request
1383 :returns: rspec versions supported ad a dictionary.
1387 version_manager = VersionManager()
1388 ad_rspec_versions = []
1389 request_rspec_versions = []
1390 for rspec_version in version_manager.versions:
1391 if rspec_version.content_type in ['*', 'ad']:
1392 ad_rspec_versions.append(rspec_version.to_dict())
1393 if rspec_version.content_type in ['*', 'request']:
1394 request_rspec_versions.append(rspec_version.to_dict())
1396 'testbed': self.testbed_name(),
1397 'geni_request_rspec_versions': request_rspec_versions,
1398 'geni_ad_rspec_versions': ad_rspec_versions}
1400 # first 2 args are None in case of resource discovery
1401 def list_resources (self, version=None, options={}):
1402 aggregate = IotlabAggregate(self)
1403 rspec = aggregate.list_resources(version=version, options=options)
1406 def describe(self, urns, version, options={}):
1407 aggregate = IotlabAggregate(self)
1408 return aggregate.describe(urns, version=version, options=options)
1410 def status (self, urns, options={}):
1411 aggregate = IotlabAggregate(self)
1412 desc = aggregate.describe(urns, version='GENI 3')
1413 status = {'geni_urn': desc['geni_urn'],
1414 'geni_slivers': desc['geni_slivers']}
1418 def allocate (self, urn, rspec_string, expiration, options={}):
1420 aggregate = IotlabAggregate(self)
1422 slices = IotlabSlices(self)
1423 peer = slices.get_peer(xrn.get_hrn())
1424 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
1428 users = options.get('geni_users', [])
1430 sfa_users = options.get('sfa_users', [])
1432 slice_record = sfa_users[0].get('slice_record', [])
1433 slice_record['user'] = {'keys': users[0]['keys'],
1434 'email': users[0]['email'],
1435 'hrn': slice_record['reg-researchers'][0]}
1437 logger.debug("IOTLABDRIVER.PY \t urn %s allocate options %s "
1441 rspec = RSpec(rspec_string)
1442 # requested_attributes = rspec.version.get_slice_attributes()
1444 # ensure site record exists
1446 # ensure slice record exists
1448 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
1449 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
1450 \r\n \r\n current_slice %s" % (current_slice))
1451 # ensure person records exists
1453 # oui c'est degueulasse, le slice_record se retrouve modifie
1454 # dans la methode avec les infos du user, els infos sont propagees
1455 # dans verify_slice_leases
1456 persons = slices.verify_persons(xrn.hrn, slice_record, users,
1458 # ensure slice attributes exists
1459 # slices.verify_slice_attributes(slice, requested_attributes,
1462 # add/remove slice from nodes
1463 requested_xp_dict = self._process_requested_xp_dict(rspec)
1465 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
1466 % (requested_xp_dict))
1467 request_nodes = rspec.version.get_nodes_with_slivers()
1469 for start_time in requested_xp_dict:
1470 lease = requested_xp_dict[start_time]
1471 for hostname in lease['hostname']:
1472 nodes_list.append(hostname)
1474 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
1475 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
1476 % (nodes_list, slice_record))
1479 rspec_requested_leases = rspec.version.get_leases()
1480 leases = slices.verify_slice_leases(slice_record,
1481 requested_xp_dict, peer)
1482 logger.debug("IOTLABDRIVER.PY \tallocate leases %s \
1483 rspec_requested_leases %s" % (leases,
1484 rspec_requested_leases))
1485 # update sliver allocations
1486 for hostname in nodes_list:
1487 client_id = hostname
1488 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
1489 component_id = node_urn
1490 slice_urn = current_slice['reg-urn']
1491 for lease in leases:
1492 if hostname in lease['reserved_nodes']:
1493 index = lease['reserved_nodes'].index(hostname)
1494 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
1495 lease['resource_ids'][index] )
1496 sliver_id = Xrn(sliver_hrn, type='sliver').urn
1497 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
1498 component_id=component_id,
1499 slice_urn = slice_urn,
1500 allocation_state='geni_allocated')
1501 record.sync(self.api.dbsession())
1503 return aggregate.describe([xrn.get_urn()], version=rspec.version)
1505 def provision(self, urns, options={}):
1507 slices = IotlabSlices(self)
1508 aggregate = IotlabAggregate(self)
1509 slivers = aggregate.get_slivers(urns)
1510 current_slice = slivers[0]
1511 peer = slices.get_peer(current_slice['hrn'])
1512 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
1513 users = options.get('geni_users', [])
1514 # persons = slices.verify_persons(current_slice['hrn'],
1515 # current_slice, users, peer, sfa_peer, options=options)
1516 # slices.handle_peer(None, None, persons, peer)
1517 # update sliver allocation states and set them to geni_provisioned
1518 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
1519 dbsession = self.api.dbsession()
1520 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',
1522 version_manager = VersionManager()
1523 rspec_version = version_manager.get_version(options[
1524 'geni_rspec_version'])
1525 return self.describe(urns, rspec_version, options=options)