Repository navigation
host: restore a VM from a snapshot and a VmConfig (SL2.16) - #1470
Pedro Henrique Penna (ppenna) merged 2 commits into
Conversation
This pull request changes existing testsIt modifies or removes 9 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests. Test code
Relocated unchanged: 0; added: 14. Compared the merge base |
There was a problem hiding this comment.
🔵 Needs a closer look
The new restore path and external-launch example lack VM runtime validation on the pinned OpenVMM, leaving Linux hard-link and dead-controller safety checks unresolved and requiring human review.
No open issues 🎉
What changed in this PR
Implements SL2.16 of #1103: caller-owned snapshot restore preparation through host::vm::create, building on the composed launch and capture APIs without requiring a sandbox store.
Changes:
- Adds strict restore eligibility checks, hard-linked snapshot views, rollback, and restore arguments using captured NIC addressing with current network policy.
- Transfers the prebound restore-ready listener through both launch paths and extends the external-launch example.
- Shares VM directory ownership below snapshot and launch modules, updates tests and documentation, and includes named-snapshot CLI groundwork.
The PR remains a draft handoff; new-path VM runtime validation and full CI/dependency validation are outstanding.
| File | Description |
|---|---|
scripts/test-layout-allowlist.json |
Updates allowances for removed hooks and CLI groundwork. |
nvx-rs/src/host/vm/tests.rs |
Adds restore eligibility, rollback, arguments, and listener-ownership coverage. |
nvx-rs/src/host/vm.rs |
Implements restore preparation and listener handoff. |
nvx-rs/src/host/vm_directory/tests.rs |
Relocates directory privacy and endpoint tests. |
nvx-rs/src/host/vm_directory.rs |
Extracts shared VM directory and output ownership. |
nvx-rs/src/host/snapshot/tests.rs |
Adds reusable restore fixtures and hard-link tests. |
nvx-rs/src/host/snapshot/capture.rs |
Uses the shared directory module to avoid a launch dependency. |
nvx-rs/src/host/snapshot.rs |
Adds fixed-inventory restore-view hard linking. |
nvx-rs/src/host/restore.rs |
Uses shared directory ownership and exposes ready-event receipt. |
nvx-rs/src/host/mod.rs |
Registers the private directory module. |
nvx-rs/src/host/config/mod.rs |
Shares launch rendering and adds restore-device arguments. |
nvx-rs/src/host/cli/store/mod.rs |
Exposes locked state internally for snapshot storage. |
nvx-rs/src/host/cli/snapshots/tests.rs |
Tests snapshot naming, publication, locking, and privacy. |
nvx-rs/src/host/cli/snapshots.rs |
Adds immutable named-snapshot storage groundwork. |
nvx-rs/src/host/cli/sandbox/state/tests.rs |
Tests source-snapshot serialization and validation. |
nvx-rs/src/host/cli/sandbox/state.rs |
Records optional source-snapshot names and shares utilities. |
nvx-rs/src/host/cli/mod.rs |
Registers snapshot storage and centralizes utility functions. |
nvx-rs/README.md |
Documents restore ownership, locking, and example usage. |
nvx-rs/public-api/windows.txt |
Records the ready receiver and listener fields. |
nvx-rs/public-api/linux.txt |
Records the ready receiver and listener fields. |
nvx-rs/examples/external-launch.rs |
Demonstrates restore-ready verification, confirmed exit, and view cleanup. |
Review effort: Balanced
Move the console attachment checks and the runtime options (the CPU profile, the guest shutdown action and the control authentication timeout) out of VmConfig::openvmm_arguments into console_backend and runtime_arguments, so that a snapshot restore can render them by the same rules as a cold boot. A cold boot's arguments do not change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a313023 to
9bc9d40
Compare
vm::create refused every snapshot, which left callers on the store-coupled clone launch. With from: Some(snapshot), it now refuses Boot, checks Snapshot::accepts at the host's real time, hard-links the snapshot's fixed OpenVMM files into a new <vm_dir>/openvmm/ view, binds the restore-ready listener before any spawn, and renders the restore's arguments by the clone launch's rules: the devices at the snapshot's processor capacity, --restore-network-policy with the restore's own policy instead of --net, --restore-absent-scratch for an upper in RAM, --restore-processors only for a snapshot that records its boot processors, --restore-memory, the console attachment that the snapshot allows, and the snapshot's backend and CPU profile. A view on another filesystem fails; nothing is copied. The snapshot's NIC feeds Prepared::nic and activation_record, whose network carries the restore policy's DNS, publication and proxy. The listener moves, never reopened nor inherited by the child, through VmmCommand::ready to an external launcher, or through Launched::ready from vm::spawn. ReadyListener::receive becomes public, so that such a caller verifies the restore-ready peer. A failed creation removes only what it created: the links, the view, the listener's socket and the log. create's docs state the caller's Linux per-snapshot lock, held from create through the peer-verified restore-ready event or the VM's verified exit, and around the view's removal. OpenVMM checks the snapshot's files only before its one restore-ready connection, which it does not retry, so a restore whose caller dies before that connection cannot complete, and the caller needs no durable in-flight record. The external-launch example takes the snapshot's lock before opening it, restores a snapshot that `nvx-rs snapshot capture` captured, with its disconnected boot console, up to the verified ready event, then stops the VM and removes the view. Tests cover the refusals before any output exists, the view's links and rollback, the restore arguments, the NIC and activation record, the listener's handoff through both launch paths, and, when NVX_VM_TEST_OTHER_FILESYSTEM names a second filesystem, the refusal of a view across filesystems. A snapshot captured with nvx-rs snapshot capture restored through the example to its verified ready event on KVM, MSHV and WHP test VMs, with OpenVMM 14dc4116 and the guest artifacts of CI run 42956031193. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bf30d9e to
b37d0fa
Compare
8b77521
into
feature/nvx-refactor
Part of #1103 (SL2.16, "A VM restores from a snapshot and a
VmConfig"). Parent #1081, umbrella #1076.Merging this PR completes phase 2 of #1076: once SL2.16 lands, every PR of phases 1 and 2 has merged into
feature/nvx-refactor, so its merge is the API-ready commit that the PRs of phases 4 and 5 wait for.What and why
host::vm::createrefused every snapshot, which left callers on the store-coupled clone launch. Withfrom: Some(snapshot)it now prepares a restore from aSnapshotand aVmConfig:Boot, and callsSnapshot::acceptswith the host's real time (HostTime::now) before it creates any output.manifest.bin,memory.bin,state.bin) into a new private<vm_dir>/openvmm/. A view on another filesystem fails with the native error (EXDEV,ERROR_NOT_SAME_DEVICE); nothing is copied, and there is no snapshot-parent fallback.host/template/clone/launch.rs): the devices at the snapshot's processor capacity,--restore-network-policywith the restore's own policy in place of--netand the guest's address,--restore-absent-scratchfor an upper in RAM,--restore-processorsonly when the snapshot records its boot processors,--restore-memory, the console attachment that the snapshot allows (a snapshot capturedDisconnectedrefuses a listener), the snapshot's backend and CPU profile, and the launch options. No kernel, initramfs, command line or--memory.Prepared::nicis the snapshot's NIC, andactivation_recordtakes the restore policy's DNS, publication and proxy.createbinds the restore-ready listener before any spawn and moves that same listener, never reopened nor in the child's inheritance allowlist, throughVmmCommand::readyto an external launcher, or throughLaunched::readyfromvm::spawn.create's rustdoc and the README state the caller-owned Linux per-snapshot lock (held fromcreate, including adding the links, through the peer-verified restore-ready event or the VM's verified exit, and around the view's removal; NVX takes none and Windows needs none) and why no durable in-flight record is needed: OpenVMM checks the snapshot's files only before its one restore-ready connection, which it does not retry, so a caller that dies before it leaves a restore that cannot complete.examples/external-launch.rsgains a restore: given a snapshot directory and an EROFS image, it takes the snapshot'skey.binlock on Linux before opening the snapshot, restores throughvm::create(Some)and its own launcher, verifies the restore-ready event withReadyListener::receive, then stops the VM, confirms its exit and removes the view. It restores the snapshots thatnvx-rs snapshot captureproduces (disconnected boot console).Public API and a Scope extension
The public-API snapshots change by three entries on each platform:
Launched::readyandVmmCommand::readyare what the Scope names. MakingReadyListener::receivepublic extends the Scope: #1076's design has callers drive restores themselves, with their own launchers, and the Linux lock rule thatcreatedocuments needs such a caller to verify the restore-ready peer before it releases the lock. Withoutreceive, an external launcher has onlyinto_std()and must reimplement theSO_PEERPIDFDand named-pipe client checks; with it, the example verifies the peer through the library.receivewas crate-private for SL4.3's blocking driver, which can still use it. Nothing else becomes public.The example requires a snapshot captured with a disconnected boot console, as
nvx-rs snapshot capturecaptures one, rather than the listener that the handed-off version required: no NVX tool captures with a listener, andSnapshot::acceptsrefuses a console attachment that the capture did not record, so the example now restores the snapshots that NVX's own tooling produces.Commits
828725deconfig: share console and runtime option rendering: a preparatory refactoring. It moves the console attachment checks and the runtime options intoconsole_backendandruntime_arguments, which the restore reuses. A cold boot's arguments do not change (the config tests compare them whole).b37d0fa3host: restore a VM from a snapshot and a VmConfig (SL2.16): the restore, its tests, docs and example.History
This PR was handed off by Enrique Saurez (@esaurez) (checkpoint on #1103). Its earlier head
a3130238sat on #1465's input-join branch. The inputs that it composed have since merged intofeature/nvx-refactor(#1434, #1437, #1455, #1457, #1297), so the branch now holds only SL2.16's own work, replayed ontofeature/nvx-refactor5947e4e8and squashed into the two commits above with their authorship; the corrections of this qualification are folded into the second. #1465's own commit (a formatting fix of the composed imports) is not needed. The base is nowfeature/nvx-refactor.Size
Measured against
feature/nvx-refactor: 357 core lines (estimate 420, stop 600) in 5 counted files:host/vm.rs139,examples/external-launch.rs103,host/config/mod.rs93,host/snapshot.rs20,host/restore.rs2.host/mod.rschanges only its rustdoc (0 core lines).Not in this PR
Owning or acquiring the per-snapshot lock; durable in-flight restore records; copying snapshot files, cross-filesystem restores or a snapshot-parent fallback; NIC re-addressing or a console listener absent from the capture; driving activation to Ready, retries or cancellation (SL2.18a's
RestoreMachine, SL4.3's blocking driver); tiers other than Fresh.Validation
Artifacts: CI run 42956031193 of
feature/nvx-refactor5947e4e8(guest kernel, Alpine initramfs and Ubuntu EROFS layer, and OpenVMM14dc4116for linux-gnu, linux-musl and windows-msvc, each checked against its provenance). This change touches neither the guest nor OpenVMM.nvx-rsand the example were built from this branch on each host. The headb37d0fa3has the same tree asbf30d9ea, on which the Windows checks ran. The runtime checks and the Linux rerun ran ona939ec07, which differs from it only in README paragraphs.nvx-rs snapshot capture, thenexternal-launchrestoring that snapshot throughvm::create(Some)and its own launcher to the peer-verified restore-ready event, then stop, confirmed exit and view removalexternal-launchcold launch (the refactored cold renderer)nvx.py test-microvm --scenario l3-l4-egress-policy --scenario filesystem-comma-paths --scenario run-console-restore(nvx-rs runthroughvm::create)snapshot_creation_refuses_a_true_cross_filesystem_view_without_copyingwithNVX_VM_TEST_OTHER_FILESYSTEM(tmpfs to ext4)ERROR_NOT_SAME_DEVICEGates, with the commands of this branch's
check-quality,check-nvx-rsandvalidate-nvxactions:7c09bca1, test layout, Markdown links, test changes, rustfmt, the five warning-denied Clippy configurations, default and no-default tests, bundling, rustdoc with warnings denied, the public API, MSRV 1.89, the macOS check, the guest-binary build and checks, and the runtime adapter's protocol, host and guest configurations passed.cargo test --all-featuresand the guest-binary tests failed the same 28guest::tests (a process-groupkillreturnsEINVALon that host) that fail at the base5947e4e8on the same host, so they are environmental there; CI passed them at the base. Ona939ec07, the gates that the later changes affect passed again: test layout, links, test changes, rustfmt, Clippy, thehost::tests (1125), rustdoc, the public API, MSRV and the macOS check.bf30d9ea):cargo test --all-featuresandcargo testpassed (1440 and 1219 library tests, and every integration test).bf30d9ea): test layout, Markdown links, test changes, rustfmt, the five Clippy configurations, no-default build and tests, bundling, rustdoc, MSRV 1.89, and the runtime adapter's protocol and host configurations passed. Under the workstation's heavy parallel load,cargo test --all-featuresandcargo testeach failed two timing-sensitive tests (children_inherit_only_their_standard_handles, anda_capture_ack_and_successful_output_without_timely_exit_are_stopped_but_never_finishedorthe_restore_to_ready_deadline_runs_from_the_launch_through_every_step), which pass alone there and in the full runs on nvx-whp-test. Of thevalidate-nvxCLI suite,compilealland the modules that read the test-layout allowlist, the test changes, the public API and the links (test_test_layout,test_test_changes,test_public_api,test_markdown_links: 178 tests) passed; the full module list did not finish within 70 minutes on the overloaded workstation, so it is left to CI.b37d0fa3, the same tree asbf30d9ea): rustfmt, Clippy (--lib --no-default-featuresand--all-targets --all-features) and the test layout passed again, andrebase_check.py verifyfound both commits signed on5947e4e8.Left to CI: the full microVM and runtime-adapter suites on KVM, MSHV and WHP, and the benchmarks.
Changes to existing tests (
tests-modified)python3 scripts/check_test_changes.py --base origin/feature/nvx-refactorlists 9 changes, and 14 tests are added:RestoreFixture(host::snapshot::tests) becomespub(in crate::host), withcurrent,retime,all_processors_onlineandconsole_listener, so that the VM tests restore real fixtures at the host's real time. Its existing uses are unchanged.cold_creation_is_inspectable_without_a_process_listener_or_capability_fileandspawn_returns_the_same_outputs_and_capability_with_a_verified_processalso assert that a cold launch has no ready listener.a_missing_boot_and_a_snapshot_are_refused_before_any_output_is_createdis renameda_missing_boot_and_boot_with_a_snapshot_are_refused_before_any_output_is_created, with the same body: a snapshot is no longer refused as such, so its case now checks the refusal ofBootwith a snapshot (the sameUnsupportedkind and "Snapshot" fragment, and no output).a_library_vm_outlives_the_caller_that_spawned_it_without_retaining_its_output_pipeinitializes the newready: Nonefield of itsLaunchedliteral.#[cfg_attr(not(test), expect(dead_code, ...))]) ofReadyListener::bind,endpointandreceiveand ofSnapshot::dirare removed, since production code uses them now;scripts/check_test_layout.py --tightenremoved their two allowlist entries.The clone path's launch, retry and failure tests are kept unchanged: this PR deletes nothing of the clone path.