Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-rapi @ 7e9760c3

History | View | Annotate | Download (4.7 kB)

1 8c229cc7 Oleksiy Mishchenko
#!/usr/bin/python
2 8c229cc7 Oleksiy Mishchenko
#
3 8c229cc7 Oleksiy Mishchenko
4 8c229cc7 Oleksiy Mishchenko
# Copyright (C) 2006, 2007 Google Inc.
5 8c229cc7 Oleksiy Mishchenko
#
6 8c229cc7 Oleksiy Mishchenko
# This program is free software; you can redistribute it and/or modify
7 8c229cc7 Oleksiy Mishchenko
# it under the terms of the GNU General Public License as published by
8 8c229cc7 Oleksiy Mishchenko
# the Free Software Foundation; either version 2 of the License, or
9 8c229cc7 Oleksiy Mishchenko
# (at your option) any later version.
10 8c229cc7 Oleksiy Mishchenko
#
11 8c229cc7 Oleksiy Mishchenko
# This program is distributed in the hope that it will be useful, but
12 8c229cc7 Oleksiy Mishchenko
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 8c229cc7 Oleksiy Mishchenko
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 8c229cc7 Oleksiy Mishchenko
# General Public License for more details.
15 8c229cc7 Oleksiy Mishchenko
#
16 8c229cc7 Oleksiy Mishchenko
# You should have received a copy of the GNU General Public License
17 8c229cc7 Oleksiy Mishchenko
# along with this program; if not, write to the Free Software
18 8c229cc7 Oleksiy Mishchenko
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 8c229cc7 Oleksiy Mishchenko
# 02110-1301, USA.
20 8c229cc7 Oleksiy Mishchenko
21 8c229cc7 Oleksiy Mishchenko
""" Ganeti Remote API master script.
22 8c229cc7 Oleksiy Mishchenko
"""
23 8c229cc7 Oleksiy Mishchenko
24 8c229cc7 Oleksiy Mishchenko
import glob
25 441e7cfd Oleksiy Mishchenko
import logging
26 8c229cc7 Oleksiy Mishchenko
import optparse
27 8c229cc7 Oleksiy Mishchenko
import sys
28 8c229cc7 Oleksiy Mishchenko
import os
29 cfe3c70f Michael Hanselmann
import signal
30 8c229cc7 Oleksiy Mishchenko
31 8c229cc7 Oleksiy Mishchenko
from ganeti import constants
32 3cd62121 Michael Hanselmann
from ganeti import errors
33 3cd62121 Michael Hanselmann
from ganeti import http
34 16a8967d Michael Hanselmann
from ganeti import daemon
35 5675cd1f Iustin Pop
from ganeti import ssconf
36 8c229cc7 Oleksiy Mishchenko
from ganeti import utils
37 3cd62121 Michael Hanselmann
from ganeti.rapi import connector
38 3cd62121 Michael Hanselmann
39 bc2929fc Michael Hanselmann
import ganeti.http.server
40 3cd62121 Michael Hanselmann
41 bc2929fc Michael Hanselmann
42 7e9760c3 Michael Hanselmann
class RemoteApiRequestContext(object):
43 7e9760c3 Michael Hanselmann
  """Data structure for Remote API requests.
44 7e9760c3 Michael Hanselmann
45 7e9760c3 Michael Hanselmann
  """
46 7e9760c3 Michael Hanselmann
  def __init__(self):
47 7e9760c3 Michael Hanselmann
    self.handler = None
48 7e9760c3 Michael Hanselmann
    self.handler_fn = None
49 7e9760c3 Michael Hanselmann
50 7e9760c3 Michael Hanselmann
51 bc2929fc Michael Hanselmann
class RemoteApiHttpServer(http.server.HttpServer):
52 3cd62121 Michael Hanselmann
  """REST Request Handler Class.
53 3cd62121 Michael Hanselmann
54 3cd62121 Michael Hanselmann
  """
55 16a8967d Michael Hanselmann
  def __init__(self, *args, **kwargs):
56 bc2929fc Michael Hanselmann
    http.server.HttpServer.__init__(self, *args, **kwargs)
57 3cd62121 Michael Hanselmann
    self._resmap = connector.Mapper()
