AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
서버 BMC에 연결하면 하드웨어 점검·무인 ESXi 설치·결과 검증·Holodeck 준비까지 수행
Point it at a server's BMC and it checks the hardware, installs ESXi unattended, verifies the result and prepares the host for Holodeck.
개발 도구Python · JavaScriptGitHub @djsincla온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Bare metal to VMware Holodeck through one API: Redfish preflight, unattended ESXi install, host prep and appliance (OVA) deployment for your lab.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Point GroundZero at a server's BMC. It checks the hardware, installs ESXi unattended,
validates the result, and gets the host ready for VMware Holodeck.
Building a Holodeck lab usually means an evening of iDRAC consoles, hand-edited kickstarts and
re-burned ISOs. GroundZero turns that into one repeatable, API-driven run:README 전문 보기 ↗Building a Holodeck lab usually means an evening of iDRAC consoles, hand-edited kickstarts and re-burned ISOs. GroundZero turns that into one repeatable, API-driven run:
/api/v1, OpenAPI at /docs) does all the work. The CLI,
the web UI and your automation are clients of that same API.flowchart LR
subgraph Inputs
ISO[("Image repository<br/><sub>stock ISOs and OVAs you download</sub>")]
CS["Config set<br/><sub>network · disk rule · NTP · CPU override</sub>"]
HV["Per-server values<br/><sub>hostname · IP · NIC overrides</sub>"]
end
BMC["BMC<br/><sub>Redfish</sub>"] --> PF["Preflight<br/><sub>read-only</sub>"]
ISO & CS & HV --> BUILD["Just-in-time ISO<br/><sub>kickstart + boot config</sub>"]
PF --> BUILD
BUILD --> MOUNT["Virtual media<br/>boot once · reset"]
MOUNT --> VAL["Validate<br/><sub>build · IP · VLAN · uplinks · NTP · datastores</sub>"]
VAL --> HD["Holodeck 9<br/><sub>host prep + deploy</sub>"]
classDef next stroke-dasharray: 5 5
class HD next
The image repository, config sets and hosts stay separate, and they are only merged at deploy time. A deploy preview shows the exact kickstart, with secrets masked, before anything touches the server.
| Milestone | Scope | State |
|---|---|---|
| M1 | API, job model, Redfish client, inventory, Holodeck 9 preflight | ✅ done |
| M2 | Unattended ESXi 9.x install via virtual media, with CPU override, VMFS preservation and post-install validation | ✅ done: ESXi 9.1.1 on a Dell R740xd |
| M2.5 | Config sets with capture from a running host, ISO repository, deploy preview, web UI, certificate pinning | ✅ done (UI refresh in progress) |
| M3 | Holodeck readiness, host prep (MTU 9000, port groups, NTP, datastore), jumbo-frame verification, Holorouter | ✅ done |
| M3.5 | Modular pipeline (typed inputs and outputs), any OVA deployed from its own inputs, appliance profiles, replace | ✅ done (v0.3.0) |
| M4 | Capture profiles from running appliances, adopt existing VMs, outputs with a source | ✅ done (v0.4.0) |
| M5 | Configure BIOS (VT-x, VT-d, UEFI boot mode) over Redfish | ✅ done (v0.5.0) |
| M5.5 | Cluster mode: names from the BMC, addresses from a pool, optional DNS check | ✅ done (v0.6.0) |
| M6 | The Holodeck deploy job (stage binaries, deploy) | ⏳ next |
| M7 | Windows guest customisation, NSX bare-metal Edge plugin, more OEM profiles | 📋 planned |
Setting it up for your own lab? Follow the step-by-step installation guide: prerequisites, network requirements, native or container install, and every step from preflight to the Holorouter.
Requires Python 3.12+ and uv.
uv sync
cp .env.example .env # lab credentials (git-ignored, never hard-coded)
uv run groundzero serve # API on http://127.0.0.1:7182 (+ TLS media server on :443)
uv run groundzero ui # open the web UI
Then, from another terminal:
# 1. Register the server and check it
uv run groundzero hosts add --bmc 10.0.0.50 --name r740xd # password is prompted
uv run groundzero preflight r740xd
# 2. Describe the OS you want: capture from a running host, or build one in the UI
uv run groundzero os set r740xd --address 192.0.2.101
uv run groundzero config capture r740xd --name lab-esxi
# 3. Drop stock ISOs into ./images, then install by filename or ISO id
# (the CLI previews the kickstart and asks for a typed confirmation)
uv run groundzero images list
uv run groundzero install r740xd --iso VMware-VMvisor-Installer-9.1.1.0.25714478.x86_64.iso --config lab-esxi \
--hostname esxi1 --ip 192.0.2.101
The REST API, the web UI, the install-media server and the SQLite state ship as one OCI image. It
runs with Podman (free and open source, Apache-2.0, with no Docker Desktop licence
needed). Colima or Rancher Desktop also work, with
GZ_ENGINE=docker.
brew install podman && podman machine init && podman machine start # one-time, macOS
scripts/gz-container build
scripts/gz-container up --bmc 198.51.100.11 # detects this machine's address on the route to the BMC
scripts/gz-container ui # open the UI, signed in
scripts/gz-container logs | status | token | shell | down
groundzero-data
volume and survives upgrades and restarts../images, mounted read-only.127.0.0.1:7182 only. The media server is published on
:443, so the BMC can fetch the install ISO.up works that address out from the route to the BMC. Run up again if the VPN
address changes, or set GROUNDZERO_MEDIA_PUBLIC_URL yourself.groundzero serve first, since they use the same ports, or set
GZ_API_PORT and GZ_MEDIA_PORT.To call the API directly, use the bearer token from uv run groundzero token show:
TOKEN=$(uv run groundzero token show)
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:7182/api/v1/hosts
| Area | Endpoints |
|---|---|
| Hosts | GET/POST /hosts, GET/DELETE /hosts/{id}, PUT/GET /hosts/{id}/os (how to reach the installed OS) |
| Tasks | GET /tasks (the catalog, with each task's parameter schema), GET /hosts/{id}/pipeline, POST /hosts/{id}/tasks/{task} |
| Outputs | GET /hosts/{id}/outputs, GET /hosts/{id}/outputs/{kind}: what each task produced, and the next task reads |
| Config | GET /os-families, GET/POST /config-sets, GET/PUT/DELETE /config-sets/{id}, GET/PUT /hosts/{id}/host-values/{family} |
| Images | GET /images, POST /images/rescan, GET /images/{id}/descriptor (an OVA's inputs, as a JSON Schema) |
| Install | POST /hosts/{id}/install/preview (the kickstart, before anything runs) |
| Trust | GET /hosts/{id}/certificates, POST /hosts/{id}/certificates/{role}/trust |
| Jobs | GET /jobs, GET /jobs/{id}, GET /jobs/{id}/events (SSE), POST /jobs/{id}/cancel |
/api/v1. /healthz is unauthenticated.application/problem+json.202 and a Job. Each host can run only one job at a time.~/.groundzero/ (SQLite, the API token and the encryption
key). Override the location with GROUNDZERO_HOME.| Concern | How it's handled |
|---|---|
| Credentials at rest | Fernet-encrypted in SQLite. Write-only through the API: responses show has_root_password, never the value. |
| Credentials in transit | TLS certificates are pinned on first use per host and role (bmc, os). After a legitimate change (a reinstall, a renewed certificate), re-trust with groundzero hosts trust HOST bmc|os. |
| Install media | Built per job, served from an unguessable URL that expires, logged per request, and always deleted afterwards. |
| Destructive actions | Installs need a typed confirmation. VMFS is preserved unless wipe_install_disk_vmfs is set. |
| Secrets in the repo | None. Lab credentials live only in the git-ignored .env. |
Functional testing is a first-class requirement. Every feature ships with tests at several levels:
| Level | What it exercises | Command |
|---|---|---|
| Unit / contract | Pure logic, OpenAPI snapshot, problem+json errors | uv run pytest |
| Functional | The real groundzero serve process and CLI over HTTP, against a simulated R740xd and ESXi | part of uv run pytest |
| Browser | The web UI in headless Chromium (Playwright) | uv run pytest -m browser |
| Live | The same workflows against real lab hardware, including a check that preflight made no changes | uv run pytest -m live (opt-in) |
| Container | Builds the image, runs it with a simulated BMC, and checks that state survives a restart and that it runs as non-root | uv run pytest -m container |
uv run ruff check . && uv run mypy && uv run pytest && uv run pytest -m browser # what CI runs
uv run pytest -m container # CI, separate job
GROUNDZERO_SIMULATE_BMC_DIR=<capture dir> groundzero serve. Inject faults
with GROUNDZERO_SIMULATE_FAULTS='["late-attach"]'. The available faults are ignore-boot-once,
slow-insert, late-attach, kickstart-error and os-unreachable.uv run groundzero dev capture --bmc 198.51.100.11 --out tests/fixtures/dell-r740xdUPDATE_SNAPSHOTS=1 uv run pytest tests/test_api.py.src/groundzero/
api/ FastAPI app, auth, problem+json errors, routers
core/ settings, models, SQLite store, jobs, services, TLS pinning
redfish/ async client, vendor detection, OEM profiles, capture/replay
inventory/ typed HostInventory + collector
preflight/ CPU support table, requirement profiles (TOML), evaluator
osconfig/ OS plugins (ESXi today; NSX bare-metal Edge next): settings schemas, capture, spec
install/ ISO builder, kickstart, media server, install job + validation
esxi/ vSphere API reads (network, storage, version probe)
simulator/ stateful Redfish BMC + ESXi with fault injection
web/ the web UI (plain HTML/CSS/JS, no build step)
cli/ Typer CLI (a thin API client) + dev tools
scripts/ gz-container: build/run the single-container bundle
docs/ installation guide, lab network and Holodeck host-network notes
tests/ unit, functional, browser and live suites; recorded fixtures
legacy/ the original VCF Readiness v9.7.3 code, kept for reference only
GroundZero began as a fork of the VCF Readiness Assessment Tool v9.7.3 by John Nicholson, and was rebuilt API-first around taking bare metal to a running VMware Holodeck.
legacy/: the original tool, kept for reference (license,
third-party licenses)src/groundzero/vcf_readiness/: the VCF 9 readiness rules (CPU
generation support tiers) carried over from it (license)See NOTICE for the details.
VMware, VCF, ESXi and Holodeck are trademarks of Broadcom. GroundZero is an independent project and is not affiliated with or endorsed by Broadcom.