Skip to content

nvx-rs slimming 2.1.1: one value for a VM's configuration #1097

Closed

Description

Parent: #1079, in #1076. Needs: #1091. Unblocks: #1098, #1101, #1102.

Goal. Caller-owned values describe a VM's whole configuration: Runtime and LaunchOptions, for what every launch shares; VmConfig, for a VM's machine, root, view, console, network, export and boot; and CaptureConfig, for what a capture adds. VmConfig, CaptureConfig, the identities and the checked leaf values check their own data without reading the host. A runtime identity mismatch gets an error kind of its own.

Notes.

PRs, in order. Each PR has one goal, leaves dev green, and names in its description each old test of its area as kept, rewritten or retired, with each change that check_test_changes.py reports. Its tests follow the repository's test layout: a module's unit tests, and the code that only they use, sit in its tests.rs or tests/ and move with it. The estimates count core lines (code, not comments, docs or tests) and counted files; each PR records its measured values. Each PR does what its Scope says and no more: a case, input or layout that its Scope doesn't name, and whatever "Not in this PR" lists, is out of scope. Address every review comment within the scope, and ask before acting on one that asks for more. A PR whose measured core lines pass the stop that its Estimate names (twice the estimate, at most 600) stops and asks before continuing.

  1. SL2.2: What every launch shares is one value.

    • Objective: The artifacts, identity and launch-wide options used by every VM are currently spread across storage, platform and launch code. host::runtime gives callers one reusable value for those inputs while preserving the existing identity semantics, and a runtime identity mismatch gets an error kind of its own.
    • Contents: host::runtime: git mv of RuntimeIdentity (new, check, differences), ArtifactIdentity (new, sha256, as_str) and IdentityPart (OpenVmm, Kernel, Initramfs, BootContract, ControlContract, ControlSession) out of nvx-rs/src/host/store/identity.rs, and of probe_hypervisor; new Runtime { openvmm, kernel, initramfs, identity, hypervisor, cpu_profile, windows_breakaway, options }; LaunchOptions { guest_shutdown, control_auth_timeout }, without the boot console; and GuestPowerAction: exit (the default, which host::vm::stop relies on), halt or reset. The authentication timeout is how long OpenVMM waits for the host to authenticate. ErrorKind::RuntimeMismatch (new) is new, and today's runtime-mismatch code takes it instead of Other; ErrorKind::Unsupported's docs name the malformed values that the identity checks already refuse with it.
    • Scope:
      • Move RuntimeIdentity, ArtifactIdentity and IdentityPart from nvx-rs/src/host/store/identity.rs into host::runtime, preserving new, check, differences, sha256 and as_str.
      • Move probe_hypervisor into host::runtime without changing the Linux, Windows or unsupported-host probes.
      • Add Runtime with the OpenVMM, kernel and initramfs paths, identity, hypervisor, optional CPU profile, Windows breakaway setting and LaunchOptions.
      • Add LaunchOptions { guest_shutdown, control_auth_timeout }, where the timeout bounds how long OpenVMM waits for the host to authenticate, and GuestPowerAction::{Exit, Halt, Reset}, with exit as the default.
      • Add ErrorKind::RuntimeMismatch, which today's runtime-mismatch errors take instead of Other, and let ErrorKind::Unsupported's docs name malformed values, which the identity checks already refuse with it.
    • Not in this PR:
      • Reading or hashing artifact files: identities remain caller-supplied labels, and sha256 only validates and formats a digest.
      • Putting the boot console in LaunchOptions: console attachment belongs to each VmConfig in SL2.3a.
      • Launching, stopping or reattaching a VM: later host APIs consume Runtime and apply the shutdown action.
      • New CPU-profile parsing or hypervisor detection behavior: this PR only stores the profile request and moves the existing probe.
      • No new builders, generic validation framework, blanket serde derives or extensible option map: preserve the identities' existing serialization and use only the fixed runtime and launch-option fields.
      • Changing an error code's spelling or meaning, a message or the CLI's exit status: only the kind of runtime-mismatch changes.
    • Approach: Use git mv for the identity implementation and public hypervisor probe. Move the identity cases from host/store/tests.rs into host/runtime/tests.rs; keep the platform implementations and their test support with their platform modules. Add the two small data types beside them, with a direct default for GuestPowerAction::Exit; do not introduce builders, artifact discovery or launch orchestration. Add the kind with its spelling and its code, and change only that code's kind.
    • Done when:
      • The moved identity tests still cover invalid labels, normalized sha256: identities, contract checks and every differing identity part.
      • A Runtime fixture supplies each shared launch field, and GuestPowerAction::default() is Exit.
      • The moved hypervisor probe keeps its current platform behavior.
      • A runtime-mismatch error has the kind RuntimeMismatch, the code table's test records it, and the CLI still prints the same code.
    • Needs: SL0.4, in nvx-rs slimming 1.1.1: the public API is checked, and NVX's programs are hidden from it #1091.
    • Estimate: 160 core lines, 5 counted files. Past 320 core lines, stop and ask before continuing.
  2. SL2.3a: A VM's machine, root, view and console are one value, checked without touching the host.

    • Objective: A caller needs one value for a VM's machine, root, view, export and console, instead of assembling launch-specific plans. VmConfig::check rejects malformed values without opening paths or inspecting the host.
    • Contents: host::config: VmConfig { processors, memory_mib, root, view, filesystem, console }, to which SL2.3b adds network and the optional boot; RootConfig::{Blockless, Layered(LayeredRoot)}; LayeredRoot { image, format, gpt_first_partition_bound, upper, overlay }; UpperConfig::{Scratch { path, journal }, Ram { max_memory_percent }}, the RAM upper's cap, from 1 to 90 and 50 by default; and ConsoleAttachment::{Listener, Disconnected} (the console device always exists). VmConfig::check checks the whole value without reading the host, and a refused value is an Unsupported error that names its field. activation::View { hostname, machine_id } is new here, beside WorkloadView, which SL2.5b removes.
    • Scope:
      • Add host::config::VmConfig with processors, memory, root, view, filesystem and console fields.
      • Add blockless and layered roots, including the image path and format, optional GPT first-partition bound, scratch or RAM upper, journal policy and the two existing overlay modes.
      • Add ConsoleAttachment::{Listener, Disconnected}; the console device exists in both cases.
      • Add activation::View { hostname, machine_id } beside the existing WorkloadView.
      • Make VmConfig::check validate the complete value purely, including a RAM upper cap from 1 through 90 with 50 as its default; a refused value is an Unsupported error that names its field.
    • Not in this PR:
      • Opening image or scratch paths, reading GPT data, probing filesystems or checking host support: configuration checks are host-independent.
      • The network field and the optional boot field: SL2.3b adds them with their types.
      • Rendering kernel tokens or OpenVMM arguments: SL2.4a1 through SL2.4c lower the checked value.
      • Removing WorkloadView or changing the activation-record version: SL2.5b does both.
      • Adding a third console mode or omitting the console device: the repository needs only listener and disconnected attachments.
      • No builders, generic validation framework, blanket serde derives or extensible option map: the fixed fields and direct checks are the complete configuration surface in this PR.
    • Approach: Define plain public data types in host::config and reuse activation's existing journal, overlay and machine-ID vocabulary. Keep check as structural and numeric validation over the value itself; do not add builders, filesystem readers, host probes or separate configurations for cold boots and restores.
    • Done when:
      • VmConfig::check accepts representative valid blockless and layered configurations.
      • A RAM upper accepts caps 1 through 90, defaults to 50, and refuses values outside that range.
      • VmConfig::check has a case for each documented refusal of its fields, runs without host I/O, and accepts both ConsoleAttachment variants.
    • Needs: SL2.2, above.
    • Estimate: 290 core lines, 3 counted files. Past 580 core lines, stop and ask before continuing.
  3. SL2.3b: The network and the cold-only settings are part of that value.

    • Objective: The same VM configuration must describe its network and distinguish cold-only command-line settings from restore settings. Callers get a checked IPv4 guest address type, while later launch code decides whether the optional address and Boot fit a cold boot or restore.
    • Contents: VmConfig gains its network field and its optional boot field: NetworkConfig { guest_network, policy }, whose address is optional: NVX's default at a cold boot, the snapshot's at a restore; the checked net::Ipv4Cidr (new) (new, parse, address, prefix_len, with serde); NicConfig { guest_network }; DEFAULT_GUEST_NETWORK, moved from host::launch; and Boot { command_line }, required without a snapshot and refused with one.
    • Scope:
      • Add VmConfig's network field: NetworkConfig { guest_network, policy }, with an optional checked guest address, and NicConfig { guest_network }.
      • Add net::Ipv4Cidr with new, parsing, address and prefix accessors, and serde support for the static guest-network form already accepted by the repository.
      • Move DEFAULT_GUEST_NETWORK from nvx-rs/src/host/launch.rs into host::config.
      • Add VmConfig's optional boot field, Boot { command_line }, as its cold-only portion; cold boots use the default address when none is supplied, while restores use the snapshot's address.
    • Not in this PR:
      • IPv6 guest addresses, DHCP or address discovery: the existing VM network accepts one static IPv4 address with a /1 through /30 prefix.
      • Checking a path, policy file or host network state: Ipv4Cidr and the configuration checks are value-only.
      • Enforcing whether Boot is present for a cold boot or absent for a restore: the later host::vm::create sees the snapshot.
      • Reserving command-line tokens or rendering the kernel command line: SL2.4a2 and SL2.4b do that work.
      • Changing network-policy lowering or OpenVMM arguments: this PR only places the existing policy value in the configuration.
      • No builders, generic validation framework, blanket serde derives or extensible network option map: add only the fixed fields, direct checks and Ipv4Cidr serialization this PR names.
    • Approach: Extract the existing guest-network validation from host::launch into one small Ipv4Cidr value and reuse the current address rules. Store the policy and optional address directly in NetworkConfig; do not add an address allocator, network probe or second command-line parser.
    • Done when:
      • Ipv4Cidr construction, parsing and serde round-trip valid addresses and preserve the address and prefix accessors.
      • Ipv4Cidr refuses missing or invalid prefixes, IPv6, and the network, gateway and broadcast addresses.
      • Configuration checks accept both an omitted guest address and an explicit valid address.
      • VmConfig::check accepts representative valid blockless and layered configurations, both with and without boot.
    • Needs: SL2.3a, above.
    • Estimate: 220 core lines, 3 counted files. Past 440 core lines, stop and ask before continuing.
  4. SL2.3c: A capture is one value, which names its snapshots.

    • Objective: Capture-specific settings are currently embedded in broader template concepts. CaptureConfig isolates the inputs a capture adds, checks them without host I/O and derives a stable identity that callers can persist as the name of equivalent snapshots.
    • Contents: Boot::capture; CaptureConfig { disks, processors, memory, invariants }, with CaptureConfig::check, whose refusals are Unsupported errors; DiskCapture::Fresh { image, scratch }, on a #[non_exhaustive] enum; Capacity { boot, capacity } (processors 1, 2, 4 or 8; memory capacity aligned to 128 MiB); the caller's opaque Invariants, with new().with(..); BlockGeometry { length, logical_block_size, physical_block_size }, moved into host::config with the template manifest's validation; and CaptureIdentity (displayable, comparable and serializable) from CaptureConfig::identity(&VmConfig, &Runtime).
    • Scope:
      • Add Boot::capture and CaptureConfig { disks, processors, memory, invariants }, with a pure CaptureConfig::check whose refusals are Unsupported errors.
      • Add non-exhaustive DiskCapture::Fresh { image, scratch }; this PR supports only the repository's fresh-capture device pair.
      • Add Capacity { boot, capacity }: processor boot and capacity are each 1, 2, 4 or 8, and boot does not exceed capacity; memory boot is positive, capacity is at least boot, and capacity is aligned to 128 MiB.
      • Move Invariants and BlockGeometry into host::config, preserving invariant name, value and count limits and the template manifest's geometry validation.
      • Add displayable, comparable and serializable CaptureIdentity, derived by CaptureConfig::identity(&VmConfig, &Runtime) from the supported fresh capture's identifying inputs: runtime identity and contract versions, hypervisor and CPU-profile request, disk geometries, processor and memory boot/capacity, invariants, effective NIC address, console attachment, export presence and boot command line. An omitted cold-boot NIC address equals the explicit default. Exclude paths, per-launch options, restore view and network policy, duplicate VmConfig processor/memory fields, and layered-root format, image identity, GPT bound, upper and overlay details; a fresh capture is blockless. Later VM creation still owns the fresh-capture root/export refusals.
    • Not in this PR:
      • Additional disk-capture variants or storage generations: the enum is non-exhaustive so later work can add them without this PR designing them.
      • Creating snapshot files, reading manifests or driving capture: later snapshot APIs consume the checked configuration.
      • Interpreting or matching invariant names and values: they remain opaque caller-owned strings with only syntax and size checks.
      • Reading or hashing image, scratch or runtime files for the identity: the identity uses the supplied configuration and runtime identity.
      • Moving the NIC, console or export into CaptureConfig: they remain properties of the capture VM's VmConfig.
      • No builders, generic validation framework, blanket serde derives or extensible capture-option map: add only the fixed fields, direct checks and serialization this PR names.
    • Approach: Adapt the existing CaptureClass, Invariants and geometry checks into smaller configuration-owned values. Encode CaptureIdentity deterministically from the checked values and existing identities; do not introduce snapshot storage, file inspection, pluggable identity providers or speculative disk modes.
    • Done when:
      • CaptureConfig::check accepts valid fresh captures and refuses unsupported processor boot or capacity, processor boot above capacity, zero memory boot, memory capacity below boot, and memory capacity not aligned to 128 MiB.
      • host/template/key/tests.rs's Invariants::with name, value and maximum-setting cases move to host/config/tests.rs.
      • host/template/manifest/tests.rs's BlockGeometry validation cases move to host/config/tests.rs, preserving all three fields.
      • Equal VmConfig, Runtime and CaptureConfig inputs produce equal identities, and each identifying field is covered by a differing-input test.
    • Needs: SL2.3b, above.
    • Estimate: 250 core lines, 4 counted files. Past 500 core lines, stop and ask before continuing.

