1. Your first provision script

A provision block that waits for the guest and configures it through the typed API.

After this lesson you can

- Attach a provision script to the lab - Use lab.vm(…), wait_ready, and exec from wscript - Understand when provisions run (after boot, in declaration order)

A provision "scripts/setup.ws" { } block runs its script after vmlab up boots the VMs (scope it with vms = ["dc01"] to run only when those VMs come up). The script's fn main(lab: Lab) receives the running lab; lab.vm("alp")? yields a VM handle whose wait_ready(secs) blocks until the guest agent answers and whose exec runs guest commands with a typed ExecResult back.

This replaces chains of vmlab exec calls: one script, real control flow, real error handling.

§ 1Exercise: Wait, exec, report

Write scripts/setup.ws that waits for the guest and logs its Alpine release, then re-run vmlab up.

wscript
use vmlab

fn main(lab: Lab) {
    let alp = lab.vm("alp").expect("no vm alp")
    alp.wait_ready(600).expect("agent never came up")
    let rel = alp.exec("/bin/cat", ["/etc/alpine-release"]).expect("exec failed")
    lab.log("alpine release: " + rel.stdout.trim())
}

Expected result

vmlab up ends with alpine release: 3.23.x in the lab log (also visible via vmlab logs).

Hint

exec takes the program and its arguments separately — alp.exec("/bin/cat", ["/etc/alpine-release"]), not one shell string.