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 slice_hrn %s \r\n slices %s self.driver.hrn %s"
107 % (slice_hrn, 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 \
123 for node in node_ids_list:
124 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
125 sliver_xrn.set_authority(self.driver.hrn)
126 sliver = Sliver({'sliver_id': sliver_xrn.urn,
127 'name': sfa_slice['hrn'],
128 'type': 'iotlab-node',
131 slivers[node] = sliver
133 #Add default sliver attribute :
134 #connection information for iotlab
135 if get_authority(sfa_slice['hrn']) == self.driver.iotlab_api.root_auth:
136 tmp = sfa_slice['hrn'].split('.')
137 ldap_username = tmp[1].split('_')[0]
139 slivers['default_sliver'] = {'ssh': ssh_access,
140 'login': ldap_username}
142 #TODO get_slice_and_slivers Find the login of the external user
144 logger.debug("IOTLABAGGREGATE api get_slice_and_slivers slivers %s "
146 return (slices, slivers)
149 def get_nodes(self, slices=None, slivers=[], options=None):
150 """Returns the nodes in the slice using the rspec format, with all the
153 Fetch the nodes ids in the slices dictionary and get all the nodes
154 properties from OAR. Makes a rspec dicitonary out of this and returns
155 it. If the slice does not have any job running or scheduled, that is
156 it has no reserved nodes, then returns an empty list.
158 :param slices: list of slices (record dictionaries)
159 :param slivers: the list of slivers in all the slices
160 :type slices: list of dicts
161 :type slivers: list of Sliver object (dictionaries)
162 :returns: An empty list if the slice has no reserved nodes, a rspec
163 list with all the nodes and their properties (a dict per node)
167 .. seealso:: get_slice_and_slivers
170 # NT: the semantic of this function is not clear to me :
171 # if slice is not defined, then all the nodes should be returned
172 # if slice is defined, we should return only the nodes that
173 # are part of this slice
174 # but what is the role of the slivers parameter ?
175 # So i assume that slice['node_ids'] will be the same as slivers for us
176 slice_nodes_list = []
177 if slices is not None:
178 for one_slice in slices:
180 slice_nodes_list = one_slice['node_ids']
181 # if we are dealing with a slice that has no node just
182 # return an empty list. In iotlab a slice can have multiple
183 # jobs scheduled, so it either has at least one lease or
188 # get the granularity in second for the reservation system
189 grain = self.driver.iotlab_api.GetLeaseGranularity()
191 nodes = self.driver.iotlab_api.GetNodes()
195 #if slices, this means we got to list all the nodes given to this slice
196 # Make a list of all the nodes in the slice before getting their
200 logger.debug("IOTLABAGGREGATE api get_nodes slices %s "
203 reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
204 logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
205 % (slice_nodes_list))
207 nodes_dict[node['node_id']] = node
208 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
210 rspec_node = IotlabNode()
211 # xxx how to retrieve site['login_base']
212 #site_id=node['site_id']
213 #site=sites_dict[site_id]
215 # rspec_node['mobile'] = node['mobile']
216 rspec_node['archi'] = node['archi']
217 rspec_node['radio'] = node['radio']
219 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
221 rspec_node['component_id'] = iotlab_xrn.urn
222 rspec_node['component_name'] = node['hostname']
223 rspec_node['component_manager_id'] = \
224 hrn_to_urn(self.driver.iotlab_api.root_auth,
227 # Iotlab's nodes are federated : there is only one authority
228 # for all Iotlab sites, registered in SFA.
229 # Removing the part including the site
230 # in authority_id SA 27/07/12
231 rspec_node['authority_id'] = rspec_node['component_manager_id']
233 # do not include boot state (<available> element)
234 #in the manifest rspec
236 rspec_node['boot_state'] = node['boot_state']
237 if node['hostname'] in reserved_nodes:
238 rspec_node['boot_state'] = "Reserved"
239 rspec_node['exclusive'] = 'true'
240 rspec_node['hardware_types'] = [HardwareType({'name':
244 location = IotlabLocation({'country':'France', 'site':
246 rspec_node['location'] = location
248 # Adding mobility of the node in the rspec
249 mobility = IotlabMobility()
250 for field in mobility:
252 mobility[field] = node[field]
253 except KeyError, error:
254 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
255 mobility %s " % (error))
256 rspec_node['mobility'] = mobility
258 position = IotlabPosition()
259 for field in position:
261 position[field] = node[field]
262 except KeyError, error:
263 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
264 position %s " % (error))
266 rspec_node['position'] = position
267 #rspec_node['interfaces'] = []
270 granularity = Granularity({'grain': grain})
271 rspec_node['granularity'] = granularity
272 rspec_node['tags'] = []
273 if node['hostname'] in slivers:
275 sliver = slivers[node['hostname']]
276 rspec_node['sliver_id'] = sliver['sliver_id']
277 rspec_node['client_id'] = node['hostname']
278 rspec_node['slivers'] = [sliver]
280 # slivers always provide the ssh service
281 login = Login({'authentication': 'ssh-keys',
282 'hostname': node['hostname'], 'port': '22',
283 'username': sliver['name']})
284 service = Services({'login': login})
285 rspec_node['services'] = [service]
286 rspec_nodes.append(rspec_node)
290 def get_all_leases(self, ldap_username):
293 Get list of lease dictionaries which all have the mandatory keys
294 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
295 All the leases running or scheduled are returned.
297 :param ldap_username: if ldap uid is not None, looks for the leases
298 belonging to this user.
299 :type ldap_username: string
300 :returns: rspec lease dictionary with keys lease_id, component_id,
301 slice_id, start_time, duration.
304 .. note::There is no filtering of leases within a given time frame.
305 All the running or scheduled leases are returned. options
306 removed SA 15/05/2013
311 #now = int(time.time())
312 #lease_filter = {'clip': now }
315 #lease_filter.update({'name': slice_record['name']})
317 #leases = self.driver.iotlab_api.GetLeases(lease_filter)
319 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
321 leases = self.driver.iotlab_api.GetLeases(login=ldap_username)
322 grain = self.driver.iotlab_api.GetLeaseGranularity()
326 #as many leases as there are nodes in the job
327 for node in lease['reserved_nodes']:
328 rspec_lease = Lease()
329 rspec_lease['lease_id'] = lease['lease_id']
330 #site = node['site_id']
331 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
333 rspec_lease['component_id'] = iotlab_xrn.urn
334 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
335 #site, node['hostname'])
337 rspec_lease['slice_id'] = lease['slice_id']
339 #No info on the slice used in iotlab_xp table
341 rspec_lease['start_time'] = lease['t_from']
342 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
344 rspec_leases.append(rspec_lease)
347 def get_rspec(self, slice_xrn=None, login=None, version=None,
351 - a full advertisement rspec with the testbed resources if slice_xrn is
352 not specified.If a lease option is given, also returns the leases
353 scheduled on the testbed.
354 - a manifest Rspec with the leases and nodes in slice's leases if
355 slice_xrn is not None.
357 :param slice_xrn: srn of the slice
358 :type slice_xrn: string
359 :param login: user'uid (ldap login) on iotlab
361 :param version: can be set to sfa or iotlab
362 :type version: RSpecVersion
363 :param options: used to specify if the leases should also be included in
375 version_manager = VersionManager()
376 version = version_manager.get_version(version)
377 logger.debug("IotlabAggregate \t get_rspec ***version %s \
378 version.type %s version.version %s options %s \r\n"
379 % (version, version.type, version.version, options))
381 if slice_xrn is None:
382 rspec_version = version_manager._get_version(version.type,
383 version.version, 'ad')
386 rspec_version = version_manager._get_version(
387 version.type, version.version, 'manifest')
389 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
390 if slice_xrn and slices is not None:
391 #Get user associated with this slice
392 #for one_slice in slices :
393 ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
394 # ldap_username = slices[0]['user']
395 tmp = ldap_username.split('.')
396 ldap_username = tmp[1]
397 logger.debug("IotlabAggregate \tget_rspec **** \
398 LDAP USERNAME %s \r\n" \
400 #at this point sliver may be empty if no iotlab job
401 #is running for this user/slice.
402 rspec = RSpec(version=rspec_version, user_options=options)
404 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
405 slice_xrn %s slices %s\r\n \r\n"
406 % (slice_xrn, slices))
408 if options is not None and 'list_leases' in options:
409 lease_option = options['list_leases']
411 #If no options are specified, at least print the resources
414 #lease_option = 'all'
416 if lease_option in ['all', 'resources']:
417 #if not options.get('list_leases') or options.get('list_leases')
418 #and options['list_leases'] != 'leases':
419 nodes = self.get_nodes(slices, slivers)
420 if slice_xrn and slices is None:
423 logger.debug("IotlabAggregate \t lease_option %s \
424 get rspec ******* nodes %s"
425 % (lease_option, nodes))
427 sites_set = set([node['location']['site'] for node in nodes])
429 #In case creating a job, slice_xrn is not set to None
430 rspec.version.add_nodes(nodes)
431 if slice_xrn and slices is not None:
432 # #Get user associated with this slice
433 # #for one_slice in slices :
434 # ldap_username = slices[0]['reg_researchers']
435 # # ldap_username = slices[0]['user']
436 # tmp = ldap_username.split('.')
437 # ldap_username = tmp[1]
438 # # ldap_username = tmp[1].split('_')[0]
440 logger.debug("IotlabAggregate \tget_rspec **** \
441 version type %s ldap_ user %s \r\n" \
442 % (version.type, ldap_username))
443 if version.type == "Iotlab":
444 rspec.version.add_connection_information(
445 ldap_username, sites_set)
447 default_sliver = slivers.get('default_sliver', [])
448 if default_sliver and len(nodes) is not 0:
449 #default_sliver_attribs = default_sliver.get('tags', [])
450 logger.debug("IotlabAggregate \tget_rspec **** \
451 default_sliver%s \r\n" % (default_sliver))
452 for attrib in default_sliver:
453 rspec.version.add_default_sliver_attribute(
454 attrib, default_sliver[attrib])
456 if lease_option in ['all','leases']:
457 leases = self.get_all_leases(ldap_username)
458 rspec.version.add_leases(leases)
459 logger.debug("IotlabAggregate \tget_rspec **** \
460 FINAL RSPEC %s \r\n" % (rspec.toxml()))