Statistics
| Branch: | Tag: | Revision:

root / lib / server / rapi.py @ 377ae13e

History | View | Annotate | Download (9.7 kB)

1 69cf3abd Michael Hanselmann
#
2 8c229cc7 Oleksiy Mishchenko
#
3 8c229cc7 Oleksiy Mishchenko
4 b42ea9ed Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 7260cfbe Iustin Pop
"""Ganeti Remote API master script.
22 7260cfbe Iustin Pop

23 8c229cc7 Oleksiy Mishchenko
"""
24 8c229cc7 Oleksiy Mishchenko
25 b459a848 Andrea Spadaccini
# pylint: disable=C0103,W0142
26 7260cfbe Iustin Pop
27 7260cfbe Iustin Pop
# C0103: Invalid name ganeti-watcher
28 7260cfbe Iustin Pop
29 441e7cfd Oleksiy Mishchenko
import logging
30 8c229cc7 Oleksiy Mishchenko
import optparse
31 8c229cc7 Oleksiy Mishchenko
import sys
32 8c229cc7 Oleksiy Mishchenko
import os
33 b5b67ef9 Michael Hanselmann
import os.path
34 073c31a5 Michael Hanselmann
import errno
35 8c229cc7 Oleksiy Mishchenko
36 a2e60f14 René Nussbaumer
try:
37 b459a848 Andrea Spadaccini
  from pyinotify import pyinotify # pylint: disable=E0611
38 a2e60f14 René Nussbaumer
except ImportError:
39 a2e60f14 René Nussbaumer
  import pyinotify
40 a2e60f14 René Nussbaumer
41 a2e60f14 René Nussbaumer
from ganeti import asyncnotifier
42 8c229cc7 Oleksiy Mishchenko
from ganeti import constants
43 3cd62121 Michael Hanselmann
from ganeti import http
44 16a8967d Michael Hanselmann
from ganeti import daemon
45 5675cd1f Iustin Pop
from ganeti import ssconf
46 77e1d753 Iustin Pop
from ganeti import luxi
47 1f8588f6 Iustin Pop
from ganeti import serializer
48 e4ef4343 Michael Hanselmann
from ganeti import compat
49 2287b920 Michael Hanselmann
from ganeti import utils
50 3cd62121 Michael Hanselmann
from ganeti.rapi import connector
51 3cd62121 Michael Hanselmann
52 b459a848 Andrea Spadaccini
import ganeti.http.auth   # pylint: disable=W0611
53 bc2929fc Michael Hanselmann
import ganeti.http.server
54 3cd62121 Michael Hanselmann
55 bc2929fc Michael Hanselmann
56 7e9760c3 Michael Hanselmann
class RemoteApiRequestContext(object):
57 7e9760c3 Michael Hanselmann
  """Data structure for Remote API requests.
58 7e9760c3 Michael Hanselmann

59 7e9760c3 Michael Hanselmann
  """
60 7e9760c3 Michael Hanselmann
  def __init__(self):
61 7e9760c3 Michael Hanselmann
    self.handler = None
62 7e9760c3 Michael Hanselmann
    self.handler_fn = None
63 b5b67ef9 Michael Hanselmann
    self.handler_access = None
64 ab221ddf Michael Hanselmann
    self.body_data = None
65 7e9760c3 Michael Hanselmann
66 7e9760c3 Michael Hanselmann
67 e0003509 Michael Hanselmann
class RemoteApiHandler(http.auth.HttpServerRequestAuthentication,
68 e0003509 Michael Hanselmann
                       http.server.HttpServerHandler):
69 3cd62121 Michael Hanselmann
  """REST Request Handler Class.
70 3cd62121 Michael Hanselmann

71 3cd62121 Michael Hanselmann
  """
72 b5b67ef9 Michael Hanselmann
  AUTH_REALM = "Ganeti Remote API"
73 b5b67ef9 Michael Hanselmann
74 e0003509 Michael Hanselmann
  def __init__(self):
75 b459a848 Andrea Spadaccini
    # pylint: disable=W0233
76 e4ef4343 Michael Hanselmann
    # it seems pylint doesn't see the second parent class there
77 e0003509 Michael Hanselmann
    http.server.HttpServerHandler.__init__(self)
78 b5b67ef9 Michael Hanselmann
    http.auth.HttpServerRequestAuthentication.__init__(self)
79 3cd62121 Michael Hanselmann
    self._resmap = connector.Mapper()
80 e4ef4343 Michael Hanselmann
    self._users = None
81 3cd62121 Michael Hanselmann
82 e4ef4343 Michael Hanselmann
  def LoadUsers(self, filename):
83 e4ef4343 Michael Hanselmann
    """Loads a file containing users and passwords.
84 a2e60f14 René Nussbaumer

85 e4ef4343 Michael Hanselmann
    @type filename: string
86 e4ef4343 Michael Hanselmann
    @param filename: Path to file
87 a2e60f14 René Nussbaumer

88 a2e60f14 René Nussbaumer
    """
89 073c31a5 Michael Hanselmann
    logging.info("Reading users file at %s", filename)
90 2287b920 Michael Hanselmann
    try:
91 073c31a5 Michael Hanselmann
      try:
92 073c31a5 Michael Hanselmann
        contents = utils.ReadFile(filename)
93 073c31a5 Michael Hanselmann
      except EnvironmentError, err:
94 073c31a5 Michael Hanselmann
        self._users = None
95 073c31a5 Michael Hanselmann
        if err.errno == errno.ENOENT:
96 073c31a5 Michael Hanselmann
          logging.warning("No users file at %s", filename)
97 073c31a5 Michael Hanselmann
        else:
98 073c31a5 Michael Hanselmann
          logging.warning("Error while reading %s: %s", filename, err)
99 073c31a5 Michael Hanselmann
        return False
100 a2e60f14 René Nussbaumer
101 2287b920 Michael Hanselmann
      users = http.auth.ParsePasswordFile(contents)
102 073c31a5 Michael Hanselmann
103 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
104 a2e60f14 René Nussbaumer
      # We don't care about the type of exception
105 2287b920 Michael Hanselmann
      logging.error("Error while parsing %s: %s", filename, err)
106 e4ef4343 Michael Hanselmann
      return False
107 a2e60f14 René Nussbaumer
108 e4ef4343 Michael Hanselmann
    self._users = users
109 073c31a5 Michael Hanselmann
110 e4ef4343 Michael Hanselmann
    return True
111 a2e60f14 René Nussbaumer
112 377ae13e Michael Hanselmann
  @staticmethod
113 377ae13e Michael Hanselmann
  def FormatErrorMessage(values):
114 377ae13e Michael Hanselmann
    """Formats the body of an error message.
115 377ae13e Michael Hanselmann

116 377ae13e Michael Hanselmann
    @type values: dict
117 377ae13e Michael Hanselmann
    @param values: dictionary with keys C{code}, C{message} and C{explain}.
118 377ae13e Michael Hanselmann
    @rtype: tuple; (string, string)
119 377ae13e Michael Hanselmann
    @return: Content-type and response body
120 377ae13e Michael Hanselmann

121 377ae13e Michael Hanselmann
    """
122 377ae13e Michael Hanselmann
    return (http.HTTP_APP_JSON, serializer.DumpJson(values))
123 377ae13e Michael Hanselmann
124 7e9760c3 Michael Hanselmann
  def _GetRequestContext(self, req):
125 7e9760c3 Michael Hanselmann
    """Returns the context for a request.
126 7e9760c3 Michael Hanselmann

127 7e9760c3 Michael Hanselmann
    The context is cached in the req.private variable.
128 7e9760c3 Michael Hanselmann

129 7e9760c3 Michael Hanselmann
    """
130 7e9760c3 Michael Hanselmann
    if req.private is None:
131 85414b69 Iustin Pop
      (HandlerClass, items, args) = \
