Add a mailman3 list server
This should now be a largely functional deployment of mailman 3. There are still some bits that need testing but we'll use followup changes to force failure and hold nodes. This deployment of mailman3 uses upstream docker container images. We currently hack up uids and gids to accomodate that. We also hack up the settings file and bind mount it over the upstream file in order to use host networking. We override the hyperkitty index type to xapian. All list domains are hosted in a single installation and we use native vhosting to handle that. We'll deploy this to a new server and migrate one mailing list domain at a time. This will allow us to start with lists.opendev.org and test things like dmarc settings before expanding to the remaining lists. A migration script is also included, which has seen extensive testing on held nodes for importing copies of the production data sets. Change-Id: Ic9bf5cfaf0b87c100a6ce003a6645010a7b50358
This commit is contained in:
parent
220a3ced6d
commit
c1c91886b4
89
inventory/service/group_vars/mailman3.yaml
Normal file
89
inventory/service/group_vars/mailman3.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
exim_queue_interval: '1m'
|
||||
exim_queue_run_max: '50'
|
||||
exim_smtp_accept_max: '100'
|
||||
exim_smtp_accept_max_per_host: '10'
|
||||
iptables_extra_public_tcp_ports:
|
||||
- 25
|
||||
- 80
|
||||
- 443
|
||||
- 465
|
||||
letsencrypt_certs:
|
||||
lists-opendev-org-main:
|
||||
- "{{ inventory_hostname }}"
|
||||
- lists.opendev.org
|
||||
- lists.airshipit.org
|
||||
- lists.katacontainers.io
|
||||
- lists.openinfra.dev
|
||||
- lists.openstack.org
|
||||
- lists.starlingx.io
|
||||
- lists.zuul-ci.org
|
||||
borg_backup_excludes_extra:
|
||||
# db is backed up in dumps, don't capture live files
|
||||
- /var/lib/mailman/database
|
||||
# backed up by streaming backup
|
||||
- /var/backups/mailman-mariadb
|
||||
# Can regenerate indexes from source email files
|
||||
- /var/lib/mailman/web-data/fulltext_index
|
||||
exim_routers:
|
||||
- mailman_verp_router: |
|
||||
{% raw -%}
|
||||
driver = dnslookup
|
||||
condition = ${if or{{eq{$sender_host_address}{127.0.0.1}}\
|
||||
{eq{$sender_host_address}{::1}}}{yes}{no}}
|
||||
{% endraw %}
|
||||
domains = !+local_domains
|
||||
ignore_target_hosts = <; 0.0.0.0; \
|
||||
127.0.0.0/8; \
|
||||
::1/128;fe80::/10;fe \
|
||||
c0::/10;ff00::/8
|
||||
senders = "*-bounces@*"
|
||||
transport = mailman_verp_smtp
|
||||
- dnslookup: '{{ exim_dnslookup_router }}'
|
||||
- system_aliases: '{{ exim_system_aliases_router }}'
|
||||
- domain_aliases: |
|
||||
driver = redirect
|
||||
allow_fail
|
||||
allow_defer
|
||||
data = ${lookup{$local_part@$domain}lsearch{/etc/aliases.domain}}
|
||||
file_transport = address_file
|
||||
pipe_transport = address_pipe
|
||||
- localuser: '{{ exim_localuser_router }}'
|
||||
- mailman_copy: |
|
||||
driver = accept
|
||||
domains = lists.openstack.org
|
||||
local_parts = openstack-discuss
|
||||
transport = local_copy
|
||||
unseen
|
||||
- mailman_router: |
|
||||
driver = accept
|
||||
domains = {{ mm_domains }}
|
||||
local_part_suffix = -admin : \
|
||||
-bounces : -bounces+* : \
|
||||
-confirm : -confirm+* : \
|
||||
-join : -leave : \
|
||||
-owner : -request : \
|
||||
-subscribe : -unsubscribe
|
||||
local_part_suffix_optional
|
||||
require_files = /var/lib/mailman/core/var/lists/${local_part}.${domain}
|
||||
transport = mailman_transport
|
||||
exim_transports:
|
||||
- local_copy: |
|
||||
driver = appendfile
|
||||
file = /var/mail/$local_part
|
||||
group = mail
|
||||
mode = 0660
|
||||
- mailman_transport: |
|
||||
debug_print = "Email for mailman"
|
||||
driver = smtp
|
||||
protocol = lmtp
|
||||
allow_localhost
|
||||
hosts = localhost
|
||||
port = 8024
|
||||
rcpt_include_affixes = true
|
||||
- mailman_verp_smtp: |
|
||||
driver = smtp
|
||||
headers_add = Errors-To: ${return_path}
|
||||
headers_remove = Errors-To
|
||||
max_rcpt = 1
|
||||
return_path = ${local_part:$return_path}+$local_part=$domain@${domain:$return_path}
|
||||
mailman_multihost: true
|
@ -24,11 +24,13 @@ groups:
|
||||
- kdc03.openstack.org
|
||||
- eavesdrop01.opendev.org
|
||||
- paste01.opendev.org
|
||||
- lists01.opendev.org
|
||||
# These are test specific hosts that we add to the backup
|
||||
# group to mimic as much as possible what their prod version
|
||||
# end up doing.
|
||||
- gitea99.opendev.org
|
||||
- review99.opendev.org
|
||||
- lists99.opendev.org
|
||||
# All these servers are "special-cased" in specifically
|
||||
# as they are puppet and should be replaced "soon"
|
||||
- lists.openstack.org
|
||||
@ -89,6 +91,7 @@ groups:
|
||||
- keycloak[0-9]*.opendev.org
|
||||
- lists.katacontainers.io
|
||||
- lists.openstack.org
|
||||
- lists[0-9]*.opendev.org
|
||||
- meetpad[0-9]*.opendev.org
|
||||
- mirror[0-9]*.opendev.org
|
||||
- nb[0-9]*.opendev.org
|
||||
@ -100,8 +103,10 @@ groups:
|
||||
- translate[0-9]*.open*.org
|
||||
- zuul[0-9]*.opendev.org
|
||||
mailman:
|
||||
- lists*.katacontainers.io
|
||||
- lists*.open*.org
|
||||
- lists.katacontainers.io
|
||||
- lists.openstack.org
|
||||
mailman3:
|
||||
- lists[0-9]*.opendev.org
|
||||
meetpad:
|
||||
- meetpad[0-9]*.opendev.org
|
||||
mirror:
|
||||
|
225
inventory/service/host_vars/lists01.opendev.org.yaml
Normal file
225
inventory/service/host_vars/lists01.opendev.org.yaml
Normal file
@ -0,0 +1,225 @@
|
||||
mm_domains: 'lists.openstack.org:lists.zuul-ci.org:lists.airshipit.org:lists.starlingx.io:lists.opendev.org:lists.openinfra.dev:lists.katacontainers.io'
|
||||
exim_local_domains: "@:{{ mm_domains }}"
|
||||
exim_enable_spf: true
|
||||
exim_aliases:
|
||||
root: "{{ ','.join(listadmins|default([])) }}"
|
||||
interop-wg: openstack-discuss
|
||||
openstack: openstack-discuss
|
||||
openstack-dev: openstack-discuss
|
||||
openstack-infra: openstack-discuss
|
||||
openstack-operators: openstack-discuss
|
||||
openstack-security: openstack-discuss
|
||||
openstack-sigs: openstack-discuss
|
||||
openstack-tc: openstack-discuss
|
||||
user-committee: openstack-discuss
|
||||
airship-discuss-owner: spam
|
||||
community-owner: spam
|
||||
edge-computing-owner: spam
|
||||
foundation-board-confidential-owner: spam
|
||||
foundation-board-owner: spam
|
||||
foundation-owner: spam
|
||||
legal-discuss-owner: spam
|
||||
mailman-owner: spam
|
||||
marketing-owner: spam
|
||||
openstack-announce-owner: spam
|
||||
openstack-docs-owner: spam
|
||||
openstack-fr-owner: spam
|
||||
openstack-i18n-owner: spam
|
||||
openstack-infra-owner: spam
|
||||
openstack-ko-owner: spam
|
||||
openstack-qa-owner: spam
|
||||
product-wg-owner: spam
|
||||
user-committee-owner: spam
|
||||
spam: ':fail: delivery temporarily disabled due to ongoing spam flood'
|
||||
# TODO It would be better to bypass verification for postorius@listdomain
|
||||
# and set a :fail: rule for anyone trying to send email to this addr.
|
||||
# But that requires updating our main exim config so that needs more thought.
|
||||
postorius: ':blackhole: outgoing email only from this address'
|
||||
exim_domain_aliases:
|
||||
community@lists.openstack.org: community@lists.openinfra.dev
|
||||
edge-computing@lists.openstack.org: edge-computing@lists.opendev.org
|
||||
foundation@lists.openstack.org: foundation@lists.openinfra.dev
|
||||
foundation-board@lists.openstack.org: foundation-board@lists.openinfra.dev
|
||||
foundation-board-confidential@lists.openstack.org: foundation-board-confidential@lists.openinfra.dev
|
||||
goldmembers@lists.openstack.org: goldmembers@lists.openinfra.dev
|
||||
marketing@lists.openstack.org: marketing@lists.openinfra.dev
|
||||
staff@lists.openstack.org: staff@lists.openinfra.dev
|
||||
summit-programming-committee@lists.openinfra.dev: summit-track-chairs@lists.openinfra.dev
|
||||
summitsponsors@lists.openstack.org: summitsponsors@lists.openinfra.dev
|
||||
mailman_sites:
|
||||
# First entry in this list is the primary web domain
|
||||
- listdomain: lists.opendev.org
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: computing-force-network
|
||||
description: 'Organizing efforts around Computing Force Network related area'
|
||||
owner: 'niujie@outlook.com'
|
||||
- name: edge-computing
|
||||
description: 'Organizing efforts around the edge-computing focus area.'
|
||||
owner: 'ildiko@openinfra.dev'
|
||||
- name: floss-mooc
|
||||
description: 'Discussions & Coordination around the FLOSS MOOC being collaboratively developed here: https://gitlab.com/mooc-floss/mooc-floss'
|
||||
owner: 'knelson@openinfra.dev'
|
||||
- name: nbmp-discuss
|
||||
description: 'Collaborating on Network Based Media Processing related platform and infrastructure systems usage and development.'
|
||||
owner: 'ildiko@openstack.org'
|
||||
- name: openinfralabs
|
||||
description: 'Discussion of the OpenInfra Labs academic and research resource sharing effort'
|
||||
owner: 'mnaser@vexxhost.com'
|
||||
- name: rust-vmm
|
||||
description: 'Collaborating on Rust-based virtual machine monitors.'
|
||||
owner: 'claire@openstack.org'
|
||||
- name: rustyk8s
|
||||
description: 'Collaborating on Rust-based Kubernetes API.'
|
||||
owner: 'allison@lohutok.net'
|
||||
- name: service-announce
|
||||
description: 'Announcement list for OpenDev services.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
- name: service-discuss
|
||||
description: 'Discussion list for OpenDev services.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
- name: service-incident
|
||||
description: 'Private list for OpenDev incident coordination.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
private: true
|
||||
# The domains and lists below are currently commented out as we intend on
|
||||
# deploying a single domain and its lists at a time starting with
|
||||
# lists.opendev.org. As we deploy other domains we can uncomment these
|
||||
# blocks. Double check no new lists are been added or removed first.
|
||||
#- listdomain: lists.airshipit.org
|
||||
# install_languages: ['en']
|
||||
# lists:
|
||||
# - name: airship-announce
|
||||
# description: 'Announcements of Airship releases and other important information.'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
# - name: airship-discuss
|
||||
# description: 'Discussion of Airship usage and development.'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
# - name: airship-embargo-notice
|
||||
# description: 'Embargoed security vulnerability announcements for Airship consumers.'
|
||||
# owner: 'andrew.walters@att.com'
|
||||
# private: true
|
||||
# - name: airship-job-failures
|
||||
# description: 'Notification messages for failures from CICD jobs.'
|
||||
# owner: 'roman.gorshunov@att.com'
|
||||
# - name: airship-security
|
||||
# description: 'Public Airship security advisories.'
|
||||
# owner: 'andrew.walters@att.com'
|
||||
#- listdomain: lists.katacontainers.io
|
||||
# install_languages: ['en']
|
||||
# lists:
|
||||
# - name: embargo-notice
|
||||
# description: 'Announcements of embargoed notices for the Kata Containers project'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
# private: true
|
||||
# - name: kata-dev
|
||||
# description: 'Kata Containers Development Mailing List (not for usage questions)'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
# - name: kata-hypervisor
|
||||
# description: 'Discussion of security and virtualization targeted at container use cases'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
#- listdomain: lists.openinfra.dev
|
||||
# install_languages: ['en']
|
||||
# lists:
|
||||
# - name: community
|
||||
# description: 'The OpenInfra Community team is the main contact point for anybody running a local OpenInfra Group.'
|
||||
# owner: 'allison@openinfra.dev'
|
||||
# - name: foundation
|
||||
# description: 'General discussion list for activities of the OpenInfra Foundation'
|
||||
# owner: 'jonathan@openinfra.dev'
|
||||
# - name: foundation-board
|
||||
# description: 'OpenInfra Foundation Board of Directors'
|
||||
# owner: 'jonathan@openinfra.dev'
|
||||
# - name: foundation-board-confidential
|
||||
# description: 'OpenInfra Foundation Board of Directors'
|
||||
# owner: 'jonathan@openinfra.dev'
|
||||
# private: true
|
||||
# - name: goldmembers
|
||||
# description: 'The discussion list for Gold Members of the OpenInfra Foundation'
|
||||
# owner: 'jonathan@openinfra.dev'
|
||||
# private: true
|
||||
# - name: marketing
|
||||
# description: 'The OpenInfra Marketing list is the meant to facilitate discussion and best practice sharing among marketers and event organizers in the OpenInfra community.'
|
||||
# owner: 'allison@openinfra.dev'
|
||||
# - name: staff
|
||||
# description: 'Private list for OpenInfra Foundation staff members'
|
||||
# owner: 'mark@openinfra.dev'
|
||||
# private: true
|
||||
# - name: summit-track-chairs
|
||||
# description: 'OpenInfra Summit track chair communications'
|
||||
# owner: 'erin@openinfra.dev'
|
||||
# private: true
|
||||
# - name: summitsponsors
|
||||
# description: 'Coordination among OpenInfra Summit event sponsors'
|
||||
# owner: 'erin@openinfra.dev'
|
||||
# private: true
|
||||
#- listdomain: lists.openstack.org
|
||||
# install_languages: ['de', 'fr', 'it', 'ko', 'ru', 'vi', 'zh_TW']
|
||||
# lists:
|
||||
# - name: embargo-notice
|
||||
# description: 'Announcements to stakeholders for embargoed security vulnerabilities.'
|
||||
# owner: 'fungi@yuggoth.org'
|
||||
# private: true
|
||||
# - name: legal-discuss
|
||||
# description: 'Discussions on legal matters related to the project'
|
||||
# owner: 'thierry@openinfra.dev'
|
||||
# - name: openstack-announce
|
||||
# description: 'Key announcements about OpenStack & Security advisories'
|
||||
# owner: 'fungi@yuggoth.org'
|
||||
# - name: openstack-discuss
|
||||
# description: 'Discussion of OpenStack usage and development.'
|
||||
# owner: 'fungi@yuggoth.org'
|
||||
# - name: openstack-es
|
||||
# description: 'Lista de correo acerca de OpenStack en español'
|
||||
# owner: 'flavio@redhat.com'
|
||||
# - name: openstack-fr
|
||||
# description: 'List of the OpenStack french user group'
|
||||
# owner: 'erwan@erwan.com'
|
||||
# - name: openstack-hpc
|
||||
# description: 'High-Performance Computing OpenStack List'
|
||||
# owner: 'brian.schott@nimbisservices.com'
|
||||
# - name: openstack-i18n
|
||||
# description: 'List of the OpenStack Internationalization team.'
|
||||
# owner: 'guoyingc@cn.ibm.com'
|
||||
# - name: openstack-it
|
||||
# description: 'Discussioni su OpenStack in italiano'
|
||||
# owner: 'stefano@openstack.org'
|
||||
# - name: openstack-ko
|
||||
# description: 'OpenStack Korea Community Discussions in Korean (오픈스택 한국 커뮤니티 메일링리스트)'
|
||||
# owner: 'ianyrchoi@gmail.com'
|
||||
# - name: openstack-mentoring
|
||||
# description: 'List to coordinate interactions between mentors and mentees of the OpenStack mentoring program. Also for questions about the mentoring program (i.e. how to get involved, how it works, etc.'
|
||||
# owner: 'amy@demarco.com'
|
||||
# - name: openstack-stable-maint
|
||||
# description: 'A mailing list for the OpenStack Stable Branch test reports.'
|
||||
# owner: 'tony@bakeyournoodle.com'
|
||||
# - name: openstack-zh
|
||||
# description: 'OpenStack社区中文讨论群组'
|
||||
# owner: 'yeluaiesec@gmail.com'
|
||||
# - name: release-announce
|
||||
# description: 'Announcement of official OpenStack releases.'
|
||||
# owner: 'thierry@openstack.org'
|
||||
# - name: release-job-failures
|
||||
# description: 'Notification messages for failures from release-related build jobs.'
|
||||
# owner: 'doug@doughellmann.com'
|
||||
#- listdomain: lists.starlingx.io
|
||||
# install_languages: ['en']
|
||||
# lists:
|
||||
# - name: starlingx-announce
|
||||
# description: 'Announcements of StarlingX releases and other important information.'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
# - name: starlingx-discuss
|
||||
# description: 'Discussion of StarlingX usage and development.'
|
||||
# owner: 'jonathan@openstack.org'
|
||||
#- listdomain: lists.zuul-ci.org
|
||||
# install_languages: ['en']
|
||||
# lists:
|
||||
# - name: zuul-announce
|
||||
# description: 'Announcements of Zuul releases and other important information.'
|
||||
# owner: 'corvus@inaugust.com'
|
||||
# - name: zuul-discuss
|
||||
# description: 'Discussion of Zuul usage and development.'
|
||||
# owner: 'corvus@inaugust.com'
|
||||
# - name: zuul-jobs-failures
|
||||
# description: 'Gets notifications about zuul-jobs periodic job failures.'
|
||||
# owner: 'ssbarnea@redhat.com'
|
@ -45,6 +45,9 @@
|
||||
- name: letsencrypt updated lists-openstack-org-main
|
||||
include_tasks: roles/letsencrypt-create-certs/handlers/restart_apache.yaml
|
||||
|
||||
- name: letsencrypt updated lists-opendev-org-main
|
||||
include_tasks: roles/letsencrypt-create-certs/handlers/restart_apache.yaml
|
||||
|
||||
# Static
|
||||
- name: letsencrypt updated static-opendev-org-main
|
||||
include_tasks: roles/letsencrypt-create-certs/handlers/restart_apache.yaml
|
||||
|
1
playbooks/roles/mailman3/README.rst
Normal file
1
playbooks/roles/mailman3/README.rst
Normal file
@ -0,0 +1 @@
|
||||
Role to configure mailman3.
|
10
playbooks/roles/mailman3/files/99-max_allowed_packet.cnf
Normal file
10
playbooks/roles/mailman3/files/99-max_allowed_packet.cnf
Normal file
@ -0,0 +1,10 @@
|
||||
[mysqldump]
|
||||
# Default is 24MB which is not large enough for all mailman attachments.
|
||||
# This affects clients including mysqldump. It is larger than the server
|
||||
# side because mysqldump apparently can do larger packets to insert blobs.
|
||||
max_allowed_packet=256M
|
||||
|
||||
[mysqld]
|
||||
# Default is 16MB which is not large enough for all mailman attachments.
|
||||
# This affects the server side.
|
||||
max_allowed_packet=128M
|
429
playbooks/roles/mailman3/files/web-settings.py
Normal file
429
playbooks/roles/mailman3/files/web-settings.py
Normal file
@ -0,0 +1,429 @@
|
||||
# This file has been copied from:
|
||||
# https://github.com/maxking/docker-mailman/blob/2693386453ff3865b7c106c6aa456b683bd3bf08/web/mailman-web/settings.py
|
||||
# In order to override the ALLOWED_HOSTS setting.
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 1998-2016 by the Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of Mailman Suite.
|
||||
#
|
||||
# Mailman Suite is free sofware: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Mailman Suite is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with Mailman Suite. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
Django Settings for Mailman Suite (hyperkitty + postorius)
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
import dj_database_url
|
||||
import sys
|
||||
from socket import gethostbyname
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
ADMINS = (
|
||||
('Mailman Suite Admin', 'root@localhost'),
|
||||
)
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# Hosts/domain names that are valid for this site; required if DEBUG is False
|
||||
# See https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = [
|
||||
"localhost", # Archiving API from Mailman, keep it.
|
||||
"127.0.0.1", # Archiving API from Mailman, keep it. OpenDev edit
|
||||
# "lists.your-domain.org",
|
||||
# Add here all production URLs you may have.
|
||||
# The next two entries are commented out to prevent name resolution
|
||||
# problems. This is an opendev local edit.
|
||||
# Note we cannot use settings_local.py as this entry is evaluated at
|
||||
# import time.
|
||||
#"mailman-web",
|
||||
#gethostbyname("mailman-web"),
|
||||
os.environ.get('SERVE_FROM_DOMAIN'),
|
||||
#os.environ.get('DJANGO_ALLOWED_HOSTS'),
|
||||
]
|
||||
|
||||
# We have modified handling of DJANGO_ALLOWED_HOSTS here to deserialize a
|
||||
# list of hosts into a python list of strings.
|
||||
django_allowed_hosts = os.environ.get('DJANGO_ALLOWED_HOSTS')
|
||||
if django_allowed_hosts:
|
||||
ALLOWED_HOSTS.extend(django_allowed_hosts.split(':'))
|
||||
|
||||
# Mailman API credentials
|
||||
MAILMAN_REST_API_URL = os.environ.get('MAILMAN_REST_URL', 'http://mailman-core:8001')
|
||||
MAILMAN_REST_API_USER = os.environ.get('MAILMAN_REST_USER', 'restadmin')
|
||||
MAILMAN_REST_API_PASS = os.environ.get('MAILMAN_REST_PASSWORD', 'restpass')
|
||||
MAILMAN_ARCHIVER_KEY = os.environ.get('HYPERKITTY_API_KEY')
|
||||
MAILMAN_ARCHIVER_FROM = (os.environ.get('MAILMAN_HOST_IP', gethostbyname(os.environ.get('MAILMAN_HOSTNAME', 'mailman-core'))),)
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = []
|
||||
DEFAULT_APPS = [
|
||||
'hyperkitty',
|
||||
'postorius',
|
||||
'django_mailman3',
|
||||
# Uncomment the next line to enable the admin:
|
||||
'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'django_gravatar',
|
||||
'compressor',
|
||||
'haystack',
|
||||
'django_extensions',
|
||||
'django_q',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
]
|
||||
|
||||
MAILMAN_WEB_SOCIAL_AUTH = [
|
||||
'django_mailman3.lib.auth.fedora',
|
||||
'allauth.socialaccount.providers.openid',
|
||||
'allauth.socialaccount.providers.github',
|
||||
'allauth.socialaccount.providers.gitlab',
|
||||
'allauth.socialaccount.providers.google',
|
||||
]
|
||||
|
||||
MIDDLEWARE = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django_mailman3.middleware.TimezoneMiddleware',
|
||||
'postorius.middleware.PostoriusMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.template.context_processors.media',
|
||||
'django.template.context_processors.static',
|
||||
'django.template.context_processors.tz',
|
||||
'django.template.context_processors.csrf',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django_mailman3.context_processors.common',
|
||||
'hyperkitty.context_processors.common',
|
||||
'postorius.context_processors.postorius',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
|
||||
# dj_database_url uses $DATABASE_URL environment variable to create a
|
||||
# django-style-config-dict.
|
||||
# https://github.com/kennethreitz/dj-database-url
|
||||
DATABASES = {
|
||||
'default': dj_database_url.config(conn_max_age=600)
|
||||
}
|
||||
|
||||
# If you're behind a proxy, use the X-Forwarded-Host header
|
||||
# See https://docs.djangoproject.com/en/1.8/ref/settings/#use-x-forwarded-host
|
||||
USE_X_FORWARDED_HOST = True
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_ROOT = '/opt/mailman-web-data/static'
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# Additional locations of static files
|
||||
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
)
|
||||
|
||||
|
||||
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
||||
|
||||
LOGIN_URL = 'account_login'
|
||||
LOGIN_REDIRECT_URL = 'list_index'
|
||||
LOGOUT_URL = 'account_logout'
|
||||
|
||||
|
||||
# Use SERVE_FROM_DOMAIN as the default domain in the email.
|
||||
hostname = os.environ.get('SERVE_FROM_DOMAIN', 'localhost.local')
|
||||
DEFAULT_FROM_EMAIL = 'postorius@{}'.format(hostname)
|
||||
SERVER_EMAIL = 'root@{}'.format(hostname)
|
||||
|
||||
# Change this when you have a real email backend
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = os.environ.get('SMTP_HOST', '')
|
||||
EMAIL_PORT = os.environ.get('SMTP_PORT', 25)
|
||||
EMAIL_HOST_USER = os.environ.get('SMTP_HOST_USER', '')
|
||||
EMAIL_HOST_PASSWORD = os.environ.get('SMTP_HOST_PASSWORD', '')
|
||||
EMAIL_USE_TLS = os.environ.get('SMTP_USE_TLS', False)
|
||||
EMAIL_USE_SSL = os.environ.get('SMTP_USE_SSL', False)
|
||||
|
||||
# Compatibility with Bootstrap 3
|
||||
from django.contrib.messages import constants as messages # flake8: noqa
|
||||
MESSAGE_TAGS = {
|
||||
messages.ERROR: 'danger'
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Social auth
|
||||
#
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
)
|
||||
|
||||
# Django Allauth
|
||||
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
|
||||
ACCOUNT_EMAIL_REQUIRED = True
|
||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||
# You probably want https in production, but this is a dev setup file
|
||||
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
|
||||
ACCOUNT_UNIQUE_EMAIL = True
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = {
|
||||
'openid': {
|
||||
'SERVERS': [
|
||||
dict(id='yahoo',
|
||||
name='Yahoo',
|
||||
openid_url='http://me.yahoo.com'),
|
||||
],
|
||||
},
|
||||
'google': {
|
||||
'SCOPE': ['profile', 'email'],
|
||||
'AUTH_PARAMS': {'access_type': 'online'},
|
||||
},
|
||||
'facebook': {
|
||||
'METHOD': 'oauth2',
|
||||
'SCOPE': ['email'],
|
||||
'FIELDS': [
|
||||
'email',
|
||||
'name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'locale',
|
||||
'timezone',
|
||||
],
|
||||
'VERSION': 'v2.4',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# django-compressor
|
||||
# https://pypi.python.org/pypi/django_compressor
|
||||
#
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/less', 'lessc {infile} {outfile}'),
|
||||
('text/x-scss', 'sassc -t compressed {infile} {outfile}'),
|
||||
('text/x-sass', 'sassc -t compressed {infile} {outfile}'),
|
||||
)
|
||||
|
||||
# On a production setup, setting COMPRESS_OFFLINE to True will bring a
|
||||
# significant performance improvement, as CSS files will not need to be
|
||||
# recompiled on each requests. It means running an additional "compress"
|
||||
# management command after each code upgrade.
|
||||
# http://django-compressor.readthedocs.io/en/latest/usage/#offline-compression
|
||||
# COMPRESS_OFFLINE = True
|
||||
|
||||
#
|
||||
# Full-text search engine
|
||||
#
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
|
||||
'PATH': "/opt/mailman-web-data/fulltext_index",
|
||||
# You can also use the Xapian engine, it's faster and more accurate,
|
||||
# but requires another library.
|
||||
# http://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.html#xapian
|
||||
# Example configuration for Xapian:
|
||||
#'ENGINE': 'xapian_backend.XapianEngine'
|
||||
},
|
||||
}
|
||||
|
||||
import sys
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
# the site admins on every HTTP 500 error when DEBUG=False.
|
||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||
# more details on how to customize your logging configuration.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
},
|
||||
'file':{
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
#'class': 'logging.handlers.WatchedFileHandler',
|
||||
'filename': os.environ.get('DJANGO_LOG_URL','/opt/mailman-web-data/logs/mailmanweb.log'),
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'simple',
|
||||
'level': 'INFO',
|
||||
'stream': sys.stdout,
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins', 'file'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['file'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'hyperkitty': {
|
||||
'handlers': ['file'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'postorius': {
|
||||
'handlers': ['file'],
|
||||
'level': 'INFO',
|
||||
'propagate': True
|
||||
},
|
||||
},
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '%(levelname)s %(asctime)s %(process)d %(name)s %(message)s'
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(message)s'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
if os.environ.get('LOG_TO_CONSOLE') == 'yes':
|
||||
LOGGING['loggers']['django']['handlers'].append('console')
|
||||
LOGGING['loggers']['django.request']['handlers'].append('console')
|
||||
|
||||
# HyperKitty-specific
|
||||
#
|
||||
# Only display mailing-lists from the same virtual host as the webserver
|
||||
FILTER_VHOST = False
|
||||
|
||||
|
||||
Q_CLUSTER = {
|
||||
'timeout': 300,
|
||||
'retry': 300,
|
||||
'save_limit': 100,
|
||||
'orm': 'default',
|
||||
}
|
||||
|
||||
POSTORIUS_TEMPLATE_BASE_URL = os.environ.get('POSTORIUS_TEMPLATE_BASE_URL', 'http://mailman-web:8000')
|
||||
|
||||
DISKCACHE_PATH = os.environ.get('DISKCACHE_PATH', '/opt/mailman-web-data/diskcache')
|
||||
DISKCACHE_SIZE = os.environ.get('DISKCACHE_SIZE', 2 ** 30) # 1 gigabyte
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'diskcache.DjangoCache',
|
||||
'LOCATION': DISKCACHE_PATH,
|
||||
'OPTIONS': {
|
||||
'size_limit': DISKCACHE_SIZE,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
try:
|
||||
from settings_local import *
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Compatibility for older installs that override INSTALLED_APPS
|
||||
if not INSTALLED_APPS:
|
||||
INSTALLED_APPS = DEFAULT_APPS + MAILMAN_WEB_SOCIAL_AUTH
|
21
playbooks/roles/mailman3/files/web-settings_local.py
Normal file
21
playbooks/roles/mailman3/files/web-settings_local.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Override default index system. Xapian will be the default in the next
|
||||
# major release of mailman3, but is currently recommended.
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'xapian_backend.XapianEngine',
|
||||
'PATH': "/opt/mailman-web-data/fulltext_index",
|
||||
},
|
||||
}
|
||||
|
||||
# Disable Gravatar integration since it violates privacy expectations
|
||||
HYPERKITTY_ENABLE_GRAVATAR = False
|
||||
|
||||
# This disables web auth using Google, GitHub, Gitlab, Yahoo,
|
||||
# Fedora, and generic OpenID.
|
||||
# TODO: In the future we will want to enable this specifically for
|
||||
# our keycloak server only.
|
||||
MAILMAN_WEB_SOCIAL_AUTH = []
|
||||
|
||||
FILTER_VHOST = True
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
9
playbooks/roles/mailman3/handlers/main.yaml
Normal file
9
playbooks/roles/mailman3/handlers/main.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
- name: mailman restart apache2
|
||||
service:
|
||||
name: apache2
|
||||
state: restarted
|
||||
|
||||
- name: mailman reload apache2
|
||||
service:
|
||||
name: apache2
|
||||
state: reloaded
|
114
playbooks/roles/mailman3/tasks/create_lists.yaml
Normal file
114
playbooks/roles/mailman3/tasks/create_lists.yaml
Normal file
@ -0,0 +1,114 @@
|
||||
- name: Check if domain exists
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/domains/{{ mm_site.listdomain }}'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: GET
|
||||
body_format: json
|
||||
status_code: [200, 404]
|
||||
register: domain_exists
|
||||
no_log: true
|
||||
|
||||
- name: Create list domain in mm3
|
||||
when: domain_exists.status == 404
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/domains'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
mail_host: "{{ mm_site.listdomain }}"
|
||||
status_code: [201]
|
||||
no_log: true
|
||||
|
||||
- name: Check if list exists
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/lists/{{ mm_list.name }}@{{ mm_site.listdomain }}'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: GET
|
||||
body_format: json
|
||||
status_code: [200, 404]
|
||||
register: list_exists
|
||||
loop: "{{ mm_site.lists }}"
|
||||
loop_control:
|
||||
loop_var: mm_list
|
||||
no_log: true
|
||||
|
||||
- name: Create lists in mm3
|
||||
when: list_exists.results[exists_idx].status == 404
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/lists'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
fqdn_listname: "{{ mm_list.name }}@{{ mm_site.listdomain }}"
|
||||
style_name: "{{ mm_list.private | default('false') | bool | ternary('private-default', 'legacy-default') }}"
|
||||
status_code: [201]
|
||||
loop: "{{ mm_site.lists }}"
|
||||
loop_control:
|
||||
loop_var: mm_list
|
||||
index_var: exists_idx
|
||||
no_log: true
|
||||
|
||||
- name: Set list properties in mm3
|
||||
when: list_exists.results[exists_idx].status == 404
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/lists/{{ mm_list.name }}@{{ mm_site.listdomain }}/config'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: PATCH
|
||||
body_format: json
|
||||
body:
|
||||
description: "{{ mm_list.description }}"
|
||||
advertised: "{{ mm_list.private | default('false') | bool | ternary('false', 'true') }}"
|
||||
# TODO enable this when lynx is present on the container images
|
||||
# convert_html_to_plaintext: "true"
|
||||
process_bounces: "false"
|
||||
filter_extensions:
|
||||
- "exe"
|
||||
- "bat"
|
||||
- "cmd"
|
||||
- "com"
|
||||
- "pif"
|
||||
- "scr"
|
||||
- "vbs"
|
||||
- "cpl"
|
||||
pass_types:
|
||||
- "multipart/mixed"
|
||||
- "multipart/alternative"
|
||||
- "text/plain"
|
||||
status_code: [204]
|
||||
loop: "{{ mm_site.lists }}"
|
||||
loop_control:
|
||||
loop_var: mm_list
|
||||
index_var: exists_idx
|
||||
no_log: true
|
||||
|
||||
- name: Set list owner in mm3
|
||||
when: list_exists.results[exists_idx].status == 404
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/members'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
list_id: "{{ mm_list.name }}.{{ mm_site.listdomain }}"
|
||||
subscriber: "{{ mm_list.owner }}"
|
||||
role: "owner"
|
||||
status_code: [201]
|
||||
loop: "{{ mm_site.lists }}"
|
||||
loop_control:
|
||||
loop_var: mm_list
|
||||
index_var: exists_idx
|
||||
no_log: true
|
278
playbooks/roles/mailman3/tasks/main.yaml
Normal file
278
playbooks/roles/mailman3/tasks/main.yaml
Normal file
@ -0,0 +1,278 @@
|
||||
# The old mailman2 exim config refers to this file. Write it out
|
||||
# to make basic testing happy, but we may need to clean it up or
|
||||
# modify it for mailman3.
|
||||
- name: Write /etc/aliases.domain
|
||||
template:
|
||||
src: "domain_aliases.j2"
|
||||
dest: "/etc/aliases.domain"
|
||||
mode: '0444'
|
||||
|
||||
- name: Create Mailman Group
|
||||
group:
|
||||
name: mailman
|
||||
gid: 10010
|
||||
system: yes
|
||||
|
||||
- name: Create Mailman User
|
||||
user:
|
||||
name: mailman
|
||||
uid: 10010
|
||||
comment: Mailman User
|
||||
shell: /bin/bash
|
||||
home: /var/lib/mailman
|
||||
group: mailman
|
||||
create_home: yes
|
||||
system: yes
|
||||
|
||||
#### Install Mailman ####
|
||||
|
||||
- name: Ensure Mailman core volume directory exists
|
||||
file:
|
||||
state: directory
|
||||
path: "/var/lib/mailman/core"
|
||||
# TODO: undo for https://github.com/maxking/docker-mailman/issues/550
|
||||
owner: 100
|
||||
group: 65533
|
||||
mode: '0755'
|
||||
|
||||
- name: Ensure Mailman database volume directory exists
|
||||
file:
|
||||
state: directory
|
||||
path: "/var/lib/mailman/database"
|
||||
# TODO: undo for https://github.com/maxking/docker-mailman/issues/550
|
||||
owner: 999
|
||||
group: 999
|
||||
mode: '0755'
|
||||
|
||||
- name: Ensure Mailman web volume directories exist
|
||||
file:
|
||||
state: directory
|
||||
path: "/var/lib/mailman/{{ item }}"
|
||||
# TODO: undo for https://github.com/maxking/docker-mailman/issues/550
|
||||
owner: 100
|
||||
group: 101
|
||||
mode: '0755'
|
||||
loop:
|
||||
- import
|
||||
- web
|
||||
- web-data
|
||||
- web-data/fulltext_index
|
||||
- web-data/mm2archives
|
||||
|
||||
- name: Copy our overridden settings.py for mailman-web
|
||||
copy:
|
||||
src: web-settings.py
|
||||
dest: /var/lib/mailman/web/settings.py
|
||||
# TODO: undo for https://github.com/maxking/docker-mailman/issues/550
|
||||
owner: 100
|
||||
group: 101
|
||||
mode: '0644'
|
||||
|
||||
- name: Copy our settings_local.py for mailman-web
|
||||
copy:
|
||||
src: web-settings_local.py
|
||||
dest: /var/lib/mailman/web-data/settings_local.py
|
||||
# TODO: undo for https://github.com/maxking/docker-mailman/issues/550
|
||||
owner: 100
|
||||
group: 101
|
||||
mode: '0644'
|
||||
|
||||
- name: Copy our max_allowed_packet override config
|
||||
copy:
|
||||
src: 99-max_allowed_packet.cnf
|
||||
dest: /var/lib/mailman/99-max_allowed_packet.cnf
|
||||
owner: 999
|
||||
group: 999
|
||||
mode: '0644'
|
||||
|
||||
- name: Ensure /etc/mailman-compose directory
|
||||
file:
|
||||
state: directory
|
||||
path: /etc/mailman-compose
|
||||
mode: '0755'
|
||||
|
||||
- name: Put docker-compose file in place
|
||||
template:
|
||||
src: docker-compose.yaml.j2
|
||||
dest: /etc/mailman-compose/docker-compose.yaml
|
||||
mode: '0600'
|
||||
|
||||
- name: Run docker-compose pull
|
||||
shell:
|
||||
cmd: docker-compose pull
|
||||
chdir: /etc/mailman-compose/
|
||||
|
||||
- name: Run docker-compose up
|
||||
shell:
|
||||
cmd: docker-compose up -d
|
||||
chdir: /etc/mailman-compose/
|
||||
|
||||
- name: Run docker prune to cleanup unneeded images
|
||||
shell:
|
||||
cmd: docker image prune -f
|
||||
|
||||
- name: Install apache2
|
||||
package:
|
||||
name:
|
||||
- apache2
|
||||
- apache2-utils
|
||||
state: present
|
||||
|
||||
- name: Apache modules
|
||||
apache2_module:
|
||||
state: present
|
||||
name: "{{ a2_mod }}"
|
||||
loop:
|
||||
- authz_host
|
||||
- proxy
|
||||
- proxy_uwsgi
|
||||
- ssl
|
||||
- rewrite
|
||||
loop_control:
|
||||
loop_var: a2_mod
|
||||
notify: mailman restart apache2
|
||||
|
||||
- name: Make sure packaged default site disabled
|
||||
command: a2dissite 000-default.conf
|
||||
args:
|
||||
removes: /etc/apache2/sites-enabled/000-default.conf
|
||||
|
||||
- name: Create mailman vhost config
|
||||
template:
|
||||
src: mailman.vhost.j2
|
||||
dest: "/etc/apache2/sites-enabled/50-{{ mailman_sites.0.listdomain }}.conf"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify: mailman reload apache2
|
||||
|
||||
- name: Enable apache2 server
|
||||
service:
|
||||
name: "apache2"
|
||||
enabled: yes
|
||||
|
||||
#### Configure Mailman Services ####
|
||||
|
||||
- name: Wait for mm3 REST API to be up and running
|
||||
uri:
|
||||
url: 'http://localhost:8001/3.1/domains'
|
||||
url_username: restadmin
|
||||
url_password: "{{ mailman3_rest_password }}"
|
||||
force_basic_auth: yes
|
||||
method: GET
|
||||
register: mm_rest_api_up
|
||||
delay: 1
|
||||
retries: 300
|
||||
until: mm_rest_api_up and mm_rest_api_up.status == 200
|
||||
no_log: true
|
||||
|
||||
# It has been difficult to nail down a reliable mathod for determining
|
||||
# when the database is sufficiently populated that we can create the django
|
||||
# admin user. We apply a number of approaches in response to this. If we
|
||||
# can identify a single method that is reliable this list can be trimmed.
|
||||
- name: Wait for DB to be populated
|
||||
command: >
|
||||
docker exec mailman-compose_database_1 bash -c
|
||||
'mysql -u mailman -p"$MYSQL_PASSWORD" -D mailmandb -e
|
||||
"SHOW TABLES LIKE \"auth_user\";"'
|
||||
register: django_db_exists
|
||||
delay: 1
|
||||
retries: 300
|
||||
until: django_db_exists.stdout_lines | length > 1 and django_db_exists.stdout_lines[1] == "auth_user"
|
||||
|
||||
- name: Wait for DB to be populated second approach
|
||||
command: >
|
||||
docker exec mailman-core alembic -c /usr/lib/python3.9/site-packages/mailman/config/alembic.cfg current
|
||||
register: alembic_version
|
||||
delay: 1
|
||||
retries: 300
|
||||
until: alembic_version.stdout_lines | length > 0 and "(head)" in alembic_version.stdout_lines[0]
|
||||
|
||||
- name: Wait for DB to be populated third approach
|
||||
shell: >
|
||||
docker exec mailman-web bash -c
|
||||
'python3 manage.py showmigrations' |
|
||||
grep -q '^ \[ \] [0-9]\+_.*'
|
||||
register: django_db_migrations
|
||||
delay: 1
|
||||
retries: 300
|
||||
failed_when: false
|
||||
# When grep stops matching the empty '[ ]' that indicates all migrations
|
||||
# are marked with '[X]' and are complete. Grep returns non zero when we
|
||||
# reach this point.
|
||||
until: django_db_migrations.rc != 0
|
||||
|
||||
- name: Check if django admin user exists
|
||||
command: >
|
||||
docker exec mailman-compose_database_1 bash -c
|
||||
'mysql -u mailman -p"$MYSQL_PASSWORD" -D mailmandb -e
|
||||
"SELECT COUNT(id) FROM auth_user WHERE id = 1 AND is_superuser = 1;"'
|
||||
register: django_admin_exists
|
||||
|
||||
- name: Create django admin user
|
||||
when: django_admin_exists.stdout_lines[1] == "0"
|
||||
command: >
|
||||
docker exec mailman-web bash -c
|
||||
"DJANGO_SUPERUSER_PASSWORD={{ mailman3_admin_password }}
|
||||
python3 manage.py createsuperuser --no-input
|
||||
--username {{ mailman3_admin_user }}
|
||||
--email '{{ mailman3_admin_email }}'"
|
||||
no_log: true
|
||||
|
||||
- name: Create lists in mm3
|
||||
include_tasks: create_lists.yaml
|
||||
loop: "{{ mailman_sites }}"
|
||||
loop_control:
|
||||
loop_var: mm_site
|
||||
|
||||
#### Logrotate for service logs ####
|
||||
|
||||
- name: Rotate mailman logs
|
||||
include_role:
|
||||
name: logrotate
|
||||
vars:
|
||||
logrotate_rotate: 90
|
||||
logrotate_file_name: '/var/lib/mailman/web-data/logs/*.log'
|
||||
|
||||
#### Database Backups ####
|
||||
|
||||
- name: Create db backup dest
|
||||
file:
|
||||
state: directory
|
||||
path: /var/backups/mailman-mariadb
|
||||
mode: 0700
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Set up cron job to backup the database
|
||||
cron:
|
||||
name: mailman-db-backup
|
||||
state: present
|
||||
user: root
|
||||
job: >
|
||||
/usr/local/bin/docker-compose -f /etc/mailman-compose/docker-compose.yaml exec -T database
|
||||
bash -c '/usr/bin/mysqldump --opt --databases mailmandb --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"' |
|
||||
gzip -9 > /var/backups/mailman-mariadb/mailman-mariadb.sql.gz
|
||||
minute: 14
|
||||
hour: 5
|
||||
|
||||
- name: Rotate db backups
|
||||
include_role:
|
||||
name: logrotate
|
||||
vars:
|
||||
logrotate_file_name: /var/backups/mailman-mariadb/mailman-mariadb.sql.gz
|
||||
logrotate_compress: false
|
||||
|
||||
- name: Setup db backup streaming job
|
||||
block:
|
||||
- name: Create backup streaming config dir
|
||||
file:
|
||||
path: /etc/borg-streams
|
||||
state: directory
|
||||
|
||||
- name: Create db streaming file
|
||||
copy:
|
||||
content: >-
|
||||
/usr/local/bin/docker-compose -f /etc/mailman-compose/docker-compose.yaml exec -T mariadb
|
||||
bash -c '/usr/bin/mysqldump --skip-extended-insert --databases mailmandb --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"'
|
||||
dest: /etc/borg-streams/mysql
|
71
playbooks/roles/mailman3/templates/docker-compose.yaml.j2
Normal file
71
playbooks/roles/mailman3/templates/docker-compose.yaml.j2
Normal file
@ -0,0 +1,71 @@
|
||||
# Adapted from https://github.com/maxking/docker-mailman/blob/2693386453ff3865b7c106c6aa456b683bd3bf08/docker-compose-mysql.yaml
|
||||
# which is an MIT licensed repo.
|
||||
|
||||
version: '2'
|
||||
services:
|
||||
mailman-core:
|
||||
image: docker.io/maxking/mailman-core:0.4
|
||||
restart: always
|
||||
container_name: mailman-core
|
||||
volumes:
|
||||
- /var/lib/mailman/core:/opt/mailman/
|
||||
- /var/lib/mailman/import:/opt/import
|
||||
stop_grace_period: 30s
|
||||
depends_on:
|
||||
- database
|
||||
environment:
|
||||
- DATABASE_URL=mysql+pymysql://mailman:{{ mailman3_db_password }}@127.0.0.1:3306/mailmandb?charset=utf8mb4&use_unicode=1
|
||||
- DATABASE_TYPE=mysql
|
||||
- DATABASE_CLASS=mailman.database.mysql.MySQLDatabase
|
||||
- HYPERKITTY_URL=http://127.0.0.1:8000/hyperkitty
|
||||
- HYPERKITTY_API_KEY={{ mailman3_hyperkitty_api_key }}
|
||||
- SMTP_HOST=localhost
|
||||
- MM_HOSTNAME=localhost
|
||||
- MAILMAN_REST_USER=restadmin
|
||||
- MAILMAN_REST_PASSWORD={{ mailman3_rest_password }}
|
||||
network_mode: host
|
||||
#user: mailman
|
||||
|
||||
mailman-web:
|
||||
image: docker.io/maxking/mailman-web:0.4
|
||||
restart: always
|
||||
container_name: mailman-web
|
||||
depends_on:
|
||||
- database
|
||||
volumes:
|
||||
- /var/lib/mailman/import:/opt/import
|
||||
- /var/lib/mailman/web-data:/opt/mailman-web-data
|
||||
- /var/lib/mailman/web/settings.py:/opt/mailman-web/settings.py
|
||||
environment:
|
||||
# Testing to see if these are really necessary
|
||||
#- MAILMAN_ADMIN_USER={{ mailman3_admin_user }}
|
||||
#- MAILMAN_ADMIN_EMAIL={{ mailman3_admin_email }}
|
||||
- SERVE_FROM_DOMAIN=lists.opendev.org
|
||||
- DJANGO_ALLOWED_HOSTS={{ mm_domains }}
|
||||
- DATABASE_TYPE=mysql
|
||||
- DATABASE_URL=mysql://mailman:{{ mailman3_db_password }}@127.0.0.1:3306/mailmandb?charset=utf8mb4
|
||||
- HYPERKITTY_API_KEY={{ mailman3_hyperkitty_api_key }}
|
||||
- SECRET_KEY={{ mailman3_django_secret_key }}
|
||||
- DYLD_LIBRARY_PATH=/usr/local/mysql/lib/
|
||||
- MAILMAN_HOSTNAME=localhost
|
||||
- MAILMAN_REST_URL=http://127.0.0.1:8001
|
||||
- MAILMAN_REST_USER=restadmin
|
||||
- MAILMAN_REST_PASSWORD={{ mailman3_rest_password }}
|
||||
- POSTORIUS_TEMPLATE_BASE_URL=http://127.0.0.1:8000
|
||||
- SMTP_HOST=localhost
|
||||
network_mode: host
|
||||
#user: mailman
|
||||
|
||||
database:
|
||||
environment:
|
||||
MYSQL_DATABASE: mailmandb
|
||||
MYSQL_USER: mailman
|
||||
MYSQL_PASSWORD: {{ mailman3_db_password }}
|
||||
MYSQL_ROOT_PASSWORD: {{ mailman3_db_root_password }}
|
||||
image: docker.io/library/mariadb:10.6
|
||||
restart: always
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
volumes:
|
||||
- /var/lib/mailman/database:/var/lib/mysql
|
||||
- /var/lib/mailman/99-max_allowed_packet.cnf:/etc/mysql/conf.d/99-max_allowed_packet.cnf:ro
|
||||
network_mode: host
|
6
playbooks/roles/mailman3/templates/domain_aliases.j2
Normal file
6
playbooks/roles/mailman3/templates/domain_aliases.j2
Normal file
@ -0,0 +1,6 @@
|
||||
# /etc/aliases.domain
|
||||
{% for k, v in exim_domain_aliases|dictsort %}
|
||||
{% if v %}
|
||||
{{ k }}: {{ v }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
69
playbooks/roles/mailman3/templates/mailman.vhost.j2
Normal file
69
playbooks/roles/mailman3/templates/mailman.vhost.j2
Normal file
@ -0,0 +1,69 @@
|
||||
<VirtualHost *:80>
|
||||
ServerName {{ mailman_sites.0.listdomain }}
|
||||
{% for site in mailman_sites[1:] -%}
|
||||
ServerAlias {{ site.listdomain }}
|
||||
{% endfor -%}
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/{{ mailman_sites.0.listdomain }}-error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/{{ mailman_sites.0.listdomain }}-access.log combined
|
||||
|
||||
# Use mod rewrite to redirect as we want to preserve the FQDN for each
|
||||
# mm3 vhost.
|
||||
RewriteEngine On
|
||||
RewriteRule "/(.*)" "https://%{HTTP_HOST}/$1" [R=301]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerName {{ mailman_sites.0.listdomain }}
|
||||
{% for site in mailman_sites[1:] -%}
|
||||
ServerAlias {{ site.listdomain }}
|
||||
{% endfor -%}
|
||||
ServerAdmin webmaster@openstack.org
|
||||
ErrorLog ${APACHE_LOG_DIR}/{{ mailman_sites.0.listdomain }}-ssl-error.log
|
||||
LogLevel warn
|
||||
CustomLog ${APACHE_LOG_DIR}/{{ mailman_sites.0.listdomain }}-ssl-access.log combined
|
||||
|
||||
SSLEngine on
|
||||
SSLProtocol All -SSLv2 -SSLv3
|
||||
# Note: this list should ensure ciphers that provide forward secrecy
|
||||
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!AES256:!aNULL:!eNULL:!MD5:!DSS:!PSK:!SRP
|
||||
SSLHonorCipherOrder on
|
||||
|
||||
SSLCertificateFile /etc/letsencrypt-certs/{{ inventory_hostname }}/{{ inventory_hostname }}.cer
|
||||
SSLCertificateKeyFile /etc/letsencrypt-certs/{{ inventory_hostname }}/{{ inventory_hostname }}.key
|
||||
SSLCertificateChainFile /etc/letsencrypt-certs/{{ inventory_hostname }}/ca.cer
|
||||
|
||||
Alias /static /var/lib/mailman/web-data/static
|
||||
Alias /favicon.ico /var/lib/mailman/web-data/static/hyperkitty/img/favicon.ico
|
||||
|
||||
<Location "/admin">
|
||||
Require local
|
||||
</Location>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteRule "/pipermail/(.*)" "/var/lib/mailman/web-data/mm2archives/%{HTTP_HOST}/public/$1"
|
||||
RewriteRule "/cgi-bin/mailman/listinfo/(.*)" "https://%{HTTP_HOST}/postorius/lists/$1.%{HTTP_HOST}/"
|
||||
RewriteRule "/cgi-bin/mailman/listinfo" "https://%{HTTP_HOST}/postorius/lists/"
|
||||
|
||||
ProxyPassMatch ^/static/ !
|
||||
ProxyPass "/" "uwsgi://localhost:8080/"
|
||||
|
||||
<Directory /var/lib/mailman/web-data/static/>
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /var/lib/mailman/web-data/mm2archives/>
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
Require all granted
|
||||
</Directory>
|
||||
</VirtualHost>
|
10
playbooks/service-lists3.yaml
Normal file
10
playbooks/service-lists3.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
# Maintaing a todo list here as a central accounting file
|
||||
# TODO Test mailman dmarc settings
|
||||
# TODO fix container uid/gid mismatch with bind mounted contents
|
||||
# this breaks xapian
|
||||
- hosts: "mailman3:!disabled"
|
||||
name: "Configure mailman3 servers"
|
||||
roles:
|
||||
- iptables
|
||||
- install-docker
|
||||
- mailman3
|
294
playbooks/zuul/files/host_vars/lists99.opendev.org.yaml
Normal file
294
playbooks/zuul/files/host_vars/lists99.opendev.org.yaml
Normal file
@ -0,0 +1,294 @@
|
||||
mailman_list_password: notarealpassword
|
||||
mailman3_db_password: Eith5vii5beezohc
|
||||
mailman3_db_root_password: eiloh9Edohngaeri
|
||||
mailman3_hyperkitty_api_key: Thosai4Xomeque9e
|
||||
mailman3_django_secret_key: ohki3ohWusai8tee
|
||||
mailman3_rest_password: OhTo3doh5ohsuope
|
||||
mailman3_admin_user: admin
|
||||
mailman3_admin_email: infra-root@openstack.org
|
||||
mailman3_admin_password: AeNie8vegeiquei1
|
||||
mm_domains: 'lists.openstack.org:lists.zuul-ci.org:lists.airshipit.org:lists.starlingx.io:lists.opendev.org:lists.openinfra.dev:lists.katacontainers.io'
|
||||
exim_local_domains: "@:{{ mm_domains }}"
|
||||
exim_enable_spf: true
|
||||
exim_aliases:
|
||||
root: "{{ ','.join(listadmins|default([])) }}"
|
||||
interop-wg: openstack-discuss
|
||||
openstack: openstack-discuss
|
||||
openstack-dev: openstack-discuss
|
||||
openstack-infra: openstack-discuss
|
||||
openstack-operators: openstack-discuss
|
||||
openstack-security: openstack-discuss
|
||||
openstack-sigs: openstack-discuss
|
||||
openstack-tc: openstack-discuss
|
||||
user-committee: openstack-discuss
|
||||
airship-discuss-owner: spam
|
||||
community-owner: spam
|
||||
edge-computing-owner: spam
|
||||
foundation-board-confidential-owner: spam
|
||||
foundation-board-owner: spam
|
||||
foundation-owner: spam
|
||||
legal-discuss-owner: spam
|
||||
mailman-owner: spam
|
||||
marketing-owner: spam
|
||||
openstack-announce-owner: spam
|
||||
openstack-docs-owner: spam
|
||||
openstack-fr-owner: spam
|
||||
openstack-i18n-owner: spam
|
||||
openstack-infra-owner: spam
|
||||
openstack-ko-owner: spam
|
||||
openstack-qa-owner: spam
|
||||
product-wg-owner: spam
|
||||
user-committee-owner: spam
|
||||
spam: ':fail: delivery temporarily disabled due to ongoing spam flood'
|
||||
# TODO It would be better to bypass verification for postorius@listdomain
|
||||
# and set a :fail: rule for anyone trying to send email to this addr.
|
||||
# But that requires updating our main exim config so that needs more thought.
|
||||
postorius: ':blackhole: outgoing email only from this address'
|
||||
exim_domain_aliases:
|
||||
community@lists.openstack.org: community@lists.openinfra.dev
|
||||
edge-computing@lists.openstack.org: edge-computing@lists.opendev.org
|
||||
foundation@lists.openstack.org: foundation@lists.openinfra.dev
|
||||
foundation-board@lists.openstack.org: foundation-board@lists.openinfra.dev
|
||||
foundation-board-confidential@lists.openstack.org: foundation-board-confidential@lists.openinfra.dev
|
||||
goldmembers@lists.openstack.org: goldmembers@lists.openinfra.dev
|
||||
marketing@lists.openstack.org: marketing@lists.openinfra.dev
|
||||
staff@lists.openstack.org: staff@lists.openinfra.dev
|
||||
summit-programming-committee@lists.openinfra.dev: summit-track-chairs@lists.openinfra.dev
|
||||
summitsponsors@lists.openstack.org: summitsponsors@lists.openinfra.dev
|
||||
exim_routers:
|
||||
- mailman_verp_router: |
|
||||
{% raw -%}
|
||||
driver = dnslookup
|
||||
condition = ${if or{{eq{$sender_host_address}{127.0.0.1}}\
|
||||
{eq{$sender_host_address}{::1}}}{yes}{no}}
|
||||
{% endraw %}
|
||||
domains = !+local_domains
|
||||
ignore_target_hosts = <; 0.0.0.0; \
|
||||
64.94.110.11; \
|
||||
127.0.0.0/8; \
|
||||
::1/128;fe80::/10;fe \
|
||||
c0::/10;ff00::/8
|
||||
senders = "*-bounces@*"
|
||||
transport = mailman_verp_smtp
|
||||
- dnslookup: '{{ exim_dnslookup_router }}'
|
||||
- system_aliases: '{{ exim_system_aliases_router }}'
|
||||
- domain_aliases: |
|
||||
driver = redirect
|
||||
allow_fail
|
||||
allow_defer
|
||||
data = ${lookup{$local_part@$domain}lsearch{/etc/aliases.domain}}
|
||||
file_transport = address_file
|
||||
pipe_transport = address_pipe
|
||||
- localuser: '{{ exim_localuser_router }}'
|
||||
- mailman_copy: |
|
||||
driver = accept
|
||||
domains = lists.openstack.org
|
||||
local_parts = openstack-discuss
|
||||
transport = local_copy
|
||||
unseen
|
||||
- mailman_router: |
|
||||
driver = accept
|
||||
domains = {{ mm_domains }}
|
||||
local_part_suffix = -admin : \
|
||||
-bounces : -bounces+* : \
|
||||
-confirm : -confirm+* : \
|
||||
-join : -leave : \
|
||||
-owner : -request : \
|
||||
-subscribe : -unsubscribe
|
||||
local_part_suffix_optional
|
||||
require_files = /var/lib/mailman/core/var/lists/${local_part}.${domain}
|
||||
transport = mailman_transport
|
||||
exim_transports:
|
||||
- local_copy: |
|
||||
driver = appendfile
|
||||
file = /var/mail/$local_part
|
||||
group = mail
|
||||
mode = 0660
|
||||
- mailman_transport: |
|
||||
debug_print = "Email for mailman"
|
||||
driver = smtp
|
||||
protocol = lmtp
|
||||
allow_localhost
|
||||
hosts = localhost
|
||||
port = 8024
|
||||
rcpt_include_affixes = true
|
||||
- mailman_verp_smtp: |
|
||||
driver = smtp
|
||||
headers_add = Errors-To: ${return_path}
|
||||
headers_remove = Errors-To
|
||||
max_rcpt = 1
|
||||
return_path = ${local_part:$return_path}+$local_part=$domain@${domain:$return_path}
|
||||
mailman_multihost: true
|
||||
mailman_sites:
|
||||
# First entry in this list is the primary web domain
|
||||
- listdomain: lists.opendev.org
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: computing-force-network
|
||||
description: 'Organizing efforts around Computing Force Network related area'
|
||||
owner: 'niujie@outlook.com'
|
||||
- name: edge-computing
|
||||
description: 'Organizing efforts around the edge-computing focus area.'
|
||||
owner: 'ildiko@openinfra.dev'
|
||||
- name: floss-mooc
|
||||
description: 'Discussions & Coordination around the FLOSS MOOC being collaboratively developed here: https://gitlab.com/mooc-floss/mooc-floss'
|
||||
owner: 'knelson@openinfra.dev'
|
||||
- name: nbmp-discuss
|
||||
description: 'Collaborating on Network Based Media Processing related platform and infrastructure systems usage and development.'
|
||||
owner: 'ildiko@openstack.org'
|
||||
- name: openinfralabs
|
||||
description: 'Discussion of the OpenInfra Labs academic and research resource sharing effort'
|
||||
owner: 'mnaser@vexxhost.com'
|
||||
- name: rust-vmm
|
||||
description: 'Collaborating on Rust-based virtual machine monitors.'
|
||||
owner: 'claire@openstack.org'
|
||||
- name: rustyk8s
|
||||
description: 'Collaborating on Rust-based Kubernetes API.'
|
||||
owner: 'allison@lohutok.net'
|
||||
- name: service-announce
|
||||
description: 'Announcement list for OpenDev services.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
- name: service-discuss
|
||||
description: 'Discussion list for OpenDev services.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
- name: service-incident
|
||||
description: 'Private list for OpenDev incident coordination.'
|
||||
owner: 'cboylan@sapwetik.org'
|
||||
private: true
|
||||
- listdomain: lists.airshipit.org
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: airship-announce
|
||||
description: 'Announcements of Airship releases and other important information.'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- name: airship-discuss
|
||||
description: 'Discussion of Airship usage and development.'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- name: airship-embargo-notice
|
||||
description: 'Embargoed security vulnerability announcements for Airship consumers.'
|
||||
owner: 'andrew.walters@att.com'
|
||||
private: true
|
||||
- name: airship-job-failures
|
||||
description: 'Notification messages for failures from CICD jobs.'
|
||||
owner: 'roman.gorshunov@att.com'
|
||||
- name: airship-security
|
||||
description: 'Public Airship security advisories.'
|
||||
owner: 'andrew.walters@att.com'
|
||||
- listdomain: lists.katacontainers.io
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: embargo-notice
|
||||
description: 'Announcements of embargoed notices for the Kata Containers project'
|
||||
owner: 'jonathan@openstack.org'
|
||||
private: true
|
||||
- name: kata-dev
|
||||
description: 'Kata Containers Development Mailing List (not for usage questions)'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- name: kata-hypervisor
|
||||
description: 'Discussion of security and virtualization targeted at container use cases'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- listdomain: lists.openinfra.dev
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: community
|
||||
description: 'The OpenInfra Community team is the main contact point for anybody running a local OpenInfra Group.'
|
||||
owner: 'allison@openinfra.dev'
|
||||
- name: foundation
|
||||
description: 'General discussion list for activities of the OpenInfra Foundation'
|
||||
owner: 'jonathan@openinfra.dev'
|
||||
- name: foundation-board
|
||||
description: 'OpenInfra Foundation Board of Directors'
|
||||
owner: 'jonathan@openinfra.dev'
|
||||
- name: foundation-board-confidential
|
||||
description: 'OpenInfra Foundation Board of Directors'
|
||||
owner: 'jonathan@openinfra.dev'
|
||||
private: true
|
||||
- name: goldmembers
|
||||
description: 'The discussion list for Gold Members of the OpenInfra Foundation'
|
||||
owner: 'jonathan@openinfra.dev'
|
||||
private: true
|
||||
- name: marketing
|
||||
description: 'The OpenInfra Marketing list is the meant to facilitate discussion and best practice sharing among marketers and event organizers in the OpenInfra community.'
|
||||
owner: 'allison@openinfra.dev'
|
||||
- name: staff
|
||||
description: 'Private list for OpenInfra Foundation staff members'
|
||||
owner: 'mark@openinfra.dev'
|
||||
private: true
|
||||
- name: summit-track-chairs
|
||||
description: 'OpenInfra Summit track chair communications'
|
||||
owner: 'erin@openinfra.dev'
|
||||
private: true
|
||||
- name: summitsponsors
|
||||
description: 'Coordination among OpenInfra Summit event sponsors'
|
||||
owner: 'erin@openinfra.dev'
|
||||
private: true
|
||||
- listdomain: lists.openstack.org
|
||||
install_languages: ['de', 'fr', 'it', 'ko', 'ru', 'vi', 'zh_TW']
|
||||
lists:
|
||||
- name: embargo-notice
|
||||
description: 'Announcements to stakeholders for embargoed security vulnerabilities.'
|
||||
owner: 'fungi@yuggoth.org'
|
||||
private: true
|
||||
- name: legal-discuss
|
||||
description: 'Discussions on legal matters related to the project'
|
||||
owner: 'thierry@openinfra.dev'
|
||||
- name: openstack-announce
|
||||
description: 'Key announcements about OpenStack & Security advisories'
|
||||
owner: 'fungi@yuggoth.org'
|
||||
- name: openstack-discuss
|
||||
description: 'Discussion of OpenStack usage and development.'
|
||||
owner: 'fungi@yuggoth.org'
|
||||
- name: openstack-es
|
||||
description: 'Lista de correo acerca de OpenStack en español'
|
||||
owner: 'flavio@redhat.com'
|
||||
- name: openstack-fr
|
||||
description: 'List of the OpenStack french user group'
|
||||
owner: 'erwan@erwan.com'
|
||||
- name: openstack-hpc
|
||||
description: 'High-Performance Computing OpenStack List'
|
||||
owner: 'brian.schott@nimbisservices.com'
|
||||
- name: openstack-i18n
|
||||
description: 'List of the OpenStack Internationalization team.'
|
||||
owner: 'guoyingc@cn.ibm.com'
|
||||
- name: openstack-it
|
||||
description: 'Discussioni su OpenStack in italiano'
|
||||
owner: 'stefano@openstack.org'
|
||||
- name: openstack-ko
|
||||
description: 'OpenStack Korea Community Discussions in Korean (오픈스택 한국 커뮤니티 메일링리스트)'
|
||||
owner: 'ianyrchoi@gmail.com'
|
||||
- name: openstack-mentoring
|
||||
description: 'List to coordinate interactions between mentors and mentees of the OpenStack mentoring program. Also for questions about the mentoring program (i.e. how to get involved, how it works, etc.'
|
||||
owner: 'amy@demarco.com'
|
||||
- name: openstack-stable-maint
|
||||
description: 'A mailing list for the OpenStack Stable Branch test reports.'
|
||||
owner: 'tony@bakeyournoodle.com'
|
||||
- name: openstack-zh
|
||||
description: 'OpenStack社区中文讨论群组'
|
||||
owner: 'yeluaiesec@gmail.com'
|
||||
- name: release-announce
|
||||
description: 'Announcement of official OpenStack releases.'
|
||||
owner: 'thierry@openstack.org'
|
||||
- name: release-job-failures
|
||||
description: 'Notification messages for failures from release-related build jobs.'
|
||||
owner: 'doug@doughellmann.com'
|
||||
- listdomain: lists.starlingx.io
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: starlingx-announce
|
||||
description: 'Announcements of StarlingX releases and other important information.'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- name: starlingx-discuss
|
||||
description: 'Discussion of StarlingX usage and development.'
|
||||
owner: 'jonathan@openstack.org'
|
||||
- listdomain: lists.zuul-ci.org
|
||||
install_languages: ['en']
|
||||
lists:
|
||||
- name: zuul-announce
|
||||
description: 'Announcements of Zuul releases and other important information.'
|
||||
owner: 'corvus@inaugust.com'
|
||||
- name: zuul-discuss
|
||||
description: 'Discussion of Zuul usage and development.'
|
||||
owner: 'corvus@inaugust.com'
|
||||
- name: zuul-jobs-failures
|
||||
description: 'Gets notifications about zuul-jobs periodic job failures.'
|
||||
owner: 'ssbarnea@redhat.com'
|
16
playbooks/zuul/lists3-alias-logs.yaml
Normal file
16
playbooks/zuul/lists3-alias-logs.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
# We need to do this in a run playbook so that we copy logs even
|
||||
# when the run playbooks fail. Failure in the run playbooks prevents the
|
||||
# test playbook from running.
|
||||
- hosts: "mailman3"
|
||||
tasks:
|
||||
- name: Alias mailman-web logs
|
||||
file:
|
||||
state: link
|
||||
src: /var/lib/mailman/web-data/logs
|
||||
path: /var/lib/mailman/mailman-web-logs
|
||||
|
||||
- name: Alias mailman-core logs
|
||||
file:
|
||||
state: link
|
||||
src: /var/lib/mailman/core/var/logs
|
||||
path: /var/lib/mailman/mailman-core-logs
|
@ -151,6 +151,14 @@
|
||||
- host_vars/paste99.opendev.org.yaml
|
||||
- host_vars/refstack01.openstack.org.yaml
|
||||
- host_vars/review99.opendev.org.yaml
|
||||
- name: Write lists99 host_vars.
|
||||
# This file is special because it has raw tags in it that we need to
|
||||
# carry through. I can't figure out a better way to do that then copying
|
||||
# it directly rather than treating it as a template.
|
||||
copy:
|
||||
src: "files/host_vars/lists99.opendev.org.yaml"
|
||||
dest: "/etc/ansible/hosts/host_vars/lists99.opendev.org.yaml"
|
||||
|
||||
- name: Display group membership
|
||||
command: ansible localhost -m debug -a 'var=groups'
|
||||
- name: Run base.yaml
|
||||
|
19
playbooks/zuul/test-lists3.yaml
Normal file
19
playbooks/zuul/test-lists3.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
- hosts: "mailman3"
|
||||
tasks:
|
||||
- name: Force hyperkitty to populate info about the new lists we created
|
||||
command: docker exec mailman-web ./manage.py runjobs hourly
|
||||
|
||||
- name: Update /etc/hosts in order to test mm3 vhosts
|
||||
lineinfile:
|
||||
state: present
|
||||
backrefs: yes
|
||||
path: /etc/hosts
|
||||
regexp: '^127\.0\.0\.1\s+(.*)$'
|
||||
line: '127.0.0.1 \1 {{ mm_site.listdomain }}'
|
||||
loop: "{{ mailman_sites }}"
|
||||
loop_control:
|
||||
loop_var: mm_site
|
||||
|
||||
- name: Run selenium container
|
||||
include_role:
|
||||
name: run-selenium
|
61
testinfra/test_lists_opendev_org.py
Normal file
61
testinfra/test_lists_opendev_org.py
Normal file
@ -0,0 +1,61 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from util import take_screenshots
|
||||
|
||||
testinfra_hosts = ['lists99.opendev.org']
|
||||
|
||||
def test_mariadb_listening(host):
|
||||
mariadb_port = host.socket("tcp://127.0.0.1:3306")
|
||||
assert mariadb_port.is_listening
|
||||
|
||||
def test_mailman3_web_listening(host):
|
||||
mailman_web = host.socket("tcp://0.0.0.0:8000")
|
||||
assert mailman_web.is_listening
|
||||
mailman_uwsgi = host.socket("tcp://0.0.0.0:8080")
|
||||
assert mailman_uwsgi.is_listening
|
||||
|
||||
def test_mailman3_core_listening(host):
|
||||
mailman_rest = host.socket("tcp://127.0.0.1:8001")
|
||||
assert mailman_rest.is_listening
|
||||
mailman_lmtp = host.socket("tcp://127.0.0.1:8024")
|
||||
assert mailman_lmtp.is_listening
|
||||
|
||||
def test_apache2_listening(host):
|
||||
apache2_http = host.socket("tcp://0.0.0.0:80")
|
||||
assert apache2_http.is_listening
|
||||
apache2_https = host.socket("tcp://0.0.0.0:443")
|
||||
assert apache2_https.is_listening
|
||||
|
||||
def test_mailman3_screenshots(host):
|
||||
shots = (
|
||||
("https://lists.opendev.org:443", None, "mm3-opendev-main.png"),
|
||||
("https://lists.opendev.org:443/hyperkitty/",
|
||||
None, "mm3-opendev-archives.png"),
|
||||
("https://lists.opendev.org:443"
|
||||
"/hyperkitty/list/service-discuss@lists.opendev.org/",
|
||||
None, "mm3-opendev-list.png"),
|
||||
("https://lists.opendev.org:443"
|
||||
"/accounts/login/?next=/postorius/lists/",
|
||||
None, "mm3-opendev-login.png"),
|
||||
("https://lists.openstack.org:443", None, "mm3-openstack-main.png"),
|
||||
("https://lists.openstack.org:443/hyperkitty/",
|
||||
None, "mm3-openstack-archives.png"),
|
||||
("https://lists.openstack.org:443"
|
||||
"/hyperkitty/list/openstack-discuss@lists.openstack.org/",
|
||||
None, "mm3-openstack-list.png"),
|
||||
("https://lists.openstack.org:443"
|
||||
"/accounts/login/?next=/postorius/lists/",
|
||||
None, "mm3-openstack-login.png"),
|
||||
)
|
||||
|
||||
take_screenshots(host, shots)
|
28
tools/mm3-migrate.sh
Normal file
28
tools/mm3-migrate.sh
Normal file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
s=$1
|
||||
test -z "$s" && echo 'Specify the list FQDN to migrate!' && exit 1
|
||||
echo "*** starting at $(date -Is) ***"
|
||||
set -x
|
||||
for m in $(
|
||||
ls -d /var/lib/mailman/import/$s/lists/* \
|
||||
| grep -v /mailman$ \
|
||||
| cut -d/ -f8
|
||||
); do
|
||||
time sudo docker-compose -f /etc/mailman-compose/docker-compose.yaml \
|
||||
exec -T -u mailman mailman-core mailman import21 $m@$s \
|
||||
/opt/import/$s/lists/$m/config.pck
|
||||
time sudo docker-compose -f /etc/mailman-compose/docker-compose.yaml \
|
||||
exec -T -u mailman mailman-web python3 manage.py hyperkitty_import -l \
|
||||
$m@$s /opt/import/$s/archives/private/$m.mbox/$m.mbox
|
||||
time sudo docker-compose -f /etc/mailman-compose/docker-compose.yaml \
|
||||
exec -T -u mailman mailman-web python3 manage.py \
|
||||
update_index_one_list $m@$s
|
||||
done
|
||||
sudo mv /var/lib/mailman/import/$s/archives \
|
||||
/var/lib/mailman/web-data/mm2archives/$s
|
||||
for a in /var/lib/mailman/web-data/mm2archives/$s/public/*; do
|
||||
sudo ln -fs ../private/`basename $a` $a
|
||||
done
|
||||
set +x
|
||||
echo "*** completed at $(date -Is) ***"
|
@ -563,9 +563,23 @@
|
||||
- inventory/service/host_vars/lists.katacontainers.io.yaml
|
||||
- playbooks/roles/iptables/
|
||||
- playbooks/roles/base/exim
|
||||
- playbooks/roles/mailman
|
||||
- playbooks/roles/mailman/
|
||||
- playbooks/service-lists.yaml
|
||||
|
||||
- job:
|
||||
name: infra-prod-service-lists3
|
||||
parent: infra-prod-service-base
|
||||
description: Run service-lists3.yaml playbook.
|
||||
vars:
|
||||
playbook_name: service-lists3.yaml
|
||||
files:
|
||||
- inventory/base
|
||||
- inventory/service/host_vars/lists01.opendev.org.yaml
|
||||
- playbooks/roles/iptables/
|
||||
- playbooks/roles/base/exim
|
||||
- playbooks/roles/mailman3/
|
||||
- playbooks/service-lists3.yaml
|
||||
|
||||
# Run AFS changes separately so we can make sure to only do one at a time
|
||||
# (turns out quorum is nice to have)
|
||||
- job:
|
||||
|
@ -30,6 +30,7 @@
|
||||
soft: true
|
||||
- system-config-run-kerberos
|
||||
- system-config-run-lists
|
||||
- system-config-run-lists3
|
||||
- system-config-run-nodepool:
|
||||
dependencies:
|
||||
- name: opendev-buildset-registry
|
||||
@ -180,6 +181,7 @@
|
||||
soft: true
|
||||
- system-config-run-kerberos
|
||||
- system-config-run-lists
|
||||
- system-config-run-lists3
|
||||
- system-config-run-nodepool:
|
||||
dependencies:
|
||||
- name: opendev-buildset-registry
|
||||
@ -461,6 +463,12 @@
|
||||
soft: true
|
||||
- name: infra-prod-letsencrypt
|
||||
soft: true
|
||||
- infra-prod-service-lists3: &infra-prod-service-lists3
|
||||
dependencies:
|
||||
- name: infra-prod-service-borg-backup
|
||||
soft: true
|
||||
- name: infra-prod-letsencrypt
|
||||
soft: true
|
||||
- infra-prod-service-mirror: &infra-prod-service-mirror
|
||||
dependencies:
|
||||
- name: infra-prod-letsencrypt
|
||||
@ -599,6 +607,7 @@
|
||||
- infra-prod-service-keycloak: *infra-prod-service-keycloak
|
||||
- infra-prod-service-meetpad: *infra-prod-service-meetpad
|
||||
- infra-prod-service-lists: *infra-prod-service-lists
|
||||
- infra-prod-service-lists3: *infra-prod-service-lists3
|
||||
- infra-prod-service-mirror: *infra-prod-service-mirror
|
||||
- infra-prod-service-nodepool: *infra-prod-service-nodepool
|
||||
- infra-prod-service-static: *infra-prod-service-static
|
||||
|
@ -258,7 +258,7 @@
|
||||
- inventory/service/host_vars/lists.katacontainers.io.yaml
|
||||
- inventory/service/group_vars/mailman.yaml
|
||||
- playbooks/roles/base/exim
|
||||
- playbooks/roles/mailman
|
||||
- playbooks/roles/mailman/
|
||||
- playbooks/service-lists.yaml
|
||||
- playbooks/test-lists.yaml
|
||||
- playbooks/zuul/templates/host_vars/lists.openstack.org.yaml.j2
|
||||
@ -286,6 +286,49 @@
|
||||
'/var/log/apache2': logs
|
||||
'/var/log/mailman': logs
|
||||
|
||||
- job:
|
||||
name: system-config-run-lists3
|
||||
# We don't use the system-config-run-containers base job because we
|
||||
# are consuming upstream containers only.
|
||||
parent: system-config-run
|
||||
description: |
|
||||
Run the playbook for a mailman3 list server.
|
||||
timeout: 3600
|
||||
nodeset:
|
||||
nodes:
|
||||
- <<: *bridge_node_x86
|
||||
- name: lists99.opendev.org
|
||||
label: ubuntu-jammy
|
||||
groups:
|
||||
- <<: *bastion_group
|
||||
required-projects:
|
||||
- opendev/system-config
|
||||
files:
|
||||
- playbooks/bootstrap-bridge.yaml
|
||||
- inventory/service/host_vars/lists01.opendev.org.yaml
|
||||
- inventory/service/group_vars/mailman3.yaml
|
||||
- playbooks/roles/base/exim
|
||||
- playbooks/roles/mailman3
|
||||
- playbooks/service-lists3.yaml
|
||||
- playbooks/test-lists3.yaml
|
||||
- playbooks/zuul/files/host_vars/lists99.opendev.org.yaml
|
||||
- testinfra/test_lists_opendev_org.py
|
||||
vars:
|
||||
run_playbooks:
|
||||
- playbooks/letsencrypt.yaml
|
||||
- playbooks/service-lists3.yaml
|
||||
# Run this twice to check idempotency
|
||||
- playbooks/service-lists3.yaml
|
||||
- playbooks/zuul/lists3-alias-logs.yaml
|
||||
run_test_playbook: playbooks/zuul/test-lists3.yaml
|
||||
host-vars:
|
||||
lists99.opendev.org:
|
||||
host_copy_output:
|
||||
'/var/log/acme.sh': logs
|
||||
'/var/log/apache2': logs
|
||||
'/var/lib/mailman/mailman-web-logs': logs
|
||||
'/var/lib/mailman/mailman-core-logs': logs
|
||||
|
||||
- job:
|
||||
name: system-config-run-nodepool
|
||||
parent: system-config-run
|
||||
|
Loading…
Reference in New Issue
Block a user