[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:
Joshua Ferguson 2024-06-25 10:40:17 -04:00 committed by Ashley Wulber
parent b096107f81
commit b4561cfc71
4 changed files with 47 additions and 31 deletions

9
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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
);
});
}
}
} }

View file

@ -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(),
) )