4 # Copyright (C) 2006, 2007 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 """ Ganeti Remote API master script.
31 from ganeti import logger
32 from ganeti import constants
33 from ganeti import errors
34 from ganeti import http
35 from ganeti import ssconf
36 from ganeti import utils
37 from ganeti.rapi import connector
40 class RESTRequestHandler(http.HTTPRequestHandler):
41 """REST Request Handler Class.
45 super(RESTRequestHandler, self).setup()
46 self._resmap = connector.Mapper()
48 def HandleRequest(self):
49 """ Handels a request.
52 (HandlerClass, items, args) = self._resmap.getController(self.path)
53 handler = HandlerClass(self, items, args, self.post_data)
55 command = self.command.upper()
57 fn = getattr(handler, command)
58 except AttributeError, err:
59 raise http.HTTPBadRequest()
65 logging.exception("Error while handling the %s request", command)
68 except errors.OpPrereqError, err:
69 # TODO: "Not found" is not always the correct error. Ganeti's core must
70 # differentiate between different error types.
71 raise http.HTTPNotFound(message=str(err))
76 class RESTHttpServer(http.HTTPServer):
77 def serve_forever(self):
78 """Handle one request at a time until told to quit."""
79 sighandler = utils.SignalHandler([signal.SIGINT, signal.SIGTERM])
81 while not sighandler.called:
88 """Parse the command line options.
91 (options, args) as from OptionParser.parse_args()
94 parser = optparse.OptionParser(description="Ganeti Remote API",
95 usage="%prog [-d] [-p port]",
96 version="%%prog (ganeti) %s" %
97 constants.RAPI_VERSION)
98 parser.add_option("-d", "--debug", dest="debug",
99 help="Enable some debug messages",
100 default=False, action="store_true")
101 parser.add_option("-p", "--port", dest="port",
102 help="Port to run API (%s default)." %
104 default=constants.RAPI_PORT, type="int")
105 parser.add_option("-S", "--https", dest="ssl",
106 help="Secure HTTP protocol with SSL",
107 default=False, action="store_true")
108 parser.add_option("-K", "--ssl-key", dest="ssl_key",
110 default=None, type="string")
111 parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
112 help="SSL certificate",
113 default=None, type="string")
114 parser.add_option("-f", "--foreground", dest="fork",
115 help="Don't detach from the current terminal",
116 default=True, action="store_false")
118 options, args = parser.parse_args()
121 print >> sys.stderr, "Usage: %s [-d] [-p port]" % sys.argv[0]
124 if options.ssl and not (options.ssl_cert and options.ssl_key):
125 print >> sys.stderr, ("For secure mode please provide "
126 "--ssl-key and --ssl-cert arguments")
136 options, args = ParseOptions()
138 ssconf.CheckMaster(options.debug)
141 utils.Daemonize(logfile=constants.LOG_RAPISERVER)
143 logger.SetupLogging(constants.LOG_RAPISERVER, debug=options.debug,
144 stderr_logging=not options.fork)
146 utils.WritePidFile(constants.RAPI_PID)
148 log_fd = open(constants.LOG_RAPIACCESS, 'a')
150 apache_log = http.ApacheLogfile(log_fd)
151 httpd = RESTHttpServer(("", options.port), RESTRequestHandler,
154 httpd.serve_forever()
157 utils.RemovePidFile(constants.RAPI_PID)
165 if __name__ == '__main__':