58 3cd62121 Michael Hanselmann
59 7e9760c3 Michael Hanselmann
  def _GetRequestContext(self, req):
60 7e9760c3 Michael Hanselmann
    """Returns the context for a request.
61 7e9760c3 Michael Hanselmann
62 7e9760c3 Michael Hanselmann
    The context is cached in the req.private variable.
63 7e9760c3 Michael Hanselmann
64 7e9760c3 Michael Hanselmann
    """
65 7e9760c3 Michael Hanselmann
    if req.private is None:
66 7e9760c3 Michael Hanselmann
      (HandlerClass, items, args) = self._resmap.getController(req.request_path)
67 7e9760c3 Michael Hanselmann
68 7e9760c3 Michael Hanselmann
      ctx = RemoteApiRequestContext()
69 7e9760c3 Michael Hanselmann
      ctx.handler = HandlerClass(items, args, req)
70 7e9760c3 Michael Hanselmann
71 7e9760c3 Michael Hanselmann
      method = req.request_method.upper()
72 7e9760c3 Michael Hanselmann
      try:
73 7e9760c3 Michael Hanselmann
        ctx.handler_fn = getattr(ctx.handler, method)
74 7e9760c3 Michael Hanselmann
      except AttributeError, err:
75 7e9760c3 Michael Hanselmann
        raise http.HttpBadRequest()
76 7e9760c3 Michael Hanselmann
77 7e9760c3 Michael Hanselmann
      req.private = ctx
78 7e9760c3 Michael Hanselmann
79 7e9760c3 Michael Hanselmann
    return req.private
80 7e9760c3 Michael Hanselmann
81 16a8967d Michael Hanselmann
  def HandleRequest(self, req):
82 16a8967d Michael Hanselmann
    """Handles a request.
83 3cd62121 Michael Hanselmann
84 3cd62121 Michael Hanselmann
    """
85 7e9760c3 Michael Hanselmann
    ctx = self._GetRequestContext(req)
86 3cd62121 Michael Hanselmann
87 3cd62121 Michael Hanselmann
    try:
88 7e9760c3 Michael Hanselmann
      result = ctx.handler_fn()
89 7e9760c3 Michael Hanselmann
      sn = ctx.handler.getSerialNumber()
90 713faea6 Oleksiy Mishchenko
      if sn:
91 713faea6 Oleksiy Mishchenko
        req.response_headers[http.HTTP_ETAG] = str(sn)
92 16a8967d Michael Hanselmann
    except:
93 16a8967d Michael Hanselmann
      logging.exception("Error while handling the %s request", method)
94 16a8967d Michael Hanselmann
      raise
95 3cd62121 Michael Hanselmann
96 3cd62121 Michael Hanselmann
    return result
97 8c229cc7 Oleksiy Mishchenko
98 8c229cc7 Oleksiy Mishchenko
99 8c229cc7 Oleksiy Mishchenko
def ParseOptions():
100 8c229cc7 Oleksiy Mishchenko
  """Parse the command line options.
101 8c229cc7 Oleksiy Mishchenko
102 c41eea6e Iustin Pop
  @return: (options, args) as from OptionParser.parse_args()
103 8c229cc7 Oleksiy Mishchenko
104 8c229cc7 Oleksiy Mishchenko
  """
105 8c229cc7 Oleksiy Mishchenko
  parser = optparse.OptionParser(description="Ganeti Remote API",
106 8c229cc7 Oleksiy Mishchenko
                    usage="%prog [-d] [-p port]",
107 8c229cc7 Oleksiy Mishchenko
                    version="%%prog (ganeti) %s" %
108 8c229cc7 Oleksiy Mishchenko
                                 constants.RAPI_VERSION)
109 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-d", "--debug", dest="debug",
110 8c229cc7 Oleksiy Mishchenko
                    help="Enable some debug messages",
111 8c229cc7 Oleksiy Mishchenko
                    default=False, action="store_true")
112 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-p", "--port", dest="port",
113 8c229cc7 Oleksiy Mishchenko
                    help="Port to run API (%s default)." %
114 8c229cc7 Oleksiy Mishchenko
                                 constants.RAPI_PORT,
115 8c229cc7 Oleksiy Mishchenko
                    default=constants.RAPI_PORT, type="int")
