diff --git a/Development.md b/Development.md index fdfb29c..07c1f1a 100644 --- a/Development.md +++ b/Development.md @@ -1,212 +1,185 @@ # Testing -All of these tests have been automated in [sanity.rs](./pid1/tests/sanity.rs). +All of these tests have been automated in [`pid1/tests/sanity.rs`](./pid1/tests/sanity.rs). -The `examples` directory contains several programs used for testing this library. +The [`pid1/examples` directory](./pid1/examples) contains several programs used for testing this library. - `simple.rs`: A program that demonstrates the usage of the `pid1-rs` library. - `zombie.rs`: Creates a zombie process. - `sigterm_handler.rs`: A program that has a `SIGTERM` handler and exits upon receiving the signal. - `sigterm_loop.rs`: A buggy program that does not exit on `SIGTERM`. -- `dumb_shell.rs`: An alternative shell for testing, since `bash` - automatically reaps child processes. +- `dumb_shell.rs`: An alternative shell for testing, since `bash` automatically reaps child processes. ## Environment setup - Run the test program via the just recipe: `build-image` - You can get shell access to it via the recipe: `exec-shell` -``` shellsession -❯ just exec-shell -docker exec -it pid1rs sh -/ # ps aux -PID USER TIME COMMAND - 1 root 0:05 /simple - 7 root 0:00 /simple - 8 root 0:00 sh - 14 root 0:00 [date] - 15 root 0:00 ps aux -``` + ```console + $ just exec-shell + + # docker exec -it pid1rs sh + $ ps aux + PID USER TIME COMMAND + 1 root 0:05 /simple + 7 root 0:00 /simple + 8 root 0:00 sh + 15 root 0:00 ps aux + ``` # Tests ## Basic functionality -``` shellsession -❯ just test -... -docker run --name pid1rs -t pid1rstest +```console +$ just test + +# docker run --rm --name pid1rs pid1rstest pid1-rs: Process running as PID 1 -pid1-rs: Process not running as Pid 1: PID 7 In the simple process, going to sleep. Process ID is 7 Args: ["/simple"] -Wed Sep 27 08:29:35 UTC 2023 -Wed Sep 27 08:29:37 UTC 2023 -Wed Sep 27 08:29:39 UTC 2023 +pid1-rs: Reaped PID 7 ``` -Ensure that the process exits with a status code of 0. The test above -confirms the following: +Ensure that the process exits with a status code of `0`. The test above confirms the following: - The `simple` program was executed as PID 1. -- It relaunched itself as PID 7, which then executed various child processes. +- It relaunched itself as PID 7, before exiting and was then reaped. ## Zombie process -``` shellsession -❯ just run-image -... -docker rm pid1rs || exit 0 -pid1rs -docker run --name pid1rs -t pid1rstest /simple --sleep -pid1-rs: Process running as PID 1 -pid1-rs: Process not running as Pid 1: PID 7 -In the simple process, going to sleep. Process ID is 7 -Args: ["/simple", "--sleep"] -Wed Sep 27 08:34:57 UTC 2023 -Wed Sep 27 08:34:59 UTC 2023 -Wed Sep 27 08:35:01 UTC 2023 -Going to sleep 500 seconds -Wed Sep 27 08:35:03 UTC 2023 -``` +1. Run the `run-image` recipe: -While it's executing, open a new shell and run the recipe to create a -zombie process: + ```console + $ just run-image -``` shellsession -❯ just run-zombie -docker exec -t pid1rs zombie -Process ID is 9 -Parent process: going to sleep and exit -``` + # docker run --rm --name pid1rs pid1rstest /simple --sleep 20 + pid1-rs: Process running as PID 1 + In the simple process, going to sleep. Process ID is 7 + Args: ["/simple", "--sleep", "20"] + Going to sleep 20 seconds + ``` -You should see the following logs from the `simple` process, indicating -that a process has been reaped: +2. While it's executing, open a new shell and run the recipe to create a zombie process: -``` shellsession -... -Wed Sep 27 09:40:56 UTC 2023 -Reaped pid: 15 -``` + ```console + $ just run-zombie + + # docker exec pid1rs zombie + Process ID is 9 + Parent process: going to sleep and exit + ``` + +3. You should see the following logs from the `simple` process, indicating that a process has been reaped: + + ```console + Reaped PID: 15 + ``` ## Child Exit code status propagation -- Run the `run-image` recipe: +1. Run the `run-orphans` recipe: -``` shellsession -❯ just run-image -... -docker rm pid1rs || exit 0 -pid1rs -docker run --name pid1rs -t pid1rstest /simple --sleep -pid1-rs: Process running as PID 1 -pid1-rs: Process not running as Pid 1: PID 7 -In the simple process, going to sleep. Process ID is 7 -Args: ["/simple", "--sleep"] -Wed Sep 27 08:34:57 UTC 2023 -Wed Sep 27 08:34:59 UTC 2023 -Wed Sep 27 08:35:01 UTC 2023 -Going to sleep 500 seconds -Wed Sep 27 08:35:03 UTC 2023 -``` + ```console + $ just run-image -- Run the `exec-shell` recipe and perform the test: - -``` shellsession -❯ just exec-shell -docker exec -it pid1rs sh -/ # ps -aux -USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND -root 1 0.0 0.0 996 4 pts/0 Ss+ 12:34 0:00 /simple --sleep -root 7 0.0 0.0 976 4 pts/0 S+ 12:34 0:00 /simple --sleep -root 8 0.0 0.0 0 0 pts/0 Z+ 12:34 0:00 [date] -root 9 0.0 0.0 1672 1048 pts/1 Ss 12:34 0:00 sh -root 14 0.0 0.0 0 0 pts/0 Z+ 12:34 0:00 [date] -root 15 0.0 0.0 0 0 pts/0 Z+ 12:34 0:00 [date] -root 16 0.0 0.0 0 0 pts/0 Z+ 12:34 0:00 [date] -root 17 0.0 0.0 2460 1608 pts/1 R+ 12:34 0:00 ps -aux -/ # kill -12 7 -``` + # docker run --rm --name pid1rs pid1rstest /simple --sleep 20 --create-grandchildren + pid1-rs: Process running as PID 1 + In the simple process, going to sleep. Process ID is 7 + Args: ["/simple", "--sleep", "20", "--create-grandchildren"] + Spawning 3 grandchildren processes that will be orphaned. + Going to sleep 20 seconds + ``` -- Check the logs of the `run-image` recipe to find the exit status - code: +2. Run the `exec-shell` recipe and perform the test: -``` shellsession -... -error: Recipe `run-image` failed on line 21 with exit code 140 -``` + ```console + $ just exec-shell + + # docker exec -it pid1rs sh + $ ps -aux + USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + root 1 0.8 0.0 1048 756 ? Ss 10:11 0:00 /simple --sleep 20 --create-grandchildren + root 7 0.0 0.0 1040 860 ? S 10:11 0:00 /simple --sleep 20 --create-grandchildren + root 8 0.0 0.0 0 0 ? Z 10:11 0:00 [sleep] + root 9 0.0 0.0 0 0 ? Z 10:11 0:00 [sleep] + root 10 0.0 0.0 0 0 ? Z 10:11 0:00 [sleep] + root 11 0.3 0.1 2900 1888 pts/0 Ss 10:11 0:00 sh + root 17 0.0 0.1 7072 3068 pts/0 R+ 10:11 0:00 ps -aux + + $ kill -12 7 + ``` + +3. Check the logs of the `run-orphans` recipe to find the exit status code: -The exit code 140 is correct (128 + 12). + ```console + error: Recipe `run-orphans` failed on line 21 with exit code 140 + ``` -## SIGINT/SIGTERM handling + The exit code 140 is correct (128 + 12). -The goal of this test is to verify that the child process's `SIGTERM` -handler is called if it is defined. +## SIGINT / SIGTERM handling + +The goal of this test is to verify that the child process's `SIGTERM` handler is called if it is defined. These are the signal codes: -- SIGINT: 2 -- SIGTERM: 15 +- `SIGINT`: 2 +- `SIGTERM`: 15 -Execute the recipe `sigterm-test`: +1. Execute the recipe `sigterm-test`: -``` shellsession -❯ just sigterm-test -docker rm pid1rs || exit 0 -pid1rs -docker run --name pid1rs -t pid1rstest sigterm_handler -pid1-rs: Process running as PID 1 -pid1-rs: Process not running as Pid 1: PID 7 -This APP can be killed by SIGTERM (15) -``` + ```console + $ just sigterm-test -Now, send `SIGTERM` to the PID 1 process: + # docker run --rm --name pid1rs pid1rstest sigterm_handler + pid1-rs: Process running as PID 1 + This APP can be killed by SIGTERM (15) + ``` -``` shellsession -❯ just send-sigterm -``` +2. Now, send `SIGTERM` to the PID 1 process: -Confirm from the logs that the `SIGTERM` handler was called and that -the process exited with a status of 0: + ```shell + just send-sigterm + ``` -``` shellsession -App got SIGTERM 15, going to exit -``` +3. Confirm from the logs that the `SIGTERM` handler was called and that the process exited with a status of `0`: + + ```console + App got SIGTERM 15, going to exit + ``` -Now, perform the same test with `SIGINT`. You can confirm that nothing -is printed, as this signal is not handled by the application. +Now, perform the same test with `SIGINT`. You can confirm that nothing is printed, +as this signal is not handled by the application. ## SIGTERM ignore -This test is for an application that ignores `SIGTERM` and continues -running. This library should be able to forcibly kill such processes. +This test is for an application that ignores `SIGTERM` and continues running. +This library should be able to forcibly kill such processes. -Execute the recipe `sigloop-test`: +1. Execute the recipe `sigloop-test`: -``` shellsession -❯ just sigloop-test -docker rm pid1rs || exit 0 -pid1rs -docker run --name pid1rs -t pid1rstest sigterm_loop -pid1-rs: Process running as PID 1 -pid1-rs: Process not running as Pid 1: PID 7 -This APP ignores SIGTERM (15) -``` + ```console + $ just sigloop-test -Now, send `SIGTERM` to the PID 1 process: + # docker run --rm --name pid1rs pid1rstest sigterm_loop + pid1-rs: Process running as PID 1 + This APP ignores SIGTERM (15) + ``` -``` shellsession -❯ just send-sigterm -``` +2. Now, send `SIGTERM` to the PID 1 process: -You will see that it would have exited: + ```shell + just send-sigterm + ``` -``` shellsession -App got SIGTERM 15, but will not exit -App got SIGTERM 15, but will not exit -error: Recipe `sigloop-test` failed on line 44 with exit code 137 -``` +3. You will see that it would have exited: + + ```console + App got SIGTERM 15, but will not exit + App got SIGTERM 15, but will not exit + error: Recipe `sigloop-test` failed on line 44 with exit code 137 + ``` -You can confirm from the status code (137) that the child process was -killed by `SIGKILL` (signal 9, exit code 128 + 9), because the -application ignored `SIGTERM`. +You can confirm from the status code (137) that the child process was killed by +`SIGKILL` (signal 9, exit code 128 + 9), because the application ignored `SIGTERM`. diff --git a/README.md b/README.md index dc0fb3d..3520bf5 100644 --- a/README.md +++ b/README.md @@ -109,22 +109,25 @@ CMD [ "your-application", "--arg1" ] The `pid1` binary supports various command-line options: -``` shellsession +```shellsession ❯ pid1 --help -Usage: +A Unix PID1 process wrapper for signal handling and zombie reaping + +Usage: pid1 [OPTIONS] [ARGS]... Arguments: Process to run - [ARGS]... Arguments to the process + [ARGS]... Arguments to that process Options: - -w, --workdir Specify working direcory - -t, --timeout Timeout (in seconds) to wait for child proess to exit [default: 2] + -w, --workdir Specify working directory + -t, --timeout Grace period for stopping before escalating to SIGKILL [default: 2] -v, --verbose Turn on verbose output - -e, --env Override environment variables. Can specify multiple times - -u, --user-id Run command with user ID - -g, --group-id Run command with group ID + -e, --env Override environment variables. Can specify multiple times + -u, --user-id Run command with user ID + -g, --group-id Run command with group ID -h, --help Print help + -V, --version Print version ``` --- diff --git a/justfile b/justfile index 7d190f7..1386761 100644 --- a/justfile +++ b/justfile @@ -1,36 +1,38 @@ +drun_pid1 := "docker run --rm --name pid pid1runner" + # List all recipies default: just --list --unsorted # Build pid binary build-release-binary: - cargo build --target x86_64-unknown-linux-musl --release + cargo build --bin pid1 --release --target {{ arch() }}-unknown-linux-musl # Build test container test: build-release-binary - cp target/x86_64-unknown-linux-musl/release/pid1 ./pid1-exe/etc/ - cd pid1-exe/etc && docker build . -f Dockerfile --tag pid1runner + cp target/{{ arch() }}-unknown-linux-musl/release/pid1 ./pid1-exe/etc/ + docker build --tag pid1runner ./pid1-exe/etc/ # Test docker image test-init-image: - docker run --rm --interactive --name pid pid1runner ps aux - docker run --rm --interactive --name pid pid1runner ls - docker run --rm --interactive --name pid pid1runner ls / - docker run --rm --interactive --name pid pid1runner id - docker run --rm --interactive --name pid pid1runner --workdir=/home pwd - docker run --rm --interactive --name pid pid1runner --env HELLO=WORLD --env=FOO=BYE printenv HELLO FOO + {{ drun_pid1 }} ps aux + {{ drun_pid1 }} ls + {{ drun_pid1 }} ls / + {{ drun_pid1 }} id + {{ drun_pid1 }} --workdir=/home pwd + {{ drun_pid1 }} --env HELLO=WORLD --env=FOO=BYE printenv HELLO FOO # Exec init image exec-init-image: - docker run --rm --name pid --tty --interactive pid1runner sh + docker run --rm -it --name pid pid1runner sh # Build binary for other architectures binaries clean='false': - cross build --target x86_64-unknown-linux-gnu --release + cross build --bin pid1 --release --target x86_64-unknown-linux-gnu -{{ clean }} && docker image rm ghcr.io/cross-rs/x86_64-unknown-linux-gnu:0.2.5 - cross build --target aarch64-unknown-linux-gnu --release + cross build --bin pid1 --release --target aarch64-unknown-linux-gnu -{{ clean }} && docker image rm ghcr.io/cross-rs/aarch64-unknown-linux-gnu:0.2.5 - cross build --target aarch64-unknown-linux-musl --release + cross build --bin pid1 --release --target aarch64-unknown-linux-musl -{{ clean }} && docker image rm ghcr.io/cross-rs/aarch64-unknown-linux-musl:0.2.5 # Copy binaries to artifacts directory diff --git a/pid1-exe/Cargo.toml b/pid1-exe/Cargo.toml index 74a8716..a48f920 100644 --- a/pid1-exe/Cargo.toml +++ b/pid1-exe/Cargo.toml @@ -2,14 +2,13 @@ name = "pid1-exe" version = "0.1.6" edition = "2021" -description = "pid1 handling library for proper signal and zombie reaping of the PID1 process" +description = "A Unix PID1 process wrapper for signal handling and zombie reaping" readme = "../README.md" homepage = "https://github.com/fpco/pid1-rs" repository = "https://github.com/fpco/pid1-rs" license = "MIT" keywords = ["cli", "init", "pid1", "process"] categories = ["command-line-utilities"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] name = "pid1" @@ -21,5 +20,7 @@ clap = { version = "4.5.41", default-features = false, features = [ "help", "std", ] } -pid1 = { version = "0.1.6", path = "../pid1" } signal-hook = "0.4.3" + +[target.'cfg(unix)'.dependencies] +pid1 = { version = "0.1.6", path = "../pid1" } diff --git a/pid1-exe/src/cli.rs b/pid1-exe/src/cli.rs index 44a4449..bdd1a73 100644 --- a/pid1-exe/src/cli.rs +++ b/pid1-exe/src/cli.rs @@ -1,104 +1,108 @@ -use clap::Parser; -#[cfg(target_family = "unix")] use pid1::Pid1Settings; -#[cfg(target_family = "unix")] use signal_hook::{ consts::{SIGCHLD, SIGINT, SIGTERM}, iterator::Signals, }; -#[cfg(target_family = "unix")] use std::os::unix::process::CommandExt; -#[cfg(target_family = "unix")] use std::time::Duration; -use std::{error::Error, ffi::OsString, path::PathBuf}; +use std::{str::FromStr, ffi::OsString, path::PathBuf}; -#[derive(Parser, Debug, PartialEq)] +#[derive(clap::Parser, Debug, PartialEq)] +#[command(version, about, long_about = None)] pub(crate) struct Pid1App { - /// Specify working direcory + /// Specify working directory #[arg(short, long, value_name = "DIR")] pub(crate) workdir: Option, - /// Timeout (in seconds) to wait for child proess to exit - #[arg(short, long, value_name = "TIMEOUT", default_value_t = 2)] + + /// Grace period for stopping before escalating to SIGKILL + #[arg(short, long, value_name = "SECONDS", default_value_t = 2)] pub(crate) timeout: u8, + /// Turn on verbose output - #[arg(short, long, default_value_t = false)] + #[arg(short, long)] pub(crate) verbose: bool, + /// Override environment variables. Can specify multiple times. - #[arg(short, long, value_parser=parse_key_val::)] - pub(crate) env: Vec<(OsString, OsString)>, + #[arg(short, long, value_name = "KEY=VALUE")] + pub(crate) env: Vec, + /// Run command with user ID - #[arg(short, long, value_name = "USER_ID")] - user_id: Option, + #[arg(short, long, value_name = "USER ID")] + pub(crate) user_id: Option, + /// Run command with group ID - #[arg(short, long, value_name = "GROUP_ID")] - group_id: Option, + #[arg(short, long, value_name = "GROUP ID")] + pub(crate) group_id: Option, + /// Process to run - #[arg(required = true)] + #[arg(trailing_var_arg = true)] pub(crate) command: String, - /// Arguments to the process - #[arg(required = false)] + + /// Arguments to that process pub(crate) args: Vec, } impl Pid1App { - #[cfg(target_family = "unix")] + /// Parses CLI arguments from the environment. + pub(crate) fn from_cli() -> Self { + use clap::Parser; + Self::parse() + } + pub(crate) fn run(self) -> ! { - let mut child = std::process::Command::new(&self.command); - let child = child.args(&self.args[..]); + let mut cmd = std::process::Command::new(&self.command); + cmd.args(&self.args); + if let Some(workdir) = &self.workdir { - child.current_dir(workdir); + cmd.current_dir(workdir); } if let Some(user_id) = &self.user_id { - child.uid(*user_id); + cmd.uid(*user_id); } if let Some(group_id) = &self.group_id { - child.gid(*group_id); + cmd.gid(*group_id); } - for (key, value) in &self.env { - child.env(key, value); + for KeyValue(key, value) in &self.env { + cmd.env(key, value); } + let pid = std::process::id(); if pid != 1 { - let status = child.exec(); + let status = cmd.exec(); eprintln!("execvp failed with: {status:?}"); std::process::exit(1); - } else { - // Install signal handlers before launching child process - let signals = Signals::new([SIGTERM, SIGINT, SIGCHLD]).unwrap(); - let child = child.spawn(); - let child = match child { - Ok(child) => child, - Err(err) => { - eprintln!("pid1: {} spawn failed. Got error: {err}", self.command); - std::process::exit(1); - } - }; - - Pid1Settings::new() - .enable_log(self.verbose) - .timeout(Duration::from_secs(self.timeout.into())) - .pid1_handling(signals, child) } - } - #[cfg(target_family = "windows")] - pub(crate) fn run(self) -> ! { - eprintln!("pid1: Not supported on Windows"); - std::process::exit(1); + // CRITICAL: Install signal handlers BEFORE spawning the child. + // This prevents a race condition where a fast-failing child sends SIGCHLD + // before we are ready to catch and reap it, creating zombie processes. + let signals = Signals::new([SIGTERM, SIGINT, SIGCHLD]).unwrap(); + + let child = cmd.spawn().unwrap_or_else(|err| { + eprintln!("pid1: {} spawn failed. Got error: {err}", self.command); + std::process::exit(1); + }); + + Pid1Settings::new() + .enable_log(self.verbose) + .timeout(Duration::from_secs(self.timeout.into())) + .pid1_handling(signals, child) } } -/// Parse a single key-value pair -fn parse_key_val(s: &str) -> Result<(T, U), Box> -where - T: std::str::FromStr, - T::Err: Error + Send + Sync + 'static, - U: std::str::FromStr, - U::Err: Error + Send + Sync + 'static, -{ - let pos = s - .find('=') - .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?; - Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) +/// A CLI argument parsed from a `KEY=VALUE` pair. +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct KeyValue(OsString, OsString); + +impl FromStr for KeyValue { + type Err = String; + + /// Parses a CLI flag value into a [`KeyValue`] type. + fn from_str(s: &str) -> Result { + let (key, value) = s.split_once('=') + .ok_or_else(|| format!("invalid `KEY=VALUE` pair: no `=` found in `{s}`"))?; + + Ok(KeyValue(key.into(), value.into())) + } } diff --git a/pid1-exe/src/main.rs b/pid1-exe/src/main.rs index 4922c96..00b1f0c 100644 --- a/pid1-exe/src/main.rs +++ b/pid1-exe/src/main.rs @@ -1,10 +1,10 @@ +#[cfg(unix)] mod cli; -use clap::Parser; - -use crate::cli::Pid1App; - fn main() { - let cli = Pid1App::parse(); - cli.run() + #[cfg(unix)] + cli::Pid1App::from_cli().run(); + + #[cfg(not(unix))] + compile_error!("`pid1` is only compatible with Unix-like operating systems."); } diff --git a/pid1/justfile b/pid1/justfile index 33bb8b3..f9bb5f0 100644 --- a/pid1/justfile +++ b/pid1/justfile @@ -15,37 +15,37 @@ build-image: cp ../target/x86_64-unknown-linux-musl/debug/examples/sigterm_handler etc cp ../target/x86_64-unknown-linux-musl/debug/examples/sigterm_loop etc cp ../target/x86_64-unknown-linux-musl/debug/examples/dumb_shell etc - docker build etc -f etc/Dockerfile --tag pid1rstest + docker build --tag pid1rstest ./etc/ # Run test image run-image: - docker rm pid1rs || exit 0 - docker run --name pid1rs -t pid1rstest /simple --sleep 20 + docker run --rm --name pid1rs pid1rstest /simple --sleep 20 + +# Run orphans image +run-orphans: + docker run --rm --name pid1rs pid1rstest /simple --sleep 20 --create-grandchildren # Run zombie in the container run-zombie: - docker exec -t pid1rs zombie + docker exec pid1rs zombie # Test test: build-image - docker rm pid1rs || exit 0 - docker run --name pid1rs -t pid1rstest + docker run --rm --name pid1rs pid1rstest cargo test # Run SIGTERM test sigterm-test: - docker rm pid1rs || exit 0 - docker run --name pid1rs -t pid1rstest sigterm_handler + docker run --rm --name pid1rs pid1rstest sigterm_handler # Send SIGTERM to container send-sigterm: - docker exec -it pid1rs kill 1 + docker exec pid1rs kill 1 # Run SIGTERM loop test sigloop-test: - docker rm pid1rs || exit 0 - docker run --name pid1rs -t pid1rstest sigterm_loop + docker run --rm --name pid1rs pid1rstest sigterm_loop -# Exec into that docker container +# Exec into the `pid1rs` docker container exec-shell: docker exec -it pid1rs bash diff --git a/pid1/tests/sanity.rs b/pid1/tests/sanity.rs index 5721dac..6e30186 100644 --- a/pid1/tests/sanity.rs +++ b/pid1/tests/sanity.rs @@ -18,7 +18,6 @@ impl Container { "run", "--name", self.name.as_str(), - "-t", self.image.as_str(), ]) .output() @@ -31,7 +30,7 @@ impl Container { impl Drop for Container { fn drop(&mut self) { - // Use rm -f to stop and remove the container. This is robust + // Use `rm -f` to stop and remove the container. This is robust // and ensures cleanup even if tests fail to stop the container. let output = Command::new("docker") .args(["rm", "-f", self.name.as_str()]) @@ -72,7 +71,6 @@ fn reaps_zombie_process() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "/simple", "--sleep", @@ -85,7 +83,7 @@ fn reaps_zombie_process() { let zombie_result = s.spawn(|| { let zombie_output = container - .plain_run(&["exec", "-t", container.name.as_str(), "zombie"]) + .plain_run(&["exec", container.name.as_str(), "zombie"]) .unwrap(); zombie_output }); @@ -117,7 +115,6 @@ fn child_process_status_code() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "/simple", "--sleep", @@ -144,7 +141,6 @@ fn child_process_status_code() { container .plain_run(&[ "exec", - "-t", container.name.as_str(), "kill", "-12", @@ -174,7 +170,6 @@ fn sigterm_handling() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "sigterm_handler", ]); @@ -184,7 +179,7 @@ fn sigterm_handling() { let kill_result = s.spawn(|| { std::thread::sleep(Duration::from_secs(2)); container - .plain_run(&["exec", "-t", container.name.as_str(), "kill", "1"]) + .plain_run(&["exec", container.name.as_str(), "kill", "1"]) .unwrap() }); @@ -210,7 +205,6 @@ fn sigterm_ignore() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "sigterm_loop", ]); @@ -220,7 +214,7 @@ fn sigterm_ignore() { let kill_result = s.spawn(|| { std::thread::sleep(Duration::from_secs(2)); container - .plain_run(&["exec", "-t", container.name.as_str(), "kill", "1"]) + .plain_run(&["exec", container.name.as_str(), "kill", "1"]) .unwrap() }); @@ -261,7 +255,6 @@ fn reaps_multiple_zombie_processes() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "/simple", "--sleep", @@ -294,7 +287,6 @@ fn reaps_multiple_zombie_processes() { let zombie_check_output = container .plain_run(&[ "exec", - "-t", container.name.as_str(), "sh", "-c", @@ -351,7 +343,6 @@ fn reaps_orphaned_grandchildren() { "run", "--name", container.name.as_str(), - "-t", container.image.as_str(), "/simple", "--create-grandchildren",