refactor(#1474): group journalctl read args into a journalquery struct
This commit is contained in:
parent
98660d134a
commit
f751c4495f
7 changed files with 77 additions and 116 deletions
|
|
@ -579,14 +579,15 @@ pub async fn dispatch_host_journal(
|
||||||
tracing::info!(%agent, machine = %c, %n, "get_host_journal (container)");
|
tracing::info!(%agent, machine = %c, %n, "get_host_journal (container)");
|
||||||
return match crate::priv_client::read_container_journal(
|
return match crate::priv_client::read_container_journal(
|
||||||
c,
|
c,
|
||||||
n,
|
hive_sh4re::priv_proto::JournalQuery {
|
||||||
false,
|
lines: n,
|
||||||
hive_sh4re::priv_proto::JournalOutput::Short,
|
unit: unit.clone(),
|
||||||
unit.clone(),
|
priority: priority.as_ref().map(|p| p.as_str().to_owned()),
|
||||||
priority.as_ref().map(|p| p.as_str().to_owned()),
|
grep: grep.clone(),
|
||||||
grep.clone(),
|
since: since.clone(),
|
||||||
since.clone(),
|
until: until.clone(),
|
||||||
until.clone(),
|
..Default::default()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1225,14 +1225,13 @@ async fn get_journal(
|
||||||
};
|
};
|
||||||
match crate::priv_client::read_container_journal(
|
match crate::priv_client::read_container_journal(
|
||||||
&prefixed,
|
&prefixed,
|
||||||
lines,
|
hive_sh4re::priv_proto::JournalQuery {
|
||||||
true,
|
lines,
|
||||||
hive_sh4re::priv_proto::JournalOutput::ShortIso,
|
boot: true,
|
||||||
unit,
|
output: hive_sh4re::priv_proto::JournalOutput::ShortIso,
|
||||||
None,
|
unit,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
},
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1450,14 +1450,10 @@ async fn container_journal_tail(container: &str) -> String {
|
||||||
// is delegated to hive-priv (hive-c0re itself runs unprivileged).
|
// is delegated to hive-priv (hive-c0re itself runs unprivileged).
|
||||||
let res = crate::priv_client::read_container_journal(
|
let res = crate::priv_client::read_container_journal(
|
||||||
container,
|
container,
|
||||||
40,
|
hive_sh4re::priv_proto::JournalQuery {
|
||||||
false,
|
lines: 40,
|
||||||
hive_sh4re::priv_proto::JournalOutput::Short,
|
..Default::default()
|
||||||
None,
|
},
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
match res {
|
match res {
|
||||||
|
|
|
||||||
|
|
@ -233,14 +233,10 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
|
||||||
tracing::info!(%agent, %machine, %n, "manager: get_logs");
|
tracing::info!(%agent, %machine, %n, "manager: get_logs");
|
||||||
match crate::priv_client::read_container_journal(
|
match crate::priv_client::read_container_journal(
|
||||||
&machine,
|
&machine,
|
||||||
n,
|
hive_sh4re::priv_proto::JournalQuery {
|
||||||
false,
|
lines: n,
|
||||||
hive_sh4re::priv_proto::JournalOutput::Short,
|
..Default::default()
|
||||||
None,
|
},
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use anyhow::{Context as _, Result, bail};
|
use anyhow::{Context as _, Result, bail};
|
||||||
use hive_sh4re::priv_proto::{
|
use hive_sh4re::priv_proto::{
|
||||||
BindMount, JournalOutput, NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse,
|
BindMount, JournalQuery, NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse,
|
||||||
PrivStream,
|
PrivStream,
|
||||||
};
|
};
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||||
|
|
@ -162,29 +162,14 @@ pub async fn list_containers() -> Result<String> {
|
||||||
/// Read a container's journal via the root helper (`journalctl -M`).
|
/// Read a container's journal via the root helper (`journalctl -M`).
|
||||||
/// Returns `(stdout, stderr)`; a non-zero journalctl exit is reported in
|
/// Returns `(stdout, stderr)`; a non-zero journalctl exit is reported in
|
||||||
/// `stderr` rather than as an `Err`, so callers can surface either.
|
/// `stderr` rather than as an `Err`, so callers can surface either.
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub async fn read_container_journal(
|
pub async fn read_container_journal(
|
||||||
container: &str,
|
container: &str,
|
||||||
lines: u32,
|
query: JournalQuery,
|
||||||
boot: bool,
|
|
||||||
output: JournalOutput,
|
|
||||||
unit: Option<String>,
|
|
||||||
priority: Option<String>,
|
|
||||||
grep: Option<String>,
|
|
||||||
since: Option<String>,
|
|
||||||
until: Option<String>,
|
|
||||||
) -> Result<(String, String)> {
|
) -> Result<(String, String)> {
|
||||||
check(
|
check(
|
||||||
call(&PrivRequest::ReadContainerJournal {
|
call(&PrivRequest::ReadContainerJournal {
|
||||||
container: container.to_owned(),
|
container: container.to_owned(),
|
||||||
lines,
|
query,
|
||||||
boot,
|
|
||||||
output,
|
|
||||||
unit,
|
|
||||||
priority,
|
|
||||||
grep,
|
|
||||||
since,
|
|
||||||
until,
|
|
||||||
})
|
})
|
||||||
.await?,
|
.await?,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context as _, Result, bail};
|
use anyhow::{Context as _, Result, bail};
|
||||||
use hive_sh4re::priv_proto::{
|
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,
|
NetworkIsolation, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse, PrivStream, PrivStreamLine,
|
||||||
SIBLING_CONTAINERS,
|
SIBLING_CONTAINERS,
|
||||||
};
|
};
|
||||||
|
|
@ -222,28 +222,10 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String,
|
||||||
|
|
||||||
PrivRequest::ReadContainerJournal {
|
PrivRequest::ReadContainerJournal {
|
||||||
ref container,
|
ref container,
|
||||||
lines,
|
ref query,
|
||||||
boot,
|
|
||||||
output,
|
|
||||||
ref unit,
|
|
||||||
ref priority,
|
|
||||||
ref grep,
|
|
||||||
ref since,
|
|
||||||
ref until,
|
|
||||||
} => {
|
} => {
|
||||||
validate_container_system_name(container)?;
|
validate_container_system_name(container)?;
|
||||||
read_container_journal(
|
read_container_journal(container, query).await
|
||||||
container,
|
|
||||||
lines,
|
|
||||||
boot,
|
|
||||||
output,
|
|
||||||
unit.as_deref(),
|
|
||||||
priority.as_deref(),
|
|
||||||
grep.as_deref(),
|
|
||||||
since.as_deref(),
|
|
||||||
until.as_deref(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivRequest::WriteNspawnFlags {
|
PrivRequest::WriteNspawnFlags {
|
||||||
|
|
@ -606,46 +588,35 @@ async fn container_run_streaming(
|
||||||
/// hard error — journalctl's own diagnostic (folded into `stderr` with
|
/// hard error — journalctl's own diagnostic (folded into `stderr` with
|
||||||
/// the exit status) is what the caller surfaces to the operator, so the
|
/// the exit status) is what the caller surfaces to the operator, so the
|
||||||
/// helper never bails.
|
/// helper never bails.
|
||||||
#[allow(clippy::too_many_arguments)]
|
async fn read_container_journal(container: &str, query: &JournalQuery) -> Result<(String, String)> {
|
||||||
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)> {
|
|
||||||
let mut args: Vec<String> = vec![
|
let mut args: Vec<String> = vec![
|
||||||
"-M".to_owned(),
|
"-M".to_owned(),
|
||||||
container.to_owned(),
|
container.to_owned(),
|
||||||
"--no-pager".to_owned(),
|
"--no-pager".to_owned(),
|
||||||
format!("--output={}", output.as_journalctl()),
|
format!("--output={}", query.output.as_journalctl()),
|
||||||
"-n".to_owned(),
|
"-n".to_owned(),
|
||||||
lines.to_string(),
|
query.lines.to_string(),
|
||||||
];
|
];
|
||||||
if boot {
|
if query.boot {
|
||||||
args.push("-b".to_owned());
|
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.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.to_owned());
|
args.push(p.clone());
|
||||||
}
|
}
|
||||||
// `--grep=`/`--since=`/`--until=` use the `=`-joined form so a value
|
// `--grep=`/`--since=`/`--until=` use the `=`-joined form so a value
|
||||||
// can never be parsed as a separate journalctl flag.
|
// 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}"));
|
args.push(format!("--grep={g}"));
|
||||||
}
|
}
|
||||||
if let Some(s) = since {
|
if let Some(s) = &query.since {
|
||||||
args.push(format!("--since={s}"));
|
args.push(format!("--since={s}"));
|
||||||
}
|
}
|
||||||
if let Some(u) = until {
|
if let Some(u) = &query.until {
|
||||||
args.push(format!("--until={u}"));
|
args.push(format!("--until={u}"));
|
||||||
}
|
}
|
||||||
let out = Command::new("journalctl")
|
let out = Command::new("journalctl")
|
||||||
|
|
|
||||||
|
|
@ -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 <lines>`.
|
||||||
|
pub lines: u32,
|
||||||
|
/// `-b` — restrict to the current boot.
|
||||||
|
#[serde(default)]
|
||||||
|
pub boot: bool,
|
||||||
|
/// `--output=<...>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub output: JournalOutput,
|
||||||
|
/// `-u <unit>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub unit: Option<String>,
|
||||||
|
/// `-p <priority>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub priority: Option<String>,
|
||||||
|
/// `--grep=<regex>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub grep: Option<String>,
|
||||||
|
/// `--since=<ts>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub since: Option<String>,
|
||||||
|
/// `--until=<ts>`.
|
||||||
|
#[serde(default)]
|
||||||
|
pub until: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// One bind-mount entry for `WriteNspawnFlags`.
|
/// One bind-mount entry for `WriteNspawnFlags`.
|
||||||
/// hive-priv constructs `--bind=<host_path>:<container_path>` (or `--bind-ro=`)
|
/// hive-priv constructs `--bind=<host_path>:<container_path>` (or `--bind-ro=`)
|
||||||
/// and validates both paths before writing the conf file.
|
/// and validates both paths before writing the conf file.
|
||||||
|
|
@ -132,29 +166,8 @@ pub enum PrivRequest {
|
||||||
ReadContainerJournal {
|
ReadContainerJournal {
|
||||||
/// System container name (`h-<agent>` or a sibling service).
|
/// System container name (`h-<agent>` or a sibling service).
|
||||||
container: String,
|
container: String,
|
||||||
/// `-n <lines>`.
|
/// journalctl knobs (see [`JournalQuery`]).
|
||||||
lines: u32,
|
query: JournalQuery,
|
||||||
/// `-b` — restrict to the current boot.
|
|
||||||
#[serde(default)]
|
|
||||||
boot: bool,
|
|
||||||
/// `--output=<...>`.
|
|
||||||
#[serde(default)]
|
|
||||||
output: JournalOutput,
|
|
||||||
/// `-u <unit>`.
|
|
||||||
#[serde(default)]
|
|
||||||
unit: Option<String>,
|
|
||||||
/// `-p <priority>`.
|
|
||||||
#[serde(default)]
|
|
||||||
priority: Option<String>,
|
|
||||||
/// `--grep=<regex>`.
|
|
||||||
#[serde(default)]
|
|
||||||
grep: Option<String>,
|
|
||||||
/// `--since=<ts>`.
|
|
||||||
#[serde(default)]
|
|
||||||
since: Option<String>,
|
|
||||||
/// `--until=<ts>`.
|
|
||||||
#[serde(default)]
|
|
||||||
until: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// --- Config file writes ---
|
// --- Config file writes ---
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue