trust-dns: port to dyn-dns for determining WAN IP

although the systemd wantedBy directive is working,
`before` seems to be ignored when the unit fails. so on first run,
dyn-dns runs, fails (poor net connectivity), then trust-dns starts
(fails), then they both restart 10s later.

it's not great, but good enough. also, wan IP is persisted, so this
likely won't happen much in practice.
This commit is contained in:
colin 2022-12-19 13:12:21 +00:00
parent 3122334a41
commit 97044bf70e
3 changed files with 30 additions and 66 deletions

View File

@ -49,62 +49,21 @@
"/var/lib/trust-dns/native.uninsane.org.zone"
];
systemd.services.ddns-trust-dns = {
description = "update dynamic DNS entries for self-hosted trust-dns";
after = [ "network.target" ];
wantedBy = [ "trust-dns.service" ];
restartTriggers = [(
builtins.toJSON config.sane.services.trust-dns
)];
serviceConfig.Type = "oneshot";
script = let
check-ip = "${pkgs.sane-scripts}/bin/sane-ip-check-router-wan";
sed = "${pkgs.gnused}/bin/sed";
zone-dir = "/var/lib/trust-dns";
zone-out = "${zone-dir}/native.uninsane.org.zone";
diff = "${pkgs.diffutils}/bin/diff";
systemctl = "${pkgs.systemd}/bin/systemctl";
zone-template = pkgs.writeText "native.uninsane.org.zone.in" ''
@ A %NATIVE%
ns1 A %NATIVE%
native A %NATIVE%
'';
in ''
set -ex
mkdir -p ${zone-dir}
ip=$(${check-ip})
${sed} s/%NATIVE%/$ip/ ${zone-template} > ${zone-out}.new
# see if anything changed
# TODO: instead of diffing, we could `dig` against the actual deployment.
# - that could be more resilient to races.
touch ${zone-out} # in case it didn't exist yet
cp ${zone-out} ${zone-out}.old
mv ${zone-out}.new ${zone-out}
# if so, restart trust-dns
if [ ${diff} -u ${zone-out}.old ${zone-out} ]
then
echo "zone unchanged. ip: $ip"
else
echo "zone changed."
status=$(${systemctl} is-active trust-dns.service || true)
echo $status
if [ "$status" = "active" ]
then
echo "restarting trust-dns."
${systemctl} restart trust-dns.service
fi
fi
systemd.services.trust-dns.preStart = let
sed = "${pkgs.gnused}/bin/sed";
zone-dir = "/var/lib/trust-dns";
zone-out = "${zone-dir}/native.uninsane.org.zone";
zone-template = pkgs.writeText "native.uninsane.org.zone.in" ''
@ A %NATIVE%
ns1 A %NATIVE%
native A %NATIVE%
'';
};
in ''
# make WAN records available to trust-dns
mkdir -p ${zone-dir}
ip=$(cat '${config.sane.services.dyn-dns.ipPath}')
${sed} s/%NATIVE%/$ip/ ${zone-template} > ${zone-out}
'';
systemd.timers.ddns-trust-dns = {
# wantedBy = [ "multi-user.target" ];
wantedBy = [ "trust-dns.service" ];
timerConfig = {
OnStartupSec = "10min";
OnUnitActiveSec = "10min";
};
};
sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ];
}

View File

@ -41,32 +41,39 @@ in
config = mkIf cfg.enable {
systemd.services.dyn-dns = {
description = "update this host's record of its WAN IP";
after = [ "network.target" ];
restartTriggers = [(builtins.toJSON cfg)];
serviceConfig.Type = "oneshot";
restartTriggers = [(builtins.toJSON cfg)];
after = [ "network.target" ];
wantedBy = cfg.restartOnChange;
before = cfg.restartOnChange;
script = ''
mkdir -p $(dirname '${cfg.ipPath}')
mkdir -p "$(dirname '${cfg.ipPath}')"
newIp=$(${cfg.ipCmd})
oldIp=$(cat '${cfg.ipPath}' || true)
# systemd path units are triggered on any file write action,
# regardless of content change. so only update the file if our IP *actually* changed
if [ "$newIp" != "$(cat '${cfg.ipPath}')" ]
if [ "$newIp" != "$oldIp" ]
then
echo "$newIp" > '${cfg.ipPath}'
echo "WAN ip changed $oldIp -> $newIp"
fi
exit $(test -f '${cfg.ipPath}')
'';
};
systemd.timers.dyn-dns = {
wantedBy = [ "multi-user.target" ];
# if anything wants dyn-dns.service, they surely want the timer too.
wantedBy = [ "dyn-dns.service" ];
timerConfig = {
OnStartupSec = cfg.interval;
OnUnitActiveSec = cfg.interval;
};
};
systemd.paths.dyn-dns-watcher = {
before = [ "dyn-dns.service" ];
wantedBy = [ "dyn-dns.service" ];
before = [ "dyn-dns.timer" ];
wantedBy = [ "dyn-dns.timer" ];
pathConfig = {
Unit = "dyn-dns-reactor.service";
PathChanged = [ cfg.ipPath ];

View File

@ -137,8 +137,6 @@ in
RestartSec = "10s";
# TODO: hardening (like, don't run as root!)
};
wants = [ "ddns-trust-dns.service" "ddns-trust-dns.timer" ];
# XXX: can't be after ddns-trust-dns.service, because the latter `restarts` this one -- *before* it's done activating.
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
};