Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/run-nvx-microvm-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ jobs:

with open(sys.argv[1], encoding="utf-8") as stream:
config = json.load(stream)
if config["format"] != 9 or config["export"]["owner"] != "caller":
if config["format"] != 10 or config["export"]["owner"] != "caller":
sys.exit(f"managed sandbox did not persist caller ownership: {config}")
EOF
errors=$(mktemp)
Expand Down Expand Up @@ -690,7 +690,7 @@ jobs:
("/opt/hostedtoolcache", "", "ro", ["nvx-denied"], "directory"),
("/results/output.txt", "", "rw", [], "file"),
]
if config["format"] != 9 or "mounts" in config or shares != expected:
if config["format"] != 10 or "mounts" in config or shares != expected:
sys.exit(f"managed sandbox did not persist every share: {config}")
EOF
nvx-rs/target/release/nvx-rs sandbox start --state-dir "${state}"
Expand Down Expand Up @@ -819,7 +819,7 @@ jobs:
["nvx-writable"],
),
]
if config["format"] != 9 or "mounts" in config or shares != expected:
if config["format"] != 10 or "mounts" in config or shares != expected:
sys.exit(f"managed sandbox did not persist the access policy: {config}")
EOF
nvx-rs/target/release/nvx-rs sandbox start --state-dir "${state}"
Expand Down Expand Up @@ -1125,7 +1125,7 @@ jobs:
$denied = ($child.denied | ForEach-Object { $_.Substring($child.root.Length + 1).Replace("\", "/") }) -join ";"
"$($bind.target),$($bind.source),$mode,$denied,$kind"
}) -join " "
if ($config.format -ne 9 -or $shares -ne "/workspace,,rw,nvx-denied,directory /config/settings.json,,ro,,file /opt/hostedtoolcache,,ro,nvx-denied,directory /results/output.txt,,rw,,file") {
if ($config.format -ne 10 -or $shares -ne "/workspace,,rw,nvx-denied,directory /config/settings.json,,ro,,file /opt/hostedtoolcache,,ro,nvx-denied,directory /results/output.txt,,rw,,file") {
throw "managed sandbox did not persist every share: $($config | ConvertTo-Json -Compress -Depth 5)"
}
try {
Expand Down Expand Up @@ -1223,7 +1223,7 @@ jobs:
function Get-Relative($paths) {
($paths | ForEach-Object { $_.Substring($child.root.Length + 1).Replace("\", "/") }) -join ","
}
if ($config.format -ne 9 -or @($config.export.children).Count -ne 1 -or @($config.export.binds).Count -ne 1 -or $bind.target -ne "/workspace" -or $bind.readOnly -or (Get-Relative $child.denied) -ne "nvx-denied" -or (Get-Relative $child.allowed) -ne "nvx-denied/nvx-allowed" -or (Get-Relative $child.write) -ne "nvx-writable") {
if ($config.format -ne 10 -or @($config.export.children).Count -ne 1 -or @($config.export.binds).Count -ne 1 -or $bind.target -ne "/workspace" -or $bind.readOnly -or (Get-Relative $child.denied) -ne "nvx-denied" -or (Get-Relative $child.allowed) -ne "nvx-denied/nvx-allowed" -or (Get-Relative $child.write) -ne "nvx-writable") {
throw "managed sandbox did not persist the access policy: $($config | ConvertTo-Json -Compress -Depth 5)"
}
try {
Expand Down
4 changes: 2 additions & 2 deletions doc/acceptance-case-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ suite in its shards, and the public sandbox scenarios in its guest and sandbox j
| `sandbox-gpt-layer` | kept | The [cold cells](#cold-boots) of a GPT disk, over a scratch upper and over a RAM upper, through `run`, and `provision` and `start` |
| `sandbox-lifecycle` | kept | A [cold cell](#cold-boots): the EROFS layer over a scratch upper, through `provision` and `start`, which also reattach to the VM from a new process for each command |
| `sandbox-proxy-only` | kept | Its proxy-only network, over the EROFS layer and a scratch upper; it is no [cold cell](#cold-boots) of its own |
| `sandbox-ram-upper` | kept | A [cold cell](#cold-boots): the EROFS layer over a RAM upper, through `run`, and `provision` and `start` |
| `sandbox-ram-upper` | kept | A [cold cell](#cold-boots): the EROFS layer over a RAM upper, through `run`, and `provision` and `start`. Since SL3.10c, it checks that `provision` records the configuration's format 10 |
| `scratch-snapshot` | kept | |
| `smp` | kept | |
| `smp-lapic` | kept | Runs only when a run names it |
Expand Down Expand Up @@ -447,7 +447,7 @@ their own. The tests that a step runs have rows of their own where they concern
| `.github/workflows/run-nvx-microvm-tests.yml` | Run public managed sandbox acceptance on Linux and on Windows | kept | Runs `sandbox-gpt-layer` and `vm-lifecycle` too, since SL5.1b: see [Cold boots](#cold-boots); and `snapshot-core` and `snapshot-tiers`, since SL5.1c: see [Snapshots](#snapshots) |
| `.github/workflows/run-nvx-microvm-tests.yml` | Run Ubuntu and Azure Linux guest smoke tests on Linux and on Windows | kept | |
| `.github/workflows/run-nvx-microvm-tests.yml` | Run extended Ubuntu guest tests on Linux/KVM | kept | No longer runs `snapshot-core`, which needs the Alpine control guest since SL5.1c rewrote it |
| `.github/workflows/run-nvx-microvm-tests.yml` | Run the Ubuntu sandbox layer, live-share, managed live-share, caller-owned live-share, concurrent shares and share access policy tests on Linux and on Windows | kept | The layer smoke test is the `run` of a [cold cell](#cold-boots) |
| `.github/workflows/run-nvx-microvm-tests.yml` | Run the Ubuntu sandbox layer, live-share, managed live-share, caller-owned live-share, concurrent shares and share access policy tests on Linux and on Windows | kept | The layer smoke test is the `run` of a [cold cell](#cold-boots). Since SL3.10c, the share tests check that `provision` records the configuration's format 10 |
| `.github/workflows/run-nvx-microvm-tests.yml` | Build the runtime adapter's guest agent on Linux; Download the runtime adapter's guest agent on Windows | retired | The adapter's guest agent |
| `.github/workflows/run-nvx-microvm-tests.yml` | Run runtime adapter scenarios on Linux and on Windows | retired | The adapter's scenarios, whose fates are above |
| `.github/workflows/run-platform.yml` | Run benchmark: the acceptance test, the performance suite, the multi-vCPU shell restore and the device operation rates | kept | |
Expand Down
2 changes: 1 addition & 1 deletion doc/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ inside a writable part of a share. On Windows, it refuses a path that only a
verbatim `\\?\` path names, such as that of a directory whose name ends in a
period or a space, which the path without the prefix would not name. The
shares' children follow their resolved host paths. A managed sandbox stores
the plan in its typed configuration, in format 9. Each `start` checks it again,
the plan in its typed configuration, in format 10. Each `start` checks it again,
as `run` does once it has verified the distro layer: it refuses a host path
that no longer holds a directory or regular file as recorded, a recorded path
whose file identity changed, and shares whose host paths came to overlap, such
Expand Down
13 changes: 7 additions & 6 deletions nvx-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2879,15 +2879,16 @@ The state directory is the directory of the sandbox's
sandbox shares, and `config.json` is the CLI's own record beside them. It also
records the [distro binding](#distro-bindings) and the
[scratch binding](#checked-handoff) of the sandbox, and its network as the
typed `SandboxNetwork`, in the serde form of the plan's network. The typed
configuration names one EROFS or GPT image by path and identity, and a scratch
upper by path or a RAM upper with its cap from 1 through 90 percent, 50 by
default. `nvx-rs` refuses earlier configuration formats rather than migrating
them:
network options from which each `start` builds the policy again, as `provision`
built it. The typed configuration names one EROFS or GPT image by path and
identity, and a scratch upper by path or a RAM upper with its cap from 1 through
90 percent, 50 by default. `nvx-rs` refuses earlier configuration formats, such
as format 9, rather than migrating them, and says to deprovision the sandbox and
provision it again:

| File | Contents |
| --- | --- |
| `config.json` | The provisioned sandbox, in format 9 only: `image` holds its format, path and identity; `upper` is tagged as scratch with its path or RAM with `max_memory_percent`. `distro_binding` binds the image, and `scratch_binding` binds scratch or is `null` for RAM. The export and network are typed, `null` when absent. A sandbox that `snapshot restore` provisioned also records its snapshot's name under `source_snapshot`, the absolute path of the snapshot's store under `source_store`, and the program and arguments of the workload that each restore runs under `workload`; one that boots cold records none of them. An atomic pretty-JSON write uses mode 0600, and start reads the same strict typed fields without a legacy reader. |
| `config.json` | The provisioned sandbox, in format 10 only: `image` holds its format, path and identity; `upper` is tagged as scratch with its path or RAM with `max_memory_percent`. `distro_binding` binds the image, and `scratch_binding` binds scratch or is `null` for RAM. The export is typed, `null` when absent. `network`, `null` without `--net`, holds `--net`, `--network-egress`, `--network-ingress`, `--host-loopback`, `--network-proxy`, each `null` when not given, and the `--host-loopback-forward` options, as given, with the egress rules in OpenVMM's form, from a policy file's compile if one was given. A sandbox that `snapshot restore` provisioned also records its snapshot's name under `source_snapshot`, the absolute path of the snapshot's store under `source_store`, and the program and arguments of the workload that each restore runs under `workload`; one that boots cold records none of them. An atomic pretty-JSON write uses mode 0600, and start reads the same strict typed fields without a legacy reader. |
| `sandbox.lock` | The store's lock, which serializes the lifecycle transitions |
| `exec.lock` | The exec lock, which an `exec` holds from before it finds the running VM until its workload ends, so that one `exec` at a time runs in the sandbox; it stays from the first `exec` until `deprovision` |
| `launch.json` | The store's journal of a start in progress, or of one that was interrupted |
Expand Down
16 changes: 2 additions & 14 deletions nvx-rs/src/host/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ use super::{Exit, Result, check_interrupt, output};
use crate::ErrorCode;
use crate::activation::{MachineIdMode, View};
use crate::host::artifacts::{ArtifactDir, Guest, require_artifact};
use crate::host::config::{
Boot, ConsoleAttachment, NetworkConfig, NicConfig, RootConfig, VmConfig,
};
use crate::host::config::{Boot, ConsoleAttachment, NicConfig, RootConfig, VmConfig};
use crate::host::filesystem::{
self, ExportPlan, ExportRequest, Mapping, Owner, PathList, ReservedTargets, Target,
};
Expand Down Expand Up @@ -643,17 +641,7 @@ fn cold_vm_config(
rules: &NativeRules,
filesystem: Option<ExportPlan>,
) -> Result<VmConfig> {
let network = sandbox_network(&options.network, rules)?
.map(|network| -> Result<NetworkConfig> {
Ok(NetworkConfig {
guest_network: Some(
crate::net::Ipv4Cidr::parse(network.guest_network())
.map_err(|error| Exit::error(ErrorCode::Unsupported, error.to_string()))?,
),
policy: network.policy().clone(),
})
})
.transpose()?;
let network = sandbox_network(&options.network, rules)?;
let config = VmConfig {
processors: options.processors,
memory_mib: memory_mib(options),
Expand Down
5 changes: 4 additions & 1 deletion nvx-rs/src/host/cli/sandbox/lifecycle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use crate::host::cli::artifacts::{Located, locate};
use crate::host::cli::deadline::RETRY_INTERVAL;
use crate::host::cli::sandbox::lock::LifecycleLock;
use crate::host::cli::sandbox::state::{
Config, RecordedDistro, RecordedScratch, Source, read_config, serialize_launch, write_json,
Config, NetworkRecord, RecordedDistro, RecordedScratch, Source, read_config, serialize_launch,
write_json,
};
use crate::host::cli::sandbox::{Artifacts, error_with_cause};
use crate::host::cli::session::Session;
Expand Down Expand Up @@ -68,6 +69,8 @@ pub(crate) struct ProvisionConfig<'a> {
pub(crate) cmdline: &'a str,
/// The RAM upper's cap, or the default when omitted.
pub(crate) ram_upper_percent: Option<u8>,
/// The network options, or `None` without `--net`.
pub(crate) network: Option<&'a NetworkRecord>,
}

/// The control features that the layered sandbox root must provide for the requests of
Expand Down
11 changes: 7 additions & 4 deletions nvx-rs/src/host/cli/sandbox/lifecycle/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::host::cli::download::Hold;
use crate::host::cli::exec_lock::ExecLock;
use crate::host::cli::sandbox::lock::LifecycleLock;
use crate::host::cli::sandbox::state::{
Config, RecordedDistro, RecordedScratch, Source, read_config, serialize_launch,
Config, NetworkRecord, RecordedDistro, RecordedScratch, Source, read_config, serialize_launch,
};
use crate::host::cli::sandbox::{
Artifacts, Options, error_with_cause, hypervisor, path_string, refuse_own_files,
Expand Down Expand Up @@ -538,9 +538,10 @@ pub(crate) fn exec_workload(
/// the workload ended, or nothing for a dry run, which launches nothing.
///
/// The VM is the one that `start` launches for the configuration that `provision` records for
/// `launch`, whose distro layer `distro` is at the path that `provision` records, with the options
/// of `options`: the run serializes that configuration and reads it back as `start` does, then
/// launches it as `start` does, but in a temporary VM directory rather than a state directory.
/// `launch`, whose distro layer `distro` is at the path that `provision` records, and `network`,
/// the record of its network options, if any, with the options of `options`: the run serializes
/// that configuration and reads it back as `start` does, then launches it as `start` does, but in
/// a temporary VM directory rather than a state directory.
/// Before it downloads or launches anything, it refuses what `start` refuses of the configuration
/// and `exec` of `request`, after a missing artifact; it then refuses the shares that `start`
/// refuses, with its VM directory in place of a state directory, and those of the OpenVMM that it
Expand All @@ -555,6 +556,7 @@ pub(crate) fn exec_workload(
pub(crate) fn run(
launch: &SandboxLaunch,
distro: &RecordedDistro,
network: Option<&NetworkRecord>,
artifacts: &Artifacts<'_>,
options: &Options,
request: &ExecRequest,
Expand All @@ -566,6 +568,7 @@ pub(crate) fn run(
memory_mib: options.memory_mib,
cmdline: &options.cmdline,
ram_upper_percent: options.ram_upper_percent,
network,
};
let recorded = record(launch, distro, &provision).and_then(|(config, launch)| {
// As `start` does, refuse the user's own nvx_* tokens, and the command line that the
Expand Down
1 change: 1 addition & 0 deletions nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fn run_checks_again_that_its_shares_do_not_overlap() {
memory_mib: 256,
cmdline: "",
ram_upper_percent: None,
network: None,
};
record(&launch, &distro, &config).unwrap();

Expand Down
10 changes: 3 additions & 7 deletions nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::host::cli::sandbox::sandbox_network;
use crate::host::cli::sandbox::state::{RecordedDistro, serialize_launch, write_json};
use crate::host::cli::snapshots::{self, Name};
use crate::host::cli::store::StateDir;
use crate::host::config::NetworkConfig;
use crate::host::filesystem::{Bind, ExportChild, ExportPlan, Owner};
use crate::host::network::{Access, NetworkPolicy};
use crate::host::paths::resolve;
Expand All @@ -31,7 +30,6 @@ use crate::host::sandbox::options::sandbox_mounts;
use crate::host::sandbox::{SandboxLaunch, SandboxSettings, SandboxUpper};
use crate::host::snapshot::tests::RestoreFixture;
use crate::host::snapshot::{DESCRIPTION_FILE, KEY_FILE, OPENVMM_DIR};
use crate::net::Ipv4Cidr;
use crate::protocol::root::RootImage;
use crate::protocol::{
APP_ACTIVATE, APP_EXEC, APP_EXIT, APP_HEADER_LEN, APP_MAPS, APP_READY, APP_STDOUT, OUTER_DATA,
Expand Down Expand Up @@ -385,12 +383,8 @@ fn a_one_off_restore_installs_the_network_options_of_run_as_its_own_policy() {
.nic();
let network = run::restored_network(options.network, nic).unwrap();
let rules = network.egress_rules().unwrap();
let network = sandbox_network(&network, &rules).unwrap().unwrap();
let mut config = fixture.restore.config.clone();
config.network = Some(NetworkConfig {
guest_network: Some(Ipv4Cidr::parse(network.guest_network()).unwrap()),
policy: network.policy().clone(),
});
config.network = sandbox_network(&network, &rules).unwrap();
fixture.start("state", config, "ready", 30.0).unwrap();
// The guest learns the DNS server that the policy lets it reach, and announces its listeners,
// which the policy publishes on host loopback.
Expand Down Expand Up @@ -691,6 +685,7 @@ fn deprovision_removes_a_restored_sandboxs_view_only_under_its_snapshots_lock()
memory_mib: 512,
cmdline: "",
ram_upper_percent: None,
network: None,
};
let distro = RecordedDistro::new(&launch, binding).unwrap();
let text = serialize_launch(&launch, &distro, None, &options, Some(&source)).unwrap();
Expand Down Expand Up @@ -742,6 +737,7 @@ fn a_restored_start_refuses_a_share_of_its_snapshot_store() {
memory_mib: 512,
cmdline: "",
ram_upper_percent: None,
network: None,
};
let distro = RecordedDistro::new(&launch, binding).unwrap();
let source = fixture.source();
Expand Down
Loading
Loading