132 85414b69 Iustin Pop
                     self._resmap.getController(req.request_path)
133 7e9760c3 Michael Hanselmann
134 7e9760c3 Michael Hanselmann
      ctx = RemoteApiRequestContext()
135 7e9760c3 Michael Hanselmann
      ctx.handler = HandlerClass(items, args, req)
136 7e9760c3 Michael Hanselmann
137 7e9760c3 Michael Hanselmann
      method = req.request_method.upper()
138 7e9760c3 Michael Hanselmann
      try:
139 7e9760c3 Michael Hanselmann
        ctx.handler_fn = getattr(ctx.handler, method)
140 f4ad2ef0 Iustin Pop
      except AttributeError:
141 33664046 René Nussbaumer
        raise http.HttpNotImplemented("Method %s is unsupported for path %s" %
142 33664046 René Nussbaumer
                                      (method, req.request_path))
143 7e9760c3 Michael Hanselmann
144 b5b67ef9 Michael Hanselmann
      ctx.handler_access = getattr(ctx.handler, "%s_ACCESS" % method, None)
145 b5b67ef9 Michael Hanselmann
146 b5b67ef9 Michael Hanselmann
      # Require permissions definition (usually in the base class)
147 b5b67ef9 Michael Hanselmann
      if ctx.handler_access is None:
148 b5b67ef9 Michael Hanselmann
        raise AssertionError("Permissions definition missing")
149 b5b67ef9 Michael Hanselmann
150 ab221ddf Michael Hanselmann
      # This is only made available in HandleRequest
151 ab221ddf Michael Hanselmann
      ctx.body_data = None
152 ab221ddf Michael Hanselmann
153 7e9760c3 Michael Hanselmann
      req.private = ctx
154 7e9760c3 Michael Hanselmann
155 23ccba04 Michael Hanselmann
    # Check for expected attributes
156 23ccba04 Michael Hanselmann
    assert req.private.handler
157 23ccba04 Michael Hanselmann
    assert req.private.handler_fn
158 23ccba04 Michael Hanselmann
    assert req.private.handler_access is not None
159 23ccba04 Michael Hanselmann
160 7e9760c3 Michael Hanselmann
    return req.private
161 7e9760c3 Michael Hanselmann
162 23ccba04 Michael Hanselmann
  def AuthenticationRequired(self, req):
163 23ccba04 Michael Hanselmann
    """Determine whether authentication is required.
164 85414b69 Iustin Pop

165 85414b69 Iustin Pop
    """
166 23ccba04 Michael Hanselmann
    return bool(self._GetRequestContext(req).handler_access)
167 85414b69 Iustin Pop
168 b5b67ef9 Michael Hanselmann
  def Authenticate(self, req, username, password):
169 b5b67ef9 Michael Hanselmann
    """Checks whether a user can access a resource.
170 b5b67ef9 Michael Hanselmann

171 b5b67ef9 Michael Hanselmann
    """
172 b5b67ef9 Michael Hanselmann
    ctx = self._GetRequestContext(req)
173 b5b67ef9 Michael Hanselmann
174 b5b67ef9 Michael Hanselmann
    # Check username and password
175 b5b67ef9 Michael Hanselmann
    valid_user = False
176 b5b67ef9 Michael Hanselmann
    if self._users:
177 b5b67ef9 Michael Hanselmann
      user = self._users.get(username, None)
178 0b08f096 Michael Hanselmann
      if user and self.VerifyBasicAuthPassword(req, username, password,
179 0b08f096 Michael Hanselmann
                                               user.password):
180 b5b67ef9 Michael Hanselmann
        valid_user = True
181 b5b67ef9 Michael Hanselmann
182 b5b67ef9 Michael Hanselmann
    if not valid_user:
183 b5b67ef9 Michael Hanselmann
      # Unknown user or password wrong
184 b5b67ef9 Michael Hanselmann
      return False
