Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-rapi @ 5675cd1f

History | View | Annotate | Download (4.4 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 optparse
26
import sys
27
import os
28
import signal
29

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

    
38

    
39
class RESTRequestHandler(http.HTTPRequestHandler):
40
  """REST Request Handler Class.
41

    
42
  """
43
  def setup(self):
44
    super(RESTRequestHandler, self).setup()
45
    self._resmap = connector.Mapper()
46

    
47
  def HandleRequest(self):
48
    """ Handels a request.
49

    
50
    """
51
    (HandlerClass, items, args) = self._resmap.getController(self.path)
52
    handler = HandlerClass(self, items, args)
53

    
54
    command = self.command.upper()
55
    try:
56
      fn = getattr(handler, command)
57
    except AttributeError, err:
58
      raise http.HTTPBadRequest()
59

    
60
    try:
61
      result = fn()
62

    
63
    except errors.OpPrereqError, err:
64
      # TODO: "Not found" is not always the correct error. Ganeti's core must
65
      # differentiate between different error types.
66
      raise http.HTTPNotFound(message=str(err))
67

    
68
    return result
69

    
70

    
71
class RESTHttpServer(http.HTTPServer):
72
  def serve_forever(self):
73
    """Handle one request at a time until told to quit."""
74
    sighandler = utils.SignalHandler([signal.SIGINT, signal.SIGTERM])
75
    try:
76
      while not sighandler.called:
77
        self.handle_request()
78
    finally:
79
      sighandler.Reset()
80

    
81

    
82
def ParseOptions():
83
  """Parse the command line options.
84

    
85
  Returns:
86
    (options, args) as from OptionParser.parse_args()
87

    
88
  """
89
  parser = optparse.OptionParser(description="Ganeti Remote API",
90
                    usage="%prog [-d] [-p port]",
91
                    version="%%prog (ganeti) %s" %
92
                                 constants.RAPI_VERSION)
93
  parser.add_option("-d", "--debug", dest="debug",
94
                    help="Enable some debug messages",
95
                    default=False, action="store_true")
96
  parser.add_option("-p", "--port", dest="port",
97
                    help="Port to run API (%s default)." %
98
                                 constants.RAPI_PORT,
99
                    default=constants.RAPI_PORT, type="int")
100
  parser.add_option("-S", "--https", dest="ssl",
101
                    help="Secure HTTP protocol with SSL",
102
                    default=False, action="store_true")
103
  parser.add_option("-K", "--ssl-key", dest="ssl_key",
104
                    help="SSL key",
105
                    default=None, type="string")
106
  parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
107
                    help="SSL certificate",
108
                    default=None, type="string")
109
  parser.add_option("-f", "--foreground", dest="fork",
110
                    help="Don't detach from the current terminal",
111
                    default=True, action="store_false")
112

    
113
  options, args = parser.parse_args()
114

    
115
  if len(args) != 0:
116
    print >> sys.stderr, "Usage: %s [-d] [-p port]" % sys.argv[0]
117
    sys.exit(1)
118

    
119
  if options.ssl and not (options.ssl_cert and options.ssl_key):
120
    print >> sys.stderr, ("For secure mode please provide "
121
                         "--ssl-key and --ssl-cert arguments")
122
    sys.exit(1)
123

    
124
  return options, args
125

    
126

    
127
def main():
128
  """Main function.
129

    
130
  """
131
  options, args = ParseOptions()
132

    
133
  ssconf.CheckMaster(options.debug)
134

    
135
  if options.fork:
136
    utils.Daemonize(logfile=constants.LOG_RAPISERVER)
137

    
138
  utils.WritePidFile(constants.RAPI_PID)
139

    
140
  log_fd = open(constants.LOG_RAPIACCESS, 'a')
141
  try:
142
    apache_log = http.ApacheLogfile(log_fd)
143
    httpd = RESTHttpServer(("", options.port), RESTRequestHandler,
144
                           httplog=apache_log)
145
    try:
146
      httpd.serve_forever()
147
    finally:
148
      httpd.server_close()
149
      utils.RemovePidFile(constants.RAPI_PID)
150

    
151
  finally:
152
    log_fd.close()
153

    
154
  sys.exit(0)
155

    
156

    
157
if __name__ == '__main__':
158
  main()