test: add --mode vm, the autopkgtest escape hatch

VM virtualization is the one backend pkh does not reimplement: the qemu
runner carries the serial-console protocol, image overlay management
and reboot support, and it is the only one satisfying
isolation-machine/needs-reboot tests. pkh execs the installed
autopkgtest with its qemu runner (--image required, --cpus/--ram-size
passthrough) in its own process group so Ctrl+C reaches the testbed
cleanup, parses the --summary file back into the pkh report model and
maps autopkgtest's exit classes onto the 0/1/2 contract (12/14/16/20
are runtime errors; the raw code rides the JSON report). Pockets, PPAs
and injection are refused in vm mode for now: they would need the
keyring setup inside the image.
This commit is contained in:
2026-09-27 21:33:11 +02:00
parent 15cc19007f
commit 7790b9452d
5 changed files with 334 additions and 16 deletions
+11 -1
View File
@@ -391,7 +391,10 @@ fn main() {
.arg(arg!(-p --pocket <pocket> "Resolve test dependencies from a specific distribution pocket (updates, security, proposed)").required(false))
.arg(arg!(--ppa <ppa> "Add a PPA as test dependency source (can be specified multiple times)").required(false).action(clap::ArgAction::Append))
.arg(arg!(--inject <package> "Inject a package into the testbed before the tests (.deb path or package name, can be specified multiple times)").required(false).action(clap::ArgAction::Append))
.arg(arg!(--mode <mode> "Testbed mode: chroot (default, an ephemeral unshare chroot) or local (the current context, no isolation)").required(false))
.arg(arg!(--mode <mode> "Testbed mode: chroot (default, an ephemeral unshare chroot), local (the current context, no isolation) or vm (a qemu VM through autopkgtest)").required(false))
.arg(arg!(--image <file> "VM image for --mode vm (required there)").required(false))
.arg(arg!(--cpus <n> "VM virtual CPUs (vm mode)").required(false).value_parser(clap::value_parser!(u32)))
.arg(arg!(--"ram-size" <mib> "VM memory size in MiB (vm mode)").required(false).value_parser(clap::value_parser!(u32)))
.arg(arg!(--debs <deb> "Explicit binary package to test, overriding the pkh deb output reuse (can be specified multiple times)").required(false).action(clap::ArgAction::Append))
.arg(
clap::Arg::new("no_build")
@@ -1062,6 +1065,13 @@ fn main() {
.map(|v| v.cloned().collect())
.unwrap_or_default(),
mode,
image: sub_matches
.get_one::<String>("image")
.map(std::path::PathBuf::from),
cpus: sub_matches.get_one::<u32>("cpus").copied(),
ram_size: sub_matches
.get_one::<u32>("ram-size")
.map(|v| v.to_string()),
debs: sub_matches
.get_many::<String>("debs")
.map(|v| v.map(std::path::PathBuf::from).collect())