Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-rapi @ 7e9760c3

History | View | Annotate | Download (4.7 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21
""" Ganeti Remote API master script.
22
"""
23

    
24
import glob
25
import logging
26
import optparse
27
import sys
28
import os
29
import signal
30

    
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti import http
34
from ganeti import daemon
35
from ganeti import ssconf
36
from ganeti import utils
37
from ganeti.rapi import connector
38

    
39
import ganeti.http.server
40

    
41

    
42
class RemoteApiRequestContext(object):
43
  """Data structure for Remote API requests.
44

    
45
  """
46
  def __init__(self):
47
    self.handler = None
48
    self.handler_fn = None
49

    
50

    
51
class RemoteApiHttpServer(http.server.HttpServer):
52
  """REST Request Handler Class.
53

    
54
  """
55
  def __init__(self, *args, **kwargs):
56
    http.server.HttpServer.__init__(self, *args, **kwargs)
57
    self._resmap = connector.Mapper()
58

    
59
  def _GetRequestContext(self, req):
60
    """Returns the context for a request.
61

    
62
    The context is cached in the req.private variable.
63

    
64
    """
65
    if req.private is None:
66
      (HandlerClass, items, args) = self._resmap.getController(req.request_path)
67

    
68
      ctx = RemoteApiRequestContext()
69
      ctx.handler = HandlerClass(items, args, req)
70

    
71
      method = req.request_method.upper()
72
      try:
73
        ctx.handler_fn = getattr(ctx.handler, method)
74
      except AttributeError, err:
75
        raise http.HttpBadRequest()
76

    
77
      req.private = ctx
78

    
79
    return req.private
80

    
81
  def HandleRequest(self, req):
82
    """Handles a request.
83

    
84
    """
85
    ctx = self._GetRequestContext(req)
86

    
87
    try:
88
      result = ctx.handler_fn()
89
      sn = ctx.handler.getSerialNumber()
90
      if sn:
91
        req.response_headers[http.HTTP_ETAG] = str(sn)
92
    except:
93
      logging.exception("Error while handling the %s request", method)
94
      raise
95

    
96
    return result
97

    
98

    
99
def ParseOptions():
100
  """Parse the command line options.
101

    
102
  @return: (options, args) as from OptionParser.parse_args()
103

    
104
  """
105
  parser = optparse.OptionParser(description="Ganeti Remote API",
106
                    usage="%prog [-d] [-p port]",
107
                    version="%%prog (ganeti) %s" %
108
                                 constants.RAPI_VERSION)
109
  parser.add_option("-d", "--debug", dest="debug",
110
                    help="Enable some debug messages",
111
                    default=False, action="store_true")
112
  parser.add_option("-p", "--port", dest="port",
113
                    help="Port to run API (%s default)." %
114
                                 constants.RAPI_PORT,
115
                    default=constants.RAPI_PORT, type="int")
116
  parser.add_option("-S", "--https", dest="ssl",
117
                    help="Secure HTTP protocol with SSL",
118
                    default=False, action="store_true")
119
  parser.add_option("-K", "--ssl-key", dest="ssl_key",
120
                    help="SSL key",
121
                    default=None, type="string")
122
  parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
123
                    help="SSL certificate",
124
                    default=None, type="string")
125
  parser.add_option("-f", "--foreground", dest="fork",
126
                    help="Don't detach from the current terminal",
127
                    default=True, action="store_false")
128

    
129
  options, args = parser.parse_args()
130

    
131
  if len(args) != 0:
132
    print >> sys.stderr, "Usage: %s [-d] [-p port]" % sys.argv[0]
133
    sys.exit(1)
134

    
135
  if options.ssl and not (options.ssl_cert and options.ssl_key):
136
    print >> sys.stderr, ("For secure mode please provide "
137
                         "--ssl-key and --ssl-cert arguments")
138
    sys.exit(1)
139

    
140
  return options, args
141

    
142

    
143
def main():
144
  """Main function.
145

    
146
  """
147
  options, args = ParseOptions()
148

    
149
  ssconf.CheckMaster(options.debug)
150

    
151
  if options.fork:
152
    utils.Daemonize(logfile=constants.LOG_RAPISERVER)
153

    
154
  utils.SetupLogging(constants.LOG_RAPISERVER, debug=options.debug,
155
                     stderr_logging=not options.fork)
156

    
157
  utils.WritePidFile(constants.RAPI_PID)
158
  try:
159
    mainloop = daemon.Mainloop()
160
    server = RemoteApiHttpServer(mainloop, "", options.port)
161
    server.Start()
162
    try:
163
      mainloop.Run()
164
    finally:
165
      server.Stop()
166
  finally:
167
    utils.RemovePidFile(constants.RAPI_PID)
168

    
169

    
170
if __name__ == '__main__':
171
  main()