Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions crates/integration-tests/src/tests/libvirt_verb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ pub fn test_libvirt_run_ssh_full_workflow() {
LIBVIRT_INTEGRATION_TEST_LABEL,
"--filesystem",
"ext4",
"--karg",
"bcvk.test-install-karg=1",
&test_image,
])
.expect("Failed to run libvirt run with SSH");
Expand All @@ -375,9 +377,9 @@ pub fn test_libvirt_run_ssh_full_workflow() {
println!("Waiting for VM to boot and SSH to become available...");
std::thread::sleep(std::time::Duration::from_secs(30));

// Test SSH connection with simple command
println!("Testing SSH connection: echo 'hello world'");
let ssh_output = run_bcvk(&["libvirt", "ssh", &domain_name, "--", "echo", "hello world"])
// Test SSH connection and read kernel command line
println!("Testing SSH connection and validating karg");
let ssh_output = run_bcvk(&["libvirt", "ssh", &domain_name, "--", "cat", "/proc/cmdline"])
.expect("Failed to run libvirt ssh command");

println!("SSH stdout: {}", ssh_output.stdout);
Expand All @@ -388,17 +390,19 @@ pub fn test_libvirt_run_ssh_full_workflow() {

// Check SSH results
if !ssh_output.success() {
panic!("SSH connection failed: {}", ssh_output.stderr);
panic!(
"SSH connection failed: {}\nkernel cmdline: {}",
ssh_output.stderr, ssh_output.stdout
);
}

// Verify we got the expected output
// Verify we got the expected karg in /proc/cmdline
assert!(
ssh_output.stdout.contains("hello world"),
"Expected 'hello world' in SSH output. Got: {}",
ssh_output.stdout.contains("bcvk.test-install-karg=1"),
"Expected bcvk.test-install-karg=1 in kernel cmdline.\nActual cmdline: {}",
ssh_output.stdout
);

println!("✓ Successfully executed 'echo hello world' via SSH");
println!("✓ Full libvirt run + SSH workflow test passed");
}

Expand Down
43 changes: 11 additions & 32 deletions crates/kit/src/cache_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,13 @@ impl DiskImageMetadata {

impl DiskImageMetadata {
/// Create new metadata from InstallOptions and image digest
pub fn from(options: &InstallOptions, image: &str, kernel_args: &[String]) -> Self {
pub fn from(options: &InstallOptions, image: &str) -> Self {
Self {
version: 1,
digest: image.to_owned(),
filesystem: options.filesystem.clone(),
root_size: options.root_size.clone(),
kernel_args: kernel_args.to_vec(),
kernel_args: options.karg.clone(),
composefs_native: options.composefs_native,
}
}
Expand All @@ -180,15 +180,14 @@ pub fn check_cached_disk(
path: &Path,
image_digest: &str,
install_options: &InstallOptions,
kernel_args: &[String],
) -> Result<Result<(), ValidationError>> {
if !path.exists() {
tracing::debug!("Disk image {:?} does not exist", path);
return Ok(Err(ValidationError::MissingFile));
}

// Create metadata for the current request to compute expected hash
let expected_meta = DiskImageMetadata::from(install_options, image_digest, kernel_args);
let expected_meta = DiskImageMetadata::from(install_options, image_digest);
let expected_hash = expected_meta.compute_cache_hash();

// Read the cache hash from the disk image
Expand Down Expand Up @@ -241,26 +240,16 @@ mod tests {
let install_options1 = InstallOptions {
filesystem: Some("ext4".to_string()),
root_size: Some("20G".to_string()),
storage_path: None,
composefs_native: false,
..Default::default()
};
let metadata1 = DiskImageMetadata::from(
&install_options1,
"sha256:abc123",
&["console=ttyS0".to_string()],
);
let metadata1 = DiskImageMetadata::from(&install_options1, "sha256:abc123");

let install_options2 = InstallOptions {
filesystem: Some("ext4".to_string()),
root_size: Some("20G".to_string()),
storage_path: None,
composefs_native: false,
..Default::default()
};
let metadata2 = DiskImageMetadata::from(
&install_options2,
"sha256:abc123",
&["console=ttyS0".to_string()],
);
let metadata2 = DiskImageMetadata::from(&install_options2, "sha256:abc123");

// Same inputs should generate same hash
assert_eq!(
Expand All @@ -272,14 +261,9 @@ mod tests {
let install_options3 = InstallOptions {
filesystem: Some("ext4".to_string()),
root_size: Some("20G".to_string()),
storage_path: None,
composefs_native: false,
..Default::default()
};
let metadata3 = DiskImageMetadata::from(
&install_options3,
"sha256:xyz789",
&["console=ttyS0".to_string()],
);
let metadata3 = DiskImageMetadata::from(&install_options3, "sha256:xyz789");

assert_ne!(
metadata1.compute_cache_hash(),
Expand All @@ -290,14 +274,9 @@ mod tests {
let install_options4 = InstallOptions {
filesystem: Some("xfs".to_string()),
root_size: Some("20G".to_string()),
storage_path: None,
composefs_native: false,
..Default::default()
};
let metadata4 = DiskImageMetadata::from(
&install_options4,
"sha256:abc123",
&["console=ttyS0".to_string()],
);
let metadata4 = DiskImageMetadata::from(&install_options4, "sha256:abc123");

assert_ne!(
metadata1.compute_cache_hash(),
Expand Down
8 changes: 8 additions & 0 deletions crates/kit/src/install_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub struct InstallOptions {
)]
pub storage_path: Option<Utf8PathBuf>,

#[clap(long)]
/// Set a kernel argument
pub karg: Vec<String>,

/// Default to composefs-native storage
#[clap(long)]
pub composefs_native: bool,
Expand All @@ -49,6 +53,10 @@ impl InstallOptions {
args.push(root_size.clone());
}

for k in self.karg.iter() {
args.push(format!("--karg={k}"));
}

if self.composefs_native {
args.push("--composefs-native".to_owned());
}
Expand Down
7 changes: 1 addition & 6 deletions crates/kit/src/libvirt/base_disks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ pub fn find_or_create_base_disk(
source_image: &str,
image_digest: &str,
install_options: &InstallOptions,
kernel_args: &[String],
connect_uri: Option<&str>,
) -> Result<Utf8PathBuf> {
let metadata = DiskImageMetadata::from(install_options, image_digest, kernel_args);
let metadata = DiskImageMetadata::from(install_options, image_digest);
let cache_hash = metadata.compute_cache_hash();

// Extract short hash for filename (first 16 chars after "sha256:")
Expand All @@ -45,7 +44,6 @@ pub fn find_or_create_base_disk(
base_disk_path.as_std_path(),
image_digest,
install_options,
kernel_args,
)?
.is_ok()
{
Expand All @@ -68,7 +66,6 @@ pub fn find_or_create_base_disk(
source_image,
image_digest,
install_options,
kernel_args,
connect_uri,
)?;

Expand All @@ -81,7 +78,6 @@ fn create_base_disk(
source_image: &str,
image_digest: &str,
install_options: &InstallOptions,
kernel_args: &[String],
connect_uri: Option<&str>,
) -> Result<()> {
use crate::run_ephemeral::CommonVmOpts;
Expand Down Expand Up @@ -136,7 +132,6 @@ fn create_base_disk(
temp_disk_path.as_std_path(),
image_digest,
install_options,
kernel_args,
)
.context("Querying cached disk")?;

Expand Down
1 change: 0 additions & 1 deletion crates/kit/src/libvirt/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
&opts.image,
&image_digest,
&opts.install,
&[], // kernel_args
connect_uri,
)
.with_context(|| "Failed to find or create base disk")?;
Expand Down
5 changes: 0 additions & 5 deletions crates/kit/src/libvirt/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ pub struct LibvirtUploadOpts {
/// Number of vCPUs for installation VM
#[clap(long)]
pub vcpus: Option<u32>,

/// Additional kernel arguments for installation
#[clap(long)]
pub karg: Vec<String>,
}

impl LibvirtUploadOpts {
Expand Down Expand Up @@ -219,7 +215,6 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtUploadOpts
common: crate::run_ephemeral::CommonVmOpts {
memory: opts.memory.clone(),
vcpus: opts.vcpus,
kernel_args: opts.karg.clone(),
..Default::default()
},
..Default::default()
Expand Down
5 changes: 0 additions & 5 deletions crates/kit/src/libvirt_upload_disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ pub struct LibvirtUploadDiskOpts {
#[clap(long)]
pub vcpus: Option<u32>,

/// Additional kernel arguments for installation
#[clap(long)]
pub karg: Vec<String>,

/// Skip uploading to libvirt (useful for testing)
#[clap(long)]
pub skip_upload: bool,
Expand Down Expand Up @@ -290,7 +286,6 @@ pub fn run(opts: LibvirtUploadDiskOpts) -> Result<()> {
common: crate::run_ephemeral::CommonVmOpts {
memory: opts.memory.clone(),
vcpus: opts.vcpus,
kernel_args: opts.karg.clone(),
..Default::default()
},
..Default::default()
Expand Down
8 changes: 4 additions & 4 deletions crates/kit/src/run_ephemeral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,6 @@ pub struct CommonVmOpts {
#[clap(long, help = "Number of vCPUs")]
pub vcpus: Option<u32>,

#[clap(long = "karg", help = "Additional kernel command line arguments")]
pub kernel_args: Vec<String>,

#[clap(long, help = "Enable console output to terminal for debugging")]
pub console: bool,

Expand Down Expand Up @@ -257,6 +254,9 @@ pub struct RunEphemeralOpts {
help = "Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>"
)]
pub mount_disk_files: Vec<String>,

#[clap(long = "karg", help = "Additional kernel command line arguments")]
pub kernel_args: Vec<String>,
}

/// Launch privileged container with QEMU+KVM for ephemeral VM, spawning as subprocess.
Expand Down Expand Up @@ -982,7 +982,7 @@ StandardOutput=file:/dev/virtio-ports/executestatus
kernel_cmdline.push("ds=iid-datasource-none".to_string());
}

kernel_cmdline.extend(opts.common.kernel_args.clone());
kernel_cmdline.extend(opts.kernel_args.clone());

// TODO allocate unlinked unnamed file and pass via fd
let mut tmp_swapfile = None;
Expand Down
6 changes: 2 additions & 4 deletions crates/kit/src/to_disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,6 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
opts.target_disk.as_std_path(),
&image_digest,
&opts.install,
&opts.additional.common.kernel_args,
)? {
Ok(()) => {
println!(
Expand Down Expand Up @@ -421,6 +420,7 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
opts.target_disk,
opts.additional.format.as_str()
)], // Attach target disk
kernel_args: Default::default(),
};

// Phase 5: SSH-based VM configuration and execution
Expand Down Expand Up @@ -475,7 +475,6 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
&opts.source_image,
&opts.target_disk,
&opts.install,
&opts.additional.common.kernel_args,
&opts.additional.format,
);
if let Err(e) = write_result {
Expand All @@ -496,7 +495,6 @@ fn write_disk_metadata(
source_image: &str,
target_disk: &Utf8PathBuf,
install_options: &InstallOptions,
kernel_args: &[String],
format: &Format,
) -> Result<()> {
// Note: xattrs work on regular files including raw and qcow2 images
Expand All @@ -507,7 +505,7 @@ fn write_disk_metadata(
let digest = inspect.digest.to_string();

// Prepare metadata using the new helper method
let metadata = DiskImageMetadata::from(install_options, &digest, kernel_args);
let metadata = DiskImageMetadata::from(install_options, &digest);

// Write metadata using rustix fsetxattr
let file = std::fs::OpenOptions::new()
Expand Down
8 changes: 4 additions & 4 deletions docs/src/man/bcvk-ephemeral-run-ssh.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ Run ephemeral VM and SSH into it

Number of vCPUs

**--karg**=*KERNEL_ARGS*

Additional kernel command line arguments

**--console**

Enable console output to terminal for debugging
Expand Down Expand Up @@ -109,6 +105,10 @@ Run ephemeral VM and SSH into it

Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>

**--karg**=*KERNEL_ARGS*

Additional kernel command line arguments

<!-- END GENERATED OPTIONS -->

# EXAMPLES
Expand Down
8 changes: 4 additions & 4 deletions docs/src/man/bcvk-ephemeral-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ This design allows bcvk to provide VM-like isolation and boot behavior while lev

Number of vCPUs

**--karg**=*KERNEL_ARGS*

Additional kernel command line arguments

**--console**

Enable console output to terminal for debugging
Expand Down Expand Up @@ -135,6 +131,10 @@ This design allows bcvk to provide VM-like isolation and boot behavior while lev

Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>

**--karg**=*KERNEL_ARGS*

Additional kernel command line arguments

<!-- END GENERATED OPTIONS -->

# EXAMPLES
Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/bcvk-libvirt-list-volumes.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ List available bootc volumes with metadata

**--json**

Output as structured JSON instead of table format
Output format (human-readable or JSON)

**--detailed**

Expand Down
4 changes: 4 additions & 0 deletions docs/src/man/bcvk-libvirt-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Run a bootable container as a persistent VM

Path to host container storage (auto-detected if not specified)

**--karg**=*KARG*

Set a kernel argument

**--composefs-native**

Default to composefs-native storage
Expand Down
Loading