diff --git a/crates/integration-tests/src/tests/mount_feature.rs b/crates/integration-tests/src/tests/mount_feature.rs index 36e4fd07c..285fcf2d0 100644 --- a/crates/integration-tests/src/tests/mount_feature.rs +++ b/crates/integration-tests/src/tests/mount_feature.rs @@ -20,49 +20,40 @@ use tempfile::TempDir; use crate::{get_test_image, run_bcvk, INTEGRATION_TEST_LABEL}; -/// Create a systemd unit that verifies a mount exists and contains expected content +/// Create a systemd unit that verifies a mount exists and tests writability fn create_mount_verify_unit( unit_dir: &Utf8Path, mount_name: &str, expected_file: &str, - expected_content: &str, + expected_content: Option<&str>, + readonly: bool, ) -> std::io::Result<()> { - let unit_content = format!( - r#"[Unit] -Description=Verify mount {mount_name} and poweroff -RequiresMountsFor=/run/virtiofs-mnt-{mount_name} + let (description, content_check, write_check, unit_prefix) = if readonly { + ( + format!("Verify read-only mount {mount_name} and poweroff"), + format!("ExecStart=test -f /run/virtiofs-mnt-{mount_name}/{expected_file}"), + format!("ExecStart=/bin/sh -c '! echo test-write > /run/virtiofs-mnt-{mount_name}/write-test.txt 2>/dev/null'"), + "verify-ro-mount", + ) + } else { + let content = expected_content.expect("expected_content required for writable mounts"); + ( + format!("Verify mount {mount_name} and poweroff"), + format!("ExecStart=grep -qF \"{content}\" /run/virtiofs-mnt-{mount_name}/{expected_file}"), + format!("ExecStart=/bin/sh -c 'echo test-write > /run/virtiofs-mnt-{mount_name}/write-test.txt'"), + "verify-mount", + ) + }; -[Service] -Type=oneshot -ExecStart=grep -qF "{expected_content}" /run/virtiofs-mnt-{mount_name}/{expected_file} -ExecStart=test -w /run/virtiofs-mnt-{mount_name}/{expected_file} -ExecStart=echo ok mount verify {mount_name} -ExecStart=systemctl poweroff -StandardOutput=journal+console -StandardError=journal+console -"# - ); - - let unit_path = unit_dir.join(format!("verify-mount-{}.service", mount_name)); - fs::write(&unit_path, unit_content)?; - Ok(()) -} - -/// Create a systemd unit that tries to write to a mount to verify read-only status -fn create_ro_mount_verify_unit( - unit_dir: &Utf8Path, - mount_name: &str, - expected_file: &str, -) -> std::io::Result<()> { let unit_content = format!( r#"[Unit] -Description=Verify read-only mount {mount_name} and poweroff +Description={description} RequiresMountsFor=/run/virtiofs-mnt-{mount_name} [Service] Type=oneshot -ExecStart=test -f /run/virtiofs-mnt-{mount_name}/{expected_file} -ExecStart=test '!' -w /run/virtiofs-mnt-{mount_name}/{expected_file} +{content_check} +{write_check} ExecStart=echo ok mount verify {mount_name} ExecStart=systemctl poweroff StandardOutput=journal+console @@ -70,7 +61,7 @@ StandardError=journal+console "# ); - let unit_path = unit_dir.join(format!("verify-ro-mount-{}.service", mount_name)); + let unit_path = unit_dir.join(format!("{unit_prefix}-{mount_name}.service")); fs::write(&unit_path, unit_content)?; Ok(()) } @@ -90,8 +81,14 @@ pub fn test_mount_feature_bind() { fs::create_dir(&system_dir).expect("Failed to create system directory"); // Create verification unit - create_mount_verify_unit(&system_dir, "testmount", "test.txt", test_content) - .expect("Failed to create verify unit"); + create_mount_verify_unit( + &system_dir, + "testmount", + "test.txt", + Some(test_content), + false, + ) + .expect("Failed to create verify unit"); println!("Testing bind mount with temp directory: {}", temp_dir_path); @@ -135,7 +132,7 @@ pub fn test_mount_feature_ro_bind() { fs::create_dir(&system_dir).expect("Failed to create system directory"); // Create verification unit for read-only mount - create_ro_mount_verify_unit(&system_dir, "romount", "readonly.txt") + create_mount_verify_unit(&system_dir, "romount", "readonly.txt", None, true) .expect("Failed to create verify unit"); println!( diff --git a/crates/kit/src/qemu.rs b/crates/kit/src/qemu.rs index 3221c5232..bf894ba73 100644 --- a/crates/kit/src/qemu.rs +++ b/crates/kit/src/qemu.rs @@ -898,6 +898,8 @@ pub struct VirtiofsConfig { /// Host directory to share pub shared_dir: Utf8PathBuf, pub debug: bool, + /// Mount as read-only + pub readonly: bool, } impl Default for VirtiofsConfig { @@ -906,6 +908,8 @@ impl Default for VirtiofsConfig { socket_path: "/run/inner-shared/virtiofs.sock".into(), shared_dir: "/run/source-image".into(), debug: false, + // We don't need to write to this, there's a transient overlay + readonly: true, } } } @@ -977,8 +981,8 @@ pub async fn spawn_virtiofsd_async(config: &VirtiofsConfig) -> Result Result<()> { socket_path: socket_path.clone().into(), shared_dir: source_path, debug: false, + readonly: is_readonly, }; additional_mounts.push((virtiofsd_config, tag.clone()));