Expand description
§Virtx
Run tasks in disposable Linux VMs from your own code: what a task reads, and what it runs.
Both are ordinary on purpose: a script, a build or a model handed a filesystem and a shell already knows both interfaces, and every added capability arrives as a file to read or a command to run.
- What it reads is a filesystem, with
cat,grepor anything else once a binding mounts it on the host. - What it runs is commands, each an argv sent over one channel, with everything the command wrote coming back.
§Quickstart
Needs the mount feature. On Linux the binding is FuseMount; macOS uses FuseTMount and
Windows DokanMount, with nothing else changed.
use std::path::Path;
use virtx::console::ConsoleClient;
use virtx::fs::{Directory, FuseMount};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// What the task reads: an in-memory file beside a host directory.
let context = Directory::new()
.with_file("notes/today.md", "ship the release".as_bytes())?
.with_mount("project", "/home/me/project")?;
// Constructing the guard mounts, dropping it unmounts; the console holds it for the session.
let mount = FuseMount::try_new(context, Path::new("/tmp/session"))?;
// What the task runs. A session's shape, including where each tree appears to
// commands, is fixed when the console is built.
let mut console = ConsoleClient::builder()
.mount(mount, "/work")
.build()
.await?;
let result = console.exec(["sh", "-c", "wc -w /work/notes/today.md"], None).await?;
println!("{}", String::from_utf8_lossy(&result.stdout));
Ok(())
}§Structure
fs: what a session reads and writes. Stores, the in-memoryDirectory, and the bindings that mount them on the host.console: what a session runs.ConsoleClientruns commands in a session, whichRelayshares with another native module in the same process (ailoy’s, say).protocol: the wire between a console client and a console server. The server is a prebuilt binary,virtx-uvm, thatensure_virtxfetches into the cache’sbin.image: the images a session runs on, declared or built ahead of time.
fs and console meet only at Mount: a console takes trees already
mounted and never builds one or touches a binding, and fs does not know a console
exists. There is no shared error type: fs answers in std::io::Error, classified by
kind, and console in Failure, or anyhow::Error while building.
§The file layout
A module with submodules is a directory whose mod.rs holds its documentation and
re-exports, and whose siblings hold the code, including one named after the module for its
main type (message/message.rs has Message); hence
module_inception is allowed.
Modules§
- console
- The public end: a console server to run commands in, over one channel.
- fs
- Trees a store describes in-process, and trees the operating system has mounted.
- image
- Images a session runs on: declared as a
Recipe, named byImageSource, or built ahead of a session withImageClient. - protocol
- The two ends of a console, and the wire between them.
Functions§
- cache_
root - Everything virtx keeps on this host, under one root:
$VIRTX_HOME, orvirtxunder the user’s cache directory. - ensure_
virtx - Fetch the console server into
cache_root/binif absent, and return that directory.