mailman/templates/mailman-hyperkitty-archiver...

109 lines
3.5 KiB
Django/Jinja

#!{{ mailman_bindir }}/python3
"""Disable HyperKitty for Mailman lists whose archive policy is never."""
import argparse
import fcntl
import logging
import sys
from mailman.config import config
from mailman.core.initialize import initialize
from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.mailinglist import IListArchiverSet
from zope.component import getUtility
CONFIG_FILE = {{ (mailman_conf_dir + '/mailman.cfg') | to_json }}
LOCK_FILE = {{ mailman_hyperkitty_archiver_reconciliation_lock | to_json }}
ARCHIVER_NAME = 'hyperkitty'
logging.basicConfig(
level=logging.INFO,
format='mailman-hyperkitty-archiver-reconcile: %(levelname)s: %(message)s')
LOG = logging.getLogger(__name__)
def normalize_policy(value):
if hasattr(value, 'name'):
value = value.name
if isinstance(value, int):
return {0: 'never', 1: 'private', 2: 'public'}.get(value, str(value))
return str(value).strip().lower()
def reconcile(dry_run):
initialize(CONFIG_FILE)
lists = sorted(
getUtility(IListManager).mailing_lists,
key=lambda mailing_list: mailing_list.fqdn_listname.casefold())
candidates = []
for mailing_list in lists:
if normalize_policy(mailing_list.archive_policy) != 'never':
continue
archiver = IListArchiverSet(mailing_list).get(ARCHIVER_NAME)
if archiver is not None and archiver.is_enabled:
candidates.append((mailing_list, archiver))
changed = 0
if dry_run:
for mailing_list, _archiver in candidates:
LOG.info(
'would disable %s for %s (archive policy is never)',
ARCHIVER_NAME, mailing_list.fqdn_listname)
config.db.abort()
else:
for mailing_list, archiver in candidates:
# Re-read both rows before changing them so a concurrent Postorius
# update cannot be overwritten from the initial snapshot.
config.db.store.refresh(mailing_list)
config.db.store.refresh(archiver)
if (normalize_policy(mailing_list.archive_policy) != 'never' or
not archiver.is_enabled):
LOG.warning(
'skipping %s: settings changed during reconciliation',
mailing_list.fqdn_listname)
continue
archiver.is_enabled = False
changed += 1
LOG.info(
'disabled %s for %s (archive policy is never)',
ARCHIVER_NAME, mailing_list.fqdn_listname)
config.db.commit()
LOG.info(
'%d Core lists, %d inconsistent archiver settings, %d changed',
len(lists), len(candidates), changed)
return 0
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--dry-run', action='store_true',
help='report inconsistent lists without changing Mailman Core')
arguments = parser.parse_args()
try:
with open(LOCK_FILE, 'w') as lock_handle:
try:
fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
LOG.error('another reconciliation process holds %s', LOCK_FILE)
return 1
return reconcile(arguments.dry_run)
except Exception as error:
try:
config.db.abort()
except Exception:
# Preserve the original initialization or database exception.
pass
LOG.exception('reconciliation failed: %s', error)
return 1
if __name__ == '__main__':
sys.exit(main())