|
|
|
|
@@ -1,7 +1,6 @@
|
|
|
|
|
"""
|
|
|
|
|
Chat Mail pyinfra deploy.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import importlib.resources
|
|
|
|
|
import subprocess
|
|
|
|
|
@@ -10,15 +9,13 @@ import io
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
from pyinfra import host
|
|
|
|
|
from pyinfra.operations import apt, files, server, systemd, pip, util
|
|
|
|
|
from pyinfra.operations import apt, files, server, systemd, pip
|
|
|
|
|
from pyinfra.facts.files import File
|
|
|
|
|
from pyinfra.facts.systemd import SystemdEnabled
|
|
|
|
|
from .acmetool import deploy_acmetool
|
|
|
|
|
|
|
|
|
|
from chatmaild.config import read_config, Config
|
|
|
|
|
|
|
|
|
|
from typing import Callable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _build_chatmaild(dist_dir) -> None:
|
|
|
|
|
dist_dir = Path(dist_dir).resolve()
|
|
|
|
|
@@ -129,8 +126,10 @@ def _install_remote_venv_with_chatmaild(config) -> None:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[], bool]:
|
|
|
|
|
def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> bool:
|
|
|
|
|
"""Configures OpenDKIM"""
|
|
|
|
|
need_restart = False
|
|
|
|
|
|
|
|
|
|
server.group(name="Create opendkim group", group="opendkim", system=True)
|
|
|
|
|
server.user(
|
|
|
|
|
name="Create opendkim user",
|
|
|
|
|
@@ -153,6 +152,7 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain, "opendkim_selector": dkim_selector},
|
|
|
|
|
)
|
|
|
|
|
need_restart |= main_config.changed
|
|
|
|
|
|
|
|
|
|
screen_script = files.put(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("opendkim/screen.lua"),
|
|
|
|
|
@@ -161,6 +161,7 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= screen_script.changed
|
|
|
|
|
|
|
|
|
|
final_script = files.put(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("opendkim/final.lua"),
|
|
|
|
|
@@ -169,6 +170,7 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= final_script.changed
|
|
|
|
|
|
|
|
|
|
files.directory(
|
|
|
|
|
name="Add opendkim directory to /etc",
|
|
|
|
|
@@ -187,6 +189,7 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain, "opendkim_selector": dkim_selector},
|
|
|
|
|
)
|
|
|
|
|
need_restart |= keytable.changed
|
|
|
|
|
|
|
|
|
|
signing_table = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("opendkim/SigningTable"),
|
|
|
|
|
@@ -196,7 +199,7 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain, "opendkim_selector": dkim_selector},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
need_restart |= signing_table.changed
|
|
|
|
|
files.directory(
|
|
|
|
|
name="Add opendkim socket directory to /var/spool/postfix",
|
|
|
|
|
path="/var/spool/postfix/opendkim",
|
|
|
|
|
@@ -221,12 +224,10 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> Callable[[]
|
|
|
|
|
_sudo_user="opendkim",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return util.any_changed(
|
|
|
|
|
main_config, screen_script, final_script, keytable, signing_table
|
|
|
|
|
)
|
|
|
|
|
return need_restart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _install_mta_sts_daemon() -> Callable[[], bool]:
|
|
|
|
|
def _install_mta_sts_daemon() -> bool:
|
|
|
|
|
need_restart = False
|
|
|
|
|
|
|
|
|
|
config = files.put(
|
|
|
|
|
@@ -239,6 +240,7 @@ def _install_mta_sts_daemon() -> Callable[[], bool]:
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= config.changed
|
|
|
|
|
|
|
|
|
|
server.shell(
|
|
|
|
|
name="install postfix-mta-sts-resolver with pip",
|
|
|
|
|
@@ -258,12 +260,15 @@ def _install_mta_sts_daemon() -> Callable[[], bool]:
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= systemd_unit.changed
|
|
|
|
|
|
|
|
|
|
return util.any_changed(config, systemd_unit)
|
|
|
|
|
return need_restart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _configure_postfix(config: Config, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
def _configure_postfix(config: Config, debug: bool = False) -> bool:
|
|
|
|
|
"""Configures Postfix SMTP server."""
|
|
|
|
|
need_restart = False
|
|
|
|
|
|
|
|
|
|
main_config = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("postfix/main.cf.j2"),
|
|
|
|
|
dest="/etc/postfix/main.cf",
|
|
|
|
|
@@ -272,6 +277,7 @@ def _configure_postfix(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
mode="644",
|
|
|
|
|
config=config,
|
|
|
|
|
)
|
|
|
|
|
need_restart |= main_config.changed
|
|
|
|
|
|
|
|
|
|
master_config = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("postfix/master.cf.j2"),
|
|
|
|
|
@@ -282,6 +288,7 @@ def _configure_postfix(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
debug=debug,
|
|
|
|
|
config=config,
|
|
|
|
|
)
|
|
|
|
|
need_restart |= master_config.changed
|
|
|
|
|
|
|
|
|
|
header_cleanup = files.put(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath(
|
|
|
|
|
@@ -292,21 +299,27 @@ def _configure_postfix(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= header_cleanup.changed
|
|
|
|
|
|
|
|
|
|
# Login map that 1:1 maps email address to login.
|
|
|
|
|
login_map = files.put(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("postfix/login_map"),
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath(
|
|
|
|
|
"postfix/login_map"
|
|
|
|
|
),
|
|
|
|
|
dest="/etc/postfix/login_map",
|
|
|
|
|
user="root",
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= login_map.changed
|
|
|
|
|
|
|
|
|
|
return util.any_changed(main_config, master_config, header_cleanup, login_map)
|
|
|
|
|
return need_restart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _configure_dovecot(config: Config, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
def _configure_dovecot(config: Config, debug: bool = False) -> bool:
|
|
|
|
|
"""Configures Dovecot IMAP server."""
|
|
|
|
|
need_restart = False
|
|
|
|
|
|
|
|
|
|
main_config = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("dovecot/dovecot.conf.j2"),
|
|
|
|
|
dest="/etc/dovecot/dovecot.conf",
|
|
|
|
|
@@ -316,6 +329,7 @@ def _configure_dovecot(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
config=config,
|
|
|
|
|
debug=debug,
|
|
|
|
|
)
|
|
|
|
|
need_restart |= main_config.changed
|
|
|
|
|
auth_config = files.put(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("dovecot/auth.conf"),
|
|
|
|
|
dest="/etc/dovecot/auth.conf",
|
|
|
|
|
@@ -323,6 +337,7 @@ def _configure_dovecot(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
group="root",
|
|
|
|
|
mode="644",
|
|
|
|
|
)
|
|
|
|
|
need_restart |= auth_config.changed
|
|
|
|
|
|
|
|
|
|
files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("dovecot/expunge.cron.j2"),
|
|
|
|
|
@@ -344,11 +359,13 @@ def _configure_dovecot(config: Config, debug: bool = False) -> Callable[[], bool
|
|
|
|
|
persist=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return util.any_changed(main_config, auth_config)
|
|
|
|
|
return need_restart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _configure_nginx(domain: str, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
def _configure_nginx(domain: str, debug: bool = False) -> bool:
|
|
|
|
|
"""Configures nginx HTTP server."""
|
|
|
|
|
need_restart = False
|
|
|
|
|
|
|
|
|
|
main_config = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("nginx/nginx.conf.j2"),
|
|
|
|
|
dest="/etc/nginx/nginx.conf",
|
|
|
|
|
@@ -357,6 +374,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain},
|
|
|
|
|
)
|
|
|
|
|
need_restart |= main_config.changed
|
|
|
|
|
|
|
|
|
|
autoconfig = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("nginx/autoconfig.xml.j2"),
|
|
|
|
|
@@ -366,6 +384,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain},
|
|
|
|
|
)
|
|
|
|
|
need_restart |= autoconfig.changed
|
|
|
|
|
|
|
|
|
|
mta_sts_config = files.template(
|
|
|
|
|
src=importlib.resources.files(__package__).joinpath("nginx/mta-sts.txt.j2"),
|
|
|
|
|
@@ -375,6 +394,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
mode="644",
|
|
|
|
|
config={"domain_name": domain},
|
|
|
|
|
)
|
|
|
|
|
need_restart |= mta_sts_config.changed
|
|
|
|
|
|
|
|
|
|
# install CGI newemail script
|
|
|
|
|
#
|
|
|
|
|
@@ -395,7 +415,7 @@ def _configure_nginx(domain: str, debug: bool = False) -> Callable[[], bool]:
|
|
|
|
|
mode="755",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return util.any_changed(main_config, autoconfig, mta_sts_config)
|
|
|
|
|
return need_restart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _remove_rspamd() -> None:
|
|
|
|
|
@@ -499,12 +519,7 @@ def deploy_chatmail(config_path: Path) -> None:
|
|
|
|
|
service="opendkim.service",
|
|
|
|
|
running=True,
|
|
|
|
|
enabled=True,
|
|
|
|
|
)
|
|
|
|
|
systemd.service(
|
|
|
|
|
name="Restart OpenDKIM",
|
|
|
|
|
service="opendkim.service",
|
|
|
|
|
restarted=True,
|
|
|
|
|
_if=opendkim_need_restart,
|
|
|
|
|
restarted=opendkim_need_restart,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
systemd.service(
|
|
|
|
|
@@ -513,12 +528,7 @@ def deploy_chatmail(config_path: Path) -> None:
|
|
|
|
|
daemon_reload=True,
|
|
|
|
|
running=True,
|
|
|
|
|
enabled=True,
|
|
|
|
|
)
|
|
|
|
|
systemd.service(
|
|
|
|
|
name="Restart MTA-STS daemon",
|
|
|
|
|
service="mta-sts-daemon.service",
|
|
|
|
|
restarted=True,
|
|
|
|
|
_if=mta_sts_need_restart,
|
|
|
|
|
restarted=mta_sts_need_restart,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
systemd.service(
|
|
|
|
|
@@ -526,12 +536,7 @@ def deploy_chatmail(config_path: Path) -> None:
|
|
|
|
|
service="postfix.service",
|
|
|
|
|
running=True,
|
|
|
|
|
enabled=True,
|
|
|
|
|
)
|
|
|
|
|
systemd.service(
|
|
|
|
|
name="Restart Postfix",
|
|
|
|
|
service="postfix.service",
|
|
|
|
|
restarted=True,
|
|
|
|
|
_if=postfix_need_restart,
|
|
|
|
|
restarted=postfix_need_restart,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
systemd.service(
|
|
|
|
|
@@ -539,12 +544,7 @@ def deploy_chatmail(config_path: Path) -> None:
|
|
|
|
|
service="dovecot.service",
|
|
|
|
|
running=True,
|
|
|
|
|
enabled=True,
|
|
|
|
|
)
|
|
|
|
|
systemd.service(
|
|
|
|
|
name="Restart Dovecot",
|
|
|
|
|
service="dovecot.service",
|
|
|
|
|
restarted=True,
|
|
|
|
|
_if=dovecot_need_restart,
|
|
|
|
|
restarted=dovecot_need_restart,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
systemd.service(
|
|
|
|
|
@@ -552,12 +552,7 @@ def deploy_chatmail(config_path: Path) -> None:
|
|
|
|
|
service="nginx.service",
|
|
|
|
|
running=True,
|
|
|
|
|
enabled=True,
|
|
|
|
|
)
|
|
|
|
|
systemd.service(
|
|
|
|
|
name="Restart nginx",
|
|
|
|
|
service="nginx.service",
|
|
|
|
|
restarted=True,
|
|
|
|
|
_if=nginx_need_restart,
|
|
|
|
|
restarted=nginx_need_restart,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# This file is used by auth proxy.
|
|
|
|
|
|