Clark Boylan c1c91886b4 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
2022-11-11 23:20:19 +00:00

279 lines
7.4 KiB
YAML

# 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