116 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-S", "--https", dest="ssl",
117 8c229cc7 Oleksiy Mishchenko
                    help="Secure HTTP protocol with SSL",
118 8c229cc7 Oleksiy Mishchenko
                    default=False, action="store_true")
119 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-K", "--ssl-key", dest="ssl_key",
120 8c229cc7 Oleksiy Mishchenko
                    help="SSL key",
121 8c229cc7 Oleksiy Mishchenko
                    default=None, type="string")
122 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
123 8c229cc7 Oleksiy Mishchenko
                    help="SSL certificate",
124 8c229cc7 Oleksiy Mishchenko
                    default=None, type="string")
125 8c229cc7 Oleksiy Mishchenko
  parser.add_option("-f", "--foreground", dest="fork",
126 8c229cc7 Oleksiy Mishchenko
                    help="Don't detach from the current terminal",
127 8c229cc7 Oleksiy Mishchenko
                    default=True, action="store_false")
128 8c229cc7 Oleksiy Mishchenko
129 8c229cc7 Oleksiy Mishchenko
  options, args = parser.parse_args()
130 8c229cc7 Oleksiy Mishchenko
131 8c229cc7 Oleksiy Mishchenko
  if len(args) != 0:
132 8c229cc7 Oleksiy Mishchenko
    print >> sys.stderr, "Usage: %s [-d] [-p port]" % sys.argv[0]
133 8c229cc7 Oleksiy Mishchenko
    sys.exit(1)
134 8c229cc7 Oleksiy Mishchenko
135 8c229cc7 Oleksiy Mishchenko
  if options.ssl and not (options.ssl_cert and options.ssl_key):
136 8c229cc7 Oleksiy Mishchenko
    print >> sys.stderr, ("For secure mode please provide "
137 8c229cc7 Oleksiy Mishchenko
                         "--ssl-key and --ssl-cert arguments")
138 8c229cc7 Oleksiy Mishchenko
    sys.exit(1)
139 8c229cc7 Oleksiy Mishchenko
140 8c229cc7 Oleksiy Mishchenko
  return options, args
141 8c229cc7 Oleksiy Mishchenko
142 8c229cc7 Oleksiy Mishchenko
143 8c229cc7 Oleksiy Mishchenko
def main():
144 8c229cc7 Oleksiy Mishchenko
  """Main function.
145 8c229cc7 Oleksiy Mishchenko
146 8c229cc7 Oleksiy Mishchenko
  """
147 8c229cc7 Oleksiy Mishchenko
  options, args = ParseOptions()
148 3cd62121 Michael Hanselmann
149 5675cd1f Iustin Pop
  ssconf.CheckMaster(options.debug)
150 5675cd1f Iustin Pop
151 8c229cc7 Oleksiy Mishchenko
  if options.fork:
152 8c229cc7 Oleksiy Mishchenko
    utils.Daemonize(logfile=constants.LOG_RAPISERVER)
153 3cd62121 Michael Hanselmann
154 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_RAPISERVER, debug=options.debug,
155 441e7cfd Oleksiy Mishchenko
                     stderr_logging=not options.fork)
156 441e7cfd Oleksiy Mishchenko
157 99e88451 Iustin Pop
  utils.WritePidFile(constants.RAPI_PID)
158 3cd62121 Michael Hanselmann
  try:
159 16a8967d Michael Hanselmann
    mainloop = daemon.Mainloop()
160 23e46494 Michael Hanselmann
    server = RemoteApiHttpServer(mainloop, "", options.port)
161 16a8967d Michael Hanselmann
    server.Start()
162 3cd62121 Michael Hanselmann
    try:
163 16a8967d Michael Hanselmann
      mainloop.Run()
164 3cd62121 Michael Hanselmann
    finally:
165 16a8967d Michael Hanselmann
      server.Stop()
166 3cd62121 Michael Hanselmann
  finally:
167 16a8967d Michael Hanselmann
    utils.RemovePidFile(constants.RAPI_PID)
168 8c229cc7 Oleksiy Mishchenko
169 8c229cc7 Oleksiy Mishchenko
170 8c229cc7 Oleksiy Mishchenko
if __name__ == '__main__':
171 8c229cc7 Oleksiy Mishchenko
  main()