diff --git a/daemons/ganeti-rapi b/daemons/ganeti-rapi index bd87b19b0229d0151c190899965e404698d024a5..195d5c2c90dea9f83dfcd9d6ea592394f1e76c0a 100755 --- a/daemons/ganeti-rapi +++ b/daemons/ganeti-rapi @@ -36,6 +36,7 @@ from ganeti import daemon from ganeti import ssconf from ganeti import utils from ganeti import luxi +from ganeti import serializer from ganeti.rapi import connector import ganeti.http.auth @@ -52,6 +53,24 @@ class RemoteApiRequestContext(object): self.handler_access = None +class JsonErrorRequestExecutor(http.server.HttpServerRequestExecutor): + """Custom Request Executor class that formats HTTP errors in JSON. + + """ + error_content_type = "application/json" + + def _FormatErrorMessage(self, values): + """Formats the body of an error message. + + @type values: dict + @param values: dictionary with keys code, message and explain. + @rtype: string + @return: the body of the message + + """ + return serializer.DumpJson(values, indent=True) + + class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication, http.server.HttpServer): """REST Request Handler Class. @@ -233,7 +252,9 @@ def main(): try: mainloop = daemon.Mainloop() server = RemoteApiHttpServer(mainloop, "", options.port, - ssl_params=ssl_params, ssl_verify_peer=False) + ssl_params=ssl_params, ssl_verify_peer=False, + request_executor_class= + JsonErrorRequestExecutor) server.Start() try: mainloop.Run() diff --git a/lib/http/server.py b/lib/http/server.py index d7ac0e18863323b432c377f9bd712be05e4bc67d..b74eb3674121dc64958c3a81916971fde2aaad19 100644 --- a/lib/http/server.py +++ b/lib/http/server.py @@ -207,7 +207,7 @@ class _HttpClientToServerMessageReader(http.HttpMessageReader): return http.HttpClientToServerStartLine(method, path, version) -class _HttpServerRequestExecutor(object): +class HttpServerRequestExecutor(object): """Implements server side of HTTP. This class implements the server side of HTTP. It's based on code of @@ -405,8 +405,18 @@ class _HttpServerRequestExecutor(object): headers[http.HTTP_CONTENT_TYPE] = self.error_content_type self.response_msg.headers = headers - self.response_msg.body = self.error_message_format % values + self.response_msg.body = self._FormatErrorMessage(values) + def _FormatErrorMessage(self, values): + """Formats the body of an error message. + + @type values: dict + @param values: dictionary with keys code, message and explain. + @rtype: string + @return: the body of the message + + """ + return self.error_message_format % values class HttpServer(http.HttpBase): """Generic HTTP server class @@ -417,7 +427,8 @@ class HttpServer(http.HttpBase): MAX_CHILDREN = 20 def __init__(self, mainloop, local_address, port, - ssl_params=None, ssl_verify_peer=False): + ssl_params=None, ssl_verify_peer=False, + request_executor_class=None): """Initializes the HTTP server @type mainloop: ganeti.daemon.Mainloop @@ -431,10 +442,18 @@ class HttpServer(http.HttpBase): @type ssl_verify_peer: bool @param ssl_verify_peer: Whether to require client certificate and compare it with our certificate + @type request_executor_class: class + @param request_executor_class: an class derived from the + HttpServerRequestExecutor class """ http.HttpBase.__init__(self) + if request_executor_class is None: + self.request_executor = HttpServerRequestExecutor + else: + self.request_executor = request_executor_class + self.mainloop = mainloop self.local_address = local_address self.port = port @@ -505,7 +524,7 @@ class HttpServer(http.HttpBase): if pid == 0: # Child process try: - _HttpServerRequestExecutor(self, connection, client_addr) + self.request_executor(self, connection, client_addr) except Exception: logging.exception("Error while handling request from %s:%s", client_addr[0], client_addr[1])