Skip to content

Commit ec8e251

Browse files
authored
Merge pull request #351 from Dstack-TEE/refactor-sys-config
vmm: Refactor sys-config generation code
2 parents 29e755d + 161dde7 commit ec8e251

File tree

3 files changed

+61
-161
lines changed

3 files changed

+61
-161
lines changed

vmm/src/app.rs

Lines changed: 58 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use anyhow::{bail, Context, Result};
88
use bon::Builder;
99
use dstack_kms_rpc::kms_client::KmsClient;
1010
use dstack_types::shared_filenames::{
11-
compat_v3, APP_COMPOSE, ENCRYPTED_ENV, INSTANCE_INFO, SYS_CONFIG, USER_CONFIG,
11+
APP_COMPOSE, ENCRYPTED_ENV, INSTANCE_INFO, SYS_CONFIG, USER_CONFIG,
1212
};
1313
use dstack_vmm_rpc::{self as pb, GpuInfo, StatusRequest, StatusResponse, VmConfiguration};
1414
use fs_err as fs;
@@ -489,119 +489,9 @@ impl App {
489489
let shared_dir = self.shared_dir(id);
490490
let manifest = work_dir.manifest().context("Failed to read manifest")?;
491491
let cfg = &self.config;
492-
let image_path = cfg.image_path.join(&manifest.image);
493-
let image = Image::load(image_path).context("Failed to load image info")?;
494-
let img_ver = image.info.version_tuple().unwrap_or((0, 0, 0));
495-
let kms_urls = if manifest.kms_urls.is_empty() {
496-
cfg.cvm.kms_urls.clone()
497-
} else {
498-
manifest.kms_urls.clone()
499-
};
500-
let gateway_urls = if manifest.gateway_urls.is_empty() {
501-
cfg.cvm.gateway_urls.clone()
502-
} else {
503-
manifest.gateway_urls.clone()
504-
};
505-
let sys_config = if img_ver >= (0, 5, 0) {
506-
let os_image_hash = hex::decode(image.digest.unwrap_or_default())
507-
.context("Failed to decode image digest")?;
508-
let gpus = manifest.gpus.unwrap_or_default();
509-
let vm_config = serde_json::to_string(&dstack_types::VmConfig {
510-
spec_version: 1,
511-
os_image_hash,
512-
cpu_count: manifest.vcpu,
513-
memory_size: manifest.memory as u64 * 1024 * 1024,
514-
qemu_single_pass_add_pages: cfg.cvm.qemu_single_pass_add_pages,
515-
pic: cfg.cvm.qemu_pic,
516-
qemu_version: cfg.cvm.qemu_version.clone(),
517-
pci_hole64_size: cfg.cvm.qemu_pci_hole64_size,
518-
hugepages: manifest.hugepages,
519-
num_gpus: gpus.gpus.len() as u32,
520-
num_nvswitches: gpus.bridges.len() as u32,
521-
hotplug_off: cfg.cvm.qemu_hotplug_off,
522-
image: Some(manifest.image.clone()),
523-
})?;
524-
json!({
525-
"kms_urls": kms_urls,
526-
"gateway_urls": gateway_urls,
527-
"pccs_url": cfg.cvm.pccs_url,
528-
"docker_registry": cfg.cvm.docker_registry,
529-
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
530-
"vm_config": vm_config,
531-
})
532-
} else if img_ver >= (0, 4, 2) {
533-
json!({
534-
"kms_urls": kms_urls,
535-
"gateway_urls": gateway_urls,
536-
"pccs_url": cfg.cvm.pccs_url,
537-
"docker_registry": cfg.cvm.docker_registry,
538-
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
539-
})
540-
} else if img_ver >= (0, 4, 0) {
541-
let rootfs_hash = image
542-
.info
543-
.rootfs_hash
544-
.as_ref()
545-
.context("Rootfs hash not found in image info")?;
546-
json!({
547-
"rootfs_hash": rootfs_hash,
548-
"kms_urls": kms_urls,
549-
"tproxy_urls": gateway_urls,
550-
"pccs_url": cfg.cvm.pccs_url,
551-
"docker_registry": cfg.cvm.docker_registry,
552-
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
553-
})
554-
} else {
555-
let rootfs_hash = image
556-
.info
557-
.rootfs_hash
558-
.as_ref()
559-
.context("Rootfs hash not found in image info")?;
560-
json!({
561-
"rootfs_hash": rootfs_hash,
562-
"kms_url": kms_urls.first(),
563-
"tproxy_url": gateway_urls.first(),
564-
"pccs_url": cfg.cvm.pccs_url,
565-
"docker_registry": cfg.cvm.docker_registry,
566-
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
567-
})
568-
};
569-
let sys_config_str =
570-
serde_json::to_string(&sys_config).context("Failed to serialize vm config")?;
571-
let config_file = if img_ver >= (0, 4, 0) {
572-
SYS_CONFIG
573-
} else {
574-
compat_v3::SYS_CONFIG
575-
};
576-
fs::write(shared_dir.join(config_file), sys_config_str)
492+
let sys_config_str = make_sys_config(cfg, &manifest)?;
493+
fs::write(shared_dir.join(SYS_CONFIG), sys_config_str)
577494
.context("Failed to write vm config")?;
578-
if img_ver < (0, 4, 0) {
579-
// Sync .encrypted-env to encrypted-env
580-
let compat_encrypted_env_path = shared_dir.join(compat_v3::ENCRYPTED_ENV);
581-
let encrypted_env_path = shared_dir.join(ENCRYPTED_ENV);
582-
if compat_encrypted_env_path.exists() {
583-
fs::remove_file(&compat_encrypted_env_path)?;
584-
}
585-
if encrypted_env_path.exists() {
586-
fs::copy(&encrypted_env_path, &compat_encrypted_env_path)?;
587-
}
588-
589-
// Sync certs
590-
let certs_dir = shared_dir.join("certs");
591-
fs::create_dir_all(&certs_dir).context("Failed to create certs directory")?;
592-
if cfg.cvm.ca_cert.is_empty()
593-
|| cfg.cvm.tmp_ca_cert.is_empty()
594-
|| cfg.cvm.tmp_ca_key.is_empty()
595-
{
596-
bail!("Certificates are required for older images");
597-
}
598-
fs::copy(&cfg.cvm.ca_cert, certs_dir.join("ca.cert"))
599-
.context("Failed to copy ca cert")?;
600-
fs::copy(&cfg.cvm.tmp_ca_cert, certs_dir.join("tmp-ca.cert"))
601-
.context("Failed to copy tmp ca cert")?;
602-
fs::copy(&cfg.cvm.tmp_ca_key, certs_dir.join("tmp-ca.key"))
603-
.context("Failed to copy tmp ca key")?;
604-
}
605495
Ok(())
606496
}
607497

