2 """ aggregate class management """
4 from sfa.util.xrn import Xrn, hrn_to_urn
5 from sfa.util.sfatime import utcparse, datetime_to_string
6 from sfa.util.sfalogging import logger
7 from sfa.rspecs.rspec import RSpec
8 from sfa.rspecs.elements.hardware_type import HardwareType
9 from sfa.rspecs.elements.lease import Lease
10 from sfa.rspecs.elements.granularity import Granularity
11 from sfa.rspecs.version_manager import VersionManager
12 from sfa.rspecs.elements.services import ServicesElement
13 from sfa.rspecs.elements.login import Login
14 from sfa.rspecs.elements.sliver import Sliver
15 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition
16 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabNode
17 from sfa.rspecs.elements.versions.iotlabv1Node import IotlabLocation
18 from sfa.iotlab.iotlablease import LeaseTable
23 class IotLABAggregate(object):
25 SFA aggregate for Iot-LAB testbed
28 def __init__(self, driver):
31 def leases_to_rspec_leases(self, leases):
32 """ Get leases attributes list"""
35 for node in lease['resources']:
37 rspec_lease['lease_id'] = lease['id']
38 iotlab_xrn = Xrn('.'.join([self.driver.root_auth,
41 rspec_lease['component_id'] = iotlab_xrn.urn
42 rspec_lease['start_time'] = str(lease['date'])
44 duration = int(lease['duration']) / 60
45 rspec_lease['duration'] = duration
46 rspec_lease['slice_id'] = lease['slice_id']
47 rspec_leases.append(rspec_lease)
50 def node_to_rspec_node(self, node):
51 """ Get node attributes """
52 rspec_node = IotlabNode()
53 rspec_node['mobile'] = node['mobile']
54 rspec_node['archi'] = node['archi']
55 if ':' in node['archi']:
56 rspec_node['radio'] = (node['archi'].split(':'))[1]
58 rspec_node['radio'] = node['archi']
59 iotlab_xrn = Xrn('.'.join([self.driver.root_auth,
60 Xrn.escape(node['network_address'])]),
62 # rspec_node['boot_state'] = 'true'
63 if node['state'] == 'Absent' or \
64 node['state'] == 'Suspected' or \
65 node['state'] == 'Dead' or \
66 node['state'] == 'Busy':
67 rspec_node['available'] = 'false'
69 rspec_node['available'] = 'true'
70 rspec_node['component_id'] = iotlab_xrn.urn
71 rspec_node['component_name'] = node['network_address']
72 rspec_node['component_manager_id'] = hrn_to_urn(self.driver.root_auth,
74 rspec_node['authority_id'] = rspec_node['component_manager_id']
75 rspec_node['exclusive'] = 'true'
76 rspec_node['hardware_types'] = \
77 [HardwareType({'name': node['archi']})]
78 location = IotlabLocation({'country': 'France',
79 'site': node['site']})
80 rspec_node['location'] = location
81 position = IotlabPosition()
82 for field in position:
83 position[field] = node[field]
84 granularity = Granularity({'grain': 30})
85 rspec_node['granularity'] = granularity
86 rspec_node['tags'] = []
89 def sliver_to_rspec_node(self, sliver):
90 """ Get node and sliver attributes """
91 rspec_node = self.node_to_rspec_node(sliver)
92 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
93 rspec_node['sliver_id'] = sliver['sliver_id']
94 rspec_sliver = Sliver({'sliver_id': sliver['sliver_id'],
95 'name': sliver['name'],
96 'type': sliver['archi'],
98 rspec_node['slivers'] = [rspec_sliver]
99 # slivers always provide the ssh service
100 login = Login({'authentication': 'ssh-keys',
101 'hostname': sliver['hostname'],
103 'username': sliver['name'],
104 'login': sliver['name']
106 service = ServicesElement({'login': login})
107 rspec_node['services'] = [service]
111 def rspec_node_to_geni_sliver(cls, rspec_node):
112 """ Get sliver status """
113 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
114 'geni_expires': rspec_node['expires'],
115 'geni_allocation_status': 'geni_allocated',
116 'geni_operational_status': 'geni_pending_allocation',
121 def list_resources(self, version=None, options=None):
123 list_resources method sends a RSpec with all Iot-LAB testbed nodes
124 and leases (OAR job submission). For leases we get all OAR jobs with
125 state Waiting or Running. If we have an entry in SFA database
126 (lease table) with OAR job id this submission was launched by SFA
127 driver, otherwise it was launched by Iot-LAB Webportal or CLI-tools
132 <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
134 "urn:publicid:IDN+iotlab+node+m3-10.devgrenoble.iot-lab.info"
135 exclusive="true" component_name="m3-10.devgrenoble.iot-lab.info">
136 <hardware_type name="iotlab-node"/>
137 <location country="France"/>
138 <granularity grain="60"/>
142 <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
143 start_time="1427792400" duration="30">
145 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
150 # pylint:disable=R0914,W0212
151 logger.warning("iotlabaggregate list_resources")
152 logger.warning("iotlabaggregate list_resources options %s" % options)
156 version_manager = VersionManager()
157 version = version_manager.get_version(version)
158 rspec_version = version_manager._get_version(version.type,
161 rspec = RSpec(version=rspec_version, user_options=options)
163 nodes = self.driver.shell.get_nodes()
164 reserved_nodes = self.driver.shell.get_reserved_nodes()
165 if 'error' not in nodes and 'error' not in reserved_nodes:
166 # convert nodes to rspec nodes
169 rspec_node = self.node_to_rspec_node(nodes[node])
170 rspec_nodes.append(rspec_node)
171 rspec.version.add_nodes(rspec_nodes)
175 # find OAR jobs id for all slices in SFA database
176 for lease in self.driver.api.dbsession().query(LeaseTable).all():
177 db_leases[lease.job_id] = lease.slice_hrn
179 for lease_id in reserved_nodes:
180 # onelab slice = job submission from OneLAB
181 if lease_id in db_leases:
182 reserved_nodes[lease_id]['slice_id'] = \
183 hrn_to_urn(db_leases[lease_id],
185 # iotlab slice = job submission from Iot-LAB
187 reserved_nodes[lease_id]['slice_id'] = \
188 hrn_to_urn(self.driver.root_auth + '.' +
189 reserved_nodes[lease_id][
192 leases.append(reserved_nodes[lease_id])
194 rspec_leases = self.leases_to_rspec_leases(leases)
195 rspec.version.add_leases(rspec_leases)
198 def get_slivers(self, urns, leases, nodes):
199 """ Get slivers attributes list """
200 logger.warning("iotlabaggregate get_slivers")
201 logger.warning("iotlabaggregate get_slivers urns %s" % urns)
204 for node in lease['resources']:
205 network_address = node.split(".")
206 sliver_node = nodes[node]
207 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
210 start_time = datetime.datetime.fromtimestamp(lease['date'])
211 duration = datetime.timedelta(seconds=int(lease['duration']))
212 sliver_node['expires'] = start_time + duration
213 sliver_node['sliver_id'] = Xrn(sliver_hrn,
215 # frontend SSH hostname
216 sliver_node['hostname'] = '.'.join(network_address[1:])
218 sliver_node['name'] = lease['owner']
219 slivers.append(sliver_node)
222 def _delete_db_lease(self, job_id):
223 """ Delete lease table row in SFA database """
224 logger.warning("iotlabdriver _delete_db_lease lease job_id : %s"
226 self.driver.api.dbsession().query(LeaseTable).filter(
227 LeaseTable.job_id == job_id).delete()
228 self.driver.api.dbsession().commit()
230 def describe(self, urns, version=None, options=None):
232 describe method returns slice slivers (allocated resources) and leases
233 (OAR job submission). We search in lease table of SFA database all OAR
234 jobs id for this slice and match OAR jobs with state Waiting or
235 Running. If OAR job id doesn't exist the experiment is terminated and
236 we delete the database table entry. Otherwise we add slivers and leases
240 geni_slivers : a list of allocated slivers with information about
241 their allocation and operational state
242 geni_urn : the URN of the slice in which the sliver has been
244 geni_rspec: a RSpec describing the allocated slivers and leases
250 <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
252 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"
253 client_id="m3-10.grenoble.iot-lab.info"
254 sliver_id="urn:publicid:IDN+iotlab+sliver+9953-m3-10"
255 exclusive="true" component_name="m3-10.grenoble.iot-lab.info">
256 <hardware_type name="iotlab-node"/>
257 <location country="France"/>
258 <granularity grain="30"/>
259 <sliver_type name="iotlab-exclusive"/>
261 <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
262 start_time="1427792428" duration="29">
264 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
270 # pylint:disable=R0914,W0212
271 logger.warning("iotlabaggregate describe")
272 logger.warning("iotlabaggregate describe urns : %s" % urns)
275 version_manager = VersionManager()
276 version = version_manager.get_version(version)
277 rspec_version = version_manager._get_version(version.type,
280 rspec = RSpec(version=rspec_version, user_options=options)
284 nodes = self.driver.shell.get_nodes()
285 reserved_nodes = self.driver.shell.get_reserved_nodes()
286 if 'error' not in nodes and 'error' not in reserved_nodes:
287 # find OAR jobs id for one slice in SFA database
288 db_leases = [(lease.job_id, lease.slice_hrn)
289 for lease in self.driver.api.dbsession()
291 .filter(LeaseTable.slice_hrn == xrn.hrn).all()]
294 for job_id, slice_hrn in db_leases:
295 # OAR job terminated, we delete entry in database
296 if job_id not in reserved_nodes:
297 self._delete_db_lease(job_id)
299 # onelab slice = job submission from OneLAB
300 lease = reserved_nodes[job_id]
301 lease['slice_id'] = hrn_to_urn(slice_hrn, 'slice')
305 slivers = self.get_slivers(urns, leases, nodes)
307 date = utcparse(slivers[0]['expires'])
308 rspec_expires = datetime_to_string(date)
310 rspec_expires = datetime_to_string(utcparse(time.time()))
311 rspec.xml.set('expires', rspec_expires)
315 for sliver in slivers:
316 rspec_node = self.sliver_to_rspec_node(sliver)
317 rspec_nodes.append(rspec_node)
318 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
319 geni_slivers.append(geni_sliver)
320 logger.warning("iotlabaggregate describe geni_slivers %s" %
322 rspec.version.add_nodes(rspec_nodes)
324 rspec_leases = self.leases_to_rspec_leases(leases)
325 logger.warning("iotlabaggregate describe rspec_leases %s" %
327 rspec.version.add_leases(rspec_leases)
329 return {'geni_urn': urns[0],
330 'geni_rspec': rspec.toxml(),
331 'geni_slivers': geni_slivers}