# pve-vm-setup

Textual TUI for creating Proxmox VMs with live reference data, guarded create controls, and a guided multi-step wizard.

## What it does

- logs into a Proxmox VE API endpoint
- loads nodes, pools, storages, bridges, tags, and ISO images from the live cluster
- walks through VM creation in a step-by-step wizard
- can run in a safe read-only mode, a normal live-create mode, or a restricted test mode

## Commands

- Run directly from this repo (without cloning): `uvx git+https://git.s1q.dev/phg/pve-vm-setup.git`
- Install dependencies: `uv sync`
- Run the app from the checkout repository: `uv run -m pve_vm_setup`
- Run live diagnostics: `uv run -m pve_vm_setup --doctor-live`
- Run tests: `uv run pytest`
- Run read-only live tests: `uv run pytest -m live`
- Run live create tests: `uv run pytest -m live_create`
- Lint: `uv run ruff check .`
- Format: `uv run ruff format .`

## Typical usage

1. Copy `.env.example` to `~/.config/pve-vm-setup/.env` or `.env`.
2. Fill in the Proxmox connection settings.
3. Decide whether this machine should be allowed to create VMs at all.
4. Optionally enable test mode if you want live creates restricted to a known node/pool and auto-tagged.
5. Start the app with `uv run python -m pve_vm_setup`.
6. Log in and complete the wizard.

Before the final create request, the app asks whether the VM should be started automatically after creation.

## Operating modes

### Read-only mode

Use this when you want to browse live data and validate the setup without creating anything.

- Set `PROXMOX_PREVENT_CREATE=true`
- Recommended for first-time setup
- `--doctor-live` is useful here

### Normal live-create mode

Use this when you want to create real VMs without the extra test-mode restrictions.

- Set `PROXMOX_PREVENT_CREATE=false` or leave it unset
- Leave `PROXMOX_ENABLE_TEST_MODE=false`
- Recommended only when you are comfortable with the target cluster and defaults

### Restricted test mode

Use this when you want live creates, but only inside a constrained sandbox.

- Set `PROXMOX_PREVENT_CREATE=false`
- Set `PROXMOX_ENABLE_TEST_MODE=true`
- `PROXMOX_TEST_NODE`, `PROXMOX_TEST_POOL`, `PROXMOX_TEST_TAG`, and `PROXMOX_TEST_VM_NAME_PREFIX` become required
- The app restricts creates to the configured node and pool
- The app automatically adds the configured tag and name prefix

## Environment variables

Start from `.env.example`. The table below describes every supported variable that is currently parsed by the app.

Configuration source order:

1. Process environment variables
2. `~/.config/pve-vm-setup/.env`
3. `.env` in the current working directory

Higher entries override lower ones.

| Variable | Required | Default | Recommended | Purpose |
| --- | --- | --- | --- | --- |
| `PROXMOX_URL` | Required for live access | none | Yes | Base Proxmox URL, for example `https://pve.example.com:8006`. This is the only setting required to make the interactive app use the real Proxmox backend instead of fake mode. |
| `PROXMOX_REALM` | Optional | none | Recommended | Default realm for login. If unset, the login view loads realms from Proxmox and lets you choose one manually. Still required for non-interactive doctor login checks. |
| `PROXMOX_USER` | Optional | none | Recommended | Default username shown in the login form. If unset, you can type it manually. Still required for non-interactive doctor login checks. |
| `PROXMOX_PASSWORD` | Optional | none | Usually no | Default password shown in the login form. If unset, you can type it manually. Still required for non-interactive doctor login checks. |
| `PROXMOX_VERIFY_TLS` | Optional | `false` | Yes, if your certificates are valid | Controls TLS certificate verification for API calls. Set to `true` for properly trusted certificates. Set to `false` only for internal or self-signed setups you explicitly trust. |
| `PROXMOX_API_BASE` | Optional | `/api2/json` | Usually leave as-is | API base path appended to `PROXMOX_URL`. Only change this if your deployment needs a different base path. |
| `PROXMOX_REQUEST_TIMEOUT_SECONDS` | Optional | `15` | Usually yes | Request timeout used for API calls and task polling. Increase it if your environment is slow. |
| `PROXMOX_DEFAULT_ISO_SELECTOR` | Optional | unset | Optional | Controls which ISO image is auto-selected in the OS step. Uses glob matching by default. If prefixed with `regex:`, the remainder is treated as a regular expression. |
| `PROXMOX_PREVENT_CREATE` | Optional | `false` | Yes | Global create safety switch. Set to `true` to block VM creation completely. Leave unset or set to `false` to allow creates. |
| `PROXMOX_ENABLE_TEST_MODE` | Optional | `false` | Yes for shared or risky environments | Enables restricted live-create mode. When enabled, the `PROXMOX_TEST_*` scope settings become mandatory. |
| `PROXMOX_TEST_NODE` | Required only in test mode | none | Yes in test mode | Node that live creates are restricted to. |
| `PROXMOX_TEST_POOL` | Required only in test mode | none | Yes in test mode | Pool that live creates are restricted to. |
| `PROXMOX_TEST_TAG` | Required only in test mode | `codex-e2e` | Yes in test mode | Tag added automatically to created VMs in test mode. |
| `PROXMOX_TEST_VM_NAME_PREFIX` | Required only in test mode | `codex-e2e-` | Yes in test mode | Prefix added automatically to VM names in test mode. |
| `PROXMOX_KEEP_FAILED_VM` | Optional | `true` | Leave as-is for now | Parsed by settings, but currently not acted on by the create workflow yet. Treat it as reserved for future cleanup behavior. |