@@ -676,6 +566,61 @@ impl App {
676566
}
677567
}
678568

569+
pub(crate) fn make_sys_config(cfg: &Config, manifest: &Manifest) -> Result<String> {
570+
let image_path = cfg.image_path.join(&manifest.image);
571+
let image = Image::load(image_path).context("Failed to load image info")?;
572+
let img_ver = image.info.version_tuple().unwrap_or((0, 0, 0));
573+
let kms_urls = if manifest.kms_urls.is_empty() {
574+
cfg.cvm.kms_urls.clone()
575+
} else {
576+
manifest.kms_urls.clone()
577+
};
578+
let gateway_urls = if manifest.gateway_urls.is_empty() {
579+
cfg.cvm.gateway_urls.clone()
580+
} else {
581+
manifest.gateway_urls.clone()
582+
};
583+
if img_ver < (0, 5, 0) {
584+
bail!("Unsupported image version: {img_ver:?}");
585+
}
586+
587+
let sys_config = json!({
588+
"kms_urls": kms_urls,
589+
"gateway_urls": gateway_urls,
590+
"pccs_url": cfg.cvm.pccs_url,
591+
"docker_registry": cfg.cvm.docker_registry,
592+
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
593+
"vm_config": serde_json::to_string(&make_vm_config(cfg, manifest, &image))?,
594+
});
595+
let sys_config_str =
596+
serde_json::to_string(&sys_config).context("Failed to serialize vm config")?;
597+
Ok(sys_config_str)
598+
}
599+
600+
fn make_vm_config(cfg: &Config, manifest: &Manifest, image: &Image) -> dstack_types::VmConfig {
601+
let os_image_hash = image
602+
.digest
603+
.as_ref()
604+
.and_then(|d| hex::decode(d).ok())
605+
.unwrap_or_default();
606+
let gpus = manifest.gpus.clone().unwrap_or_default();
607+
dstack_types::VmConfig {
608+
spec_version: 1,
609+
os_image_hash,
610+
cpu_count: manifest.vcpu,
611+
memory_size: manifest.memory as u64 * 1024 * 1024,
612+
qemu_single_pass_add_pages: cfg.cvm.qemu_single_pass_add_pages,
613+
pic: cfg.cvm.qemu_pic,
614+
qemu_version: cfg.cvm.qemu_version.clone(),
615+
pci_hole64_size: cfg.cvm.qemu_pci_hole64_size,
616+
hugepages: manifest.hugepages,
617+
num_gpus: gpus.gpus.len() as u32,
618+
num_nvswitches: gpus.bridges.len() as u32,
619+
hotplug_off: cfg.cvm.qemu_hotplug_off,
620+
image: Some(manifest.image.clone()),
621+
}
622+
}
623+
679624
fn paginate<T>(items: Vec<T>, page: u32, page_size: u32) -> impl Iterator<Item = T> {
680625
let skip;
681626
let take;

vmm/src/config.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,6 @@ pub struct CvmConfig {
170170
/// Use sudo to run the VM
171171
pub user: String,
172172

173-
/// The CA certificate
174-
#[serde(default)]
175-
pub ca_cert: String,
176-
/// The tmp CA certificate
177-
#[serde(default)]
178-
pub tmp_ca_cert: String,
179-
/// The tmp CA key
180-
#[serde(default)]
181-
pub tmp_ca_key: String,
182-
183173
/// Auto restart configuration
184174
pub auto_restart: AutoRestartConfig,
185175

vmm/src/one_shot.rs

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// SPDX-License-Identifier: Apache-2.0
44

5-
use crate::app::{Image, VmConfig, VmWorkDir};
5+
use crate::app::{make_sys_config, Image, VmConfig, VmWorkDir};
66
use crate::config::Config;
77
use crate::main_service;
88
use anyhow::{Context, Result};
@@ -235,44 +235,9 @@ Compose file content (first 200 chars):
235235

236236
// 2. Create .sys-config.json (critical for 0.5.x VMs)
237237
// Use manifest URLs if available, fallback to config URLs (matching VMM's sync_dynamic_config logic)
238-
let kms_urls = if manifest.kms_urls.is_empty() {
239-
config.cvm.kms_urls.clone()
240-
} else {
241-
manifest.kms_urls.clone()
242-
};
243-
let gateway_urls = if manifest.gateway_urls.is_empty() {
244-
config.cvm.gateway_urls.clone()
245-
} else {
246-
manifest.gateway_urls.clone()
247-
};
248-
249-
let sys_config = serde_json::json!({
250-
"kms_urls": kms_urls,
251-
"gateway_urls": gateway_urls,
252-
"pccs_url": config.cvm.pccs_url,
253-
"docker_registry": config.cvm.docker_registry,
254-
"host_api_url": format!("vsock://2:{}/api", config.host_api.port),
255-
"vm_config": serde_json::to_string(&dstack_types::VmConfig {
256-
spec_version: 1,
257-
os_image_hash: image.digest.as_ref()
258-
.and_then(|d| hex::decode(d).ok())
259-
.unwrap_or_default(),
260-
cpu_count: manifest.vcpu,
261-
memory_size: manifest.memory as u64 * 1024 * 1024,
262-
qemu_single_pass_add_pages: config.cvm.qemu_single_pass_add_pages,
263-
pic: config.cvm.qemu_pic,
264-
qemu_version: config.cvm.qemu_version.clone(),
265-
pci_hole64_size: config.cvm.qemu_pci_hole64_size,
266-
hugepages: manifest.hugepages,
267-
num_gpus: manifest.gpus.as_ref().map_or(0, |g| g.gpus.len() as u32),
268-
num_nvswitches: manifest.gpus.as_ref().map_or(0, |g| g.bridges.len() as u32),
269-
hotplug_off: config.cvm.qemu_hotplug_off,
270-
image: Some(manifest.image.clone()),
271-
})?
272-
});
238+
let sys_config_str = make_sys_config(&config, &manifest)?;
273239
let sys_config_path = vm_work_dir.shared_dir().join(".sys-config.json");
274-
fs_err::write(&sys_config_path, serde_json::to_string(&sys_config)?)
275-
.context("Failed to write sys config")?;
240+
fs_err::write(&sys_config_path, sys_config_str).context("Failed to write sys config")?;
276241

277242
// Create vm-state.json with initial state
278243
vm_work_dir

0 commit comments

Comments
 (0)