feat: Create RunDriver (#196)
This will be used for running containers for various tasks. There will be a way to take all output from the process and a way to display output from a running container like our builds have.
This commit is contained in:
parent
1a348f8137
commit
784be9869a
16 changed files with 510 additions and 98 deletions
|
|
@ -32,6 +32,7 @@ indicatif.workspace = true
|
|||
indicatif-log-bridge.workspace = true
|
||||
log.workspace = true
|
||||
once_cell.workspace = true
|
||||
tempdir.workspace = true
|
||||
serde.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{
|
|||
fs::OpenOptions,
|
||||
io::{BufRead, BufReader, Result, Write as IoWrite},
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, ExitStatus},
|
||||
process::{Command, ExitStatus, Stdio},
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::Duration,
|
||||
|
|
@ -199,7 +199,9 @@ impl CommandLogging for Command {
|
|||
let log_prefix = Arc::new(log_header(short_name));
|
||||
let (reader, writer) = os_pipe::pipe()?;
|
||||
|
||||
self.stdout(writer.try_clone()?).stderr(writer);
|
||||
self.stdout(writer.try_clone()?)
|
||||
.stderr(writer)
|
||||
.stdin(Stdio::piped());
|
||||
|
||||
let progress = Logger::multi_progress()
|
||||
.add(ProgressBar::new_spinner().with_message(format!("{} {name}", message.as_ref())));
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use std::{
|
||||
process,
|
||||
fs,
|
||||
path::PathBuf,
|
||||
process::{self, Command},
|
||||
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
|
||||
use log::{error, trace, warn};
|
||||
use log::{debug, error, trace, warn};
|
||||
use nix::{
|
||||
libc::{SIGABRT, SIGCONT, SIGHUP, SIGTSTP},
|
||||
sys::signal::{kill, Signal},
|
||||
|
|
@ -20,7 +22,31 @@ use signal_hook::{
|
|||
|
||||
use crate::logging::Logger;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ContainerId {
|
||||
cid_path: PathBuf,
|
||||
requires_sudo: bool,
|
||||
crt: String,
|
||||
}
|
||||
|
||||
impl ContainerId {
|
||||
pub fn new<P, S>(cid_path: P, container_runtime: S, requires_sudo: bool) -> Self
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
S: Into<String>,
|
||||
{
|
||||
let cid_path = cid_path.into();
|
||||
let crt = container_runtime.into();
|
||||
Self {
|
||||
cid_path,
|
||||
requires_sudo,
|
||||
crt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PID_LIST: Lazy<Arc<Mutex<Vec<i32>>>> = Lazy::new(|| Arc::new(Mutex::new(vec![])));
|
||||
static CID_LIST: Lazy<Arc<Mutex<Vec<ContainerId>>>> = Lazy::new(|| Arc::new(Mutex::new(vec![])));
|
||||
|
||||
/// Initialize Ctrl-C handler. This should be done at the start
|
||||
/// of a binary.
|
||||
|
|
@ -57,10 +83,36 @@ where
|
|||
warn!("Received termination signal, cleaning up...");
|
||||
trace!("{info:#?}");
|
||||
|
||||
Logger::multi_progress().clear().unwrap();
|
||||
Logger::multi_progress()
|
||||
.clear()
|
||||
.expect("Should clear multi_progress");
|
||||
|
||||
send_signal_processes(termsig);
|
||||
|
||||
let cid_list = CID_LIST.clone();
|
||||
let cid_list = cid_list.lock().expect("Should lock mutex");
|
||||
cid_list.iter().for_each(|cid| {
|
||||
if let Ok(id) = fs::read_to_string(&cid.cid_path) {
|
||||
let id = id.trim();
|
||||
debug!("Killing container {id}");
|
||||
|
||||
let status = if cid.requires_sudo {
|
||||
Command::new("sudo")
|
||||
.arg(&cid.crt)
|
||||
.arg("stop")
|
||||
.arg(id)
|
||||
.status()
|
||||
} else {
|
||||
Command::new(&cid.crt).arg("stop").arg(id).status()
|
||||
};
|
||||
|
||||
if let Err(e) = status {
|
||||
error!("Failed to kill container {id}: Error {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
drop(cid_list);
|
||||
|
||||
process::exit(1);
|
||||
}
|
||||
SIGTSTP => {
|
||||
|
|
@ -86,8 +138,12 @@ where
|
|||
fn send_signal_processes(sig: i32) {
|
||||
let pid_list = PID_LIST.clone();
|
||||
let pid_list = pid_list.lock().expect("Should lock mutex");
|
||||
|
||||
pid_list.iter().for_each(|pid| {
|
||||
if let Err(e) = kill(Pid::from_raw(*pid), Signal::try_from(sig).unwrap()) {
|
||||
if let Err(e) = kill(
|
||||
Pid::from_raw(*pid),
|
||||
Signal::try_from(sig).expect("Should be valid signal"),
|
||||
) {
|
||||
error!("Failed to kill process {pid}: Error {e}");
|
||||
} else {
|
||||
trace!("Killed process {pid}");
|
||||
|
|
@ -130,3 +186,28 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a cid to the list to kill when the program
|
||||
/// recieves a kill signal.
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if the mutex cannot be locked.
|
||||
pub fn add_cid(cid: &ContainerId) {
|
||||
let mut cid_list = CID_LIST.lock().expect("Should lock cid_list");
|
||||
|
||||
if !cid_list.contains(cid) {
|
||||
cid_list.push(cid.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a cid from the list of pids to kill.
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if the mutex cannot be locked.
|
||||
pub fn remove_cid(cid: &ContainerId) {
|
||||
let mut cid_list = CID_LIST.lock().expect("Should lock cid_list");
|
||||
|
||||
if let Some(index) = cid_list.iter().position(|val| *val == *cid) {
|
||||
cid_list.swap_remove(index);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue