Skip to content

cli: let a named snapshot carry a NIC (SL3.7c) - #1502

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl3-7c-snapshot-nic
Nov 12, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl3-7c-snapshot-nic

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1114 (SL3.7c, "a named snapshot can carry a NIC"). Parent #1084, umbrella #1076.

What and why

snapshot capture gave its VM no NIC, and a snapshot restores only with the NIC presence that it captured. So no named snapshot could restore with a network: the restore's own DNS server, egress, forwards and published listeners, which snapshot restore (SL3.8a) and run --restore-snapshot (SL3.8b) install, never reached a real guest (gap analysis, slice definition).

  • snapshot capture --net IPV4/PREFIX (opt-in) gives the capture VM a NIC at that static address, under the complete deny-all policy: no egress, ingress or host-loopback access, and no rules, forwards, proxy or DNS server. That is the one policy whose NIC a restore may replace with its own. The library already attaches a capture's NIC under that policy and records it in the capture context, the key and snapshot.json (Snapshot::nic). Without --net, capture is unchanged.
  • snapshot restore takes its network at the snapshot's NIC, as run --restore-snapshot does. Both commands take the NIC that snapshots::restore_source returns (cli: restore managed sandboxes from named snapshots (SL3.8a2) #1487, cli: restore named snapshots once with run (SL3.8b) #1489), and apply their network options through run::restored_network, using the existing lowering. A NIC-less snapshot refuses network options before anything is provisioned; Snapshot::accepts used to refuse them only after the provision.
  • Decision: a restore takes no --net (approved by Pedro Henrique Penna (@ppenna)). The snapshot decides whether a restore has a NIC, and at which address. A restore of a NIC snapshot brings only its own DNS, egress, forwards and listeners. So snapshot restore treats --net as a cold-boot-only option and leaves it unrecognized, and run --restore-snapshot keeps refusing it. The help of snapshot restore, snapshot capture and run, doc/usage.md and nvx-rs/README.md say that a restore's NIC comes from the snapshot, and that --net belongs to snapshot capture. This differs from esaurez's first implementation (esaurez/private-sl38b-0325-b2, used only as a reference), which kept --net on snapshot restore and required it to repeat the captured address.
  • untiered-network-policy now runs on named snapshots through the public CLI, and only its raw parts retire.
    • It captures the template with snapshot capture --net 192.0.2.2/24 and restores it four times into sandboxes of the Ubuntu layer over a RAM upper:
      • the template's deny-all and private-network ingress, through snapshot restore, then sandbox stop and sandbox deprovision;
      • egress rules that admit DNS over IPv4 and one host service, and explicit host loopback with a forward, through run --restore-snapshot.
    • Each guest reports its resolver, whether its listener announcer runs, and which host services it reaches. The host exchanges lines with the guest's server through the forward and the published port (on host loopback alone, or through a private host address), and checks that nothing publishes the port when the policy publishes nothing.
    • So SL3.8a's "restored guest receives the restore's DNS and announcer policy" and SL3.8b's DNS, egress, forwards and listener checks run on real VMs. The CLI must also refuse, before provisioning, a restore without --network-profile and one with --net.
    • The workload's script is its sh -c argument, whitespace and all, since a restore sends its workload as an exec request (SL3.8a2).
    • The host can't release the guest's hold of its port: a restored workload takes no input, and deny-all has no way in. So it bounds its "nothing published" check against the guest's 6-second hold. It must check within 2 s of seeing LISTENING, and see the hold end at least 2 s after its check; otherwise the check fails instead of passing (Copilot's review).
    • A failed restore's error now names its cause, and a failed run keeps the VM log of each sandbox that it leaves, so that a CI failure can be diagnosed.
  • CI. The scenario reads the Ubuntu layer, so it becomes a public sandbox scenario. CI runs it in each backend's "Run public managed sandbox acceptance" step, after snapshot-core and snapshot-tiers, and no longer in the default suite's shards (microvm_shards.json re-planned with plan-microvm-shards).
  • Case matrix. SL5.1c (tests: capture and restore named snapshots end to end on real VMs (SL5.1c) #1500) kept the scenario on a raw snapshot, with the row "kept until a strict snapshot can carry a NIC (SL3.7c)". That row is now rewritten, and names the raw parts that retire and the CLI's refusals that replace OpenVMM's. The MicroVM scenarios' summary row is recounted: of 54 tests, 50 kept, 3 rewritten and 1 retired (51, 2 and 1 before). The rows of the adapter's clone tests that the scenario covers now say what its restores check, and the Snapshots section lists the restore of a snapshot with a NIC, which installs a network policy of its own.

Not in this PR: re-addressing a restored VM's NIC, and snapshots of blockless VMs' running workloads.

Size

Measured against feature/nvx-refactor f03c21c3f0c, as #1076 defines them; the same as against the earlier base 1b902ac16a5:

  • Core lines: 28, or 30 with the workflow's two --scenario lines: capture.rs 15, snapshots.rs 10, and run.rs 3, the lines of its --net help (estimate: about 80; stop at 160).
  • Counted files: 5 (estimate: 3; limit: 5):
    • nvx-rs/src/host/cli/snapshots/capture.rs and nvx-rs/src/host/cli/snapshots.rs;
    • nvx-rs/src/host/cli/run.rs, for its help text only, so 4 files if help text counts as docs;
    • scripts/nvx_tools/microvm_tests.py, the scenario. It is end-to-end test code (417 added lines), whose lines count as tests, as in tests: run every cold cell and the public VM lifecycle on real VMs (SL5.1b) #1496;
    • .github/workflows/run-nvx-microvm-tests.yml, because the scenario moves to the public acceptance steps.

Commits

  1. 32ef4e09a92 cli: let a named snapshot carry a NIC (SL3.7c): snapshot capture --net; snapshot restore's network at the snapshot's NIC; --net left unrecognized by snapshot restore; unit tests, help, rustdoc and docs (doc/usage.md, doc/run.md, nvx-rs/README.md).
  2. 9a91a4fe077 tests: run untiered-network-policy on named snapshots (SL3.7c): the scenario rewrite, its unit tests, the CI wiring, the shard plan, and the docs (doc/ci.md, doc/usage.md, doc/acceptance-case-matrix.md).

Validation

Hosts: KVM on nvx-kvm-test (Azure Linux 3.0, kernel 6.6), MSHV on nvx-mshv-test (Azure Linux 3.0, kernel 6.18 mshv3), and WHP on nvx-whp-test. At earlier heads, while nvx-whp-test was degraded, WHP ran on the local Windows workstation. The guest artifacts come from CI run 43135776204 (feature/nvx-refactor 012123bf9ac, an ancestor of the base; no guest code has changed since), and at earlier heads from run 43075697333. OpenVMM is at pin 14dc4116, the same as this branch's: on Linux from release v0.1.0-dev.53ad09678bc1, because nvx-rs download finds no release for this branch, and on WHP from CI run 43135776204.

At the head 9a91a4fe077, after the rebase onto feature/nvx-refactor f03c21c3f0c:

Check Where Result
CI run 43187334633 CI passed: 33 jobs succeeded, Required status check among them, and 9 were skipped. The "Guests and sandboxes" jobs of KVM, MSHV and WHP ran untiered-network-policy in "Run public managed sandbox acceptance", after snapshot-core and snapshot-tiers, whose named snapshots have no NIC, and all three passed
cargo fmt --all --check; cargo clippy --locked with --all-targets --all-features, --lib, --lib --no-default-features, --lib --bins --features cli, --lib --bins --no-default-features --features testing, all -D warnings Windows passed
cargo test --locked --all-features --lib -- host::cli::snapshots host::cli::run host::cli::sandbox host::snapshot Windows passed: 168 tests
cargo test --locked --all-features --test cli -- snapshot restore run capture Windows passed: 31 tests
RUSTDOCFLAGS="-D warnings" cargo doc --locked --no-deps --all-features; python scripts/check_test_layout.py Windows passed
ruff check, ruff format --check, pyright (Linux and Windows) on the scenario and its tests; python -m unittest -k untiered scripts/test_microvm_tests.py; CiConfigurationTests and the usage doc's test in scripts/test_nvx_tools.py Windows passed: 18 untiered tests
The workstream's case-matrix check (check_matrix.py, against 99d2022085f) and the docs' links Windows passed
test-microvm --scenario untiered-network-policy KVM and MSHV: 2 runs each all passed, 27 s each
same, --backend whp WHP (nvx-whp-test): 2 runs both passed, 36–37 s
Per-restore reports, identical on every backend and run all deny-all: resolver=none announcer=none allowed=denied other=denied, 0 exchanges; egress-dns: resolver=192.0.2.1 announcer=none allowed=reached other=denied, 0; host-loopback: resolver=fd00::c000:201 announcer=running allowed=denied other=denied, 2; private-ingress: resolver=192.0.2.1 announcer=running allowed=reached other=reached, 1; refusals: the snapshot has a NIC, so its restore needs --network-profile and --net is not accepted for restore
NIC-less capture (snapshot.json "nic": null), restored by snapshot restore (then stopped and deprovisioned) and by run --restore-snapshot without network options KVM, MSHV, WHP passed: the guest sees only lo, and no sandbox is left
NIC-less snapshot with --network-profile portable, or --network-egress allow, through both commands KVM, MSHV, WHP refused before provisioning: the snapshot has no NIC, so its restore takes no network options
A restore with --net 192.0.2.2/24 --network-profile portable, through both commands KVM, MSHV, WHP refused before provisioning: snapshot restore leaves --net unrecognized (status 2), and run --restore-snapshot says --net is not accepted for restore (status 1). No OpenVMM process was left on any host

At earlier heads of this PR, whose code differs only as the commits above describe:

Check Where Result
test-microvm --scenario untiered-network-policy KVM and MSHV: 4 runs each before the hold bounds, 3 each with them (ee8c9e177e6) all passed, 19–29 s each; no OpenVMM process or fixture left
same, --backend whp local WHP: 26 runs, 4 of them with the hold bounds (1 at d2b0aa0c1b3), and 4 beside 24 CPU-bound processes 25 passed, 30–79 s. One run, while other agents' builds held the workstation at 90–100% CPU, reported the deny-all restore failed after its guest had printed every check. Its message didn't name a cause; it now does, and the run keeps the sandbox's VM log. The 22 runs since passed, and so did both runs on nvx-whp-test and CI's WHP job at this head
Every step of check-nvx-rs that runs on Windows (fmt, five clippy runs, tests with all, default and no default features, bundling, docs, MSRV 1.89, the runtime adapter's protocol-only and host-only configurations) Windows passed
fmt, clippy, public_api.py; cargo test --locked --all-features --no-fail-fast Linux (nvx-kvm-test) passed, but for the 28 guest:: unit tests that fail on that host at the base too
The validate-nvx unittest list and compileall Linux, Windows passed: 1835 tests
python -m unittest scripts/test_microvm_tests.py Windows 347 tests; one timeout in test_private_network_ingress_script_checks_policy_and_traffic, whose 10 s budget for a Git sh script ran out under load. That test and its script don't change here, and it passed 3 times alone

Left to CI: the guest binaries and the macOS check (no guest or platform code changes here), and the shell linters (no listed script changes).

Test changes (tests-modified)

python3 scripts/check_test_changes.py --base origin/feature/nvx-refactor lists 30 changes to existing tests and 19 additions, compared with f03c21c3f0c:

  • host::cli::snapshots::capture::tests::write_recipe: the fake VMM's manifest has a NIC when the capture's context has one, as OpenVMM's has for a VM with a NIC.
  • GuestConsoleEchoTests.test_scripts_awaiting_a_release_turn_the_echo_off_first: drops untiered-network-policy.sh.in, which no longer awaits a console release, because a restored sandbox's workload has no console.
  • Kept and rewritten for named snapshots:
    • test_untiered_network_policy_script_reports_the_repair_and_serves_the_host, renamed ..._reports_the_policy_and_serves_the_host: the script takes the number of exchanges as its argument in place of the console release, holds its port when it has no client, and reports what the activation set up in place of the raw restore's repair.
    • test_untiered_network_restores_name_what_their_policies_give_the_guest: also names which restores are one-off run --restore-snapshots, without the raw restores' --restore-network-policy settings.
    • test_untiered_network_policy_restores_one_template_with_four_policies, which the tool lists as removed, became test_untiered_network_policy_restores_one_named_template_with_four_policies. It checks the CLI's commands in place of OpenVMM's: the capture with --net; the four restores with their policies and scripts; the stops and deprovisions; the refusals; and the host's wait for the end of each hold.
    • test_untiered_network_policy_requires_what_each_policy_gives_the_guest: the same assertions, through the simulated CLI.
    • test_untiered_network_policy_reports_guest_failures and test_untiered_network_policy_checks_where_ingress_publishes_the_guest_port: the same assertions; the failure message now also names its cause.
    • The helpers _simulate_untiered_network_guest and _run_untiered_network_policy simulate nvx-rs in place of OpenVMM.
    • CiConfigurationTests.test_ci_runs_the_public_sandbox_acceptance_on_every_backend (test_nvx_tools.py): expects --scenario untiered-network-policy in the public acceptance steps.
  • Scenario code (end-to-end tests): the scenario joins SANDBOX_CONTROL_SCENARIOS and PUBLIC_SANDBOX_SCENARIOS, and _run_scenarios gives it the backend, the timeout and the output directory, in place of OpenVMM's executable, kernel, initramfs and memory size. Only the raw parts retire:
    • the raw capture and restores;
    • the guest's repair marker (UNTIERED_POST_RESTORE_MARKER, UNTIERED_NETWORK_GUEST_MARKERS);
    • the console release (UNTIERED_NETWORK_CHECKED, UNTIERED_NETWORK_MAX_CLIENTS) and UntieredNetworkRestore.network_settings;
    • OpenVMM's refusals of a raw restore that keeps the template's policy but passes another, or passes private-network ingress without --restore-network-policy, which the CLI can't issue. The CLI's refusals of a restore without --network-profile and of one with --net take their place.
  • CI wiring: untiered-network-policy leaves the default suite's shards on kvm, mshv and whp, and runs in the public acceptance steps instead.
  • Added:
    • the_capture_parser_takes_for_net_only_an_address_that_openvmm_accepts;
    • a_capture_with_net_gives_its_vm_a_deny_all_nic_which_its_snapshot_keeps;
    • a_restore_takes_its_network_at_the_nic_of_its_snapshot_before_it_provisions;
    • test_untiered_network_policy_script_fits_one_argument_of_an_exec_request;
    • test_untiered_network_exchanges_check_first_that_nothing_publishes_the_port;
    • test_untiered_network_hold_must_cover_the_hosts_check;
    • test_untiered_network_policy_fails_on_markers_that_reach_the_host_late;
    • test_untiered_network_policy_stops_and_removes_what_a_failure_leaves;
    • test_untiered_network_policy_leaves_no_openvmm_process_or_sandbox;
    • test_untiered_network_policy_requires_the_clis_refusals;
    • test_runner_dispatches_public_untiered_network_policy.

@ppenna Pedro Henrique Penna (ppenna) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 11, 2026
@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 30 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

Change What Before After
modified helper fn write_recipe in host::cli::snapshots::capture::tests nvx-rs/src/host/cli/snapshots/capture/tests.rs:201 nvx-rs/src/host/cli/snapshots/capture/tests.rs:203
modified helper def MicrovmTests._simulate_untiered_network_guest in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14544 scripts/test_microvm_tests.py:14554
modified helper def MicrovmTests._run_untiered_network_policy in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14583 scripts/test_microvm_tests.py:14592
modified test def GuestConsoleEchoTests.test_scripts_awaiting_a_release_turn_the_echo_off_first in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:2640 scripts/test_microvm_tests.py:2640
modified test def MicrovmTests.test_untiered_network_policy_script_reports_the_repair_and_serves_the_host in scripts/test_microvm_tests.py (renamed to test_untiered_network_policy_script_reports_the_policy_and_serves_the_host) scripts/test_microvm_tests.py:14241 scripts/test_microvm_tests.py:14236
modified test def MicrovmTests.test_untiered_network_restores_name_what_their_policies_give_the_guest in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14296 scripts/test_microvm_tests.py:14306
modified test def MicrovmTests.test_untiered_network_policy_requires_what_each_policy_gives_the_guest in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14827 scripts/test_microvm_tests.py:15004
modified test def MicrovmTests.test_untiered_network_policy_reports_guest_failures in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14916 scripts/test_microvm_tests.py:15061
modified test def MicrovmTests.test_untiered_network_policy_checks_where_ingress_publishes_the_guest_port in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14936 scripts/test_microvm_tests.py:15157
modified test def CiConfigurationTests.test_ci_runs_the_public_sandbox_acceptance_on_every_backend in scripts/test_nvx_tools.py scripts/test_nvx_tools.py:12467 scripts/test_nvx_tools.py:12467
removed test def MicrovmTests.test_untiered_network_policy_restores_one_template_with_four_policies in scripts/test_microvm_tests.py scripts/test_microvm_tests.py:14702

End-to-end tests

Change What Before After
modified file scripts/nvx_tools/microvm_test_scripts/untiered-network-policy.sh.in scripts/nvx_tools/microvm_test_scripts/untiered-network-policy.sh.in scripts/nvx_tools/microvm_test_scripts/untiered-network-policy.sh.in
modified helper assignment SANDBOX_CONTROL_SCENARIOS in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:191 scripts/nvx_tools/microvm_tests.py:192
modified helper assignment PUBLIC_SANDBOX_SCENARIOS in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:217 scripts/nvx_tools/microvm_tests.py:219
modified helper assignment UNTIERED_NETWORK_CHECKED in scripts/nvx_tools/microvm_tests.py (renamed to UNTIERED_NETWORK_SNAPSHOT) scripts/nvx_tools/microvm_tests.py:529 scripts/nvx_tools/microvm_tests.py:530
modified helper assignment UNTIERED_NETWORK_MAX_CLIENTS in scripts/nvx_tools/microvm_tests.py (renamed to UNTIERED_NETWORK_HOLD_SECONDS) scripts/nvx_tools/microvm_tests.py:543 scripts/nvx_tools/microvm_tests.py:547
modified helper assignment UNTIERED_NETWORK_REJECTED in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:546 scripts/nvx_tools/microvm_tests.py:550
modified helper def untiered_network_policy_script in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9036 scripts/nvx_tools/microvm_tests.py:9038
modified helper class UntieredNetworkRestore in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9056 scripts/nvx_tools/microvm_tests.py:9062
modified helper def untiered_network_restores in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9092 scripts/nvx_tools/microvm_tests.py:9095
modified helper def _untiered_network_exchanges in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9228 scripts/nvx_tools/microvm_tests.py:9238
modified helper def _run_untiered_network_restore in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9285 scripts/nvx_tools/microvm_tests.py:9332
modified helper def run_untiered_network_policy in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9351 scripts/nvx_tools/microvm_tests.py:9551
modified helper def _run_scenarios in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:11992 scripts/nvx_tools/microvm_tests.py:12259
removed helper assignment UNTIERED_POST_RESTORE_MARKER in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:526
removed helper assignment UNTIERED_NETWORK_GUEST_MARKERS in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:552
removed helper def UntieredNetworkRestore.network_settings in scripts/nvx_tools/microvm_tests.py scripts/nvx_tools/microvm_tests.py:9080

CI test wiring

Change What Before After
removed scenario untiered-network-policy on kvm scripts/nvx_tools/microvm_shards.json
removed scenario untiered-network-policy on mshv scripts/nvx_tools/microvm_shards.json
removed scenario untiered-network-policy on whp scripts/nvx_tools/microvm_shards.json

Relocated unchanged: 0; added: 19. Compared the merge base f03c21c3f0c7 with 9a91a4fe077f.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The port-denial tests can falsely pass if delayed marker delivery lets the guest listener expire before probing, since the timing guard starts only when the host consumes the marker.

1 open issue
What changed in this PR

This PR completes SL3.7c of #1114 by letting named snapshots carry a network interface, enabling the existing restore commands to apply their own network policies to real guests.

Changes:

  • Adds opt-in snapshot capture --net with a deny-all capture policy.
  • Makes snapshot restore use the captured address, reject --net, and validate network options before provisioning.
  • Rewrites network-policy acceptance around named snapshots and moves it into each backend’s public sandbox CI suite.
File Description
scripts/​test_nvx_tools.py Checks the scenario’s public acceptance CI wiring.
scripts/​test_microvm_tests.py Tests CLI orchestration, guest checks, refusals, and cleanup.
scripts/​nvx_tools/​microvm_tests.py Runs four network policies through named-snapshot CLI restores.
scripts/​nvx_tools/​microvm_test_scripts/​untiered-network-policy.sh.in Adapts guest probes and listener handling for restored workloads.
scripts/​nvx_tools/​microvm_shards.json Removes the scenario from default shards and rebalances them.
nvx-rs/​src/​host/​cli/​snapshots/​tests.rs Tests network validation before provisioning.
nvx-rs/​src/​host/​cli/​snapshots/​capture/​tests.rs Tests address parsing, deny-all capture, and retained NIC metadata.
nvx-rs/​src/​host/​cli/​snapshots/​capture.rs Adds optional NIC configuration to capture.
nvx-rs/​src/​host/​cli/​snapshots.rs Uses the captured NIC and rejects restore-time addressing.
nvx-rs/​src/​host/​cli/​run.rs Updates rustdoc for shared restore-network handling.
nvx-rs/​README.md Documents networked capture and restore behavior.
doc/​usage.md Documents CLI options, restrictions, and scenario requirements.
doc/​run.md Clarifies named-snapshot network-policy replacement.
doc/​ci.md Describes the rewritten acceptance scenario and its CI placement.
doc/​acceptance-case-matrix.md Attributes named-snapshot network coverage to SL3.7c.
.github/​workflows/​run-nvx-microvm-tests.yml Adds the scenario to Linux and Windows public acceptance steps.

Review effort: Balanced

Comment thread scripts/nvx_tools/microvm_tests.py Resolved
Base automatically changed from agents/slim-sl3-8b-run-restore to feature/nvx-refactor November 12, 2026 00:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the named-snapshot networking changes.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

`snapshot capture` gave its VM no NIC, and a snapshot restores only
with the NIC presence that it captured, so no named snapshot could
restore with a network: the restore's own DNS server, egress,
forwards, and published listeners, which `snapshot restore` (SL3.8a)
and `run --restore-snapshot` (SL3.8b) install, reached no real guest.

`snapshot capture --net IPV4/PREFIX` now gives the capture VM a NIC at
that static address under the complete deny-all policy, with egress,
ingress, and host-loopback access denied and no rules, forwards,
proxy, or DNS server, the one policy whose NIC a restore may give a
policy of its own. The library already attaches a capture's NIC under
that policy and records the NIC in the capture context, the key, and
`snapshot.json`, so `Snapshot::nic` returns it. Without `--net`, the
capture is unchanged.

`snapshot restore` now takes its network at the snapshot's NIC, as
`run --restore-snapshot` does: both take the NIC that
`snapshots::restore_source` returns, and the network options of the
restore through `run::restored_network`. The network options of a
snapshot with a NIC, which need `--network-profile`, become the
restore's own policy at the NIC's address, through the same lowering,
and those of a snapshot without a NIC are refused, before anything is
provisioned, where the start's `Snapshot::accepts` refused them after
the provision. `--net`, which only a cold boot takes, joins the options
that `snapshot restore` leaves unrecognized: a restore keeps the address
that its snapshot captured. The help of `snapshot restore`,
`snapshot capture` and `run`, and the docs, say that a restore's NIC
comes from its snapshot, and that `snapshot capture --net` gives a
snapshot its NIC.

Not here: re-addressing a restored VM's NIC, and snapshots of the
running workloads of blockless VMs.

Tests: the capture parser takes for `--net` only an address that
OpenVMM accepts; a capture with `--net` attaches its VM's NIC under
the complete deny-all policy alone, and its snapshot keeps the NIC and
its address, in its key and description, while one without has no
NIC; and `snapshot restore` refuses the network options of a snapshot
without a NIC and a snapshot with a NIC without `--network-profile`
before it provisions anything, and gives the options of one with a NIC
the NIC's address. The fake VMM of the capture tests writes a manifest
with a NIC for a VM that has one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The untiered-network-policy scenario drove OpenVMM directly: it booted
a VM with a NIC under the complete deny-all policy, captured a raw
snapshot of it with a post-restore script, and restored that snapshot
with `--restore-network-policy` and four network policies. The CLI no
longer restores raw snapshots, and `snapshot capture --net` now
captures a named snapshot with such a NIC, so the scenario now runs on
named snapshots, through the CLI's restore paths.

It captures the template with `nvx-rs snapshot capture --net` and
restores it four times, each into a sandbox of the Ubuntu layer over a
RAM upper, with the network options of a policy at the NIC's captured
address, and the scenario's checks as the restored workload:
`snapshot restore`, whose sandboxes the scenario then stops and
deprovisions, restores the template's own deny-all and private-network
ingress with allowed egress, which show the restore's DNS server and
announcer (SL3.8a's check); and `run --restore-snapshot` restores
egress rules that admit DNS over IPv4 and one host service, and
explicit host loopback with a forward under egress rules that admit
DNS over IPv6 alone, which show its DNS server, egress, forwards, and
published listeners (SL3.8b's checks). Each restored workload reports
its resolver, whether the announcer of its listeners runs, and which
host services it reaches, then serves the host through the forward
and the published port, as many clients as the scenario names, or
without one, holds its port for six seconds, while the host checks that
nothing publishes it. The host cannot end the hold, as a restored
workload takes no input and deny-all has no way in, so it must check
within two seconds of seeing the server listen, and see the hold end at
least two seconds after its check: a check that a late marker could
have moved past the hold fails instead of passing. The workload's
script is its `sh -c` argument, whitespace and all, as a restore sends
its workload as an exec request. The scenario keeps its checks of
those reports, of the requests that the host services receive, of
where each policy publishes the guest's port, and that no restore
changes the template, and adds that no restore leaves its sandbox or
an OpenVMM process behind.

Only the raw parts retire: the raw capture and restores, the guest's
repair marker, the console release, and OpenVMM's refusals of a raw
restore that keeps the template's policy but passes another or passes
private-network ingress without `--restore-network-policy`, which the
CLI cannot issue. In their place, the CLI must refuse, before it
provisions anything, a restore of the template without
`--network-profile`, and one that names the NIC's address with
`--net`. A failed run stops the sandboxes that it left, ends the
OpenVMM processes that name its fixture, keeps the VM log of each
sandbox, and then deprovisions the sandboxes, as the sandbox lifecycle
acceptance cleans up, and a failed restore's error names its cause.

The scenario now reads the Ubuntu layer, so it becomes a public
sandbox scenario: CI runs it in each backend's guest and sandbox job,
beside the other public scenarios, and no longer in the shards of the
default suite, which plan-microvm-shards re-planned. The case matrix
now gives the scenario's rewrite, and that of the tests of the
adapter's clones that it covers, to SL3.7c.

Tests: the unit tests of the scenario run it against a simulated
nvx-rs, whose restores' workloads request the real host services as
their policies admit, and keep checking the reports, the host
services, the publications, and the template, and now the commands of
the capture, the restores, their stops and deprovisions, and the
refusals, a script that fits one argument of an exec request, the
timing of the host's check of an unpublished port against the guest's
hold, also with markers that reach the host late, the cleanup after a
failure, and the leftovers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the named-snapshot networking changes.

No open issues 🎉

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat-nvx-refactor tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants