refactor: Add AcmetoolDeployer

- This splits the existing deploy_acmetool() routine into methods for
  the install, configure, and activate stages.
This commit is contained in:
cliffmccarthy
2025-09-08 08:16:59 -05:00
parent 6afd31fb17
commit afc1be2671
2 changed files with 119 additions and 96 deletions

View File

@@ -19,7 +19,7 @@ from pyinfra.facts.server import Sysctl
from pyinfra.facts.systemd import SystemdEnabled from pyinfra.facts.systemd import SystemdEnabled
from pyinfra.operations import apt, files, pip, server, systemd from pyinfra.operations import apt, files, pip, server, systemd
from .acmetool import deploy_acmetool from .acmetool import AcmetoolDeployer
from .deployer import Deployer from .deployer import Deployer
from .www import build_webpages, find_merge_conflict, get_paths 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", line="nameserver 9.9.9.9",
) )
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"]
unbound_deployer = UnboundDeployer() unbound_deployer = UnboundDeployer()
iroh_deployer = IrohDeployer(enable_iroh_relay=config.enable_iroh_relay) 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) opendkim_deployer = OpendkimDeployer(mail_domain=mail_domain)
# Dovecot should be started before Postfix # Dovecot should be started before Postfix
@@ -929,6 +935,7 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
all_deployers = [ all_deployers = [
unbound_deployer, unbound_deployer,
iroh_deployer, iroh_deployer,
acmetool_deployer,
opendkim_deployer, opendkim_deployer,
dovecot_deployer, dovecot_deployer,
postfix_deployer, postfix_deployer,
@@ -1013,12 +1020,9 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
iroh_deployer.configure() iroh_deployer.configure()
iroh_deployer.activate() iroh_deployer.activate()
# Deploy acmetool to have TLS certificates. acmetool_deployer.install()
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"] acmetool_deployer.configure()
deploy_acmetool( acmetool_deployer.activate()
email=config.acme_email,
domains=tls_domains,
)
apt.packages( apt.packages(
# required for setfacl for echobot # required for setfacl for echobot

View File

@@ -2,9 +2,20 @@ import importlib.resources
from pyinfra.operations import apt, files, server, systemd from pyinfra.operations import apt, files, server, systemd
from ..deployer import Deployer
def deploy_acmetool(email="", domains=[]):
"""Deploy acmetool.""" class AcmetoolDeployer(Deployer):
def __init__(self, *, email, domains, **kwargs):
super().__init__(**kwargs)
self.domains = domains
self.email = email
self.need_restart_redirector = False
self.need_restart_reconcile_service = False
self.need_restart_reconcile_timer = False
@staticmethod
def install_impl():
apt.packages( apt.packages(
name="Install acmetool", name="Install acmetool",
packages=["acmetool"], packages=["acmetool"],
@@ -30,13 +41,14 @@ def deploy_acmetool(email="", domains=[]):
present=False, present=False,
) )
def configure_impl(self):
files.template( files.template(
src=importlib.resources.files(__package__).joinpath("response-file.yaml.j2"), src=importlib.resources.files(__package__).joinpath("response-file.yaml.j2"),
dest="/var/lib/acme/conf/responses", dest="/var/lib/acme/conf/responses",
user="root", user="root",
group="root", group="root",
mode="644", mode="644",
email=email, email=self.email,
) )
files.template( files.template(
@@ -56,14 +68,7 @@ def deploy_acmetool(email="", domains=[]):
group="root", group="root",
mode="644", mode="644",
) )
self.need_restart_redirector = service_file.changed
systemd.service(
name="Setup acmetool-redirector service",
service="acmetool-redirector.service",
running=True,
enabled=True,
restarted=service_file.changed,
)
reconcile_service_file = files.put( reconcile_service_file = files.put(
src=importlib.resources.files(__package__).joinpath( src=importlib.resources.files(__package__).joinpath(
@@ -74,14 +79,7 @@ def deploy_acmetool(email="", domains=[]):
group="root", group="root",
mode="644", mode="644",
) )
self.need_restart_reconcile_service = reconcile_service_file.changed
systemd.service(
name="Setup acmetool-reconcile service",
service="acmetool-reconcile.service",
running=False,
enabled=False,
daemon_reload=reconcile_service_file.changed,
)
reconcile_timer_file = files.put( reconcile_timer_file = files.put(
src=importlib.resources.files(__package__).joinpath("acmetool-reconcile.timer"), src=importlib.resources.files(__package__).joinpath("acmetool-reconcile.timer"),
@@ -90,16 +88,37 @@ def deploy_acmetool(email="", domains=[]):
group="root", group="root",
mode="644", mode="644",
) )
self.need_restart_reconcile_timer = reconcile_timer_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_redirector,
)
self.need_restart_redirector = False
systemd.service(
name="Setup acmetool-reconcile service",
service="acmetool-reconcile.service",
running=False,
enabled=False,
daemon_reload=self.need_restart_reconcile_service,
)
self.need_restart_reconcile_service = False
systemd.service( systemd.service(
name="Setup acmetool-reconcile timer", name="Setup acmetool-reconcile timer",
service="acmetool-reconcile.timer", service="acmetool-reconcile.timer",
running=True, running=True,
enabled=True, enabled=True,
daemon_reload=reconcile_timer_file.changed, daemon_reload=self.need_restart_reconcile_timer,
) )
self.need_restart_reconcile_timer = False
server.shell( server.shell(
name=f"Request certificate for: {', '.join(domains)}", name=f"Request certificate for: {', '.join(self.domains)}",
commands=[f"acmetool want --xlog.severity=debug {' '.join(domains)}"], commands=[f"acmetool want --xlog.severity=debug {' '.join(self.domains)}"],
) )