From 84ab4bb6b8d770f6840b2059a08da37a02885b9f Mon Sep 17 00:00:00 2001 From: cliffmccarthy <16453869+cliffmccarthy@users.noreply.github.com> Date: Mon, 8 Sep 2025 08:16:59 -0500 Subject: [PATCH] refactor: Add AcmetoolDeployer - This splits the existing deploy_acmetool() routine into methods for the install, configure, and activate stages. --- cmdeploy/src/cmdeploy/__init__.py | 18 +-- cmdeploy/src/cmdeploy/acmetool/__init__.py | 123 ++++++++++++--------- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/cmdeploy/src/cmdeploy/__init__.py b/cmdeploy/src/cmdeploy/__init__.py index ba77c79b..aae202ca 100644 --- a/cmdeploy/src/cmdeploy/__init__.py +++ b/cmdeploy/src/cmdeploy/__init__.py @@ -19,7 +19,7 @@ from pyinfra.facts.server import Sysctl from pyinfra.facts.systemd import SystemdEnabled from pyinfra.operations import apt, files, pip, server, systemd -from .acmetool import deploy_acmetool +from .acmetool import AcmetoolDeployer from .deployer import Deployer from .www import build_webpages, find_merge_conflict, get_paths @@ -913,8 +913,14 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None: line="nameserver 9.9.9.9", ) + tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"] + unbound_deployer = UnboundDeployer() iroh_deployer = IrohDeployer(enable_iroh_relay=config.enable_iroh_relay) + + # Deploy acmetool to have TLS certificates. + acmetool_deployer = AcmetoolDeployer(email=config.acme_email, domains=tls_domains) + opendkim_deployer = OpendkimDeployer(mail_domain=mail_domain) # Dovecot should be started before Postfix @@ -929,6 +935,7 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None: all_deployers = [ unbound_deployer, iroh_deployer, + acmetool_deployer, opendkim_deployer, dovecot_deployer, postfix_deployer, @@ -1013,12 +1020,9 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None: iroh_deployer.configure() iroh_deployer.activate() - # Deploy acmetool to have TLS certificates. - tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"] - deploy_acmetool( - email=config.acme_email, - domains=tls_domains, - ) + acmetool_deployer.install() + acmetool_deployer.configure() + acmetool_deployer.activate() apt.packages( # required for setfacl for echobot diff --git a/cmdeploy/src/cmdeploy/acmetool/__init__.py b/cmdeploy/src/cmdeploy/acmetool/__init__.py index 28d4fd88..6bded704 100644 --- a/cmdeploy/src/cmdeploy/acmetool/__init__.py +++ b/cmdeploy/src/cmdeploy/acmetool/__init__.py @@ -2,66 +2,79 @@ import importlib.resources from pyinfra.operations import apt, files, server, systemd +from ..deployer import Deployer -def deploy_acmetool(email="", domains=[]): - """Deploy acmetool.""" - apt.packages( - name="Install acmetool", - packages=["acmetool"], - ) - files.put( - src=importlib.resources.files(__package__).joinpath("acmetool.cron").open("rb"), - dest="/etc/cron.d/acmetool", - user="root", - group="root", - mode="644", - ) +class AcmetoolDeployer(Deployer): + def __init__(self, *, email, domains, **kwargs): + super().__init__(**kwargs) + self.domains = domains + self.email = email + self.need_restart = False - files.put( - src=importlib.resources.files(__package__).joinpath("acmetool.hook").open("rb"), - dest="/usr/lib/acme/hooks/nginx", - user="root", - group="root", - mode="744", - ) + @staticmethod + def install_impl(): + apt.packages( + name="Install acmetool", + packages=["acmetool"], + ) - files.template( - src=importlib.resources.files(__package__).joinpath("response-file.yaml.j2"), - dest="/var/lib/acme/conf/responses", - user="root", - group="root", - mode="644", - email=email, - ) + def configure_impl(self): + files.put( + src=importlib.resources.files(__package__).joinpath("acmetool.cron").open("rb"), + dest="/etc/cron.d/acmetool", + user="root", + group="root", + mode="644", + ) - files.template( - src=importlib.resources.files(__package__).joinpath("target.yaml.j2"), - dest="/var/lib/acme/conf/target", - user="root", - group="root", - mode="644", - ) + files.put( + src=importlib.resources.files(__package__).joinpath("acmetool.hook").open("rb"), + dest="/usr/lib/acme/hooks/nginx", + user="root", + group="root", + mode="744", + ) - service_file = files.put( - src=importlib.resources.files(__package__).joinpath( - "acmetool-redirector.service" - ), - dest="/etc/systemd/system/acmetool-redirector.service", - user="root", - group="root", - mode="644", - ) + files.template( + src=importlib.resources.files(__package__).joinpath("response-file.yaml.j2"), + dest="/var/lib/acme/conf/responses", + user="root", + group="root", + mode="644", + email=self.email, + ) - systemd.service( - name="Setup acmetool-redirector service", - service="acmetool-redirector.service", - running=True, - enabled=True, - restarted=service_file.changed, - ) + files.template( + src=importlib.resources.files(__package__).joinpath("target.yaml.j2"), + dest="/var/lib/acme/conf/target", + user="root", + group="root", + mode="644", + ) - server.shell( - name=f"Request certificate for: {', '.join(domains)}", - commands=[f"acmetool want --xlog.severity=debug {' '.join(domains)}"], - ) + service_file = files.put( + src=importlib.resources.files(__package__).joinpath( + "acmetool-redirector.service" + ), + dest="/etc/systemd/system/acmetool-redirector.service", + user="root", + group="root", + mode="644", + ) + self.need_restart = service_file.changed + + def activate_impl(self): + systemd.service( + name="Setup acmetool-redirector service", + service="acmetool-redirector.service", + running=True, + enabled=True, + restarted=self.need_restart, + ) + self.need_restart = False + + server.shell( + name=f"Request certificate for: {', '.join(self.domains)}", + commands=[f"acmetool want --xlog.severity=debug {' '.join(self.domains)}"], + )