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.iotlabv1Node import IotlabPosition, \
19 IotlabNode, IotlabLocation, IotlabMobility
21 from sfa.util.sfalogging import logger
22 from sfa.util.xrn import Xrn
25 def iotlab_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 iotlab_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 iotlab node's xrn
50 return Xrn('.'.join([root_auth, Xrn.escape(hostname)]), type='node')
53 class IotlabAggregate:
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 iotlab
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 iotlab 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 iotlab, 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 # GetSlices always returns a list, even if there is only one element
102 slices = self.driver.testbed_shell.GetSlices(slice_filter=str(slice_name),
103 slice_filter_type='slice_hrn',
106 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
107 slice_hrn %s \r\n slices %s self.driver.hrn %s"
108 % (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:
115 sfa_slice = slices[0]
117 node_ids_list = sfa_slice['node_ids']
119 logger.log_exc("IOTLABAGGREGATE \t \
120 get_slice_and_slivers No nodes in the slice \
125 for node in node_ids_list:
126 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
127 sliver_xrn.set_authority(self.driver.hrn)
128 sliver = Sliver({'sliver_id': sliver_xrn.urn,
129 'name': sfa_slice['hrn'],
130 'type': 'iotlab-node',
133 slivers[node] = sliver
135 #Add default sliver attribute :
136 #connection information for iotlab
137 # if get_authority(sfa_slice['hrn']) == self.driver.testbed_shell.root_auth:
138 # tmp = sfa_slice['hrn'].split('.')
139 # ldap_username = tmp[1].split('_')[0]
141 # slivers['default_sliver'] = {'ssh': ssh_access,
142 # 'login': ldap_username}
144 ldap_username = self.find_ldap_username_from_slice(sfa_slice)
146 if ldap_username is not None:
148 slivers['default_sliver'] = {'ssh': ssh_access,
149 'login': ldap_username}
152 logger.debug("IOTLABAGGREGATE api get_slice_and_slivers slivers %s "
154 return (slices, slivers)
156 def find_ldap_username_from_slice(self, sfa_slice):
157 researchers = [sfa_slice['reg_researchers'][0].__dict__]
160 ret = self.driver.testbed_shell.GetPersons(researchers)
162 ldap_username = ret[0]['uid']
167 def get_nodes(self, slices=None, slivers=[], options=None):
168 """Returns the nodes in the slice using the rspec format, with all the
171 Fetch the nodes ids in the slices dictionary and get all the nodes
172 properties from OAR. Makes a rspec dicitonary out of this and returns
173 it. If the slice does not have any job running or scheduled, that is
174 it has no reserved nodes, then returns an empty list.
176 :param slices: list of slices (record dictionaries)
177 :param slivers: the list of slivers in all the slices
178 :type slices: list of dicts
179 :type slivers: list of Sliver object (dictionaries)
180 :returns: An empty list if the slice has no reserved nodes, a rspec
181 list with all the nodes and their properties (a dict per node)
185 .. seealso:: get_slice_and_slivers
188 # NT: the semantic of this function is not clear to me :
189 # if slice is not defined, then all the nodes should be returned
190 # if slice is defined, we should return only the nodes that
191 # are part of this slice
192 # but what is the role of the slivers parameter ?
193 # So i assume that slice['node_ids'] will be the same as slivers for us
194 slice_nodes_list = []
195 if slices is not None:
196 for one_slice in slices:
198 slice_nodes_list = one_slice['node_ids']
199 # if we are dealing with a slice that has no node just
200 # return an empty list. In iotlab a slice can have multiple
201 # jobs scheduled, so it either has at least one lease or
206 # get the granularity in second for the reservation system
207 grain = self.driver.testbed_shell.GetLeaseGranularity()
209 nodes = self.driver.testbed_shell.GetNodes()
213 #if slices, this means we got to list all the nodes given to this slice
214 # Make a list of all the nodes in the slice before getting their
218 logger.debug("IOTLABAGGREGATE api get_nodes slices %s "
221 reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
222 logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
223 % (slice_nodes_list))
225 nodes_dict[node['node_id']] = node
226 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
228 rspec_node = IotlabNode()
229 # xxx how to retrieve site['login_base']
230 #site_id=node['site_id']
231 #site=sites_dict[site_id]
233 # rspec_node['mobile'] = node['mobile']
234 rspec_node['archi'] = node['archi']
235 rspec_node['radio'] = node['radio']
237 iotlab_xrn = iotlab_xrn_object(self.driver.testbed_shell.root_auth,
239 rspec_node['component_id'] = iotlab_xrn.urn
240 rspec_node['component_name'] = node['hostname']
241 rspec_node['component_manager_id'] = \
242 hrn_to_urn(self.driver.testbed_shell.root_auth,
245 # Iotlab's nodes are federated : there is only one authority
246 # for all Iotlab sites, registered in SFA.
247 # Removing the part including the site
248 # in authority_id SA 27/07/12
249 rspec_node['authority_id'] = rspec_node['component_manager_id']
251 # do not include boot state (<available> element)
252 #in the manifest rspec
254 rspec_node['boot_state'] = node['boot_state']
255 if node['hostname'] in reserved_nodes:
256 rspec_node['boot_state'] = "Reserved"
257 rspec_node['exclusive'] = 'true'
258 rspec_node['hardware_types'] = [HardwareType({'name':
262 location = IotlabLocation({'country':'France', 'site':
264 rspec_node['location'] = location
266 # Adding mobility of the node in the rspec
267 mobility = IotlabMobility()
268 for field in mobility:
270 mobility[field] = node[field]
271 except KeyError, error:
272 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
273 mobility %s " % (error))
274 rspec_node['mobility'] = mobility
276 position = IotlabPosition()
277 for field in position:
279 position[field] = node[field]
280 except KeyError, error:
281 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
282 position %s " % (error))
284 rspec_node['position'] = position
285 #rspec_node['interfaces'] = []
288 granularity = Granularity({'grain': grain})
289 rspec_node['granularity'] = granularity
290 rspec_node['tags'] = []
291 if node['hostname'] in slivers:
293 sliver = slivers[node['hostname']]
294 rspec_node['sliver_id'] = sliver['sliver_id']
295 rspec_node['client_id'] = node['hostname']
296 rspec_node['slivers'] = [sliver]
298 # slivers always provide the ssh service
299 login = Login({'authentication': 'ssh-keys',
300 'hostname': node['hostname'], 'port': '22',
301 'username': sliver['name']})
302 service = Services({'login': login})
303 rspec_node['services'] = [service]
304 rspec_nodes.append(rspec_node)
308 def get_all_leases(self, ldap_username):
311 Get list of lease dictionaries which all have the mandatory keys
312 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
313 All the leases running or scheduled are returned.
315 :param ldap_username: if ldap uid is not None, looks for the leases
316 belonging to this user.
317 :type ldap_username: string
318 :returns: rspec lease dictionary with keys lease_id, component_id,
319 slice_id, start_time, duration.
322 .. note::There is no filtering of leases within a given time frame.
323 All the running or scheduled leases are returned. options
324 removed SA 15/05/2013
329 #now = int(time.time())
330 #lease_filter = {'clip': now }
333 #lease_filter.update({'name': slice_record['name']})
335 #leases = self.driver.testbed_shell.GetLeases(lease_filter)
337 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
339 leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
340 grain = self.driver.testbed_shell.GetLeaseGranularity()
344 #as many leases as there are nodes in the job
345 for node in lease['reserved_nodes']:
346 rspec_lease = Lease()
347 rspec_lease['lease_id'] = lease['lease_id']
348 #site = node['site_id']
349 iotlab_xrn = iotlab_xrn_object(self.driver.testbed_shell.root_auth,
351 rspec_lease['component_id'] = iotlab_xrn.urn
352 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
353 #site, node['hostname'])
355 rspec_lease['slice_id'] = lease['slice_id']
357 #No info on the slice used in testbed_xp table
359 rspec_lease['start_time'] = lease['t_from']
360 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
362 rspec_leases.append(rspec_lease)
365 def get_rspec(self, slice_xrn=None, login=None, version=None,
369 - a full advertisement rspec with the testbed resources if slice_xrn is
370 not specified.If a lease option is given, also returns the leases
371 scheduled on the testbed.
372 - a manifest Rspec with the leases and nodes in slice's leases if
373 slice_xrn is not None.
375 :param slice_xrn: srn of the slice
376 :type slice_xrn: string
377 :param login: user'uid (ldap login) on iotlab
379 :param version: can be set to sfa or iotlab
380 :type version: RSpecVersion
381 :param options: used to specify if the leases should also be included in
393 version_manager = VersionManager()
394 version = version_manager.get_version(version)
395 logger.debug("IotlabAggregate \t get_rspec ***version %s \
396 version.type %s version.version %s options %s \r\n"
397 % (version, version.type, version.version, options))
399 if slice_xrn is None:
400 rspec_version = version_manager._get_version(version.type,
401 version.version, 'ad')
404 rspec_version = version_manager._get_version(
405 version.type, version.version, 'manifest')
407 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
408 if slice_xrn and slices is not None:
409 #Get user associated with this slice
410 #for one_slice in slices :
411 ldap_username = self.find_ldap_username_from_slice(slices[0])
412 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
413 # # ldap_username = slices[0]['user']
414 # tmp = ldap_username.split('.')
415 # ldap_username = tmp[1]
416 logger.debug("IotlabAggregate \tget_rspec **** \
417 LDAP USERNAME %s \r\n" \
419 #at this point sliver may be empty if no iotlab job
420 #is running for this user/slice.
421 rspec = RSpec(version=rspec_version, user_options=options)
423 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
424 slice_xrn %s slices %s\r\n \r\n"
425 % (slice_xrn, slices))
427 if options is not None and 'list_leases' in options:
428 lease_option = options['list_leases']
430 #If no options are specified, at least print the resources
433 #lease_option = 'all'
435 if lease_option in ['all', 'resources']:
436 #if not options.get('list_leases') or options.get('list_leases')
437 #and options['list_leases'] != 'leases':
438 nodes = self.get_nodes(slices, slivers)
439 if slice_xrn and slices is None:
442 logger.debug("IotlabAggregate \t lease_option %s \
443 get rspec ******* nodes %s"
444 % (lease_option, nodes))
446 sites_set = set([node['location']['site'] for node in nodes])
448 #In case creating a job, slice_xrn is not set to None
449 rspec.version.add_nodes(nodes)
450 if slice_xrn and slices is not None:
451 # #Get user associated with this slice
452 # #for one_slice in slices :
453 # ldap_username = slices[0]['reg_researchers']
454 # # ldap_username = slices[0]['user']
455 # tmp = ldap_username.split('.')
456 # ldap_username = tmp[1]
457 # # ldap_username = tmp[1].split('_')[0]
459 logger.debug("IotlabAggregate \tget_rspec **** \
460 version type %s ldap_ user %s \r\n" \
461 % (version.type, ldap_username))
462 if version.type == "Iotlab":
463 rspec.version.add_connection_information(
464 ldap_username, sites_set)
466 default_sliver = slivers.get('default_sliver', [])
467 if default_sliver and len(nodes) is not 0:
468 #default_sliver_attribs = default_sliver.get('tags', [])
469 logger.debug("IotlabAggregate \tget_rspec **** \
470 default_sliver%s \r\n" % (default_sliver))
471 for attrib in default_sliver:
472 rspec.version.add_default_sliver_attribute(
473 attrib, default_sliver[attrib])
475 if lease_option in ['all','leases']:
476 leases = self.get_all_leases(ldap_username)
477 rspec.version.add_leases(leases)
478 logger.debug("IotlabAggregate \tget_rspec **** \
479 FINAL RSPEC %s \r\n" % (rspec.toxml()))