feat: restart the host (reboot_host)
netOrk asks a driver for reboot_host before it offers a restart, and the Linux driver had none, so a Linux host -- and OpenMediaVault and QTS, which inherit this driver -- could not be restarted from netOrk at all (netOrk #637). reboot_host runs /sbin/reboot detached and two seconds late through _run_privileged: the launcher's exit status comes back before the host goes down, and closing the session cannot take the restart with it. A refusal (sudo without a password) raises with what the host said.
This commit is contained in:
@@ -1517,3 +1517,41 @@ class TestTerminalCodes:
|
||||
driver._device.send_command.side_effect = ["0", "Hit:1 noble InRelease\n\x1b>__NETORK_RC=0"]
|
||||
|
||||
assert driver.refresh_available_updates()["success"] is True
|
||||
|
||||
|
||||
class TestRebootHost:
|
||||
"""``reboot_host`` (napalm-device-types' ``HostRebootMixin``) restarts the host.
|
||||
|
||||
Without it netOrk could not restart a Linux host at all: its capability check
|
||||
looks for ``reboot_host`` and found nothing (netOrk #637). The restart is
|
||||
detached and a moment late, so the launcher's exit status comes back before
|
||||
the host goes down, and closing the session cannot take it along.
|
||||
"""
|
||||
|
||||
def test_the_driver_can_restart_its_host(self):
|
||||
assert callable(getattr(LinuxDriver, "reboot_host", None))
|
||||
|
||||
def test_the_restart_is_detached_and_privileged(self, driver):
|
||||
driver._root = False
|
||||
driver._device.send_command.return_value = "\n__NETORK_RC=0"
|
||||
|
||||
driver.reboot_host()
|
||||
|
||||
sent = driver._device.send_command.call_args[0][0]
|
||||
assert sent.startswith("sudo -n sh -c ")
|
||||
assert "/sbin/reboot" in sent and "trap" in sent and "&" in sent
|
||||
assert sent.endswith("echo __NETORK_RC=$?")
|
||||
|
||||
def test_a_refusal_is_raised_with_what_the_host_said(self, driver):
|
||||
driver._root = False
|
||||
driver._device.send_command.return_value = "sudo: a password is required\n__NETORK_RC=1"
|
||||
|
||||
with pytest.raises(RuntimeError, match="password is required"):
|
||||
driver.reboot_host()
|
||||
|
||||
def test_no_exit_status_is_no_success(self, driver):
|
||||
driver._root = True
|
||||
driver._device.send_command.return_value = "something else"
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
driver.reboot_host()
|
||||
|
||||
Reference in New Issue
Block a user