Statistics
| Branch: | Tag: | Revision:

root / lib / server / rapi.py @ 1f350e0f

History | View | Annotate | Download (10.6 kB)

1 69cf3abd Michael Hanselmann
#
2 8c229cc7 Oleksiy Mishchenko
#
3 8c229cc7 Oleksiy Mishchenko
4 5224c9bf Michael Hanselmann
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012, 2013 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 a5ce2ea2 Michael Hanselmann
from ganeti import pathutils
51 3cd62121 Michael Hanselmann
from ganeti.rapi import connector
52 5224c9bf Michael Hanselmann
from ganeti.rapi import baserlib
53 3cd62121 Michael Hanselmann
54 b459a848 Andrea Spadaccini
import ganeti.http.auth   # pylint: disable=W0611
55 bc2929fc Michael Hanselmann
import ganeti.http.server
56 3cd62121 Michael Hanselmann
57 bc2929fc Michael Hanselmann
58 7e9760c3 Michael Hanselmann
class RemoteApiRequestContext(object):
59 7e9760c3 Michael Hanselmann
  """Data structure for Remote API requests.
60 7e9760c3 Michael Hanselmann

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

73 3cd62121 Michael Hanselmann
  """
74 b5b67ef9 Michael Hanselmann
  AUTH_REALM = "Ganeti Remote API"
75 b5b67ef9 Michael Hanselmann
76 27a8a190 Michael Hanselmann
  def __init__(self, user_fn, reqauth, _client_cls=None):
77 abe318b3 Michael Hanselmann
    """Initializes this class.
78 abe318b3 Michael Hanselmann

79 abe318b3 Michael Hanselmann
    @type user_fn: callable
80 abe318b3 Michael Hanselmann
    @param user_fn: Function receiving username as string and returning
81 abe318b3 Michael Hanselmann
      L{http.auth.PasswordFileUser} or C{None} if user is not found
82 27a8a190 Michael Hanselmann
    @type reqauth: bool
83 27a8a190 Michael Hanselmann
    @param reqauth: Whether to require authentication
84 abe318b3 Michael Hanselmann

85 abe318b3 Michael Hanselmann
    """
86 b459a848 Andrea Spadaccini
    # pylint: disable=W0233
87 e4ef4343 Michael Hanselmann
    # it seems pylint doesn't see the second parent class there
88 e0003509 Michael Hanselmann
    http.server.HttpServerHandler.__init__(self)
89 b5b67ef9 Michael Hanselmann
    http.auth.HttpServerRequestAuthentication.__init__(self)
90 da04c447 Michael Hanselmann
    self._client_cls = _client_cls
91 3cd62121 Michael Hanselmann
    self._resmap = connector.Mapper()
92 abe318b3 Michael Hanselmann
    self._user_fn = user_fn
93 27a8a190 Michael Hanselmann
    self._reqauth = reqauth
94 a2e60f14 René Nussbaumer
95 377ae13e Michael Hanselmann
  @staticmethod
96 377ae13e Michael Hanselmann
  def FormatErrorMessage(values):
97 377ae13e Michael Hanselmann
    """Formats the body of an error message.
98 377ae13e Michael Hanselmann

99 377ae13e Michael Hanselmann
    @type values: dict
100 377ae13e Michael Hanselmann
    @param values: dictionary with keys C{code}, C{message} and C{explain}.
101 377ae13e Michael Hanselmann
    @rtype: tuple; (string, string)
102 377ae13e Michael Hanselmann
    @return: Content-type and response body
103 377ae13e Michael Hanselmann

104 377ae13e Michael Hanselmann
    """
105 377ae13e Michael Hanselmann
    return (http.HTTP_APP_JSON, serializer.DumpJson(values))
106 377ae13e Michael Hanselmann
107 7e9760c3 Michael Hanselmann
  def _GetRequestContext(self, req):
