|
13 | 13 | import signal |
14 | 14 | import socket |
15 | 15 | import subprocess |
| 16 | +import threading |
16 | 17 | import time |
17 | 18 | from pathlib import Path |
18 | 19 | from typing import Any, Dict, Optional, Tuple |
@@ -90,6 +91,7 @@ def ensure_console(self, vm_name: str) -> Dict[str, Any]: |
90 | 91 | } |
91 | 92 | self._write_state(vm_state_path, state) |
92 | 93 | logger.debug("VNC console state stored for %s: %s", vm_name, state) |
| 94 | + self._monitor_console(vm_name, state) |
93 | 95 | return self._response_payload(state) |
94 | 96 |
|
95 | 97 | def stop_console(self, vm_name: str) -> Dict[str, Any]: |
@@ -187,6 +189,28 @@ def _cleanup_state(self, state: Dict[str, Any]) -> None: |
187 | 189 | (self.state_dir / f"{vm_name}{suffix}").unlink(missing_ok=True) |
188 | 190 | except Exception: |
189 | 191 | pass |
| 192 | + def _monitor_console(self, vm_name: str, state: Dict[str, Any]) -> None: |
| 193 | + def _watch(): |
| 194 | + x11_pid = state.get("x11vnc_pid") |
| 195 | + if not x11_pid: |
| 196 | + return |
| 197 | + try: |
| 198 | + proc = psutil.Process(int(x11_pid)) |
| 199 | + proc.wait() |
| 200 | + except (psutil.NoSuchProcess, psutil.ZombieProcess, psutil.AccessDenied): |
| 201 | + pass |
| 202 | + except Exception as exc: |
| 203 | + logger.debug("Console watcher for %s encountered error: %s", vm_name, exc) |
| 204 | + finally: |
| 205 | + try: |
| 206 | + state_path = self._state_path(vm_name) |
| 207 | + if state_path.exists(): |
| 208 | + self.stop_console(vm_name) |
| 209 | + except Exception: |
| 210 | + logger.debug("Watcher cleanup for %s failed", vm_name, exc_info=True) |
| 211 | + |
| 212 | + thread = threading.Thread(target=_watch, name=f"fc-vnc-watch-{vm_name}", daemon=True) |
| 213 | + thread.start() |
190 | 214 |
|
191 | 215 | def _allocate_port(self) -> int: |
192 | 216 | family = socket.AF_INET6 if ":" in self.bind_host else socket.AF_INET |
@@ -317,7 +341,7 @@ def _start_x11vnc(self, vm_name: str, display: str, port: int, password_file: Pa |
317 | 341 | str(port), |
318 | 342 | "-rfbauth", |
319 | 343 | str(password_file), |
320 | | - "-forever", |
| 344 | + "-once", |
321 | 345 | "-shared", |
322 | 346 | "-noxdamage", |
323 | 347 | "-nolookup", |
|
0 commit comments