185 b5b67ef9 Michael Hanselmann
186 b5b67ef9 Michael Hanselmann
    if (not ctx.handler_access or
187 b5b67ef9 Michael Hanselmann
        set(user.options).intersection(ctx.handler_access)):
188 b5b67ef9 Michael Hanselmann
      # Allow access
189 b5b67ef9 Michael Hanselmann
      return True
190 b5b67ef9 Michael Hanselmann
191 b5b67ef9 Michael Hanselmann
    # Access forbidden
192 b5b67ef9 Michael Hanselmann
    raise http.HttpForbidden()
193 b5b67ef9 Michael Hanselmann
194 16a8967d Michael Hanselmann
  def HandleRequest(self, req):
195 16a8967d Michael Hanselmann
    """Handles a request.
196 3cd62121 Michael Hanselmann

197 3cd62121 Michael Hanselmann
    """
198 7e9760c3 Michael Hanselmann
    ctx = self._GetRequestContext(req)
199 3cd62121 Michael Hanselmann
200 ab221ddf Michael Hanselmann
    # Deserialize request parameters
201 ab221ddf Michael Hanselmann
    if req.request_body:
202 ab221ddf Michael Hanselmann
      # RFC2616, 7.2.1: Any HTTP/1.1 message containing an entity-body SHOULD
203 ab221ddf Michael Hanselmann
      # include a Content-Type header field defining the media type of that
204 ab221ddf Michael Hanselmann
      # body. [...] If the media type remains unknown, the recipient SHOULD
205 ab221ddf Michael Hanselmann
      # treat it as type "application/octet-stream".
206 ab221ddf Michael Hanselmann
      req_content_type = req.request_headers.get(http.HTTP_CONTENT_TYPE,
207 ab221ddf Michael Hanselmann
                                                 http.HTTP_APP_OCTET_STREAM)
208 16b037a9 Michael Hanselmann
      if req_content_type.lower() != http.HTTP_APP_JSON.lower():
209 ab221ddf Michael Hanselmann
        raise http.HttpUnsupportedMediaType()
210 ab221ddf Michael Hanselmann
211 ab221ddf Michael Hanselmann
      try:
212 ab221ddf Michael Hanselmann
        ctx.body_data = serializer.LoadJson(req.request_body)
213 ab221ddf Michael Hanselmann
      except Exception:
214 ab221ddf Michael Hanselmann
        raise http.HttpBadRequest(message="Unable to parse JSON data")
215 ab221ddf Michael Hanselmann
    else:
216 ab221ddf Michael Hanselmann
      ctx.body_data = None
217 ab221ddf Michael Hanselmann
218 3cd62121 Michael Hanselmann
    try:
219 7e9760c3 Michael Hanselmann
      result = ctx.handler_fn()
220 77e1d753 Iustin Pop
    except luxi.TimeoutError:
221 77e1d753 Iustin Pop
      raise http.HttpGatewayTimeout()
222 77e1d753 Iustin Pop
    except luxi.ProtocolError, err:
223 77e1d753 Iustin Pop
      raise http.HttpBadGateway(str(err))
224 16a8967d Michael Hanselmann
    except:
225 e09fdcfa Iustin Pop
      method = req.request_method.upper()
226 16a8967d Michael Hanselmann
      logging.exception("Error while handling the %s request", method)
227 16a8967d Michael Hanselmann
      raise
228 3cd62121 Michael Hanselmann
229 16b037a9 Michael Hanselmann
    req.resp_headers[http.HTTP_CONTENT_TYPE] = http.HTTP_APP_JSON
230 ab221ddf Michael Hanselmann
231 ab221ddf Michael Hanselmann
    return serializer.DumpJson(result)
232 8c229cc7 Oleksiy Mishchenko
233 8c229cc7 Oleksiy Mishchenko
234 073c31a5 Michael Hanselmann
class FileEventHandler(asyncnotifier.FileEventHandlerBase):
235 073c31a5 Michael Hanselmann
  def __init__(self, wm, path, cb):