108 7e9760c3 Michael Hanselmann
    """Returns the context for a request.
109 7e9760c3 Michael Hanselmann

110 7e9760c3 Michael Hanselmann
    The context is cached in the req.private variable.
111 7e9760c3 Michael Hanselmann

112 7e9760c3 Michael Hanselmann
    """
113 7e9760c3 Michael Hanselmann
    if req.private is None:
114 85414b69 Iustin Pop
      (HandlerClass, items, args) = \
115 85414b69 Iustin Pop
                     self._resmap.getController(req.request_path)
116 7e9760c3 Michael Hanselmann
117 7e9760c3 Michael Hanselmann
      ctx = RemoteApiRequestContext()
118 da04c447 Michael Hanselmann
      ctx.handler = HandlerClass(items, args, req, _client_cls=self._client_cls)
119 7e9760c3 Michael Hanselmann
120 7e9760c3 Michael Hanselmann
      method = req.request_method.upper()
121 7e9760c3 Michael Hanselmann
      try:
122 7e9760c3 Michael Hanselmann
        ctx.handler_fn = getattr(ctx.handler, method)
123 f4ad2ef0 Iustin Pop
      except AttributeError:
124 33664046 René Nussbaumer
        raise http.HttpNotImplemented("Method %s is unsupported for path %s" %
125 33664046 René Nussbaumer
                                      (method, req.request_path))
126 7e9760c3 Michael Hanselmann
127 5224c9bf Michael Hanselmann
      ctx.handler_access = baserlib.GetHandlerAccess(ctx.handler, method)
128 b5b67ef9 Michael Hanselmann
129 b5b67ef9 Michael Hanselmann
      # Require permissions definition (usually in the base class)
130 b5b67ef9 Michael Hanselmann
      if ctx.handler_access is None:
131 b5b67ef9 Michael Hanselmann
        raise AssertionError("Permissions definition missing")
132 b5b67ef9 Michael Hanselmann
133 ab221ddf Michael Hanselmann
      # This is only made available in HandleRequest
134 ab221ddf Michael Hanselmann
      ctx.body_data = None
135 ab221ddf Michael Hanselmann
136 7e9760c3 Michael Hanselmann
      req.private = ctx
137 7e9760c3 Michael Hanselmann
138 23ccba04 Michael Hanselmann
    # Check for expected attributes
139 23ccba04 Michael Hanselmann
    assert req.private.handler
140 23ccba04 Michael Hanselmann
    assert req.private.handler_fn
141 23ccba04 Michael Hanselmann
    assert req.private.handler_access is not None
142 23ccba04 Michael Hanselmann
143 7e9760c3 Michael Hanselmann
    return req.private
144 7e9760c3 Michael Hanselmann
145 23ccba04 Michael Hanselmann
  def AuthenticationRequired(self, req):
146 23ccba04 Michael Hanselmann
    """Determine whether authentication is required.
147 85414b69 Iustin Pop

148 85414b69 Iustin Pop
    """
149 27a8a190 Michael Hanselmann
    return self._reqauth or bool(self._GetRequestContext(req).handler_access)
150 85414b69 Iustin Pop
151 b5b67ef9 Michael Hanselmann
  def Authenticate(self, req, username, password):
152 b5b67ef9 Michael Hanselmann
    """Checks whether a user can access a resource.
153 b5b67ef9 Michael Hanselmann

154 b5b67ef9 Michael Hanselmann
    """
155 b5b67ef9 Michael Hanselmann
    ctx = self._GetRequestContext(req)
156 b5b67ef9 Michael Hanselmann
157 abe318b3 Michael Hanselmann
    user = self._user_fn(username)
158 abe318b3 Michael Hanselmann
    if not (user and
159 abe318b3 Michael Hanselmann
            self.VerifyBasicAuthPassword(req, username, password,
160 abe318b3 Michael Hanselmann
                                         user.password)):
161 b5b67ef9 Michael Hanselmann
      # Unknown user or password wrong
