From a6367e55ae38b6b8cbaf108fa1cfe8768afd5188 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 13 Oct 2026 04:11:42 +0300 Subject: [PATCH] fix: tolerate QMP socket removal during status probes --- hydra/runtime.py | 6 ++++-- tests/test_runtime.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hydra/runtime.py b/hydra/runtime.py index 57a6962..5ea7ea8 100644 --- a/hydra/runtime.py +++ b/hydra/runtime.py @@ -182,9 +182,11 @@ class Runtime: raise RuntimeError(f'Cannot verify VM identity: {exc}') from exc def _listening(self, path: Path) -> bool: - if not path.exists(): + try: + mode = path.lstat().st_mode + except FileNotFoundError: return False - if not stat.S_ISSOCK(path.lstat().st_mode): + if not stat.S_ISSOCK(mode): raise RuntimeError(f'Refusing non-socket runtime path: {path}') with socket.socket(socket.AF_UNIX) as probe: probe.settimeout(min(1, self.boot_timeout)) diff --git a/tests/test_runtime.py b/tests/test_runtime.py index 40a27d3..6a86c0f 100644 --- a/tests/test_runtime.py +++ b/tests/test_runtime.py @@ -105,6 +105,19 @@ class RuntimeTests(unittest.TestCase): self.assertNotIn('-vnc', argv) self.assertNotIn('-virtfs', argv) + def test_socket_removed_during_stat_is_safely_not_listening(self): + paths = self.runtime.paths('guest') + paths.qmp.parent.mkdir(parents=True) + with socket.socket(socket.AF_UNIX) as fixture: + fixture.bind(str(paths.qmp)) + original_lstat = Path.lstat + def disappearing_socket(path): + if path == paths.qmp: + path.unlink(missing_ok=True) + return original_lstat(path) + with patch.object(Path, 'lstat', disappearing_socket): + self.assertFalse(self.runtime._listening(paths.qmp)) + def test_argv_provides_audio_and_manual_usb_channels(self): argv = build_qemu_argv(self.profile, self.runtime.paths('guest')) self.assertIn('spice,id=audio', argv)