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 slices = self.driver.iotlab_api.GetSlices(slice_filter=str(slice_name),
102 slice_filter_type='slice_hrn',
105 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
106 sfa_slice %s \r\n slices %s self.driver.hrn %s"
107 % (sfa_slice, slices, self.driver.hrn))
109 return (sfa_slice, slivers)
111 # sort slivers by node id , if there is a job
112 #and therefore, node allocated to this slice
113 for sfa_slice in slices:
115 node_ids_list = sfa_slice['node_ids']
117 logger.log_exc("IOTLABAGGREGATE \t \
118 get_slice_and_slivers No nodes in the slice \
122 for node in node_ids_list:
123 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
124 sliver_xrn.set_authority(self.driver.hrn)
125 sliver = Sliver({'sliver_id': sliver_xrn.urn,
126 'name': sfa_slice['hrn'],
127 'type': 'iotlab-node',
130 slivers[node] = sliver
132 #Add default sliver attribute :
133 #connection information for iotlab
134 if get_authority(sfa_slice['hrn']) == self.driver.iotlab_api.root_auth:
135 tmp = sfa_slice['hrn'].split('.')
136 ldap_username = tmp[1].split('_')[0]
138 slivers['default_sliver'] = {'ssh': ssh_access,
139 'login': ldap_username}
141 #TODO get_slice_and_slivers Find the login of the external user
143 logger.debug("IOTLABAGGREGATE api get_slice_and_slivers slivers %s "
145 return (slices, slivers)
148 def get_nodes(self, slices=None, slivers=[], options=None):
149 """Returns the nodes in the slice using the rspec format, with all the
152 Fetch the nodes ids in the slices dictionary and get all the nodes
153 properties from OAR. Makes a rspec dicitonary out of this and returns
154 it. If the slice does not have any job running or scheduled, that is
155 it has no reserved nodes, then returns an empty list.
157 :param slices: list of slices (record dictionaries)
158 :param slivers: the list of slivers in all the slices
159 :type slices: list of dicts
160 :type slivers: list of Sliver object (dictionaries)
161 :returns: An empty list if the slice has no reserved nodes, a rspec
162 list with all the nodes and their properties (a dict per node)
166 .. seealso:: get_slice_and_slivers
169 # NT: the semantic of this function is not clear to me :
170 # if slice is not defined, then all the nodes should be returned
171 # if slice is defined, we should return only the nodes that
172 # are part of this slice
173 # but what is the role of the slivers parameter ?
174 # So i assume that slice['node_ids'] will be the same as slivers for us
175 slice_nodes_list = []
176 if slices is not None:
177 for one_slice in slices:
179 slice_nodes_list = one_slice['node_ids']
180 # if we are dealing with a slice that has no node just
181 # return an empty list. In iotlab a slice can have multiple
182 # jobs scheduled, so it either has at least one lease or
187 # get the granularity in second for the reservation system
188 grain = self.driver.iotlab_api.GetLeaseGranularity()
190 nodes = self.driver.iotlab_api.GetNodes()
194 #if slices, this means we got to list all the nodes given to this slice
195 # Make a list of all the nodes in the slice before getting their
199 logger.debug("IOTLABAGGREGATE api get_nodes slices %s "
202 reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
203 logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
204 % (slice_nodes_list))
206 nodes_dict[node['node_id']] = node
207 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
209 rspec_node = IotlabNode()
210 # xxx how to retrieve site['login_base']
211 #site_id=node['site_id']
212 #site=sites_dict[site_id]
214 # rspec_node['mobile'] = node['mobile']
215 rspec_node['archi'] = node['archi']
216 rspec_node['radio'] = node['radio']
218 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
220 rspec_node['component_id'] = iotlab_xrn.urn
221 rspec_node['component_name'] = node['hostname']
222 rspec_node['component_manager_id'] = \
223 hrn_to_urn(self.driver.iotlab_api.root_auth,
226 # Iotlab's nodes are federated : there is only one authority
227 # for all Iotlab sites, registered in SFA.
228 # Removing the part including the site
229 # in authority_id SA 27/07/12
230 rspec_node['authority_id'] = rspec_node['component_manager_id']
232 # do not include boot state (<available> element)
233 #in the manifest rspec
235 rspec_node['boot_state'] = node['boot_state']
236 if node['hostname'] in reserved_nodes:
237 rspec_node['boot_state'] = "Reserved"
238 rspec_node['exclusive'] = 'true'
239 rspec_node['hardware_types'] = [HardwareType({'name':
243 location = IotlabLocation({'country':'France', 'site':
245 rspec_node['location'] = location
247 # Adding mobility of the node in the rspec
248 mobility = IotlabMobility()
249 for field in mobility:
251 mobility[field] = node[field]
252 except KeyError, error:
253 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
254 mobility %s " % (error))
255 rspec_node['mobility'] = mobility
257 position = IotlabPosition()
258 for field in position:
260 position[field] = node[field]
261 except KeyError, error:
262 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
263 position %s " % (error))
265 rspec_node['position'] = position
266 #rspec_node['interfaces'] = []
269 granularity = Granularity({'grain': grain})
270 rspec_node['granularity'] = granularity
271 rspec_node['tags'] = []
272 if node['hostname'] in slivers:
274 sliver = slivers[node['hostname']]
275 rspec_node['sliver_id'] = sliver['sliver_id']
276 rspec_node['client_id'] = node['hostname']
277 rspec_node['slivers'] = [sliver]
279 # slivers always provide the ssh service
280 login = Login({'authentication': 'ssh-keys',
281 'hostname': node['hostname'], 'port': '22',
282 'username': sliver['name']})
283 service = Services({'login': login})
284 rspec_node['services'] = [service]
285 rspec_nodes.append(rspec_node)
289 def get_all_leases(self, ldap_username):
292 Get list of lease dictionaries which all have the mandatory keys
293 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
294 All the leases running or scheduled are returned.
296 :param ldap_username: if ldap uid is not None, looks for the leases
297 belonging to this user.
298 :type ldap_username: string
299 :returns: rspec lease dictionary with keys lease_id, component_id,
300 slice_id, start_time, duration.
303 .. note::There is no filtering of leases within a given time frame.
304 All the running or scheduled leases are returned. options
305 removed SA 15/05/2013
310 #now = int(time.time())
311 #lease_filter = {'clip': now }
314 #lease_filter.update({'name': slice_record['name']})
316 #leases = self.driver.iotlab_api.GetLeases(lease_filter)
318 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
320 leases = self.driver.iotlab_api.GetLeases(login=ldap_username)
321 grain = self.driver.iotlab_api.GetLeaseGranularity()
325 #as many leases as there are nodes in the job
326 for node in lease['reserved_nodes']:
327 rspec_lease = Lease()
328 rspec_lease['lease_id'] = lease['lease_id']
329 #site = node['site_id']
330 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
332 rspec_lease['component_id'] = iotlab_xrn.urn
333 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
334 #site, node['hostname'])
336 rspec_lease['slice_id'] = lease['slice_id']
338 #No info on the slice used in iotlab_xp table
340 rspec_lease['start_time'] = lease['t_from']
341 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
343 rspec_leases.append(rspec_lease)
346 def get_rspec(self, slice_xrn=None, login=None, version=None,
350 - a full advertisement rspec with the testbed resources if slice_xrn is
351 not specified.If a lease option is given, also returns the leases
352 scheduled on the testbed.
353 - a manifest Rspec with the leases and nodes in slice's leases if
354 slice_xrn is not None.
356 :param slice_xrn: srn of the slice
357 :type slice_xrn: string
358 :param login: user'uid (ldap login) on iotlab
360 :param version: can be set to sfa or iotlab
361 :type version: RSpecVersion
362 :param options: used to specify if the leases should also be included in
374 version_manager = VersionManager()
375 version = version_manager.get_version(version)
376 logger.debug("IotlabAggregate \t get_rspec ***version %s \
377 version.type %s version.version %s options %s \r\n"
378 % (version, version.type, version.version, options))
380 if slice_xrn is None:
381 rspec_version = version_manager._get_version(version.type,
382 version.version, 'ad')
385 rspec_version = version_manager._get_version(
386 version.type, version.version, 'manifest')
388 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
389 if slice_xrn and slices is not None:
390 #Get user associated with this slice
391 #for one_slice in slices :
392 ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
393 # ldap_username = slices[0]['user']
394 tmp = ldap_username.split('.')
395 ldap_username = tmp[1]
396 logger.debug("IotlabAggregate \tget_rspec **** \
397 LDAP USERNAME %s \r\n" \
399 #at this point sliver may be empty if no iotlab job
400 #is running for this user/slice.
401 rspec = RSpec(version=rspec_version, user_options=options)
403 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
404 slice_xrn %s slices %s\r\n \r\n"
405 % (slice_xrn, slices))
407 if options is not None and 'list_leases' in options:
408 lease_option = options['list_leases']
410 #If no options are specified, at least print the resources
413 #lease_option = 'all'
415 if lease_option in ['all', 'resources']:
416 #if not options.get('list_leases') or options.get('list_leases')
417 #and options['list_leases'] != 'leases':
418 nodes = self.get_nodes(slices, slivers)
419 if slice_xrn and slices is None:
422 logger.debug("IotlabAggregate \t lease_option %s \
423 get rspec ******* nodes %s"
424 % (lease_option, nodes))
426 sites_set = set([node['location']['site'] for node in nodes])
428 #In case creating a job, slice_xrn is not set to None
429 rspec.version.add_nodes(nodes)
430 if slice_xrn and slices is not None:
431 # #Get user associated with this slice
432 # #for one_slice in slices :
433 # ldap_username = slices[0]['reg_researchers']
434 # # ldap_username = slices[0]['user']
435 # tmp = ldap_username.split('.')
436 # ldap_username = tmp[1]
437 # # ldap_username = tmp[1].split('_')[0]
439 logger.debug("IotlabAggregate \tget_rspec **** \
440 version type %s ldap_ user %s \r\n" \
441 % (version.type, ldap_username))
442 if version.type == "Iotlab":
443 rspec.version.add_connection_information(
444 ldap_username, sites_set)
446 default_sliver = slivers.get('default_sliver', [])
447 if default_sliver and len(nodes) is not 0:
448 #default_sliver_attribs = default_sliver.get('tags', [])
449 logger.debug("IotlabAggregate \tget_rspec **** \
450 default_sliver%s \r\n" % (default_sliver))
451 for attrib in default_sliver:
452 rspec.version.add_default_sliver_attribute(
453 attrib, default_sliver[attrib])
455 if lease_option in ['all','leases']:
456 leases = self.get_all_leases(ldap_username)
457 rspec.version.add_leases(leases)
458 logger.debug("IotlabAggregate \tget_rspec **** \
459 FINAL RSPEC %s \r\n" % (rspec.toxml()))