mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-16 05:36:29 +00:00
Add start transient unit dbus method (#4237)
This commit is contained in:
parent
f5b6feec77
commit
dc4a753fe3
@ -315,3 +315,22 @@ class ResolvConfMode(str, Enum):
|
|||||||
STATIC = "static"
|
STATIC = "static"
|
||||||
STUB = "stub"
|
STUB = "stub"
|
||||||
UPLINK = "uplink"
|
UPLINK = "uplink"
|
||||||
|
|
||||||
|
|
||||||
|
class StopUnitMode(str, Enum):
|
||||||
|
"""Mode for stopping the unit."""
|
||||||
|
|
||||||
|
REPLACE = "replace"
|
||||||
|
FAIL = "fail"
|
||||||
|
IGNORE_DEPENDENCIES = "ignore-dependencies"
|
||||||
|
IGNORE_REQUIREMENTS = "ignore-requirements"
|
||||||
|
|
||||||
|
|
||||||
|
class StartUnitMode(str, Enum):
|
||||||
|
"""Mode for starting the unit."""
|
||||||
|
|
||||||
|
REPLACE = "replace"
|
||||||
|
FAIL = "fail"
|
||||||
|
IGNORE_DEPENDENCIES = "ignore-dependencies"
|
||||||
|
IGNORE_REQUIREMENTS = "ignore-requirements"
|
||||||
|
ISOLATE = "isolate"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Interface to Systemd over D-Bus."""
|
"""Interface to Systemd over D-Bus."""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from dbus_fast import Variant
|
||||||
from dbus_fast.aio.message_bus import MessageBus
|
from dbus_fast.aio.message_bus import MessageBus
|
||||||
|
|
||||||
from ..exceptions import DBusError, DBusInterfaceError
|
from ..exceptions import DBusError, DBusInterfaceError
|
||||||
@ -13,6 +14,8 @@ from .const import (
|
|||||||
DBUS_IFACE_SYSTEMD_MANAGER,
|
DBUS_IFACE_SYSTEMD_MANAGER,
|
||||||
DBUS_NAME_SYSTEMD,
|
DBUS_NAME_SYSTEMD,
|
||||||
DBUS_OBJECT_SYSTEMD,
|
DBUS_OBJECT_SYSTEMD,
|
||||||
|
StartUnitMode,
|
||||||
|
StopUnitMode,
|
||||||
)
|
)
|
||||||
from .interface import DBusInterfaceProxy, dbus_property
|
from .interface import DBusInterfaceProxy, dbus_property
|
||||||
from .utils import dbus_connected
|
from .utils import dbus_connected
|
||||||
@ -73,24 +76,24 @@ class Systemd(DBusInterfaceProxy):
|
|||||||
await self.dbus.Manager.call_power_off()
|
await self.dbus.Manager.call_power_off()
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def start_unit(self, unit, mode) -> str:
|
async def start_unit(self, unit: str, mode: StartUnitMode) -> str:
|
||||||
"""Start a systemd service unit. Returns object path of job."""
|
"""Start a systemd service unit. Returns object path of job."""
|
||||||
return await self.dbus.Manager.call_start_unit(unit, mode)
|
return await self.dbus.Manager.call_start_unit(unit, mode.value)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def stop_unit(self, unit, mode) -> str:
|
async def stop_unit(self, unit: str, mode: StopUnitMode) -> str:
|
||||||
"""Stop a systemd service unit. Returns object path of job."""
|
"""Stop a systemd service unit. Returns object path of job."""
|
||||||
return await self.dbus.Manager.call_stop_unit(unit, mode)
|
return await self.dbus.Manager.call_stop_unit(unit, mode.value)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def reload_unit(self, unit, mode) -> str:
|
async def reload_unit(self, unit: str, mode: StartUnitMode) -> str:
|
||||||
"""Reload a systemd service unit. Returns object path of job."""
|
"""Reload a systemd service unit. Returns object path of job."""
|
||||||
return await self.dbus.Manager.call_reload_or_restart_unit(unit, mode)
|
return await self.dbus.Manager.call_reload_or_restart_unit(unit, mode.value)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def restart_unit(self, unit, mode) -> str:
|
async def restart_unit(self, unit: str, mode: StartUnitMode) -> str:
|
||||||
"""Restart a systemd service unit. Returns object path of job."""
|
"""Restart a systemd service unit. Returns object path of job."""
|
||||||
return await self.dbus.Manager.call_restart_unit(unit, mode)
|
return await self.dbus.Manager.call_restart_unit(unit, mode.value)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def list_units(
|
async def list_units(
|
||||||
@ -98,3 +101,12 @@ class Systemd(DBusInterfaceProxy):
|
|||||||
) -> list[tuple[str, str, str, str, str, str, str, int, str, str]]:
|
) -> list[tuple[str, str, str, str, str, str, str, int, str, str]]:
|
||||||
"""Return a list of available systemd services."""
|
"""Return a list of available systemd services."""
|
||||||
return await self.dbus.Manager.call_list_units()
|
return await self.dbus.Manager.call_list_units()
|
||||||
|
|
||||||
|
@dbus_connected
|
||||||
|
async def start_transient_unit(
|
||||||
|
self, unit: str, mode: StartUnitMode, properties: list[tuple[str, Variant]]
|
||||||
|
) -> str:
|
||||||
|
"""Start a transient unit which is released when stopped or on reboot. Returns object path of job."""
|
||||||
|
return await self.dbus.Manager.call_start_transient_unit(
|
||||||
|
unit, mode.value, properties, []
|
||||||
|
)
|
||||||
|
@ -5,6 +5,7 @@ import logging
|
|||||||
import attr
|
import attr
|
||||||
|
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
|
from ..dbus.const import StartUnitMode, StopUnitMode
|
||||||
from ..exceptions import HassioError, HostNotSupportedError, HostServiceError
|
from ..exceptions import HassioError, HostNotSupportedError, HostServiceError
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
@ -42,7 +43,7 @@ class ServiceManager(CoreSysAttributes):
|
|||||||
self._check_dbus(unit)
|
self._check_dbus(unit)
|
||||||
|
|
||||||
_LOGGER.info("Starting local service %s", unit)
|
_LOGGER.info("Starting local service %s", unit)
|
||||||
return self.sys_dbus.systemd.start_unit(unit, MOD_REPLACE)
|
return self.sys_dbus.systemd.start_unit(unit, StartUnitMode.REPLACE)
|
||||||
|
|
||||||
def stop(self, unit) -> Awaitable[str]:
|
def stop(self, unit) -> Awaitable[str]:
|
||||||
"""Stop a service on host.
|
"""Stop a service on host.
|
||||||
@ -52,7 +53,7 @@ class ServiceManager(CoreSysAttributes):
|
|||||||
self._check_dbus(unit)
|
self._check_dbus(unit)
|
||||||
|
|
||||||
_LOGGER.info("Stopping local service %s", unit)
|
_LOGGER.info("Stopping local service %s", unit)
|
||||||
return self.sys_dbus.systemd.stop_unit(unit, MOD_REPLACE)
|
return self.sys_dbus.systemd.stop_unit(unit, StopUnitMode.REPLACE)
|
||||||
|
|
||||||
def reload(self, unit) -> Awaitable[str]:
|
def reload(self, unit) -> Awaitable[str]:
|
||||||
"""Reload a service on host.
|
"""Reload a service on host.
|
||||||
@ -62,7 +63,7 @@ class ServiceManager(CoreSysAttributes):
|
|||||||
self._check_dbus(unit)
|
self._check_dbus(unit)
|
||||||
|
|
||||||
_LOGGER.info("Reloading local service %s", unit)
|
_LOGGER.info("Reloading local service %s", unit)
|
||||||
return self.sys_dbus.systemd.reload_unit(unit, MOD_REPLACE)
|
return self.sys_dbus.systemd.reload_unit(unit, StartUnitMode.REPLACE)
|
||||||
|
|
||||||
def restart(self, unit) -> Awaitable[str]:
|
def restart(self, unit) -> Awaitable[str]:
|
||||||
"""Restart a service on host.
|
"""Restart a service on host.
|
||||||
@ -72,7 +73,7 @@ class ServiceManager(CoreSysAttributes):
|
|||||||
self._check_dbus(unit)
|
self._check_dbus(unit)
|
||||||
|
|
||||||
_LOGGER.info("Restarting local service %s", unit)
|
_LOGGER.info("Restarting local service %s", unit)
|
||||||
return self.sys_dbus.systemd.restart_unit(unit, MOD_REPLACE)
|
return self.sys_dbus.systemd.restart_unit(unit, StartUnitMode.REPLACE)
|
||||||
|
|
||||||
def exists(self, unit) -> bool:
|
def exists(self, unit) -> bool:
|
||||||
"""Check if a unit exists and return True."""
|
"""Check if a unit exists and return True."""
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
"""Test hostname dbus interface."""
|
"""Test hostname dbus interface."""
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
|
from dbus_fast import Variant
|
||||||
from dbus_fast.aio.message_bus import MessageBus
|
from dbus_fast.aio.message_bus import MessageBus
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from supervisor.dbus.const import StartUnitMode, StopUnitMode
|
||||||
from supervisor.dbus.systemd import Systemd
|
from supervisor.dbus.systemd import Systemd
|
||||||
from supervisor.exceptions import DBusNotConnectedError
|
from supervisor.exceptions import DBusNotConnectedError
|
||||||
|
|
||||||
@ -65,12 +67,12 @@ async def test_start_unit(
|
|||||||
systemd = Systemd()
|
systemd = Systemd()
|
||||||
|
|
||||||
with pytest.raises(DBusNotConnectedError):
|
with pytest.raises(DBusNotConnectedError):
|
||||||
await systemd.start_unit("test_unit", "replace")
|
await systemd.start_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
|
|
||||||
await systemd.connect(dbus_session_bus)
|
await systemd.connect(dbus_session_bus)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
await systemd.start_unit("test_unit", "replace")
|
await systemd.start_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
== "/org/freedesktop/systemd1/job/7623"
|
== "/org/freedesktop/systemd1/job/7623"
|
||||||
)
|
)
|
||||||
assert systemd_service.StartUnit.calls == [("test_unit", "replace")]
|
assert systemd_service.StartUnit.calls == [("test_unit", "replace")]
|
||||||
@ -82,12 +84,12 @@ async def test_stop_unit(systemd_service: SystemdService, dbus_session_bus: Mess
|
|||||||
systemd = Systemd()
|
systemd = Systemd()
|
||||||
|
|
||||||
with pytest.raises(DBusNotConnectedError):
|
with pytest.raises(DBusNotConnectedError):
|
||||||
await systemd.stop_unit("test_unit", "replace")
|
await systemd.stop_unit("test_unit", StopUnitMode.REPLACE)
|
||||||
|
|
||||||
await systemd.connect(dbus_session_bus)
|
await systemd.connect(dbus_session_bus)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
await systemd.stop_unit("test_unit", "replace")
|
await systemd.stop_unit("test_unit", StopUnitMode.REPLACE)
|
||||||
== "/org/freedesktop/systemd1/job/7623"
|
== "/org/freedesktop/systemd1/job/7623"
|
||||||
)
|
)
|
||||||
assert systemd_service.StopUnit.calls == [("test_unit", "replace")]
|
assert systemd_service.StopUnit.calls == [("test_unit", "replace")]
|
||||||
@ -101,12 +103,12 @@ async def test_restart_unit(
|
|||||||
systemd = Systemd()
|
systemd = Systemd()
|
||||||
|
|
||||||
with pytest.raises(DBusNotConnectedError):
|
with pytest.raises(DBusNotConnectedError):
|
||||||
await systemd.restart_unit("test_unit", "replace")
|
await systemd.restart_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
|
|
||||||
await systemd.connect(dbus_session_bus)
|
await systemd.connect(dbus_session_bus)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
await systemd.restart_unit("test_unit", "replace")
|
await systemd.restart_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
== "/org/freedesktop/systemd1/job/7623"
|
== "/org/freedesktop/systemd1/job/7623"
|
||||||
)
|
)
|
||||||
assert systemd_service.RestartUnit.calls == [("test_unit", "replace")]
|
assert systemd_service.RestartUnit.calls == [("test_unit", "replace")]
|
||||||
@ -120,12 +122,12 @@ async def test_reload_unit(
|
|||||||
systemd = Systemd()
|
systemd = Systemd()
|
||||||
|
|
||||||
with pytest.raises(DBusNotConnectedError):
|
with pytest.raises(DBusNotConnectedError):
|
||||||
await systemd.reload_unit("test_unit", "replace")
|
await systemd.reload_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
|
|
||||||
await systemd.connect(dbus_session_bus)
|
await systemd.connect(dbus_session_bus)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
await systemd.reload_unit("test_unit", "replace")
|
await systemd.reload_unit("test_unit", StartUnitMode.REPLACE)
|
||||||
== "/org/freedesktop/systemd1/job/7623"
|
== "/org/freedesktop/systemd1/job/7623"
|
||||||
)
|
)
|
||||||
assert systemd_service.ReloadOrRestartUnit.calls == [("test_unit", "replace")]
|
assert systemd_service.ReloadOrRestartUnit.calls == [("test_unit", "replace")]
|
||||||
@ -146,3 +148,47 @@ async def test_list_units(dbus_session_bus: MessageBus):
|
|||||||
assert units[1][2] == "not-found"
|
assert units[1][2] == "not-found"
|
||||||
assert units[3][0] == "zram-swap.service"
|
assert units[3][0] == "zram-swap.service"
|
||||||
assert units[3][2] == "loaded"
|
assert units[3][2] == "loaded"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_start_transient_unit(
|
||||||
|
systemd_service: SystemdService, dbus_session_bus: MessageBus
|
||||||
|
):
|
||||||
|
"""Test start transient unit."""
|
||||||
|
systemd_service.StartTransientUnit.calls.clear()
|
||||||
|
systemd = Systemd()
|
||||||
|
|
||||||
|
with pytest.raises(DBusNotConnectedError):
|
||||||
|
await systemd.start_transient_unit(
|
||||||
|
"tmp-test.mount",
|
||||||
|
StartUnitMode.FAIL,
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
await systemd.connect(dbus_session_bus)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
await systemd.start_transient_unit(
|
||||||
|
"tmp-test.mount",
|
||||||
|
StartUnitMode.FAIL,
|
||||||
|
[
|
||||||
|
("Description", Variant("s", "Test")),
|
||||||
|
("What", Variant("s", "//homeassistant/config")),
|
||||||
|
("Type", Variant("s", "cifs")),
|
||||||
|
("Options", Variant("s", "username=homeassistant,password=password")),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
== "/org/freedesktop/systemd1/job/7623"
|
||||||
|
)
|
||||||
|
assert systemd_service.StartTransientUnit.calls == [
|
||||||
|
(
|
||||||
|
"tmp-test.mount",
|
||||||
|
"fail",
|
||||||
|
[
|
||||||
|
["Description", Variant("s", "Test")],
|
||||||
|
["What", Variant("s", "//homeassistant/config")],
|
||||||
|
["Type", Variant("s", "cifs")],
|
||||||
|
["Options", Variant("s", "username=homeassistant,password=password")],
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
@ -664,6 +664,13 @@ class Systemd(DBusServiceMock):
|
|||||||
"""Restart a service unit."""
|
"""Restart a service unit."""
|
||||||
return "/org/freedesktop/systemd1/job/7623"
|
return "/org/freedesktop/systemd1/job/7623"
|
||||||
|
|
||||||
|
@dbus_method()
|
||||||
|
def StartTransientUnit(
|
||||||
|
self, name: "s", mode: "s", properties: "a(sv)", aux: "a(sa(sv))"
|
||||||
|
) -> "o":
|
||||||
|
"""Start a transient service unit."""
|
||||||
|
return "/org/freedesktop/systemd1/job/7623"
|
||||||
|
|
||||||
@dbus_method()
|
@dbus_method()
|
||||||
def ListUnits(
|
def ListUnits(
|
||||||
self,
|
self,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user