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
325 changes: 281 additions & 44 deletions tests/runtime-adapter/README.md

Large diffs are not rendered by default.

1,013 changes: 909 additions & 104 deletions tests/runtime-adapter/src/bin/runtime-adapter-host.rs

Large diffs are not rendered by default.

372 changes: 372 additions & 0 deletions tests/runtime-adapter/src/clone.rs

Large diffs are not rendered by default.

36 changes: 27 additions & 9 deletions tests/runtime-adapter/src/hook.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The host program's step hook, for tests: at a named [`Step`] of a launch, it pauses the
//! program, so that a test can act between two steps, as when it replaces a staged image once the
//! launch has checked it, or it exits the program without unwinding, as a crash would end it there.
//! The host program's step hook, for tests: at a named [`Step`] of a launch, or of a command that
//! reattaches to a VM, it pauses the program, so that a test can act between two steps, as when it
//! replaces a staged image once the launch has checked it, or ends a clone's VM once a stop found
//! it, or it exits the program without unwinding, as a crash would end it there.
//!
//! The variable [`STEP_HOOK`] names the step, and what the hook does at it, its [`Action`]:
//!
Expand All @@ -12,8 +13,9 @@
//! the system releases when a process exits, such as its descriptors or handles, and their
//! locks.
//!
//! Without the variable, the hook does nothing. `runtime-adapter-host launch` reads it, and refuses
//! a value that names no step or action, as it refuses a command line that is not a command.
//! Without the variable, the hook does nothing. `runtime-adapter-host launch`, `reattach`, and
//! `stop` read it, and refuse a value that names no step or action, as they refuse a command line
//! that is not a command.

use std::env;
use std::ffi::OsStr;
Expand All @@ -32,8 +34,8 @@ pub const HOOK_EXIT: u8 = 5;
/// How often a paused program checks whether its pause file is gone.
const PAUSE_POLL: Duration = Duration::from_millis(10);

/// A named step of a launch, at which the step hook acts: right after what the launch has done by
/// then, and before what it does next.
/// A named step of a launch, or of a command that reattaches to a VM, at which the step hook acts:
/// right after what the command has done by then, and before what it does next.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Step {
/// `checked`: the launch has checked the bindings of its images, and the export of its shares,
Expand All @@ -52,11 +54,26 @@ pub enum Step {
/// has answered, and the launch is about to commit, so its journal still records the VMM,
/// which no runtime record names yet.
Commit,
/// `found`: `reattach` or `stop` has found the sandbox's VM running, and holds it, under the
/// sandbox's lock, with the session in which a clone answered the Activate of its record
/// again, if the VM is a clone's, but has sent the guest agent nothing more, and stopped
/// nothing.
Found,
}

impl Step {
/// The steps, in the order in which a launch reaches them.
pub const ALL: [Self; 4] = [Self::Checked, Self::Spawned, Self::Ready, Self::Commit];
/// The steps of a launch, in the order in which it reaches them.
pub const LAUNCH: [Self; 4] = [Self::Checked, Self::Spawned, Self::Ready, Self::Commit];

/// The steps: those of a launch, in the order in which it reaches them, then that of a command
/// that reattaches.
pub const ALL: [Self; 5] = [
Self::Checked,
Self::Spawned,
Self::Ready,
Self::Commit,
Self::Found,
Comment thread
esaurez marked this conversation as resolved.
Resolved
];

/// Returns the step's name.
pub const fn as_str(self) -> &'static str {
Expand All @@ -65,6 +82,7 @@ impl Step {
Self::Spawned => "spawned",
Self::Ready => "ready",
Self::Commit => "commit",
Self::Found => "found",
}
}

