1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::{
config::YoukiConfig,
error::LibcontainerError,
hooks,
notify_socket::{NotifySocket, NOTIFY_FILE},
};
use super::{Container, ContainerStatus};
use nix::{sys::signal, unistd};
impl Container {
/// Starts a previously created container
///
/// # Example
///
/// ```no_run
/// use libcontainer::container::builder::ContainerBuilder;
/// use libcontainer::syscall::syscall::SyscallType;
///
/// # fn main() -> anyhow::Result<()> {
/// let mut container = ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .as_init("/var/run/docker/bundle")
/// .build()?;
///
/// container.start();
/// # Ok(())
/// # }
/// ```
pub fn start(&mut self) -> Result<(), LibcontainerError> {
self.refresh_status()?;
if !self.can_start() {
tracing::error!(status = ?self.status(), id = ?self.id(), "cannot start container due to incorrect state");
return Err(LibcontainerError::IncorrectStatus);
}
let config = YoukiConfig::load(&self.root).map_err(|err| {
tracing::error!(
"failed to load runtime spec for container {}: {}",
self.id(),
err
);
err
})?;
if let Some(hooks) = config.hooks.as_ref() {
// While prestart is marked as deprecated in the OCI spec, the docker and integration test still
// uses it.
#[allow(deprecated)]
hooks::run_hooks(hooks.prestart().as_ref(), Some(self)).map_err(|err| {
tracing::error!("failed to run pre start hooks: {}", err);
// In the case where prestart hook fails, the runtime must
// stop the container before generating an error and exiting.
let _ = self.kill(signal::Signal::SIGKILL, true);
err
})?;
}
unistd::chdir(self.root.as_os_str()).map_err(|err| {
tracing::error!("failed to change directory to container root: {}", err);
LibcontainerError::OtherSyscall(err)
})?;
let mut notify_socket = NotifySocket::new(self.root.join(NOTIFY_FILE));
notify_socket.notify_container_start()?;
self.set_status(ContainerStatus::Running)
.save()
.map_err(|err| {
tracing::error!(id = ?self.id(), ?err, "failed to save state for container");
err
})?;
// Run post start hooks. It runs after the container process is started.
// It is called in the runtime namespace.
if let Some(hooks) = config.hooks.as_ref() {
hooks::run_hooks(hooks.poststart().as_ref(), Some(self)).map_err(|err| {
tracing::error!("failed to run post start hooks: {}", err);
err
})?;
}
Ok(())
}
}