supermachine 0.4.15

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.
//! Bake an image with custom env / cmd / memory via `Image::builder`.
//!
//! ```sh
//! cargo supermachine build --release --example builder
//! target/release/examples/builder
//! ```
//!
//! Each setter that touches the workload's behaviour (env, cmd,
//! memory, guest_port) is part of the bake's input fingerprint, so
//! changing it produces a different snapshot. Use
//! `with_name(...)` to keep multiple side-by-side configs of the
//! same image ref.

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

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

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let t0 = Instant::now();

    // Same image ref as oci_simple.rs but with a custom env var.
    // First run bakes a fresh snapshot; subsequent runs hit the
    // cache as long as the inputs match.
    let image = Image::builder("nginx:1.27-alpine")
        .with_name("nginx-builder-demo")
        .with_memory_mib(256)
        .with_env("DEMO_MARKER", "from-builder")
        .build()?;
    eprintln!("image ready in {:?}", t0.elapsed());

    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(())
}