container_device_interface/generate/
generator.rs

1use std::cmp::Ordering;
2use std::path::PathBuf;
3
4use oci_spec::runtime::{Hook, LinuxDevice, LinuxDeviceCgroup, LinuxDeviceType, Mount};
5
6use super::config::Generator;
7
8impl Generator {
9    // remove_device removes a device from g.config.linux.devices
10    pub fn remove_device(&mut self, path: &str) {
11        self.init_config_linux();
12        if let Some(linux) = self.config.as_mut().unwrap().linux_mut() {
13            if let Some(devices) = linux.devices_mut() {
14                if let Some(index) = devices
15                    .iter()
16                    .position(|device| device.path() == &PathBuf::from(path))
17                {
18                    devices.remove(index);
19                }
20            }
21        }
22    }
23
24    // add_device adds a device into g.config.linux.devices
25    pub fn add_device(&mut self, device: LinuxDevice) {
26        self.init_config_linux();
27
28        if let Some(linux) = self.config.as_mut().unwrap().linux_mut() {
29            if let Some(devices) = linux.devices_mut() {
30                if let Some(index) = devices.iter().position(|dev| dev.path() == device.path()) {
31                    devices[index] = device;
32                } else {
33                    devices.push(device);
34                }
35            } else {
36                linux.set_devices(Some(vec![device]));
37            }
38        }
39    }
40
41    // add_linux_resources_device adds a device into g.config.linux.resources.devices
42    pub fn add_linux_resources_device(
43        &mut self,
44        allow: bool,
45        dev_type: LinuxDeviceType,
46        major: Option<i64>,
47        minor: Option<i64>,
48        access: Option<String>,
49    ) {
50        self.init_config_linux_resources_devices();
51        if let Some(linux) = self.config.as_mut().unwrap().linux_mut() {
52            if let Some(resource) = linux.resources_mut() {
53                if let Some(devices) = resource.devices_mut() {
54                    let mut device = LinuxDeviceCgroup::default();
55                    device.set_allow(allow);
56                    device.set_typ(Some(dev_type));
57                    device.set_major(major);
58                    device.set_minor(minor);
59                    device.set_access(access);
60
61                    devices.push(device);
62                }
63            }
64        }
65    }
66
67    /// set Linux Intel RDT ClosID
68    pub fn set_linux_intel_rdt_clos_id(&mut self, clos_id: String) {
69        self.init_config_linux_intel_rdt();
70        if let Some(linux) = self.config.as_mut().unwrap().linux_mut() {
71            if let Some(intel_rdt) = linux.intel_rdt_mut() {
72                intel_rdt.set_clos_id(Some(clos_id));
73            }
74        }
75    }
76
77    // add_process_additional_gid adds an additional gid into g.config.process.additional_gids.
78    pub fn add_process_additional_gid(&mut self, gid: u32) {
79        self.init_config_process();
80        if let Some(process) = self.config.as_mut().unwrap().process_mut() {
81            if let Some(additional_gids) = process.user().additional_gids() {
82                let mut tmp_vec = additional_gids.clone();
83                if !additional_gids.contains(&gid) {
84                    tmp_vec.push(gid)
85                }
86
87                process.user_mut().set_additional_gids(Some(tmp_vec));
88            }
89        }
90    }
91
92    pub fn add_multiple_process_env(&mut self, envs: &[String]) {
93        self.init_config_process();
94
95        if let Some(process) = self.config.as_mut().unwrap().process_mut() {
96            let mut env_vec: Vec<String> = process.env_mut().get_or_insert_with(Vec::new).to_vec();
97            for env in envs {
98                let split: Vec<&str> = env.splitn(2, '=').collect();
99                let key = split[0].to_string();
100                let idx = self.env_map.entry(key.clone()).or_insert(env_vec.len());
101
102                if let Some(elem) = env_vec.get_mut(*idx) {
103                    elem.clone_from(env);
104                } else {
105                    env_vec.push(env.clone());
106                    self.env_map.insert(key, env_vec.len() - 1);
107                }
108            }
109            process.set_env(Some(env_vec));
110        }
111    }
112
113    // add_prestart_hook adds a prestart hook into g.config.hooks.prestart.
114    pub fn add_prestart_hook(&mut self, hook: Hook) {
115        self.init_config_hooks();
116        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
117            if let Some(prestart_hooks) = hooks.prestart_mut() {
118                prestart_hooks.push(hook);
119            } else {
120                hooks.set_prestart(Some(vec![hook]));
121            }
122        }
123    }
124
125    // add_poststop_hook adds a poststop hook into g.config.hooks.poststop.
126    pub fn add_poststop_hook(&mut self, hook: Hook) {
127        self.init_config_hooks();
128        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
129            if let Some(poststop_hooks) = hooks.poststop_mut() {
130                poststop_hooks.push(hook);
131            } else {
132                hooks.set_poststop(Some(vec![hook]));
133            }
134        }
135    }
136
137    // add_poststart_hook adds a poststart hook into g.config.hooks.poststart.
138    pub fn add_poststart_hook(&mut self, hook: Hook) {
139        self.init_config_hooks();
140        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
141            if let Some(poststart_hooks) = hooks.poststart_mut() {
142                poststart_hooks.push(hook);
143            } else {
144                hooks.set_poststart(Some(vec![hook]));
145            }
146        }
147    }
148
149    // add_createruntime_hook adds a create_runtime hook into g.config.hooks.create_runtime.
150    pub fn add_createruntime_hook(&mut self, hook: Hook) {
151        self.init_config_hooks();
152        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
153            if let Some(create_runtime) = hooks.create_runtime_mut() {
154                create_runtime.push(hook);
155            } else {
156                hooks.set_create_runtime(Some(vec![hook]));
157            }
158        }
159    }
160
161    // add_createcontainer_hook adds a create_container hook into g.config.hooks.create_container.
162    pub fn add_createcontainer_hook(&mut self, hook: Hook) {
163        self.init_config_hooks();
164        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
165            if let Some(create_container) = hooks.create_container_mut() {
166                create_container.push(hook);
167            } else {
168                hooks.set_create_container(Some(vec![hook]));
169            }
170        }
171    }
172
173    // add_start_container_hook adds a start container hook into g.config.hooks.start_container.
174    pub fn add_startcontainer_hook(&mut self, hook: Hook) {
175        self.init_config_hooks();
176        if let Some(hooks) = self.config.as_mut().unwrap().hooks_mut() {
177            if let Some(start_container) = hooks.start_container_mut() {
178                start_container.push(hook);
179            } else {
180                hooks.set_start_container(Some(vec![hook]));
181            }
182        }
183    }
184
185    // remove_mount removes a mount point on the dest directory
186    pub fn remove_mount(&mut self, dest: &str) {
187        if let Some(mounts) = self.config.as_mut().unwrap().mounts_mut() {
188            if let Some(index) = mounts
189                .iter()
190                .position(|m| m.destination() == &PathBuf::from(dest))
191            {
192                mounts.remove(index);
193            }
194        }
195    }
196
197    // add_mount adds a mount into g.config.mounts.
198    pub fn add_mount(&mut self, mount: Mount) {
199        self.init_config_mounts();
200
201        if let Some(mounts) = self.config.as_mut().unwrap().mounts_mut() {
202            mounts.push(mount);
203        }
204    }
205
206    // sort_mounts sorts the mounts in the given OCI Spec.
207    pub fn sort_mounts(&mut self) {
208        if let Some(ref mut mounts) = self.config.as_mut().unwrap().mounts_mut() {
209            mounts.sort_by(|a, b| a.destination().cmp(b.destination()));
210        }
211    }
212
213    // list_mounts returns the list of mounts
214    pub fn list_mounts(&self) -> Option<&Vec<Mount>> {
215        self.config.as_ref().and_then(|spec| spec.mounts().as_ref())
216    }
217
218    // clear_mounts clear g.Config.Mounts
219    pub fn clear_mounts(&mut self) {
220        if let Some(spec) = self.config.as_mut() {
221            spec.set_mounts(None);
222        }
223    }
224}
225
226// OrderedMounts defines how to sort an OCI Spec Mount slice.
227// This is the almost the same implementation sa used by CRI-O and Docker,
228// with a minor tweak for stable sorting order (easier to test):
229//
230//	https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26
231struct OrderedMounts(Vec<Mount>);
232
233#[allow(dead_code)]
234impl OrderedMounts {
235    fn new(mounts: Vec<Mount>) -> Self {
236        OrderedMounts(mounts)
237    }
238
239    // parts returns the number of parts in the destination of a mount. Used in sorting.
240    fn parts(&self, i: usize) -> usize {
241        self.0[i].destination().components().count()
242    }
243}
244
245impl Ord for OrderedMounts {
246    fn cmp(&self, other: &Self) -> Ordering {
247        let self_parts = self.parts(0);
248        let other_parts = other.parts(0);
249        self_parts
250            .cmp(&other_parts)
251            .then_with(|| self.0[0].destination().cmp(other.0[0].destination()))
252    }
253}
254
255impl PartialOrd for OrderedMounts {
256    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
257        Some(self.cmp(other))
258    }
259}
260
261impl PartialEq for OrderedMounts {
262    fn eq(&self, other: &Self) -> bool {
263        self.parts(0) == other.parts(0) && self.0[0].destination() == other.0[0].destination()
264    }
265}
266
267impl Eq for OrderedMounts {}