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):
72 Get the slices and the associated leases if any, from the cortexlab
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 cortexlab 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 cortexlab, only leases. The goal
90 is to be consistent with the SFA standard.
98 return (sfa_slice, slivers)
99 slice_urn = hrn_to_urn(slice_xrn, 'slice')
100 slice_hrn, _ = urn_to_hrn(slice_xrn)
101 slice_name = slice_hrn
103 # GetSlices always returns a list, even if there is only one element
104 slices = self.driver.testbed_shell.GetSlices(slice_filter=str(slice_name),
105 slice_filter_type='slice_hrn',
108 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
109 slice_hrn %s \r\n slices %s self.driver.hrn %s"
110 % (slice_hrn, slices, self.driver.hrn))
112 return (sfa_slice, slivers)
114 # sort slivers by node id , if there is a job
115 #and therefore, node allocated to this slice
116 # for sfa_slice in slices:
117 sfa_slice = slices[0]
119 node_ids_list = sfa_slice['node_ids']
121 logger.log_exc("CORTEXLABAGGREGATE \t \
122 get_slice_and_slivers No nodes in the slice \
127 for node in node_ids_list:
128 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
129 sliver_xrn.set_authority(self.driver.hrn)
130 sliver = Sliver({'sliver_id': sliver_xrn.urn,
131 'name': sfa_slice['hrn'],
132 'type': 'cortexlab-node',
135 slivers[node] = sliver
137 #Add default sliver attribute :
138 #connection information for cortexlab, assuming it is the same ssh
141 ldap_username = self.find_ldap_username_from_slice(sfa_slice)
143 if ldap_username is not None:
145 slivers['default_sliver'] = {'ssh': ssh_access,
146 'login': ldap_username}
149 logger.debug("CORTEXLABAGGREGATE api get_slice_and_slivers slivers %s "
151 return (slices, slivers)
154 def find_ldap_username_from_slice(self, sfa_slice):
155 researchers = [sfa_slice['reg_researchers'][0].__dict__]
158 ret = self.driver.testbed_shell.GetPersons(researchers)
160 ldap_username = ret[0]['uid']
166 def get_nodes(self, slices=None, slivers=[], options=None):
167 """Returns the nodes in the slice using the rspec format, with all the
170 Fetch the nodes ids in the slices dictionary and get all the nodes
171 properties from OAR. Makes a rspec dicitonary out of this and returns
172 it. If the slice does not have any job running or scheduled, that is
173 it has no reserved nodes, then returns an empty list.
175 :param slices: list of slices (record dictionaries)
176 :param slivers: the list of slivers in all the slices
177 :type slices: list of dicts
178 :type slivers: list of Sliver object (dictionaries)
179 :returns: An empty list if the slice has no reserved nodes, a rspec
180 list with all the nodes and their properties (a dict per node)
184 .. seealso:: get_slice_and_slivers
187 # NT: the semantic of this function is not clear to me :
188 # if slice is not defined, then all the nodes should be returned
189 # if slice is defined, we should return only the nodes that
190 # are part of this slice
191 # but what is the role of the slivers parameter ?
192 # So i assume that slice['node_ids'] will be the same as slivers for us
193 slice_nodes_list = []
194 if slices is not None:
195 for one_slice in slices:
197 slice_nodes_list = one_slice['node_ids']
198 # if we are dealing with a slice that has no node just
199 # return an empty list. In cortexlab a slice can have multiple
200 # jobs scheduled, so it either has at least one lease or
205 # get the granularity in second for the reservation system
206 grain = self.driver.testbed_shell.GetLeaseGranularity()
208 nodes = self.driver.testbed_shell.GetNodes()
212 #if slices, this means we got to list all the nodes given to this slice
213 # Make a list of all the nodes in the slice before getting their
217 logger.debug("CortexlabAggregate api get_nodes slices %s "
220 reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
221 logger.debug("CortexlabAggregate api get_nodes slice_nodes_list %s "
222 % (slice_nodes_list))
224 nodes_dict[node['node_id']] = node
225 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
231 cortexlab_xrn = cortexlab_xrn_object(self.driver.testbed_shell.root_auth,
233 rspec_node['component_id'] = cortexlab_xrn.urn
234 rspec_node['component_name'] = node['hostname']
235 rspec_node['component_manager_id'] = \
236 hrn_to_urn(self.driver.testbed_shell.root_auth,
239 # Iotlab's nodes are federated : there is only one authority
240 # for all Iotlab sites, registered in SFA.
241 # Removing the part including the site
242 # in authority_id SA 27/07/12
243 rspec_node['authority_id'] = rspec_node['component_manager_id']
246 # boot state removed if you need it uncomment
247 # rspec_node['boot_state'] = node['boot_state']
248 # if node['hostname'] in reserved_nodes:
249 # rspec_node['boot_state'] = "Reserved"
251 rspec_node['exclusive'] = 'true'
252 rspec_node['hardware_types'] = [HardwareType({'name':
256 # Location, mobility and position removed. If you need it go check
257 # get_nodes in iotlabaggregate.py
260 granularity = Granularity({'grain': grain})
261 rspec_node['granularity'] = granularity
262 rspec_node['tags'] = []
263 if node['hostname'] in slivers:
265 sliver = slivers[node['hostname']]
266 rspec_node['sliver_id'] = sliver['sliver_id']
267 rspec_node['client_id'] = node['hostname']
268 rspec_node['slivers'] = [sliver]
270 # slivers always provide the ssh service
271 login = Login({'authentication': 'ssh-keys',
272 'hostname': node['hostname'], 'port': '22',
273 'username': sliver['name']})
274 service = Services({'login': login})
275 rspec_node['services'] = [service]
276 rspec_nodes.append(rspec_node)
280 def get_all_leases(self, ldap_username):
283 Get list of lease dictionaries which all have the mandatory keys
284 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
285 All the leases running or scheduled are returned.
287 :param ldap_username: if ldap uid is not None, looks for the leases
288 belonging to this user.
289 :type ldap_username: string
290 :returns: rspec lease dictionary with keys lease_id, component_id,
291 slice_id, start_time, duration.
294 .. note::There is no filtering of leases within a given time frame.
295 All the running or scheduled leases are returned. options
296 removed SA 15/05/2013
301 #now = int(time.time())
302 #lease_filter = {'clip': now }
306 logger.debug("CortexlabAggregate get_all_leases ldap_username %s "
308 leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
309 grain = self.driver.testbed_shell.GetLeaseGranularity()
313 #as many leases as there are nodes in the job
314 for node in lease['reserved_nodes']:
315 rspec_lease = Lease()
316 rspec_lease['lease_id'] = lease['lease_id']
318 cortexlab_xrn = cortexlab_xrn_object(
319 self.driver.testbed_shell.root_auth, node)
320 rspec_lease['component_id'] = cortexlab_xrn.urn
321 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
322 #site, node['hostname'])
324 rspec_lease['slice_id'] = lease['slice_id']
326 #No info on the slice used in cortexlab_xp table
328 rspec_lease['start_time'] = lease['t_from']
329 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
331 rspec_leases.append(rspec_lease)
334 def get_rspec(self, slice_xrn=None, login=None, version=None,
338 - a full advertisement rspec with the testbed resources if slice_xrn is
339 not specified.If a lease option is given, also returns the leases
340 scheduled on the testbed.
341 - a manifest Rspec with the leases and nodes in slice's leases if
342 slice_xrn is not None.
344 :param slice_xrn: srn of the slice
345 :type slice_xrn: string
346 :param login: user'uid (ldap login) on cortexlab
348 :param version: can be set to sfa or cortexlab
349 :type version: RSpecVersion
350 :param options: used to specify if the leases should also be included in
362 version_manager = VersionManager()
363 version = version_manager.get_version(version)
364 logger.debug("CortexlabAggregate \t get_rspec ***version %s \
365 version.type %s version.version %s options %s \r\n"
366 % (version, version.type, version.version, options))
368 if slice_xrn is None:
369 rspec_version = version_manager._get_version(version.type,
370 version.version, 'ad')
373 rspec_version = version_manager._get_version(
374 version.type, version.version, 'manifest')
376 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
377 if slice_xrn and slices is not None:
378 #Get user associated with this slice
379 #for one_slice in slices :
380 ldap_username = self.find_ldap_username_from_slice(slices[0])
381 # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
382 # # ldap_username = slices[0]['user']
383 # tmp = ldap_username.split('.')
384 # ldap_username = tmp[1]
385 logger.debug("CortexlabAggregate \tget_rspec **** \
386 LDAP USERNAME %s \r\n" \
388 #at this point sliver may be empty if no cortexlab job
389 #is running for this user/slice.
390 rspec = RSpec(version=rspec_version, user_options=options)
392 logger.debug("\r\n \r\n CortexlabAggregate \tget_rspec *** \
393 slice_xrn %s slices %s\r\n \r\n"
394 % (slice_xrn, slices))
396 if options is not None and 'list_leases' in options:
397 lease_option = options['list_leases']
399 #If no options are specified, at least print the resources
402 #lease_option = 'all'
404 if lease_option in ['all', 'resources']:
405 #if not options.get('list_leases') or options.get('list_leases')
406 #and options['list_leases'] != 'leases':
407 nodes = self.get_nodes(slices, slivers)
408 if slice_xrn and slices is None:
411 logger.debug("CortexlabAggregate \t lease_option %s \
412 get rspec ******* nodes %s"
413 % (lease_option, nodes))
415 sites_set = set([node['location']['site'] for node in nodes])
417 #In case creating a job, slice_xrn is not set to None
418 rspec.version.add_nodes(nodes)
419 if slice_xrn and slices is not None:
420 # #Get user associated with this slice
421 # #for one_slice in slices :
422 # ldap_username = slices[0]['reg_researchers']
423 # # ldap_username = slices[0]['user']
424 # tmp = ldap_username.split('.')
425 # ldap_username = tmp[1]
426 # # ldap_username = tmp[1].split('_')[0]
428 logger.debug("CortexlabAggregate \tget_rspec **** \
429 version type %s ldap_ user %s \r\n" \
430 % (version.type, ldap_username))
431 if version.type == "Iotlab":
432 rspec.version.add_connection_information(
433 ldap_username, sites_set)
435 default_sliver = slivers.get('default_sliver', [])
436 if default_sliver and len(nodes) is not 0:
437 #default_sliver_attribs = default_sliver.get('tags', [])
438 logger.debug("CortexlabAggregate \tget_rspec **** \
439 default_sliver%s \r\n" % (default_sliver))
440 for attrib in default_sliver:
441 rspec.version.add_default_sliver_attribute(
442 attrib, default_sliver[attrib])
444 if lease_option in ['all','leases']:
445 leases = self.get_all_leases(ldap_username)
446 rspec.version.add_leases(leases)
447 logger.debug("CortexlabAggregate \tget_rspec **** \
448 FINAL RSPEC %s \r\n" % (rspec.toxml()))