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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
20 from cmframework.server.cmhttperrors import CMHTTPErrors
21 from cmframework.apis import cmerror
22 from cmframework.server import cmhttprpc
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
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)
49 # For request and resonse data
50 rpc = cmhttprpc.HTTPRPC()
51 rpc.rep_status = CMHTTPErrors.get_ok_status()
53 # get the interesting fields
54 rpc.req_method = environ['REQUEST_METHOD']
55 path = environ['PATH_INFO']
57 rpc.req_filter = urlparse.parse_qs(urllib.unquote(environ['QUERY_STRING']))
58 except KeyError as exp:
60 content_type = environ['CONTENT_TYPE']
62 content_size = environ['CONTENT_LENGTH']
67 # get the action to be done
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():
74 rpc.req_params[key] = value
76 rpc.rep_status = CMHTTPErrors.get_resource_not_found_status()
77 raise cmerror.CMError('The requested url is not found')
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':
84 while totalread < size:
85 data = environ['wsgi.input'].read()
86 totalread += len(data)
89 rpc.rep_status = CMHTTPErrors.get_unsupported_content_type_status()
90 raise cmerror.CMError('Only json content is supported')
94 logging.info('Calling %s with rpc=%s', action, str(rpc))
95 actionfunc = getattr(self, action)
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)))
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)
110 logging.info('Replying with rpc=%s', str(rpc))
111 response_headers = [('Content-type', 'application/json')]
112 start_response(rpc.rep_status, response_headers)
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'
121 self.rest_api_factory.get_apis(rpc)
123 def handle_properties(self, rpc):
124 logging.debug('handle_properties called')
125 api = self._get_api(rpc)
127 api.handle_properties(rpc)
129 def handle_property(self, rpc):
130 logging.debug('handle_property called')
131 api = self._get_api(rpc)
133 api.handle_property(rpc)
135 def handle_snapshots(self, rpc):
136 logging.debug('handle_snapshots called')
137 api = self._get_api(rpc)
139 api.handle_snapshots(rpc)
141 def handle_snapshot(self, rpc):
142 logging.debug('handle_snapshot called')
143 api = self._get_api(rpc)
145 api.handle_snapshot(rpc)
147 def handle_agent_activate(self, rpc):
148 logging.debug('handle_agent_activate called')
149 api = self._get_api(rpc)
151 api.handle_agent_activate(rpc)
153 def handle_activate(self, rpc):
154 logging.debug('handle_activate called')
155 api = self._get_api(rpc)
157 api.handle_activate(rpc)
159 def handle_activator_disable(self, rpc):
160 logging.debug('handle_activator_disable called')
161 api = self._get_api(rpc)
163 api.handle_activator_disable(rpc)
165 def handle_activator_enable(self, rpc):
166 logging.debug('handle_activator_enable called')
167 api = self._get_api(rpc)
169 api.handle_activator_enable(rpc)
171 def handle_reboot(self, rpc):
172 logging.debug('handle_reboot called')
173 api = self._get_api(rpc)
175 api.handle_reboot(rpc)
177 def handle_changes(self, rpc):
178 logging.debug('handle_changes called')
179 api = self._get_api(rpc)
181 api.handle_changes(rpc)
183 def _get_api(self, rpc):
184 logging.debug('_get_api called')
187 version = rpc.req_params['api']
188 api = self.rest_api_factory.get_api(version)
190 rpc.rep_status = CMHTTPErrors.get_resource_not_found_status()
192 rpc.rep_status = CMHTTPErrors.get_request_not_ok_status()