Repository navigation
runtime-adapter: start and run from a template, and run the stage's scenarios as one suite - #963
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Relative NVX_ARTIFACTS_DIR paths remain unresolved when Cargo runs in tests/runtime-adapter, causing VM tests to look in the wrong directory and potentially fail despite artifacts being present.
1 open issue
What changed in this PR
Completes the runtime adapter’s template and clone operations for #847 by adding a one-execution run command, typed selection refusals, and a named acceptance suite.
Changes:
- Reports template-selection refusals separately from clone failures.
- Runs one authenticated execution in a clone, preserving its network and shares, then tears it down and releases its lease.
- Adds a manifest of 153 scenarios across 10 targets and integrates name and result checks into CI.
| File | Description |
|---|---|
| tests/runtime-adapter/tests/vm_clone.rs | Tests selection refusals and clone runs, including networks and shares. |
| tests/runtime-adapter/tests/host_session.rs | Tests shutdown with late execution messages. |
| tests/runtime-adapter/tests/clone_start.rs | Tests run options, preflight, and selection refusals. |
| tests/runtime-adapter/src/lib.rs | Documents running an execution in a clone. |
| tests/runtime-adapter/src/host/executions.rs | Identifies messages belonging to tracked executions. |
| tests/runtime-adapter/src/host.rs | Allows shutdown to skip accepted late messages. |
| tests/runtime-adapter/src/bin/runtime-adapter-host.rs | Implements selection outcomes and the shared start/run lifecycle. |
| tests/runtime-adapter/scenarios.txt | Names the consolidated stage suite. |
| tests/runtime-adapter/README.md | Documents operations, outcomes, and every stage scenario. |
| scripts/test_nvx_tools.py | Tests suite validation, execution checks, and CI wiring. |
| scripts/nvx.py | Registers test-runtime-adapter. |
| scripts/nvx_tools/runtime_adapter_tests.py | Validates scenario coverage and runs named tests. |
| scripts/nvx_tools/ci.py | Makes suite-runner changes trigger microVM tests. |
| doc/usage.md | Documents the new suite command. |
| doc/contribute.md | Updates contributor guidance for running the suite. |
| doc/ci.md | Describes named runtime-adapter coverage in CI. |
| .github/workflows/run-nvx-microvm-tests.yml | Runs the consolidated suite on Linux and Windows. |
| .github/actions/validate-nvx/action.yml | Checks the new command’s help on both platforms. |
Review effort: Balanced
597b1b4 to
7500b77
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The execution-error path discards teardown status 8 and exits with 1, losing the typed clone-failure outcome; it should preserve that status and add coverage for a clone dying during execution.
1 open issue
Review effort: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
Static review confirmed suite coverage but could not establish teardown, lease-release, and VM-exit race correctness without fresh exact-head runtime validation on KVM, MSHV, and WHP.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
59525ef to
918e6fc
Compare
32942c3 to
83fdc81
Compare
918e6fc to
6863d47
Compare
83fdc81 to
43879d7
Compare
6863d47 to
f43428e
Compare
A start whose template store refuses its selection now ends with the refusal's record, in the form of a clone failure's, at the stage `selection`, and with the exit status 10, before it leases or launches anything. A template store that does not exist, and a generation that the store never published or no longer holds, name no template; a generation whose capture the restore window of its time contract no longer admits at the host's time is expired; and one that a tombstone quarantines, or whose capture is after the host's time, is ineligible. The record's code is that of NVX's error, and the diagnostic stays on standard error. A selection that races a retirement, or follows one that a crash interrupted, ends as the store's refusal of the lease too: a retirement tombstones a generation before it deletes its payload, and deletes none that a lease keeps, and the start reads the generation's compatibility key before the lease only for a memory target that the request does not name, leaving a key that it cannot read to NVX's plan. The clone tests check each refusal through the record, including a generation that `remove` retired, and the unit tests the refusals of a selection that names no template, which need no hypervisor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d3db585-441c-495b-901f-ab7203c0f36b
`runtime-adapter-host run` runs one execution in a clone of a generation of a template store, then tears the clone down, in one command. - Its preflight stages the clone's images in the sandbox's store, as `stage` does, and prints `preflight=staged`, before the clone's start, which hashes nothing. A start that the guest would refuse fails the command, as a usage error, before it stages anything. - It starts the clone as `start` does, through the same code, and ends as a start ends once the template store refuses the selection (status 10) or the clone fails (8, or 9 while the teardown is unresolved). - It runs the execution in the clone's root, through `host::Executions`, in the session of the clone order in which the clone's sandbox started, as `exec` runs one: the program, its arguments, and its environment reach the guest in the execution's start, never in the template's boot tokens. - Whatever the execution did, it stops the clone as `stop` does, and releases the lease once the VM exited. It holds the sandbox's lock from the lease to the teardown. It exits 0 once the execution finished, whatever its status, and the clone stopped. - An execution that failed to run, as one whose session ended, fails the command after the teardown. Since the session may have ended with the VM, as when its VMM crashed, the run first waits up to 10 seconds for the VMM to exit, as a stop waits for one that it terminated: the stop then finds that the VM exited without it, and ends the clone as a reattach that finds it so does, with the record of its failure. The run exits with the stop's status once it is not a success (8, or 9, for a clone that failed, and 4 for a root that failed), and with 1 otherwise. The stop takes the same session, in which the guest may still send messages about an execution that the driver finished without them, as when it gave up waiting for its outcome. `Client::stop_skipping` stops the guest agent as `stop` does, but skips the messages that its caller accepts, and `Executions::is_about` accepts the guest's messages about the driver's own executions; `stop` keeps its behavior. The parsing of an execution's options, the checks of its starts, the run of the executions, and the stop of a VM are factored out of `exec` and `reattach`, which keep their behavior. The README gains the table of the template and clone operations, and documents `run`, its key, and its statuses. The unit tests cover run's command lines and its refused selections after the preflight, and a stop that skips the guest's late messages about the executions that the driver gave up on; the VM tests cover a run with one execution, an execution that the guest refuses, and runs whose clone does not start. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d3db585-441c-495b-901f-ab7203c0f36b
The stage's integration of network templates and exports gives `start` the options `--network` and `--share`, with `--deny`, `--reserved`, and `--share-root`, beside `--first-partition-bound` and `--machine-id`, and `run` takes the options of a start. A run read its network only in its start, though, once its preflight staged the images, and checked the execution's start without the proxy of the network. So `CloneOptions::plan` now reads the clone's network, and plans the clone and the export of its shares, as the start did first, and both commands plan before anything else: a start before it reads the template store, and a run before its preflight stages anything. A network, an image, or shares that the plan refuses then fail a run with nothing created, and the run checks the execution's start with the URL of the network's proxy in its environment, as `exec` gives it to an execution of a clone, before it stages anything. The start's behavior is unchanged. The host program's documentation and the README give `run` the start's options, and say that the execution finds the clone's shares beneath its root. `clone_start` checks the run's new usage errors, and that a run refuses a network or shares that the plan refuses before it stages anything. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d3db585-441c-495b-901f-ab7203c0f36b
…th shares, in VMs `run` now takes the start's network and shares, so two rows check that the run's execution gets them in its clone, in one command: - a run of a clone of a proxy-only template gives its execution the URL of the network's proxy in `http_proxy`, `https_proxy`, `HTTP_PROXY`, and `HTTPS_PROXY`, after the execution's own entries, as the executions of a started clone find it, then tears the clone down; a run of a network that lets nothing through finds no template there, and NVX's plan refuses its clone, once the preflight staged the images, before any VMM starts, so the run runs nothing; - a run's execution reads a host file through the run's share, which the restore sequence mapped beneath the clone's root before the clone's sandbox started, and writes another through it, which the host's directory keeps once the run tore the clone down. A third row checks a run whose clone's VM exits during its execution. The execution, as user ID 0, tells the host through the run's share that it runs, then waits, while the test terminates the clone's VMM. The run waits for the VMM's exit, so its stop finds that the VM exited, and the clone fails, as NVX attributes the loss of its status, which quarantines nothing. The run ends with that failure's status 8, after the diagnostic of the executions' failure, once it released the lease, and the template still serves clones. `Cloned::assert_ran_mapped` checks a run whose clone applied mappings, `execution_facts` returns what a run, or an exec, printed of its first execution, and `Template::begin_in` begins a start or a run that the test ends itself. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d3db585-441c-495b-901f-ab7203c0f36b
The adapter's CI step ran its ignored tests, so a VM scenario that was renamed or gone dropped out of it without a failure, and the scenarios without a hypervisor ran only in the nvx-rs job. tests/runtime-adapter/scenarios.txt now names the stage's consolidated suite, each scenario by its test target and test: every operation's outcomes, from create to run, without a hypervisor and in VMs, and every scenario of vm_template, vm_clone, vm_layered, vm_restart and vm_steps, 155 in all. nvx.py test-runtime-adapter runs it. It takes the adapter's test targets from Cargo's metadata and lists the tests of each named one, and fails unless the lines name exactly those tests and neither the library nor another test target has an ignored test. It then runs each target's scenarios by name with --exact, the ignored ones included, and fails unless each of them reported ok and the target passed as many tests as it names. --check-only checks the names alone. The microVM workflow's runtime adapter steps run it on each backend in place of cargo test -- --ignored, and validate-nvx checks its help. The README lists every scenario with what it proves, in the order of the manifest, which a unit test keeps in step. The usage, CI and contribution documents describe the command. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d3db585-441c-495b-901f-ab7203c0f36b
f43428e to
41a4181
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The validator incorrectly rejects an explicitly selected KVM backend on hosts exposing both /dev/mshv and accessible /dev/kvm, preventing the suite from running despite explicit backend support.
1 open issue
Review effort: Balanced
| targets = read_scenarios() | ||
| environment = os.environ.copy() | ||
| if not check_only: | ||
| validate_openvmm_test_backend(backend) |

