mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-27 02:56:31 +00:00
Unmount mounts before backup restore (#4557)
This commit is contained in:
parent
2bb10a32d7
commit
5ae585ce13
@ -1,4 +1,5 @@
|
|||||||
"""Representation of a backup file."""
|
"""Representation of a backup file."""
|
||||||
|
import asyncio
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
from collections.abc import Awaitable
|
from collections.abc import Awaitable
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@ -490,6 +491,18 @@ class Backup(CoreSysAttributes):
|
|||||||
_LOGGER.warning("Can't find restore folder %s", name)
|
_LOGGER.warning("Can't find restore folder %s", name)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Unmount any mounts within folder
|
||||||
|
bind_mounts = [
|
||||||
|
bound.bind_mount
|
||||||
|
for bound in self.sys_mounts.bound_mounts
|
||||||
|
if bound.bind_mount.local_where
|
||||||
|
and bound.bind_mount.local_where.is_relative_to(origin_dir)
|
||||||
|
]
|
||||||
|
if bind_mounts:
|
||||||
|
await asyncio.gather(
|
||||||
|
*[bind_mount.unmount() for bind_mount in bind_mounts]
|
||||||
|
)
|
||||||
|
|
||||||
# Clean old stuff
|
# Clean old stuff
|
||||||
if origin_dir.is_dir():
|
if origin_dir.is_dir():
|
||||||
await remove_folder(origin_dir, content_only=True)
|
await remove_folder(origin_dir, content_only=True)
|
||||||
@ -510,7 +523,13 @@ class Backup(CoreSysAttributes):
|
|||||||
except (tarfile.TarError, OSError) as err:
|
except (tarfile.TarError, OSError) as err:
|
||||||
_LOGGER.warning("Can't restore folder %s: %s", name, err)
|
_LOGGER.warning("Can't restore folder %s: %s", name, err)
|
||||||
|
|
||||||
|
try:
|
||||||
await self.sys_run_in_executor(_restore)
|
await self.sys_run_in_executor(_restore)
|
||||||
|
finally:
|
||||||
|
if bind_mounts:
|
||||||
|
await asyncio.gather(
|
||||||
|
*[bind_mount.mount() for bind_mount in bind_mounts]
|
||||||
|
)
|
||||||
|
|
||||||
# Restore folder sequential
|
# Restore folder sequential
|
||||||
# avoid issue on slow IO
|
# avoid issue on slow IO
|
||||||
|
@ -433,6 +433,57 @@ async def test_backup_media_with_mounts(
|
|||||||
assert not mount_dir.exists()
|
assert not mount_dir.exists()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_backup_media_with_mounts_retains_files(
|
||||||
|
coresys: CoreSys,
|
||||||
|
all_dbus_services: dict[str, DBusServiceMock],
|
||||||
|
tmp_supervisor_data,
|
||||||
|
path_extern,
|
||||||
|
mount_propagation,
|
||||||
|
):
|
||||||
|
"""Test backing up media folder with mounts retains mount files."""
|
||||||
|
systemd_service: SystemdService = all_dbus_services["systemd"]
|
||||||
|
systemd_service.response_get_unit = [
|
||||||
|
DBusError("org.freedesktop.systemd1.NoSuchUnit", "error"),
|
||||||
|
"/org/freedesktop/systemd1/unit/tmp_2dyellow_2emount",
|
||||||
|
DBusError("org.freedesktop.systemd1.NoSuchUnit", "error"),
|
||||||
|
"/org/freedesktop/systemd1/unit/tmp_2dyellow_2emount",
|
||||||
|
"/org/freedesktop/systemd1/unit/tmp_2dyellow_2emount",
|
||||||
|
"/org/freedesktop/systemd1/unit/tmp_2dyellow_2emount",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add a media mount
|
||||||
|
await coresys.mounts.load()
|
||||||
|
await coresys.mounts.create_mount(
|
||||||
|
Mount.from_dict(
|
||||||
|
coresys,
|
||||||
|
{
|
||||||
|
"name": "media_test",
|
||||||
|
"usage": "media",
|
||||||
|
"type": "cifs",
|
||||||
|
"server": "test.local",
|
||||||
|
"share": "test",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make a partial backup
|
||||||
|
coresys.core.state = CoreState.RUNNING
|
||||||
|
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
|
||||||
|
backup: Backup = await coresys.backups.do_backup_partial("test", folders=["media"])
|
||||||
|
|
||||||
|
systemd_service.StopUnit.calls.clear()
|
||||||
|
systemd_service.StartTransientUnit.calls.clear()
|
||||||
|
with patch.object(DockerHomeAssistant, "is_running", return_value=True):
|
||||||
|
await coresys.backups.do_restore_partial(backup, folders=["media"])
|
||||||
|
|
||||||
|
assert systemd_service.StopUnit.calls == [
|
||||||
|
("mnt-data-supervisor-media-media_test.mount", "fail")
|
||||||
|
]
|
||||||
|
assert systemd_service.StartTransientUnit.calls == [
|
||||||
|
("mnt-data-supervisor-media-media_test.mount", "fail", ANY, [])
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_backup_share_with_mounts(
|
async def test_backup_share_with_mounts(
|
||||||
coresys: CoreSys,
|
coresys: CoreSys,
|
||||||
all_dbus_services: dict[str, DBusServiceMock],
|
all_dbus_services: dict[str, DBusServiceMock],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user