Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-rapi @ 99e88451

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 utils
35
from ganeti.rapi import connector
36

    
37

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

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

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

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

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

    
59
    try:
60
      result = fn()
61

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

    
67
    return result
68

    
69

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

    
80

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

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

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

    
112
  options, args = parser.parse_args()
113

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

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

    
123
  return options, args
124

    
125

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

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

    
132
  if options.fork:
133
    utils.Daemonize(logfile=constants.LOG_RAPISERVER)
134

    
135
  utils.WritePidFile(constants.RAPI_PID)
136

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

    
148
  finally:
149
    log_fd.close()
150

    
151
  sys.exit(0)
152

    
153

    
154
if __name__ == '__main__':
155
  main()