refactor(cmdeploy): share deployed path constants

This commit is contained in:
ccclxxiii
2026-06-25 09:26:01 -05:00
parent 2681ca312e
commit d7a16d2be1
13 changed files with 285 additions and 150 deletions
+9 -7
View File
@@ -1,5 +1,7 @@
from pyinfra.operations import apt, server
from cmdeploy.constants import ACME_PATHS, CONFIG_FILES
from ..basedeploy import Deployer
@@ -14,30 +16,30 @@ class AcmetoolDeployer(Deployer):
packages=["acmetool"],
)
self.remove_file("/etc/cron.d/acmetool")
self.remove_file(CONFIG_FILES["cron_acmetool"])
self.put_executable("acmetool/acmetool.hook", "/etc/acme/hooks/nginx")
self.remove_file("/usr/lib/acme/hooks/nginx")
self.put_executable("acmetool/acmetool.hook", ACME_PATHS["hook_nginx"])
self.remove_file(ACME_PATHS["legacy_hook_nginx"])
def configure(self):
self.put_template(
"acmetool/response-file.yaml.j2",
"/var/lib/acme/conf/responses",
ACME_PATHS["responses"],
email=self.email,
)
self.put_template(
"acmetool/target.yaml.j2",
"/var/lib/acme/conf/target",
ACME_PATHS["target"],
)
server.shell(
name=f"Remove old acmetool desired files for {self.domains[0]}",
commands=[f"rm -f /var/lib/acme/desired/{self.domains[0]}-*"],
commands=[f"rm -f {ACME_PATHS['desired_dir']}/{self.domains[0]}-*"],
)
self.put_template(
"acmetool/desired.yaml.j2",
f"/var/lib/acme/desired/{self.domains[0]}",
f"{ACME_PATHS['desired_dir']}/{self.domains[0]}",
domains=self.domains,
)
+4 -3
View File
@@ -8,6 +8,8 @@ from pyinfra.facts.files import Sha256File
from pyinfra.facts.server import Command
from pyinfra.operations import files, server, systemd
from cmdeploy.constants import CHATMAILD_PATHS
def has_systemd():
"""Returns False during Docker image builds or any other non-systemd environment."""
@@ -52,9 +54,8 @@ def get_resource(arg, pkg=__package__):
def configure_remote_units(deployer, mail_domain, units) -> None:
remote_base_dir = "/usr/local/lib/chatmaild"
remote_venv_dir = f"{remote_base_dir}/venv"
remote_chatmail_inipath = f"{remote_base_dir}/chatmail.ini"
remote_venv_dir = CHATMAILD_PATHS["venv_dir"]
remote_chatmail_inipath = CHATMAILD_PATHS["config"]
# install systemd units
for fn in units:
+91
View File
@@ -0,0 +1,91 @@
CHATMAILD_PATHS = {
"base_dir": "/usr/local/lib/chatmaild",
"dist_dir": "/usr/local/lib/chatmaild/dist",
"venv_dir": "/usr/local/lib/chatmaild/venv",
"config": "/usr/local/lib/chatmaild/chatmail.ini",
}
BINARY_PATHS = {
"chatmail_turn": "/usr/local/bin/chatmail-turn",
"filtermail": "/usr/local/bin/filtermail",
"iroh_relay": "/usr/local/bin/iroh-relay",
"mtail": "/usr/local/bin/mtail",
}
CONFIG_DIRS = {
"dkimkeys": "/etc/dkimkeys",
"dovecot": "/etc/dovecot",
"mtail": "/etc/mtail",
"nginx": "/etc/nginx",
"opendkim": "/etc/opendkim",
"postfix": "/etc/postfix",
"unbound": "/etc/unbound",
}
CONFIG_FILES = {
"apt_install_recommends": "/etc/apt/apt.conf.d/00InstallRecommends",
"apt_obs_keyring": "/etc/apt/keyrings/obs-home-deltachat.gpg",
"apt_pin_dovecot": "/etc/apt/preferences.d/pin-dovecot",
"chatmail_nocreate": "/etc/chatmail-nocreate",
"chatmail_version": "/etc/chatmail-version",
"cron_acmetool": "/etc/cron.d/acmetool",
"cron_chatmail_metrics": "/etc/cron.d/chatmail-metrics",
"cron_expunge": "/etc/cron.d/expunge",
"dovecot_auth": "/etc/dovecot/auth.conf",
"dovecot_conf": "/etc/dovecot/dovecot.conf",
"dovecot_push_notification": "/etc/dovecot/push_notification.lua",
"iroh_relay": "/etc/iroh-relay.toml",
"journald": "/etc/systemd/journald.conf",
"mailname": "/etc/mailname",
"mtail_program": "/etc/mtail/delivered_mail.mtail",
"mtasts_daemon": "/etc/mta-sts-daemon.yml",
"nginx_conf": "/etc/nginx/nginx.conf",
"opendkim_conf": "/etc/opendkim.conf",
"policy_rc_d": "/usr/sbin/policy-rc.d",
"postfix_lmtp_header_cleanup": "/etc/postfix/lmtp_header_cleanup",
"postfix_login_map": "/etc/postfix/login_map",
"postfix_main": "/etc/postfix/main.cf",
"postfix_master": "/etc/postfix/master.cf",
"postfix_smtp_tls_policy_map": "/etc/postfix/smtp_tls_policy_map",
"postfix_smtp_tls_policy_map_db": "/etc/postfix/smtp_tls_policy_map.db",
"postfix_submission_header_cleanup": "/etc/postfix/submission_header_cleanup",
"systemd_dovecot_restart": "/etc/systemd/system/dovecot.service.d/10_restart.conf",
"systemd_mtasts_daemon": "/etc/systemd/system/mta-sts-daemon.service",
"systemd_opendkim_restart": "/etc/systemd/system/opendkim.service.d/10-prevent-memory-leak.conf",
"systemd_postfix_restart": "/etc/systemd/system/postfix@.service.d/10_restart.conf",
"unbound_chatmail": "/etc/unbound/unbound.conf.d/chatmail.conf",
}
WEB_PATHS = {
"html_dir": "/var/www/html",
"autoconfig": "/var/www/html/.well-known/autoconfig/mail/config-v1.1.xml",
"mta_sts": "/var/www/html/.well-known/mta-sts.txt",
"metrics": "/var/www/html/metrics",
"newemail_cgi": "/usr/lib/cgi-bin/newemail.py",
}
ACME_PATHS = {
"etc_dir": "/etc/acme",
"var_dir": "/var/lib/acme",
"hook_nginx": "/etc/acme/hooks/nginx",
"legacy_hook_nginx": "/usr/lib/acme/hooks/nginx",
"responses": "/var/lib/acme/conf/responses",
"target": "/var/lib/acme/conf/target",
"desired_dir": "/var/lib/acme/desired",
}
TLS_PATHS = {
"self_cert": "/etc/ssl/certs/mailserver.pem",
"self_key": "/etc/ssl/private/mailserver.key",
}
STATE_DIRS = {
"from_cmdeploy": "/root/from-cmdeploy",
"postfix_mta_sts_resolver": "/usr/local/lib/postfix-mta-sts-resolver",
"var_lib_dovecot": "/var/lib/dovecot",
"var_lib_nginx": "/var/lib/nginx",
"var_lib_postfix": "/var/lib/postfix",
"var_lib_unbound": "/var/lib/unbound",
"var_log_nginx": "/var/log/nginx",
"var_spool_postfix": "/var/spool/postfix",
}
+37 -26
View File
@@ -16,6 +16,14 @@ from pyinfra.facts.systemd import SystemdEnabled
from pyinfra.operations import apt, files, pip, server, systemd
from cmdeploy.cmdeploy import Out
from cmdeploy.constants import (
BINARY_PATHS,
CHATMAILD_PATHS,
CONFIG_DIRS,
CONFIG_FILES,
STATE_DIRS,
WEB_PATHS,
)
from .acmetool import AcmetoolDeployer
from .basedeploy import (
@@ -83,16 +91,15 @@ def remove_legacy_artifacts():
def _install_remote_venv_with_chatmaild(deployer) -> None:
remove_legacy_artifacts()
dist_file = _build_chatmaild(dist_dir=Path("chatmaild/dist"))
remote_base_dir = "/usr/local/lib/chatmaild"
remote_dist_file = f"{remote_base_dir}/dist/{dist_file.name}"
remote_venv_dir = f"{remote_base_dir}/venv"
remote_dist_file = f"{CHATMAILD_PATHS['dist_dir']}/{dist_file.name}"
remote_venv_dir = CHATMAILD_PATHS["venv_dir"]
apt.packages(
name="apt install python3-virtualenv",
packages=["python3-virtualenv"],
)
deployer.ensure_directory(f"{remote_base_dir}/dist")
deployer.ensure_directory(CHATMAILD_PATHS["dist_dir"])
deployer.put_file(
src=dist_file.open("rb"),
dest=remote_dist_file,
@@ -118,16 +125,15 @@ def _install_remote_venv_with_chatmaild(deployer) -> None:
def _configure_remote_venv_with_chatmaild(deployer, config) -> None:
remote_base_dir = "/usr/local/lib/chatmaild"
remote_chatmail_inipath = f"{remote_base_dir}/chatmail.ini"
remote_chatmail_inipath = CHATMAILD_PATHS["config"]
deployer.put_file(
src=config._getbytefile(),
dest=remote_chatmail_inipath,
)
deployer.remove_file("/etc/cron.d/chatmail-metrics")
deployer.remove_file("/var/www/html/metrics")
deployer.remove_file(CONFIG_FILES["cron_chatmail_metrics"])
deployer.remove_file(WEB_PATHS["metrics"])
class UnboundDeployer(Deployer):
@@ -169,15 +175,15 @@ class UnboundDeployer(Deployer):
server.shell(
name="Generate root keys for validating DNSSEC",
commands=[
"unbound-anchor -a /var/lib/unbound/root.key || true",
f"unbound-anchor -a {STATE_DIRS['var_lib_unbound']}/root.key || true",
],
)
self.ensure_directory(
path="/etc/unbound/unbound.conf.d",
path=f"{CONFIG_DIRS['unbound']}/unbound.conf.d",
)
self.put_template(
"unbound/unbound.conf.j2",
"/etc/unbound/unbound.conf.d/chatmail.conf",
CONFIG_FILES["unbound_chatmail"],
disable_ipv6=self.config.disable_ipv6,
)
@@ -201,9 +207,9 @@ class UnboundDeployer(Deployer):
class MtastsDeployer(Deployer):
def configure(self):
# Remove configuration.
self.remove_file("/etc/mta-sts-daemon.yml")
self.remove_directory("/usr/local/lib/postfix-mta-sts-resolver")
self.remove_file("/etc/systemd/system/mta-sts-daemon.service")
self.remove_file(CONFIG_FILES["mtasts_daemon"])
self.remove_directory(STATE_DIRS["postfix_mta_sts_resolver"])
self.remove_file(CONFIG_FILES["systemd_mtasts_daemon"])
def activate(self):
self.ensure_service(
@@ -218,7 +224,7 @@ class WebsiteDeployer(Deployer):
self.config = config
def install(self):
self.ensure_directory("/var/www")
self.ensure_directory(str(Path(WEB_PATHS["html_dir"]).parent))
def configure(self):
www_path, src_dir, build_dir = get_paths(self.config)
@@ -238,7 +244,9 @@ class WebsiteDeployer(Deployer):
return
# if it is not a hugo page, upload it as is
files.rsync(
f"{www_path}/", "/var/www/html", flags=["-avz", "--chown=www-data"]
f"{www_path}/",
WEB_PATHS["html_dir"],
flags=["-avz", "--chown=www-data"],
)
@@ -248,10 +256,10 @@ class LegacyRemoveDeployer(Deployer):
# remove historic expunge script
# which is now implemented through a systemd timer (chatmail-expire)
self.remove_file("/etc/cron.d/expunge")
self.remove_file(CONFIG_FILES["cron_expunge"])
# Remove OBS repository key that is no longer used.
self.remove_file("/etc/apt/keyrings/obs-home-deltachat.gpg")
self.remove_file(CONFIG_FILES["apt_obs_keyring"])
self.ensure_line(
path="/etc/apt/sources.list",
line="deb [signed-by=/etc/apt/keyrings/obs-home-deltachat.gpg] https://download.opensuse.org/repositories/home:/deltachat/Debian_12/ ./",
@@ -302,7 +310,7 @@ class TurnDeployer(Deployer):
"0fb3e792419494e21ecad536464929dba706bb2c88884ed8f1788141d26fc756",
),
}[host.get_fact(facts.server.Arch)]
self.download_executable(url, "/usr/local/bin/chatmail-turn", sha256sum)
self.download_executable(url, BINARY_PATHS["chatmail_turn"], sha256sum)
def configure(self):
configure_remote_units(self, self.mail_domain, self.units)
@@ -328,14 +336,14 @@ class IrohDeployer(Deployer):
}[host.get_fact(facts.server.Arch)]
self.download_executable(
url,
"/usr/local/bin/iroh-relay",
BINARY_PATHS["iroh_relay"],
sha256sum,
extract="gunzip | tar -xf - ./iroh-relay -O",
)
def configure(self):
self.ensure_systemd_unit("iroh-relay.service")
self.put_file("iroh-relay.toml", "/etc/iroh-relay.toml")
self.put_file("iroh-relay.toml", CONFIG_FILES["iroh_relay"])
def activate(self):
self.ensure_service(
@@ -346,7 +354,7 @@ class IrohDeployer(Deployer):
class JournaldDeployer(Deployer):
def configure(self):
self.put_file("journald.conf", "/etc/systemd/journald.conf")
self.put_file("journald.conf", CONFIG_FILES["journald"])
def activate(self):
self.ensure_service("systemd-journald.service")
@@ -388,7 +396,7 @@ class ChatmailDeployer(Deployer):
def install(self):
self.put_file(
src=BytesIO(b'APT::Install-Recommends "false";\n'),
dest="/etc/apt/apt.conf.d/00InstallRecommends",
dest=CONFIG_FILES["apt_install_recommends"],
)
apt.update(name="apt update", cache_time=24 * 3600)
apt.upgrade(name="upgrade apt packages", auto_remove=True)
@@ -414,9 +422,10 @@ class ChatmailDeployer(Deployer):
# This file is used by auth proxy.
# https://wiki.debian.org/EtcMailName
server.shell(
name="Setup /etc/mailname",
name=f"Setup {CONFIG_FILES['mailname']}",
commands=[
f"echo {self.mail_domain} >/etc/mailname; chmod 644 /etc/mailname"
f"echo {self.mail_domain} >{CONFIG_FILES['mailname']}; "
f"chmod 644 {CONFIG_FILES['mailname']}"
],
)
@@ -442,7 +451,9 @@ class GithashDeployer(Deployer):
git_diff = subprocess.check_output(["git", "diff"]).decode()
except Exception:
git_diff = ""
self.put_file(src=StringIO(git_hash + git_diff), dest="/etc/chatmail-version")
self.put_file(
src=StringIO(git_hash + git_diff), dest=CONFIG_FILES["chatmail_version"]
)
def get_tls_deployer(config, mail_domain):
+7 -5
View File
@@ -14,6 +14,7 @@ from cmdeploy.basedeploy import (
configure_remote_units,
is_in_container,
)
from cmdeploy.constants import CONFIG_FILES
DOVECOT_ARCHIVE_VERSION = "2.3.21+dfsg1-3"
DOVECOT_PACKAGE_VERSION = f"1:{DOVECOT_ARCHIVE_VERSION}"
@@ -64,7 +65,7 @@ class DovecotDeployer(Deployer):
"Pin: version *\n"
"Pin-Priority: -1\n"
),
dest="/etc/apt/preferences.d/pin-dovecot",
dest=CONFIG_FILES["apt_pin_dovecot"],
)
def configure(self):
@@ -134,18 +135,19 @@ def _download_dovecot_package(package: str, arch: str) -> tuple[str | None, bool
return deb_filename, True
def _configure_dovecot(deployer, config: Config, debug: bool = False):
"""Configures Dovecot IMAP server."""
deployer.put_template(
"dovecot/dovecot.conf.j2",
"/etc/dovecot/dovecot.conf",
CONFIG_FILES["dovecot_conf"],
config=config,
debug=debug,
disable_ipv6=config.disable_ipv6,
)
deployer.put_file("dovecot/auth.conf", "/etc/dovecot/auth.conf")
deployer.put_file("dovecot/auth.conf", CONFIG_FILES["dovecot_auth"])
deployer.put_file(
"dovecot/push_notification.lua", "/etc/dovecot/push_notification.lua"
"dovecot/push_notification.lua", CONFIG_FILES["dovecot_push_notification"]
)
# as per https://doc.dovecot.org/2.3/configuration_manual/os/
@@ -178,7 +180,7 @@ def _configure_dovecot(deployer, config: Config, debug: bool = False):
deployer.put_file(
"service/10_restart_on_failure.conf",
"/etc/systemd/system/dovecot.service.d/10_restart.conf",
CONFIG_FILES["systemd_dovecot_restart"],
)
# Validate dovecot configuration before restart
+3 -2
View File
@@ -3,12 +3,13 @@ import os
from pyinfra import facts, host
from cmdeploy.basedeploy import Deployer
from cmdeploy.constants import BINARY_PATHS, CHATMAILD_PATHS
class FiltermailDeployer(Deployer):
services = ["filtermail", "filtermail-incoming", "filtermail-transport"]
bin_path = "/usr/local/bin/filtermail"
config_path = "/usr/local/lib/chatmaild/chatmail.ini"
bin_path = BINARY_PATHS["filtermail"]
config_path = CHATMAILD_PATHS["config"]
def install(self):
local_bin = os.environ.get("CHATMAIL_FILTERMAIL_BINARY")
+3 -2
View File
@@ -2,6 +2,7 @@ from pyinfra import facts, host
from pyinfra.operations import apt
from cmdeploy.basedeploy import Deployer
from cmdeploy.constants import BINARY_PATHS, CONFIG_FILES
class MtailDeployer(Deployer):
@@ -24,7 +25,7 @@ class MtailDeployer(Deployer):
}[host.get_fact(facts.server.Arch)]
self.download_executable(
url,
"/usr/local/bin/mtail",
BINARY_PATHS["mtail"],
sha256sum,
extract="gunzip | tar -xf - mtail -O",
)
@@ -37,7 +38,7 @@ class MtailDeployer(Deployer):
address=self.mtail_address or "127.0.0.1",
port=3903,
)
self.put_file("mtail/delivered_mail.mtail", "/etc/mtail/delivered_mail.mtail")
self.put_file("mtail/delivered_mail.mtail", CONFIG_FILES["mtail_program"])
def activate(self):
active = bool(self.mtail_address)
+8 -7
View File
@@ -5,6 +5,7 @@ from cmdeploy.basedeploy import (
Deployer,
get_resource,
)
from cmdeploy.constants import CONFIG_FILES, WEB_PATHS
class NginxDeployer(Deployer):
@@ -31,14 +32,14 @@ class NginxDeployer(Deployer):
# For documentation about policy-rc.d, see:
# https://people.debian.org/~hmh/invokerc.d-policyrc.d-specification.txt
#
self.put_executable(src="policy-rc.d", dest="/usr/sbin/policy-rc.d")
self.put_executable(src="policy-rc.d", dest=CONFIG_FILES["policy_rc_d"])
apt.packages(
name="Install nginx",
packages=["nginx", "libnginx-mod-stream"],
)
self.remove_file("/usr/sbin/policy-rc.d")
self.remove_file(CONFIG_FILES["policy_rc_d"])
def configure(self):
_configure_nginx(self, self.config)
@@ -52,29 +53,29 @@ def _configure_nginx(deployer, config: Config, debug: bool = False):
deployer.put_template(
"nginx/nginx.conf.j2",
"/etc/nginx/nginx.conf",
CONFIG_FILES["nginx_conf"],
config=config,
disable_ipv6=config.disable_ipv6,
)
deployer.put_template(
"nginx/autoconfig.xml.j2",
"/var/www/html/.well-known/autoconfig/mail/config-v1.1.xml",
WEB_PATHS["autoconfig"],
config=config,
)
deployer.put_template(
"nginx/mta-sts.txt.j2",
"/var/www/html/.well-known/mta-sts.txt",
WEB_PATHS["mta_sts"],
config=config,
)
# install CGI newemail script
#
cgi_dir = "/usr/lib/cgi-bin"
cgi_dir = WEB_PATHS["newemail_cgi"].rsplit("/", 1)[0]
deployer.ensure_directory(cgi_dir)
deployer.put_executable(
src=get_resource("newemail.py", pkg="chatmaild").open("rb"),
dest=f"{cgi_dir}/newemail.py",
dest=WEB_PATHS["newemail_cgi"],
)
+14 -12
View File
@@ -7,6 +7,7 @@ from pyinfra.facts.files import File
from pyinfra.operations import apt, files, server
from cmdeploy.basedeploy import Deployer
from cmdeploy.constants import CONFIG_DIRS, CONFIG_FILES, STATE_DIRS
class OpendkimDeployer(Deployer):
@@ -28,43 +29,44 @@ class OpendkimDeployer(Deployer):
self.put_template(
"opendkim/opendkim.conf",
"/etc/opendkim.conf",
CONFIG_FILES["opendkim_conf"],
config={"domain_name": domain, "opendkim_selector": dkim_selector},
)
self.remove_file("/etc/opendkim/screen.lua")
self.remove_file("/etc/opendkim/final.lua")
self.remove_file(f"{CONFIG_DIRS['opendkim']}/screen.lua")
self.remove_file(f"{CONFIG_DIRS['opendkim']}/final.lua")
self.ensure_directory(
"/etc/opendkim",
CONFIG_DIRS["opendkim"],
owner="opendkim",
mode="750",
)
self.put_template(
"opendkim/KeyTable",
"/etc/dkimkeys/KeyTable",
f"{CONFIG_DIRS['dkimkeys']}/KeyTable",
owner="opendkim",
config={"domain_name": domain, "opendkim_selector": dkim_selector},
)
self.put_template(
"opendkim/SigningTable",
"/etc/dkimkeys/SigningTable",
f"{CONFIG_DIRS['dkimkeys']}/SigningTable",
owner="opendkim",
config={"domain_name": domain, "opendkim_selector": dkim_selector},
)
self.ensure_directory(
"/var/spool/postfix/opendkim",
f"{STATE_DIRS['var_spool_postfix']}/opendkim",
owner="opendkim",
mode="750",
)
if not host.get_fact(File, f"/etc/dkimkeys/{dkim_selector}.private"):
dkim_private_key = f"{CONFIG_DIRS['dkimkeys']}/{dkim_selector}.private"
if not host.get_fact(File, dkim_private_key):
server.shell(
name="Generate OpenDKIM domain keys",
commands=[
f"/usr/sbin/opendkim-genkey -D /etc/dkimkeys -d {domain} -s {dkim_selector}"
f"/usr/sbin/opendkim-genkey -D {CONFIG_DIRS['dkimkeys']} -d {domain} -s {dkim_selector}"
],
_use_su_login=True,
_su_user="opendkim",
@@ -72,12 +74,12 @@ class OpendkimDeployer(Deployer):
self.put_file(
"opendkim/systemd.conf",
"/etc/systemd/system/opendkim.service.d/10-prevent-memory-leak.conf",
CONFIG_FILES["systemd_opendkim_restart"],
)
files.file(
name="chown opendkim: /etc/dkimkeys/opendkim.private",
path="/etc/dkimkeys/opendkim.private",
name=f"chown opendkim: {dkim_private_key}",
path=dkim_private_key,
user="opendkim",
group="opendkim",
)
+13 -8
View File
@@ -1,6 +1,7 @@
from pyinfra.operations import apt, server
from cmdeploy.basedeploy import Deployer
from cmdeploy.constants import CONFIG_FILES
class PostfixDeployer(Deployer):
@@ -21,39 +22,43 @@ class PostfixDeployer(Deployer):
self.put_template(
"postfix/main.cf.j2",
"/etc/postfix/main.cf",
CONFIG_FILES["postfix_main"],
config=config,
disable_ipv6=config.disable_ipv6,
)
self.put_template(
"postfix/master.cf.j2",
"/etc/postfix/master.cf",
CONFIG_FILES["postfix_master"],
debug=False,
config=config,
)
self.put_file(
"postfix/submission_header_cleanup",
"/etc/postfix/submission_header_cleanup",
CONFIG_FILES["postfix_submission_header_cleanup"],
)
self.put_file(
"postfix/lmtp_header_cleanup",
CONFIG_FILES["postfix_lmtp_header_cleanup"],
)
self.put_file("postfix/lmtp_header_cleanup", "/etc/postfix/lmtp_header_cleanup")
res = self.put_file(
"postfix/smtp_tls_policy_map", "/etc/postfix/smtp_tls_policy_map"
"postfix/smtp_tls_policy_map",
CONFIG_FILES["postfix_smtp_tls_policy_map"],
)
tls_policy_changed = res.changed
if tls_policy_changed:
server.shell(
commands=["postmap /etc/postfix/smtp_tls_policy_map"],
commands=[f"postmap {CONFIG_FILES['postfix_smtp_tls_policy_map']}"],
)
# Login map that 1:1 maps email address to login.
self.put_file("postfix/login_map", "/etc/postfix/login_map")
self.put_file("postfix/login_map", CONFIG_FILES["postfix_login_map"])
self.put_file(
"service/10_restart_on_failure.conf",
"/etc/systemd/system/postfix@.service.d/10_restart.conf",
CONFIG_FILES["systemd_postfix_restart"],
)
# Validate postfix configuration before restart
+69 -58
View File
@@ -4,6 +4,17 @@ from pathlib import Path
from chatmaild.config import read_config
from pyinfra.operations import apt, files, server
from cmdeploy.constants import (
ACME_PATHS,
BINARY_PATHS,
CHATMAILD_PATHS,
CONFIG_DIRS,
CONFIG_FILES,
STATE_DIRS,
TLS_PATHS,
WEB_PATHS,
)
CHATMAIL_UNITS = [
"doveauth.service",
"lastlogin.service",
@@ -63,66 +74,66 @@ PACKAGE_NAMES = [
]
RELAY_FILES = [
"/etc/apt/apt.conf.d/00InstallRecommends",
"/etc/apt/keyrings/obs-home-deltachat.gpg",
"/etc/apt/preferences.d/pin-dovecot",
"/etc/chatmail-nocreate",
"/etc/chatmail-version",
"/etc/cron.d/acmetool",
"/etc/cron.d/chatmail-metrics",
"/etc/cron.d/expunge",
"/etc/dovecot/auth.conf",
"/etc/dovecot/dovecot.conf",
"/etc/dovecot/push_notification.lua",
"/etc/iroh-relay.toml",
"/etc/mailname",
"/etc/mta-sts-daemon.yml",
"/etc/mtail/delivered_mail.mtail",
"/etc/nginx/nginx.conf",
"/etc/opendkim.conf",
"/etc/postfix/lmtp_header_cleanup",
"/etc/postfix/login_map",
"/etc/postfix/main.cf",
"/etc/postfix/master.cf",
"/etc/postfix/smtp_tls_policy_map",
"/etc/postfix/smtp_tls_policy_map.db",
"/etc/postfix/submission_header_cleanup",
"/etc/systemd/journald.conf",
"/etc/systemd/system/mta-sts-daemon.service",
"/etc/systemd/system/dovecot.service.d/10_restart.conf",
"/etc/systemd/system/opendkim.service.d/10-prevent-memory-leak.conf",
"/etc/systemd/system/postfix@.service.d/10_restart.conf",
"/etc/unbound/unbound.conf.d/chatmail.conf",
"/usr/lib/cgi-bin/newemail.py",
"/usr/local/bin/chatmail-turn",
"/usr/local/bin/filtermail",
"/usr/local/bin/iroh-relay",
"/usr/local/bin/mtail",
"/usr/sbin/policy-rc.d",
"/var/www/html/metrics",
CONFIG_FILES["apt_install_recommends"],
CONFIG_FILES["apt_obs_keyring"],
CONFIG_FILES["apt_pin_dovecot"],
CONFIG_FILES["chatmail_nocreate"],
CONFIG_FILES["chatmail_version"],
CONFIG_FILES["cron_acmetool"],
CONFIG_FILES["cron_chatmail_metrics"],
CONFIG_FILES["cron_expunge"],
CONFIG_FILES["dovecot_auth"],
CONFIG_FILES["dovecot_conf"],
CONFIG_FILES["dovecot_push_notification"],
CONFIG_FILES["iroh_relay"],
CONFIG_FILES["journald"],
CONFIG_FILES["mailname"],
CONFIG_FILES["mtail_program"],
CONFIG_FILES["mtasts_daemon"],
CONFIG_FILES["nginx_conf"],
CONFIG_FILES["opendkim_conf"],
CONFIG_FILES["policy_rc_d"],
CONFIG_FILES["postfix_lmtp_header_cleanup"],
CONFIG_FILES["postfix_login_map"],
CONFIG_FILES["postfix_main"],
CONFIG_FILES["postfix_master"],
CONFIG_FILES["postfix_smtp_tls_policy_map"],
CONFIG_FILES["postfix_smtp_tls_policy_map_db"],
CONFIG_FILES["postfix_submission_header_cleanup"],
CONFIG_FILES["systemd_dovecot_restart"],
CONFIG_FILES["systemd_mtasts_daemon"],
CONFIG_FILES["systemd_opendkim_restart"],
CONFIG_FILES["systemd_postfix_restart"],
CONFIG_FILES["unbound_chatmail"],
WEB_PATHS["metrics"],
WEB_PATHS["newemail_cgi"],
BINARY_PATHS["chatmail_turn"],
BINARY_PATHS["filtermail"],
BINARY_PATHS["iroh_relay"],
BINARY_PATHS["mtail"],
]
PACKAGE_CONFIG_DIRS = [
"/etc/dkimkeys",
"/etc/dovecot",
"/etc/nginx",
"/etc/opendkim",
"/etc/postfix",
"/etc/unbound",
CONFIG_DIRS["dkimkeys"],
CONFIG_DIRS["dovecot"],
CONFIG_DIRS["nginx"],
CONFIG_DIRS["opendkim"],
CONFIG_DIRS["postfix"],
CONFIG_DIRS["unbound"],
]
RELAY_DIRS = [
"/etc/mtail",
"/root/from-cmdeploy",
"/usr/local/lib/chatmaild",
"/usr/local/lib/postfix-mta-sts-resolver",
"/var/lib/dovecot",
"/var/lib/nginx",
"/var/lib/postfix",
"/var/lib/unbound",
"/var/log/nginx",
"/var/spool/postfix",
"/var/www/html",
CONFIG_DIRS["mtail"],
STATE_DIRS["from_cmdeploy"],
CHATMAILD_PATHS["base_dir"],
STATE_DIRS["postfix_mta_sts_resolver"],
STATE_DIRS["var_lib_dovecot"],
STATE_DIRS["var_lib_nginx"],
STATE_DIRS["var_lib_postfix"],
STATE_DIRS["var_lib_unbound"],
STATE_DIRS["var_log_nginx"],
STATE_DIRS["var_spool_postfix"],
WEB_PATHS["html_dir"],
]
EMPTY_SYSTEMD_DIRS = [
@@ -220,11 +231,11 @@ def _remove_dynamic_state(config, keep_packages: bool):
_remove_dir(str(home_vmail))
if config.tls_cert_mode == "self":
_remove_file("/etc/ssl/certs/mailserver.pem")
_remove_file("/etc/ssl/private/mailserver.key")
_remove_file(TLS_PATHS["self_cert"])
_remove_file(TLS_PATHS["self_key"])
elif config.tls_cert_mode == "acme":
_remove_dir("/etc/acme")
_remove_dir("/var/lib/acme")
_remove_dir(ACME_PATHS["etc_dir"])
_remove_dir(ACME_PATHS["var_dir"])
def _restore_basic_resolver():
+4 -5
View File
@@ -2,6 +2,8 @@ import shlex
from pyinfra.operations import server
from cmdeploy.constants import TLS_PATHS
from ..basedeploy import Deployer
@@ -31,9 +33,8 @@ class SelfSignedTlsDeployer(Deployer):
def __init__(self, mail_domain):
self.mail_domain = mail_domain
self.cert_path = "/etc/ssl/certs/mailserver.pem"
self.key_path = "/etc/ssl/private/mailserver.key"
self.cert_path = TLS_PATHS["self_cert"]
self.key_path = TLS_PATHS["self_key"]
def configure(self):
@@ -48,5 +49,3 @@ class SelfSignedTlsDeployer(Deployer):
def activate(self):
pass
+23 -15
View File
@@ -1,6 +1,14 @@
from unittest.mock import call
from cmdeploy import removers
from cmdeploy.constants import (
ACME_PATHS,
CHATMAILD_PATHS,
CONFIG_DIRS,
CONFIG_FILES,
STATE_DIRS,
TLS_PATHS,
)
def test_remove_chatmail_purges_packages_and_state(make_config, monkeypatch):
@@ -28,20 +36,20 @@ def test_remove_chatmail_purges_packages_and_state(make_config, monkeypatch):
"purge": True,
}
]
assert call(path="/usr/local/lib/chatmaild", present=False) in [
assert call(path=CHATMAILD_PATHS["base_dir"], present=False) in [
call(path=entry["path"], present=entry["present"]) for entry in dir_calls
]
assert call(path=str(config.mailboxes_dir), present=False) in [
call(path=entry["path"], present=entry["present"]) for entry in dir_calls
]
assert any(entry["path"] == "/var/lib/acme" for entry in dir_calls)
assert any(entry["path"] == ACME_PATHS["var_dir"] for entry in dir_calls)
assert any(
entry["path"] == "/etc/systemd/system/doveauth.service" for entry in file_calls
)
assert any(entry["path"] == "/etc/postfix/main.cf" for entry in file_calls)
assert any(entry["path"] == "/etc/opendkim.conf" for entry in file_calls)
assert any(entry["path"] == "/etc/postfix" for entry in dir_calls)
assert any(entry["path"] == "/var/log/nginx" for entry in dir_calls)
assert any(entry["path"] == CONFIG_FILES["postfix_main"] for entry in file_calls)
assert any(entry["path"] == CONFIG_FILES["opendkim_conf"] for entry in file_calls)
assert any(entry["path"] == CONFIG_DIRS["postfix"] for entry in dir_calls)
assert any(entry["path"] == STATE_DIRS["var_log_nginx"] for entry in dir_calls)
assert any(
"userdel -r vmail" in command
for entry in shell_calls
@@ -73,13 +81,13 @@ def test_remove_chatmail_keep_packages_and_external_tls(make_config, monkeypatch
removed_dirs = {entry["path"] for entry in dir_calls}
assert "/certs/fullchain.pem" not in removed_files
assert "/certs/privkey.pem" not in removed_files
assert "/var/lib/acme" not in removed_dirs
assert "/etc/nginx" not in removed_dirs
assert "/etc/unbound" not in removed_dirs
assert "/etc/postfix" not in removed_dirs
assert "/etc/dovecot" not in removed_dirs
assert "/etc/nginx/nginx.conf" in removed_files
assert "/etc/unbound/unbound.conf.d/chatmail.conf" in removed_files
assert ACME_PATHS["var_dir"] not in removed_dirs
assert CONFIG_DIRS["nginx"] not in removed_dirs
assert CONFIG_DIRS["unbound"] not in removed_dirs
assert CONFIG_DIRS["postfix"] not in removed_dirs
assert CONFIG_DIRS["dovecot"] not in removed_dirs
assert CONFIG_FILES["nginx_conf"] in removed_files
assert CONFIG_FILES["unbound_chatmail"] in removed_files
def test_remove_chatmail_removes_self_signed_tls(make_config, monkeypatch):
@@ -95,5 +103,5 @@ def test_remove_chatmail_removes_self_signed_tls(make_config, monkeypatch):
removers.remove_chatmail(config._inipath)
removed = {entry["path"] for entry in file_calls}
assert "/etc/ssl/certs/mailserver.pem" in removed
assert "/etc/ssl/private/mailserver.key" in removed
assert TLS_PATHS["self_cert"] in removed
assert TLS_PATHS["self_key"] in removed