2 File providing methods to generate valid RSpecs for the Iotlab testbed.
3 Contains methods to get information on slice, slivers, nodes and leases,
4 formatting them and turn it into a RSpec.
6 from sfa.util.xrn import hrn_to_urn, urn_to_hrn, get_authority
8 from sfa.rspecs.rspec import RSpec
9 #from sfa.rspecs.elements.location import Location
10 from sfa.rspecs.elements.hardware_type import HardwareType
11 from sfa.rspecs.elements.login import Login
12 from sfa.rspecs.elements.services import Services
13 from sfa.rspecs.elements.sliver import Sliver
14 from sfa.rspecs.elements.lease import Lease
15 from sfa.rspecs.elements.granularity import Granularity
16 from sfa.rspecs.version_manager import VersionManager
18 from sfa.rspecs.elements.versions.cortexlabv1Node import IotlabPosition, \
19 IotlabNode, IotlabLocation, IotlabMobility
21 from sfa.util.sfalogging import logger
22 from sfa.util.xrn import Xrn
25 def cortexlab_xrn_to_hostname(xrn):
26 """Returns a node's hostname from its xrn.
27 :param xrn: The nodes xrn identifier.
28 :type xrn: Xrn (from sfa.util.xrn)
30 :returns: node's hostname.
34 return Xrn.unescape(Xrn(xrn=xrn, type='node').get_leaf())
37 def cortexlab_xrn_object(root_auth, hostname):
38 """Creates a valid xrn object from the node's hostname and the authority
41 :param hostname: the node's hostname.
42 :param root_auth: the SFA root authority.
43 :type hostname: string
44 :type root_auth: string
46 :returns: the cortexlab node's xrn
50 return Xrn('.'.join([root_auth, Xrn.escape(hostname)]), type='node')
53 class CortexlabAggregate:
54 """Aggregate manager class for Iotlab. """
67 def __init__(self, driver):
70 def get_slice_and_slivers(self, slice_xrn, login=None):
72 Get the slices and the associated leases if any, from the cortexlab
73 testbed. One slice can have mutliple leases.
74 For each slice, get the nodes in the associated lease
75 and create a sliver with the necessary info and insert it into the
76 sliver dictionary, keyed on the node hostnames.
77 Returns a dict of slivers based on the sliver's node_id.
81 :param slice_xrn: xrn of the slice
82 :param login: user's login on cortexlab ldap
84 :type slice_xrn: string
86 :returns: a list of slices dict and a list of Sliver object
89 .. note: There is no real slivers in cortexlab, only leases. The goal
90 is to be consistent with the SFA standard.
96 return (sfa_slice, slivers)
97 slice_urn = hrn_to_urn(slice_xrn, 'slice')
98 slice_hrn, _ = urn_to_hrn(slice_xrn)
99 slice_name = slice_hrn
101 slices = self.driver.cortexlab_api.GetSlices(slice_filter=str(slice_name),
102 slice_filter_type='slice_hrn',
105 logger.debug("CortexlabAggregate api \tget_slice_and_slivers \
106 slice_hrn %s \r\n slices %s self.driver.hrn %s"
107 % (slice_hrn, slices, self.driver.hrn))
110 return (sfa_slice, slivers)
112 # sort slivers by node id , if there is a job
113 #and therefore, node allocated to this slice
114 for sfa_slice in slices:
116 node_ids_list = sfa_slice['node_ids']
118 logger.log_exc("CortexlabAggregate \t \
119 get_slice_and_slivers No nodes in the slice \
124 for node in node_ids_list:
125 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
126 sliver_xrn.set_authority(self.driver.hrn)
127 sliver = Sliver({'sliver_id': sliver_xrn.urn,
128 'name': sfa_slice['hrn'],
129 'type': 'cortexlab-node',
132 slivers[node] = sliver
134 #Add default sliver attribute :
135 #connection information for cortexlab
136 if get_authority(sfa_slice['hrn']) == self.driver.cortexlab_api.root_auth:
137 tmp = sfa_slice['hrn'].split('.')
138 ldap_username = tmp[1].split('_')[0]
140 slivers['default_sliver'] = {'ssh': ssh_access,
141 'login': ldap_username}
143 #TODO get_slice_and_slivers Find the login of the external user
145 logger.debug("CortexlabAggregate api get_slice_and_slivers slivers %s "
147 return (slices, slivers)
150 def get_nodes(self, slices=None, slivers=[], options=None):
151 """Returns the nodes in the slice using the rspec format, with all the
154 Fetch the nodes ids in the slices dictionary and get all the nodes
155 properties from OAR. Makes a rspec dicitonary out of this and returns
156 it. If the slice does not have any job running or scheduled, that is
157 it has no reserved nodes, then returns an empty list.
159 :param slices: list of slices (record dictionaries)
160 :param slivers: the list of slivers in all the slices
161 :type slices: list of dicts
162 :type slivers: list of Sliver object (dictionaries)
163 :returns: An empty list if the slice has no reserved nodes, a rspec
164 list with all the nodes and their properties (a dict per node)
168 .. seealso:: get_slice_and_slivers
171 # NT: the semantic of this function is not clear to me :
172 # if slice is not defined, then all the nodes should be returned
173 # if slice is defined, we should return only the nodes that
174 # are part of this slice
175 # but what is the role of the slivers parameter ?
176 # So i assume that slice['node_ids'] will be the same as slivers for us
177 slice_nodes_list = []
178 if slices is not None:
179 for one_slice in slices:
181 slice_nodes_list = one_slice['node_ids']
182 # if we are dealing with a slice that has no node just
183 # return an empty list. In cortexlab a slice can have multiple
184 # jobs scheduled, so it either has at least one lease or
189 # get the granularity in second for the reservation system
190 grain = self.driver.cortexlab_api.GetLeaseGranularity()
192 nodes = self.driver.cortexlab_api.GetNodes()
196 #if slices, this means we got to list all the nodes given to this slice
197 # Make a list of all the nodes in the slice before getting their
201 logger.debug("CortexlabAggregate api get_nodes slices %s "
204 reserved_nodes = self.driver.cortexlab_api.GetNodesCurrentlyInUse()
205 logger.debug("CortexlabAggregate api get_nodes slice_nodes_list %s "
206 % (slice_nodes_list))
208 nodes_dict[node['node_id']] = node
209 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
211 rspec_node = IotlabNode()
212 # xxx how to retrieve site['login_base']
213 #site_id=node['site_id']
214 #site=sites_dict[site_id]
216 # rspec_node['mobile'] = node['mobile']
217 rspec_node['archi'] = node['archi']
218 rspec_node['radio'] = node['radio']
220 cortexlab_xrn = cortexlab_xrn_object(self.driver.cortexlab_api.root_auth,
222 rspec_node['component_id'] = cortexlab_xrn.urn
223 rspec_node['component_name'] = node['hostname']
224 rspec_node['component_manager_id'] = \
225 hrn_to_urn(self.driver.cortexlab_api.root_auth,
228 # Iotlab's nodes are federated : there is only one authority
229 # for all Iotlab sites, registered in SFA.
230 # Removing the part including the site
231 # in authority_id SA 27/07/12
232 rspec_node['authority_id'] = rspec_node['component_manager_id']
234 # do not include boot state (<available> element)
235 #in the manifest rspec
237 rspec_node['boot_state'] = node['boot_state']
238 if node['hostname'] in reserved_nodes:
239 rspec_node['boot_state'] = "Reserved"
240 rspec_node['exclusive'] = 'true'
241 rspec_node['hardware_types'] = [HardwareType({'name':
245 location = IotlabLocation({'country':'France', 'site':
247 rspec_node['location'] = location
249 # Adding mobility of the node in the rspec
250 mobility = IotlabMobility()
251 for field in mobility:
253 mobility[field] = node[field]
254 except KeyError, error:
255 logger.log_exc("CortexlabAggregate\t get_nodes \
256 mobility %s " % (error))
257 rspec_node['mobility'] = mobility
259 position = IotlabPosition()
260 for field in position:
262 position[field] = node[field]
263 except KeyError, error:
264 logger.log_exc("CortexlabAggregate\t get_nodes \
265 position %s " % (error))
267 rspec_node['position'] = position
268 #rspec_node['interfaces'] = []
271 granularity = Granularity({'grain': grain})
272 rspec_node['granularity'] = granularity
273 rspec_node['tags'] = []
274 if node['hostname'] in slivers:
276 sliver = slivers[node['hostname']]
277 rspec_node['sliver_id'] = sliver['sliver_id']
278 rspec_node['client_id'] = node['hostname']
279 rspec_node['slivers'] = [sliver]
281 # slivers always provide the ssh service
282 login = Login({'authentication': 'ssh-keys',
283 'hostname': node['hostname'], 'port': '22',
284 'username': sliver['name']})
285 service = Services({'login': login})
286 rspec_node['services'] = [service]
287 rspec_nodes.append(rspec_node)
291 def get_all_leases(self, ldap_username):
294 Get list of lease dictionaries which all have the mandatory keys
295 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
296 All the leases running or scheduled are returned.
298 :param ldap_username: if ldap uid is not None, looks for the leases
299 belonging to this user.
300 :type ldap_username: string
301 :returns: rspec lease dictionary with keys lease_id, component_id,
302 slice_id, start_time, duration.
305 .. note::There is no filtering of leases within a given time frame.
306 All the running or scheduled leases are returned. options
307 removed SA 15/05/2013
312 #now = int(time.time())
313 #lease_filter = {'clip': now }
316 #lease_filter.update({'name': slice_record['name']})
318 #leases = self.driver.cortexlab_api.GetLeases(lease_filter)
320 logger.debug("CortexlabAggregate get_all_leases ldap_username %s "
322 leases = self.driver.cortexlab_api.GetLeases(login=ldap_username)
323 grain = self.driver.cortexlab_api.GetLeaseGranularity()
327 #as many leases as there are nodes in the job
328 for node in lease['reserved_nodes']:
329 rspec_lease = Lease()
330 rspec_lease['lease_id'] = lease['lease_id']
331 #site = node['site_id']
332 cortexlab_xrn = cortexlab_xrn_object(self.driver.cortexlab_api.root_auth,
334 rspec_lease['component_id'] = cortexlab_xrn.urn
335 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
336 #site, node['hostname'])
338 rspec_lease['slice_id'] = lease['slice_id']
340 #No info on the slice used in cortexlab_xp table
342 rspec_lease['start_time'] = lease['t_from']
343 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
345 rspec_leases.append(rspec_lease)
348 def get_rspec(self, slice_xrn=None, login=None, version=None,
352 - a full advertisement rspec with the testbed resources if slice_xrn is
353 not specified.If a lease option is given, also returns the leases
354 scheduled on the testbed.
355 - a manifest Rspec with the leases and nodes in slice's leases if
356 slice_xrn is not None.
358 :param slice_xrn: srn of the slice
359 :type slice_xrn: string
360 :param login: user'uid (ldap login) on cortexlab
362 :param version: can be set to sfa or cortexlab
363 :type version: RSpecVersion
364 :param options: used to specify if the leases should also be included in
376 version_manager = VersionManager()
377 version = version_manager.get_version(version)
378 logger.debug("CortexlabAggregate \t get_rspec ***version %s \
379 version.type %s version.version %s options %s \r\n"
380 % (version, version.type, version.version, options))
382 if slice_xrn is None:
383 rspec_version = version_manager._get_version(version.type,
384 version.version, 'ad')
387 rspec_version = version_manager._get_version(
388 version.type, version.version, 'manifest')
390 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
391 if slice_xrn and slices is not None:
392 #Get user associated with this slice
393 #for one_slice in slices :
394 ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
395 # ldap_username = slices[0]['user']
396 tmp = ldap_username.split('.')
397 ldap_username = tmp[1]
398 logger.debug("CortexlabAggregate \tget_rspec **** \
399 LDAP USERNAME %s \r\n" \
401 #at this point sliver may be empty if no cortexlab job
402 #is running for this user/slice.
403 rspec = RSpec(version=rspec_version, user_options=options)
405 logger.debug("\r\n \r\n CortexlabAggregate \tget_rspec *** \
406 slice_xrn %s slices %s\r\n \r\n"
407 % (slice_xrn, slices))
409 if options is not None and 'list_leases' in options:
410 lease_option = options['list_leases']
412 #If no options are specified, at least print the resources
415 #lease_option = 'all'
417 if lease_option in ['all', 'resources']:
418 #if not options.get('list_leases') or options.get('list_leases')
419 #and options['list_leases'] != 'leases':
420 nodes = self.get_nodes(slices, slivers)
421 if slice_xrn and slices is None:
424 logger.debug("CortexlabAggregate \t lease_option %s \
425 get rspec ******* nodes %s"
426 % (lease_option, nodes))
428 sites_set = set([node['location']['site'] for node in nodes])
430 #In case creating a job, slice_xrn is not set to None
431 rspec.version.add_nodes(nodes)
432 if slice_xrn and slices is not None:
433 # #Get user associated with this slice
434 # #for one_slice in slices :
435 # ldap_username = slices[0]['reg_researchers']
436 # # ldap_username = slices[0]['user']
437 # tmp = ldap_username.split('.')
438 # ldap_username = tmp[1]
439 # # ldap_username = tmp[1].split('_')[0]
441 logger.debug("CortexlabAggregate \tget_rspec **** \
442 version type %s ldap_ user %s \r\n" \
443 % (version.type, ldap_username))
444 if version.type == "Iotlab":
445 rspec.version.add_connection_information(
446 ldap_username, sites_set)
448 default_sliver = slivers.get('default_sliver', [])
449 if default_sliver and len(nodes) is not 0:
450 #default_sliver_attribs = default_sliver.get('tags', [])
451 logger.debug("CortexlabAggregate \tget_rspec **** \
452 default_sliver%s \r\n" % (default_sliver))
453 for attrib in default_sliver:
454 rspec.version.add_default_sliver_attribute(
455 attrib, default_sliver[attrib])
457 if lease_option in ['all','leases']:
458 leases = self.get_all_leases(ldap_username)
459 rspec.version.add_leases(leases)
460 logger.debug("CortexlabAggregate \tget_rspec **** \
461 FINAL RSPEC %s \r\n" % (rspec.toxml()))