forked from ISTI-ansible-roles/ansible-role-mailman
109 lines
3.5 KiB
Django/Jinja
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())
|