1import fcntl
2import os
3from pathlib import Path
4import shutil
5import subprocess
6import time
7
8
9def ensure_hub(vm_home):
10 root = vm_home / "run" / "lab"
11 socket_dir = root / "switch"
12 pidfile = root / "vde.pid"
13 root.mkdir(parents=True, exist_ok=True)
14 with (root / ".lock").open("a") as lock:
15 fcntl.flock(lock, fcntl.LOCK_EX)
16 try:
17 pid = int(pidfile.read_text())
18 os.kill(pid, 0)
19 if (socket_dir / "ctl").exists():
20 return socket_dir
21 except (FileNotFoundError, ProcessLookupError, ValueError):
22 pass
23 pidfile.unlink(missing_ok=True)
24 shutil.rmtree(socket_dir, ignore_errors=True)
25 executable = shutil.which("vde_switch") or "/opt/homebrew/bin/vde_switch"
26 if not Path(executable).is_file():
27 raise SystemExit("Install the Homebrew vde package for the VM lab network")
28 subprocess.run([
29 executable, "--daemon", "--nostdin", "--numports", "64",
30 "--sock", str(socket_dir), "--pidfile", str(pidfile),
31 "--dirmode", "0700", "--mode", "0600",
32 ], check=True)
33 for _ in range(50):
34 if pidfile.exists() and (socket_dir / "ctl").exists():
35 return socket_dir
36 time.sleep(0.1)
37 raise SystemExit("The VM lab network did not start")