Revision e4ef4343 daemons/ganeti-rapi

b/daemons/ganeti-rapi
44 44
from ganeti import ssconf
45 45
from ganeti import luxi
46 46
from ganeti import serializer
47
from ganeti import compat
47 48
from ganeti.rapi import connector
48 49

  
49 50
import ganeti.http.auth   # pylint: disable-msg=W0611
......
88 89

  
89 90
  def __init__(self, *args, **kwargs):
90 91
    # pylint: disable-msg=W0233
91
  # it seems pylint doesn't see the second parent class there
92
    # it seems pylint doesn't see the second parent class there
92 93
    http.server.HttpServer.__init__(self, *args, **kwargs)
93 94
    http.auth.HttpServerRequestAuthentication.__init__(self)
94 95
    self._resmap = connector.Mapper()
96
    self._users = None
95 97

  
96
    # Load password file
97
    if os.path.isfile(constants.RAPI_USERS_FILE):
98
      wm = pyinotify.WatchManager()
99
      hdl = asyncnotifier.SingleFileEventHandler(wm, self._OnUsersFileUpdate,
100
                                                 constants.RAPI_USERS_FILE)
101
      self._users_inotify_handler = hdl
102
      asyncnotifier.AsyncNotifier(wm, default_proc_fun=hdl)
103
      self._users = None
104
      self._OnUsersFileUpdate(False)
105
    else:
106
      self._users = None
107

  
108
  def _OnUsersFileUpdate(self, notifier_enabled):
109
    """Called upon update of the RAPI users file by pyinotify.
98
  def LoadUsers(self, filename):
99
    """Loads a file containing users and passwords.
110 100

  
111
    @type notifier_enabled: boolean
112
    @param notifier_enabled: whether the notifier is still enabled
101
    @type filename: string
102
    @param filename: Path to file
113 103

  
114 104
    """
115
    logging.info("Reloading modified %s", constants.RAPI_USERS_FILE)
105
    if not os.path.isfile(constants.RAPI_USERS_FILE):
106
      logging.warning("Users file %s not found", filename)
107
      return False
116 108

  
117 109
    try:
118
      users = http.auth.ReadPasswordFile(constants.RAPI_USERS_FILE)
119
      self._users = users
110
      users = http.auth.ReadPasswordFile(filename)
120 111
    except Exception, err: # pylint: disable-msg=W0703
121 112
      # We don't care about the type of exception
122
      logging.error("Error while reading %s: %s", constants.RAPI_USERS_FILE,
123
                    err)
113
      logging.error("Error while reading %s: %s", filename, err)
114
      return False
124 115

  
125
    # Renable the watch again if we'd an atomic update of the file (e.g. mv)
126
    if not notifier_enabled:
127
      self._users_inotify_handler.enable()
116
    self._users = users
117
    return True
128 118

  
129 119
  def _GetRequestContext(self, req):
130 120
    """Returns the context for a request.
......
236 226
    return serializer.DumpJson(result)
237 227

  
238 228

  
229
class FileWatcher:
230
  def __init__(self, filename, cb):
231
    """Initializes this class.
232

  
233
    @type filename: string
234
    @param filename: File to watch
235
    @type cb: callable
236
    @param cb: Function called on file change
237

  
238
    """
239
    self._filename = filename
240
    self._cb = cb
241

  
242
    wm = pyinotify.WatchManager()
243
    self._handler = asyncnotifier.SingleFileEventHandler(wm, self._OnInotify,
244
                                                         filename)
245
    asyncnotifier.AsyncNotifier(wm, default_proc_fun=self._handler)
246
    self._handler.enable()
247

  
248
  def _OnInotify(self, notifier_enabled):
249
    """Called upon update of the RAPI users file by pyinotify.
250

  
251
    @type notifier_enabled: boolean
252
    @param notifier_enabled: whether the notifier is still enabled
253

  
254
    """
255
    logging.info("Reloading modified %s", self._filename)
256

  
257
    self._cb()
258

  
259
    # Renable the watch again if we'd an atomic update of the file (e.g. mv)
260
    if not notifier_enabled:
261
      self._handler.enable()
262

  
263

  
239 264
def CheckRapi(options, args):
240 265
  """Initial checks whether to run or exit with a failure.
241 266

  
......
265 290
                               ssl_params=options.ssl_params,
266 291
                               ssl_verify_peer=False,
267 292
                               request_executor_class=JsonErrorRequestExecutor)
293

  
294
  if os.path.exists(constants.RAPI_USERS_FILE):
295
    # Setup file watcher (it'll be driven by asyncore)
296
    FileWatcher(constants.RAPI_USERS_FILE,
297
                compat.partial(server.LoadUsers, constants.RAPI_USERS_FILE))
298

  
299
  server.LoadUsers(constants.RAPI_USERS_FILE)
300

  
268 301
  # pylint: disable-msg=E1101
269 302
  # it seems pylint doesn't see the second parent class there
270 303
  server.Start()

Also available in: Unified diff