cloud_hypervisor_command_builder/
lib.rs

1pub mod to_command;
2
3use std::fmt::{Display, Formatter};
4use std::net::IpAddr;
5use std::path::PathBuf;
6
7use bytesize::ByteSize;
8use derive_builder::Builder;
9use serde::{Deserialize, Serialize};
10
11use crate::to_command::ToCommand;
12
13#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
14pub enum OnOff {
15    On,
16    Off,
17}
18
19impl Display for OnOff {
20    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21        match self {
22            OnOff::On => {
23                write!(f, "on")
24            }
25            OnOff::Off => {
26                write!(f, "off")
27            }
28        }
29    }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
33pub enum PathOrFileDescriptorOption {
34    Path(PathBuf),
35    Fd(usize),
36}
37
38#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
39pub struct CloudHypervisorInstance {
40    bin_path: PathBuf,
41    cpus: Option<Cpus>,
42    platform: Option<Platform>,
43    memory: Option<Memory>,
44    memory_zone: Option<MemoryZone>,
45    firmware: Option<PathBuf>,
46    kernel: Option<PathBuf>,
47    initramfs: Option<PathBuf>,
48    cmdline: Option<String>,
49    rate_limit_group: Option<Vec<RateLimitGroup>>,
50    disk: Option<Vec<Disk>>,
51    net: Option<Vec<Net>>,
52    rng: Option<Rng>,
53    balloon: Option<Balloon>,
54    fs: Option<Vec<Fs>>,
55    pmem: Option<Vec<Pmem>>,
56    serial: Option<Serial>,
57    console: Option<Console>,
58    device: Option<Vec<Device>>,
59    user_device: Option<Vec<UserDevice>>,
60    vdpa: Option<Vec<Vdpa>>,
61    vsock: Option<Vsock>,
62    pvpanic: Option<bool>,
63    numa: Option<Vec<Numa>>,
64    watchdog: Option<bool>,
65    log_file: Option<PathBuf>,
66    api_socket: Option<PathOrFileDescriptorOption>,
67    event_monitor: Option<PathOrFileDescriptorOption>,
68    restore: Option<Restore>,
69    seccomp: Option<SecComp>,
70    tpm: Option<PathBuf>,
71    sgx_epc: Option<Vec<SgxEpc>>,
72    debug_console: Option<DebugConsole>,
73    v: Option<u8>,
74}
75
76impl CloudHypervisorInstance {
77    pub fn new(bin_path: PathBuf) -> Self {
78        CloudHypervisorInstance {
79            bin_path,
80            ..Self::default()
81        }
82    }
83
84    pub fn cpus(&mut self, cpus: Cpus) -> &mut Self {
85        self.cpus = Some(cpus);
86        self
87    }
88    pub fn platform(&mut self, platform: Platform) -> &mut Self {
89        self.platform = Some(platform);
90        self
91    }
92    pub fn memory(&mut self, memory: Memory) -> &mut Self {
93        self.memory = Some(memory);
94        self
95    }
96    pub fn memory_zone(&mut self, memory_zone: MemoryZone) -> &mut Self {
97        self.memory_zone = Some(memory_zone);
98        self
99    }
100    pub fn firmware(&mut self, firmware: PathBuf) -> &mut Self {
101        self.firmware = Some(firmware);
102        self
103    }
104    pub fn kernel(&mut self, kernel: PathBuf) -> &mut Self {
105        self.kernel = Some(kernel);
106        self
107    }
108    pub fn initramfs(&mut self, initramfs: PathBuf) -> &mut Self {
109        self.initramfs = Some(initramfs);
110        self
111    }
112    pub fn cmdline(&mut self, cmdline: String) -> &mut Self {
113        self.cmdline = Some(cmdline);
114        self
115    }
116    pub fn rate_limit_group(&mut self, rate_limit_group: RateLimitGroup) -> &mut Self {
117        match &mut self.rate_limit_group {
118            None => {
119                self.rate_limit_group = Some(vec![rate_limit_group]);
120            }
121            Some(rate_limit_groups) => {
122                rate_limit_groups.push(rate_limit_group);
123            }
124        }
125        self
126    }
127    pub fn disk(&mut self, disk: Disk) -> &mut Self {
128        match &mut self.disk {
129            None => {
130                self.disk = Some(vec![disk]);
131            }
132            Some(disks) => {
133                disks.push(disk);
134            }
135        }
136        self
137    }
138    pub fn net(&mut self, net: Net) -> &mut Self {
139        match &mut self.net {
140            None => {
141                self.net = Some(vec![net]);
142            }
143            Some(nets) => {
144                nets.push(net);
145            }
146        }
147        self
148    }
149    pub fn rng(&mut self, rng: Rng) -> &mut Self {
150        self.rng = Some(rng);
151        self
152    }
153    pub fn balloon(&mut self, balloon: Balloon) -> &mut Self {
154        self.balloon = Some(balloon);
155        self
156    }
157    pub fn fs(&mut self, fs: Fs) -> &mut Self {
158        match &mut self.fs {
159            None => {
160                self.fs = Some(vec![fs]);
161            }
162            Some(fss) => {
163                fss.push(fs);
164            }
165        }
166        self
167    }
168    pub fn pmem(&mut self, pmem: Pmem) -> &mut Self {
169        match &mut self.pmem {
170            None => {
171                self.pmem = Some(vec![pmem]);
172            }
173            Some(pmems) => {
174                pmems.push(pmem);
175            }
176        }
177        self
178    }
179    pub fn serial(&mut self, serial: Serial) -> &mut Self {
180        self.serial = Some(serial);
181        self
182    }
183    pub fn console(&mut self, console: Console) -> &mut Self {
184        self.console = Some(console);
185        self
186    }
187    pub fn device(&mut self, device: Device) -> &mut Self {
188        match &mut self.device {
189            None => {
190                self.device = Some(vec![device]);
191            }
192            Some(devices) => {
193                devices.push(device);
194            }
195        }
196
197        self
198    }
199    pub fn user_device(&mut self, user_device: UserDevice) -> &mut Self {
200        match &mut self.user_device {
201            None => {
202                self.user_device = Some(vec![user_device]);
203            }
204            Some(user_devices) => {
205                user_devices.push(user_device);
206            }
207        }
208        self
209    }
210    pub fn vdpa(&mut self, vdpa: Vdpa) -> &mut Self {
211        match &mut self.vdpa {
212            None => {
213                self.vdpa = Some(vec![vdpa]);
214            }
215            Some(vdpas) => {
216                vdpas.push(vdpa);
217            }
218        }
219        self
220    }
221    pub fn vsock(&mut self, vsock: Vsock) -> &mut Self {
222        self.vsock = Some(vsock);
223        self
224    }
225    pub fn pvpanic(&mut self, pvpanic: bool) -> &mut Self {
226        self.pvpanic = Some(pvpanic);
227        self
228    }
229    pub fn numa(&mut self, numa: Numa) -> &mut Self {
230        match &mut self.numa {
231            None => {
232                self.numa = Some(vec![numa]);
233            }
234            Some(numas) => {
235                numas.push(numa);
236            }
237        }
238        self
239    }
240    pub fn watchdog(&mut self, watchdog: bool) -> &mut Self {
241        self.watchdog = Some(watchdog);
242        self
243    }
244    pub fn log_file(&mut self, log_file: PathBuf) -> &mut Self {
245        self.log_file = Some(log_file);
246        self
247    }
248    pub fn api_socket(&mut self, api_socket: PathOrFileDescriptorOption) -> &mut Self {
249        self.api_socket = Some(api_socket);
250        self
251    }
252    pub fn event_monitor(&mut self, event_monitor: PathOrFileDescriptorOption) -> &mut Self {
253        self.event_monitor = Some(event_monitor);
254        self
255    }
256    pub fn restore(&mut self, restore: Restore) -> &mut Self {
257        self.restore = Some(restore);
258        self
259    }
260    pub fn seccomp(&mut self, seccomp: SecComp) -> &mut Self {
261        self.seccomp = Some(seccomp);
262        self
263    }
264    pub fn tpm(&mut self, tpm: PathBuf) -> &mut Self {
265        self.tpm = Some(tpm);
266        self
267    }
268    pub fn sgx_epc(&mut self, sgx_epc: SgxEpc) -> &mut Self {
269        match &mut self.sgx_epc {
270            None => {
271                self.sgx_epc = Some(vec![sgx_epc]);
272            }
273            Some(sgx_epcs) => {
274                sgx_epcs.push(sgx_epc);
275            }
276        }
277
278        self
279    }
280    pub fn debug_console(&mut self, debug_console: DebugConsole) -> &mut Self {
281        self.debug_console = Some(debug_console);
282        self
283    }
284    pub fn v(&mut self) -> &mut Self {
285        match &mut self.v {
286            None => self.v = Some(1),
287            Some(v) => {
288                *v += 1;
289            }
290        }
291        self
292    }
293}
294
295impl ToCommand for CloudHypervisorInstance {
296    fn to_command(&self) -> Vec<String> {
297        let mut cmd = vec![self.bin_path.display().to_string()];
298
299        if let Some(cpus) = &self.cpus {
300            cmd.append(cpus.to_command().as_mut());
301        }
302        if let Some(platform) = &self.platform {
303            cmd.append(platform.to_command().as_mut());
304        }
305        if let Some(memory) = &self.memory {
306            cmd.append(memory.to_command().as_mut());
307        }
308        if let Some(memory_zone) = &self.memory_zone {
309            cmd.append(memory_zone.to_command().as_mut());
310        }
311        if let Some(firmware) = &self.firmware {
312            cmd.push("--firmware".to_string());
313            cmd.push(firmware.display().to_string());
314        }
315        if let Some(kernel) = &self.kernel {
316            cmd.push("--kernel".to_string());
317            cmd.push(kernel.display().to_string());
318        }
319        if let Some(initramfs) = &self.initramfs {
320            cmd.push("--initramfs".to_string());
321            cmd.push(initramfs.display().to_string());
322        }
323        if let Some(cmdline) = &self.cmdline {
324            cmd.push("--cmdline".to_string());
325            cmd.push(cmdline.to_string());
326        }
327        if let Some(rate_limit_groups) = &self.rate_limit_group {
328            let mut arg = vec![];
329            for rate_limit_group in rate_limit_groups {
330                if let Some(bw_size) = &rate_limit_group.bw_size {
331                    arg.push(format!("bw_size={}", bw_size.0));
332                }
333                if let Some(bw_one_time_burst) = &rate_limit_group.bw_one_time_burst {
334                    arg.push(format!("bw_one_time_burst={}", bw_one_time_burst));
335                }
336                if let Some(bw_refill_time) = &rate_limit_group.bw_refill_time {
337                    arg.push(format!("bw_refill_time={}", bw_refill_time));
338                }
339                if let Some(ops_size) = &rate_limit_group.ops_size {
340                    arg.push(format!("ops_size={}", ops_size));
341                }
342                if let Some(ops_one_time_burst) = &rate_limit_group.ops_one_time_burst {
343                    arg.push(format!("ops_one_time_burst={}", ops_one_time_burst));
344                }
345                if let Some(ops_refill_time) = &rate_limit_group.ops_refill_time {
346                    arg.push(format!("ops_refill_time={}", ops_refill_time));
347                }
348                if let Some(id) = &rate_limit_group.id {
349                    arg.push(format!("id={}", id));
350                }
351                if !arg.is_empty() {
352                    cmd.push("--rate_limit_group".to_string());
353                    cmd.push(arg.join(","));
354                }
355            }
356        }
357        if let Some(disks) = &self.disk {
358            if !disks.is_empty() {
359                let mut added = false;
360
361                for disk in disks {
362                    let mut arg = vec![];
363                    if let Some(path) = &disk.path {
364                        arg.push(format!("path={}", path.display()));
365                    }
366                    if let Some(readonly) = &disk.readonly {
367                        arg.push(format!("readonly={}", readonly));
368                    }
369                    if let Some(direct) = &disk.direct {
370                        arg.push(format!("direct={}", direct));
371                    }
372                    if let Some(iommu) = &disk.iommu {
373                        arg.push(format!("iommu={}", iommu));
374                    }
375                    if let Some(num_queues) = &disk.num_queues {
376                        arg.push(format!("num_queues={}", num_queues));
377                    }
378                    if let Some(queue_size) = &disk.queue_size {
379                        arg.push(format!("queue_size={}", queue_size));
380                    }
381                    if let Some(vhost_user) = &disk.vhost_user {
382                        arg.push(format!("vhost_user={}", vhost_user));
383                    }
384                    if let Some(socket) = &disk.socket {
385                        arg.push(format!("socket={}", socket.display()));
386                    }
387                    if let Some(bw_size) = &disk.bw_size {
388                        arg.push(format!("bw_size={}", bw_size.0));
389                    }
390                    if let Some(bw_one_time_burst) = &disk.bw_one_time_burst {
391                        arg.push(format!("bw_one_time_burst={}", bw_one_time_burst));
392                    }
393                    if let Some(bw_refill_time) = &disk.bw_refill_time {
394                        arg.push(format!("bw_refill_time={}", bw_refill_time));
395                    }
396                    if let Some(ops_size) = &disk.ops_size {
397                        arg.push(format!("ops_size={}", ops_size));
398                    }
399                    if let Some(ops_one_time_burst) = &disk.ops_one_time_burst {
400                        arg.push(format!("ops_one_time_burst={}", ops_one_time_burst));
401                    }
402                    if let Some(ops_refill_time) = &disk.ops_refill_time {
403                        arg.push(format!("ops_refill_time={}", ops_refill_time));
404                    }
405                    if let Some(id) = &disk.id {
406                        arg.push(format!("id={}", id));
407                    }
408                    if let Some(pci_segment) = &disk.pci_segment {
409                        arg.push(format!("pci_segment={}", pci_segment));
410                    }
411                    if let Some(rate_limit_group) = &disk.rate_limit_group {
412                        arg.push(format!("rate_limit_group={}", rate_limit_group));
413                    }
414                    if let Some(queue_affinity) = &disk.queue_affinity {
415                        arg.push(format!("queue_affinity={}", queue_affinity));
416                    }
417                    if !arg.is_empty() {
418                        if !added {
419                            cmd.push("--disk".to_string());
420                            added = true;
421                        }
422                        cmd.push(arg.join(","));
423                    }
424                }
425            }
426        }
427        if let Some(nets) = &self.net {
428            if !nets.is_empty() {
429                let mut added = false;
430
431                for net in nets {
432                    let mut arg = vec![];
433
434                    if let Some(tap) = &net.tap {
435                        arg.push(format!("tap={}", tap));
436                    }
437                    if let Some(ip) = &net.ip {
438                        arg.push(format!("ip={}", ip));
439                    }
440                    if let Some(mask) = &net.mask {
441                        arg.push(format!("mask={}", mask));
442                    }
443                    if let Some(mac) = &net.mac {
444                        arg.push(format!("mac={}", mac));
445                    }
446                    if let Some(fd) = &net.fd {
447                        arg.push(format!(
448                            "fd={}",
449                            fd.iter()
450                                .map(|v| v.to_string())
451                                .collect::<Vec<String>>()
452                                .join(",")
453                        ));
454                    }
455                    if let Some(iommu) = &net.iommu {
456                        arg.push(format!("iommu={}", iommu));
457                    }
458                    if let Some(num_queues) = &net.num_queues {
459                        arg.push(format!("num_queues={}", num_queues));
460                    }
461                    if let Some(queue_size) = &net.queue_size {
462                        arg.push(format!("queue_size={}", queue_size));
463                    }
464                    if let Some(id) = &net.id {
465                        arg.push(format!("id={}", id));
466                    }
467                    if let Some(vhost_user) = &net.vhost_user {
468                        arg.push(format!("vhost_user={}", vhost_user));
469                    }
470                    if let Some(socket) = &net.socket {
471                        arg.push(format!("socket={}", socket.display()));
472                    }
473                    if let Some(vhost_mode) = &net.vhost_mode {
474                        arg.push(format!("vhost_mode={}", vhost_mode));
475                    }
476                    if let Some(bw_size) = &net.bw_size {
477                        arg.push(format!("bw_size={}", bw_size.0));
478                    }
479                    if let Some(bw_one_time_burst) = &net.bw_one_time_burst {
480                        arg.push(format!("bw_one_time_burst={}", bw_one_time_burst));
481                    }
482                    if let Some(bw_refill_time) = &net.bw_refill_time {
483                        arg.push(format!("bw_refill_time={}", bw_refill_time));
484                    }
485                    if let Some(ops_size) = &net.ops_size {
486                        arg.push(format!("ops_size={}", ops_size));
487                    }
488                    if let Some(ops_one_time_burst) = &net.ops_one_time_burst {
489                        arg.push(format!("ops_one_time_burst={}", ops_one_time_burst));
490                    }
491                    if let Some(ops_refill_time) = &net.ops_refill_time {
492                        arg.push(format!("ops_refill_time={}", ops_refill_time));
493                    }
494                    if let Some(pci_segment) = &net.pci_segment {
495                        arg.push(format!("pci_segment={}", pci_segment));
496                    }
497                    if let Some(offload_tso) = &net.offload_tso {
498                        arg.push(format!("offload_tso={}", offload_tso));
499                    }
500                    if let Some(offload_ufo) = &net.offload_ufo {
501                        arg.push(format!("offload_ufo={}", offload_ufo));
502                    }
503                    if let Some(offload_csum) = &net.offload_csum {
504                        arg.push(format!("offload_csum={}", offload_csum));
505                    }
506                    if !arg.is_empty() {
507                        if !added {
508                            cmd.push("--net".to_string());
509                            added = true;
510                        }
511                        cmd.push(arg.join(","));
512                    }
513                }
514            }
515        }
516        if let Some(rng) = &self.rng {
517            cmd.push("--rng".to_string());
518            match rng {
519                Rng::Src(path) => {
520                    cmd.push(format!("src={}", path.display()));
521                }
522                Rng::Iommu(state) => {
523                    cmd.push(format!("iommu={}", state));
524                }
525            }
526        }
527        if let Some(balloon) = &self.balloon {
528            let mut arg = vec![];
529            if let Some(size) = &balloon.size {
530                arg.push(format!("size={}", size.0));
531            }
532            if let Some(deflate_on_oom) = &balloon.deflate_on_oom {
533                arg.push(format!("deflate_on_oom={}", deflate_on_oom));
534            }
535            if let Some(free_page_reporting) = &balloon.free_page_reporting {
536                arg.push(format!("free_page_reporting={}", free_page_reporting));
537            }
538            if !arg.is_empty() {
539                cmd.push("--balloon".to_string());
540                cmd.push(arg.join(","));
541            }
542        }
543        if let Some(fss) = &self.fs {
544            if !fss.is_empty() {
545                let mut added = false;
546
547                for fs in fss {
548                    let mut arg = vec![];
549                    if let Some(tag) = &fs.tag {
550                        arg.push(format!("tag={}", tag));
551                    }
552                    if let Some(socket) = &fs.socket {
553                        arg.push(format!("socket={}", socket.display()));
554                    }
555                    if let Some(num_queues) = &fs.num_queues {
556                        arg.push(format!("num_queues={}", num_queues));
557                    }
558                    if let Some(queue_size) = &fs.queue_size {
559                        arg.push(format!("queue_size={}", queue_size));
560                    }
561                    if let Some(id) = &fs.id {
562                        arg.push(format!("id={}", id));
563                    }
564                    if let Some(pci_segment) = &fs.pci_segment {
565                        arg.push(format!("pci_segment={}", pci_segment));
566                    }
567                    if !arg.is_empty() {
568                        if !added {
569                            cmd.push("--fs".to_string());
570                            added = true;
571                        }
572                        cmd.push(arg.join(","));
573                    }
574                }
575            }
576        }
577        if let Some(pmems) = &self.pmem {
578            if !pmems.is_empty() {
579                let mut added = false;
580
581                for pmem in pmems {
582                    let mut arg = vec![];
583
584                    if let Some(path) = &pmem.file {
585                        arg.push(format!("file={}", path.display()));
586                    }
587                    if let Some(size) = &pmem.size {
588                        arg.push(format!("size={}", size));
589                    }
590                    if let Some(iommu) = &pmem.iommu {
591                        arg.push(format!("iommu={}", iommu));
592                    }
593                    if let Some(discard_writes) = &pmem.discard_writes {
594                        arg.push(format!("discard_writes={}", discard_writes));
595                    }
596                    if let Some(id) = &pmem.id {
597                        arg.push(format!("id={}", id));
598                    }
599                    if let Some(pci_segment) = &pmem.pci_segment {
600                        arg.push(format!("pci_segment={}", pci_segment));
601                    }
602                    if !arg.is_empty() {
603                        if !added {
604                            cmd.push("--pmem".to_string());
605                            added = true;
606                        }
607                        cmd.push(arg.join(","));
608                    }
609                }
610            }
611        }
612        if let Some(serial) = &self.serial {
613            cmd.push("--serial".to_string());
614            match serial {
615                Serial::Off => {
616                    cmd.push("off".to_string());
617                }
618                Serial::Null => {
619                    cmd.push("null".to_string());
620                }
621                Serial::Pty => {
622                    cmd.push("pty".to_string());
623                }
624                Serial::Tty => {
625                    cmd.push("tty".to_string());
626                }
627                Serial::File(path) => cmd.push(format!("file={}", path.display())),
628                Serial::Socket(path) => cmd.push(format!("socket={}", path.display())),
629            }
630        }
631        if let Some(console) = &self.console {
632            cmd.push("--console".to_string());
633            match console {
634                Console::Off => {
635                    cmd.push("off".to_string());
636                }
637                Console::Null => {
638                    cmd.push("null".to_string());
639                }
640                Console::Pty => {
641                    cmd.push("pty".to_string());
642                }
643                Console::Tty => {
644                    cmd.push("tty".to_string());
645                }
646                Console::File(path) => cmd.push(format!("file={}", path.display())),
647                Console::Iommu(state) => {
648                    cmd.push(format!("iommu={}", state));
649                }
650            }
651        }
652        if let Some(devices) = &self.device {
653            if !devices.is_empty() {
654                let mut added = false;
655
656                for device in devices {
657                    let mut arg = vec![];
658
659                    if let Some(path) = &device.path {
660                        arg.push(format!("path={}", path.display()));
661                    }
662                    if let Some(iommu) = &device.iommu {
663                        arg.push(format!("iommu={}", iommu));
664                    }
665                    if let Some(id) = &device.id {
666                        arg.push(format!("id={}", id));
667                    }
668                    if let Some(pci_segment) = &device.pci_segment {
669                        arg.push(format!("pci_segment={}", pci_segment));
670                    }
671                    if !arg.is_empty() {
672                        if !added {
673                            cmd.push("--device".to_string());
674                            added = true;
675                        }
676                        cmd.push(arg.join(","));
677                    }
678                }
679            }
680        }
681        if let Some(user_devices) = &self.user_device {
682            if !user_devices.is_empty() {
683                let mut added = false;
684
685                for user_device in user_devices {
686                    let mut arg = vec![];
687
688                    if let Some(path) = &user_device.socket {
689                        arg.push(format!("socket={}", path.display()));
690                    }
691                    if let Some(id) = &user_device.id {
692                        arg.push(format!("id={}", id));
693                    }
694                    if let Some(pci_segment) = &user_device.pci_segment {
695                        arg.push(format!("pci_segment={}", pci_segment));
696                    }
697                    if !arg.is_empty() {
698                        if !added {
699                            cmd.push("--user-device".to_string());
700                            added = true;
701                        }
702                        cmd.push(arg.join(","));
703                    }
704                }
705            }
706        }
707        if let Some(vsock) = &self.vsock {
708            let mut arg = vec![];
709            if let Some(cid) = &vsock.cid {
710                arg.push(format!("cid={}", cid));
711            }
712            if let Some(path) = &vsock.socket {
713                arg.push(format!("socket={}", path.display()));
714            }
715            if let Some(iommu) = &vsock.iommu {
716                arg.push(format!("iommu={}", iommu));
717            }
718            if let Some(id) = &vsock.id {
719                arg.push(format!("id={}", id));
720            }
721            if let Some(pci_segment) = &vsock.pci_segment {
722                arg.push(format!("pci_segment={}", pci_segment));
723            }
724            if !arg.is_empty() {
725                cmd.push("--vsock".to_string());
726                cmd.push(arg.join(","));
727            }
728        }
729        if let Some(vdpas) = &self.vdpa {
730            if !vdpas.is_empty() {
731                let mut added = false;
732
733                for vdpa in vdpas {
734                    let mut arg = vec![];
735                    if let Some(path) = &vdpa.path {
736                        arg.push(format!("path={}", path.display()));
737                    }
738                    if let Some(num_queues) = &vdpa.num_queues {
739                        arg.push(format!("num_queues={}", num_queues));
740                    }
741                    if let Some(iommu) = &vdpa.iommu {
742                        arg.push(format!("iommu={}", iommu));
743                    }
744                    if let Some(id) = &vdpa.id {
745                        arg.push(format!("id={}", id));
746                    }
747                    if let Some(pci_segment) = &vdpa.pci_segment {
748                        arg.push(format!("pci_segment={}", pci_segment));
749                    }
750                    if !arg.is_empty() {
751                        if !added {
752                            cmd.push("--vdpa".to_string());
753                            added = true;
754                        }
755                        cmd.push(arg.join(","));
756                    }
757                }
758            }
759        }
760        if let Some(pvpanic) = self.pvpanic {
761            if pvpanic {
762                cmd.push("--pvpanic".to_string());
763            }
764        }
765        if let Some(numas) = &self.numa {
766            if !numas.is_empty() {
767                let mut added = false;
768
769                for numa in numas {
770                    let mut arg = vec![];
771                    if let Some(guest_numa_id) = &numa.guest_numa_id {
772                        arg.push(format!("guest_numa_id={}", guest_numa_id));
773                    }
774                    if let Some(cpus) = &numa.cpus {
775                        arg.push(format!(
776                            "cpus={}",
777                            cpus.iter()
778                                .map(|v| v.to_string())
779                                .collect::<Vec<String>>()
780                                .join(",")
781                        ));
782                    }
783                    if let Some(distances) = &numa.distances {
784                        arg.push(format!(
785                            "distances={}",
786                            distances
787                                .iter()
788                                .map(|v| v.to_string())
789                                .collect::<Vec<String>>()
790                                .join(",")
791                        ));
792                    }
793                    if let Some(memory_zones) = &numa.memory_zones {
794                        arg.push(format!(
795                            "memory_zones={}",
796                            memory_zones
797                                .iter()
798                                .map(|v| v.to_string())
799                                .collect::<Vec<String>>()
800                                .join(",")
801                        ));
802                    }
803                    if let Some(sgx_epc_sections) = &numa.sgx_epc_sections {
804                        arg.push(format!(
805                            "sgx_epc_sections={}",
806                            sgx_epc_sections
807                                .iter()
808                                .map(|v| v.to_string())
809                                .collect::<Vec<String>>()
810                                .join(",")
811                        ));
812                    }
813                    if let Some(pci_segments) = &numa.pci_segments {
814                        arg.push(format!(
815                            "pci_segments={}",
816                            pci_segments
817                                .iter()
818                                .map(|v| v.to_string())
819                                .collect::<Vec<String>>()
820                                .join(",")
821                        ));
822                    }
823                    if !arg.is_empty() {
824                        if !added {
825                            cmd.push("--numa".to_string());
826                            added = true;
827                        }
828                        cmd.push(arg.join(","));
829                    }
830                }
831            }
832        }
833        if let Some(watchdog) = self.watchdog {
834            if watchdog {
835                cmd.push("--watchdog".to_string());
836            }
837        }
838        if let Some(log_file) = &self.log_file {
839            cmd.push("--log-file".to_string());
840            cmd.push(log_file.display().to_string());
841        }
842        if let Some(api_socket) = &self.api_socket {
843            cmd.push("--api-socket".to_string());
844            match api_socket {
845                PathOrFileDescriptorOption::Path(path) => {
846                    cmd.push(format!("path={}", path.display()));
847                }
848                PathOrFileDescriptorOption::Fd(fd) => {
849                    cmd.push(format!("fd={}", fd));
850                }
851            }
852        }
853        if let Some(event_monitor) = &self.event_monitor {
854            cmd.push("--event-monitor".to_string());
855            match event_monitor {
856                PathOrFileDescriptorOption::Path(path) => {
857                    cmd.push(format!("path={}", path.display()));
858                }
859                PathOrFileDescriptorOption::Fd(fd) => {
860                    cmd.push(format!("fd={}", fd));
861                }
862            }
863        }
864        if let Some(restore) = &self.restore {
865            let mut arg = vec![];
866            if let Some(source_url) = &restore.source_url {
867                arg.push(format!("source_url={}", source_url));
868            }
869            if let Some(prefault) = &restore.prefault {
870                arg.push(format!("prefault={}", prefault));
871            }
872            if !arg.is_empty() {
873                cmd.push("--restore".to_string());
874                cmd.push(arg.join(","));
875            }
876        }
877        if let Some(seccomp) = &self.seccomp {
878            cmd.push("--seccomp".to_string());
879            match seccomp {
880                SecComp::True => {
881                    cmd.push("true".to_string());
882                }
883                SecComp::False => {
884                    cmd.push("false".to_string());
885                }
886                SecComp::Log => {
887                    cmd.push("log".to_string());
888                }
889            }
890        }
891        if let Some(tpm) = &self.tpm {
892            cmd.push("--tpm".to_string());
893            cmd.push(tpm.display().to_string());
894        }
895        if let Some(sgx_epcs) = &self.sgx_epc {
896            if !sgx_epcs.is_empty() {
897                let mut added = false;
898
899                for sgx_epc in sgx_epcs {
900                    let mut arg = vec![];
901                    if let Some(id) = &sgx_epc.id {
902                        arg.push(format!("id={}", id));
903                    }
904                    if let Some(size) = &sgx_epc.size {
905                        arg.push(format!("size={}", size));
906                    }
907                    if let Some(prefault) = &sgx_epc.prefault {
908                        arg.push(format!("prefault={}", prefault));
909                    }
910                    if !arg.is_empty() {
911                        if !added {
912                            cmd.push("--sgx-epc".to_string());
913                            added = true;
914                        }
915                        cmd.push(arg.join(","));
916                    }
917                }
918            }
919        }
920        if let Some(debug_console) = &self.debug_console {
921            let mut arg = vec![];
922            if let Some(ctype) = &debug_console.console_type {
923                match ctype {
924                    DebugConsoleType::Off => {
925                        arg.push("off".to_string());
926                    }
927                    DebugConsoleType::Pty => arg.push("pty".to_string()),
928                    DebugConsoleType::Tty => arg.push("tty".to_string()),
929                    DebugConsoleType::File(path) => {
930                        arg.push(format!("file={}", path.display()));
931                    }
932                }
933            }
934            if let Some(iobase) = &debug_console.iobase {
935                arg.push(format!("iobase={}", iobase));
936            }
937            if !arg.is_empty() {
938                cmd.push("--debug-console".to_string());
939                cmd.push(arg.join(","));
940            }
941        }
942        if let Some(v) = self.v {
943            for _ in 0..v {
944                cmd.push("-v".to_string());
945            }
946        }
947        cmd
948    }
949}
950
951#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
952#[builder(setter(strip_option), default)]
953pub struct CpuAffinity {
954    pub vcpu: u8,
955    pub host_cpus: Vec<usize>,
956}
957
958#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
959#[builder(setter(strip_option), default)]
960pub struct CpuFeatures {
961    pub amx: Option<bool>,
962}
963
964#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
965#[builder(setter(strip_option), default)]
966pub struct CpuTopology {
967    pub threads_per_core: u8,
968    pub cores_per_die: u8,
969    pub dies_per_package: u8,
970    pub packages: u8,
971}
972
973#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
974#[builder(setter(strip_option), default)]
975pub struct Cpus {
976    pub boot: Option<u8>,
977    pub max: Option<u8>,
978    pub topology: Option<CpuTopology>,
979    pub kvm_hyperv: Option<OnOff>,
980    pub max_phys_bits: Option<u8>,
981    pub affinity: Option<Vec<CpuAffinity>>,
982    pub features: Option<CpuFeatures>,
983}
984
985impl ToCommand for Cpus {
986    fn to_command(&self) -> Vec<String> {
987        let mut cmd = vec![];
988
989        let mut arg: Vec<String> = vec![];
990        if let Some(boot) = self.boot {
991            arg.push(format!("boot={}", boot));
992        }
993        if let Some(max) = self.max {
994            arg.push(format!("max={}", max));
995        }
996        if let Some(topology) = &self.topology {
997            arg.push(format!(
998                "topology={}:{}:{}:{}",
999                topology.threads_per_core,
1000                topology.cores_per_die,
1001                topology.dies_per_package,
1002                topology.packages
1003            ));
1004        }
1005        if let Some(kvm_hyperv) = &self.kvm_hyperv {
1006            arg.push(format!("kvm_hyperv={}", kvm_hyperv));
1007        }
1008        if let Some(max_phys_bits) = self.max_phys_bits {
1009            arg.push(format!("max_phys_bits={}", max_phys_bits));
1010        }
1011        if let Some(affinity) = &self.affinity {
1012            if !affinity.is_empty() {
1013                let mut aarg: Vec<String> = vec![];
1014                for vcpu in affinity {
1015                    aarg.push(format!(
1016                        "{}@[{}]",
1017                        vcpu.vcpu,
1018                        vcpu.host_cpus
1019                            .iter()
1020                            .map(|v| v.to_string())
1021                            .collect::<Vec<String>>()
1022                            .join(",")
1023                    ));
1024                }
1025                arg.push(format!("affinity=[{}]", aarg.join(",")));
1026            }
1027        }
1028        if let Some(features) = &self.features {
1029            let mut farg = vec![];
1030
1031            if let Some(amx) = features.amx {
1032                if amx {
1033                    farg.push("amx");
1034                }
1035            }
1036            if !farg.is_empty() {
1037                arg.push(format!("features={}", farg.join(",")));
1038            }
1039        }
1040        if !arg.is_empty() {
1041            cmd.push("--cpus".to_string());
1042            cmd.push(arg.join(","));
1043        }
1044
1045        cmd
1046    }
1047}
1048
1049#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1050#[builder(setter(strip_option, into), default)]
1051pub struct Platform {
1052    pub num_pci_segments: Option<u8>,
1053    pub iommu_segments: Option<u8>,
1054    pub serial_number: Option<String>,
1055    pub uuid: Option<String>,
1056    pub oem_strings: Option<Vec<String>>,
1057}
1058impl ToCommand for Platform {
1059    fn to_command(&self) -> Vec<String> {
1060        let mut cmd = vec![];
1061        let mut arg: Vec<String> = vec![];
1062        if let Some(num_pci_segments) = &self.num_pci_segments {
1063            arg.push(format!("num_pci_segments={}", num_pci_segments));
1064        }
1065
1066        if let Some(iommu_segments) = &self.iommu_segments {
1067            arg.push(format!("iommu_segments={}", iommu_segments));
1068        }
1069        if let Some(serial_number) = &self.serial_number {
1070            arg.push(format!("serial_number={}", serial_number));
1071        }
1072        if let Some(uuid) = &self.uuid {
1073            arg.push(format!("uuid={}", uuid));
1074        }
1075        if let Some(oem_strings) = &self.oem_strings {
1076            if !oem_strings.is_empty() {
1077                arg.push(format!("oem_strings=[{}]", oem_strings.join(",")));
1078            }
1079        }
1080
1081        if !arg.is_empty() {
1082            cmd.push("--platform".to_string());
1083            cmd.push(arg.join(","));
1084        }
1085
1086        cmd
1087    }
1088}
1089
1090#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1091pub enum MemoryHotplugMethod {
1092    Acpi,
1093    VirtioMem,
1094}
1095
1096impl Display for MemoryHotplugMethod {
1097    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1098        match self {
1099            MemoryHotplugMethod::Acpi => {
1100                write!(f, "acpi")
1101            }
1102            MemoryHotplugMethod::VirtioMem => {
1103                write!(f, "virtio-mem")
1104            }
1105        }
1106    }
1107}
1108#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1109#[builder(setter(strip_option, into), default)]
1110pub struct Memory {
1111    pub size: Option<ByteSize>,
1112    pub mergeable: Option<OnOff>,
1113    pub shared: Option<OnOff>,
1114    pub hugepages: Option<OnOff>,
1115    pub hugepage_size: Option<ByteSize>,
1116    pub hotplug_method: Option<MemoryHotplugMethod>,
1117    pub hotplug_size: Option<ByteSize>,
1118    pub hotplugged_size: Option<ByteSize>,
1119    pub prefault: Option<OnOff>,
1120    pub thp: Option<OnOff>,
1121}
1122
1123impl ToCommand for Memory {
1124    fn to_command(&self) -> Vec<String> {
1125        let mut cmd = vec![];
1126        let mut arg: Vec<String> = vec![];
1127
1128        if let Some(size) = &self.size {
1129            arg.push(format!("size={}", size.0));
1130        }
1131
1132        if let Some(mergeable) = &self.mergeable {
1133            arg.push(format!("mergeable={}", mergeable));
1134        }
1135
1136        if let Some(shared) = &self.shared {
1137            arg.push(format!("shared={}", shared));
1138        }
1139
1140        if let Some(hugepages) = &self.hugepages {
1141            arg.push(format!("hugepages={}", hugepages));
1142        }
1143
1144        if let Some(hugepage_size) = &self.hugepage_size {
1145            arg.push(format!("hugepage_size={}", hugepage_size.0));
1146        }
1147
1148        if let Some(hotplug_method) = &self.hotplug_method {
1149            arg.push(format!("hotplug_method={}", hotplug_method));
1150        }
1151
1152        if let Some(hotplug_size) = &self.hotplug_size {
1153            arg.push(format!("hotplug_size={}", hotplug_size.0));
1154        }
1155
1156        if let Some(hotplugged_size) = &self.hotplugged_size {
1157            arg.push(format!("hotplugged_size={}", hotplugged_size.0));
1158        }
1159
1160        if let Some(prefault) = &self.prefault {
1161            arg.push(format!("prefault={}", prefault));
1162        }
1163
1164        if let Some(thp) = &self.thp {
1165            arg.push(format!("thp={}", thp));
1166        }
1167
1168        if !arg.is_empty() {
1169            cmd.push("--memory".to_string());
1170            cmd.push(arg.join(","));
1171        }
1172
1173        cmd
1174    }
1175}
1176
1177#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1178#[builder(setter(strip_option, into), default)]
1179pub struct MemoryZone {
1180    pub size: Option<ByteSize>,
1181    pub file: Option<PathBuf>,
1182    pub shared: Option<OnOff>,
1183    pub hugepages: Option<OnOff>,
1184    pub hugepage_size: Option<ByteSize>,
1185    pub host_numa_node: Option<usize>,
1186    pub id: Option<String>,
1187    pub hotplug_size: Option<ByteSize>,
1188    pub hotplugged_size: Option<ByteSize>,
1189    pub prefault: Option<OnOff>,
1190}
1191
1192impl ToCommand for MemoryZone {
1193    fn to_command(&self) -> Vec<String> {
1194        let mut cmd = vec![];
1195        let mut arg: Vec<String> = vec![];
1196
1197        if let Some(size) = &self.size {
1198            arg.push(format!("size={}", size.0));
1199        }
1200
1201        if let Some(path) = &self.file {
1202            arg.push(format!("file={}", path.display()));
1203        }
1204
1205        if let Some(shared) = &self.shared {
1206            arg.push(format!("shared={}", shared));
1207        }
1208
1209        if let Some(hugepages) = &self.hugepages {
1210            arg.push(format!("hugepages={}", hugepages));
1211        }
1212
1213        if let Some(hugepage_size) = &self.hugepage_size {
1214            arg.push(format!("hugepage_size={}", hugepage_size.0));
1215        }
1216
1217        if let Some(host_numa_node) = &self.host_numa_node {
1218            arg.push(format!("host_numa_node={}", host_numa_node));
1219        }
1220
1221        if let Some(id) = &self.id {
1222            arg.push(format!("id={}", id));
1223        }
1224
1225        if let Some(hotplug_size) = &self.hotplug_size {
1226            arg.push(format!("hotplug_size={}", hotplug_size.0));
1227        }
1228
1229        if let Some(hotplugged_size) = &self.hotplugged_size {
1230            arg.push(format!("hotplugged_size={}", hotplugged_size.0));
1231        }
1232
1233        if let Some(prefault) = &self.prefault {
1234            arg.push(format!("prefault={}", prefault));
1235        }
1236
1237        if !arg.is_empty() {
1238            cmd.push("--memory-zone".to_string());
1239            cmd.push(arg.join(","));
1240        }
1241
1242        cmd
1243    }
1244}
1245
1246#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1247#[builder(setter(strip_option, into), default)]
1248pub struct RateLimitGroup {
1249    pub bw_size: Option<ByteSize>,
1250    pub bw_one_time_burst: Option<ByteSize>,
1251    pub bw_refill_time: Option<usize>,
1252    pub ops_size: Option<usize>,
1253    pub ops_one_time_burst: Option<usize>,
1254    pub ops_refill_time: Option<usize>,
1255    pub id: Option<String>,
1256}
1257
1258#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1259#[builder(setter(strip_option, into), default)]
1260pub struct Disk {
1261    pub path: Option<PathBuf>,
1262    pub readonly: Option<OnOff>,
1263    pub direct: Option<OnOff>,
1264    pub iommu: Option<OnOff>,
1265    pub num_queues: Option<usize>,
1266    pub queue_size: Option<usize>,
1267    pub vhost_user: Option<OnOff>,
1268    pub socket: Option<PathBuf>,
1269    pub bw_size: Option<ByteSize>,
1270    pub bw_one_time_burst: Option<ByteSize>,
1271    pub bw_refill_time: Option<usize>,
1272    pub ops_size: Option<usize>,
1273    pub ops_one_time_burst: Option<usize>,
1274    pub ops_refill_time: Option<usize>,
1275    pub id: Option<String>,
1276    pub pci_segment: Option<String>,
1277    pub rate_limit_group: Option<String>,
1278    pub queue_affinity: Option<String>,
1279}
1280
1281#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1282pub enum VhostMode {
1283    Client,
1284    Server,
1285}
1286
1287impl Display for VhostMode {
1288    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1289        match self {
1290            VhostMode::Client => {
1291                write!(f, "client")
1292            }
1293            VhostMode::Server => {
1294                write!(f, "server")
1295            }
1296        }
1297    }
1298}
1299#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1300#[builder(setter(strip_option, into), default)]
1301pub struct Net {
1302    pub tap: Option<String>,
1303    pub ip: Option<IpAddr>,
1304    pub mask: Option<u8>,
1305    pub mac: Option<String>,
1306    pub fd: Option<Vec<usize>>,
1307    pub iommu: Option<OnOff>,
1308    pub num_queues: Option<usize>,
1309    pub queue_size: Option<usize>,
1310    pub id: Option<String>,
1311    pub vhost_user: Option<OnOff>,
1312    pub socket: Option<PathBuf>,
1313    pub vhost_mode: Option<VhostMode>,
1314    pub bw_size: Option<ByteSize>,
1315    pub bw_one_time_burst: Option<ByteSize>,
1316    pub bw_refill_time: Option<usize>,
1317    pub ops_size: Option<usize>,
1318    pub ops_one_time_burst: Option<usize>,
1319    pub ops_refill_time: Option<usize>,
1320    pub pci_segment: Option<String>,
1321    pub offload_tso: Option<OnOff>,
1322    pub offload_ufo: Option<OnOff>,
1323    pub offload_csum: Option<OnOff>,
1324}
1325#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1326pub enum Rng {
1327    Src(PathBuf),
1328    Iommu(OnOff),
1329}
1330
1331#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1332#[builder(setter(strip_option, into), default)]
1333pub struct Balloon {
1334    pub size: Option<ByteSize>,
1335    pub deflate_on_oom: Option<OnOff>,
1336    pub free_page_reporting: Option<OnOff>,
1337}
1338
1339#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1340#[builder(setter(strip_option, into), default)]
1341pub struct Fs {
1342    pub tag: Option<String>,
1343    pub socket: Option<PathBuf>,
1344    pub num_queues: Option<usize>,
1345    pub queue_size: Option<usize>,
1346    pub id: Option<String>,
1347    pub pci_segment: Option<String>,
1348}
1349
1350#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1351#[builder(setter(strip_option, into), default)]
1352pub struct Pmem {
1353    pub file: Option<PathBuf>,
1354    pub size: Option<usize>,
1355    pub iommu: Option<OnOff>,
1356    pub discard_writes: Option<OnOff>,
1357    pub id: Option<String>,
1358    pub pci_segment: Option<String>,
1359}
1360
1361#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1362pub enum Serial {
1363    Off,
1364    Null,
1365    Pty,
1366    Tty,
1367    File(PathBuf),
1368    Socket(PathBuf),
1369}
1370#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1371pub enum Console {
1372    Off,
1373    Null,
1374    Pty,
1375    Tty,
1376    File(PathBuf),
1377    Iommu(OnOff),
1378}
1379
1380#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1381#[builder(setter(strip_option, into), default)]
1382pub struct Device {
1383    pub path: Option<PathBuf>,
1384    pub iommu: Option<OnOff>,
1385    pub id: Option<String>,
1386    pub pci_segment: Option<String>,
1387}
1388#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1389#[builder(setter(strip_option, into), default)]
1390pub struct UserDevice {
1391    pub socket: Option<PathBuf>,
1392    pub id: Option<String>,
1393    pub pci_segment: Option<String>,
1394}
1395
1396#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1397#[builder(setter(strip_option, into), default)]
1398pub struct Vdpa {
1399    pub path: Option<PathBuf>,
1400    pub num_queues: Option<usize>,
1401    pub iommu: Option<OnOff>,
1402    pub id: Option<String>,
1403    pub pci_segment: Option<String>,
1404}
1405#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1406#[builder(setter(strip_option, into), default)]
1407pub struct Vsock {
1408    pub cid: Option<String>,
1409    pub socket: Option<PathBuf>,
1410    pub iommu: Option<OnOff>,
1411    pub id: Option<String>,
1412    pub pci_segment: Option<String>,
1413}
1414
1415#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1416#[builder(setter(strip_option, into), default)]
1417pub struct Numa {
1418    pub guest_numa_id: Option<String>,
1419    pub cpus: Option<Vec<usize>>,
1420    pub distances: Option<Vec<usize>>,
1421    pub memory_zones: Option<Vec<String>>,
1422    pub sgx_epc_sections: Option<Vec<String>>,
1423    pub pci_segments: Option<Vec<String>>,
1424}
1425
1426#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1427#[builder(setter(strip_option, into), default)]
1428pub struct Restore {
1429    pub source_url: Option<String>,
1430    pub prefault: Option<OnOff>,
1431}
1432#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1433pub enum SecComp {
1434    True,
1435    False,
1436    Log,
1437}
1438
1439#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1440#[builder(setter(strip_option, into), default)]
1441pub struct SgxEpc {
1442    pub id: Option<String>,
1443    pub size: Option<String>,
1444    pub prefault: Option<OnOff>,
1445}
1446
1447#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1448pub enum DebugConsoleType {
1449    Off,
1450    Pty,
1451    Tty,
1452    File(PathBuf),
1453}
1454
1455#[derive(Builder, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1456#[builder(setter(strip_option, into), default)]
1457pub struct DebugConsole {
1458    pub console_type: Option<DebugConsoleType>,
1459    pub iobase: Option<String>,
1460}