mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-14 12:46:32 +00:00
DataDisk reload devices (#3129)
* DataDisk reload devices * improve loading * simplify * validate input device * add comments * Add agent version to API * more tests * fix test lint
This commit is contained in:
parent
74530baeb7
commit
53eae96a98
@ -6,3 +6,4 @@ ATTR_DT_UTC = "dt_utc"
|
||||
ATTR_DT_SYNCHRONIZED = "dt_synchronized"
|
||||
ATTR_DISK_DATA = "disk_data"
|
||||
ATTR_DEVICE = "device"
|
||||
ATTR_AGENT_VERSION = "agent_version"
|
||||
|
@ -25,7 +25,13 @@ from ..const import (
|
||||
CONTENT_TYPE_BINARY,
|
||||
)
|
||||
from ..coresys import CoreSysAttributes
|
||||
from .const import ATTR_DT_SYNCHRONIZED, ATTR_DT_UTC, ATTR_USE_NTP, ATTR_USE_RTC
|
||||
from .const import (
|
||||
ATTR_AGENT_VERSION,
|
||||
ATTR_DT_SYNCHRONIZED,
|
||||
ATTR_DT_UTC,
|
||||
ATTR_USE_NTP,
|
||||
ATTR_USE_RTC,
|
||||
)
|
||||
from .utils import api_process, api_process_raw, api_validate
|
||||
|
||||
SERVICE = "service"
|
||||
@ -40,6 +46,7 @@ class APIHost(CoreSysAttributes):
|
||||
async def info(self, request):
|
||||
"""Return host information."""
|
||||
return {
|
||||
ATTR_AGENT_VERSION: self.sys_dbus.agent.version,
|
||||
ATTR_CHASSIS: self.sys_host.info.chassis,
|
||||
ATTR_CPE: self.sys_host.info.cpe,
|
||||
ATTR_DEPLOYMENT: self.sys_host.info.deployment,
|
||||
|
@ -37,5 +37,10 @@ class DataDisk(DBusInterface):
|
||||
|
||||
@dbus_connected
|
||||
async def change_device(self, device: Path) -> None:
|
||||
"""Load/Update AppArmor profile."""
|
||||
"""Migrate data disk to a new device."""
|
||||
await self.dbus.DataDisk.ChangeDevice(device.as_posix())
|
||||
|
||||
@dbus_connected
|
||||
async def reload_device(self) -> None:
|
||||
"""Reload device data."""
|
||||
await self.dbus.DataDisk.ReloadDevice()
|
||||
|
@ -107,6 +107,10 @@ class HassOSJobError(HassOSError, JobException):
|
||||
"""Function not supported by HassOS."""
|
||||
|
||||
|
||||
class HassOSDataDiskError(HassOSError):
|
||||
"""Issues with the DataDisk feature from HAOS."""
|
||||
|
||||
|
||||
# HaCli
|
||||
|
||||
|
||||
@ -278,6 +282,10 @@ class DBusFatalError(DBusError):
|
||||
"""DBus call going wrong."""
|
||||
|
||||
|
||||
class DBusInterfaceMethodError(DBusInterfaceError):
|
||||
"""Dbus method was not definied."""
|
||||
|
||||
|
||||
class DBusParseError(DBusError):
|
||||
"""DBus parse error."""
|
||||
|
||||
|
@ -3,8 +3,18 @@ import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from awesomeversion import AwesomeVersion
|
||||
|
||||
from ..coresys import CoreSys, CoreSysAttributes
|
||||
from ..exceptions import DBusError, HassOSError, HassOSJobError, HostError
|
||||
from ..exceptions import (
|
||||
DBusError,
|
||||
HardwareNotFound,
|
||||
HassOSDataDiskError,
|
||||
HassOSError,
|
||||
HassOSJobError,
|
||||
HostError,
|
||||
)
|
||||
from ..hardware.const import UdevSubsystem
|
||||
from ..jobs.const import JobCondition, JobExecutionLimit
|
||||
from ..jobs.decorator import Job
|
||||
|
||||
@ -23,6 +33,13 @@ class DataDisk(CoreSysAttributes):
|
||||
"""Return Path to used Disk for data."""
|
||||
return self.sys_dbus.agent.datadisk.current_device
|
||||
|
||||
@Job(conditions=[JobCondition.OS_AGENT])
|
||||
async def load(self) -> None:
|
||||
"""Load DataDisk feature."""
|
||||
# Update datadisk details on OS-Agent
|
||||
if self.sys_dbus.agent.version >= AwesomeVersion("1.2.0"):
|
||||
await self.sys_dbus.agent.datadisk.reload_device()
|
||||
|
||||
@Job(
|
||||
conditions=[JobCondition.HAOS, JobCondition.OS_AGENT, JobCondition.HEALTHY],
|
||||
limit=JobExecutionLimit.ONCE,
|
||||
@ -30,14 +47,32 @@ class DataDisk(CoreSysAttributes):
|
||||
)
|
||||
async def migrate_disk(self, new_disk: Path) -> None:
|
||||
"""Move data partition to a new disk."""
|
||||
# Need some error handling, but we need know what disk_used will return
|
||||
# Validate integrity of the data input
|
||||
try:
|
||||
device = self.sys_hardware.get_by_path(new_disk)
|
||||
except HardwareNotFound:
|
||||
raise HassOSDataDiskError(
|
||||
f"'{new_disk!s}' don't exists on the host!", _LOGGER.error
|
||||
) from None
|
||||
|
||||
if device.subsystem != UdevSubsystem.DISK:
|
||||
raise HassOSDataDiskError(
|
||||
f"'{new_disk!s}' is not a harddisk!", _LOGGER.error
|
||||
)
|
||||
if self.sys_hardware.disk.is_system_partition(device):
|
||||
raise HassOSDataDiskError(
|
||||
f"'{new_disk}' is a system disk and can't be used!", _LOGGER.error
|
||||
)
|
||||
|
||||
# Migrate data on Host
|
||||
try:
|
||||
await self.sys_dbus.agent.datadisk.change_device(new_disk)
|
||||
except DBusError as err:
|
||||
raise HassOSError(
|
||||
raise HassOSDataDiskError(
|
||||
f"Can't move data partition to {new_disk!s}: {err!s}", _LOGGER.error
|
||||
) from err
|
||||
|
||||
# Restart Host for finish the process
|
||||
try:
|
||||
await self.sys_host.control.reboot()
|
||||
except HostError as err:
|
||||
|
@ -146,6 +146,7 @@ class OSManager(CoreSysAttributes):
|
||||
self._os_name = cpe.get_product()[0]
|
||||
|
||||
await self.sys_dbus.rauc.update()
|
||||
await self.datadisk.load()
|
||||
|
||||
_LOGGER.info(
|
||||
"Detect Home Assistant Operating System %s / BootSlot %s",
|
||||
|
@ -16,6 +16,7 @@ from . import clean_env
|
||||
from ..exceptions import (
|
||||
DBusFatalError,
|
||||
DBusInterfaceError,
|
||||
DBusInterfaceMethodError,
|
||||
DBusNotConnectedError,
|
||||
DBusParseError,
|
||||
DBusProgramError,
|
||||
@ -296,7 +297,7 @@ class DBusCallWrapper:
|
||||
def __call__(self) -> None:
|
||||
"""Catch this method from being called."""
|
||||
_LOGGER.error("D-Bus method %s not exists!", self.interface)
|
||||
raise DBusFatalError()
|
||||
raise DBusInterfaceMethodError()
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
"""Map to dbus method."""
|
||||
|
@ -1,6 +1,10 @@
|
||||
"""Test OS API."""
|
||||
import pytest
|
||||
|
||||
from supervisor.coresys import CoreSys
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_os_info(api_client):
|
||||
@ -17,3 +21,28 @@ async def test_api_os_info(api_client):
|
||||
"disk_data",
|
||||
):
|
||||
assert attr in result["data"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_os_info_with_agent(api_client, coresys: CoreSys):
|
||||
"""Test docker info api."""
|
||||
await coresys.dbus.agent.connect()
|
||||
await coresys.dbus.agent.update()
|
||||
|
||||
resp = await api_client.get("/os/info")
|
||||
result = await resp.json()
|
||||
|
||||
assert result["data"]["disk_data"] == "/dev/sda"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_os_move_data(api_client, coresys: CoreSys):
|
||||
"""Test docker info api."""
|
||||
await coresys.dbus.agent.connect()
|
||||
await coresys.dbus.agent.update()
|
||||
coresys.os._available = True
|
||||
|
||||
resp = await api_client.post("/os/datadisk/move", json={"device": "/dev/sdaaaa"})
|
||||
result = await resp.json()
|
||||
|
||||
assert result["message"] == "'/dev/sdaaaa' don't exists on the host!"
|
||||
|
@ -26,3 +26,14 @@ async def test_dbus_osagent_datadisk_change_device(coresys: CoreSys):
|
||||
await coresys.dbus.agent.connect()
|
||||
|
||||
assert await coresys.dbus.agent.datadisk.change_device(Path("/dev/sdb")) is None
|
||||
|
||||
|
||||
async def test_dbus_osagent_datadisk_reload_device(coresys: CoreSys):
|
||||
"""Change datadisk on device."""
|
||||
|
||||
with pytest.raises(DBusNotConnectedError):
|
||||
await coresys.dbus.agent.datadisk.reload_device()
|
||||
|
||||
await coresys.dbus.agent.connect()
|
||||
|
||||
assert await coresys.dbus.agent.datadisk.reload_device() is None
|
||||
|
1
tests/fixtures/io_hass_os_DataDisk-ReloadDevice.fixture
vendored
Normal file
1
tests/fixtures/io_hass_os_DataDisk-ReloadDevice.fixture
vendored
Normal file
@ -0,0 +1 @@
|
||||
(<true>,)
|
4
tests/fixtures/io_hass_os_DataDisk.xml
vendored
4
tests/fixtures/io_hass_os_DataDisk.xml
vendored
@ -45,6 +45,10 @@
|
||||
<arg type="b" direction="out">
|
||||
</arg>
|
||||
</method>
|
||||
<method name="ReloadDevice">
|
||||
<arg type="b" direction="out">
|
||||
</arg>
|
||||
</method>
|
||||
<property name="CurrentDevice" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true">
|
||||
</annotation>
|
||||
|
Loading…
x
Reference in New Issue
Block a user