use std::process::{Command, Stdio};
use std::time::Duration;
use super::local::LocalPty;
use super::Transport;
use crate::error::Result;
pub struct DockerExec {
inner: LocalPty,
container: String,
marker: String,
}
impl DockerExec {
pub fn spawn(container: &str, marker: &str) -> Result<Self> {
let env = format!("EXECKIT_SID={marker}");
let inner = LocalPty::spawn(
"docker",
&["exec", "-it", "-e", &env, "--", container, "/bin/sh"],
)?;
Ok(Self {
inner,
container: container.to_string(),
marker: marker.to_string(),
})
}
}
impl Transport for DockerExec {
fn write_all(&mut self, bytes: &[u8]) -> Result<()> {
self.inner.write_all(bytes)
}
fn recv_timeout(&self, dur: Duration) -> Option<Vec<u8>> {
self.inner.recv_timeout(dur)
}
}
impl Drop for DockerExec {
fn drop(&mut self) {
let script = format!(
"for p in /proc/[0-9]*; do \
tr '\\0' '\\n' < \"$p/environ\" 2>/dev/null | grep -qx 'EXECKIT_SID={m}' && \
kill -9 \"${{p#/proc/}}\" 2>/dev/null; \
done",
m = self.marker
);
let _ = Command::new("docker")
.args(["exec", "--", &self.container, "/bin/sh", "-c", &script])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
}
}