Files
James Stringer 4087baa4bf Add headless --headless daemon, HTTP/JSON API + Python SDK, and SSH key deploy
Headless mode: `appsandbox.exe --headless` runs a single-owner daemon that hosts
the core over a loopback HTTP/JSON API (http.sys) with a host.json discovery
file. A dependency-free Python SDK, examples, and a self-contained regression
suite live under tools/headless-api/ (PLAN.md = design rationale).

The API mirrors the GUI: create/start/shutdown/stop/delete/edit, snapshots and
branches (incl. base branches via the new asb_snap_base_branch_count), templates,
sshInfo, an SSE /v1/events stream, GUI-mirrored input validation, a startup
fail-fast (admin / Win11 build / VirtualMachinePlatform), and a single-instance
mutex shared with the GUI so only one of GUI/headless runs at a time.

SSH key deploy: sshDeployKey (requires sshEnabled) has the core generate an
AppSandbox ed25519 keypair once and the guest agent write the public key into
authorized_keys -- Windows administrators_authorized_keys (+ ACL), Linux/macOS
~/.ssh -- reporting a new ssh_key_deployed status (sshState 4). The GUI SSH
button and the SDK use the key for password-less login. Verified end-to-end on
Windows.

The Linux guest builds its agent/driver source from this branch's GitHub repo;
asb_core.c points the prefetch at "headless-api" (revert to "main" before merge,
see PLAN.md).
2026-06-09 20:12:18 -04:00

31 lines
1.1 KiB
Python

"""Start a VM and poll until it is up. Usage: python start_vm.py <name>"""
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import asb
if len(sys.argv) < 2:
sys.exit("usage: python start_vm.py <name> (run list_vms.py to see names)")
name = sys.argv[1]
c = asb.connect()
code, body = c.start(name)
print("start ->", code, body)
print("polling status (Ctrl-C to stop watching)...")
# These VMs can take 10-15 min to reach 'online' (agent connected). Polling is
# miss-proof: the current state is read live each time, so disconnects don't matter.
last = None
import time
while True:
s = c.status(name)
if (s["state"], s.get("progress")) != last:
last = (s["state"], s.get("progress"))
print(f' state={s["state"]:10} running={s["running"]} progress={s.get("progress")}')
if s["state"] == "online":
print("VM is online (guest agent connected).")
break
if s["state"] == "stopped":
print("VM is stopped (start may have failed -- check the daemon log / alerts).")
break
time.sleep(3)