blob: 355d65336d7b1729f122f9e787e904ce4bbde9ec [file] [log] [blame]
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -04001"""
2#
3# Copyright 2016 RIFT.IO Inc
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18@file app.py
19@author Austin Cormier(austin.cormier@riftio.com)
20@author Varun Prasad(varun.prasad@riftio.com)
21@date 2016-06-14
22"""
23
24import asyncio
25import collections
26import concurrent.futures
27import logging
28import sys
29
30import tornado
31import tornado.httpserver
32import tornado.web
33import tornado.platform.asyncio
34
35import gi
36gi.require_version('RwcalYang', '1.0')
37gi.require_version('RwCal', '1.0')
38gi.require_version('RwLog', '1.0')
39gi.require_version('RwTypes', '1.0')
40from gi.repository import (
41 RwCal,
42 RwcalYang,
43 RwTypes,
44)
45
46logger = logging.getLogger(__name__)
47
48if sys.version_info < (3, 4, 4):
49 asyncio.ensure_future = asyncio.async
50
51
52class CalCallFailure(Exception):
53 pass
54
55
56class RPCParam(object):
57 def __init__(self, key, proto_type=None):
58 self.key = key
59 self.proto_type = proto_type
60
61
62class CalRequestHandler(tornado.web.RequestHandler):
63 def initialize(self, log, loop, cal, account, executor, cal_method,
64 input_params=None, output_params=None):
65 self.log = log
66 self.loop = loop
67 self.cal = cal
68 self.account = account
69 self.executor = executor
70 self.cal_method = cal_method
71 self.input_params = input_params
72 self.output_params = output_params
73
74 def wrap_status_fn(self, fn, *args, **kwargs):
75
76 ret = fn(*args, **kwargs)
77 if not isinstance(ret, collections.Iterable):
78 ret = [ret]
79
80 rw_status = ret[0]
81
82 if type(rw_status) is RwCal.RwcalStatus:
83 rw_status = rw_status.status
84
85 if type(rw_status) != RwTypes.RwStatus:
86 raise ValueError("First return value of %s function was not a RwStatus" %
87 fn.__name__)
88
89 if rw_status != RwTypes.RwStatus.SUCCESS:
90 msg = "%s returned %s" % (fn.__name__, str(rw_status))
91 self.log.error(msg)
92 raise CalCallFailure(msg)
93
94 return ret[1:]
95
96 @tornado.gen.coroutine
97 def post(self):
98 def body_to_cal_args():
99 cal_args = []
100 if self.input_params is None:
101 return cal_args
102
103 input_dict = tornado.escape.json_decode(self.request.body)
104 if len(input_dict) != len(self.input_params):
105 raise ValueError("Got %s parameters, expected %s" %
106 (len(input_dict), len(self.input_params)))
107
108 for input_param in self.input_params:
109 key = input_param.key
110 value = input_dict[key]
111 proto_type = input_param.proto_type
112
113 if proto_type is not None:
114 proto_cls = getattr(RwcalYang, proto_type)
115 self.log.debug("Deserializing into %s type", proto_cls)
116 value = proto_cls.from_dict(value)
117
118 cal_args.append(value)
119
120 return cal_args
121
122 def cal_return_vals(return_vals):
123 output_params = self.output_params
124 if output_params is None:
125 output_params = []
126
127 if len(return_vals) != len(output_params):
128 raise ValueError("Got %s return values. Expected %s",
129 len(return_vals), len(output_params))
130
131 write_dict = {"return_vals": []}
132 for i, output_param in enumerate(output_params):
133 key = output_param.key
134 proto_type = output_param.proto_type
135 output_value = return_vals[i]
136
137 if proto_type is not None:
138 output_value = output_value.as_dict()
139
140 return_val = {
141 "key": key,
142 "value": output_value,
143 "proto_type": proto_type,
144 }
145
146 write_dict["return_vals"].append(return_val)
147
148 return write_dict
149
150 @asyncio.coroutine
151 def handle_request():
152 self.log.debug("Got cloudsimproxy POST request: %s", self.request.body)
153 cal_args = body_to_cal_args()
154
155 # Execute the CAL request in a seperate thread to prevent
156 # blocking the main loop.
157 return_vals = yield from self.loop.run_in_executor(
158 self.executor,
159 self.wrap_status_fn,
160 getattr(self.cal, self.cal_method),
161 self.account,
162 *cal_args
163 )
164
165 return cal_return_vals(return_vals)
166
167 f = asyncio.ensure_future(handle_request(), loop=self.loop)
168 return_dict = yield tornado.platform.asyncio.to_tornado_future(f)
169
170 self.log.debug("Responding to %s RPC with %s", self.cal_method, return_dict)
171
172 self.clear()
173 self.set_status(200)
174 self.write(return_dict)
175
176
177class CalProxyApp(tornado.web.Application):
178 def __init__(self, log, loop, cal_interface, cal_account):
179 self.log = log
180 self.loop = loop
181 self.cal = cal_interface
182 self.account = cal_account
183
184 attrs = dict(
185 log=self.log,
186 loop=self.loop,
187 cal=cal_interface,
188 account=cal_account,
189 # Create an executor with a single worker to prevent
190 # having multiple simulteneous calls into CAL (which is not threadsafe)
191 executor=concurrent.futures.ThreadPoolExecutor(1)
192 )
193
194 def mk_attrs(cal_method, input_params=None, output_params=None):
195 new_attrs = {
196 "cal_method": cal_method,
197 "input_params": input_params,
198 "output_params": output_params
199 }
200 new_attrs.update(attrs)
201
202 return new_attrs
203
204 super(CalProxyApp, self).__init__([
205 (r"/api/get_image_list", CalRequestHandler,
206 mk_attrs(
207 cal_method="get_image_list",
208 output_params=[
209 RPCParam("images", "VimResources"),
210 ]
211 ),
212 ),
213
214 (r"/api/create_image", CalRequestHandler,
215 mk_attrs(
216 cal_method="create_image",
217 input_params=[
218 RPCParam("image", "ImageInfoItem"),
219 ],
220 output_params=[
221 RPCParam("image_id"),
222 ]
223 ),
224 ),
225
226 (r"/api/delete_image", CalRequestHandler,
227 mk_attrs(
228 cal_method="delete_image",
229 input_params=[
230 RPCParam("image_id"),
231 ],
232 ),
233 ),
234
235 (r"/api/get_image", CalRequestHandler,
236 mk_attrs(
237 cal_method="get_image",
238 input_params=[
239 RPCParam("image_id"),
240 ],
241 output_params=[
242 RPCParam("image", "ImageInfoItem"),
243 ],
244 ),
245 ),
246
247 (r"/api/create_vm", CalRequestHandler,
248 mk_attrs(
249 cal_method="create_vm",
250 input_params=[
251 RPCParam("vm", "VMInfoItem"),
252 ],
253 output_params=[
254 RPCParam("vm_id"),
255 ],
256 ),
257 ),
258
259 (r"/api/start_vm", CalRequestHandler,
260 mk_attrs(
261 cal_method="start_vm",
262 input_params=[
263 RPCParam("vm_id"),
264 ],
265 ),
266 ),
267
268 (r"/api/stop_vm", CalRequestHandler,
269 mk_attrs(
270 cal_method="stop_vm",
271 input_params=[
272 RPCParam("vm_id"),
273 ],
274 ),
275 ),
276
277 (r"/api/delete_vm", CalRequestHandler,
278 mk_attrs(
279 cal_method="delete_vm",
280 input_params=[
281 RPCParam("vm_id"),
282 ],
283 ),
284 ),
285
286 (r"/api/reboot_vm", CalRequestHandler,
287 mk_attrs(
288 cal_method="reboot_vm",
289 input_params=[
290 RPCParam("vm_id"),
291 ],
292 ),
293 ),
294
295 (r"/api/get_vm_list", CalRequestHandler,
296 mk_attrs(
297 cal_method="get_vm_list",
298 output_params=[
299 RPCParam("vms", "VimResources"),
300 ],
301 ),
302 ),
303
304 (r"/api/get_vm", CalRequestHandler,
305 mk_attrs(
306 cal_method="get_vm",
307 input_params=[
308 RPCParam("vm_id"),
309 ],
310 output_params=[
311 RPCParam("vms", "VMInfoItem"),
312 ],
313 ),
314 ),
315
316 (r"/api/create_flavor", CalRequestHandler,
317 mk_attrs(
318 cal_method="create_flavor",
319 input_params=[
320 RPCParam("flavor", "FlavorInfoItem"),
321 ],
322 output_params=[
323 RPCParam("flavor_id"),
324 ],
325 ),
326 ),
327
328 (r"/api/delete_flavor", CalRequestHandler,
329 mk_attrs(
330 cal_method="delete_flavor",
331 input_params=[
332 RPCParam("flavor_id"),
333 ],
334 ),
335 ),
336
337 (r"/api/get_flavor_list", CalRequestHandler,
338 mk_attrs(
339 cal_method="get_flavor_list",
340 output_params=[
341 RPCParam("flavors", "VimResources"),
342 ],
343 ),
344 ),
345
346 (r"/api/get_flavor", CalRequestHandler,
347 mk_attrs(
348 cal_method="get_flavor",
349 input_params=[
350 RPCParam("flavor_id"),
351 ],
352 output_params=[
353 RPCParam("flavor", "FlavorInfoItem"),
354 ],
355 ),
356 ),
357
358 (r"/api/create_network", CalRequestHandler,
359 mk_attrs(
360 cal_method="create_network",
361 input_params=[
362 RPCParam("network", "NetworkInfoItem"),
363 ],
364 output_params=[
365 RPCParam("network_id"),
366 ],
367 ),
368 ),
369
370 (r"/api/delete_network", CalRequestHandler,
371 mk_attrs(
372 cal_method="delete_network",
373 input_params=[
374 RPCParam("network_id"),
375 ],
376 ),
377 ),
378
379 (r"/api/get_network", CalRequestHandler,
380 mk_attrs(
381 cal_method="get_network",
382 input_params=[
383 RPCParam("network_id"),
384 ],
385 output_params=[
386 RPCParam("network", "NetworkInfoItem"),
387 ],
388 ),
389 ),
390
391 (r"/api/get_network_list", CalRequestHandler,
392 mk_attrs(
393 cal_method="get_network_list",
394 output_params=[
395 RPCParam("networks", "VimResources"),
396 ],
397 ),
398 ),
399
400 (r"/api/get_management_network", CalRequestHandler,
401 mk_attrs(
402 cal_method="get_management_network",
403 output_params=[
404 RPCParam("network", "NetworkInfoItem"),
405 ],
406 ),
407 ),
408
409 (r"/api/create_port", CalRequestHandler,
410 mk_attrs(
411 cal_method="create_port",
412 input_params=[
413 RPCParam("port", "PortInfoItem"),
414 ],
415 output_params=[
416 RPCParam("port_id"),
417 ],
418 ),
419 ),
420
421 (r"/api/delete_port", CalRequestHandler,
422 mk_attrs(
423 cal_method="delete_port",
424 input_params=[
425 RPCParam("port_id"),
426 ],
427 ),
428 ),
429
430 (r"/api/get_port", CalRequestHandler,
431 mk_attrs(
432 cal_method="get_port",
433 input_params=[
434 RPCParam("port_id"),
435 ],
436 output_params=[
437 RPCParam("port", "PortInfoItem"),
438 ],
439 ),
440 ),
441
442 (r"/api/get_port_list", CalRequestHandler,
443 mk_attrs(
444 cal_method="get_port_list",
445 output_params=[
446 RPCParam("ports", "VimResources"),
447 ],
448 ),
449 ),
450
451 (r"/api/create_virtual_link", CalRequestHandler,
452 mk_attrs(
453 cal_method="create_virtual_link",
454 input_params=[
455 RPCParam("link_params", "VirtualLinkReqParams"),
456 ],
457 output_params=[
458 RPCParam("link_id"),
459 ],
460 ),
461 ),
462
463 (r"/api/delete_virtual_link", CalRequestHandler,
464 mk_attrs(
465 cal_method="delete_virtual_link",
466 input_params=[
467 RPCParam("link_id"),
468 ],
469 ),
470 ),
471
472 (r"/api/get_virtual_link", CalRequestHandler,
473 mk_attrs(
474 cal_method="get_virtual_link",
475 input_params=[
476 RPCParam("link_id"),
477 ],
478 output_params=[
479 RPCParam("response", "VirtualLinkInfoParams"),
480 ],
481 ),
482 ),
483
484 (r"/api/get_virtual_link_list", CalRequestHandler,
485 mk_attrs(
486 cal_method="get_virtual_link_list",
487 output_params=[
488 RPCParam("resources", "VNFResources"),
489 ],
490 ),
491 ),
492
493 (r"/api/create_vdu", CalRequestHandler,
494 mk_attrs(
495 cal_method="create_vdu",
496 input_params=[
497 RPCParam("vdu_params", "VDUInitParams"),
498 ],
499 output_params=[
500 RPCParam("vdu_id"),
501 ],
502 ),
503 ),
504
505 (r"/api/modify_vdu", CalRequestHandler,
506 mk_attrs(
507 cal_method="modify_vdu",
508 input_params=[
509 RPCParam("vdu_params", "VDUModifyParams"),
510 ],
511 ),
512 ),
513
514 (r"/api/delete_vdu", CalRequestHandler,
515 mk_attrs(
516 cal_method="delete_vdu",
517 input_params=[
518 RPCParam("vdu_id"),
519 ],
520 ),
521 ),
522
523 (r"/api/get_vdu", CalRequestHandler,
524 mk_attrs(
525 cal_method="get_vdu",
526 input_params=[
527 RPCParam("vdu_id"),
528 ],
529 output_params=[
530 RPCParam("response", "VDUInfoParams"),
531 ],
532 ),
533 ),
534
535 (r"/api/get_vdu_list", CalRequestHandler,
536 mk_attrs(
537 cal_method="get_vdu_list",
538 output_params=[
539 RPCParam("resources", "VNFResources"),
540 ],
541 ),
542 )
543 ])