firecracker_rs_sdk/
firecracker.rs1use std::{
4 fs::{File, OpenOptions},
5 path::{Path, PathBuf},
6 process::{Command, Stdio},
7};
8
9use serde::{Deserialize, Serialize};
10
11use crate::{instance::Instance, Error, Result};
12
13pub const DEFAULT_API_SOCK: &'static str = "/run/firecracker.socket";
14pub const DEFAULT_HTTP_API_MAX_PAYLOAD_SIZE: usize = 51200;
15pub const DEFAULT_ID: &'static str = "anonymous-instance";
16
17#[derive(Debug, Clone, Default, Serialize, Deserialize)]
18pub struct FirecrackerOption {
19 firecracker_bin: PathBuf,
20
21 pub(crate) api_sock: Option<PathBuf>,
23
24 boot_timer: Option<bool>,
26
27 config_file: Option<PathBuf>,
29
30 describe_snapshot: Option<bool>,
32
33 http_api_max_payload_size: Option<usize>,
35
36 id: Option<String>,
38
39 level: Option<String>,
41
42 log_path: Option<PathBuf>,
44
45 metadata: Option<PathBuf>,
47
48 metrics_path: Option<PathBuf>,
50
51 mmds_size_limit: Option<PathBuf>,
53
54 module: Option<String>,
56
57 no_api: Option<bool>,
59
60 no_seccomp: Option<bool>,
62
63 parent_cpu_time_us: Option<usize>,
65
66 seccomp_filter: Option<String>,
68
69 show_level: Option<bool>,
71
72 show_log_origin: Option<bool>,
74
75 start_time_cpu_us: Option<usize>,
77
78 start_time_us: Option<usize>,
80
81 stdin: Option<PathBuf>,
83
84 stdout: Option<PathBuf>,
86
87 stderr: Option<PathBuf>,
89}
90
91impl FirecrackerOption {
92 pub fn new<P: AsRef<Path>>(firecracker_bin: P) -> Self {
93 Self {
94 firecracker_bin: firecracker_bin.as_ref().into(),
95 ..Default::default()
96 }
97 }
98
99 fn exec_file_name(&self) -> Result<PathBuf> {
100 let exec_file_name = self
101 .firecracker_bin
102 .file_name()
103 .ok_or_else(|| Error::Configuration("jailer `exec_file` ends with `..`".into()))?;
104 Ok(exec_file_name.into())
105 }
106
107 pub fn build(&mut self) -> Result<Instance> {
108 let mut command = self.build_cmd();
110
111 if let Some(ref stdin) = self.stdin {
113 command.stdin(Stdio::from(File::open(stdin)?));
114 }
115
116 if let Some(ref stdout) = self.stdout {
117 command.stdout(Stdio::from(
118 OpenOptions::new().create(true).write(true).open(stdout)?,
119 ));
120 }
121
122 if let Some(ref stderr) = self.stderr {
123 command.stderr(Stdio::from(
124 OpenOptions::new().create(true).write(true).open(stderr)?,
125 ));
126 }
127
128 let socket_on_host = self
129 .api_sock
130 .clone()
131 .unwrap_or_else(|| DEFAULT_API_SOCK.into());
132
133 Ok(Instance::new(
134 socket_on_host,
135 None,
136 None,
137 None,
138 command,
139 self.exec_file_name()?,
140 ))
141 }
142
143 pub(crate) fn build_cmd(&self) -> Command {
144 let mut cmd = Command::new(&self.firecracker_bin);
145
146 let api_sock = match self.api_sock {
147 Some(ref api_sock) => api_sock,
148 None => &DEFAULT_API_SOCK.into(),
149 };
150
151 cmd.arg("--api-sock").arg(api_sock);
158
159 if let Some(true) = self.boot_timer {
160 cmd.arg("--boot-timer");
161 }
162
163 if let Some(ref config_file) = self.config_file {
164 cmd.arg("--config-file").arg(config_file);
165 }
166
167 if let Some(ref http_api_max_payload_size) = self.http_api_max_payload_size {
168 cmd.arg("--http-api-max-payload-size")
169 .arg(http_api_max_payload_size.to_string());
170 }
171
172 if let Some(ref id) = self.id {
173 cmd.arg("--id").arg(id);
174 }
175
176 if let Some(ref level) = self.level {
177 cmd.arg("--level").arg(level);
178 }
179
180 if let Some(ref log_path) = self.log_path {
181 cmd.arg("--log-path").arg(log_path);
182 }
183
184 if let Some(ref metadata) = self.metadata {
185 cmd.arg("--metadata").arg(metadata);
186 }
187
188 if let Some(ref metrics_path) = self.metrics_path {
189 cmd.arg("--metrics-path").arg(metrics_path);
190 }
191
192 if let Some(ref mmds_size_limit) = self.mmds_size_limit {
193 cmd.arg("--mmds-size-limit").arg(mmds_size_limit);
194 }
195
196 if let Some(ref module) = self.module {
197 cmd.arg("--module").arg(module);
198 }
199
200 if let Some(true) = self.no_api {
201 cmd.arg("--no-api");
202 }
203
204 if let Some(true) = self.no_seccomp {
205 cmd.arg("--no-seccomp");
206 }
207
208 if let Some(ref parent_cpu_time_us) = self.parent_cpu_time_us {
209 cmd.arg("--parent-cpu-time-us")
210 .arg(parent_cpu_time_us.to_string());
211 }
212
213 if let Some(ref seccomp_filter) = self.seccomp_filter {
214 cmd.arg("--seccomp-filter").arg(seccomp_filter);
215 }
216
217 if let Some(true) = self.show_level {
218 cmd.arg("--show-level");
219 }
220
221 if let Some(true) = self.show_log_origin {
222 cmd.arg("--show-log-origin");
223 }
224
225 if let Some(ref start_time_cpu_us) = self.start_time_cpu_us {
226 cmd.arg("--start-time-cpu-us")
227 .arg(start_time_cpu_us.to_string());
228 }
229
230 if let Some(ref start_time_us) = self.start_time_us {
231 cmd.arg("--start-time-us").arg(start_time_us.to_string());
232 }
233
234 cmd
235 }
236
237 pub fn api_sock<P: AsRef<Path>>(&mut self, api_sock: P) -> &mut Self {
238 self.api_sock = Some(api_sock.as_ref().into());
239 self
240 }
241
242 pub fn boot_timer(&mut self) -> &mut Self {
243 self.boot_timer = Some(true);
244 self
245 }
246
247 pub fn config_file<P: AsRef<Path>>(&mut self, config_file: Option<P>) -> &mut Self {
248 self.config_file = config_file.and_then(|x| Some(x.as_ref().to_path_buf()));
249 self
250 }
251
252 pub fn http_api_max_payload_size(
253 &mut self,
254 http_api_max_payload_size: usize,
255 ) -> &mut Self {
256 self.http_api_max_payload_size = Some(http_api_max_payload_size);
257 self
258 }
259
260 pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
261 self.id = Some(id.as_ref().to_string());
262 self
263 }
264
265 pub fn level<S: AsRef<str>>(&mut self, level: S) -> &mut Self {
266 self.level = Some(level.as_ref().to_string());
267 self
268 }
269
270 pub fn log_path<P: AsRef<Path>>(&mut self, log_path: Option<P>) -> &mut Self {
271 self.log_path = log_path.and_then(|x| Some(x.as_ref().to_path_buf()));
272 self
273 }
274
275 pub fn metadata<P: AsRef<Path>>(&mut self, metadata: Option<P>) -> &mut Self {
276 self.metadata = metadata.and_then(|x| Some(x.as_ref().to_path_buf()));
277 self
278 }
279
280 pub fn metrics_path<P: AsRef<Path>>(&mut self, metrics_path: Option<P>) -> &mut Self {
281 self.metrics_path = metrics_path.and_then(|x| Some(x.as_ref().to_path_buf()));
282 self
283 }
284
285 pub fn mmds_size_limit<P: AsRef<Path>>(&mut self, mmds_size_limit: Option<P>) -> &mut Self {
286 self.mmds_size_limit = mmds_size_limit.and_then(|x| Some(x.as_ref().to_path_buf()));
287 self
288 }
289
290 pub fn module<S: AsRef<str>>(&mut self, module: S) -> &mut Self {
291 self.module = Some(module.as_ref().to_string());
292 self
293 }
294
295 pub fn no_api(&mut self) -> &mut Self {
296 self.no_api = Some(true);
297 self
298 }
299
300 pub fn no_seccomp(&mut self) -> &mut Self {
301 self.no_seccomp = Some(true);
302 self
303 }
304
305 pub fn parent_cpu_time_us(&mut self, parent_cpu_time_us: usize) -> &mut Self {
306 self.parent_cpu_time_us = Some(parent_cpu_time_us);
307 self
308 }
309
310 pub fn seccomp_filter<S: AsRef<str>>(&mut self, seccomp_filter: S) -> &mut Self {
311 self.seccomp_filter = Some(seccomp_filter.as_ref().to_string());
312 self
313 }
314
315 pub fn show_level(&mut self) -> &mut Self {
316 self.show_level = Some(true);
317 self
318 }
319
320 pub fn show_log_origin(&mut self) -> &mut Self {
321 self.show_log_origin = Some(true);
322 self
323 }
324
325 pub fn start_time_cpu_us(&mut self, start_time_cpu_us: usize) -> &mut Self {
326 self.start_time_cpu_us = Some(start_time_cpu_us);
327 self
328 }
329
330 pub fn start_time_us(&mut self, start_time_us: usize) -> &mut Self {
331 self.start_time_us = Some(start_time_us);
332 self
333 }
334
335 pub fn stdin<P: AsRef<Path>>(&mut self, stdin: P) -> &mut Self {
336 self.stdin = Some(stdin.as_ref().into());
337 self
338 }
339
340 pub fn stdout<P: AsRef<Path>>(&mut self, stdout: P) -> &mut Self {
341 self.stdout = Some(stdout.as_ref().into());
342 self
343 }
344
345 pub fn stderr<P: AsRef<Path>>(&mut self, stderr: P) -> &mut Self {
346 self.stderr = Some(stderr.as_ref().into());
347 self
348 }
349}