Repository navigation
nvx-rs: apply a clone's Activate to its root and workload - #940
Merged
Pedro Henrique Penna (ppenna) merged 1 commit intoOct 28, 2026
Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
Pedro Henrique Penna (ppenna) merged 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the root and workload activation changes.
No open issues 🎉
What changed in this PR
Implements root and workload activation for restored clones, building on #939’s activation state machine as part 2 of #843. The new API applies an accepted record before the adapter reports completion and opens workload admission.
Changes:
- Adds
apply,RootTemplate,Applied, andApplyErrorfor EROFS root assembly and workload-account validation, with cleanup on failure. - Adds fake-system tests covering admission gating, record inputs, retries, account refusals, and assembly failures.
- Documents adapter integration and the settings deferred to #845, including GPT support, export, network, hostname, and machine ID.
| File | Description |
|---|---|
nvx-rs/src/guest/mod.rs |
Updates the guest-module overview with root and workload activation. |
nvx-rs/src/guest/clone/activation/apply/tests.rs |
Tests activation ordering, settings, retries, and failure cleanup. |
nvx-rs/src/guest/clone/activation/apply.rs |
Implements root assembly, identity validation, and application results. |
nvx-rs/src/guest/clone/activation.rs |
Exports the application API and updates the adapter example. |
nvx-rs/src/guest/clone.rs |
Re-exports the API and documents its lifecycle and privilege requirements. |
nvx-rs/README.md |
Documents clone application behavior and its current scope. |
Review effort: Balanced
This was referenced Oct 27, 2026
A clone's activation hands the adapter the record of the one Activate that it accepted. nvx::guest::clone::apply now applies it as at a cold boot, and returns the result that the adapter reports to Activation::complete: - It assembles the root with nvx::guest::root::assemble, with the record's image, an EROFS image whose UUID it checks if the record expects one, its upper, a tmpfs or the scratch with the record's journal policy, and its overlay mode, and with a RootTemplate: the inputs that the guest takes from its own configuration, which its template captured, the runtime directory, the distro and scratch devices, and how long the assembly waits for them. - It refuses a GPT disk before anything has a side effect, since the kernel created the block devices of the disk's partitions when it found the template's placeholder. - With the record's workload identity, it checks the identity's account in the assembled root before Ready, as NVX's init checks it at boot: Identity::new(uid, gid), without supplementary groups or capabilities, in existing-account mode, in which every execution then runs. Without one, each execution names its own identity, which Entry::check checks. It returns the Applied root and identity, which the adapter keeps, or an ApplyError, after which nothing that it mounted stays mounted, unless the error holds the unmounts that failed. It applies none of the record's other settings, its export, network, hostname, and machine ID, and it starts no process and generates no ID. Its tests drive the activation through an adapter of their own, whose fake system records every mount, account read, and teardown, and which spawns an execution only once the fence is open: nothing happens before a valid Activate, the assembly's and the identity's inputs come exactly from the record, and an image without the workload identity's account is refused before Ready. Part of #843 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8a2f342b-b46d-4a26-a11e-a996e3c1e925
Enrique Saurez (esaurez)
force-pushed
the
esaurez/843-pr1-activation-state-machine-20261024
branch
from
October 28, 2026 02:09
4e08935 to
62d8f3a
Compare
Enrique Saurez (esaurez)
force-pushed
the
esaurez/843-pr2-root-workload-activation-20261024
branch
from
October 28, 2026 02:09
d3809fb to
2747742
Compare
This was referenced Oct 28, 2026
6 tasks
Base automatically changed from
esaurez/843-pr1-activation-state-machine-20261024
to
dev
October 28, 2026 18:28
Pedro Henrique Penna (ppenna)
deleted the
esaurez/843-pr2-root-workload-activation-20261024
branch
October 28, 2026 19:05
This was referenced Oct 29, 2026
This was referenced Oct 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #939; this PR retargets when its parent merges.
Chain: #933 → #880 → #936 → #937 → #939 → this PR → #941, on
dev; #879, #881, #885, #886, #877, #932, #884, and #887 have merged.Part of #843 (PR 2 of 3: root and workload activation).
What and why
#939's
Activationhands the adapter the record of the one Activate that it accepted, and opens the fence of workload admission only once the adapter reports that the record was applied. This adds that application,nvx::guest::clone::apply(record, &RootTemplate) -> Result<Applied, ApplyError>, which activates the clone's root and workload as at a cold boot:nvx::guest::root::assemble, with the record's settings: its image, an EROFS image whose UUID it checks if the record expects one; its upper, a tmpfs or the scratch, with the record's journal policy; and its overlay mode. The assembly's other inputs come from aRootTemplate, which the guest takes from its own configuration, as its template captured it: the runtime directory, thedistroand scratch block devices, and how long the assembly waits for them.nvx::guest::entry::Identity::new(uid, gid), without supplementary groups or capabilities, in existing-account mode. Its account is checked in the assembled root before Ready, as NVX's init checks it at boot, and every execution runs as it. Without one, the adapter gives each execution its own identity, whichEntry::checkchecks.Appliedroot and identity, which the adapter keeps, or anApplyError(Gpt,Assembly, orAccount), after which nothing that it mounted stays mounted, unless the error holds the unmounts that failed. The adapter passes the result toActivation::complete. So a failed application is final, nothing retries it, and the fence still opens only insidecomplete.Ready's activation fields come from
nvx::activation::ReadyActivation, beside the adapter's own identities: that the activation applied, with the record's transaction ID. The adapter's framing comes in #941.Later in the stack
#941 gives
applythe activation's deadline:apply(record, template, deadline). The assembly waits for each device as long as the template's timeout allows, but never past the deadline: it checks the time before each poll, and sleeps no longer than until the deadline, at which it polls a last time if the deadline comes first, so that the application ends by then, past whichActivation::completefails the activation as expired.Validation
This PR was rebased onto #937's new head, 5683164, without conflicts and with its patch unchanged. At its new head, 2747742, with the OpenVMM submodule at its gitlink, d2338ea2:
Linux x86_64:
cargo fmt --check; Clippy with-D warnings,--all-targets --all-features,--lib, and--lib --no-default-features;cargo test --all-features(1798 passed),cargo test(877 passed), and the--lib --no-default-featuresbuild and test (260 passed);tests/host_modules.rs(22 passed); the bundled-artifacts test (19 passed); rustdoc with-D warnings; the MSRV (1.89) check; the aarch64-apple-darwin check.nvx.py check-guest-binaries(musl Clippy and tests, 980 passed),build-guest-binaries,test-guest-binaries(33 passed),check-static-elf.tests/runtime-adapter, which builds on nvx-rs: fmt, Clippy, build, tests, and MSRV in its protocol-only (46 passed), host-only (98 passed), and musl guest (120 passed) configurations.scripts/check_markdown_links.py./dev/null: the privileged capture test, the strict cold boot that stops at its violation, and the tests ofguest::cloneandguest::reseed(74 passed); the runtime adapter's library and guest-session tests (112 passed).Windows (x86_64-pc-windows-msvc): nvx-rs fmt, Clippy (all features,
--lib, no default features, each feature alone, and all features for the musl target), tests (all features 1118 passed, default 896, no default features 260),tests/host_modules.rs, rustdoc, MSRV;tests/runtime-adapterfmt, Clippy, build, tests (protocol-only 46 passed, host 99), and MSRV in its protocol-only and host configurations, and Clippy and MSRV in its musl guest configuration; the Markdown links. The adapter's musl rustdoc with-D warnings, which CI doesn't run, fails with the same five broken links inexec.rsandworker/mapping.rsas at #937's head; this PR doesn't touch them.Per commit, on Linux x86_64 and on Windows: fmt, Clippy with
-D warningsin CI's three configurations and--lib, andtests/host_modules.rs; on Linux, also the aarch64-apple-darwin check, and on Windows, Clippy for the musl target.This PR needs no VM. #941 runs the runtime adapter's VM suites at the head of the stack, whose guest runs this PR's code: in the CI run below, at ea69821, 58 of 58 passed on KVM, on MSHV, and on WHP.
CI:
ci.ymlrun 40619378275, dispatched on #941's head, ea69821, which covers this PR's code, since this chain's PRs don't targetdevand get no PR CI, passed: 36 jobs succeeded, among them nvx-rs and the CLI on Linux and Windows, the guest artifacts, OpenVMM's binaries, unit tests, and vmm-tests, and the NVX microVM tests, with the runtime adapter's VM suites, and the platform jobs on KVM, MSHV, and WHP; the 6 jobs that only pull requests ordevrun were skipped.Tests added (
nvx-rs/src/guest/clone/activation/apply/tests.rs). They drive the activation through an adapter of their own, whose fake system records every mount, account read, and teardown, and which spawns an execution only once the fence is open: