Skip to main content

libcontainer/
config.rs

1use std::fs;
2use std::io::{BufReader, BufWriter, Write};
3use std::path::{Path, PathBuf};
4
5use oci_spec::runtime::{Hooks, Spec};
6use serde::{Deserialize, Serialize};
7
8use crate::utils;
9
10pub enum PersonalityDomain {
11    Linux = 0x0000,
12    Linux32 = 0x0008,
13}
14
15#[derive(Debug, thiserror::Error)]
16pub enum ConfigError {
17    #[error("failed to save config")]
18    SaveIO {
19        source: std::io::Error,
20        path: PathBuf,
21    },
22    #[error("failed to save config")]
23    SaveEncode {
24        source: serde_json::Error,
25        path: PathBuf,
26    },
27    #[error("failed to parse config")]
28    LoadIO {
29        source: std::io::Error,
30        path: PathBuf,
31    },
32    #[error("failed to parse config")]
33    LoadParse {
34        source: serde_json::Error,
35        path: PathBuf,
36    },
37    #[error("missing linux in spec")]
38    MissingLinux,
39}
40
41type Result<T> = std::result::Result<T, ConfigError>;
42
43const YOUKI_CONFIG_NAME: &str = "youki_config.json";
44
45/// A configuration for passing information obtained during container creation to other commands.
46/// Keeping the information to a minimum improves performance.
47#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
48#[non_exhaustive]
49pub struct YoukiConfig {
50    pub hooks: Option<Hooks>,
51    pub cgroup_path: PathBuf,
52}
53
54impl YoukiConfig {
55    pub fn from_spec(spec: &Spec, container_id: &str) -> Result<Self> {
56        Ok(YoukiConfig {
57            hooks: spec.hooks().clone(),
58            cgroup_path: utils::get_cgroup_path(
59                spec.linux()
60                    .as_ref()
61                    .ok_or(ConfigError::MissingLinux)?
62                    .cgroups_path(),
63                container_id,
64            ),
65        })
66    }
67
68    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
69        let file = fs::File::create(path.as_ref().join(YOUKI_CONFIG_NAME)).map_err(|err| {
70            ConfigError::SaveIO {
71                source: err,
72                path: path.as_ref().to_owned(),
73            }
74        })?;
75        let mut writer = BufWriter::new(file);
76        serde_json::to_writer(&mut writer, self).map_err(|err| ConfigError::SaveEncode {
77            source: err,
78            path: path.as_ref().to_owned(),
79        })?;
80        writer.flush().map_err(|err| ConfigError::SaveIO {
81            source: err,
82            path: path.as_ref().to_owned(),
83        })?;
84
85        Ok(())
86    }
87
88    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
89        let path = path.as_ref();
90        let file =
91            fs::File::open(path.join(YOUKI_CONFIG_NAME)).map_err(|err| ConfigError::LoadIO {
92                source: err,
93                path: path.to_owned(),
94            })?;
95        let reader = BufReader::new(file);
96        let config = serde_json::from_reader(reader).map_err(|err| ConfigError::LoadParse {
97            source: err,
98            path: path.to_owned(),
99        })?;
100        Ok(config)
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use anyhow::Result;
107
108    use super::*;
109
110    #[test]
111    fn test_config_from_spec() -> Result<()> {
112        let container_id = "sample";
113        let spec = Spec::default();
114        let config = YoukiConfig::from_spec(&spec, container_id)?;
115        assert_eq!(&config.hooks, spec.hooks());
116        dbg!(&config.cgroup_path);
117        assert_eq!(
118            config.cgroup_path,
119            PathBuf::from(format!(":youki:{container_id}"))
120        );
121        Ok(())
122    }
123
124    #[test]
125    fn test_config_save_and_load() -> Result<()> {
126        let container_id = "sample";
127        let tmp = tempfile::tempdir().expect("create temp dir");
128        let spec = Spec::default();
129        let config = YoukiConfig::from_spec(&spec, container_id)?;
130        config.save(&tmp)?;
131        let act = YoukiConfig::load(&tmp)?;
132        assert_eq!(act, config);
133        Ok(())
134    }
135}