Revision e2be81cf daemons/ganeti-confd

b/daemons/ganeti-confd
32 32
import asyncore
33 33
import socket
34 34
import pyinotify
35
import time
35 36

  
36 37
from optparse import OptionParser
37 38

  
......
191 192
  check, to verify that the reload hasn't failed.
192 193

  
193 194
  """
194
  def __init__(self, reader):
195
  def __init__(self, reader, mainloop):
195 196
    """Constructor for ConfdConfigurationReloader
196 197

  
197 198
    @type reader: L{ssconf.SimpleConfigReader}
198 199
    @param reader: ganeti-confd SimpleConfigReader
200
    @type mainloop: L{daemon.Mainloop}
201
    @param mainloop: ganeti-confd mainloop
199 202

  
200 203
    """
201 204
    self.reader = reader
205
    self.mainloop = mainloop
206

  
207
    self.polling = False
208
    self.last_notification = 0
202 209

  
203 210
    # Asyncronous inotify handler for config changes
204 211
    self.wm = pyinotify.WatchManager()
205 212
    self.inotify_handler = ConfdInotifyEventHandler(self.wm, self.OnInotify)
206 213
    self.notifier = AsyncNotifier(self.wm, self.inotify_handler)
207 214

  
215
    self.timer_handle = None
216
    self._EnableTimer()
217

  
208 218
  def OnInotify(self, notifier_enabled):
209 219
    """Receive an inotify notification.
210 220

  
......
212 222
    @param notifier_enabled: whether the notifier is still enabled
213 223

  
214 224
    """
215
    if not notifier_enabled:
225
    current_time = time.time()
226
    time_delta = current_time - self.last_notification
227
    self.last_notification = current_time
228

  
229
    if time_delta < constants.CONFD_CONFIG_RELOAD_RATELIMIT:
230
      logging.debug("Moving from inotify mode to polling mode")
231
      self.polling = True
232
      if notifier_enabled:
233
        self.confd_event_handler.disable()
234

  
235
    if not self.polling and not notifier_enabled:
216 236
      try:
217 237
        self.inotify_handler.enable()
218 238
      except errors.InotifyError:
......
229 249
      # to quit.
230 250
      raise errors.ConfdFatalError(err)
231 251

  
252
    # Reset the timer. If we're polling it will go to the polling rate, if
253
    # we're not it will delay it again to its base safe timeout.
254
    self._DisableTimer()
255
    self._EnableTimer()
256

  
257
  def _DisableTimer(self):
258
    if self.timer_handle is not None:
259
      self.mainloop.scheduler.cancel(self.timer_handle)
260
      self.timer_handle = None
261

  
262
  def _EnableTimer(self):
263
    if self.polling:
264
      timeout = constants.CONFD_CONFIG_RELOAD_RATELIMIT
265
    else:
266
      timeout = constants.CONFD_CONFIG_RELOAD_TIMEOUT
267

  
268
    if self.timer_handle is None:
269
      self.timer_handle = self.mainloop.scheduler.enter(
270
        timeout, 1, self.OnTimer, [])
271

  
272
  def OnTimer(self):
273
    """Function called when the timer fires
274

  
275
    """
276
    self.timer_handle = None
277
    try:
278
      reloaded = self.reader.Reload()
279
    except errors.ConfigurationError:
280
      # transform a ConfigurationError in a fatal error, that will cause confd
281
      # to quit.
282
      raise errors.ConfdFatalError(err)
283

  
284
    if self.polling and reloaded:
285
      logging.info("Reloaded ganeti config")
286
    elif reloaded:
287
      # We have reloaded the config files, but received no inotify event.  If
288
      # an event is pending though, we just happen to have timed out before
289
      # receiving it, so this is not a problem, and we shouldn't alert
290
      if not self.notifier.check_events():
291
        logging.warning("Config file reload at timeout (inotify failure)")
292
    elif self.polling:
293
      # We're polling, but we haven't reloaded the config:
294
      # Going back to inotify mode
295
      logging.debug("Moving from polling mode to inotify mode")
296
      self.polling = False
297
      self.inotify_handler.enable()
298
    else:
299
      logging.debug("Performed configuration check")
300

  
301
    self._EnableTimer()
232 302

  
233 303

  
234 304
def CheckConfd(options, args):
......
258 328
  server = ConfdAsyncUDPServer(options.bind_address, options.port, processor)
259 329

  
260 330
  # Configuration reloader
261
  reloader = ConfdConfigurationReloader(reader)
331
  reloader = ConfdConfigurationReloader(reader, mainloop)
262 332

  
263 333
  mainloop.Run()
264 334

  

Also available in: Unified diff