From 83300b6c5ae1826c73fae78703f30dbada926a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= Date: Sat, 26 Sep 2026 09:34:57 +0900 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B7=D0=B5=D1=80=D0=B2=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=BA=D0=BE=D0=BF=D0=B8=D0=B8:=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D1=8E=D0=B4=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B4=D0=BD=D0=B5=D0=B3=D0=BE=20=D0=B2=D1=8B=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D1=8F=D0=B5=D1=82=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BC=D0=B5=D0=BD=D1=83=20=D0=BF=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=BF=D1=80=D0=BE=D1=81=D0=B0=20=D0=BC=D0=B0?= =?UTF-8?q?=D1=88=D0=B8=D0=BD=D1=8B=20=D0=B8=20=D0=BD=D0=B5=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=B0=D0=B5=D1=82=20=D0=B5=D1=91,=20?= =?UTF-8?q?=D0=B5=D1=81=D0=BB=D0=B8=20=C2=AB=D0=92=D1=8B=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D1=8C=C2=BB=20=D0=BD=D0=B0=D0=B6=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=B2=20=D1=8D=D1=82=D0=BE=D1=82=20=D0=BC=D0=BE=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_backups.py | 17 +++++++++++++++++ web/features/backups.py | 3 +++ 2 files changed, 20 insertions(+) diff --git a/tests/test_backups.py b/tests/test_backups.py index 4b5e7ec..943469c 100644 --- a/tests/test_backups.py +++ b/tests/test_backups.py @@ -643,3 +643,20 @@ def test_late_restart_watch_is_cancelled_by_user_action(fast_worker, monkeypatch watchers[0].join(timeout=5) assert not watchers[0].is_alive() and ["virsh", "start", "web01"] not in virsh.calls assert "Наблюдение снято" in core.read_operation(operation["id"])["log_tail"] + + +def test_late_restart_rechecks_cancel_after_shutdown(fast_worker, monkeypatch): + virsh = FakeVirsh(running=True, shuts_down=False) + monkeypatch.setattr(core, "run_cmd", virsh) + monkeypatch.setattr(backups, "LATE_SHUTDOWN_WATCH", 5.0) + operation = core.new_operation("backup", "Резервная копия web01", vm_name="web01") + + def shut_down_by_user(vm): + backups.cancel_late_restart(vm) # «Выключить» нажали, пока наблюдатель спрашивал состояние машины + return False + + monkeypatch.setattr(core, "vm_is_running", shut_down_by_user) + backups.restart_after_late_shutdown(operation, "web01") + assert ["virsh", "start", "web01"] not in virsh.calls + assert "Наблюдение снято" in core.read_operation(operation["id"])["log_tail"] + assert "web01" not in backups.LATE_WATCHES diff --git a/web/features/backups.py b/web/features/backups.py index e0a1a75..4c4e2a3 100644 --- a/web/features/backups.py +++ b/web/features/backups.py @@ -473,6 +473,9 @@ def restart_after_late_shutdown(operation: dict[str, Any], vm: str) -> None: core.append_operation_log(operation["id"], "Наблюдение снято: машиной занялись вручную или новой задачей.") return if not core.vm_is_running(vm): + if cancelled.is_set(): # «Выключить» нажали, пока virsh отвечал на вопрос о состоянии + core.append_operation_log(operation["id"], "Наблюдение снято: машиной занялись вручную или новой задачей.") + return if any(other["id"] != operation["id"] for other in core.active_operations_for(vm, OPERATION_TYPES)): core.append_operation_log(operation["id"], "Машина выключилась, но с ней уже работает другая задача — не запускаем.") return