systemd: container/remote restart, permanent-error backoff, recursive section via loader (step 6)
This commit is contained in:
parent
5676b1ac62
commit
dfa3840d97
6 changed files with 118 additions and 56 deletions
|
|
@ -60,7 +60,13 @@ pub mod qobject {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_name = "restartUnit"]
|
||||
fn restart_unit(self: Pin<&mut Self>, name: QString, scope: QString, machine: QString);
|
||||
fn restart_unit(
|
||||
self: Pin<&mut Self>,
|
||||
name: QString,
|
||||
scope: QString,
|
||||
host: QString,
|
||||
machine: QString,
|
||||
);
|
||||
}
|
||||
|
||||
impl cxx_qt::Initialize for SystemdService {}
|
||||
|
|
@ -527,13 +533,14 @@ impl qobject::SystemdService {
|
|||
let applet_open = self.as_ref().rust().applet_open;
|
||||
if applet_open {
|
||||
for target in &want_targets {
|
||||
let prev_last_seen = self
|
||||
.as_ref()
|
||||
.rust()
|
||||
.remote_cache
|
||||
.get(target)
|
||||
.map(|m| m.last_seen)
|
||||
.unwrap_or(0);
|
||||
let prev = self.as_ref().rust().remote_cache.get(target).cloned();
|
||||
let prev_last_seen = prev.as_ref().map(|m| m.last_seen).unwrap_or(0);
|
||||
// Backoff: don't retry hosts with a permanent error until
|
||||
// either the config changes (cache cleared) or the user
|
||||
// restarts the shell. Reuse the cached entry verbatim.
|
||||
if prev.as_ref().is_some_and(|m| m.error_kind == "permanent") {
|
||||
continue;
|
||||
}
|
||||
let entry = match fetch_via_busctl(target, &["--host", target], false, "") {
|
||||
Ok(mut m) => {
|
||||
// Enumerate + fetch remote nspawn containers via the
|
||||
|
|
@ -599,28 +606,70 @@ impl qobject::SystemdService {
|
|||
}
|
||||
}
|
||||
|
||||
fn restart_unit(self: Pin<&mut Self>, name: QString, scope: QString, machine: QString) {
|
||||
fn restart_unit(
|
||||
self: Pin<&mut Self>,
|
||||
name: QString,
|
||||
scope: QString,
|
||||
host: QString,
|
||||
machine: QString,
|
||||
) {
|
||||
let name = name.to_string();
|
||||
let scope = scope.to_string();
|
||||
let host = host.to_string();
|
||||
let machine = machine.to_string();
|
||||
let _ = self;
|
||||
rt().block_on(async move {
|
||||
// Local-only restart for now. Container/remote restart is TODO.
|
||||
if !machine.is_empty() {
|
||||
tracing::warn!(target: "nova_plugin", machine = %machine, "container/remote restart not yet implemented");
|
||||
return;
|
||||
|
||||
// Local + system or user scope: native zbus, supports user manager too.
|
||||
if host.is_empty() && machine.is_empty() {
|
||||
rt().block_on(async move {
|
||||
let conn = match scope.as_str() {
|
||||
"user" => Connection::session().await,
|
||||
_ => Connection::system().await,
|
||||
};
|
||||
let Ok(conn) = conn else { return };
|
||||
let Ok(mgr) = SystemdManagerProxy::new(&conn).await else {
|
||||
return;
|
||||
};
|
||||
if let Err(e) = mgr.restart_unit(&name, "replace").await {
|
||||
tracing::warn!(target: "nova_plugin", unit = %name, error = %e, "restart_unit failed");
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Container or remote: spawn busctl with the matching prefix flags.
|
||||
// (busctl doesn't have a concept of `--user` over remote; we restart
|
||||
// system units only for non-local hosts.)
|
||||
let mut prefix: Vec<String> = Vec::new();
|
||||
if !host.is_empty() {
|
||||
prefix.push("--host".into());
|
||||
prefix.push(host.clone());
|
||||
}
|
||||
if !machine.is_empty() {
|
||||
prefix.push("--machine".into());
|
||||
prefix.push(machine.clone());
|
||||
}
|
||||
let mut args: Vec<&str> = prefix.iter().map(String::as_str).collect();
|
||||
args.extend([
|
||||
"call",
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"RestartUnit",
|
||||
"ss",
|
||||
name.as_str(),
|
||||
"replace",
|
||||
]);
|
||||
let out = std::process::Command::new("busctl").args(&args).output();
|
||||
match out {
|
||||
Ok(o) if o.status.success() => {}
|
||||
Ok(o) => {
|
||||
let stderr = String::from_utf8_lossy(&o.stderr);
|
||||
tracing::warn!(target: "nova_plugin", unit = %name, host = %host, machine = %machine, error = %stderr, "restart_unit busctl failed");
|
||||
}
|
||||
let conn = match scope.as_str() {
|
||||
"user" => Connection::session().await,
|
||||
_ => Connection::system().await,
|
||||
};
|
||||
let Ok(conn) = conn else { return };
|
||||
let Ok(mgr) = SystemdManagerProxy::new(&conn).await else {
|
||||
return;
|
||||
};
|
||||
if let Err(e) = mgr.restart_unit(&name, "replace").await {
|
||||
tracing::warn!(target: "nova_plugin", unit = %name, error = %e, "restart_unit failed");
|
||||
Err(e) => {
|
||||
tracing::warn!(target: "nova_plugin", unit = %name, error = %e, "restart_unit busctl spawn failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue