use crate::container::create;
use crate::container::start;
use crate::{
linux::process,
socket::{SocketClient, SocketMessage, SocketServer},
state::{State, Status},
};
use anyhow::bail;
use anyhow::Result;
use nix::unistd::{self, Pid};
use oci_spec::runtime::{LinuxNamespace, Spec};
use std::{ffi::CString, path::Path, process::exit};
pub fn pipeline(
spec: &Spec,
state: &State,
namespace_list: &[LinuxNamespace],
container_socket_server: &mut SocketServer,
) -> Result<()> {
create::init_environment(spec, state, namespace_list)?;
container_socket_server.write(SocketMessage::new(Status::Creating, None))?;
container_socket_server.listen()?;
create::create_container(spec, state)?;
container_socket_server.write(SocketMessage::new(Status::Created, None))?;
container_socket_server.listen().unwrap();
start::start_container(spec, state)?;
container_socket_server.write(SocketMessage::new(Status::Running, None))?;
if let Some(process) = spec.process() {
let command = CString::new(process.args().as_ref().unwrap()[0].as_bytes())?;
let argument_list: Vec<CString> = process
.args()
.as_ref()
.unwrap()
.iter()
.map(|a| CString::new(a.to_string()).unwrap_or_default())
.collect();
unistd::execvp(&command, &argument_list)?;
} else {
bail!("the 'process' field doesn't exist");
}
Ok(())
}
pub fn fork_container(
spec: &Spec,
state: &State,
namespace_list: &[LinuxNamespace],
init_socket_path: &Path,
container_socket_path: &Path,
) -> Result<Pid> {
process::clone_child(namespace_list, || {
let mut container_socket_server = SocketServer::bind(container_socket_path).unwrap();
let init_socket_client = SocketClient::connect(init_socket_path).unwrap();
init_socket_client.shutdown().unwrap();
container_socket_server.listen().unwrap();
if let Err(error) = pipeline(spec, state, namespace_list, &mut container_socket_server) {
container_socket_server
.write(SocketMessage::new(Status::Stopped, Some(error.to_string())))
.unwrap();
exit(1);
}
0
})
}