Reload keyring on filesystem events
Subscribe to FS events from keyring directory using Python Watchdog and when a modification is observed, reload the key cache. Since we may receive more than one event about a single modification, keep directory's last modification to recognise 'false positives'.
This commit is contained in:
parent
386c23f9f8
commit
eb0d5a1326
|
@ -9,6 +9,7 @@ from aiosmtpd.smtp import Envelope
|
||||||
import asyncio
|
import asyncio
|
||||||
import email
|
import email
|
||||||
import time
|
import time
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
|
||||||
# Mail status constants.
|
# Mail status constants.
|
||||||
#
|
#
|
||||||
|
@ -59,6 +60,13 @@ def _init_controller(keys: kcache.KeyCache, tout: float = 2.5):
|
||||||
return Controller(proxy, hostname=host, port=port, ready_timeout=tout)
|
return Controller(proxy, hostname=host, port=port, ready_timeout=tout)
|
||||||
|
|
||||||
|
|
||||||
|
def _init_reloader(keyring_dir: str, reloader) -> kcache.KeyringModificationListener:
|
||||||
|
listener = kcache.KeyringModificationListener(reloader)
|
||||||
|
observer = Observer()
|
||||||
|
observer.schedule(listener, keyring_dir, recursive=False)
|
||||||
|
return observer
|
||||||
|
|
||||||
|
|
||||||
def _validate_config():
|
def _validate_config():
|
||||||
missing = conf.validate_config()
|
missing = conf.validate_config()
|
||||||
if missing:
|
if missing:
|
||||||
|
@ -71,10 +79,9 @@ def _full_param_name(tup):
|
||||||
return f"[{tup[0]}]{tup[1]}"
|
return f"[{tup[0]}]{tup[1]}"
|
||||||
|
|
||||||
|
|
||||||
async def _sleep(minutes, heartbeat_func):
|
async def _sleep(minutes):
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(minutes * 60)
|
await asyncio.sleep(minutes * 60)
|
||||||
heartbeat_func()
|
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
|
@ -82,18 +89,26 @@ def _main():
|
||||||
|
|
||||||
refresh_min = float(conf.get_item('gpg', 'cache_refresh_minutes', 2))
|
refresh_min = float(conf.get_item('gpg', 'cache_refresh_minutes', 2))
|
||||||
|
|
||||||
keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome'))
|
keyring_path = conf.get_item('gpg', 'keyhome')
|
||||||
|
keys = kcache.KeyCache(keyring_path)
|
||||||
keys.load()
|
keys.load()
|
||||||
controller = _init_controller(keys)
|
controller = _init_controller(keys)
|
||||||
|
reloader = _init_reloader(keyring_path, keys)
|
||||||
|
|
||||||
LOG.info("Starting the daemon...")
|
LOG.info(f'Watching keyring directory {keyring_path}...')
|
||||||
|
reloader.start()
|
||||||
|
|
||||||
|
LOG.info('Starting the daemon...')
|
||||||
controller.start()
|
controller.start()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
asyncio.run(_sleep(refresh_min, keys.load))
|
asyncio.run(_sleep(refresh_min))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
LOG.info("Finishing...")
|
LOG.info("Finishing...")
|
||||||
|
finally:
|
||||||
|
LOG.info('Shutting down keyring watcher and the daemon...')
|
||||||
|
reloader.stop()
|
||||||
|
reloader.join()
|
||||||
controller.stop()
|
controller.stop()
|
||||||
|
|
||||||
LOG.info("Done")
|
LOG.info("Done")
|
||||||
|
|
|
@ -7,6 +7,7 @@ module.
|
||||||
import lacre.text as text
|
import lacre.text as text
|
||||||
import logging
|
import logging
|
||||||
from os import stat
|
from os import stat
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
|
||||||
import GnuPG
|
import GnuPG
|
||||||
|
|
||||||
|
@ -107,3 +108,21 @@ class KeyCache:
|
||||||
MTIME = 8
|
MTIME = 8
|
||||||
st = stat(self._keyring_dir)
|
st = stat(self._keyring_dir)
|
||||||
return st[MTIME]
|
return st[MTIME]
|
||||||
|
|
||||||
|
|
||||||
|
class KeyringModificationListener(FileSystemEventHandler):
|
||||||
|
"""A filesystem event listener that triggers key cache reload."""
|
||||||
|
|
||||||
|
def __init__(self, cache: KeyCache):
|
||||||
|
"""Initialise a listener with a callback to be executed upon each change."""
|
||||||
|
self._cache = cache
|
||||||
|
|
||||||
|
def handle(self, event):
|
||||||
|
"""Reload keys upon FS event."""
|
||||||
|
LOG.debug(f'Reloading on event {event!r}')
|
||||||
|
self._cache.reload()
|
||||||
|
|
||||||
|
# All methods should do the same: reload the key cache.
|
||||||
|
# on_created = handle
|
||||||
|
# on_deleted = handle
|
||||||
|
on_modified = handle
|
||||||
|
|
Loading…
Reference in New Issue