add unused driver method
[sfa.git] / sfa / iotlab / iotlabdriver.py
1 # -*- coding:utf-8 -*-
2 """ driver class management """
3
4 from sfa.util.sfalogging import logger
5 from sfa.util.xrn import Xrn, urn_to_hrn
6 from sfa.rspecs.version_manager import VersionManager
7 from sfa.rspecs.rspec import RSpec
8 from sfa.managers.driver import Driver
9 from sfa.iotlab.iotlabshell import IotLABShell
10 from sfa.iotlab.iotlabaggregate import IotLABAggregate
11 from sfa.iotlab.iotlablease import LeaseTable
12
13 class IotLabDriver(Driver):
14     """
15     SFA driver for Iot-LAB testbed
16     """
17
18     def __init__(self, api):
19         Driver.__init__(self, api)
20         config = api.config
21         self.api = api
22         self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
23         self.shell = IotLABShell()
24         # need by sfa driver
25         self.cache = None
26
27     def check_sliver_credentials(self, creds, urns):
28         """ Not used and need by SFA """
29         pass
30
31     ########################################
32     ########## registry oriented
33     ########################################
34
35     ##########
36     def register(self, sfa_record, hrn, pub_key):
37         logger.warning("iotlabdriver register : not implemented")
38         return -1
39
40
41     ##########
42     def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
43         logger.warning("iotlabdriver update : not implemented")
44         return True
45
46
47     ##########
48     def remove(self, sfa_record):
49         logger.warning("iotlabdriver remove : not implemented")
50         return True
51
52
53     ########################################
54     ########## aggregate oriented
55     ########################################
56
57     def provision(self, urns, options=None):
58         logger.warning("iotlabdriver provision : not implemented")
59         version_manager = VersionManager()
60         opt = options['geni_rspec_version']
61         rspec_version = version_manager.get_version(opt)
62         return self.describe(urns, rspec_version, options=options)
63
64
65     def delete(self, urns, options=None):
66         logger.warning("iotlabdriver delete : not implemented")
67         geni_slivers = []
68         return geni_slivers
69
70
71     def aggregate_version(self):
72         logger.warning("iotlabdriver aggregate_version")
73         version_manager = VersionManager()
74         ad_rspec_versions = []
75         request_rspec_versions = []
76         for rspec_version in version_manager.versions:
77             if rspec_version.content_type in ['*', 'ad']:
78                 ad_rspec_versions.append(rspec_version.to_dict())
79             if rspec_version.content_type in ['*', 'request']:
80                 request_rspec_versions.append(rspec_version.to_dict())
81         return {
82             'testbed': self.hrn,
83             'geni_request_rspec_versions': request_rspec_versions,
84             'geni_ad_rspec_versions': ad_rspec_versions}
85
86
87     def list_resources(self, version=None, options=None):
88         logger.warning("iotlabdriver list_resources")
89         if not options:
90             options = {}
91         aggregate = IotLABAggregate(self)
92         rspec = aggregate.list_resources(version=version, options=options)
93         return rspec
94
95
96     def describe(self, urns, version, options=None):
97         logger.warning("iotlabdriver describe")
98         if not options:
99             options = {}
100         aggregate = IotLABAggregate(self)
101         return aggregate.describe(urns, version=version, options=options)
102
103
104     def status(self, urns, options=None):
105         logger.warning("iotlabdriver status")
106         aggregate = IotLABAggregate(self)
107         desc = aggregate.describe(urns, version='GENI 3')
108         status = {'geni_urn': desc['geni_urn'],
109                   'geni_slivers': desc['geni_slivers']}
110         return status
111
112
113     def _get_users(self):
114         """ Get all users """
115         ret = self.shell.get_users()
116         if 'error' in ret:
117             return None
118         return ret
119
120
121     def _get_user_login(self, caller_user):
122         """ Get user login with email """
123         email = caller_user['email']
124         # ensure user exist in LDAP tree
125         users = self._get_users()
126         if users and not email in users:
127             self.shell.add_user(caller_user)
128             users = self._get_users()
129         if users and email in users:
130             return users[email]['login']
131         else:
132             return None
133
134
135     @classmethod
136     def _get_experiment(cls, rspec):
137         """
138         Find in RSpec leases the experiment start time, duration and nodes list.
139
140         :Example:
141         <rspec>
142         ...
143         <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
144                 start_time="1427792400" duration="30">
145             <node component_id=
146                 "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
147         </lease>
148         <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
149                 start_time="1427792600" duration="50">
150             <node component_id=
151                 "urn:publicid:IDN+iotlab+node+m3-15.grenoble.iot-lab.info"/>
152         </lease>
153         ...
154         </rspec>
155         """
156         leases = rspec.version.get_leases()
157         start_time = min([int(lease['start_time'])
158                          for lease in leases])
159         end_time = max([int(lease['start_time']) +
160                        int(lease['duration'])
161                        for lease in leases])
162         nodes_list = [Xrn.unescape(Xrn(lease['component_id'].strip(),
163                       type='node').get_leaf())
164                       for lease in leases]
165         # uniq hostnames
166         nodes_list = list(set(nodes_list))
167         from math import floor
168         duration = floor((end_time - start_time)/60) # minutes
169         return nodes_list, start_time, duration
170
171
172     def _save_db_lease(self, job_id, slice_hrn):
173         """ Save lease table row in SFA database """
174         lease_row = LeaseTable(job_id,
175                                slice_hrn)
176         logger.warning("iotlabdriver _save_db_lease lease row : %s" %
177                        lease_row)
178         self.api.dbsession().add(lease_row)
179         self.api.dbsession().commit()
180
181
182     def allocate(self, urn, rspec_string, expiration, options=None):
183         """
184         Allocate method submit an experiment on Iot-LAB testbed with :
185             * user : get the slice user which launch request (caller_hrn)
186             * reservation : get the start time and duration in RSpec leases
187             * nodes : get the nodes list in RSpec leases
188         If we have a request success on Iot-LAB testbed we store in SFA
189         database the assocation OAR scheduler job id and slice hrn
190
191         :param urn : slice urn
192         :param rspec_string : RSpec received
193         :param options : options with slice users (geni_users)
194         """
195         # pylint:disable=R0914
196
197         logger.warning("iotlabdriver allocate")
198         xrn = Xrn(urn)
199         aggregate = IotLABAggregate(self)
200         # parse rspec
201         rspec = RSpec(rspec_string)
202
203         caller_hrn = options.get('actual_caller_hrn', [])
204         geni_users = options.get('geni_users', [])
205         caller_user = [user for user in geni_users if
206                        urn_to_hrn(user['urn'])[0] == caller_hrn][0]
207         logger.warning("iotlabdriver allocate caller : %s" %
208                        caller_user['email'])
209
210         login = self._get_user_login(caller_user)
211         # only if we have a user
212         if login:
213             nodes_list, start_time, duration = \
214                 self._get_experiment(rspec)
215             logger.warning("iotlabdriver allocate submit OAR job :"
216                            " %s %s %s %s" %
217                            (xrn.hrn, start_time, duration, nodes_list))
218             # [0-9A-Za-z_] with onelab.inria.test_iotlab
219             exp_name = '_'.join((xrn.hrn).split('.'))
220             # submit OAR job
221             ret = self.shell.reserve_nodes(login,
222                                            exp_name,
223                                            nodes_list,
224                                            start_time,
225                                            duration)
226
227             # in case of job submission success save slice and lease job
228             # id association in database
229             if 'id' in ret:
230                 self._save_db_lease(int(ret['id']),
231                                     xrn.hrn)
232
233         return aggregate.describe([xrn.get_urn()], version=rspec.version)