From d10973c4670d179df68b570809207f22508e329b Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 8 Jun 2026 21:54:47 +0200 Subject: [PATCH] feat(vm): add --gui/--nogui to `vm new --start`, default headless MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror the `job` flag on the manual lifecycle: `vm new --start` was hardcoded headless; add --gui/--nogui (default --nogui) so a clone can be booted into the Workstation GUI window for interactive debugging. The start banner reflects the mode. Also update the runbook: §4.1 shows the --gui variant, and §3 notes that the burnin-dummy build.sh is a ~30s fake build writing dist/build-info.txt so the examples exercise the full pipeline. --- docs/RUNBOOK-PhaseC.md | 17 +++++++++++++++++ src/ci_orchestrator/commands/vm.py | 16 +++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/RUNBOOK-PhaseC.md b/docs/RUNBOOK-PhaseC.md index 572b2e5..e9faf24 100644 --- a/docs/RUNBOOK-PhaseC.md +++ b/docs/RUNBOOK-PhaseC.md @@ -179,6 +179,10 @@ waits for the guest, runs the build, collects artifacts, and destroys the clone. It is exactly what the runner invokes on each push, and you can run it by hand too. +The examples use `Simone/burnin-dummy`, whose `build.sh` simulates a real build +(sleeps ~30 s, then writes `dist/build-info.txt`) — so the run exercises the +full clone → build → artifact-collect → destroy path end to end. + ```bash ci job \ --job-id manual-$(date +%s) \ @@ -246,6 +250,19 @@ ci vm new \ --start # prints the clone's VMX path on stdout ``` +`--start` boots the clone headless. To watch it in the Workstation GUI instead, +add `--gui` (needs an X display — see [§4.7](#47-open-a-vm-in-the-workstation-gui)): + +```bash +ci vm new \ + --template /var/lib/ci/templates/LinuxBuild2404/LinuxBuild2404.vmx \ + --snapshot BaseClean-Linux \ + --clone-base-dir /var/lib/ci/build-vms \ + --job-id dbg-1 \ + --guest-os linux \ + --start --gui +``` + ### 4.2 Wait until reachable Prints the guest IP once ready. Use `--ip-address` to skip polling, or diff --git a/src/ci_orchestrator/commands/vm.py b/src/ci_orchestrator/commands/vm.py index 10eeecf..73ba735 100644 --- a/src/ci_orchestrator/commands/vm.py +++ b/src/ci_orchestrator/commands/vm.py @@ -406,7 +406,15 @@ def vm_cleanup( "start_vm", is_flag=True, default=False, - help="Start the clone headless immediately after creation.", + help="Start the clone immediately after creation.", +) +@click.option( + "--gui/--nogui", + "gui", + default=False, + show_default=True, + help="With --start, open the Workstation GUI window (--gui, needs an X " + "display) or start headless (--nogui, the default).", ) def vm_new( template: str, @@ -416,6 +424,7 @@ def vm_new( vmrun_path: str | None, guest_os: str, start_vm: bool, + gui: bool, ) -> None: """Create a linked clone of the template VM for an ephemeral CI build. @@ -475,9 +484,10 @@ def vm_new( click.echo(f"[vm new] clone created in {elapsed:.1f}s", err=True) if start_vm: - click.echo("[vm new] starting VM headless...", err=True) + mode = "GUI" if gui else "headless" + click.echo(f"[vm new] starting VM ({mode})...", err=True) try: - backend.start(handle, headless=True) + backend.start(handle, headless=not gui) except BackendError as exc: raise click.ClickException(f"vmrun start failed: {exc}") from exc click.echo("[vm new] VM started.", err=True)