Skip to content

Commit a465f18

Browse files
committed
to-disk: Add support for --karg
For the same reason we propagate other options. Note that we had incorrectly included karg in CommonVmOptions but that can't work without direct kernel boot. Signed-off-by: Colin Walters <walters@verbum.org>
1 parent a73ec8d commit a465f18

15 files changed

Lines changed: 59 additions & 82 deletions

crates/integration-tests/src/tests/libvirt_verb.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ pub fn test_libvirt_run_ssh_full_workflow() {
356356
LIBVIRT_INTEGRATION_TEST_LABEL,
357357
"--filesystem",
358358
"ext4",
359+
"--karg",
360+
"bcvk.test-install-karg=1",
359361
&test_image,
360362
])
361363
.expect("Failed to run libvirt run with SSH");
@@ -375,9 +377,9 @@ pub fn test_libvirt_run_ssh_full_workflow() {
375377
println!("Waiting for VM to boot and SSH to become available...");
376378
std::thread::sleep(std::time::Duration::from_secs(30));
377379

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

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

389391
// Check SSH results
390392
if !ssh_output.success() {
391-
panic!("SSH connection failed: {}", ssh_output.stderr);
393+
panic!(
394+
"SSH connection failed: {}\nkernel cmdline: {}",
395+
ssh_output.stderr, ssh_output.stdout
396+
);
392397
}
393398

394-
// Verify we got the expected output
399+
// Verify we got the expected karg in /proc/cmdline
395400
assert!(
396-
ssh_output.stdout.contains("hello world"),
397-
"Expected 'hello world' in SSH output. Got: {}",
401+
ssh_output.stdout.contains("bcvk.test-install-karg=1"),
402+
"Expected bcvk.test-install-karg=1 in kernel cmdline.\nActual cmdline: {}",
398403
ssh_output.stdout
399404
);
400405

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

crates/kit/src/cache_metadata.rs

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,13 @@ impl DiskImageMetadata {
153153

154154
impl DiskImageMetadata {
155155
/// Create new metadata from InstallOptions and image digest
156-
pub fn from(options: &InstallOptions, image: &str, kernel_args: &[String]) -> Self {
156+
pub fn from(options: &InstallOptions, image: &str) -> Self {
157157
Self {
158158
version: 1,
159159
digest: image.to_owned(),
160160
filesystem: options.filesystem.clone(),
161161
root_size: options.root_size.clone(),
162-
kernel_args: kernel_args.to_vec(),
162+
kernel_args: options.karg.clone(),
163163
composefs_native: options.composefs_native,
164164
}
165165
}
@@ -180,15 +180,14 @@ pub fn check_cached_disk(
180180
path: &Path,
181181
image_digest: &str,
182182
install_options: &InstallOptions,
183-
kernel_args: &[String],
184183
) -> Result<Result<(), ValidationError>> {
185184
if !path.exists() {
186185
tracing::debug!("Disk image {:?} does not exist", path);
187186
return Ok(Err(ValidationError::MissingFile));
188187
}
189188

190189
// Create metadata for the current request to compute expected hash
191-
let expected_meta = DiskImageMetadata::from(install_options, image_digest, kernel_args);
190+
let expected_meta = DiskImageMetadata::from(install_options, image_digest);
192191
let expected_hash = expected_meta.compute_cache_hash();
193192

194193
// Read the cache hash from the disk image
@@ -241,26 +240,16 @@ mod tests {
241240
let install_options1 = InstallOptions {
242241
filesystem: Some("ext4".to_string()),
243242
root_size: Some("20G".to_string()),
244-
storage_path: None,
245-
composefs_native: false,
243+
..Default::default()
246244
};
247-
let metadata1 = DiskImageMetadata::from(
248-
&install_options1,
249-
"sha256:abc123",
250-
&["console=ttyS0".to_string()],
251-
);
245+
let metadata1 = DiskImageMetadata::from(&install_options1, "sha256:abc123");
252246

253247
let install_options2 = InstallOptions {
254248
filesystem: Some("ext4".to_string()),
255249
root_size: Some("20G".to_string()),
256-
storage_path: None,
257-
composefs_native: false,
250+
..Default::default()
258251
};
259-
let metadata2 = DiskImageMetadata::from(
260-
&install_options2,
261-
"sha256:abc123",
262-
&["console=ttyS0".to_string()],
263-
);
252+
let metadata2 = DiskImageMetadata::from(&install_options2, "sha256:abc123");
264253

265254
// Same inputs should generate same hash
266255
assert_eq!(
@@ -272,14 +261,9 @@ mod tests {
272261
let install_options3 = InstallOptions {
273262
filesystem: Some("ext4".to_string()),
274263
root_size: Some("20G".to_string()),
275-
storage_path: None,
276-
composefs_native: false,
264+
..Default::default()
277265
};
278-
let metadata3 = DiskImageMetadata::from(
279-
&install_options3,
280-
"sha256:xyz789",
281-
&["console=ttyS0".to_string()],
282-
);
266+
let metadata3 = DiskImageMetadata::from(&install_options3, "sha256:xyz789");
283267

284268
assert_ne!(
285269
metadata1.compute_cache_hash(),
@@ -290,14 +274,9 @@ mod tests {
290274
let install_options4 = InstallOptions {
291275
filesystem: Some("xfs".to_string()),
292276
root_size: Some("20G".to_string()),
293-
storage_path: None,
294-
composefs_native: false,
277+
..Default::default()
295278
};
296-
let metadata4 = DiskImageMetadata::from(
297-
&install_options4,
298-
"sha256:abc123",
299-
&["console=ttyS0".to_string()],
300-
);
279+
let metadata4 = DiskImageMetadata::from(&install_options4, "sha256:abc123");
301280

302281
assert_ne!(
303282
metadata1.compute_cache_hash(),

crates/kit/src/install_options.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ pub struct InstallOptions {
2929
)]
3030
pub storage_path: Option<Utf8PathBuf>,
3131

32+
#[clap(long)]
33+
/// Set a kernel argument
34+
pub karg: Vec<String>,
35+
3236
/// Default to composefs-native storage
3337
#[clap(long)]
3438
pub composefs_native: bool,
@@ -49,6 +53,10 @@ impl InstallOptions {
4953
args.push(root_size.clone());
5054
}
5155

56+
for k in self.karg.iter() {
57+
args.push(format!("--karg={k}"));
58+
}
59+
5260
if self.composefs_native {
5361
args.push("--composefs-native".to_owned());
5462
}

crates/kit/src/libvirt/base_disks.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ pub fn find_or_create_base_disk(
1717
source_image: &str,
1818
image_digest: &str,
1919
install_options: &InstallOptions,
20-
kernel_args: &[String],
2120
connect_uri: Option<&str>,
2221
) -> Result<Utf8PathBuf> {
23-
let metadata = DiskImageMetadata::from(install_options, image_digest, kernel_args);
22+
let metadata = DiskImageMetadata::from(install_options, image_digest);
2423
let cache_hash = metadata.compute_cache_hash();
2524

2625
// Extract short hash for filename (first 16 chars after "sha256:")
@@ -45,7 +44,6 @@ pub fn find_or_create_base_disk(
4544
base_disk_path.as_std_path(),
4645
image_digest,
4746
install_options,
48-
kernel_args,
4947
)?
5048
.is_ok()
5149
{
@@ -68,7 +66,6 @@ pub fn find_or_create_base_disk(
6866
source_image,
6967
image_digest,
7068
install_options,
71-
kernel_args,
7269
connect_uri,
7370
)?;
7471

@@ -81,7 +78,6 @@ fn create_base_disk(
8178
source_image: &str,
8279
image_digest: &str,
8380
install_options: &InstallOptions,
84-
kernel_args: &[String],
8581
connect_uri: Option<&str>,
8682
) -> Result<()> {
8783
use crate::run_ephemeral::CommonVmOpts;
@@ -136,7 +132,6 @@ fn create_base_disk(
136132
temp_disk_path.as_std_path(),
137133
image_digest,
138134
install_options,
139-
kernel_args,
140135
)
141136
.context("Querying cached disk")?;
142137

crates/kit/src/libvirt/run.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
179179
&opts.image,
180180
&image_digest,
181181
&opts.install,
182-
&[], // kernel_args
183182
connect_uri,
184183
)
185184
.with_context(|| "Failed to find or create base disk")?;

crates/kit/src/libvirt/upload.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ pub struct LibvirtUploadOpts {
4242
/// Number of vCPUs for installation VM
4343
#[clap(long)]
4444
pub vcpus: Option<u32>,
45-
46-
/// Additional kernel arguments for installation
47-
#[clap(long)]
48-
pub karg: Vec<String>,
4945
}
5046

5147
impl LibvirtUploadOpts {
@@ -219,7 +215,6 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtUploadOpts
219215
common: crate::run_ephemeral::CommonVmOpts {
220216
memory: opts.memory.clone(),
221217
vcpus: opts.vcpus,
222-
kernel_args: opts.karg.clone(),
223218
..Default::default()
224219
},
225220
..Default::default()

crates/kit/src/libvirt_upload_disk.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ pub struct LibvirtUploadDiskOpts {
4444
#[clap(long)]
4545
pub vcpus: Option<u32>,
4646

47-
/// Additional kernel arguments for installation
48-
#[clap(long)]
49-
pub karg: Vec<String>,
50-
5147
/// Skip uploading to libvirt (useful for testing)
5248
#[clap(long)]
5349
pub skip_upload: bool,
@@ -290,7 +286,6 @@ pub fn run(opts: LibvirtUploadDiskOpts) -> Result<()> {
290286
common: crate::run_ephemeral::CommonVmOpts {
291287
memory: opts.memory.clone(),
292288
vcpus: opts.vcpus,
293-
kernel_args: opts.karg.clone(),
294289
..Default::default()
295290
},
296291
..Default::default()

crates/kit/src/run_ephemeral.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,6 @@ pub struct CommonVmOpts {
165165
#[clap(long, help = "Number of vCPUs")]
166166
pub vcpus: Option<u32>,
167167

168-
#[clap(long = "karg", help = "Additional kernel command line arguments")]
169-
pub kernel_args: Vec<String>,
170-
171168
#[clap(long, help = "Enable console output to terminal for debugging")]
172169
pub console: bool,
173170

@@ -257,6 +254,9 @@ pub struct RunEphemeralOpts {
257254
help = "Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>"
258255
)]
259256
pub mount_disk_files: Vec<String>,
257+
258+
#[clap(long = "karg", help = "Additional kernel command line arguments")]
259+
pub kernel_args: Vec<String>,
260260
}
261261

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

985-
kernel_cmdline.extend(opts.common.kernel_args.clone());
985+
kernel_cmdline.extend(opts.kernel_args.clone());
986986

987987
// TODO allocate unlinked unnamed file and pass via fd
988988
let mut tmp_swapfile = None;

crates/kit/src/to_disk.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
310310
opts.target_disk.as_std_path(),
311311
&image_digest,
312312
&opts.install,
313-
&opts.additional.common.kernel_args,
314313
)? {
315314
Ok(()) => {
316315
println!(
@@ -421,6 +420,7 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
421420
opts.target_disk,
422421
opts.additional.format.as_str()
423422
)], // Attach target disk
423+
kernel_args: Default::default(),
424424
};
425425

426426
// Phase 5: SSH-based VM configuration and execution
@@ -475,7 +475,6 @@ pub fn run(opts: ToDiskOpts) -> Result<()> {
475475
&opts.source_image,
476476
&opts.target_disk,
477477
&opts.install,
478-
&opts.additional.common.kernel_args,
479478
&opts.additional.format,
480479
);
481480
if let Err(e) = write_result {
@@ -496,7 +495,6 @@ fn write_disk_metadata(
496495
source_image: &str,
497496
target_disk: &Utf8PathBuf,
498497
install_options: &InstallOptions,
499-
kernel_args: &[String],
500498
format: &Format,
501499
) -> Result<()> {
502500
// Note: xattrs work on regular files including raw and qcow2 images
@@ -507,7 +505,7 @@ fn write_disk_metadata(
507505
let digest = inspect.digest.to_string();
508506

509507
// Prepare metadata using the new helper method
510-
let metadata = DiskImageMetadata::from(install_options, &digest, kernel_args);
508+
let metadata = DiskImageMetadata::from(install_options, &digest);
511509

512510
// Write metadata using rustix fsetxattr
513511
let file = std::fs::OpenOptions::new()

docs/src/man/bcvk-ephemeral-run-ssh.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ Run ephemeral VM and SSH into it
3333

3434
Number of vCPUs
3535

36-
**--karg**=*KERNEL_ARGS*
37-
38-
Additional kernel command line arguments
39-
4036
**--console**
4137

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

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

108+
**--karg**=*KERNEL_ARGS*
109+
110+
Additional kernel command line arguments
111+
112112
<!-- END GENERATED OPTIONS -->
113113

114114
# EXAMPLES

0 commit comments

Comments
 (0)