1 from sfa.util.xrn import hrn_to_urn, urn_to_hrn, get_authority
3 from sfa.rspecs.rspec import RSpec
4 #from sfa.rspecs.elements.location import Location
5 from sfa.rspecs.elements.hardware_type import HardwareType
6 from sfa.rspecs.elements.login import Login
7 from sfa.rspecs.elements.services import Services
8 from sfa.rspecs.elements.sliver import Sliver
9 from sfa.rspecs.elements.lease import Lease
10 from sfa.rspecs.elements.granularity import Granularity
11 from sfa.rspecs.version_manager import VersionManager
13 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition, \
14 IotlabNode, IotlabLocation
16 from sfa.util.sfalogging import logger
17 from sfa.util.xrn import Xrn
20 def iotlab_xrn_to_hostname(xrn):
21 """Returns a node's hostname from its xrn.
22 :param xrn: The nodes xrn identifier.
23 :type xrn: Xrn (from sfa.util.xrn)
25 :returns: node's hostname.
29 return Xrn.unescape(Xrn(xrn=xrn, type='node').get_leaf())
32 def iotlab_xrn_object(root_auth, hostname):
33 """Creates a valid xrn object from the node's hostname and the authority
36 :param hostname: the node's hostname.
37 :param root_auth: the SFA root authority.
38 :type hostname: string
39 :type root_auth: string
41 :returns: the iotlab node's xrn
45 return Xrn('.'.join([root_auth, Xrn.escape(hostname)]), type='node')
48 class IotlabAggregate:
49 """Aggregate manager class for Iotlab. """
62 def __init__(self, driver):
65 def get_slice_and_slivers(self, slice_xrn, login=None):
67 Get the slices and the associated leases if any from the iotlab
68 testbed. One slice can have mutliple leases.
69 For each slice, get the nodes in the associated lease
70 and create a sliver with the necessary info and insert it into the
71 sliver dictionary, keyed on the node hostnames.
72 Returns a dict of slivers based on the sliver's node_id.
76 :param slice_xrn: xrn of the slice
77 :param login: user's login on iotlab ldap
79 :type slice_xrn: string
81 :returns: a list of slices dict and a list of Sliver object
84 .. note: There is no real slivers in iotlab, only leases. The goal
85 is to be consistent with the SFA standard.
91 return (sfa_slice, slivers)
92 slice_urn = hrn_to_urn(slice_xrn, 'slice')
93 slice_hrn, _ = urn_to_hrn(slice_xrn)
94 slice_name = slice_hrn
96 slices = self.driver.iotlab_api.GetSlices(slice_filter=str(slice_name),
97 slice_filter_type='slice_hrn',
100 logger.debug("IotlabAggregate api \tget_slice_and_slivers \
101 sfa_slice %s \r\n slices %s self.driver.hrn %s"
102 % (sfa_slice, slices, self.driver.hrn))
104 return (sfa_slice, slivers)
106 # sort slivers by node id , if there is a job
107 #and therefore, node allocated to this slice
108 for sfa_slice in slices:
110 node_ids_list = sfa_slice['node_ids']
112 logger.log_exc("IOTLABAGGREGATE \t \
113 get_slice_and_slivers No nodes in the slice \
117 for node in node_ids_list:
118 sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
119 sliver_xrn.set_authority(self.driver.hrn)
120 sliver = Sliver({'sliver_id': sliver_xrn.urn,
121 'name': sfa_slice['hrn'],
122 'type': 'iotlab-node',
125 slivers[node] = sliver
127 #Add default sliver attribute :
128 #connection information for iotlab
129 if get_authority(sfa_slice['hrn']) == self.driver.iotlab_api.root_auth:
130 tmp = sfa_slice['hrn'].split('.')
131 ldap_username = tmp[1].split('_')[0]
133 slivers['default_sliver'] = {'ssh': ssh_access,
134 'login': ldap_username}
136 #TODO get_slice_and_slivers Find the login of the external user
138 logger.debug("IOTLABAGGREGATE api get_slice_and_slivers slivers %s "
140 return (slices, slivers)
144 def get_nodes(self, slices=None, slivers=[], options=None):
145 """Returns the nodes in the slice using the rspec format, with all the
148 Fetch the nodes ids in the slices dictionary and get all the nodes
149 properties from OAR. Makes a rspec dicitonary out of this and returns
150 it. If the slice does not have any job running or scheduled, that is
151 it has no reserved nodes, then returns an empty list.
153 :param slices: list of slices (record dictionaries)
154 :param slivers: the list of slivers in all the slices
155 :type slices: list of dicts
156 :type slivers: list of Sliver object (dictionaries)
157 :returns: An empty list if the slice has no reserved nodes, a rspec
158 list with all the nodes and their properties (a dict per node)
162 .. seealso:: get_slice_and_slivers
165 # NT: the semantic of this function is not clear to me :
166 # if slice is not defined, then all the nodes should be returned
167 # if slice is defined, we should return only the nodes that
168 # are part of this slice
169 # but what is the role of the slivers parameter ?
170 # So i assume that slice['node_ids'] will be the same as slivers for us
171 if slices is not None:
172 for one_slice in slices:
174 slice_nodes_list = one_slice['node_ids']
175 # if we are dealing with a slice that has no node just
176 # return an empty list. In iotlab a slice can have multiple
177 # jobs scheduled, so it either has at least one lease or
182 # get the granularity in second for the reservation system
183 grain = self.driver.iotlab_api.GetLeaseGranularity()
185 nodes = self.driver.iotlab_api.GetNodes()
189 #if slices, this means we got to list all the nodes given to this slice
190 # Make a list of all the nodes in the slice before getting their
193 slice_nodes_list = []
194 logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
198 reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
199 logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list %s "
200 % (slice_nodes_list))
202 nodes_dict[node['node_id']] = node
203 if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
205 rspec_node = IotlabNode()
206 # xxx how to retrieve site['login_base']
207 #site_id=node['site_id']
208 #site=sites_dict[site_id]
210 rspec_node['mobile'] = node['mobile']
211 rspec_node['archi'] = node['archi']
212 rspec_node['radio'] = node['radio']
214 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
216 rspec_node['component_id'] = iotlab_xrn.urn
217 rspec_node['component_name'] = node['hostname']
218 rspec_node['component_manager_id'] = \
219 hrn_to_urn(self.driver.iotlab_api.root_auth,
222 # Iotlab's nodes are federated : there is only one authority
223 # for all Iotlab sites, registered in SFA.
224 # Removing the part including the site
225 # in authority_id SA 27/07/12
226 rspec_node['authority_id'] = rspec_node['component_manager_id']
228 # do not include boot state (<available> element)
229 #in the manifest rspec
232 rspec_node['boot_state'] = node['boot_state']
233 if node['hostname'] in reserved_nodes:
234 rspec_node['boot_state'] = "Reserved"
235 rspec_node['exclusive'] = 'true'
236 rspec_node['hardware_types'] = [HardwareType({'name': \
240 location = IotlabLocation({'country':'France', 'site': \
242 rspec_node['location'] = location
245 position = IotlabPosition()
246 for field in position :
248 position[field] = node[field]
249 except KeyError, error :
250 logger.log_exc("IOTLABAGGREGATE\t get_nodes \
251 position %s "% (error))
253 rspec_node['position'] = position
254 #rspec_node['interfaces'] = []
257 granularity = Granularity({'grain': grain})
258 rspec_node['granularity'] = granularity
259 rspec_node['tags'] = []
260 if node['hostname'] in slivers:
262 sliver = slivers[node['hostname']]
263 rspec_node['sliver_id'] = sliver['sliver_id']
264 rspec_node['client_id'] = node['hostname']
265 rspec_node['slivers'] = [sliver]
267 # slivers always provide the ssh service
268 login = Login({'authentication': 'ssh-keys', \
269 'hostname': node['hostname'], 'port':'22', \
270 'username': sliver['name']})
271 service = Services({'login': login})
272 rspec_node['services'] = [service]
273 rspec_nodes.append(rspec_node)
277 def get_all_leases(self):
280 Get list of lease dictionaries which all have the mandatory keys
281 ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
282 All the leases running or scheduled are returned.
284 :returns: rspec lease dictionary with keys lease_id, component_id,
285 slice_id, start_time, duration.
288 .. note::There is no filtering of leases within a given time frame.
289 All the running or scheduled leases are returned. options
290 removed SA 15/05/2013
295 #now = int(time.time())
296 #lease_filter = {'clip': now }
299 #lease_filter.update({'name': slice_record['name']})
301 #leases = self.driver.iotlab_api.GetLeases(lease_filter)
302 leases = self.driver.iotlab_api.GetLeases()
303 grain = self.driver.iotlab_api.GetLeaseGranularity()
307 #as many leases as there are nodes in the job
308 for node in lease['reserved_nodes']:
309 rspec_lease = Lease()
310 rspec_lease['lease_id'] = lease['lease_id']
311 #site = node['site_id']
312 iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
314 rspec_lease['component_id'] = iotlab_xrn.urn
315 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
316 #site, node['hostname'])
318 rspec_lease['slice_id'] = lease['slice_id']
320 #No info on the slice used in iotlab_xp table
322 rspec_lease['start_time'] = lease['t_from']
323 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
325 rspec_leases.append(rspec_lease)
328 def get_rspec(self, slice_xrn=None, login=None, version=None,
333 - a full advertisement rspec with the testbed resources if slice_xrn
334 is not specified.If a lease option is given, also returns the
335 leases scheduled on the testbed.
336 - a manifest Rspec with the leases and nodes in slice's leases
337 if slice_xrn is not None.
339 :param slice_xrn: srn of the slice
340 :param login: user'uid (ldap login) on iotlab
341 :param version: can be set to sfa or iotlab
342 :param options: used to specify if the leases should also be included in
344 :type slice_xrn: string
346 :type version: RSpecVersion
356 version_manager = VersionManager()
357 version = version_manager.get_version(version)
358 logger.debug("IotlabAggregate \t get_rspec ***version %s \
359 version.type %s version.version %s options %s \r\n"
360 % (version, version.type, version.version, options))
362 if slice_xrn is None:
363 rspec_version = version_manager._get_version(version.type,
364 version.version, 'ad')
367 rspec_version = version_manager._get_version(
368 version.type, version.version, 'manifest')
370 slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
371 #at this point sliver may be empty if no iotlab job
372 #is running for this user/slice.
373 rspec = RSpec(version=rspec_version, user_options=options)
375 logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
376 slice_xrn %s slices %s\r\n \r\n"
377 % (slice_xrn, slices))
379 if options is not None:
380 lease_option = options['list_leases']
382 #If no options are specified, at least print the resources
385 #lease_option = 'all'
387 if lease_option in ['all', 'resources']:
388 #if not options.get('list_leases') or options.get('list_leases')
389 #and options['list_leases'] != 'leases':
390 nodes = self.get_nodes(slices, slivers)
391 logger.debug("\r\n \r\n IotlabAggregate \t lease_option %s \
392 get rspec ******* nodes %s"
393 % (lease_option, nodes[0]))
395 sites_set = set([node['location']['site'] for node in nodes])
397 #In case creating a job, slice_xrn is not set to None
398 rspec.version.add_nodes(nodes)
400 #Get user associated with this slice
401 #for one_slice in slices :
402 ldap_username = slices[0]['hrn']
403 tmp = ldap_username.split('.')
404 ldap_username = tmp[1].split('_')[0]
406 if version.type == "Iotlab":
407 rspec.version.add_connection_information(
408 ldap_username, sites_set)
410 default_sliver = slivers.get('default_sliver', [])
412 #default_sliver_attribs = default_sliver.get('tags', [])
413 logger.debug("IotlabAggregate \tget_rspec **** \
414 default_sliver%s \r\n" % (default_sliver))
415 for attrib in default_sliver:
416 rspec.version.add_default_sliver_attribute(
417 attrib, default_sliver[attrib])
419 if lease_option in ['all','leases']:
420 leases = self.get_all_leases()
421 rspec.version.add_leases(leases)