236 e4ef4343 Michael Hanselmann
    """Initializes this class.
237 e4ef4343 Michael Hanselmann

238 073c31a5 Michael Hanselmann
    @param wm: Inotify watch manager
239 073c31a5 Michael Hanselmann
    @type path: string
240 073c31a5 Michael Hanselmann
    @param path: File path
241 e4ef4343 Michael Hanselmann
    @type cb: callable
242 e4ef4343 Michael Hanselmann
    @param cb: Function called on file change
243 e4ef4343 Michael Hanselmann

244 e4ef4343 Michael Hanselmann
    """
245 073c31a5 Michael Hanselmann
    asyncnotifier.FileEventHandlerBase.__init__(self, wm)
246 073c31a5 Michael Hanselmann
247 e4ef4343 Michael Hanselmann
    self._cb = cb
248 073c31a5 Michael Hanselmann
    self._filename = os.path.basename(path)
249 e4ef4343 Michael Hanselmann
250 ac96953d Michael Hanselmann
    # Different Pyinotify versions have the flag constants at different places,
251 ac96953d Michael Hanselmann
    # hence not accessing them directly
252 ac96953d Michael Hanselmann
    mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_CLOSE_WRITE"] |
253 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_DELETE"] |
254 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_FROM"] |
255 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_TO"])
256 e4ef4343 Michael Hanselmann
257 073c31a5 Michael Hanselmann
    self._handle = self.AddWatch(os.path.dirname(path), mask)
258 e4ef4343 Michael Hanselmann
259 073c31a5 Michael Hanselmann
  def process_default(self, event):
260 073c31a5 Michael Hanselmann
    """Called upon inotify event.
261 e4ef4343 Michael Hanselmann

262 e4ef4343 Michael Hanselmann
    """
263 073c31a5 Michael Hanselmann
    if event.name == self._filename:
264 073c31a5 Michael Hanselmann
      logging.debug("Received inotify event %s", event)
265 073c31a5 Michael Hanselmann
      self._cb()
266 073c31a5 Michael Hanselmann
267 073c31a5 Michael Hanselmann
268 073c31a5 Michael Hanselmann
def SetupFileWatcher(filename, cb):
269 073c31a5 Michael Hanselmann
  """Configures an inotify watcher for a file.
270 e4ef4343 Michael Hanselmann

271 073c31a5 Michael Hanselmann
  @type filename: string
272 073c31a5 Michael Hanselmann
  @param filename: File to watch
273 073c31a5 Michael Hanselmann
  @type cb: callable
274 073c31a5 Michael Hanselmann
  @param cb: Function called on file change
275 e4ef4343 Michael Hanselmann

276 073c31a5 Michael Hanselmann
  """
277 073c31a5 Michael Hanselmann
  wm = pyinotify.WatchManager()
278 073c31a5 Michael Hanselmann
  handler = FileEventHandler(wm, filename, cb)
279 073c31a5 Michael Hanselmann
  asyncnotifier.AsyncNotifier(wm, default_proc_fun=handler)
280 e4ef4343 Michael Hanselmann
281 e4ef4343 Michael Hanselmann
282 6c948699 Michael Hanselmann
def CheckRapi(options, args):
283 6c948699 Michael Hanselmann
  """Initial checks whether to run or exit with a failure.
284 8c229cc7 Oleksiy Mishchenko

285 8c229cc7 Oleksiy Mishchenko
  """
286 f93427cd Iustin Pop
  if args: # rapi doesn't take any arguments
287 f93427cd Iustin Pop
    print >> sys.stderr, ("Usage: %s [-f] [-d] [-p port] [-b ADDRESS]" %
288 f93427cd Iustin Pop
                          sys.argv[0])
289 be73fc79 Guido Trotter
    sys.exit(constants.EXIT_FAILURE)
290 8c229cc7 Oleksiy Mishchenko
291 04ccf5e9 Guido Trotter
  ssconf.CheckMaster(options.debug)
