pub struct PooledVm<'a> { /* private fields */ }Expand description
A Vm checked out of an Image’s hidden pool. Derefs
to Vm, so every method on Vm is callable. On Drop the
VM returns to the pool — the next Image::acquire gets
a freshly snapshot-restored worker in ~5 ms.
Bound to the Image’s lifetime so the pool can’t outlive
its owner. Acquires currently serialize on the pool’s single
worker; concurrent acquires from one process block until the
previous PooledVm is dropped.
Implementations§
Source§impl PooledVm<'_>
impl PooledVm<'_>
Sourcepub fn snapshot(&self, dest_dir: impl Into<PathBuf>) -> Result<Image, Error>
pub fn snapshot(&self, dest_dir: impl Into<PathBuf>) -> Result<Image, Error>
Capture a live snapshot of this pooled VM (Linux/KVM), non-consuming, so
the builder can snapshot one VM repeatedly across layers. Delegates to
Vm::snapshot_live.
Sourcepub fn snapshot_diff(
&self,
dest_dir: impl Into<PathBuf>,
base_path: &Path,
) -> Result<Image, Error>
pub fn snapshot_diff( &self, dest_dir: impl Into<PathBuf>, base_path: &Path, ) -> Result<Image, Error>
Live differential snapshot against base_path (a full snapshot’s
restore.snap) — non-consuming. Delegates to Vm::snapshot_diff_live.
Methods from Deref<Target = Vm>§
Sourcepub fn vsock_path(&self) -> &Path
pub fn vsock_path(&self) -> &Path
Path to the host-side unix socket that proxies bytes to /
from the first TSI listener inside the guest. Connect to it
with UnixStream::connect (or via Vm::connect).
Sourcepub fn exec_path(&self) -> &Path
pub fn exec_path(&self) -> &Path
Path to the host-side unix socket that bridges to the in-guest exec agent (native AF_VSOCK on the guest side). Reachable once the agent lands in the initramfs and is running guest-side; until then dialing it returns an immediate EOF.
Sourcepub fn exec<I, S>(&self, argv: I) -> Result<ExecChild>
pub fn exec<I, S>(&self, argv: I) -> Result<ExecChild>
Spawn a process inside the running guest. Equivalent to
docker exec. Returns an crate::exec::ExecChild handle
you can read stdout/stderr from, write stdin to, and
wait() for an exit status.
let image = Image::from_snapshot("path/to/snapshot")?;
let vm = Vm::start(&image, &VmConfig::new())?;
let mut child = vm.exec(["sh", "-c", "echo hi"])?;
let mut buf = String::new();
child.stdout().unwrap().read_to_string(&mut buf)?;
assert_eq!(buf, "hi\n");
child.wait()?;Sourcepub fn exec_builder(&self) -> ExecBuilder
pub fn exec_builder(&self) -> ExecBuilder
Configurable exec — TTY, env vars, cwd, initial winsize,
timeout, and the crate::exec::ExecBuilder::output
convenience that drains stdio + collects exit status into
one crate::exec::ExecOutcome.
Sourcepub fn write_file(&self, path: &str, bytes: &[u8]) -> Result<()>
pub fn write_file(&self, path: &str, bytes: &[u8]) -> Result<()>
Write bytes to path inside the guest, atomically.
Native vsock RPC — no exec, no shell. Roughly ~100 µs per
call regardless of file size (up to the 12 MiB raw limit
imposed by the agent’s frame cap).
The guest agent stages to a sibling tmp file then renames
for atomicity, so partial writes don’t leave a half-baked
file at path.
let image = Image::from_snapshot("path/to/snapshot")?;
let vm = image.start(&VmConfig::new())?;
vm.write_file("/tmp/main.rs", b"fn main() { println!(\"hi\"); }")?;
let out = vm.exec_builder()
.argv(["rustc", "/tmp/main.rs", "-o", "/tmp/main"])
.output()?;
assert!(out.success());Sourcepub fn read_file(&self, path: &str) -> Result<Vec<u8>>
pub fn read_file(&self, path: &str) -> Result<Vec<u8>>
Read path from inside the guest. Default cap is 32 MiB
(raised in 0.5.0 from the prior 4 MiB to accommodate
Playwright trace.zip artifacts and similar mid-sized blobs).
For larger files use Vm::read_file_with_max_bytes with
an explicit cap, or stream via Vm::exec (cat).
Sourcepub fn read_file_with_max_bytes(
&self,
path: &str,
max_bytes: u64,
) -> Result<Vec<u8>>
pub fn read_file_with_max_bytes( &self, path: &str, max_bytes: u64, ) -> Result<Vec<u8>>
Like Vm::read_file but with an explicit byte cap. Returns
an error if the file exceeds max_bytes so the caller never
gets a partial result silently. Cap is enforced inside the
guest before any bytes leave it.
Sourcepub fn workload_signal(&self, signum: i32) -> Result<()>
pub fn workload_signal(&self, signum: i32) -> Result<()>
Send a Unix signal to the guest’s main workload process.
Use this for docker stop-style graceful shutdown:
vm.workload_signal(libc::SIGTERM)?;
// ...wait for the workload to clean up...
vm.stop()?;Implementation: dials the in-guest exec agent on a fresh
connection with a CONTROL frame; the agent reads
/run/supermachine-workload.pid (written by init-oci’s
PID-1 supervisor) and kill(pid, signum) it. Returns
Err(NotFound) if the workload hasn’t been spawned yet
(only happens during the bake-time window).
Sourcepub fn connect(&self) -> Result<UnixStream>
pub fn connect(&self) -> Result<UnixStream>
Connect to the guest’s first TSI listener. The returned
UnixStream is byte-equivalent to a TcpStream to the
guest’s :80 (or whatever port it bound).
For HTTP, just write a request and read the response: supermachine’s vsock-mux is a transparent proxy.
Sourcepub fn request_balloon_inflate(&self, pages: u32) -> bool
pub fn request_balloon_inflate(&self, pages: u32) -> bool
Reclaim guest memory via virtio-balloon: ask the guest to release pages
4 KiB pages, which the device then madvise(MADV_FREE)s on the host RAM
map (the kernel can drop them under pressure). Requires the VM to have been
started with VmConfig::with_balloon(true) on a
cold boot; returns false if no balloon device is attached. Asynchronous —
the guest’s balloon driver frees pages in the background.
Sourcepub fn expose_tcp(
&self,
host_port: u16,
guest_port: u16,
) -> Result<TcpForwarder>
pub fn expose_tcp( &self, host_port: u16, guest_port: u16, ) -> Result<TcpForwarder>
Bind a TCP listener on 127.0.0.1:host_port that forwards
each accepted connection to the guest’s TSI listener (the
same destination as Vm::connect). Returns a
TcpForwarder that owns the accept-loop thread; drop it
(or call TcpForwarder::stop) to stop accepting new
connections. In-flight connections continue until they close
naturally.
host_port = 0 lets the OS pick a free port; read the actual
address back via TcpForwarder::local_addr.
guest_port pins the host-port → guest-port mapping. The
host writes a small per-connection routing header (SMUX-PORT -V1\0\0\0\0 + u32 BE port) before piping bytes, and the
vsock-mux peeks (MSG_PEEK) that header and routes to the
matching TSI listener instead of falling back to “first
AF_INET listener.” Pass guest_port = 0 to opt out of the
header and keep the legacy first-listener behavior — useful
when the guest only binds one port and you want a router-
style any-port forward.
Use this when you want the embedded VM to look like a normal
localhost service (e.g. http://127.0.0.1:9090/) rather than
having every caller go through vm.connect().
let image = Image::from_snapshot("path/to/snapshot")?;
let vm = Vm::start(&image, &VmConfig::new())?;
let fwd = vm.expose_tcp(9090, 80)?;
println!("nginx is on {}", fwd.local_addr());
// ... do work ...
drop(fwd); // stop forwardingSourcepub fn expose_tls(&self, cfg: TlsConfig) -> Result<SocketAddr>
pub fn expose_tls(&self, cfg: TlsConfig) -> Result<SocketAddr>
(Linux/KVM) Start a host-side TLS terminator for this VM: accept HTTPS on
cfg.listen_addr, terminate with rustls, and bridge decrypted plaintext
to the guest’s TSI listener — the guest serves plain HTTP, no TLS code in
the guest. This is the in-process counterpart of the macOS/HVF worker’s
--tls-* flags (feature parity). Fire-and-forget: the acceptor runs for
the VM’s lifetime. Requires vsock enabled.
Sourcepub fn snapshot_live(
&self,
dest_dir: impl Into<PathBuf>,
) -> Result<Image, Error>
pub fn snapshot_live( &self, dest_dir: impl Into<PathBuf>, ) -> Result<Image, Error>
LIVE snapshot (Linux/KVM): capture a loadable Image WITHOUT stopping
the guest — the VM keeps running and can be snapshotted again. Backs the
builder’s one-VM-per-layer snapshotting. &self (non-consuming).
Sourcepub fn snapshot_diff_live(
&self,
dest_dir: impl Into<PathBuf>,
base_snap: &Path,
) -> Result<Image, Error>
pub fn snapshot_diff_live( &self, dest_dir: impl Into<PathBuf>, base_snap: &Path, ) -> Result<Image, Error>
LIVE differential snapshot (Linux/KVM): like Vm::snapshot_live but
stores only the guest-RAM pages changed vs base_snap (a full snapshot’s
restore.snap). Non-consuming — the VM keeps running. The builder chains
these per layer off one VM.