refactor(cli): rename vmgui command to vmware
Rename the GUI launcher command from `vmgui` to `vmware` (`ci vmware ...`). Updates the click command name, function, log-file prefix, __main__ registration, tests and runbook references. Behaviour unchanged.
This commit is contained in:
@@ -69,7 +69,7 @@ The script defines two helpers:
|
||||
| `ci artifacts collect ...` | copy artifacts out of a guest | §4 |
|
||||
| `ci vm remove --vmx ...` | stop + delete one clone | §4 |
|
||||
| `ci vm cleanup` | sweep orphaned clones + stale locks | §4 / §6 |
|
||||
| `ci vmgui --vmx ...` | open a VMX in the VMware Workstation GUI | §4 |
|
||||
| `ci vmware --vmx ...` | open a VMX in the VMware Workstation GUI | §4 |
|
||||
| `ci creds set --user ...` | store guest credentials in keyring | §5 |
|
||||
| `ci template deploy-linux` | build the Linux template VM | §5 |
|
||||
| `ci template prepare-linux` | provision Linux template over SSH | §5 |
|
||||
@@ -217,19 +217,19 @@ Launches the **interactive** VMware Workstation GUI (not the headless vmrun path
|
||||
so you can watch/poke a clone by hand.
|
||||
|
||||
On a normal desktop session it just works — `sudo` already forwards `DISPLAY`,
|
||||
and `vmgui` behaves exactly like `sudo -u ci-runner vmware`:
|
||||
and `vmware` behaves exactly like `sudo -u ci-runner vmware`:
|
||||
```bash
|
||||
ci vmgui # bare GUI, no VM
|
||||
ci vmgui --vmx /var/lib/ci/build-vms/Clone_dbg-1_*/Clone_dbg-1_*.vmx
|
||||
ci vmgui --vmx <path> --power-on # power it on (-x)
|
||||
ci vmgui --vmx <path> --fullscreen # power on + fullscreen (-X)
|
||||
ci vmware # bare GUI, no VM
|
||||
ci vmware --vmx /var/lib/ci/build-vms/Clone_dbg-1_*/Clone_dbg-1_*.vmx
|
||||
ci vmware --vmx <path> --power-on # power it on (-x)
|
||||
ci vmware --vmx <path> --fullscreen # power on + fullscreen (-X)
|
||||
```
|
||||
Other flags: `--new-window` (`-n`), `--display :0` (force a display if `$DISPLAY`
|
||||
isn't forwarded), `--vmware-path`. Spawns detached; prints PID + log path.
|
||||
|
||||
**Why it works**: VMware connects via the X **host ACL**, not the cookie. The
|
||||
inherited `XAUTHORITY` (the desktop user's `~/.Xauthority`) is unreadable by
|
||||
ci-runner, so `vmgui` drops it and relies on the xhost grant — which is normally
|
||||
ci-runner, so `vmware` drops it and relies on the xhost grant — which is normally
|
||||
already present (`xhost` lists `SI:localuser:ci-runner`).
|
||||
|
||||
**Only if you get `cannot open X display`**: the grant is missing. Add it from
|
||||
@@ -237,8 +237,8 @@ the logged-in desktop user (not ci-runner):
|
||||
```bash
|
||||
xhost +SI:localuser:ci-runner
|
||||
```
|
||||
`vmgui` pre-flights the display (`xdpyinfo`) and prints this exact command on
|
||||
failure instead of dying silently; the GUI's output is captured in `/tmp/vmgui-*.log`.
|
||||
`vmware` pre-flights the display (`xdpyinfo`) and prints this exact command on
|
||||
failure instead of dying silently; the GUI's output is captured in `/tmp/vmware-*.log`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ from ci_orchestrator.commands.retention import retention
|
||||
from ci_orchestrator.commands.smoke import smoke
|
||||
from ci_orchestrator.commands.template import template
|
||||
from ci_orchestrator.commands.validate import validate
|
||||
from ci_orchestrator.commands.vm import vm, vmgui
|
||||
from ci_orchestrator.commands.vm import vm, vmware
|
||||
|
||||
# Re-export so legacy A1 tests that patched ``cli_module.<name>`` keep working.
|
||||
from ci_orchestrator.commands.wait import ( # noqa: F401 (intentional re-exports)
|
||||
@@ -54,7 +54,7 @@ cli.add_command(bench)
|
||||
cli.add_command(smoke)
|
||||
cli.add_command(validate)
|
||||
cli.add_command(creds)
|
||||
cli.add_command(vmgui)
|
||||
cli.add_command(vmware)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
@@ -534,7 +534,7 @@ def _launch_gui(argv: list[str], env: dict[str, str], log_path: Path) -> subproc
|
||||
)
|
||||
|
||||
|
||||
@click.command("vmgui")
|
||||
@click.command("vmware")
|
||||
@click.option(
|
||||
"--vmx",
|
||||
"--vm-path",
|
||||
@@ -575,7 +575,7 @@ def _launch_gui(argv: list[str], env: dict[str, str], log_path: Path) -> subproc
|
||||
default=None,
|
||||
help="X display to use (default: inherit $DISPLAY). e.g. ':0'.",
|
||||
)
|
||||
def vmgui(
|
||||
def vmware(
|
||||
vmx: str | None,
|
||||
vmware_path: str,
|
||||
power_on: bool,
|
||||
@@ -619,7 +619,7 @@ def vmgui(
|
||||
if xauth and not os.access(xauth, os.R_OK):
|
||||
env.pop("XAUTHORITY", None)
|
||||
click.echo(
|
||||
f"[vmgui] dropping unreadable XAUTHORITY ({xauth}); relying on xhost.",
|
||||
f"[vmware] dropping unreadable XAUTHORITY ({xauth}); relying on xhost.",
|
||||
err=True,
|
||||
)
|
||||
|
||||
@@ -644,14 +644,14 @@ def vmgui(
|
||||
argv.append(str(vmx_path))
|
||||
elif power_on or fullscreen:
|
||||
click.echo(
|
||||
"[vmgui] note: --power-on/--fullscreen ignored without --vmx.",
|
||||
"[vmware] note: --power-on/--fullscreen ignored without --vmx.",
|
||||
err=True,
|
||||
)
|
||||
|
||||
ts = datetime.now(tz=UTC).strftime("%Y%m%d-%H%M%S")
|
||||
log_path = Path(tempfile.gettempdir()) / f"vmgui-{os.getpid()}-{ts}.log"
|
||||
log_path = Path(tempfile.gettempdir()) / f"vmware-{os.getpid()}-{ts}.log"
|
||||
|
||||
click.echo(f"[vmgui] launching VMware GUI: {' '.join(argv)}")
|
||||
click.echo(f"[vmware] launching VMware GUI: {' '.join(argv)}")
|
||||
try:
|
||||
proc = _launch_gui(argv, env, log_path)
|
||||
except (OSError, ValueError) as exc:
|
||||
@@ -672,8 +672,8 @@ def vmgui(
|
||||
)
|
||||
|
||||
click.echo(
|
||||
f"[vmgui] VMware GUI started (pid {proc.pid}); display={disp}; log={log_path}"
|
||||
f"[vmware] VMware GUI started (pid {proc.pid}); display={disp}; log={log_path}"
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["cleanup_orphans", "vm", "vmgui"]
|
||||
__all__ = ["cleanup_orphans", "vm", "vmware"]
|
||||
|
||||
@@ -499,11 +499,11 @@ def test_vm_cleanup_backend_unavailable(monkeypatch: pytest.MonkeyPatch, tmp_pat
|
||||
assert "vmrun not available" in result.output
|
||||
|
||||
|
||||
# ── vmgui ───────────────────────────────────────────────────────────────────
|
||||
# ── vmware ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class _FakeProc:
|
||||
"""Minimal subprocess.Popen stand-in for vmgui tests."""
|
||||
"""Minimal subprocess.Popen stand-in for vmware GUI tests."""
|
||||
|
||||
def __init__(self, pid: int = 4242, rc: int | None = None) -> None:
|
||||
self.pid = pid
|
||||
@@ -533,68 +533,68 @@ def _capture_launch(
|
||||
return captured
|
||||
|
||||
|
||||
def test_vmgui_missing_vmx_errors(tmp_path: Path) -> None:
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(tmp_path / "nope.vmx")])
|
||||
def test_vmware_missing_vmx_errors(tmp_path: Path) -> None:
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(tmp_path / "nope.vmx")])
|
||||
assert result.exit_code != 0
|
||||
assert "VMX file not found" in result.output
|
||||
|
||||
|
||||
def test_vmgui_happy_path(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_happy_path(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert cap["argv"][-1] == str(vmx)
|
||||
assert "-x" not in cap["argv"] and "-X" not in cap["argv"]
|
||||
assert "pid 4242" in result.output
|
||||
|
||||
|
||||
def test_vmgui_power_on_adds_x(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_power_on_adds_x(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx), "--power-on"])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx), "--power-on"])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "-x" in cap["argv"]
|
||||
|
||||
|
||||
def test_vmgui_fullscreen_adds_capital_x(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_fullscreen_adds_capital_x(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(
|
||||
cli, ["vmgui", "--vmx", str(vmx), "--fullscreen", "--new-window"]
|
||||
cli, ["vmware", "--vmx", str(vmx), "--fullscreen", "--new-window"]
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "-X" in cap["argv"] and "-n" in cap["argv"]
|
||||
|
||||
|
||||
def test_vmgui_display_option_overrides_env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_display_option_overrides_env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.delenv("DISPLAY", raising=False)
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx), "--display", ":1"])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx), "--display", ":1"])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert cap["env"]["DISPLAY"] == ":1"
|
||||
assert "display=:1" in result.output
|
||||
|
||||
|
||||
def test_vmgui_errors_without_display(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_errors_without_display(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
_capture_launch(monkeypatch)
|
||||
monkeypatch.delenv("DISPLAY", raising=False)
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code != 0
|
||||
assert "no X display" in result.output
|
||||
|
||||
|
||||
def test_vmgui_preflight_failure_reports_xhost(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_preflight_failure_reports_xhost(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
_capture_launch(monkeypatch)
|
||||
@@ -603,35 +603,35 @@ def test_vmgui_preflight_failure_reports_xhost(monkeypatch: pytest.MonkeyPatch,
|
||||
vm_module, "_x_display_reachable", lambda _env: (False, "cannot open display :0")
|
||||
)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code != 0
|
||||
assert "xhost +SI:localuser:ci-runner" in result.output
|
||||
|
||||
|
||||
def test_vmgui_drops_unreadable_xauthority(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_drops_unreadable_xauthority(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
monkeypatch.setenv("XAUTHORITY", str(tmp_path / "missing.Xauthority"))
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "XAUTHORITY" not in cap["env"]
|
||||
assert "dropping unreadable XAUTHORITY" in result.output
|
||||
|
||||
|
||||
def test_vmgui_immediate_exit_surfaces_log(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_immediate_exit_surfaces_log(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
_capture_launch(monkeypatch, rc=1)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code != 0
|
||||
assert "exited immediately" in result.output
|
||||
assert "cannot open display" in result.output
|
||||
|
||||
|
||||
def test_vmgui_launch_oserror_is_reported(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
def test_vmware_launch_oserror_is_reported(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
vmx = tmp_path / "clone.vmx"
|
||||
vmx.write_text("config")
|
||||
|
||||
@@ -642,25 +642,25 @@ def test_vmgui_launch_oserror_is_reported(monkeypatch: pytest.MonkeyPatch, tmp_p
|
||||
monkeypatch.setattr(vm_module, "_x_display_reachable", lambda _env: (True, ""))
|
||||
monkeypatch.setattr(vm_module.time, "sleep", lambda _s: None)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--vmx", str(vmx)])
|
||||
assert result.exit_code != 0
|
||||
assert "failed to launch VMware GUI" in result.output
|
||||
|
||||
|
||||
def test_vmgui_without_vmx_launches_bare_gui(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_vmware_without_vmx_launches_bare_gui(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui"])
|
||||
result = CliRunner().invoke(cli, ["vmware"])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert cap["argv"][1:] == [] or cap["argv"][1:] == ["-n"]
|
||||
assert "-x" not in cap["argv"] and "-X" not in cap["argv"]
|
||||
assert "pid 4242" in result.output
|
||||
|
||||
|
||||
def test_vmgui_power_on_ignored_without_vmx(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_vmware_power_on_ignored_without_vmx(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
cap = _capture_launch(monkeypatch)
|
||||
monkeypatch.setenv("DISPLAY", ":0")
|
||||
result = CliRunner().invoke(cli, ["vmgui", "--power-on"])
|
||||
result = CliRunner().invoke(cli, ["vmware", "--power-on"])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "-x" not in cap["argv"]
|
||||
assert "ignored without --vmx" in result.output
|
||||
|
||||
Reference in New Issue
Block a user