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 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):
71 """Returns a dict of slivers based on the sliver's node_id.
73 Get the slices and the associated leases if any, from the cortexlab
74 testbed. One slice can have mutliple leases. For each slice, get the
75 nodes in the associated lease and create a sliver with the necessary
76 info and insert it into the sliver dictionary, keyed on the node
77 hostnames.Called by get_rspec.
80 :param slice_xrn: xrn of the slice
81 :param login: user's login on cortexlab ldap
83 :type slice_xrn: string
85 :returns: a list of slices dict and a list of Sliver object
88 .. note: There is no real slivers in cortexlab, only leases. The goal
89 is to be consistent with the SFA standard.
97 return (sfa_slice, slivers)
98 slice_urn = hrn_to_urn(slice_xrn, 'slice')
99 slice_hrn, _ = urn_to_hrn(slice_xrn)
100 slice_name = slice_hrn
102 # GetSlices always returns a list, even if there is only one element
103 slices = self.driver.testbed_shell.GetSlices(slice_filter=str(slice_name),
104 slice_filter_type='slice_hrn',
107 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
108 slice_hrn %s \r\n slices %s self.driver.hrn %s"
109 % (slice_hrn, slices, self.driver.hrn))
111 return (sfa_slice, slivers)
113 # sort slivers by node id , if there is a job
114 #and therefore, node allocated to this slice
115 # for sfa_slice in slices:
116 sfa_slice = slices[0]
118 node_ids_list = sfa_slice['node_ids']
120 logger.log_exc("CORTEXLABAGGREGATE \t \
121 get_slice_and_slivers No nodes in the slice \
126 for node in node_ids_list:
127 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
128 sliver_xrn.set_authority(self.driver.hrn)
129 sliver = Sliver({'sliver_id': sliver_xrn.urn,
130 'name': sfa_slice['hrn'],
131 'type': 'cortexlab-node',
134 slivers[node] = sliver
136 #Add default sliver attribute :
137 #connection information for cortexlab, assuming it is the same ssh
140 ldap_username = self.find_ldap_username_from_slice(sfa_slice)
142 if ldap_username is not None:
144 slivers['default_sliver'] = {'ssh': ssh_access,
145 'login': ldap_username}
148 logger.debug("CORTEXLABAGGREGATE api get_slice_and_slivers slivers %s "
150 return (slices, slivers)
153 def find_ldap_username_from_slice(self, sfa_slice):
154 researchers = [sfa_slice['reg_researchers'][0].__dict__]
157 ret = self.driver.testbed_shell.GetPersons(researchers)
159 ldap_username = ret[0]['uid']
165 def get_nodes(self, slices=None, slivers=[], options=None):
166 """Returns the nodes in the slice using the rspec format, with all the
169 Fetch the nodes ids in the slices dictionary and get all the nodes
170 properties from OAR. Makes a rspec dicitonary out of this and returns
171 it. If the slice does not have any job running or scheduled, that is
172 it has no reserved nodes, then returns an empty list.
174 :param slices: list of slices (record dictionaries)
175 :param slivers: the list of slivers in all the slices
176 :type slices: list of dicts
177 :type slivers: list of Sliver object (dictionaries)
178 :returns: An empty list if the slice has no reserved nodes, a rspec
179 list with all the nodes and their properties (a dict per node)
183 .. seealso:: get_slice_and_slivers
186 # NT: the semantic of this function is not clear to me :
187 # if slice is not defined, then all the nodes should be returned
188 # if slice is defined, we should return only the nodes that
189 # are part of this slice
190 # but what is the role of the slivers parameter ?
191 # So i assume that slice['node_ids'] will be the same as slivers for us
192 slice_nodes_list = []
193 if slices is not None:
194 for one_slice in slices:
196 slice_nodes_list = one_slice['node_ids']
197 # if we are dealing with a slice that has no node just
198 # return an empty list. In cortexlab a slice can have multiple
199 # jobs scheduled, so it either has at least one lease or
204 # get the granularity in second for the reservation system
205 grain = self.driver.testbed_shell.GetLeaseGranularity()
207 nodes = self.driver.testbed_shell.GetNodes()
211 #if slices, this means we got to list all the nodes given to this slice
212 # Make a list of all the nodes in the slice before getting their
216 logger.debug("CortexlabAggregate api get_nodes slices %s "
219 reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
220 logger.debug("CortexlabAggregate api get_nodes slice_nodes_list %s "
221 % (slice_nodes_list))
223 nodes_dict[node['node_id']] = node
224 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
230 cortexlab_xrn = cortexlab_xrn_object(self.driver.testbed_shell.root_auth,
232 rspec_node['component_id'] = cortexlab_xrn.urn
233 rspec_node['component_name'] = node['hostname']
234 rspec_node['component_manager_id'] = \
235 hrn_to_urn(self.driver.testbed_shell.root_auth,
238 # Iotlab's nodes are federated : there is only one authority
239 # for all Iotlab sites, registered in SFA.
240 # Removing the part including the site
241 # in authority_id SA 27/07/12
242 rspec_node['authority_id'] = rspec_node['component_manager_id']
245 # boot state removed if you need it uncomment
246 # rspec_node['boot_state'] = node['boot_state']
247 # if node['hostname'] in reserved_nodes:
248 # rspec_node['boot_state'] = "Reserved"
250 rspec_node['exclusive'] = 'true'
251 rspec_node['hardware_types'] = [HardwareType({'name':
255 # Location, mobility and position removed. If you need it go check
256 # get_nodes in iotlabaggregate.py
259 granularity = Granularity({'grain': grain})
260 rspec_node['granularity'] = granularity
261 rspec_node['tags'] = []
262 if node['hostname'] in slivers:
264 sliver = slivers[node['hostname']]
265 rspec_node['sliver_id'] = sliver['sliver_id']
266 rspec_node['client_id'] = node['hostname']
267 rspec_node['slivers'] = [sliver]
269 # slivers always provide the ssh service
270 login = Login({'authentication': 'ssh-keys',
271 'hostname': node['hostname'], 'port': '22',
272 'username': sliver['name']})
273 service = Services({'login': login})
274 rspec_node['services'] = [service]
275 rspec_nodes.append(rspec_node)
279 def get_all_leases(self, ldap_username):
281 Get list of lease dictionaries which all have the following
282 mandatory keys ('lease_id', 'hostname', 'site_id', 'name', 'start_time',
283 'duration'). All the leases running or scheduled are returned.
285 :param ldap_username: if ldap uid is not None, looks for the leases
286 belonging to this user.
287 :type ldap_username: string
288 :returns: rspec lease dictionary with keys lease_id, component_id,
289 slice_id, start_time, duration.
292 .. note::There is no filtering of leases within a given time frame.
293 All the running or scheduled leases are returned. options
294 removed SA 15/05/2013
299 #now = int(time.time())
300 #lease_filter = {'clip': now }
304 logger.debug("CortexlabAggregate get_all_leases ldap_username %s "
306 leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
307 grain = self.driver.testbed_shell.GetLeaseGranularity()
311 #as many leases as there are nodes in the job
312 for node in lease['reserved_nodes']:
313 rspec_lease = Lease()
314 rspec_lease['lease_id'] = lease['lease_id']
316 cortexlab_xrn = cortexlab_xrn_object(
317 self.driver.testbed_shell.root_auth, node)
318 rspec_lease['component_id'] = cortexlab_xrn.urn
319 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
320 #site, node['hostname'])
322 rspec_lease['slice_id'] = lease['slice_id']
324 #No info on the slice used in cortexlab_xp table
326 rspec_lease['start_time'] = lease['t_from']
327 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
329 rspec_leases.append(rspec_lease)
332 def get_rspec(self, slice_xrn=None, login=None, version=None,
336 - a full advertisement rspec with the testbed resources if slice_xrn is
337 not specified.If a lease option is given, also returns the leases
338 scheduled on the testbed.
339 - a manifest Rspec with the leases and nodes in slice's leases if
340 slice_xrn is not None.
342 :param slice_xrn: srn of the slice
343 :type slice_xrn: string
344 :param login: user'uid (ldap login) on cortexlab
346 :param version: can be set to sfa or cortexlab
347 :type version: RSpecVersion
348 :param options: used to specify if the leases should also be included in
360 version_manager = VersionManager()
361 version = version_manager.get_version(version)
362 logger.debug("CortexlabAggregate \t get_rspec ***version %s \
363 version.type %s version.version %s options %s \r\n"
364 % (version, version.type, version.version, options))
366 if slice_xrn is None:
367 rspec_version = version_manager._get_version(version.type,
368 version.version, 'ad')
371 rspec_version = version_manager._get_version(
372 version.type, version.version, 'manifest')
374 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
375 if slice_xrn and slices is not None:
376 #Get user associated with this slice
377 #for one_slice in slices :
378 ldap_username = self.find_ldap_username_from_slice(slices[0])
379 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
380 # # ldap_username = slices[0]['user']
381 # tmp = ldap_username.split('.')
382 # ldap_username = tmp[1]
383 logger.debug("CortexlabAggregate \tget_rspec **** \
384 LDAP USERNAME %s \r\n" \
386 #at this point sliver may be empty if no cortexlab job
387 #is running for this user/slice.
388 rspec = RSpec(version=rspec_version, user_options=options)
390 logger.debug("\r\n \r\n CortexlabAggregate \tget_rspec *** \
391 slice_xrn %s slices %s\r\n \r\n"
392 % (slice_xrn, slices))
394 if options is not None and 'list_leases' in options:
395 lease_option = options['list_leases']
397 #If no options are specified, at least print the resources
400 #lease_option = 'all'
402 if lease_option in ['all', 'resources']:
403 #if not options.get('list_leases') or options.get('list_leases')
404 #and options['list_leases'] != 'leases':
405 nodes = self.get_nodes(slices, slivers)
406 if slice_xrn and slices is None:
409 logger.debug("CortexlabAggregate \t lease_option %s \
410 get rspec ******* nodes %s"
411 % (lease_option, nodes))
413 sites_set = set([node['location']['site'] for node in nodes])
415 #In case creating a job, slice_xrn is not set to None
416 rspec.version.add_nodes(nodes)
417 if slice_xrn and slices is not None:
418 # #Get user associated with this slice
419 # #for one_slice in slices :
420 # ldap_username = slices[0]['reg_researchers']
421 # # ldap_username = slices[0]['user']
422 # tmp = ldap_username.split('.')
423 # ldap_username = tmp[1]
424 # # ldap_username = tmp[1].split('_')[0]
426 logger.debug("CortexlabAggregate \tget_rspec **** \
427 version type %s ldap_ user %s \r\n" \
428 % (version.type, ldap_username))
429 if version.type == "Iotlab":
430 rspec.version.add_connection_information(
431 ldap_username, sites_set)
433 default_sliver = slivers.get('default_sliver', [])
434 if default_sliver and len(nodes) is not 0:
435 #default_sliver_attribs = default_sliver.get('tags', [])
436 logger.debug("CortexlabAggregate \tget_rspec **** \
437 default_sliver%s \r\n" % (default_sliver))
438 for attrib in default_sliver:
439 rspec.version.add_default_sliver_attribute(
440 attrib, default_sliver[attrib])
442 if lease_option in ['all','leases']:
443 leases = self.get_all_leases(ldap_username)
444 rspec.version.add_leases(leases)
445 logger.debug("CortexlabAggregate \tget_rspec **** \
446 FINAL RSPEC %s \r\n" % (rspec.toxml()))