162 b5b67ef9 Michael Hanselmann
      return False
163 b5b67ef9 Michael Hanselmann
164 b5b67ef9 Michael Hanselmann
    if (not ctx.handler_access or
165 b5b67ef9 Michael Hanselmann
        set(user.options).intersection(ctx.handler_access)):
166 b5b67ef9 Michael Hanselmann
      # Allow access
167 b5b67ef9 Michael Hanselmann
      return True
168 b5b67ef9 Michael Hanselmann
169 b5b67ef9 Michael Hanselmann
    # Access forbidden
170 b5b67ef9 Michael Hanselmann
    raise http.HttpForbidden()
171 b5b67ef9 Michael Hanselmann
172 16a8967d Michael Hanselmann
  def HandleRequest(self, req):
173 16a8967d Michael Hanselmann
    """Handles a request.
174 3cd62121 Michael Hanselmann

175 3cd62121 Michael Hanselmann
    """
176 7e9760c3 Michael Hanselmann
    ctx = self._GetRequestContext(req)
177 3cd62121 Michael Hanselmann
178 ab221ddf Michael Hanselmann
    # Deserialize request parameters
179 ab221ddf Michael Hanselmann
    if req.request_body:
180 ab221ddf Michael Hanselmann
      # RFC2616, 7.2.1: Any HTTP/1.1 message containing an entity-body SHOULD
181 ab221ddf Michael Hanselmann
      # include a Content-Type header field defining the media type of that
182 ab221ddf Michael Hanselmann
      # body. [...] If the media type remains unknown, the recipient SHOULD
183 ab221ddf Michael Hanselmann
      # treat it as type "application/octet-stream".
184 ab221ddf Michael Hanselmann
      req_content_type = req.request_headers.get(http.HTTP_CONTENT_TYPE,
185 ab221ddf Michael Hanselmann
                                                 http.HTTP_APP_OCTET_STREAM)
186 16b037a9 Michael Hanselmann
      if req_content_type.lower() != http.HTTP_APP_JSON.lower():
187 ab221ddf Michael Hanselmann
        raise http.HttpUnsupportedMediaType()
188 ab221ddf Michael Hanselmann
189 ab221ddf Michael Hanselmann
      try:
190 ab221ddf Michael Hanselmann
        ctx.body_data = serializer.LoadJson(req.request_body)
191 ab221ddf Michael Hanselmann
      except Exception:
192 ab221ddf Michael Hanselmann
        raise http.HttpBadRequest(message="Unable to parse JSON data")
193 ab221ddf Michael Hanselmann
    else:
194 ab221ddf Michael Hanselmann
      ctx.body_data = None
195 ab221ddf Michael Hanselmann
196 3cd62121 Michael Hanselmann
    try:
197 7e9760c3 Michael Hanselmann
      result = ctx.handler_fn()
198 77e1d753 Iustin Pop
    except luxi.TimeoutError:
199 77e1d753 Iustin Pop
      raise http.HttpGatewayTimeout()
200 77e1d753 Iustin Pop
    except luxi.ProtocolError, err:
201 77e1d753 Iustin Pop
      raise http.HttpBadGateway(str(err))
202 3cd62121 Michael Hanselmann
203 16b037a9 Michael Hanselmann
    req.resp_headers[http.HTTP_CONTENT_TYPE] = http.HTTP_APP_JSON
204 ab221ddf Michael Hanselmann
205 ab221ddf Michael Hanselmann
    return serializer.DumpJson(result)
206 8c229cc7 Oleksiy Mishchenko
207 8c229cc7 Oleksiy Mishchenko
208 abe318b3 Michael Hanselmann
class RapiUsers:
209 abe318b3 Michael Hanselmann
  def __init__(self):
210 abe318b3 Michael Hanselmann
    """Initializes this class.
211 abe318b3 Michael Hanselmann

212 abe318b3 Michael Hanselmann
    """