## ISO selector syntax

`PROXMOX_DEFAULT_ISO_SELECTOR` supports two forms:

- Glob syntax, used by default
- Regex syntax, enabled with a `regex:` prefix

Examples:

- `PROXMOX_DEFAULT_ISO_SELECTOR=*ubuntu*`
- `PROXMOX_DEFAULT_ISO_SELECTOR=*debian-12*`
- `PROXMOX_DEFAULT_ISO_SELECTOR=regex:nixos-minimal-\d{2}\.\d{2}\..*-x86_64-linux\.iso$`

Behavior:

- if the selector matches one or more ISOs, the app picks from those matches
- if multiple matching NixOS-style ISOs exist, it prefers the latest one by release naming
- if nothing matches, the app falls back to the built-in default picker

## Recommended `.env` setups

### Safe initial setup

```dotenv
PROXMOX_URL=https://pve.example.com:8006
PROXMOX_REALM=pam
PROXMOX_USER=root
PROXMOX_PASSWORD=replace-me
PROXMOX_VERIFY_TLS=true
PROXMOX_PREVENT_CREATE=true
PROXMOX_ENABLE_TEST_MODE=false
```

### Normal live-create setup

```dotenv
PROXMOX_URL=https://pve.example.com:8006
PROXMOX_REALM=pam
PROXMOX_USER=root
PROXMOX_PASSWORD=replace-me
PROXMOX_VERIFY_TLS=true
PROXMOX_PREVENT_CREATE=false
PROXMOX_ENABLE_TEST_MODE=false
PROXMOX_DEFAULT_ISO_SELECTOR=*nixos*
```

### Restricted test setup

```dotenv
PROXMOX_URL=https://pve.example.com:8006
PROXMOX_REALM=pam
PROXMOX_USER=root
PROXMOX_PASSWORD=replace-me
PROXMOX_VERIFY_TLS=true
PROXMOX_PREVENT_CREATE=false
PROXMOX_ENABLE_TEST_MODE=true
PROXMOX_TEST_NODE=pve-test-01
PROXMOX_TEST_POOL=sandbox
PROXMOX_TEST_TAG=codex-e2e
PROXMOX_TEST_VM_NAME_PREFIX=codex-e2e-
```

## Notes and caveats

- Interactive live access only requires `PROXMOX_URL`.
- `PROXMOX_USER`, `PROXMOX_PASSWORD`, and `PROXMOX_REALM` act as login defaults for the UI.
- `--doctor-live` still requires `PROXMOX_URL`, `PROXMOX_USER`, `PROXMOX_PASSWORD`, and `PROXMOX_REALM` because it performs a full non-interactive login.
- Test mode is not the same as read-only mode. Test mode still performs real creates when creation is allowed.
- If `PROXMOX_PREVENT_CREATE=true`, the confirm step validates but actual creation is blocked.
- `PROXMOX_TEST_POOL` is currently required when test mode is enabled.
- `PROXMOX_KEEP_FAILED_VM` is currently reserved and not yet implemented in the workflow logic.

## Live diagnostics

Run:

```bash
uv run python -m pve_vm_setup --doctor-live
```

This verifies:

- transport reachability
- API base access
- visible nodes
- configured test node and pool, when test mode is enabled

Use this before enabling creates against a real cluster.

## Engineering rules

- Write tests before implementation
- Prefer small PR-sized tasks
- Keep business logic out of widgets where possible
- Field-like widgets should default to compact 3-row controls with no empty spacer line between the value row and the border
- Every screen must have empty/loading/error coverage
- Every interactive feature needs at least one Pilot test
- Visual changes should be covered by snapshot tests
