diff --git a/core/archipelago/src/api/rpc/system/handlers.rs b/core/archipelago/src/api/rpc/system/handlers.rs index cb2969d1..7c4e3a4d 100644 --- a/core/archipelago/src/api/rpc/system/handlers.rs +++ b/core/archipelago/src/api/rpc/system/handlers.rs @@ -53,6 +53,7 @@ impl RpcHandler { // hit a hostname-mismatch warning on top of the usual self-signed one // the moment a node is renamed. if hostname_updated { + sync_hostname_side_effects(&hostname).await; if let Err(e) = regenerate_tls_cert(&hostname).await { warn!(hostname = %hostname, "TLS cert regen after rename failed: {}", e); } @@ -375,6 +376,46 @@ pub(super) fn hostname_from_server_name(name: &str) -> String { } } +/// Post-rename side effects that keep the OS consistent with the new +/// hostname — all best-effort, the rename itself has already succeeded. +/// Debian resolves the local hostname via the 127.0.1.1 line in /etc/hosts; +/// leaving the old name there breaks `sudo` ("unable to resolve host") and +/// `hostname -f`. And while avahi eventually follows the kernel hostname, +/// re-announcing immediately makes http(s)://.local links work +/// right after the rename instead of minutes later. +async fn sync_hostname_side_effects(hostname: &str) { + // hostname_from_server_name guarantees [a-z0-9-], safe to interpolate. + let script = format!( + "if grep -q '^127\\.0\\.1\\.1' /etc/hosts; then sed -i 's/^127\\.0\\.1\\.1.*/127.0.1.1\\t{h}/' /etc/hosts; else printf '127.0.1.1\\t{h}\\n' >> /etc/hosts; fi", + h = hostname + ); + match tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/bin/sh", "-c", &script]) + .output() + .await + { + Ok(o) if o.status.success() => {} + Ok(o) => warn!( + "/etc/hosts hostname sync failed: {}", + String::from_utf8_lossy(&o.stderr).trim() + ), + Err(e) => warn!("/etc/hosts hostname sync failed: {}", e), + } + + let republished = tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/usr/bin/avahi-set-host-name", hostname]) + .output() + .await + .map(|o| o.status.success()) + .unwrap_or(false); + if !republished { + let _ = tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/usr/bin/systemctl", "try-restart", "avahi-daemon"]) + .output() + .await; + } +} + async fn set_system_hostname(hostname: &str) -> Result<()> { let output = tokio::process::Command::new("/usr/bin/sudo") .args(["-n", "/usr/bin/hostnamectl", "set-hostname", hostname])