driver / standard (pull_request) Successful in 14s
driver / lint (pull_request) Successful in 11s
driver / types (pull_request) Successful in 1m2s
driver / test (3.10) (pull_request) Successful in 1m9s
driver / test (3.11) (pull_request) Successful in 1m8s
driver / lowest (pull_request) Successful in 34s
driver / test (3.12) (pull_request) Successful in 1m3s
driver / test (3.13) (pull_request) Successful in 1m0s
driver / build (pull_request) Successful in 26s
driver / security (pull_request) Successful in 1m1s
CI / driver (pull_request) Successful in 3m17s
driver / publish (pull_request) Skipped
shutdown_host() posts command=shutdown to the node itself; its guests stop as on any shutdown. begin_stop_vm(name) asks a guest for its clean shutdown and returns once Proxmox took it, without waiting for the task: the caller reads get_vm_status until it stopped. Both raise RuntimeError when Proxmox refuses; an unknown guest is a ValueError. The contracts HostShutdownMixin and VmStopRequestMixin of napalm-device-types (NAPALM/napalm-device-types#55); for netOrk's graph workflows (NetOrk/netork#1636).
75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
"""shutdown_host and begin_stop_vm: shutting down without waiting.
|
|
|
|
Through the API, never over SSH: ``shutdown_host`` asks the node to shut
|
|
itself down, ``begin_stop_vm`` asks a guest for its clean (ACPI) shutdown and
|
|
returns once Proxmox accepted it — the caller reads ``get_vm_status`` until it
|
|
stopped (NetOrk/netork#1636). Neither waits for a task.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
|
|
def test_shutdown_host_posts_shutdown_to_the_node(driver):
|
|
driver.shutdown_host()
|
|
|
|
driver._node_api().status.post.assert_called_once_with(command="shutdown")
|
|
|
|
|
|
def test_a_refused_shutdown_is_a_runtime_error(driver):
|
|
driver._node_api().status.post.side_effect = Exception("Permission check failed")
|
|
|
|
with pytest.raises(RuntimeError, match="Permission check failed"):
|
|
driver.shutdown_host()
|
|
|
|
|
|
def _guests(driver, qemu, lxc=()):
|
|
node = driver._node_api()
|
|
node.qemu.get.return_value = list(qemu)
|
|
node.lxc.get.return_value = list(lxc)
|
|
return node
|
|
|
|
|
|
def test_begin_stop_vm_asks_for_a_clean_shutdown_and_does_not_wait(driver, monkeypatch):
|
|
node = _guests(driver, [{"vmid": 650, "name": "build-01"}])
|
|
waited = []
|
|
monkeypatch.setattr(driver, "_wait_for_task", lambda *a, **k: waited.append(a), raising=False)
|
|
|
|
driver.begin_stop_vm("650")
|
|
|
|
node.qemu.assert_called_with(650)
|
|
node.qemu(650).status.shutdown.post.assert_called_once_with()
|
|
assert waited == []
|
|
|
|
|
|
def test_begin_stop_vm_finds_a_guest_by_name(driver):
|
|
node = _guests(driver, [{"vmid": 650, "name": "build-01"}])
|
|
|
|
driver.begin_stop_vm("build-01")
|
|
|
|
node.qemu(650).status.shutdown.post.assert_called_once_with()
|
|
|
|
|
|
def test_begin_stop_vm_of_a_container(driver):
|
|
node = _guests(driver, [], [{"vmid": 700, "name": "ct"}])
|
|
|
|
driver.begin_stop_vm("700")
|
|
|
|
node.lxc(700).status.shutdown.post.assert_called_once_with()
|
|
|
|
|
|
def test_an_unknown_guest_is_a_value_error(driver):
|
|
_guests(driver, [])
|
|
|
|
with pytest.raises(ValueError):
|
|
driver.begin_stop_vm("999")
|
|
|
|
|
|
def test_a_refused_request_is_a_runtime_error(driver):
|
|
node = _guests(driver, [{"vmid": 650, "name": "build-01"}])
|
|
node.qemu(650).status.shutdown.post.side_effect = Exception("VM is locked")
|
|
|
|
with pytest.raises(RuntimeError, match="VM is locked"):
|
|
driver.begin_stop_vm("650")
|