Cluster: add nicparams, and update them on upgrade
[ganeti-local] / daemons / ganeti-rapi
index 9632939..7b9710a 100755 (executable)
@@ -35,6 +35,8 @@ from ganeti import http
 from ganeti import daemon
 from ganeti import ssconf
 from ganeti import utils
 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
 from ganeti.rapi import connector
 
 import ganeti.http.auth
@@ -51,6 +53,24 @@ class RemoteApiRequestContext(object):
     self.handler_access = None
 
 
     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.
 class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
                           http.server.HttpServer):
   """REST Request Handler Class.
@@ -76,7 +96,8 @@ class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
 
     """
     if req.private is None:
 
     """
     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)
 
       ctx = RemoteApiRequestContext()
       ctx.handler = HandlerClass(items, args, req)
@@ -85,7 +106,8 @@ class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
       try:
         ctx.handler_fn = getattr(ctx.handler, method)
       except AttributeError, err:
       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)
 
 
       ctx.handler_access = getattr(ctx.handler, "%s_ACCESS" % method, None)
 
@@ -97,6 +119,16 @@ class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
 
     return req.private
 
 
     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.
 
   def Authenticate(self, req, username, password):
     """Checks whether a user can access a resource.
 
@@ -133,6 +165,10 @@ class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
       sn = ctx.handler.getSerialNumber()
       if sn:
         req.response_headers[http.HTTP_ETAG] = str(sn)
       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)
     except:
       method = req.request_method.upper()
       logging.exception("Error while handling the %s request", method)
@@ -158,15 +194,15 @@ def ParseOptions():
                     help="Port to run API (%s default)." %
                                  constants.RAPI_PORT,
                     default=constants.RAPI_PORT, type="int")
                     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",
   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",
   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")
   parser.add_option("-f", "--foreground", dest="fork",
                     help="Don't detach from the current terminal",
                     default=True, action="store_false")
@@ -191,6 +227,20 @@ def main():
   """
   options, args = ParseOptions()
 
   """
   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:
   ssconf.CheckMaster(options.debug)
 
   if options.fork:
@@ -202,7 +252,10 @@ def main():
   utils.WritePidFile(constants.RAPI_PID)
   try:
     mainloop = daemon.Mainloop()
   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()
     server.Start()
     try:
       mainloop.Run()