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
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 "
204 reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
205 logger.debug("IOTLABAGGREGATE 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 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
222 rspec_node['component_id'] = iotlab_xrn.urn
223 rspec_node['component_name'] = node['hostname']
224 rspec_node['component_manager_id'] = \
225 hrn_to_urn(self.driver.iotlab_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
238 rspec_node['boot_state'] = node['boot_state']
239 if node['hostname'] in reserved_nodes:
240 rspec_node['boot_state'] = "Reserved"
241 rspec_node['exclusive'] = 'true'
242 rspec_node['hardware_types'] = [HardwareType({'name': \
246 location = IotlabLocation({'country':'France', 'site': \
248 rspec_node['location'] = location
251 position = IotlabPosition()
252 for field in position :
254 position[field] = node[field]
255 except KeyError, error :
256 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
257 position %s "% (error))
259 rspec_node['position'] = position
260 #rspec_node['interfaces'] = []
263 granularity = Granularity({'grain': grain})
264 rspec_node['granularity'] = granularity
265 rspec_node['tags'] = []
266 if node['hostname'] in slivers:
268 sliver = slivers[node['hostname']]
269 rspec_node['sliver_id'] = sliver['sliver_id']
270 rspec_node['client_id'] = node['hostname']
271 rspec_node['slivers'] = [sliver]
273 # slivers always provide the ssh service
274 login = Login({'authentication': 'ssh-keys', \
275 'hostname': node['hostname'], 'port':'22', \
276 'username': sliver['name']})
277 service = Services({'login': login})
278 rspec_node['services'] = [service]
279 rspec_nodes.append(rspec_node)
283 def get_all_leases(self, ldap_username):
286 Get list of lease dictionaries which all have the mandatory keys
287 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
288 All the leases running or scheduled are returned.
290 :param ldap_username: if ldap uid is not None, looks for the leases
291 belonging to this user.
292 :type ldap_username: string
293 :returns: rspec lease dictionary with keys lease_id, component_id,
294 slice_id, start_time, duration.
297 .. note::There is no filtering of leases within a given time frame.
298 All the running or scheduled leases are returned. options
299 removed SA 15/05/2013
304 #now = int(time.time())
305 #lease_filter = {'clip': now }
308 #lease_filter.update({'name': slice_record['name']})
310 #leases = self.driver.iotlab_api.GetLeases(lease_filter)
312 logger.debug("IOTLABAGGREGATE get_all_leases ldap_username %s "
314 leases = self.driver.iotlab_api.GetLeases(login=ldap_username)
315 grain = self.driver.iotlab_api.GetLeaseGranularity()
319 #as many leases as there are nodes in the job
320 for node in lease['reserved_nodes']:
321 rspec_lease = Lease()
322 rspec_lease['lease_id'] = lease['lease_id']
323 #site = node['site_id']
324 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
326 rspec_lease['component_id'] = iotlab_xrn.urn
327 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
328 #site, node['hostname'])
330 rspec_lease['slice_id'] = lease['slice_id']
332 #No info on the slice used in iotlab_xp table
334 rspec_lease['start_time'] = lease['t_from']
335 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
337 rspec_leases.append(rspec_lease)
340 def get_rspec(self, slice_xrn=None, login=None, version=None,
344 - a full advertisement rspec with the testbed resources if slice_xrn is
345 not specified.If a lease option is given, also returns the leases
346 scheduled on the testbed.
347 - a manifest Rspec with the leases and nodes in slice's leases if
348 slice_xrn is not None.
350 :param slice_xrn: srn of the slice
351 :type slice_xrn: string
352 :param login: user'uid (ldap login) on iotlab
354 :param version: can be set to sfa or iotlab
355 :type version: RSpecVersion
356 :param options: used to specify if the leases should also be included in
368 version_manager = VersionManager()
369 version = version_manager.get_version(version)
370 logger.debug("IotlabAggregate \t get_rspec ***version %s \
371 version.type %s version.version %s options %s \r\n"
372 % (version, version.type, version.version, options))
374 if slice_xrn is None:
375 rspec_version = version_manager._get_version(version.type,
376 version.version, 'ad')
379 rspec_version = version_manager._get_version(
380 version.type, version.version, 'manifest')
382 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
383 if slice_xrn and slices is not None:
384 #Get user associated with this slice
385 #for one_slice in slices :
386 ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
387 # ldap_username = slices[0]['user']
388 tmp = ldap_username.split('.')
389 ldap_username = tmp[1]
390 logger.debug("IotlabAggregate \tget_rspec **** \
391 LDAP USERNAME %s \r\n" \
393 #at this point sliver may be empty if no iotlab job
394 #is running for this user/slice.
395 rspec = RSpec(version=rspec_version, user_options=options)
397 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
398 slice_xrn %s slices %s\r\n \r\n"
399 % (slice_xrn, slices))
401 if options is not None:
402 lease_option = options['list_leases']
404 #If no options are specified, at least print the resources
407 #lease_option = 'all'
409 if lease_option in ['all', 'resources']:
410 #if not options.get('list_leases') or options.get('list_leases')
411 #and options['list_leases'] != 'leases':
412 nodes = self.get_nodes(slices, slivers)
414 logger.debug("IotlabAggregate \t lease_option %s \
415 get rspec ******* nodes %s"
416 % (lease_option, nodes))
418 sites_set = set([node['location']['site'] for node in nodes])
420 #In case creating a job, slice_xrn is not set to None
421 rspec.version.add_nodes(nodes)
422 if slice_xrn and slices is not None:
423 # #Get user associated with this slice
424 # #for one_slice in slices :
425 # ldap_username = slices[0]['reg_researchers']
426 # # ldap_username = slices[0]['user']
427 # tmp = ldap_username.split('.')
428 # ldap_username = tmp[1]
429 # # ldap_username = tmp[1].split('_')[0]
431 logger.debug("IotlabAggregate \tget_rspec **** \
432 version type %s ldap_ user %s \r\n" \
433 % (version.type, ldap_username))
434 if version.type == "Iotlab":
435 rspec.version.add_connection_information(
436 ldap_username, sites_set)
438 default_sliver = slivers.get('default_sliver', [])
439 if default_sliver and len(nodes) is not 0:
440 #default_sliver_attribs = default_sliver.get('tags', [])
441 logger.debug("IotlabAggregate \tget_rspec **** \
442 default_sliver%s \r\n" % (default_sliver))
443 for attrib in default_sliver:
444 rspec.version.add_default_sliver_attribute(
445 attrib, default_sliver[attrib])
447 if lease_option in ['all','leases']:
448 leases = self.get_all_leases(ldap_username)
449 rspec.version.add_leases(leases)
450 logger.debug("IotlabAggregate \tget_rspec **** \
451 FINAL RSPEC %s \r\n" % (rspec.toxml()))