From f751c4495f9dda4964c99790c2687a89910aa0e1 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 8 Jun 2026 20:26:15 +0200 Subject: [PATCH] refactor(#1474): group journalctl read args into a journalquery struct --- hive-c0re/src/agent_server.rs | 17 +++++----- hive-c0re/src/dashboard.rs | 15 ++++----- hive-c0re/src/lifecycle.rs | 12 +++---- hive-c0re/src/manager_server.rs | 12 +++---- hive-c0re/src/priv_client.rs | 21 ++---------- hive-priv/src/main.rs | 57 ++++++++----------------------- hive-sh4re/src/priv_proto.rs | 59 ++++++++++++++++++++------------- 7 files changed, 77 insertions(+), 116 deletions(-) diff --git a/hive-c0re/src/agent_server.rs b/hive-c0re/src/agent_server.rs index 4e68a2c7..80a58e6e 100644 --- a/hive-c0re/src/agent_server.rs +++ b/hive-c0re/src/agent_server.rs @@ -579,14 +579,15 @@ pub async fn dispatch_host_journal( tracing::info!(%agent, machine = %c, %n, "get_host_journal (container)"); return match crate::priv_client::read_container_journal( c, - n, - false, - hive_sh4re::priv_proto::JournalOutput::Short, - unit.clone(), - priority.as_ref().map(|p| p.as_str().to_owned()), - grep.clone(), - since.clone(), - until.clone(), + hive_sh4re::priv_proto::JournalQuery { + lines: n, + unit: unit.clone(), + priority: priority.as_ref().map(|p| p.as_str().to_owned()), + grep: grep.clone(), + since: since.clone(), + until: until.clone(), + ..Default::default() + }, ) .await { diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index 36e463a3..f03897de 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -1225,14 +1225,13 @@ async fn get_journal( }; match crate::priv_client::read_container_journal( &prefixed, - lines, - true, - hive_sh4re::priv_proto::JournalOutput::ShortIso, - unit, - None, - None, - None, - None, + hive_sh4re::priv_proto::JournalQuery { + lines, + boot: true, + output: hive_sh4re::priv_proto::JournalOutput::ShortIso, + unit, + ..Default::default() + }, ) .await { diff --git a/hive-c0re/src/lifecycle.rs b/hive-c0re/src/lifecycle.rs index b3dbe8bd..e3edb85a 100644 --- a/hive-c0re/src/lifecycle.rs +++ b/hive-c0re/src/lifecycle.rs @@ -1450,14 +1450,10 @@ async fn container_journal_tail(container: &str) -> String { // is delegated to hive-priv (hive-c0re itself runs unprivileged). let res = crate::priv_client::read_container_journal( container, - 40, - false, - hive_sh4re::priv_proto::JournalOutput::Short, - None, - None, - None, - None, - None, + hive_sh4re::priv_proto::JournalQuery { + lines: 40, + ..Default::default() + }, ) .await; match res { diff --git a/hive-c0re/src/manager_server.rs b/hive-c0re/src/manager_server.rs index a8d5158b..1e13f378 100644 --- a/hive-c0re/src/manager_server.rs +++ b/hive-c0re/src/manager_server.rs @@ -233,14 +233,10 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc) -> ManagerResp tracing::info!(%agent, %machine, %n, "manager: get_logs"); match crate::priv_client::read_container_journal( &machine, - n, - false, - hive_sh4re::priv_proto::JournalOutput::Short, - None, - None, - None, - None, - None, + hive_sh4re::priv_proto::JournalQuery { + lines: n, + ..Default::default() + }, ) .await { diff --git a/hive-c0re/src/priv_client.rs b/hive-c0re/src/priv_client.rs index 9ff74cca..bc66b286 100644 --- a/hive-c0re/src/priv_client.rs +++ b/hive-c0re/src/priv_client.rs @@ -8,7 +8,7 @@ use anyhow::{Context as _, Result, bail}; use hive_sh4re::priv_proto::{ - BindMount, JournalOutput, NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse, + BindMount, JournalQuery, NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse, PrivStream, }; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; @@ -162,29 +162,14 @@ pub async fn list_containers() -> Result { /// Read a container's journal via the root helper (`journalctl -M`). /// Returns `(stdout, stderr)`; a non-zero journalctl exit is reported in /// `stderr` rather than as an `Err`, so callers can surface either. -#[allow(clippy::too_many_arguments)] pub async fn read_container_journal( container: &str, - lines: u32, - boot: bool, - output: JournalOutput, - unit: Option, - priority: Option, - grep: Option, - since: Option, - until: Option, + query: JournalQuery, ) -> Result<(String, String)> { check( call(&PrivRequest::ReadContainerJournal { container: container.to_owned(), - lines, - boot, - output, - unit, - priority, - grep, - since, - until, + query, }) .await?, ) diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index 49ba82a3..cdfcb3a4 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -21,7 +21,7 @@ use std::path::{Path, PathBuf}; use anyhow::{Context as _, Result, bail}; use hive_sh4re::priv_proto::{ - AGENT_PREFIX, AGENT_STATE_ROOT, BindMount, JournalOutput, MANAGER_NAME, META_DIR, + AGENT_PREFIX, AGENT_STATE_ROOT, BindMount, JournalQuery, MANAGER_NAME, META_DIR, NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse, PrivStream, PrivStreamLine, SIBLING_CONTAINERS, }; @@ -222,28 +222,10 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String, PrivRequest::ReadContainerJournal { ref container, - lines, - boot, - output, - ref unit, - ref priority, - ref grep, - ref since, - ref until, + ref query, } => { validate_container_system_name(container)?; - read_container_journal( - container, - lines, - boot, - output, - unit.as_deref(), - priority.as_deref(), - grep.as_deref(), - since.as_deref(), - until.as_deref(), - ) - .await + read_container_journal(container, query).await } PrivRequest::WriteNspawnFlags { @@ -606,46 +588,35 @@ async fn container_run_streaming( /// hard error — journalctl's own diagnostic (folded into `stderr` with /// the exit status) is what the caller surfaces to the operator, so the /// helper never bails. -#[allow(clippy::too_many_arguments)] -async fn read_container_journal( - container: &str, - lines: u32, - boot: bool, - output: JournalOutput, - unit: Option<&str>, - priority: Option<&str>, - grep: Option<&str>, - since: Option<&str>, - until: Option<&str>, -) -> Result<(String, String)> { +async fn read_container_journal(container: &str, query: &JournalQuery) -> Result<(String, String)> { let mut args: Vec = vec![ "-M".to_owned(), container.to_owned(), "--no-pager".to_owned(), - format!("--output={}", output.as_journalctl()), + format!("--output={}", query.output.as_journalctl()), "-n".to_owned(), - lines.to_string(), + query.lines.to_string(), ]; - if boot { + if query.boot { args.push("-b".to_owned()); } - if let Some(u) = unit { + if let Some(u) = &query.unit { args.push("-u".to_owned()); - args.push(u.to_owned()); + args.push(u.clone()); } - if let Some(p) = priority { + if let Some(p) = &query.priority { args.push("-p".to_owned()); - args.push(p.to_owned()); + args.push(p.clone()); } // `--grep=`/`--since=`/`--until=` use the `=`-joined form so a value // can never be parsed as a separate journalctl flag. - if let Some(g) = grep { + if let Some(g) = &query.grep { args.push(format!("--grep={g}")); } - if let Some(s) = since { + if let Some(s) = &query.since { args.push(format!("--since={s}")); } - if let Some(u) = until { + if let Some(u) = &query.until { args.push(format!("--until={u}")); } let out = Command::new("journalctl") diff --git a/hive-sh4re/src/priv_proto.rs b/hive-sh4re/src/priv_proto.rs index 9fa39b6a..1b3c5a14 100644 --- a/hive-sh4re/src/priv_proto.rs +++ b/hive-sh4re/src/priv_proto.rs @@ -52,6 +52,40 @@ impl JournalOutput { } } +/// journalctl knobs for `ReadContainerJournal`. Grouped into one value so +/// the read-journal call chain (`priv_client::read_container_journal` → +/// hive-priv's executor) and its several hive-c0re callers pass a single +/// struct instead of eight positional args that travelled together 1:1. +/// `Default` is the common case (last N lines, short format, no filters); +/// callers fill `lines` and override only the knobs they need via +/// `..Default::default()`. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct JournalQuery { + /// `-n `. + pub lines: u32, + /// `-b` — restrict to the current boot. + #[serde(default)] + pub boot: bool, + /// `--output=<...>`. + #[serde(default)] + pub output: JournalOutput, + /// `-u `. + #[serde(default)] + pub unit: Option, + /// `-p `. + #[serde(default)] + pub priority: Option, + /// `--grep=`. + #[serde(default)] + pub grep: Option, + /// `--since=`. + #[serde(default)] + pub since: Option, + /// `--until=`. + #[serde(default)] + pub until: Option, +} + /// One bind-mount entry for `WriteNspawnFlags`. /// hive-priv constructs `--bind=:` (or `--bind-ro=`) /// and validates both paths before writing the conf file. @@ -132,29 +166,8 @@ pub enum PrivRequest { ReadContainerJournal { /// System container name (`h-` or a sibling service). container: String, - /// `-n `. - lines: u32, - /// `-b` — restrict to the current boot. - #[serde(default)] - boot: bool, - /// `--output=<...>`. - #[serde(default)] - output: JournalOutput, - /// `-u `. - #[serde(default)] - unit: Option, - /// `-p `. - #[serde(default)] - priority: Option, - /// `--grep=`. - #[serde(default)] - grep: Option, - /// `--since=`. - #[serde(default)] - since: Option, - /// `--until=`. - #[serde(default)] - until: Option, + /// journalctl knobs (see [`JournalQuery`]). + query: JournalQuery, }, // --- Config file writes ---