213 abe318b3 Michael Hanselmann
    self._users = None
214 abe318b3 Michael Hanselmann
215 abe318b3 Michael Hanselmann
  def Get(self, username):
216 abe318b3 Michael Hanselmann
    """Checks whether a user exists.
217 abe318b3 Michael Hanselmann

218 abe318b3 Michael Hanselmann
    """
219 abe318b3 Michael Hanselmann
    if self._users:
220 abe318b3 Michael Hanselmann
      return self._users.get(username, None)
221 abe318b3 Michael Hanselmann
    else:
222 abe318b3 Michael Hanselmann
      return None
223 abe318b3 Michael Hanselmann
224 abe318b3 Michael Hanselmann
  def Load(self, filename):
225 abe318b3 Michael Hanselmann
    """Loads a file containing users and passwords.
226 abe318b3 Michael Hanselmann

227 abe318b3 Michael Hanselmann
    @type filename: string
228 abe318b3 Michael Hanselmann
    @param filename: Path to file
229 abe318b3 Michael Hanselmann

230 abe318b3 Michael Hanselmann
    """
231 abe318b3 Michael Hanselmann
    logging.info("Reading users file at %s", filename)
232 abe318b3 Michael Hanselmann
    try:
233 abe318b3 Michael Hanselmann
      try:
234 abe318b3 Michael Hanselmann
        contents = utils.ReadFile(filename)
235 abe318b3 Michael Hanselmann
      except EnvironmentError, err:
236 abe318b3 Michael Hanselmann
        self._users = None
237 abe318b3 Michael Hanselmann
        if err.errno == errno.ENOENT:
238 abe318b3 Michael Hanselmann
          logging.warning("No users file at %s", filename)
239 abe318b3 Michael Hanselmann
        else:
240 abe318b3 Michael Hanselmann
          logging.warning("Error while reading %s: %s", filename, err)
241 abe318b3 Michael Hanselmann
        return False
242 abe318b3 Michael Hanselmann
243 abe318b3 Michael Hanselmann
      users = http.auth.ParsePasswordFile(contents)
244 abe318b3 Michael Hanselmann
245 abe318b3 Michael Hanselmann
    except Exception, err: # pylint: disable=W0703
246 abe318b3 Michael Hanselmann
      # We don't care about the type of exception
247 abe318b3 Michael Hanselmann
      logging.error("Error while parsing %s: %s", filename, err)
248 abe318b3 Michael Hanselmann
      return False
249 abe318b3 Michael Hanselmann
250 abe318b3 Michael Hanselmann
    self._users = users
251 abe318b3 Michael Hanselmann
252 abe318b3 Michael Hanselmann
    return True
253 abe318b3 Michael Hanselmann
254 abe318b3 Michael Hanselmann
255 073c31a5 Michael Hanselmann
class FileEventHandler(asyncnotifier.FileEventHandlerBase):
256 073c31a5 Michael Hanselmann
  def __init__(self, wm, path, cb):
257 e4ef4343 Michael Hanselmann
    """Initializes this class.
258 e4ef4343 Michael Hanselmann

259 073c31a5 Michael Hanselmann
    @param wm: Inotify watch manager
260 073c31a5 Michael Hanselmann
    @type path: string
261 073c31a5 Michael Hanselmann
    @param path: File path
262 e4ef4343 Michael Hanselmann
    @type cb: callable
263 e4ef4343 Michael Hanselmann
    @param cb: Function called on file change
264 e4ef4343 Michael Hanselmann

265 e4ef4343 Michael Hanselmann
    """
266 073c31a5 Michael Hanselmann
    asyncnotifier.FileEventHandlerBase.__init__(self, wm)
267 073c31a5 Michael Hanselmann
268 e4ef4343 Michael Hanselmann
    self._cb = cb
269 073c31a5 Michael Hanselmann
    self._filename = os.path.basename(path)