292 8c229cc7 Oleksiy Mishchenko
293 8b72b05c René Nussbaumer
  # Read SSL certificate (this is a little hackish to read the cert as root)
294 8b72b05c René Nussbaumer
  if options.ssl:
295 8b72b05c René Nussbaumer
    options.ssl_params = http.HttpSslParams(ssl_key_path=options.ssl_key,
296 8b72b05c René Nussbaumer
                                            ssl_cert_path=options.ssl_cert)
297 8b72b05c René Nussbaumer
  else:
298 8b72b05c René Nussbaumer
    options.ssl_params = None
299 8b72b05c René Nussbaumer
300 8c229cc7 Oleksiy Mishchenko
301 3ee53f1f Iustin Pop
def PrepRapi(options, _):
302 3ee53f1f Iustin Pop
  """Prep remote API function, executed with the PID file held.
303 8c229cc7 Oleksiy Mishchenko

304 8c229cc7 Oleksiy Mishchenko
  """
305 04ccf5e9 Guido Trotter
  mainloop = daemon.Mainloop()
306 e0003509 Michael Hanselmann
  handler = RemoteApiHandler()
307 e4ef4343 Michael Hanselmann
308 073c31a5 Michael Hanselmann
  # Setup file watcher (it'll be driven by asyncore)
309 073c31a5 Michael Hanselmann
  SetupFileWatcher(constants.RAPI_USERS_FILE,
310 e0003509 Michael Hanselmann
                   compat.partial(handler.LoadUsers, constants.RAPI_USERS_FILE))
311 e4ef4343 Michael Hanselmann
312 e0003509 Michael Hanselmann
  handler.LoadUsers(constants.RAPI_USERS_FILE)
313 e4ef4343 Michael Hanselmann
314 e0003509 Michael Hanselmann
  server = \
315 e0003509 Michael Hanselmann
    http.server.HttpServer(mainloop, options.bind_address, options.port,
316 377ae13e Michael Hanselmann
      handler, ssl_params=options.ssl_params, ssl_verify_peer=False)
317 04ccf5e9 Guido Trotter
  server.Start()
318 073c31a5 Michael Hanselmann
319 3ee53f1f Iustin Pop
  return (mainloop, server)
320 3ee53f1f Iustin Pop
321 073c31a5 Michael Hanselmann
322 b459a848 Andrea Spadaccini
def ExecRapi(options, args, prep_data): # pylint: disable=W0613
323 3ee53f1f Iustin Pop
  """Main remote API function, executed with the PID file held.
324 3ee53f1f Iustin Pop

325 3ee53f1f Iustin Pop
  """
326 3ee53f1f Iustin Pop
  (mainloop, server) = prep_data
327 04ccf5e9 Guido Trotter
  try:
328 04ccf5e9 Guido Trotter
    mainloop.Run()
329 04ccf5e9 Guido Trotter
  finally:
330 04ccf5e9 Guido Trotter
    server.Stop()
331 5675cd1f Iustin Pop
332 3cd62121 Michael Hanselmann
333 d9c82a4e Michael Hanselmann
def Main():
334 04ccf5e9 Guido Trotter
  """Main function.
335 441e7cfd Oleksiy Mishchenko

336 04ccf5e9 Guido Trotter
  """
337 04ccf5e9 Guido Trotter
  parser = optparse.OptionParser(description="Ganeti Remote API",
338 04ccf5e9 Guido Trotter
                    usage="%prog [-f] [-d] [-p port] [-b ADDRESS]",
339 9e47cad8 Iustin Pop
                    version="%%prog (ganeti) %s" % constants.RELEASE_VERSION)
340 04ccf5e9 Guido Trotter
341 3ee53f1f Iustin Pop
  daemon.GenericMain(constants.RAPI, parser, CheckRapi, PrepRapi, ExecRapi,
342 0648750e Michael Hanselmann
                     default_ssl_cert=constants.RAPI_CERT_FILE,
343 69d89cb5 René Nussbaumer
                     default_ssl_key=constants.RAPI_CERT_FILE)