diff --git a/.gitea/workflows/molecule-tests.yml b/.gitea/workflows/molecule-tests.yml new file mode 100644 index 0000000..a5d28f8 --- /dev/null +++ b/.gitea/workflows/molecule-tests.yml @@ -0,0 +1,43 @@ +#SPDX-License-Identifier: GPL-3.0-only +--- +name: Molecule Tests + +on: + schedule: + - cron: '0 7 * * 1' # Every Monday at 07:00 UTC + workflow_dispatch: + pull_request: + branches: + - main + +jobs: + molecule-tests: + runs-on: fedora-latest + steps: + - name: Add ~/.local/bin to PATH + run: echo "$HOME/.local/bin" >> "$GITEA_PATH" + + - name: Checkout + uses: actions/checkout@v6 + with: + path: ansible_role_mail + + - name: Install Molecule + run: pip install ansible molecule molecule-plugins[podman] + + - name: Install Ansible collections + run: ansible-galaxy collection install containers.podman + + - name: Run Molecule tests + working-directory: ansible_role_mail + run: molecule test + + - name: Tag latest + if: github.ref == 'refs/heads/main' + working-directory: ansible_role_mail + run: | + git config user.name "giabot" + git config user.email "bot@mail.gianet.us" + git remote set-url origin "https://giabot:${{ secrets.GITEA_TOKEN }}@gianet.us/engineering/ansible_role_mail.git" + git tag -f latest + git push -f origin latest diff --git a/meta/main.yml b/meta/main.yml index 4d799e2..741366b 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,5 +1,6 @@ galaxy_info: role_name: "mailserver" + namespace: "gianet" author: "Luciano Giacchetta" description: "Complete Mail Server Role" company: "Giacchetta Networks LLC" diff --git a/molecule/default/Dockerfile b/molecule/default/Dockerfile new file mode 100644 index 0000000..dd844bc --- /dev/null +++ b/molecule/default/Dockerfile @@ -0,0 +1,14 @@ +ARG MOLECULE_DISTRO=docker.io/library/debian:stable +FROM ${MOLECULE_DISTRO} + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + python3 \ + systemd \ + systemd-sysv \ + dbus \ + ca-certificates && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +CMD ["/usr/sbin/init"] diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..fe35d4e --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,11 @@ +#SPDX-License-Identifier: GPL-3.0-only +--- +- name: Converge + hosts: all + vars: + postfix_mail_domain: "test.local" + dovecot_users: + - name: "testuser" + pass: "testpass" + roles: + - role: ansible_role_mail diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..e1971b9 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,72 @@ +#SPDX-License-Identifier: GPL-3.0-only +--- +dependency: + name: galaxy + options: + requirements-file: molecule/default/requirements.yml + +driver: + name: podman + +platforms: + - name: debian-stable + image: docker.io/library/debian:stable + pre_build_image: false + dockerfile: Dockerfile + buildargs: + MOLECULE_DISTRO: docker.io/library/debian:stable + privileged: true + systemd: always + command: /usr/sbin/init + + - name: debian-oldstable + image: docker.io/library/debian:oldstable + pre_build_image: false + dockerfile: Dockerfile + buildargs: + MOLECULE_DISTRO: docker.io/library/debian:oldstable + privileged: true + systemd: always + command: /usr/sbin/init + + - name: ubuntu-latest + image: docker.io/library/ubuntu:latest + pre_build_image: false + dockerfile: Dockerfile + buildargs: + MOLECULE_DISTRO: docker.io/library/ubuntu:latest + privileged: true + systemd: always + command: /usr/sbin/init + + - name: ubuntu-jammy + image: docker.io/library/ubuntu:jammy + pre_build_image: false + dockerfile: Dockerfile + buildargs: + MOLECULE_DISTRO: docker.io/library/ubuntu:jammy + privileged: true + systemd: always + command: /usr/sbin/init + +provisioner: + name: ansible + env: + ANSIBLE_ROLES_PATH: "${MOLECULE_PROJECT_DIRECTORY}/.." + playbooks: + converge: converge.yml + verify: verify.yml + +scenario: + test_sequence: + - dependency + - destroy + - syntax + - create + - converge + - idempotence + - verify + - destroy + +verifier: + name: ansible diff --git a/molecule/default/requirements.yml b/molecule/default/requirements.yml new file mode 100644 index 0000000..ad7a05e --- /dev/null +++ b/molecule/default/requirements.yml @@ -0,0 +1,4 @@ +#SPDX-License-Identifier: GPL-3.0-only +--- +collections: + - name: containers.podman diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml new file mode 100644 index 0000000..7e1659b --- /dev/null +++ b/molecule/default/verify.yml @@ -0,0 +1,37 @@ +#SPDX-License-Identifier: GPL-3.0-only +--- +- name: Verify + hosts: all + tasks: + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Assert postfix service is present + ansible.builtin.assert: + that: + - "'postfix.service' in ansible_facts.services" + + - name: Assert dovecot service is present + ansible.builtin.assert: + that: + - "'dovecot.service' in ansible_facts.services" + + - name: Check postfix main.cf exists + ansible.builtin.stat: + path: /etc/postfix/main.cf + register: postfix_main_cf + + - name: Assert postfix main.cf exists + ansible.builtin.assert: + that: + - postfix_main_cf.stat.exists + + - name: Check dovecot.conf exists + ansible.builtin.stat: + path: /etc/dovecot/dovecot.conf + register: dovecot_conf + + - name: Assert dovecot.conf exists + ansible.builtin.assert: + that: + - dovecot_conf.stat.exists diff --git a/tasks/main.yml b/tasks/main.yml index 441b1ba..f26db23 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -62,13 +62,16 @@ owner: root group: root mode: '0644' + register: virtual_mailbox_maps_template notify: Restart Postfix tags: - postfix_config - dovecot_config - name: "POSTFIX | Create hash map for virtual mailbox maps" - when: dovecot_enabled | default(false) and dovecot_postfix_lmtp_enable | default(false) + when: + - dovecot_enabled | default(false) and dovecot_postfix_lmtp_enable | default(false) + - virtual_mailbox_maps_template.changed ansible.builtin.command: cmd: postmap hash:/etc/postfix/virtual_mailbox_maps changed_when: true @@ -168,6 +171,22 @@ tags: - dovecot_config +- name: "DOVECOT | Detect Dovecot version" + when: dovecot_enabled | default(false) + ansible.builtin.shell: + cmd: "dovecot --version | awk '{print $1}' | cut -d'(' -f1" + register: dovecot_version_raw + changed_when: false + tags: + - dovecot_config + +- name: "DOVECOT | Set Dovecot major version fact" + when: dovecot_enabled | default(false) + ansible.builtin.set_fact: + dovecot_major_version: "{{ dovecot_version_raw.stdout.split('.')[0] | int }}.{{ dovecot_version_raw.stdout.split('.')[1] | int }}" + tags: + - dovecot_config + - name: "DOVECOT | Configure dovecot.conf" when: dovecot_enabled | default(false) ansible.builtin.template: diff --git a/templates/10-auth.conf.j2 b/templates/10-auth.conf.j2 index b7e36ac..2da18b6 100644 --- a/templates/10-auth.conf.j2 +++ b/templates/10-auth.conf.j2 @@ -1,7 +1,11 @@ # Dovecot authentication configuration # Ansible managed: {{ ansible_managed }} +{% if dovecot_major_version is defined and dovecot_major_version is version('2.4', '>=') %} +auth_allow_cleartext = {{ 'no' if dovecot_ssl == 'required' else 'yes' }} +{% else %} disable_plaintext_auth = {{ 'yes' if dovecot_ssl == 'required' else 'no' }} +{% endif %} auth_mechanisms = {{ dovecot_auth_mechanisms }} !include auth-dovecot-users.conf.ext diff --git a/templates/10-mail.conf.j2 b/templates/10-mail.conf.j2 index edddf85..526d76f 100644 --- a/templates/10-mail.conf.j2 +++ b/templates/10-mail.conf.j2 @@ -1,7 +1,13 @@ # Dovecot mail location configuration # Ansible managed: {{ ansible_managed }} - +{% if dovecot_major_version is defined and dovecot_major_version is version('2.4', '>=') %} +{% set _driver = dovecot_mail_location.split(':')[0] %} +{% set _path = dovecot_mail_location.split(':')[1] %} +mail_driver = {{ _driver }} +mail_path = {{ _path }} +{% else %} mail_location = {{ dovecot_mail_location }} +{% endif %} namespace inbox { inbox = yes diff --git a/templates/10-ssl.conf.j2 b/templates/10-ssl.conf.j2 index 9141113..373d157 100644 --- a/templates/10-ssl.conf.j2 +++ b/templates/10-ssl.conf.j2 @@ -2,5 +2,10 @@ # Ansible managed: {{ ansible_managed }} ssl = {{ dovecot_ssl }} +{% if dovecot_major_version is defined and dovecot_major_version is version('2.4', '>=') %} +ssl_server_cert_file = {{ mail_ssl_cert }} +ssl_server_key_file = {{ mail_ssl_key }} +{% else %} ssl_cert = <{{ mail_ssl_cert }} ssl_key = <{{ mail_ssl_key }} +{% endif %} diff --git a/templates/auth-dovecot-users.conf.ext.j2 b/templates/auth-dovecot-users.conf.ext.j2 index cc72d53..528fd32 100644 --- a/templates/auth-dovecot-users.conf.ext.j2 +++ b/templates/auth-dovecot-users.conf.ext.j2 @@ -1,5 +1,21 @@ # Dovecot local users authentication # Ansible managed: {{ ansible_managed }} +{% if dovecot_major_version is defined and dovecot_major_version is version('2.4', '>=') %} + +passdb passwd-file { + default_password_scheme = SHA512-CRYPT + auth_username_format = %{user|username} + passwd_file_path = /etc/dovecot/users +} + +userdb static { + fields { + uid = vmail + gid = vmail + home = /var/vmail/%{user|username} + } +} +{% else %} passdb { driver = passwd-file @@ -10,3 +26,4 @@ userdb { driver = static args = uid=vmail gid=vmail home=/var/vmail/%n } +{% endif %} diff --git a/templates/dovecot.conf.j2 b/templates/dovecot.conf.j2 index 36604db..1afa899 100644 --- a/templates/dovecot.conf.j2 +++ b/templates/dovecot.conf.j2 @@ -1,5 +1,9 @@ # Dovecot configuration file # Ansible managed: {{ ansible_managed }} +{% if dovecot_major_version is defined and dovecot_major_version is version('2.4', '>=') %} +dovecot_config_version = 2.4.0 +dovecot_storage_version = 2.4.0 +{% endif %} protocols = {{ dovecot_protocols }} {% if dovecot_imap_capability | default('') | length > 0 %}