270 e4ef4343 Michael Hanselmann
271 ac96953d Michael Hanselmann
    # Different Pyinotify versions have the flag constants at different places,
272 ac96953d Michael Hanselmann
    # hence not accessing them directly
273 ac96953d Michael Hanselmann
    mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_CLOSE_WRITE"] |
274 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_DELETE"] |
275 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_FROM"] |
276 ac96953d Michael Hanselmann
            pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_TO"])
277 e4ef4343 Michael Hanselmann
278 073c31a5 Michael Hanselmann
    self._handle = self.AddWatch(os.path.dirname(path), mask)
279 e4ef4343 Michael Hanselmann
280 073c31a5 Michael Hanselmann
  def process_default(self, event):
281 073c31a5 Michael Hanselmann
    """Called upon inotify event.
282 e4ef4343 Michael Hanselmann

283 e4ef4343 Michael Hanselmann
    """
284 073c31a5 Michael Hanselmann
    if event.name == self._filename:
285 073c31a5 Michael Hanselmann
      logging.debug("Received inotify event %s", event)
286 073c31a5 Michael Hanselmann
      self._cb()
287 073c31a5 Michael Hanselmann
288 073c31a5 Michael Hanselmann
289 073c31a5 Michael Hanselmann
def SetupFileWatcher(filename, cb):
290 073c31a5 Michael Hanselmann
  """Configures an inotify watcher for a file.
291 e4ef4343 Michael Hanselmann

292 073c31a5 Michael Hanselmann
  @type filename: string
293 073c31a5 Michael Hanselmann
  @param filename: File to watch
294 073c31a5 Michael Hanselmann
  @type cb: callable
295 073c31a5 Michael Hanselmann
  @param cb: Function called on file change
296 e4ef4343 Michael Hanselmann

297 073c31a5 Michael Hanselmann
  """
298 073c31a5 Michael Hanselmann
  wm = pyinotify.WatchManager()
299 073c31a5 Michael Hanselmann
  handler = FileEventHandler(wm, filename, cb)
300 073c31a5 Michael Hanselmann
  asyncnotifier.AsyncNotifier(wm, default_proc_fun=handler)
301 e4ef4343 Michael Hanselmann
302 e4ef4343 Michael Hanselmann
303 6c948699 Michael Hanselmann
def CheckRapi(options, args):
304 6c948699 Michael Hanselmann
  """Initial checks whether to run or exit with a failure.
305 8c229cc7 Oleksiy Mishchenko

306 8c229cc7 Oleksiy Mishchenko
  """
307 f93427cd Iustin Pop
  if args: # rapi doesn't take any arguments
308 f93427cd Iustin Pop
    print >> sys.stderr, ("Usage: %s [-f] [-d] [-p port] [-b ADDRESS]" %
309 f93427cd Iustin Pop
                          sys.argv[0])
310 be73fc79 Guido Trotter
    sys.exit(constants.EXIT_FAILURE)
311 8c229cc7 Oleksiy Mishchenko
312 04ccf5e9 Guido Trotter
  ssconf.CheckMaster(options.debug)
313 8c229cc7 Oleksiy Mishchenko
314 8b72b05c René Nussbaumer
  # Read SSL certificate (this is a little hackish to read the cert as root)
315 8b72b05c René Nussbaumer
  if options.ssl:
316 8b72b05c René Nussbaumer
    options.ssl_params = http.HttpSslParams(ssl_key_path=options.ssl_key,
317 8b72b05c René Nussbaumer
                                            ssl_cert_path=options.ssl_cert)
318 8b72b05c René Nussbaumer
  else:
319 8b72b05c René Nussbaumer
    options.ssl_params = None
320 8b72b05c René Nussbaumer
321 8c229cc7 Oleksiy Mishchenko
322 3ee53f1f Iustin Pop
def PrepRapi(options, _):
323 3ee53f1f Iustin Pop
  """Prep remote API function, executed with the PID file held.
324 8c229cc7 Oleksiy Mishchenko

325 8c229cc7 Oleksiy Mishchenko
  """
