From f201f04d4e2ee0945eb3a377779b3b6dd5c0d124 Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 5 Jun 2026 12:13:37 +0200 Subject: [PATCH] fix(#1329): restart hive-matrix-daemon after token write so new credential is picked up immediately --- hive-c0re/src/matrix.rs | 9 +++++++++ hive-c0re/src/priv_client.rs | 11 +++++++++++ hive-priv/src/main.rs | 22 ++++++++++++++++++++++ hive-sh4re/src/priv_proto.rs | 10 ++++++++++ 4 files changed, 52 insertions(+) diff --git a/hive-c0re/src/matrix.rs b/hive-c0re/src/matrix.rs index 0f7b54d1..e55a8605 100644 --- a/hive-c0re/src/matrix.rs +++ b/hive-c0re/src/matrix.rs @@ -697,6 +697,15 @@ pub async fn ensure_user_for( .await .with_context(|| format!("matrix: write matrix-token for {name} via hive-priv"))?; tracing::info!(%name, "matrix: provisioned access token"); + + // Kick the daemon so it picks up the new token without waiting for a + // full container restart — see docs/matrix.md::Provisioning flow. + if let Err(e) = crate::priv_client::restart_matrix_daemon(name).await { + tracing::warn!(%name, error = ?e, "matrix: could not restart hive-matrix-daemon (token written; daemon will reload on next container start)"); + } else { + tracing::info!(%name, "matrix: restarted hive-matrix-daemon to pick up new token"); + } + Ok(()) } diff --git a/hive-c0re/src/priv_client.rs b/hive-c0re/src/priv_client.rs index d49c920c..0556bfb8 100644 --- a/hive-c0re/src/priv_client.rs +++ b/hive-c0re/src/priv_client.rs @@ -280,6 +280,17 @@ pub async fn write_agent_matrix_token(agent_name: &str, token: &str) -> Result<( .await?) } +/// Restart `hive-matrix-daemon.service` inside an agent container via +/// `systemctl --machine=h- restart hive-matrix-daemon.service`. +/// Non-fatal: callers should handle errors gracefully — if the container is +/// not running the restart will fail (the unit starts naturally on next boot). +pub async fn restart_matrix_daemon(agent_name: &str) -> Result<()> { + ok(call(&PrivRequest::RestartMatrixDaemon { + agent_name: agent_name.to_owned(), + }) + .await?) +} + fn check(resp: PrivResponse) -> Result<(String, String)> { if resp.ok { Ok((resp.stdout, resp.stderr)) diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index 4ef47aad..71c7e6e2 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -337,6 +337,28 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String, validate_agent_name(agent_name)?; write_agent_state_file(agent_name, "matrix-token", &format!("{token}\n")) } + + PrivRequest::RestartMatrixDaemon { ref agent_name } => { + validate_agent_name(agent_name)?; + let machine = format!("--machine=h-{agent_name}"); + let unit = "hive-matrix-daemon.service"; + let out = Command::new("systemctl") + .args([&machine, "restart", unit]) + .output() + .await + .with_context(|| format!("systemctl restart {unit} in container h-{agent_name}"))?; + if !out.status.success() { + bail!( + "systemctl restart {unit} in h-{agent_name} exited {}: {}", + out.status, + String::from_utf8_lossy(&out.stderr).trim() + ); + } + Ok(( + String::from_utf8_lossy(&out.stdout).into_owned(), + String::from_utf8_lossy(&out.stderr).into_owned(), + )) + } } } diff --git a/hive-sh4re/src/priv_proto.rs b/hive-sh4re/src/priv_proto.rs index 631225e8..39ccc4f9 100644 --- a/hive-sh4re/src/priv_proto.rs +++ b/hive-sh4re/src/priv_proto.rs @@ -189,6 +189,7 @@ pub enum PrivRequest { DaemonReload, /// Synchronise the nginx unit inside the `hive-gateway` container. + /// /// hive-priv queries `ActiveState` and dispatches: /// - `active` → `systemctl reload nginx` (SIGHUP, zero-downtime) /// - `failed` → `systemctl reset-failed nginx` + `systemctl start nginx` @@ -254,6 +255,15 @@ pub enum PrivRequest { /// Token value. hive-priv appends a trailing newline before writing. token: String, }, + + /// Restart `hive-matrix-daemon.service` inside an agent container via + /// `systemctl --machine=h- restart hive-matrix-daemon.service`. + /// Used by hive-c0re to kick the daemon after a successful token write + /// so it picks up the new credential without a full container restart. + RestartMatrixDaemon { + /// Logical agent name (validated by `validate_agent_name`). + agent_name: String, + }, } /// Response from the privileged helper.