[squash] systemd scopes support
changes for code review [squash] systemd scopes support (doesn't compile) zbus connection seems to be missing sync I think I got it scoping works again switched to a different method of systemd detection and cleaned up dead code switch launchpad dependency back to main and removed unused imports
This commit is contained in:
parent
b096107f81
commit
b4561cfc71
4 changed files with 47 additions and 31 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -685,12 +685,13 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "launch-pad"
|
name = "launch-pad"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/launch-pad#1596d1b83ae5d5c804a69146f89718776022b46b"
|
source = "git+https://github.com/pop-os/launch-pad#a267ea1fe5f80b30f82b8ec557a88b23fa4ebdc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"nix 0.26.2",
|
"nix 0.26.2",
|
||||||
"rand",
|
"rand",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
|
"sync_wrapper",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
|
@ -1255,6 +1256,12 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ color-eyre = "0.6"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
launch-pad = { git = "https://github.com/pop-os/launch-pad" }
|
launch-pad = { git = "https://github.com/pop-os/launch-pad" }
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
#launch-pad = { path = "../../../launch-pad" }
|
#launch-pad = { git = "https://github.com/pop-os/launch-pad", branch = "remove-sync-bounds" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log-panics = { version = "2", features = ["with-backtrace"] }
|
log-panics = { version = "2", features = ["with-backtrace"] }
|
||||||
rustix = "0.38"
|
rustix = "0.38"
|
||||||
|
|
|
||||||
46
src/main.rs
46
src/main.rs
|
|
@ -9,6 +9,7 @@ mod service;
|
||||||
mod systemd;
|
mod systemd;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
os::fd::{AsRawFd, OwnedFd},
|
os::fd::{AsRawFd, OwnedFd},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
@ -331,7 +332,7 @@ async fn start(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_component(
|
async fn start_component(
|
||||||
cmd: &str,
|
cmd: impl Into<Cow<'static, str>>,
|
||||||
span: tracing::Span,
|
span: tracing::Span,
|
||||||
process_manager: &ProcessManager,
|
process_manager: &ProcessManager,
|
||||||
env_vars: &[(String, String)],
|
env_vars: &[(String, String)],
|
||||||
|
|
@ -344,7 +345,9 @@ async fn start_component(
|
||||||
let socket_tx_clone = socket_tx.clone();
|
let socket_tx_clone = socket_tx.clone();
|
||||||
let stdout_span = span.clone();
|
let stdout_span = span.clone();
|
||||||
let stderr_span = span.clone();
|
let stderr_span = span.clone();
|
||||||
let cmd_clone = cmd.to_string();
|
let cmd = cmd.into();
|
||||||
|
let cmd_clone = cmd.clone();
|
||||||
|
|
||||||
let (mut fds, extra_fd_env, mut streams): (Vec<_>, Vec<_>, Vec<_>) =
|
let (mut fds, extra_fd_env, mut streams): (Vec<_>, Vec<_>, Vec<_>) =
|
||||||
itertools::multiunzip(extra_fds);
|
itertools::multiunzip(extra_fds);
|
||||||
for kv in &extra_fd_env {
|
for kv in &extra_fd_env {
|
||||||
|
|
@ -357,10 +360,10 @@ async fn start_component(
|
||||||
}
|
}
|
||||||
let (extra_fd_env, _): (Vec<_>, Vec<_>) = extra_fd_env.into_iter().unzip();
|
let (extra_fd_env, _): (Vec<_>, Vec<_>) = extra_fd_env.into_iter().unzip();
|
||||||
fds.push(fd);
|
fds.push(fd);
|
||||||
let key = process_manager
|
process_manager
|
||||||
.start(
|
.start(
|
||||||
Process::new()
|
Process::new()
|
||||||
.with_executable(cmd)
|
.with_executable(cmd.clone())
|
||||||
.with_env(env_vars.iter().cloned())
|
.with_env(env_vars.iter().cloned())
|
||||||
.with_on_stdout(move |_, _, line| {
|
.with_on_stdout(move |_, _, line| {
|
||||||
let stdout_span = stdout_span.clone();
|
let stdout_span = stdout_span.clone();
|
||||||
|
|
@ -376,6 +379,25 @@ async fn start_component(
|
||||||
}
|
}
|
||||||
.instrument(stderr_span)
|
.instrument(stderr_span)
|
||||||
})
|
})
|
||||||
|
.with_on_start(move |pman, pkey, _will_restart| {
|
||||||
|
#[cfg(feature = "systemd")]
|
||||||
|
{
|
||||||
|
async move {
|
||||||
|
if *is_systemd_used() {
|
||||||
|
if let Ok((innr_cmd, Some(pid))) = pman.get_exe_and_pid(pkey).await
|
||||||
|
{
|
||||||
|
if let Err(err) = spawn_scope(innr_cmd.clone(), vec![pid]).await
|
||||||
|
{
|
||||||
|
warn!(
|
||||||
|
"Failed to spawn scope for {}. Creating transient unit failed with {}",
|
||||||
|
innr_cmd, err
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.with_on_exit(move |mut pman, key, err_code, will_restart| {
|
.with_on_exit(move |mut pman, key, err_code, will_restart| {
|
||||||
if let Some(err) = err_code {
|
if let Some(err) = err_code {
|
||||||
error!("{cmd_clone} exited with error {}", err.to_string());
|
error!("{cmd_clone} exited with error {}", err.to_string());
|
||||||
|
|
@ -415,20 +437,4 @@ async fn start_component(
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|_| panic!("failed to start {}", cmd));
|
.unwrap_or_else(|_| panic!("failed to start {}", cmd));
|
||||||
#[cfg(feature = "systemd")]
|
|
||||||
{
|
|
||||||
if *is_systemd_used() {
|
|
||||||
//currently pid is optional hence the double unwrap
|
|
||||||
let pids = process_manager.get_pid(key).await.unwrap().unwrap();
|
|
||||||
//spawn_scope takes a vec of pids in case we want to spawn a scope for multiple processes
|
|
||||||
spawn_scope(cmd.to_string(), vec![pids])
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
warn!(
|
|
||||||
"Failed to spawn scope for {}. Creating transient unit failed with {}",
|
|
||||||
cmd, err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,18 +33,21 @@ pub fn stop_systemd_target() {
|
||||||
///Determine if systemd is used as the init system. This should work on all linux distributions.
|
///Determine if systemd is used as the init system. This should work on all linux distributions.
|
||||||
pub fn is_systemd_used() -> &'static bool {
|
pub fn is_systemd_used() -> &'static bool {
|
||||||
static IS_SYSTEMD_USED: OnceLock<bool> = OnceLock::new();
|
static IS_SYSTEMD_USED: OnceLock<bool> = OnceLock::new();
|
||||||
IS_SYSTEMD_USED.get_or_init(
|
IS_SYSTEMD_USED.get_or_init(|| {
|
||||||
|| match Command::new("readlink").args(&["/sbin/init"]).output() {
|
match Command::new("ls").args(["/run/systemd/system"]).output() {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
let init = String::from_utf8_lossy(&output.stdout);
|
if output.status.success() {
|
||||||
init.trim().ends_with("/lib/systemd/systemd")
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
warn!("unable to check if systemd is used: {}", error);
|
warn!("unable to check if systemd is used: {}", error);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "systemd")]
|
#[cfg(feature = "systemd")]
|
||||||
|
|
@ -53,8 +56,8 @@ pub async fn spawn_scope(mut command: String, pids: Vec<u32>) -> Result<(), zbus
|
||||||
let connection = Connection::session().await?;
|
let connection = Connection::session().await?;
|
||||||
let systemd_manager = SystemdManagerProxy::new(&connection).await?;
|
let systemd_manager = SystemdManagerProxy::new(&connection).await?;
|
||||||
let pids = OwnedValue::try_from(Array::from(pids)).unwrap();
|
let pids = OwnedValue::try_from(Array::from(pids)).unwrap();
|
||||||
let properties = vec![(String::from("PIDs"), pids)];
|
let properties: Vec<(String, OwnedValue)> = vec![(String::from("PIDs"), pids)];
|
||||||
if command.starts_with("/") {
|
if command.starts_with('/') {
|
||||||
// use the last component of the path as the unit name
|
// use the last component of the path as the unit name
|
||||||
command = command.rsplit('/').next().unwrap().to_string();
|
command = command.rsplit('/').next().unwrap().to_string();
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +65,7 @@ pub async fn spawn_scope(mut command: String, pids: Vec<u32>) -> Result<(), zbus
|
||||||
systemd_manager
|
systemd_manager
|
||||||
.start_transient_unit(
|
.start_transient_unit(
|
||||||
scope_name.to_string(),
|
scope_name.to_string(),
|
||||||
String::from("fail"),
|
String::from("replace"),
|
||||||
properties,
|
properties,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue