# 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: Copy our mailman-extra.cfg for mailman-core template: src: mailman-extra.cfg.j2 dest: /var/lib/mailman/core/mailman-extra.cfg # TODO: undo for https://github.com/maxking/docker-mailman/issues/550 owner: 100 group: 65533 mode: '0644' notify: mailman restart containers - 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' notify: mailman restart containers - name: Check for initial setup flag file stat: path: /var/lib/mailman/bootstrapped register: _mailman_bootstrapped # https://docs.mailman3.org/en/latest/faq.html#the-domain-name-displayed-in-hyperkitty-shows-example-com-or-something-else - name: Temporarily turn off magic domain guessing lineinfile: state: present backrefs: yes path: /var/lib/mailman/web/settings.py regexp: '^SITE_ID = 0$' line: 'SITE_ID = 1' when: not _mailman_bootstrapped.stat.exists - 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' notify: mailman restart containers - 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' notify: mailman restart containers - 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' notify: mailman restart containers - 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/ register: mailman_dcup - 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 sh -c 'alembic -c /usr/lib/python*/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: Complete new server bootstrapping when: not _mailman_bootstrapped.stat.exists block: - name: Run docker-compose down shell: cmd: docker-compose down chdir: /etc/mailman-compose/ - name: Turn magic domain guessing back on lineinfile: state: present backrefs: yes path: /var/lib/mailman/web/settings.py regexp: '^SITE_ID = 0$' line: 'SITE_ID = 1' - name: Create the bootstrapped flag file copy: content: "" dest: /var/lib/mailman/bootstrapped force: no owner: 100 group: 101 mode: '0644' - name: Run docker-compose up shell: cmd: docker-compose up -d chdir: /etc/mailman-compose/ - 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 - 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 database bash -c '/usr/bin/mysqldump --skip-extended-insert --databases mailmandb --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"' dest: /etc/borg-streams/mysql