libcontainer/container/container_delete.rs
1use std::fs;
2
3use libcgroups::common::CgroupManager;
4use libcgroups::{self};
5use nix::sys::signal;
6
7use super::{Container, ContainerStatus};
8use crate::config::YoukiConfig;
9use crate::error::LibcontainerError;
10use crate::hooks;
11use crate::process::intel_rdt::delete_resctrl_subdirectory;
12
13impl Container {
14 /// Deletes the container
15 ///
16 /// # Example
17 ///
18 /// ```no_run
19 /// use libcontainer::container::builder::ContainerBuilder;
20 /// use libcontainer::syscall::syscall::SyscallType;
21 ///
22 /// # fn main() -> anyhow::Result<()> {
23 /// let mut container = ContainerBuilder::new(
24 /// "74f1a4cb3801".to_owned(),
25 /// SyscallType::default(),
26 /// )
27 /// .as_init("/var/run/docker/bundle")
28 /// .build()?;
29 ///
30 /// container.delete(true)?;
31 /// # Ok(())
32 /// # }
33 /// ```
34 pub fn delete(&mut self, force: bool) -> Result<(), LibcontainerError> {
35 self.refresh_status()?;
36
37 tracing::debug!("container status: {:?}", self.status());
38
39 // Check if container is allowed to be deleted based on container status.
40 match self.status() {
41 ContainerStatus::Stopped => {}
42 ContainerStatus::Created => {
43 // Here, we differ from the OCI spec, but matches the same
44 // behavior as `runc` and `crun`. The OCI spec does not allow
45 // deletion of status `created` without `force` flag. But both
46 // `runc` and `crun` allows deleting `created`. Therefore we
47 // decided to follow `runc` and `crun`.
48 self.do_kill(signal::Signal::SIGKILL, true)?;
49 self.set_status(ContainerStatus::Stopped).save()?;
50 }
51 ContainerStatus::Creating | ContainerStatus::Running | ContainerStatus::Paused => {
52 // Containers can't be deleted while in these status, unless
53 // force flag is set. In the force case, we need to clean up any
54 // processes associated with containers.
55 if force {
56 self.do_kill(signal::Signal::SIGKILL, true)?;
57 self.set_status(ContainerStatus::Stopped).save()?;
58 } else {
59 tracing::error!(
60 id = ?self.id(),
61 status = ?self.status(),
62 "delete requires the container state to be stopped or created",
63 );
64 return Err(LibcontainerError::IncorrectStatus(self.status()));
65 }
66 }
67 }
68
69 // Once reached here, the container is verified that it can be deleted.
70 debug_assert!(self.status().can_delete());
71
72 if let Some(true) = &self.clean_up_intel_rdt_subdirectory() {
73 if let Err(err) = delete_resctrl_subdirectory(self.id()) {
74 tracing::warn!(
75 "failed to delete resctrl subdirectory due to: {err:?}, continue to delete"
76 );
77 }
78 }
79
80 if self.root.exists() {
81 match YoukiConfig::load(&self.root) {
82 Ok(config) => {
83 tracing::debug!("config: {:?}", config);
84
85 // remove the cgroup created for the container
86 // check https://man7.org/linux/man-pages/man7/cgroups.7.html
87 // creating and removing cgroups section for more information on cgroups
88 let cmanager = libcgroups::common::create_cgroup_manager(
89 libcgroups::common::CgroupConfig {
90 cgroup_path: config.cgroup_path.to_owned(),
91 systemd_cgroup: self.systemd(),
92 container_name: self.id().to_string(),
93 },
94 )?;
95 cmanager.remove().map_err(|err| {
96 tracing::error!(cgroup_path = ?config.cgroup_path, "failed to remove cgroup due to: {err:?}");
97 err
98 })?;
99
100 if let Some(hooks) = config.hooks.as_ref() {
101 hooks::run_hooks(hooks.poststop().as_ref(), Some(&self.state), None, None)
102 .map_err(|err| {
103 tracing::error!(err = ?err, "failed to run post stop hooks");
104 err
105 })?;
106 }
107 }
108 Err(err) => {
109 // There is a brief window where the container state is
110 // created, but the container config is not yet generated
111 // from the OCI spec. In this case, we assume as if we
112 // successfully deleted the config and moving on.
113 tracing::warn!(
114 "skipping loading youki config due to: {err:?}, continue to delete"
115 );
116 }
117 }
118
119 // remove the directory storing container state
120 tracing::debug!("remove dir {:?}", self.root);
121 fs::remove_dir_all(&self.root).map_err(|err| {
122 tracing::error!(?err, path = ?self.root, "failed to remove container dir");
123 LibcontainerError::OtherIO(err)
124 })?;
125 }
126
127 Ok(())
128 }
129}