use std::env;
use std::fmt;
use std::fs;
use std::os::unix::io::FromRawFd;
use std::process;
pub struct Config {
pub id: String,
pub namespace: String,
pub stdout: fs::File,
pub stderr: fs::File,
}
impl Config {
fn new() -> Config {
let id = match env::var("CONTAINER_ID") {
Ok(id) => id,
Err(_) => handle_err("CONTAINER_ID env not found"),
};
let namespace = match env::var("CONTAINER_NAMESPACE") {
Ok(ns) => ns,
Err(_) => handle_err("CONTAINER_NAMESPACE env not found"),
};
let stdout = unsafe { fs::File::from_raw_fd(3) };
let stderr = unsafe { fs::File::from_raw_fd(4) };
Config {
id,
namespace,
stdout,
stderr,
}
}
}
struct Ready(fs::File);
impl Ready {
fn new() -> Ready {
Ready(unsafe { fs::File::from_raw_fd(5) })
}
fn signal(self) {
drop(self.0)
}
}
pub trait Driver: Sized {
type Error: fmt::Debug;
fn new(config: Config) -> Result<Self, Self::Error>;
fn run(self) -> Result<(), Self::Error>;
}
pub fn run<D: Driver>() {
let config = Config::new();
let ready = Ready::new();
let logger = match D::new(config) {
Ok(driver) => driver,
Err(err) => handle_err(err),
};
ready.signal();
if let Err(err) = logger.run() {
handle_err(err)
} else {
process::exit(0);
}
}
#[inline]
fn handle_err(err: impl fmt::Debug) -> ! {
eprintln!("{:?}", err);
process::exit(1);
}