supermachine 0.4.23

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.
//! Restore from a self-contained snapshot bundle dir.
//!
//! Pair with `supermachine bundle --into DIR --image NAME`:
//!
//! ```sh
//! supermachine bundle --into /tmp/my-bundles --image nginx:1.27-alpine
//! cargo supermachine build --release --example bundle_load
//! target/release/examples/bundle_load /tmp/my-bundles/nginx_1_27-alpine
//! ```
//!
//! The point: the bundle dir is self-contained — kernel, snapshot,
//! layers, all relative paths inside it. An embedder ships this
//! inside `MyApp.app/Contents/Resources/<name>/` and calls
//! `Image::from_snapshot` against it. No supermachine install on
//! the end-user's machine.
//!
//! This example doesn't need `cargo install supermachine` to run
//! the bundle — it just needs the bundle dir.

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

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

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

    let t0 = Instant::now();
    let image = Image::from_snapshot(&bundle_dir)?;
    eprintln!("loaded {bundle_dir} in {:?}", t0.elapsed());
    eprintln!(
        "  memory={} MiB  vcpus={}  layers={}",
        image.memory_mib(),
        image.vcpus(),
        image.snapshot_path().display(),
    );

    let t1 = Instant::now();
    let vm = Vm::start(&image, &VmConfig::new())?;
    eprintln!("vm started in {:?}", t1.elapsed());

    let mut sock = vm.connect()?;
    sock.write_all(b"GET / HTTP/1.1\r\nHost: workload\r\nConnection: close\r\n\r\n")?;
    let mut response = Vec::new();
    sock.read_to_end(&mut response)?;
    let preview = String::from_utf8_lossy(&response);
    for line in preview.lines().take(4) {
        eprintln!("  {line}");
    }

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