Tests. The runtime and artifact identity tests move with those types, and cover invalid labels, the sha256: form, the contract checks and the differing parts; a runtime-mismatch error has the kind RuntimeMismatch. net::Ipv4Cidr's construction, parsing, accessors, invalid addresses and prefixes, and serde. Each refusal of VmConfig::check and CaptureConfig::check, an Unsupported error, such as a RAM upper's cap outside 1 to 90, a capture's processor count other than 1, 2, 4 or 8, or an unaligned memory capacity; Invariants::with keeps its limit and syntax cases. The value checks accept a valid configuration with or without boot: host::vm::create, which sees the snapshot, pairs them, in #1099 and #1103. CaptureConfig::identity gives equal identities for equal inputs, and covers the configuration, runtime and capture fields that identify a capture. BlockGeometry keeps today's fields and the template manifest's validation.

Done when: every PR above has merged, with dev green.

Activity

  1. changed the title [-]nvx-rs slimming 2.1.1: per-domain errors, and one value for a VM's configuration[/-] [+]nvx-rs slimming 2.1.1: one value for a VM's configuration[/+] on Nov 4, 2026
  2. esaurez commented on Nov 10, 2026

    @esaurez
    ContributorAuthor

    Workstream source/progress checkpoint - 2026-11-10 UTC

    Checked boxes below mean merged scope, not merely an implemented first iteration. Implementation branches are source checkpoints, not automatic qualification, Ready or merge approval. Some starting inputs are frozen/anonymous commits rather than standalone branches; their exact SHAs and known merged producer refs are recorded explicitly.

    The original technical scope remains authoritative, supplemented only by any portable technical clarification in this issue. No machine-specific execution policy is part of this checkpoint.

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

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions