use serde::{Deserialize, Serialize};
pub const BOOT_PROTO_VERSION: u32 = 1;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RootfsSpec {
Share { read_only: bool },
Block { fstype: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Strategy {
OneShot,
Agent { width: u32, height: u32 },
Snapshot { guest_vsock_port: u32 },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BootParams {
pub proto_version: u32,
pub rootfs: RootfsSpec,
pub scratch_dev: Option<String>,
pub shares: Vec<String>,
pub exec: Option<String>,
pub env_exports: Option<String>,
pub switch_root: bool,
pub net: bool,
pub strategy: Strategy,
pub capture: bool,
}
impl BootParams {
pub fn new(rootfs: RootfsSpec) -> Self {
Self {
proto_version: BOOT_PROTO_VERSION,
rootfs,
scratch_dev: None,
shares: Vec::new(),
exec: None,
env_exports: None,
switch_root: false,
net: false,
strategy: Strategy::OneShot,
capture: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_carries_current_version_and_defaults() {
let p = BootParams::new(RootfsSpec::Share { read_only: false });
assert_eq!(p.proto_version, BOOT_PROTO_VERSION);
assert_eq!(p.rootfs, RootfsSpec::Share { read_only: false });
assert!(p.scratch_dev.is_none());
assert!(p.shares.is_empty());
assert!(p.exec.is_none());
assert!(p.env_exports.is_none());
assert!(!p.switch_root);
assert!(!p.net);
assert_eq!(p.strategy, Strategy::OneShot);
assert!(!p.capture);
}
#[test]
fn json_round_trips() {
let p = BootParams {
proto_version: BOOT_PROTO_VERSION,
rootfs: RootfsSpec::Block {
fstype: "squashfs".into(),
},
scratch_dev: Some("vdb".into()),
shares: vec!["work".into(), "data".into()],
exec: Some("echo hi\nuname -a".into()),
env_exports: Some("export FOO='bar'\n".into()),
switch_root: true,
net: true,
strategy: Strategy::Agent {
width: 1280,
height: 800,
},
capture: true,
};
let j = serde_json::to_string(&p).unwrap();
let back: BootParams = serde_json::from_str(&j).unwrap();
assert_eq!(p, back);
}
#[test]
fn rootfs_and_strategy_variants_are_distinct() {
assert_ne!(
RootfsSpec::Share { read_only: true },
RootfsSpec::Share { read_only: false }
);
assert_ne!(
Strategy::Agent {
width: 1,
height: 2
},
Strategy::OneShot
);
}
}