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
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.
"""
if req.private is None:
- (HandlerClass, items, args) = self._resmap.getController(req.request_path)
+ (HandlerClass, items, args) = \
+ self._resmap.getController(req.request_path)
ctx = RemoteApiRequestContext()
ctx.handler = HandlerClass(items, args, req)
try:
ctx.handler_fn = getattr(ctx.handler, method)
except AttributeError, err:
- raise http.HttpBadRequest()
+ raise http.HttpBadRequest("Method %s is unsupported for path %s" %
+ (method, req.request_path))
ctx.handler_access = getattr(ctx.handler, "%s_ACCESS" % method, None)
return req.private
+ def GetAuthRealm(self, req):
+ """Override the auth realm for queries.
+
+ """
+ ctx = self._GetRequestContext(req)
+ if ctx.handler_access:
+ return self.AUTH_REALM
+ else:
+ return None
+
def Authenticate(self, req, username, password):
"""Checks whether a user can access a resource.
sn = ctx.handler.getSerialNumber()
if sn:
req.response_headers[http.HTTP_ETAG] = str(sn)
+ except luxi.TimeoutError:
+ raise http.HttpGatewayTimeout()
+ except luxi.ProtocolError, err:
+ raise http.HttpBadGateway(str(err))
except:
method = req.request_method.upper()
logging.exception("Error while handling the %s request", method)
help="Port to run API (%s default)." %
constants.RAPI_PORT,
default=constants.RAPI_PORT, type="int")
- parser.add_option("-S", "--https", dest="ssl",
- help="Secure HTTP protocol with SSL",
- default=False, action="store_true")
+ parser.add_option("--no-ssl", dest="ssl",
+ help="Do not secure HTTP protocol with SSL",
+ default=True, action="store_false")
parser.add_option("-K", "--ssl-key", dest="ssl_key",
help="SSL key",
- default=None, type="string")
+ default=constants.RAPI_CERT_FILE, type="string")
parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
help="SSL certificate",
- default=None, type="string")
+ default=constants.RAPI_CERT_FILE, type="string")
parser.add_option("-f", "--foreground", dest="fork",
help="Don't detach from the current terminal",
default=True, action="store_false")
"""
options, args = ParseOptions()
+ if options.fork:
+ utils.CloseFDs()
+
+ if options.ssl:
+ # Read SSL certificate
+ try:
+ ssl_params = http.HttpSslParams(ssl_key_path=options.ssl_key,
+ ssl_cert_path=options.ssl_cert)
+ except Exception, err:
+ sys.stderr.write("Can't load the SSL certificate/key: %s\n" % (err,))
+ sys.exit(1)
+ else:
+ ssl_params = None
+
ssconf.CheckMaster(options.debug)
if options.fork:
utils.WritePidFile(constants.RAPI_PID)
try:
mainloop = daemon.Mainloop()
- server = RemoteApiHttpServer(mainloop, "", options.port)
+ server = RemoteApiHttpServer(mainloop, "", options.port,
+ ssl_params=ssl_params, ssl_verify_peer=False,
+ request_executor_class=
+ JsonErrorRequestExecutor)
server.Start()
try:
mainloop.Run()