use super::{OVERLAY_NET, OVERLAY_SCRIPT_PATH};
use crate::core::shell_escape::sh_squote;
use crate::core::types::Resource;
pub(super) fn service_unit(ip_cidr: &str) -> String {
format!(
"[Unit]\n\
Description=Fleet management overlay IP (DNS/DHCP-independent)\n\
Documentation=https://github.com/paiml/infra/tree/main/machines/fleet-hosts\n\
After=network-online.target\n\
Wants=network-online.target\n\
\n\
[Service]\n\
Type=oneshot\n\
ExecStart={OVERLAY_SCRIPT_PATH} {ip_cidr}\n\
\n\
[Install]\n\
WantedBy=multi-user.target"
)
}
pub(super) fn timer_unit() -> &'static str {
"[Unit]\n\
Description=Re-assert fleet management overlay IP (self-heal NIC flaps / boot races / DHCP flush)\n\
Documentation=https://github.com/paiml/infra/tree/main/machines/fleet-hosts\n\
\n\
[Timer]\n\
OnBootSec=20s\n\
OnCalendar=minutely\n\
RandomizedDelaySec=30\n\
AccuracySec=1s\n\
Persistent=true\n\
\n\
[Install]\n\
WantedBy=timers.target"
}
pub(super) fn dispatcher_hook() -> &'static str {
"#!/bin/sh\n\
# fleet-overlay dispatcher (managed by forjar overlay_interface).\n\
# restart --no-block (NOT start) re-runs ExecStart on the plain oneshot.\n\
case \"${2:-}\" in\n\
\x20 up|dhcp4-change|dhcp6-change|reapply)\n\
\x20\x20\x20 systemctl restart --no-block fleet-overlay.service 2>/dev/null || true\n\
\x20\x20\x20 ;;\n\
esac"
}
pub(super) fn hosts_block(resource: &Resource) -> Option<String> {
let hosts = resource.overlay_hosts.as_ref()?;
if hosts.is_empty() {
return None;
}
let mut entries: Vec<(&String, &String)> = hosts.iter().collect();
entries.sort_by(|a, b| a.1.cmp(b.1).then(a.0.cmp(b.0)));
let mut body = String::new();
for (name, ip) in entries {
body.push_str(&format!(
"printf '%s %s\\n' {} {} >> \"$TMP\"\n",
sh_squote(ip),
sh_squote(name)
));
}
Some(format!(
"# -- managed /etc/hosts block (overlay_hosts) --\n\
HOSTS=/etc/hosts\n\
TMP=\"$(mktemp)\"\n\
trap 'rm -f \"$TMP\" \"$TMP.2\"' EXIT\n\
nb=$(grep -c '^# BEGIN forjar-fleet' \"$HOSTS\" 2>/dev/null || echo 0)\n\
ne=$(grep -c '^# END forjar-fleet' \"$HOSTS\" 2>/dev/null || echo 0)\n\
if [ \"$nb\" != \"$ne\" ]; then\n\
\x20 echo \"fleet-hosts: refusing to edit — unbalanced markers ($nb/$ne)\" >&2\n\
else\n\
\x20 awk '\n\
\x20\x20\x20 index($0,\"# BEGIN forjar-fleet\")==1 {{skip=1}}\n\
\x20\x20\x20 skip!=1 {{print}}\n\
\x20\x20\x20 index($0,\"# END forjar-fleet\")==1 {{skip=0}}\n\
\x20 ' \"$HOSTS\" > \"$TMP.2\"\n\
\x20 awk 'NF{{last=NR}} {{line[NR]=$0}} END{{for(i=1;i<=last;i++) print line[i]}}' \"$TMP.2\" > \"$TMP\"\n\
\x20 printf '\\n%s\\n' '# BEGIN forjar-fleet (managed by forjar overlay_interface -- do not edit by hand)' >> \"$TMP\"\n\
{body}\
\x20 printf '%s\\n' '# END forjar-fleet' >> \"$TMP\"\n\
\x20 cp \"$HOSTS\" \"$HOSTS.fleet.bak\" 2>/dev/null || true\n\
\x20 cat \"$TMP\" > \"$HOSTS\"\n\
\x20 echo 'fleet-hosts: updated /etc/hosts'\n\
fi"
))
}
pub(super) fn firewall_block(resource: &Resource) -> Option<String> {
if !resource.overlay_firewall.unwrap_or(false) {
return None;
}
Some(format!(
"# -- ufw allow overlay subnet --\n\
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -qi '^Status: active'; then\n\
\x20 if ufw status 2>/dev/null | grep -q '{OVERLAY_NET}'; then\n\
\x20\x20\x20 echo 'fleet-firewall: {OVERLAY_NET} already allowed'\n\
\x20 else\n\
\x20\x20\x20 ufw allow from {OVERLAY_NET} comment 'fleet overlay'\n\
\x20\x20\x20 echo 'fleet-firewall: allowed {OVERLAY_NET}'\n\
\x20 fi\n\
else\n\
\x20 echo 'fleet-firewall: ufw inactive/absent — skipping'\n\
fi"
))
}