326 04ccf5e9 Guido Trotter
  mainloop = daemon.Mainloop()
327 abe318b3 Michael Hanselmann
328 abe318b3 Michael Hanselmann
  users = RapiUsers()
329 abe318b3 Michael Hanselmann
330 27a8a190 Michael Hanselmann
  handler = RemoteApiHandler(users.Get, options.reqauth)
331 e4ef4343 Michael Hanselmann
332 073c31a5 Michael Hanselmann
  # Setup file watcher (it'll be driven by asyncore)
333 a5ce2ea2 Michael Hanselmann
  SetupFileWatcher(pathutils.RAPI_USERS_FILE,
334 a5ce2ea2 Michael Hanselmann
                   compat.partial(users.Load, pathutils.RAPI_USERS_FILE))
335 e4ef4343 Michael Hanselmann
336 a5ce2ea2 Michael Hanselmann
  users.Load(pathutils.RAPI_USERS_FILE)
337 e4ef4343 Michael Hanselmann
338 e0003509 Michael Hanselmann
  server = \
339 e0003509 Michael Hanselmann
    http.server.HttpServer(mainloop, options.bind_address, options.port,
340 5ae4945a Iustin Pop
                           handler,
341 5ae4945a Iustin Pop
                           ssl_params=options.ssl_params, ssl_verify_peer=False)
342 04ccf5e9 Guido Trotter
  server.Start()
343 073c31a5 Michael Hanselmann
344 3ee53f1f Iustin Pop
  return (mainloop, server)
345 3ee53f1f Iustin Pop
346 073c31a5 Michael Hanselmann
347 b459a848 Andrea Spadaccini
def ExecRapi(options, args, prep_data): # pylint: disable=W0613
348 3ee53f1f Iustin Pop
  """Main remote API function, executed with the PID file held.
349 3ee53f1f Iustin Pop

350 3ee53f1f Iustin Pop
  """
351 3ee53f1f Iustin Pop
  (mainloop, server) = prep_data
352 04ccf5e9 Guido Trotter
  try:
353 04ccf5e9 Guido Trotter
    mainloop.Run()
354 04ccf5e9 Guido Trotter
  finally:
355 04ccf5e9 Guido Trotter
    server.Stop()
356 5675cd1f Iustin Pop
357 3cd62121 Michael Hanselmann
358 d9c82a4e Michael Hanselmann
def Main():
359 04ccf5e9 Guido Trotter
  """Main function.
360 441e7cfd Oleksiy Mishchenko

361 04ccf5e9 Guido Trotter
  """
362 04ccf5e9 Guido Trotter
  parser = optparse.OptionParser(description="Ganeti Remote API",
363 5ae4945a Iustin Pop
                                 usage="%prog [-f] [-d] [-p port] [-b ADDRESS]",
364 5ae4945a Iustin Pop
                                 version="%%prog (ganeti) %s" %
365 5ae4945a Iustin Pop
                                 constants.RELEASE_VERSION)
366 27a8a190 Michael Hanselmann
  parser.add_option("--require-authentication", dest="reqauth",
367 27a8a190 Michael Hanselmann
                    default=False, action="store_true",
368 27a8a190 Michael Hanselmann
                    help=("Disable anonymous HTTP requests and require"
369 27a8a190 Michael Hanselmann
                          " authentication"))
370 04ccf5e9 Guido Trotter
371 3ee53f1f Iustin Pop
  daemon.GenericMain(constants.RAPI, parser, CheckRapi, PrepRapi, ExecRapi,
372 a5ce2ea2 Michael Hanselmann
                     default_ssl_cert=pathutils.RAPI_CERT_FILE,
373 a5ce2ea2 Michael Hanselmann
                     default_ssl_key=pathutils.RAPI_CERT_FILE)