]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/controllers/_helpers.py
import ceph 16.2.7
[ceph.git] / ceph / src / pybind / mgr / dashboard / controllers / _helpers.py
CommitLineData
a4b75251
TL
1import collections
2import json
3import logging
4import re
5from functools import wraps
6
7import cherrypy
8from ceph_argparse import ArgumentFormat # pylint: disable=import-error
9
10from ..exceptions import DashboardException
11from ..tools import getargspec
12
13logger = logging.getLogger(__name__)
14
15
16ENDPOINT_MAP = collections.defaultdict(list) # type: dict
17
18
19def _get_function_params(func):
20 """
21 Retrieves the list of parameters declared in function.
22 Each parameter is represented as dict with keys:
23 * name (str): the name of the parameter
24 * required (bool): whether the parameter is required or not
25 * default (obj): the parameter's default value
26 """
27 fspec = getargspec(func)
28
29 func_params = []
30 nd = len(fspec.args) if not fspec.defaults else -len(fspec.defaults)
31 for param in fspec.args[1:nd]:
32 func_params.append({'name': param, 'required': True})
33
34 if fspec.defaults:
35 for param, val in zip(fspec.args[nd:], fspec.defaults):
36 func_params.append({
37 'name': param,
38 'required': False,
39 'default': val
40 })
41
42 return func_params
43
44
45def generate_controller_routes(endpoint, mapper, base_url):
46 inst = endpoint.inst
47 ctrl_class = endpoint.ctrl
48
49 if endpoint.proxy:
50 conditions = None
51 else:
52 conditions = dict(method=[endpoint.method])
53
54 # base_url can be empty or a URL path that starts with "/"
55 # we will remove the trailing "/" if exists to help with the
56 # concatenation with the endpoint url below
57 if base_url.endswith("/"):
58 base_url = base_url[:-1]
59
60 endp_url = endpoint.url
61
62 if endp_url.find("/", 1) == -1:
63 parent_url = "{}{}".format(base_url, endp_url)
64 else:
65 parent_url = "{}{}".format(base_url, endp_url[:endp_url.find("/", 1)])
66
67 # parent_url might be of the form "/.../{...}" where "{...}" is a path parameter
68 # we need to remove the path parameter definition
69 parent_url = re.sub(r'(?:/\{[^}]+\})$', '', parent_url)
70 if not parent_url: # root path case
71 parent_url = "/"
72
73 url = "{}{}".format(base_url, endp_url)
74
75 logger.debug("Mapped [%s] to %s:%s restricted to %s",
76 url, ctrl_class.__name__, endpoint.action,
77 endpoint.method)
78
79 ENDPOINT_MAP[endpoint.url].append(endpoint)
80
81 name = ctrl_class.__name__ + ":" + endpoint.action
82 mapper.connect(name, url, controller=inst, action=endpoint.action,
83 conditions=conditions)
84
85 # adding route with trailing slash
86 name += "/"
87 url += "/"
88 mapper.connect(name, url, controller=inst, action=endpoint.action,
89 conditions=conditions)
90
91 return parent_url
92
93
94def json_error_page(status, message, traceback, version):
95 cherrypy.response.headers['Content-Type'] = 'application/json'
96 return json.dumps(dict(status=status, detail=message, traceback=traceback,
97 version=version))
98
99
100def allow_empty_body(func): # noqa: N802
101 """
102 The POST/PUT request methods decorated with ``@allow_empty_body``
103 are allowed to send empty request body.
104 """
105 # pylint: disable=protected-access
106 try:
107 func._cp_config['tools.json_in.force'] = False
108 except (AttributeError, KeyError):
109 func._cp_config = {'tools.json_in.force': False}
110 return func
111
112
113def validate_ceph_type(validations, component=''):
114 def decorator(func):
115 @wraps(func)
116 def validate_args(*args, **kwargs):
117 input_values = kwargs
118 for key, ceph_type in validations:
119 try:
120 ceph_type.valid(input_values[key])
121 except ArgumentFormat as e:
122 raise DashboardException(msg=e,
123 code='ceph_type_not_valid',
124 component=component)
125 return func(*args, **kwargs)
126 return validate_args
127 return decorator