2 Implements what a driver should provide for SFA to work.
4 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
5 from sfa.util.sfalogging import logger
6 from sfa.storage.model import RegRecord
7 from sfa.util.sfatime import utcparse, datetime_to_string
9 from sfa.managers.driver import Driver
10 from sfa.rspecs.version_manager import VersionManager
11 from sfa.rspecs.rspec import RSpec
13 from sfa.iotlab.iotlabxrn import xrn_object
14 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority, urn_to_hrn
16 from sfa.iotlab.iotlabaggregate import IotlabAggregate
17 from sfa.iotlab.iotlabxrn import xrn_to_hostname
18 from sfa.iotlab.iotlabslices import IotlabSlices
20 from sfa.storage.model import SliverAllocation
21 from sfa.iotlab.iotlabshell import IotlabShell
24 class IotlabDriver(Driver):
25 """ Iotlab Driver class inherited from Driver generic class.
27 Contains methods compliant with the SFA standard and the testbed
28 infrastructure (calls to LDAP and OAR).
30 .. seealso::: Driver class
33 def __init__(self, api):
36 Sets the iotlab SFA config parameters,
37 instanciates the testbed api and the iotlab database.
39 :param config: iotlab SFA configuration object
40 :type config: Config object
43 Driver.__init__(self, api)
46 self.testbed_shell = IotlabShell(api)
49 def augment_records_with_testbed_info(self, record_list):
52 Adds specific testbed info to the records.
54 :param record_list: list of sfa dictionaries records
55 :type record_list: list
56 :returns: list of records with extended information in each record
60 return self.fill_record_info(record_list)
62 def fill_record_info(self, record_list):
65 For each SFA record, fill in the iotlab specific and SFA specific
68 :param record_list: list of sfa dictionaries records
69 :type record_list: list
70 :returns: list of records with extended information in each record
73 .. warning:: Should not be modifying record_list directly because modi
74 fication are kept outside the method's scope. Howerver, there is no
75 other way to do it given the way it's called in registry manager.
79 logger.debug("IOTLABDRIVER \tfill_record_info records %s "
81 if not isinstance(record_list, list):
82 record_list = [record_list]
85 for record in record_list:
87 if str(record['type']) == 'node':
88 # look for node info using GetNodes
89 # the record is about one node only
90 filter_dict = {'hrn': [record['hrn']]}
91 node_info = self.testbed_shell.GetNodes(filter_dict)
92 # the node_info is about one node only, but it is formatted
94 record.update(node_info[0])
95 logger.debug("IOTLABDRIVER.PY \t \
96 fill_record_info NODE" % (record))
98 #If the record is a SFA slice record, then add information
99 #about the user of this slice. This kind of
100 #information is in the Iotlab's DB.
101 if str(record['type']) == 'slice':
102 if 'reg_researchers' in record and isinstance(record
105 record['reg_researchers'] = \
106 record['reg_researchers'][0].__dict__
108 {'PI': [record['reg_researchers']['hrn']],
109 'researcher': [record['reg_researchers']['hrn']],
110 'name': record['hrn'],
113 'person_ids': [record['reg_researchers']
115 # For client_helper.py compatibility
117 # For client_helper.py compatibility
119 # For client_helper.py compatibility
122 #Get iotlab slice record and oar job id if any.
123 recslice_list = self.testbed_shell.GetSlices(
124 slice_filter=str(record['hrn']),
125 slice_filter_type='slice_hrn')
127 logger.debug("IOTLABDRIVER \tfill_record_info \
128 TYPE SLICE RECUSER record['hrn'] %s record['oar_job_id']\
129 %s " % (record['hrn'], record['oar_job_id']))
130 del record['reg_researchers']
132 for rec in recslice_list:
133 logger.debug("IOTLABDRIVER\r\n \t \
134 fill_record_info oar_job_id %s "
135 % (rec['oar_job_id']))
137 record['node_ids'] = [self.testbed_shell.root_auth +
138 '.' + hostname for hostname
143 logger.debug("IOTLABDRIVER.PY \t fill_record_info SLICE \
144 recslice_list %s \r\n \t RECORD %s \r\n \
145 \r\n" % (recslice_list, record))
147 if str(record['type']) == 'user':
148 #The record is a SFA user record.
149 #Get the information about his slice from Iotlab's DB
150 #and add it to the user record.
151 recslice_list = self.testbed_shell.GetSlices(
152 slice_filter=record['record_id'],
153 slice_filter_type='record_id_user')
155 logger.debug("IOTLABDRIVER.PY \t fill_record_info \
156 TYPE USER recslice_list %s \r\n \t RECORD %s \r\n"
157 % (recslice_list, record))
158 #Append slice record in records list,
159 #therefore fetches user and slice info again(one more loop)
160 #Will update PIs and researcher for the slice
162 recuser = recslice_list[0]['reg_researchers']
163 logger.debug("IOTLABDRIVER.PY \t fill_record_info USER \
164 recuser %s \r\n \r\n" % (recuser))
166 recslice = recslice_list[0]
168 {'PI': [recuser['hrn']],
169 'researcher': [recuser['hrn']],
170 'name': record['hrn'],
173 'person_ids': [recuser['record_id']]})
175 for rec in recslice_list:
176 recslice['oar_job_id'].append(rec['oar_job_id'])
180 recslice.update({'type': 'slice',
181 'hrn': recslice_list[0]['hrn']})
183 #GetPersons takes [] as filters
184 user_iotlab = self.testbed_shell.GetPersons([record])
186 record.update(user_iotlab[0])
187 #For client_helper.py compatibility
192 record_list.append(recslice)
194 logger.debug("IOTLABDRIVER.PY \t \
195 fill_record_info ADDING SLICE\
196 INFO TO USER records %s" % (record_list))
198 except TypeError, error:
199 logger.log_exc("IOTLABDRIVER \t fill_record_info EXCEPTION %s"
204 def sliver_status(self, slice_urn, slice_hrn):
206 Receive a status request for slice named urn/hrn
207 urn:publicid:IDN+iotlab+nturro_slice hrn iotlab.nturro_slice
208 shall return a structure as described in
209 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
210 NT : not sure if we should implement this or not, but used by sface.
212 :param slice_urn: slice urn
213 :type slice_urn: string
214 :param slice_hrn: slice hrn
215 :type slice_hrn: string
219 #First get the slice with the slice hrn
220 slice_list = self.testbed_shell.GetSlices(slice_filter=slice_hrn,
221 slice_filter_type='slice_hrn')
223 if len(slice_list) == 0:
224 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
226 #Used for fetching the user info witch comes along the slice info
227 one_slice = slice_list[0]
229 #Make a list of all the nodes hostnames in use for this slice
230 slice_nodes_list = []
231 slice_nodes_list = one_slice['node_ids']
232 #Get all the corresponding nodes details
233 nodes_all = self.testbed_shell.GetNodes(
234 {'hostname': slice_nodes_list},
235 ['node_id', 'hostname', 'site', 'boot_state'])
236 nodeall_byhostname = dict([(one_node['hostname'], one_node)
237 for one_node in nodes_all])
239 for single_slice in slice_list:
241 top_level_status = 'empty'
244 ['geni_urn', 'geni_error', 'iotlab_login', 'geni_status',
245 'geni_resources'], None)
247 # ['geni_urn','geni_error', 'pl_login','geni_status',
248 # 'geni_resources'], None)
249 # result['pl_login'] = one_slice['reg_researchers'][0].hrn
250 result['iotlab_login'] = one_slice['user']
251 logger.debug("Slabdriver - sliver_status Sliver status \
252 urn %s hrn %s single_slice %s \r\n "
253 % (slice_urn, slice_hrn, single_slice))
255 if 'node_ids' not in single_slice:
257 result['geni_status'] = top_level_status
258 result['geni_resources'] = []
261 top_level_status = 'ready'
263 #A job is running on Iotlab for this slice
264 # report about the local nodes that are in the slice only
266 result['geni_urn'] = slice_urn
269 for node_hostname in single_slice['node_ids']:
271 res['iotlab_hostname'] = node_hostname
272 res['iotlab_boot_state'] = \
273 nodeall_byhostname[node_hostname]['boot_state']
275 #res['pl_hostname'] = node['hostname']
276 #res['pl_boot_state'] = \
277 #nodeall_byhostname[node['hostname']]['boot_state']
278 #res['pl_last_contact'] = strftime(self.time_format, \
279 #gmtime(float(timestamp)))
281 slice_urn, type='slice',
282 id=nodeall_byhostname[node_hostname]['node_id']).urn
284 res['geni_urn'] = sliver_id
285 #node_name = node['hostname']
286 if nodeall_byhostname[node_hostname]['boot_state'] == 'Alive':
288 res['geni_status'] = 'ready'
290 res['geni_status'] = 'failed'
291 top_level_status = 'failed'
293 res['geni_error'] = ''
295 resources.append(res)
297 result['geni_status'] = top_level_status
298 result['geni_resources'] = resources
299 logger.debug("IOTLABDRIVER \tsliver_statusresources %s res %s "
303 def get_user_record(self, hrn):
306 Returns the user record based on the hrn from the SFA DB .
308 :param hrn: user's hrn
310 :returns: user record from SFA database
314 return self.api.dbsession().query(RegRecord).filter_by(hrn=hrn).first()
316 def testbed_name(self):
319 Returns testbed's name.
320 :returns: testbed authority name.
326 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
327 def aggregate_version(self):
330 Returns the testbed's supported rspec advertisement and request
332 :returns: rspec versions supported ad a dictionary.
336 version_manager = VersionManager()
337 ad_rspec_versions = []
338 request_rspec_versions = []
339 for rspec_version in version_manager.versions:
340 if rspec_version.content_type in ['*', 'ad']:
341 ad_rspec_versions.append(rspec_version.to_dict())
342 if rspec_version.content_type in ['*', 'request']:
343 request_rspec_versions.append(rspec_version.to_dict())
345 'testbed': self.testbed_name(),
346 'geni_request_rspec_versions': request_rspec_versions,
347 'geni_ad_rspec_versions': ad_rspec_versions}
349 def _get_requested_leases_list(self, rspec):
351 Process leases in rspec depending on the rspec version (format)
352 type. Find the lease requests in the rspec and creates
353 a lease request list with the mandatory information ( nodes,
354 start time and duration) of the valid leases (duration above or
355 equal to the iotlab experiment minimum duration).
357 :param rspec: rspec request received.
359 :returns: list of lease requests found in the rspec
362 requested_lease_list = []
363 for lease in rspec.version.get_leases():
364 single_requested_lease = {}
365 logger.debug("IOTLABDRIVER.PY \t \
366 _get_requested_leases_list lease %s " % (lease))
368 if not lease.get('lease_id'):
369 if get_authority(lease['component_id']) == \
370 self.testbed_shell.root_auth:
371 single_requested_lease['hostname'] = \
373 lease.get('component_id').strip())
374 single_requested_lease['start_time'] = \
375 lease.get('start_time')
376 single_requested_lease['duration'] = lease.get('duration')
377 #Check the experiment's duration is valid before adding
378 #the lease to the requested leases list
379 duration_in_seconds = \
380 int(single_requested_lease['duration'])
381 if duration_in_seconds >= self.testbed_shell.GetMinExperimentDurationInGranularity():
382 requested_lease_list.append(single_requested_lease)
384 return requested_lease_list
387 def _group_leases_by_start_time(requested_lease_list):
389 Create dict of leases by start_time, regrouping nodes reserved
390 at the same time, for the same amount of time so as to
391 define one job on OAR.
393 :param requested_lease_list: list of leases
394 :type requested_lease_list: list
395 :returns: Dictionary with key = start time, value = list of leases
396 with the same start time.
401 requested_xp_dict = {}
402 for lease in requested_lease_list:
404 #In case it is an asap experiment start_time is empty
405 if lease['start_time'] == '':
406 lease['start_time'] = '0'
408 if lease['start_time'] not in requested_xp_dict:
409 if isinstance(lease['hostname'], str):
410 lease['hostname'] = [lease['hostname']]
412 requested_xp_dict[lease['start_time']] = lease
415 job_lease = requested_xp_dict[lease['start_time']]
416 if lease['duration'] == job_lease['duration']:
417 job_lease['hostname'].append(lease['hostname'])
419 return requested_xp_dict
421 def _process_requested_xp_dict(self, rspec):
423 Turns the requested leases and information into a dictionary
424 of requested jobs, grouped by starting time.
426 :param rspec: RSpec received
431 requested_lease_list = self._get_requested_leases_list(rspec)
432 logger.debug("IOTLABDRIVER _process_requested_xp_dict \
433 requested_lease_list %s" % (requested_lease_list))
434 xp_dict = self._group_leases_by_start_time(requested_lease_list)
435 logger.debug("IOTLABDRIVER _process_requested_xp_dict xp_dict\
441 def create_sliver(self, slice_urn, slice_hrn, creds, rspec_string,
443 """Answer to CreateSliver.
445 Creates the leases and slivers for the users from the information
446 found in the rspec string.
447 Launch experiment on OAR if the requested leases is valid. Delete
448 no longer requested leases.
451 :param creds: user's credentials
453 :param users: user record list
458 :returns: a valid Rspec for the slice which has just been
464 aggregate = IotlabAggregate(self)
466 slices = IotlabSlices(self)
467 peer = slices.get_peer(slice_hrn)
468 sfa_peer = slices.get_sfa_peer(slice_hrn)
471 if not isinstance(creds, list):
475 slice_record = users[0].get('slice_record', {})
476 logger.debug("IOTLABDRIVER.PY \t ===============create_sliver \t\
477 creds %s \r\n \r\n users %s"
479 slice_record['user'] = {'keys': users[0]['keys'],
480 'email': users[0]['email'],
481 'hrn': slice_record['reg-researchers'][0]}
483 rspec = RSpec(rspec_string)
484 logger.debug("IOTLABDRIVER.PY \t create_sliver \trspec.version \
485 %s slice_record %s users %s"
486 % (rspec.version, slice_record, users))
488 # ensure site record exists?
489 # ensure slice record exists
490 #Removed options in verify_slice SA 14/08/12
491 #Removed peer record in verify_slice SA 18/07/13
492 sfa_slice = slices.verify_slice(slice_hrn, slice_record, sfa_peer)
494 # ensure person records exists
495 #verify_persons returns added persons but the return value
497 #Removed peer record and sfa_peer in verify_persons SA 18/07/13
498 slices.verify_persons(slice_hrn, sfa_slice, users, options=options)
499 #requested_attributes returned by rspec.version.get_slice_attributes()
500 #unused, removed SA 13/08/12
501 #rspec.version.get_slice_attributes()
503 logger.debug("IOTLABDRIVER.PY create_sliver slice %s " % (sfa_slice))
505 # add/remove slice from nodes
507 #requested_slivers = [node.get('component_id') \
508 #for node in rspec.version.get_nodes_with_slivers()\
509 #if node.get('authority_id') is self.testbed_shell.root_auth]
510 #l = [ node for node in rspec.version.get_nodes_with_slivers() ]
511 #logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
512 #requested_slivers %s listnodes %s" \
513 #%(requested_slivers,l))
514 #verify_slice_nodes returns nodes, but unused here. Removed SA 13/08/12.
515 #slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
517 requested_xp_dict = self._process_requested_xp_dict(rspec)
519 logger.debug("IOTLABDRIVER.PY \tcreate_sliver requested_xp_dict %s "
520 % (requested_xp_dict))
521 #verify_slice_leases returns the leases , but the return value is unused
522 #here. Removed SA 13/08/12
523 slices.verify_slice_leases(sfa_slice,
524 requested_xp_dict, peer)
526 return aggregate.get_rspec(slice_xrn=slice_urn,
527 login=sfa_slice['login'],
528 version=rspec.version)
530 def delete(self, slice_urns, options):
532 Deletes the lease associated with the slice hrn and the credentials
533 if the slice belongs to iotlab. Answer to DeleteSliver.
535 :param slice_urn: urn of the slice
536 :type slice_urn: string
539 :returns: 1 if the slice to delete was not found on iotlab,
540 True if the deletion was successful, False otherwise otherwise.
542 .. note:: Should really be named delete_leases because iotlab does
543 not have any slivers, but only deals with leases. However,
544 SFA api only have delete_sliver define so far. SA 13/05/2013
545 .. note:: creds are unused, and are not used either in the dummy driver
548 # collect sliver ids so we can update sliver allocation states after
549 # we remove the slivers.
550 aggregate = IotlabAggregate(self)
551 slivers = aggregate.get_slivers(slice_urns)
553 slice_id = slivers[0]['slice_id']
556 for sliver in slivers:
557 node_ids.append(sliver['node_id'])
558 sliver_ids.append(sliver['sliver_id'])
559 logger.debug("IOTLABDRIVER.PY delete_sliver slivers %s slice_urns %s"
560 % (slivers, slice_urns))
561 slice_hrn = urn_to_hrn(slice_urns[0])[0]
563 sfa_slice_list = self.testbed_shell.GetSlices(
564 slice_filter=slice_hrn,
565 slice_filter_type='slice_hrn')
567 if not sfa_slice_list:
570 #Delete all leases in the slice
571 for sfa_slice in sfa_slice_list:
572 logger.debug("IOTLABDRIVER.PY delete_sliver slice %s" % (sfa_slice))
573 slices = IotlabSlices(self)
574 # determine if this is a peer slice
576 peer = slices.get_peer(slice_hrn)
578 logger.debug("IOTLABDRIVER.PY delete_sliver peer %s \
579 \r\n \t sfa_slice %s " % (peer, sfa_slice))
581 self.testbed_shell.DeleteSliceFromNodes(sfa_slice)
582 dbsession = self.api.dbsession()
583 SliverAllocation.delete_allocations(sliver_ids,dbsession)
585 logger.log_exc("IOTLABDRIVER.PY delete error ")
587 # prepare return struct
589 for sliver in slivers:
591 {'geni_sliver_urn': sliver['sliver_id'],
592 'geni_allocation_status': 'geni_unallocated',
593 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
596 def list_resources (self, slice_urn, slice_hrn, creds, options):
599 List resources from the iotlab aggregate and returns a Rspec
600 advertisement with resources found when slice_urn and slice_hrn are
601 None (in case of resource discovery).
602 If a slice hrn and urn are provided, list experiment's slice
603 nodes in a rspec format. Answer to ListResources.
606 :param slice_urn: urn of the slice
607 :param slice_hrn: name of the slice
608 :param creds: slice credenials
609 :type slice_urn: string
610 :type slice_hrn: string
611 :type creds: ? unused
612 :param options: options used when listing resources (list_leases, info,
614 :returns: rspec string in xml
617 .. note:: creds are unused
620 #cached_requested = options.get('cached', True)
622 version_manager = VersionManager()
623 # get the rspec's return format from options
625 version_manager.get_version(options.get('geni_rspec_version'))
626 version_string = "rspec_%s" % (rspec_version)
628 #panos adding the info option to the caching key (can be improved)
629 if options.get('info'):
630 version_string = version_string + "_" + \
631 options.get('info', 'default')
633 # Adding the list_leases option to the caching key
634 if options.get('list_leases'):
635 version_string = version_string + "_" + \
636 options.get('list_leases', 'default')
638 # Adding geni_available to caching key
639 if options.get('geni_available'):
640 version_string = version_string + "_" + \
641 str(options.get('geni_available'))
643 # look in cache first
644 #if cached_requested and self.cache and not slice_hrn:
645 #rspec = self.cache.get(version_string)
647 #logger.debug("IotlabDriver.ListResources: \
648 #returning cached advertisement")
651 #panos: passing user-defined options
652 aggregate = IotlabAggregate(self)
654 rspec = aggregate.get_rspec(slice_xrn=slice_urn,
655 version=rspec_version, options=options)
658 #if self.cache and not slice_hrn:
659 #logger.debug("Iotlab.ListResources: stores advertisement in cache")
660 #self.cache.add(version_string, rspec)
665 def list_slices(self, creds, options):
666 """Answer to ListSlices.
668 List slices belonging to iotlab, returns slice urns list.
669 No caching used. Options unused but are defined in the SFA method
672 :returns: slice urns list
675 .. note:: creds are unused
677 # look in cache first
679 #slices = self.cache.get('slices')
681 #logger.debug("PlDriver.list_slices returns from cache")
686 slices = self.testbed_shell.GetSlices()
687 logger.debug("IOTLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n"
689 slice_hrns = [iotlab_slice['hrn'] for iotlab_slice in slices]
691 slice_urns = [hrn_to_urn(slice_hrn, 'slice')
692 for slice_hrn in slice_hrns]
696 #logger.debug ("IotlabDriver.list_slices stores value in cache")
697 #self.cache.add('slices', slice_urns)
702 def register(self, sfa_record, hrn, pub_key):
704 Adding new user, slice, node or site should not be handled
707 ..warnings:: should not be used. Different components are in charge of
708 doing this task. Adding nodes = OAR
709 Adding users = LDAP Iotlab
710 Adding slice = Import from LDAP users
713 :param sfa_record: record provided by the client of the
715 :type sfa_record: dict
716 :param pub_key: public key of the user
717 :type pub_key: string
719 .. note:: DOES NOTHING. Returns -1.
725 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
727 No site or node record update allowed in Iotlab. The only modifications
728 authorized here are key deletion/addition on an existing user and
729 password change. On an existing user, CAN NOT BE MODIFIED: 'first_name',
730 'last_name', 'email'. DOES NOT EXIST IN SENSLAB: 'phone', 'url', 'bio',
731 'title', 'accepted_aup'. A slice is bound to its user, so modifying the
732 user's ssh key should nmodify the slice's GID after an import procedure.
734 :param old_sfa_record: what is in the db for this hrn
735 :param new_sfa_record: what was passed to the update call
736 :param new_key: the new user's public key
737 :param hrn: the user's sfa hrn
738 :type old_sfa_record: dict
739 :type new_sfa_record: dict
740 :type new_key: string
744 .. seealso:: update in driver.py.
747 pointer = old_sfa_record['pointer']
748 old_sfa_record_type = old_sfa_record['type']
750 # new_key implemented for users only
751 if new_key and old_sfa_record_type not in ['user']:
752 raise UnknownSfaType(old_sfa_record_type)
754 if old_sfa_record_type == "user":
756 all_fields = new_sfa_record
757 for key in all_fields.keys():
758 if key in ['key', 'password']:
759 update_fields[key] = all_fields[key]
762 # must check this key against the previous one if it exists
763 persons = self.testbed_shell.GetPersons([old_sfa_record])
765 keys = [person['pkey']]
766 #Get all the person's keys
767 keys_dict = self.testbed_shell.GetKeys(keys)
769 # Delete all stale keys, meaning the user has only one key
771 #TODO: do we really want to delete all the other keys?
772 #Is this a problem with the GID generation to have multiple
778 #remove all the other keys
779 for key in keys_dict:
780 self.testbed_shell.DeleteKey(person, key)
781 self.testbed_shell.AddPersonKey(
782 person, {'sshPublicKey': person['pkey']},
783 {'sshPublicKey': new_key})
786 def remove(self, sfa_record):
789 Removes users only. Mark the user as disabled in LDAP. The user and his
790 slice are then deleted from the db by running an import on the registry.
792 :param sfa_record: record is the existing sfa record in the db
793 :type sfa_record: dict
795 ..warning::As fas as the slice is concerned, here only the leases are
796 removed from the slice. The slice is record itself is not removed
801 TODO : REMOVE SLICE FROM THE DB AS WELL? SA 14/05/2013,
803 TODO: return boolean for the slice part
805 sfa_record_type = sfa_record['type']
806 hrn = sfa_record['hrn']
807 if sfa_record_type == 'user':
809 #get user from iotlab ldap
810 person = self.testbed_shell.GetPersons(sfa_record)
811 #No registering at a given site in Iotlab.
812 #Once registered to the LDAP, all iotlab sites are
815 #Mark account as disabled in ldap
816 return self.testbed_shell.DeletePerson(sfa_record)
818 elif sfa_record_type == 'slice':
819 if self.testbed_shell.GetSlices(slice_filter=hrn,
820 slice_filter_type='slice_hrn'):
821 ret = self.testbed_shell.DeleteSlice(sfa_record)
824 def check_sliver_credentials(self, creds, urns):
825 # build list of cred object hrns
826 slice_cred_names = []
828 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
829 slicename = Xrn(xrn=slice_cred_hrn).iotlab_slicename()
830 logger.debug("IOTLABDRIVER.PY \t check_sliver_credentials slicename %s \r\n \r\n"
832 slice_cred_names.append(slicename)
834 # look up slice name of slivers listed in urns arg
838 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
840 slice_ids.append(int(sliver_id_parts[0]))
845 raise Forbidden("sliver urn not provided")
847 slices = self.testbed_shell.GetSlices(slice_ids)
848 sliver_names = [single_slice['name'] for single_slice in slices]
850 # make sure we have a credential for every specified sliver ierd
851 for sliver_name in sliver_names:
852 if sliver_name not in slice_cred_names:
853 msg = "Valid credential not found for target: %s" % sliver_name
856 ########################################
857 ########## aggregate oriented
858 ########################################
861 def testbed_name (self): return "iotlab"
863 def aggregate_version (self):
866 # first 2 args are None in case of resource discovery
867 def list_resources (self, version=None, options={}):
868 aggregate = IotlabAggregate(self)
869 rspec = aggregate.list_resources(version=version, options=options)
872 def describe(self, urns, version, options={}):
873 aggregate = IotlabAggregate(self)
874 return aggregate.describe(urns, version=version, options=options)
876 def status (self, urns, options={}):
877 aggregate = IotlabAggregate(self)
878 desc = aggregate.describe(urns, version='GENI 3')
879 status = {'geni_urn': desc['geni_urn'],
880 'geni_slivers': desc['geni_slivers']}
884 def allocate (self, urn, rspec_string, expiration, options={}):
886 aggregate = IotlabAggregate(self)
888 slices = IotlabSlices(self)
889 peer = slices.get_peer(xrn.get_hrn())
890 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
894 users = options.get('geni_users', [])
896 sfa_users = options.get('sfa_users', [])
898 slice_record = sfa_users[0].get('slice_record', [])
899 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
900 \r\n \r\n options %s slice_record %s" % (options,slice_record))
902 rspec = RSpec(rspec_string)
903 # requested_attributes = rspec.version.get_slice_attributes()
905 # ensure site record exists
906 # site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
907 # ensure slice record exists
909 current_slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer)
910 logger.debug("IOTLABDRIVER.PY \t ===============allocate \t\
911 \r\n \r\n current_slice %s" % (current_slice))
912 # ensure person records exists
914 # oui c'est degueulasse, le slice_record se retrouve modifie
915 # dans la methode avec les infos du user, els infos sont propagees
916 # dans verify_slice_leases
917 persons = slices.verify_persons(xrn.hrn, slice_record, users, options=options)
918 # ensure slice attributes exists
919 # slices.verify_slice_attributes(slice, requested_attributes, options=options)
921 # add/remove slice from nodes
922 requested_xp_dict = self._process_requested_xp_dict(rspec)
924 logger.debug("IOTLABDRIVER.PY \tallocate requested_xp_dict %s "
925 % (requested_xp_dict))
926 request_nodes = rspec.version.get_nodes_with_slivers()
928 for start_time in requested_xp_dict:
929 lease = requested_xp_dict[start_time]
930 for hostname in lease['hostname']:
931 nodes_list.append(hostname)
933 # nodes = slices.verify_slice_nodes(slice_record,request_nodes, peer)
934 logger.debug("IOTLABDRIVER.PY \tallocate nodes_list %s slice_record %s"
935 % (nodes_list, slice_record))
938 rspec_requested_leases = rspec.version.get_leases()
939 leases = slices.verify_slice_leases(slice_record, requested_xp_dict, peer)
940 logger.debug("IOTLABDRIVER.PY \tallocate leases %s rspec_requested_leases %s"
941 % (leases,rspec_requested_leases))
942 # update sliver allocations
943 for hostname in nodes_list:
945 node_urn = xrn_object(self.testbed_shell.root_auth, hostname).urn
946 component_id = node_urn
947 slice_urn = current_slice['reg-urn']
949 if hostname in lease['reserved_nodes']:
950 index = lease['reserved_nodes'].index(hostname)
951 sliver_hrn = '%s.%s-%s' % (self.hrn, lease['lease_id'],
952 lease['resource_ids'][index] )
953 sliver_id = Xrn(sliver_hrn, type='sliver').urn
954 record = SliverAllocation(sliver_id=sliver_id, client_id=client_id,
955 component_id=component_id,
956 slice_urn = slice_urn,
957 allocation_state='geni_allocated')
960 ===============================IOTLABDRIVER.PY \tallocate sliver_id %s slice_urn %s \r\n"
961 % (sliver_id,slice_urn))
962 record.sync(self.api.dbsession())
963 # add/remove links links
964 # slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
968 return aggregate.describe([xrn.get_urn()], version=rspec.version)
970 def provision(self, urns, options={}):
972 slices = IotlabSlices(self)
973 aggregate = IotlabAggregate(self)
974 slivers = aggregate.get_slivers(urns)
975 current_slice = slivers[0]
976 peer = slices.get_peer(current_slice['hrn'])
977 sfa_peer = slices.get_sfa_peer(current_slice['hrn'])
978 users = options.get('geni_users', [])
979 # persons = slices.verify_persons(current_slice['hrn'],
980 # current_slice, users, peer, sfa_peer, options=options)
981 # slices.handle_peer(None, None, persons, peer)
982 # update sliver allocation states and set them to geni_provisioned
983 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
984 dbsession =self.api.dbsession()
985 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
986 version_manager = VersionManager()
987 rspec_version = version_manager.get_version(options['geni_rspec_version'])
988 return self.describe(urns, rspec_version, options=options)