Expand Down
20 changes: 11 additions & 9 deletions tests/runtime-adapter/src/layered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ pub(crate) fn unicode(path: &Path) -> Result<&str> {

/// Returns the error of a launch whose `what`, its image or its scratch image, at `path`, the
/// sandbox's store does not stage.
fn unstaged(what: &str, path: &Path) -> Error {
pub(crate) fn unstaged(what: &str, path: &Path) -> Error {
Error::unavailable(format!(
"the sandbox's store stages no {what} at {}",
path.display()
Expand Down Expand Up @@ -510,14 +510,16 @@ pub(crate) fn write_record(path: &Path, record: &Value) -> Result<()> {
/// ```
///
/// The `mode` is `layered`, or `blockless` for a VM without a layered root, whose `plan`,
/// `bindings`, and `rootConfiguration` are `null`. The `plan` is the persisted form of the VM's
/// `SandboxPlan`, which [`read_plan`](Self::read_plan) reads back, whose `network` keeps the VM's
/// network, in the form that [`read_network`] reads, or `null` without one. The `bindings` are
/// those that the launch checked, which the store stages for the plan's images, as
/// [`Staged::bindings`](crate::staged::Staged::bindings) finds them, in the serde forms of NVX's
/// `DistroBinding` and `ScratchBinding`; the scratch image's is `null` for an upper in RAM, which
/// has no scratch image. The `rootConfiguration` is the encoding of the root configuration that the
/// host sends, as it sends it, whether or not the guest accepts it.
/// `bindings`, and `rootConfiguration` are `null`, or `clone` for a clone's record, which
/// [`CloneRecord`](crate::clone::CloneRecord) writes, with the members of a layered root's, but a
/// `rootConfiguration` of `null`, and the template that the clone leases. The `plan` is the
/// persisted form of the VM's `SandboxPlan`, which [`read_plan`](Self::read_plan) reads back,
/// whose `network` keeps the VM's network, in the form that [`read_network`] reads, or `null`
/// without one. The `bindings` are those that the launch checked, which the store stages for the
/// plan's images, as [`Staged::bindings`](crate::staged::Staged::bindings) finds them, in the serde
/// forms of NVX's `DistroBinding` and `ScratchBinding`; the scratch image's is `null` for an upper
/// in RAM, which has no scratch image. The `rootConfiguration` is the encoding of the root
/// configuration that the host sends, as it sends it, whether or not the guest accepts it.
#[derive(Clone, Copy, Debug)]
pub struct LaunchRecord<'a> {
/// The VM's kernel command line.
Expand Down
10 changes: 7 additions & 3 deletions tests/runtime-adapter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
//! messages about a layered [`root`], its [`probe`]s, and [`exec`]utions, and the kernel command
//! line and statuses of its [`template`] mode;
//! - host-only, with the `host` feature: the host API too, and the host program, in the `host`,
//! `runtime`, `initramfs`, `staged`, `sharing`, `layered`, `capture`, and `hook` modules and the
//! `runtime-adapter-host` binary;
//! `runtime`, `initramfs`, `staged`, `sharing`, `layered`, `capture`, `clone`, and `hook` modules
//! and the `runtime-adapter-host` binary;
//! - guest-only, with the `guest` feature: the guest API too, and the guest agent, in the `guest`
//! and `worker` modules and the `runtime-adapter-guest` binary, a static
//! `x86_64-unknown-linux-musl` executable.
Expand Down Expand Up @@ -53,10 +53,14 @@
//! activates the clone with the host's `Activate`, whose record the guest library applies, answers
//! `Ready` with the activation, and serves the host's order as after a cold boot. On the host, the
//! `host` module's clone order is the framing through which the restore sequence of
//! `nvx::host::template` activates a clone and starts its sandbox.
//! `nvx::host::template` activates a clone and starts its sandbox, and the host program's
//! `runtime-adapter-host start` starts a clone of a generation in a sandbox of its own, which
//! leases the generation, in the `clone` module.

#[cfg(feature = "host")]
pub mod capture;
#[cfg(feature = "host")]
pub mod clone;
pub mod exec;
pub mod frame;
#[cfg(all(feature = "guest", target_os = "linux"))]
Expand Down
2 changes: 1 addition & 1 deletion tests/runtime-adapter/src/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl Facts {
}

/// Returns whether `key` is a valid key of a fact: lowercase ASCII letters, digits, `.`, and `-`.
fn valid_key(key: &str) -> bool {
pub(crate) fn valid_key(key: &str) -> bool {
!key.is_empty()
&& key.bytes().all(|byte| {
byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'.' || byte == b'-'
Expand Down
11 changes: 8 additions & 3 deletions tests/runtime-adapter/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
//! announces, the start, the executions, the probes, and the stop. The record's workload
//! identity, if it has one, is the whole sandbox's, as a root configuration's is, so that
//! executions name none, and a clone's executions run in the cgroups of the template's
//! bootstrap.
//! bootstrap. It also answers the probe `activation::ACTIVATION_PROBE`, with when the events of
//! the clone's activation and order happened, after the repair's acknowledgement of the
//! restore.
//!
//! The application applies none of the record's other settings: its export, its network, its
//! hostname, and its machine ID. Without an export, a clone refuses each part of a mapping table
Expand Down Expand Up @@ -527,7 +529,9 @@ pub fn work<S: Read + Write + AsFd>(
/// before its capture, and whose first epoch it acknowledged, which the reset that the restore
/// queued starts again: the worker attaches no session. `template` holds the inputs of the root's
/// assembly that the template captured, with which the worker [applies](RootOperations::apply)
/// the record of the host's `Activate`.
/// the record of the host's `Activate`. `acknowledged` is when the repair acknowledged the
/// restore, `nvx::guest::clone::Repaired::acknowledged_at`, if it did, from which the
/// `activation::ACTIVATION_PROBE` reports the events of the clone.
///
/// It ends as [`work`] does, and with [`Worked::Unactivated`] once the activation failed, or
/// [`Worked::Abandoned`] once the broker closed the stream before the clone was ready, after which
Expand All @@ -540,8 +544,9 @@ pub fn work_clone<S: Read + Write + AsFd>(
operations: &mut dyn RootOperations,
activation: Activation<Admission>,
template: RootTemplate,
acknowledged: Option<Instant>,
) -> Result<Worked, ServeError> {
let state = CloneState::new(activation, template);
let state = CloneState::new(activation, template, acknowledged);
serve(
Connection::resume(stream, session)?,
operations,
Expand Down
Loading
Loading