| 90 | } |
| 91 | |
| 92 | fn main() -> Result<()> { |
| 93 | tracing_subscriber::fmt::init(); |
| 94 | |
| 95 | let cli = Cli::parse(); |
| 96 | match &cli.command { |
| 97 | Commands::Measure(config) => { |
| 98 | let metadata = |
| 99 | fs::read_to_string(&config.metadata).context("Failed to read image metadata")?; |
| 100 | let image_info: ImageInfo = |
| 101 | serde_json::from_str(&metadata).context("Failed to parse image metadata")?; |
| 102 | let parent_dir = config.metadata.parent().unwrap_or(".".as_ref()); |
| 103 | let firmware_path = parent_dir.join(&image_info.bios).display().to_string(); |
| 104 | let kernel_path = parent_dir.join(&image_info.kernel).display().to_string(); |
| 105 | let initrd_path = parent_dir.join(&image_info.initrd).display().to_string(); |
| 106 | let cmdline = image_info.cmdline + " initrd=initrd"; |
| 107 | |
| 108 | // CLI flag wins, then the explicit `ovmf_variant` in metadata.json, |
| 109 | // and finally the OS version field. Older metadata.json files may |
| 110 | // carry neither, in which case fall back to the default. |
| 111 | let ovmf_variant = if let Some(v) = config.dstack_os_version.as_deref() { |
| 112 | ovmf_variant_for_version(v) |
| 113 | .with_context(|| format!("invalid dstack OS version: {v}"))? |
| 114 | } else if let Some(variant) = image_info.ovmf_variant { |
| 115 | variant |
| 116 | } else if !image_info.version.is_empty() { |
| 117 | ovmf_variant_for_version(&image_info.version) |
| 118 | .with_context(|| format!("invalid dstack OS version: {}", image_info.version))? |
| 119 | } else { |
| 120 | OvmfVariant::default() |
| 121 | }; |
| 122 | |
| 123 | let machine = Machine::builder() |
| 124 | .cpu_count(config.cpu) |
| 125 | .memory_size(config.memory) |
| 126 | .firmware(&firmware_path) |
| 127 | .kernel(&kernel_path) |
| 128 | .initrd(&initrd_path) |
| 129 | .kernel_cmdline(&cmdline) |
| 130 | .maybe_two_pass_add_pages(config.two_pass_add_pages) |
| 131 | .maybe_pic(config.pic) |
| 132 | .smm(config.smm) |
| 133 | .maybe_pci_hole64_size(config.pci_hole64_size) |
| 134 | .hugepages(config.hugepages) |
| 135 | .num_gpus(config.num_gpus) |
| 136 | .num_nvswitches(config.num_nvswitches) |
| 137 | .hotplug_off(config.hotplug_off) |
| 138 | .root_verity(config.root_verity) |
| 139 | .maybe_qemu_version(config.qemu_version.clone()) |
| 140 | .ovmf_variant(ovmf_variant) |
| 141 | .build(); |
| 142 | |
| 143 | let measurements = machine |
| 144 | .measure() |
| 145 | .context("Failed to measure machine configuration")?; |
| 146 | |
| 147 | if config.json { |
| 148 | println!("{}", serde_json::to_string_pretty(&measurements)?); |
| 149 | } else { |