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 rspec_node['radio'] = (node['archi'].split(':'))[1]
56 iotlab_xrn = Xrn('.'.join([self.driver.root_auth,
57 Xrn.escape(node['network_address'])]),
59 # rspec_node['boot_state'] = 'true'
60 if node['state'] == 'Absent' or \
61 node['state'] == 'Suspected' or \
62 node['state'] == 'Busy':
63 rspec_node['available'] = 'false'
65 rspec_node['available'] = 'true'
66 rspec_node['component_id'] = iotlab_xrn.urn
67 rspec_node['component_name'] = node['network_address']
68 rspec_node['component_manager_id'] = hrn_to_urn(self.driver.root_auth,
70 rspec_node['authority_id'] = rspec_node['component_manager_id']
71 rspec_node['exclusive'] = 'true'
72 rspec_node['hardware_types'] = \
73 [HardwareType({'name': node['archi']})]
74 location = IotlabLocation({'country': 'France',
75 'site': node['site']})
76 rspec_node['location'] = location
77 position = IotlabPosition()
78 for field in position:
79 position[field] = node[field]
80 granularity = Granularity({'grain': 30})
81 rspec_node['granularity'] = granularity
82 rspec_node['tags'] = []
85 def sliver_to_rspec_node(self, sliver):
86 """ Get node and sliver attributes """
87 rspec_node = self.node_to_rspec_node(sliver)
88 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
89 rspec_node['sliver_id'] = sliver['sliver_id']
90 rspec_sliver = Sliver({'sliver_id': sliver['sliver_id'],
91 'name': sliver['name'],
92 'type': sliver['archi'],
94 rspec_node['slivers'] = [rspec_sliver]
95 # slivers always provide the ssh service
96 login = Login({'authentication': 'ssh-keys',
97 'hostname': sliver['hostname'],
99 'username': sliver['name'],
100 'login': sliver['name']
102 service = ServicesElement({'login': login})
103 rspec_node['services'] = [service]
107 def rspec_node_to_geni_sliver(cls, rspec_node):
108 """ Get sliver status """
109 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
110 'geni_expires': rspec_node['expires'],
111 'geni_allocation_status': 'geni_allocated',
112 'geni_operational_status': 'geni_pending_allocation',
117 def list_resources(self, version=None, options=None):
119 list_resources method sends a RSpec with all Iot-LAB testbed nodes
120 and leases (OAR job submission). For leases we get all OAR jobs with
121 state Waiting or Running. If we have an entry in SFA database
122 (lease table) with OAR job id this submission was launched by SFA
123 driver, otherwise it was launched by Iot-LAB Webportal or CLI-tools
128 <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
130 "urn:publicid:IDN+iotlab+node+m3-10.devgrenoble.iot-lab.info"
131 exclusive="true" component_name="m3-10.devgrenoble.iot-lab.info">
132 <hardware_type name="iotlab-node"/>
133 <location country="France"/>
134 <granularity grain="60"/>
138 <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
139 start_time="1427792400" duration="30">
141 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
146 # pylint:disable=R0914,W0212
147 logger.warning("iotlabaggregate list_resources")
148 logger.warning("iotlabaggregate list_resources options %s" % options)
152 version_manager = VersionManager()
153 version = version_manager.get_version(version)
154 rspec_version = version_manager._get_version(version.type,
157 rspec = RSpec(version=rspec_version, user_options=options)
159 nodes = self.driver.shell.get_nodes()
160 reserved_nodes = self.driver.shell.get_reserved_nodes()
161 if 'error' not in nodes and 'error' not in reserved_nodes:
162 # convert nodes to rspec nodes
165 rspec_node = self.node_to_rspec_node(nodes[node])
166 rspec_nodes.append(rspec_node)
167 rspec.version.add_nodes(rspec_nodes)
171 # find OAR jobs id for all slices in SFA database
172 for lease in self.driver.api.dbsession().query(LeaseTable).all():
173 db_leases[lease.job_id] = lease.slice_hrn
175 for lease_id in reserved_nodes:
176 # onelab slice = job submission from OneLAB
177 if lease_id in db_leases:
178 reserved_nodes[lease_id]['slice_id'] = \
179 hrn_to_urn(db_leases[lease_id],
181 # iotlab slice = job submission from Iot-LAB
183 reserved_nodes[lease_id]['slice_id'] = \
184 hrn_to_urn(self.driver.root_auth + '.' +
185 reserved_nodes[lease_id]['owner']+"_slice",
187 leases.append(reserved_nodes[lease_id])
189 rspec_leases = self.leases_to_rspec_leases(leases)
190 rspec.version.add_leases(rspec_leases)
193 def get_slivers(self, urns, leases, nodes):
194 """ Get slivers attributes list """
195 logger.warning("iotlabaggregate get_slivers")
196 logger.warning("iotlabaggregate get_slivers urns %s" % urns)
199 for node in lease['resources']:
200 network_address = node.split(".")
201 sliver_node = nodes[node]
202 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
205 start_time = datetime.datetime.fromtimestamp(lease['date'])
206 duration = datetime.timedelta(seconds=int(lease['duration']))
207 sliver_node['expires'] = start_time + duration
208 sliver_node['sliver_id'] = Xrn(sliver_hrn,
210 # frontend SSH hostname
211 sliver_node['hostname'] = '.'.join(network_address[1:])
213 sliver_node['name'] = lease['owner']
214 slivers.append(sliver_node)
217 def _delete_db_lease(self, job_id):
218 """ Delete lease table row in SFA database """
219 logger.warning("iotlabdriver _delete_db_lease lease job_id : %s"
221 self.driver.api.dbsession().query(LeaseTable).filter(
222 LeaseTable.job_id == job_id).delete()
223 self.driver.api.dbsession().commit()
225 def describe(self, urns, version=None, options=None):
227 describe method returns slice slivers (allocated resources) and leases
228 (OAR job submission). We search in lease table of SFA database all OAR
229 jobs id for this slice and match OAR jobs with state Waiting or
230 Running. If OAR job id doesn't exist the experiment is terminated and
231 we delete the database table entry. Otherwise we add slivers and leases
235 geni_slivers : a list of allocated slivers with information about
236 their allocation and operational state
237 geni_urn : the URN of the slice in which the sliver has been
239 geni_rspec: a RSpec describing the allocated slivers and leases
245 <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
247 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"
248 client_id="m3-10.grenoble.iot-lab.info"
249 sliver_id="urn:publicid:IDN+iotlab+sliver+9953-m3-10"
250 exclusive="true" component_name="m3-10.grenoble.iot-lab.info">
251 <hardware_type name="iotlab-node"/>
252 <location country="France"/>
253 <granularity grain="30"/>
254 <sliver_type name="iotlab-exclusive"/>
256 <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
257 start_time="1427792428" duration="29">
259 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
265 # pylint:disable=R0914,W0212
266 logger.warning("iotlabaggregate describe")
267 logger.warning("iotlabaggregate describe urns : %s" % urns)
270 version_manager = VersionManager()
271 version = version_manager.get_version(version)
272 rspec_version = version_manager._get_version(version.type,
275 rspec = RSpec(version=rspec_version, user_options=options)
279 nodes = self.driver.shell.get_nodes()
280 reserved_nodes = self.driver.shell.get_reserved_nodes()
281 if 'error' not in nodes and 'error' not in reserved_nodes:
282 # find OAR jobs id for one slice in SFA database
283 db_leases = [(lease.job_id, lease.slice_hrn)
284 for lease in self.driver.api.dbsession()
286 .filter(LeaseTable.slice_hrn == xrn.hrn).all()]
289 for job_id, slice_hrn in db_leases:
290 # OAR job terminated, we delete entry in database
291 if job_id not in reserved_nodes:
292 self._delete_db_lease(job_id)
294 # onelab slice = job submission from OneLAB
295 lease = reserved_nodes[job_id]
296 lease['slice_id'] = hrn_to_urn(slice_hrn, 'slice')
300 slivers = self.get_slivers(urns, leases, nodes)
302 date = utcparse(slivers[0]['expires'])
303 rspec_expires = datetime_to_string(date)
305 rspec_expires = datetime_to_string(utcparse(time.time()))
306 rspec.xml.set('expires', rspec_expires)
310 for sliver in slivers:
311 rspec_node = self.sliver_to_rspec_node(sliver)
312 rspec_nodes.append(rspec_node)
313 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
314 geni_slivers.append(geni_sliver)
315 logger.warning("iotlabaggregate describe geni_slivers %s" %
317 rspec.version.add_nodes(rspec_nodes)
319 rspec_leases = self.leases_to_rspec_leases(leases)
320 logger.warning("iotlabaggregate describe rspec_leases %s" %
322 rspec.version.add_leases(rspec_leases)
324 return {'geni_urn': urns[0],
325 'geni_rspec': rspec.toxml(),
326 'geni_slivers': geni_slivers}