supermachine 0.4.11

Run any OCI/Docker image as a hardware-isolated microVM on macOS HVF (Linux KVM and Windows WHP in progress). Single library API, zero flags for the common case, sub-100 ms cold-restore from snapshot.
//! Embed-supermachine demo: spin up a microVM from a baked
//! snapshot, send an HTTP request to its workload over the
//! vsock-mux unix socket, print the response.
//!
//! Usage:
//!
//! ```sh
//! # Bake the snapshot once via the CLI:
//! supermachine run nginx:1.27-alpine --detach && supermachine run --stop
//!
//! # Then run this example pointing at the resulting snapshot:
//! cargo run --release --example embed_simple -- \
//!     ~/.local/supermachine-snapshots/nginx_1_27-alpine/restore.snap
//! ```
//!
//! Required setup: this example's binary needs the HVF
//! entitlement. The `cargo-supermachine` plugin handles it:
//!
//! ```sh
//! cargo install supermachine
//! cargo supermachine build --release --example embed_simple
//! ```

use std::io::{Read, Write};
use std::time::Instant;

use supermachine::{Image, Vm, VmConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let snapshot_path = std::env::args()
        .nth(1)
        .ok_or("usage: embed_simple <snapshot-path>")?;

    let t0 = Instant::now();
    let image = Image::from_snapshot(&snapshot_path)?;
    let vm = Vm::start(&image, &VmConfig::new())?;
    eprintln!("vm started in {:?}", t0.elapsed());
    eprintln!("vsock path: {}", vm.vsock_path().display());

    // Send an HTTP request directly through the vsock-mux socket.
    // The bytes proxy through to the guest's TSI listener (typically
    // the workload's :80) — supermachine's vsock bridge is a
    // transparent byte pump.
    let mut sock = vm.connect()?;
    sock.write_all(
        b"GET / HTTP/1.1\r\n\
          Host: workload\r\n\
          Connection: close\r\n\
          \r\n",
    )?;
    let mut response = Vec::new();
    sock.read_to_end(&mut response)?;
    eprintln!("response: {} bytes", response.len());

    // Print the response status line + first few headers.
    let preview = String::from_utf8_lossy(&response);
    for line in preview.lines().take(6) {
        eprintln!("  {line}");
    }

    vm.stop()?;
    eprintln!("vm stopped after {:?}", t0.elapsed());
    Ok(())
}