containerd_shimkit/sandbox/
instance_utils.rs1use std::fs::File;
4use std::io::{Error as IoError, ErrorKind, Result as IoResult};
5use std::path::PathBuf;
6
7use serde::{Deserialize, Serialize};
8
9use super::{Error, InstanceConfig};
10use crate::sys::DEFAULT_CONTAINER_ROOT_DIR;
11use crate::sys::stdio::open;
12
13#[derive(Serialize, Deserialize)]
14struct Options {
15 root: Option<PathBuf>,
16}
17
18impl InstanceConfig {
19 #[cfg_attr(feature = "tracing", tracing::instrument(level = "Debug"))]
26 pub fn determine_rootdir(
27 &self,
28 runtime: impl AsRef<str> + std::fmt::Debug,
29 ) -> Result<PathBuf, Error> {
30 let rootdir = DEFAULT_CONTAINER_ROOT_DIR.join(runtime.as_ref());
31 let file = match File::open(self.bundle.join("options.json")) {
32 Ok(f) => f,
33 Err(e) if e.kind() == ErrorKind::NotFound => return Ok(rootdir.join(&self.namespace)),
34 Err(e) => return Err(e.into()),
35 };
36 let path = serde_json::from_reader::<_, Options>(file)?
37 .root
38 .unwrap_or(rootdir)
39 .join(&self.namespace);
40 log::info!("container runtime root path is {path:?}");
41 Ok(path)
42 }
43
44 pub fn open_stdin(&self) -> IoResult<File> {
45 if self.stdin.as_os_str().is_empty() {
46 return Err(IoError::new(ErrorKind::NotFound, "File not found"));
47 }
48 open(&self.stdin)
49 }
50
51 pub fn open_stdout(&self) -> IoResult<File> {
52 if self.stdout.as_os_str().is_empty() {
53 return Err(IoError::new(ErrorKind::NotFound, "File not found"));
54 }
55 open(&self.stdout)
56 }
57
58 pub fn open_stderr(&self) -> IoResult<File> {
59 if self.stderr.as_os_str().is_empty() {
60 return Err(IoError::new(ErrorKind::NotFound, "File not found"));
61 }
62 open(&self.stderr)
63 }
64}
65
66#[cfg(unix)]
67#[cfg(test)]
68mod tests {
69 use tempfile::tempdir;
70
71 use super::*;
72
73 #[test]
74 fn test_determine_rootdir_with_options_file() -> Result<(), Error> {
75 let namespace = "test_namespace";
76 let dir = tempdir()?;
77 let rootdir = dir.path().join("runwasi");
78 let opts = Options {
79 root: Some(rootdir.clone()),
80 };
81 std::fs::write(
82 dir.path().join("options.json"),
83 serde_json::to_string(&opts)?,
84 )?;
85 let cfg = InstanceConfig {
86 bundle: dir.path().to_path_buf(),
87 namespace: namespace.to_string(),
88 ..Default::default()
89 };
90 let root = cfg.determine_rootdir("runtime")?;
91 assert_eq!(root, rootdir.join(namespace));
92 Ok(())
93 }
94
95 #[test]
96 fn test_determine_rootdir_without_options_file() -> Result<(), Error> {
97 let dir = tempdir()?;
98 let namespace = "test_namespace";
99 let cfg = InstanceConfig {
100 bundle: dir.path().to_path_buf(),
101 namespace: namespace.to_string(),
102 ..Default::default()
103 };
104 let root = cfg.determine_rootdir("runtime")?;
105 assert!(root.is_absolute());
106 assert_eq!(
107 root,
108 PathBuf::from("/run/containerd/runtime").join(namespace)
109 );
110 Ok(())
111 }
112}