Part of #847 (PR 2 of 2: start and run from a template, and the stage's suite).
Stacked on #962.
Chain: #951 → #954 → #957 → #959 → #960 → #955 → #958 → #962 → this PR, on
dev; #879, #881, #885, #886, #877, #932, #884, #887, #933, #880, #936, #937, #939, #940, #941, #888, #949, and #950 have merged.What and why
#847 asks the runtime adapter to implement every template and clone operation through public APIs and its own framing, and to run the stage's scenarios as one suite. Below this PR, the adapter's host program creates, refreshes, lists, inspects, and removes templates (#962), and starts clones of them (#954), with exports and networks (#955, #958). This PR completes the operations table: typed outcomes for a start's selection, and a
runcommand. It also runs every scenario of the stage by name in CI.Start: the selections that the template store refuses
A start whose template store refuses its selection ends with status 10, before it leases or launches anything. It prints the refusal's record, in the form of a clone failure's, at the stage
selection:no-template: a template store that does not exist (no-store), or a generation that the store never published (unpublished) or no longer holds (retired);expired: a generation whose capture the restore window of its time contract no longer admits at the host's time;ineligible: a generation that a tombstone quarantines (tombstone), or whose capture is after the host's time (early).The record's code is the code of NVX's error. Without
--memory, the start reads the generation's compatibility key before the lease, for the template's RAM, but a key that it cannot read gives no memory target rather than a failure, and the lease decides. A selection that races a retirement, or follows one that a crash interrupted, then ends as the store's refusal rather than as a failed read. A clone that NVX's plan refuses after the lease, such as one whose key cannot be read or whose network policy is not the template's, still ends with status 8.Run: one execution in a clone
runtime-adapter-host runtakes the options ofstart, then one execution, asexectakes it:preflight=staged), so the start hashes nothing.startdoes, through the same code. It ends as a start ends when the store refuses the selection (10) or the clone fails (8, or 9 while the teardown is unresolved).stopdoes and releases the lease. It prints the execution's result and the teardown's outcome.It never captures, boots cold, rehashes, or falls back to another format. Its executions find the policy's proxy, and the clone's shares beneath its root, as the executions of a started clone do.
The stage's suite, by name
tests/runtime-adapter/scenarios.txtnames the stage's consolidated suite: 155 scenarios in 11 test targets. They cover every operation's outcomes, fromcreatetorun, without a hypervisor and in VMs, and every scenario ofvm_template,vm_clone,vm_layered,vm_restart, andvm_steps. The newnvx.py test-runtime-adapter --backend {kvm,mshv,whp}runs it, in place ofcargo test -- --ignored, in the microVM workflow's runtime adapter steps. It fails when:ok, or a target passes fewer tests than it names, so a run of no test fails.--check-onlychecks the names alone. The README's "Stage scenarios" table lists every scenario with what it proves, in the manifest's order, which a unit test keeps in step.Commits
runtime-adapter: type the selections that a template store refusesruntime-adapter: run one execution in a clone of a templateruntime-adapter: give a run the network and shares of its startruntime-adapter: run executions in clones of network templates and with shares, in VMsruntime-adapter: run the stage's scenarios as one suite, by nameValidation
At this PR's head f43428e, the same five commits as the earlier head 918e6fc, restacked onto #962's head 43879d7: its tree, 82135bf4, is the merge of 918e6fc into
devat fbeb563, which holds #951, #954 and #957, plus #955's fix that treats a path whose links loop as a changed object. That merge, without the fix, passed the documentation gates ofnvx-rsand of the test adapter, Clippy, validate-nvx on Linux and on Windows, and the Markdown link check; the fix has its own tests in #955. The rest of this section describes 918e6fc, on #962's earlier head 32942c3.Pending at 918e6fc.