Initial commit
[ta/config-manager.git] / cmframework / src / cmframework / server / cmwsgihandler.py
1 # Copyright 2019 Nokia
2
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import logging
16 import urllib
17 import urlparse
18 import routes
19
20 from cmframework.server.cmhttperrors import CMHTTPErrors
21 from cmframework.apis import cmerror
22 from cmframework.server import cmhttprpc
23
24
25 class CMWSGIHandler(object):
26     def __init__(self, rest_api_factory):
27         logging.debug('CMWSGIHandler constructor called')
28         self.mapper = routes.Mapper()
29         self.mapper.connect(None, '/cm/apis', action='get_apis')
30         self.mapper.connect(None, '/cm/{api}/properties', action='handle_properties')
31         self.mapper.connect(None, '/cm/{api}/properties/{property}', action='handle_property')
32         self.mapper.connect(None, '/cm/{api}/snapshots', action='handle_snapshots')
33         self.mapper.connect(None, '/cm/{api}/snapshots/{snapshot}', action='handle_snapshot')
34         self.mapper.connect(None, '/cm/{api}/activator/enable', action='handle_activator_enable')
35         self.mapper.connect(None, '/cm/{api}/activator/disable', action='handle_activator_disable')
36         self.mapper.connect(None, '/cm/{api}/activator/agent/{node}',
37                             action='handle_agent_activate')
38         self.mapper.connect(None, '/cm/{api}/activator/{node}', action='handle_activate')
39         self.mapper.connect(None, '/cm/{api}/activator', action='handle_activate')
40         self.mapper.connect(None, '/cm/{api}/reboot', action='handle_reboot')
41         self.mapper.connect(None, '/cm/{api}/changes', action='handle_changes')
42         self.rest_api_factory = rest_api_factory
43
44     def __call__(self, environ, start_response):
45         logging.debug('Handling request started, environ=%s', str(environ))
46         # for debug, print environment
47         # pprint.pprint(environ)
48
49         # For request and resonse data
50         rpc = cmhttprpc.HTTPRPC()
51         rpc.rep_status = CMHTTPErrors.get_ok_status()
52
53         # get the interesting fields
54         rpc.req_method = environ['REQUEST_METHOD']
55         path = environ['PATH_INFO']
56         try:
57             rpc.req_filter = urlparse.parse_qs(urllib.unquote(environ['QUERY_STRING']))
58         except KeyError as exp:
59             rpc.req_filter = {}
60         content_type = environ['CONTENT_TYPE']
61         try:
62             content_size = environ['CONTENT_LENGTH']
63         except KeyError:
64             content_size = None
65
66         try:
67             # get the action to be done
68             action = ''
69             actions, _ = self.mapper.routematch(path)
70             if actions and isinstance(actions, dict):
71                 action = actions.get('action', '')
72                 for key, value in actions.iteritems():
73                     if key != 'action':
74                         rpc.req_params[key] = value
75             else:
76                 rpc.rep_status = CMHTTPErrors.get_resource_not_found_status()
77                 raise cmerror.CMError('The requested url is not found')
78
79             # get the body if available
80             if content_size and int(content_size):
81                 size = int(content_size)
82                 if content_type == 'application/json':
83                     totalread = 0
84                     while totalread < size:
85                         data = environ['wsgi.input'].read()
86                         totalread += len(data)
87                         rpc.req_body += data
88                 else:
89                     rpc.rep_status = CMHTTPErrors.get_unsupported_content_type_status()
90                     raise cmerror.CMError('Only json content is supported')
91
92             # check the action
93             try:
94                 logging.info('Calling %s with rpc=%s', action, str(rpc))
95                 actionfunc = getattr(self, action)
96                 actionfunc(rpc)
97             except AttributeError as attrerror:
98                 rpc.reply_status = CMHTTPErrors.get_resource_not_found_status()
99                 raise cmerror.CMError('Action %s not found, error: %s' % (action, str(attrerror)))
100
101         except cmerror.CMError as exp:
102             rpc.rep_status = CMHTTPErrors.get_internal_error_status()
103             rpc.rep_status += ','
104             rpc.rep_status += str(exp)
105         except Exception as exp:  # pylint: disable=broad-except
106             rpc.rep_status = CMHTTPErrors.get_internal_error_status()
107             rpc.rep_status += ','
108             rpc.rep_status += str(exp)
109         finally:
110             logging.info('Replying with rpc=%s', str(rpc))
111             response_headers = [('Content-type', 'application/json')]
112             start_response(rpc.rep_status, response_headers)
113             yield rpc.rep_body
114
115     def get_apis(self, rpc):
116         logging.debug('get_apis called')
117         if rpc.req_method != 'GET':
118             rpc.rep_status = CMHTTPErrors.get_request_not_ok_status()
119             rpc.rep_status += ', only GET operation is possible'
120         else:
121             self.rest_api_factory.get_apis(rpc)
122
123     def handle_properties(self, rpc):
124         logging.debug('handle_properties called')
125         api = self._get_api(rpc)
126         if api:
127             api.handle_properties(rpc)
128
129     def handle_property(self, rpc):
130         logging.debug('handle_property called')
131         api = self._get_api(rpc)
132         if api:
133             api.handle_property(rpc)
134
135     def handle_snapshots(self, rpc):
136         logging.debug('handle_snapshots called')
137         api = self._get_api(rpc)
138         if api:
139             api.handle_snapshots(rpc)
140
141     def handle_snapshot(self, rpc):
142         logging.debug('handle_snapshot called')
143         api = self._get_api(rpc)
144         if api:
145             api.handle_snapshot(rpc)
146
147     def handle_agent_activate(self, rpc):
148         logging.debug('handle_agent_activate called')
149         api = self._get_api(rpc)
150         if api:
151             api.handle_agent_activate(rpc)
152
153     def handle_activate(self, rpc):
154         logging.debug('handle_activate called')
155         api = self._get_api(rpc)
156         if api:
157             api.handle_activate(rpc)
158
159     def handle_activator_disable(self, rpc):
160         logging.debug('handle_activator_disable called')
161         api = self._get_api(rpc)
162         if api:
163             api.handle_activator_disable(rpc)
164
165     def handle_activator_enable(self, rpc):
166         logging.debug('handle_activator_enable called')
167         api = self._get_api(rpc)
168         if api:
169             api.handle_activator_enable(rpc)
170
171     def handle_reboot(self, rpc):
172         logging.debug('handle_reboot called')
173         api = self._get_api(rpc)
174         if api:
175             api.handle_reboot(rpc)
176
177     def handle_changes(self, rpc):
178         logging.debug('handle_changes called')
179         api = self._get_api(rpc)
180         if api:
181             api.handle_changes(rpc)
182
183     def _get_api(self, rpc):
184         logging.debug('_get_api called')
185         api = None
186         try:
187             version = rpc.req_params['api']
188             api = self.rest_api_factory.get_api(version)
189             if not api:
190                 rpc.rep_status = CMHTTPErrors.get_resource_not_found_status()
191         except KeyError:
192             rpc.rep_status = CMHTTPErrors.get_request_not_ok_status()
193         return api