Validate hassio backup settings (#138880)

* Validate hassio backup settings

* Add snapshots

* Don't reset addon and folder settings

* Adapt to changes in BackupConfig.update
pull/138941/head
Erik Montnemery 2025-02-20 16:06:33 +01:00 committed by GitHub
parent fb57284561
commit 0d8c449ff4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 247 additions and 3 deletions

View File

@ -16,7 +16,7 @@ from .agent import (
BackupAgentPlatformProtocol,
LocalBackupAgent,
)
from .config import BackupConfig
from .config import BackupConfig, CreateBackupParametersDict
from .const import DATA_MANAGER, DOMAIN
from .http import async_register_http_views
from .manager import (
@ -55,6 +55,7 @@ __all__ = [
"BackupReaderWriter",
"BackupReaderWriterError",
"CreateBackupEvent",
"CreateBackupParametersDict",
"CreateBackupStage",
"CreateBackupState",
"Folder",

View File

@ -33,6 +33,7 @@ from homeassistant.components.backup import (
BackupReaderWriter,
BackupReaderWriterError,
CreateBackupEvent,
CreateBackupParametersDict,
CreateBackupStage,
CreateBackupState,
Folder,
@ -635,7 +636,25 @@ class SupervisorBackupReaderWriter(BackupReaderWriter):
unsub()
async def async_validate_config(self, *, config: BackupConfig) -> None:
"""Validate backup config."""
"""Validate backup config.
Replace the core backup agent with the hassio default agent.
"""
core_agent_id = "backup.local"
create_backup = config.data.create_backup
if core_agent_id not in create_backup.agent_ids:
_LOGGER.debug("Backup settings don't need to be adjusted")
return
default_agent = await _default_agent(self._client)
_LOGGER.info("Adjusting backup settings to not include core backup location")
automatic_agents = [
agent_id if agent_id != core_agent_id else default_agent
for agent_id in create_backup.agent_ids
]
config.update(
create_backup=CreateBackupParametersDict(agent_ids=automatic_agents)
)
@callback
def _async_listen_job_events(

View File

@ -625,7 +625,7 @@
}),
'create_backup': dict({
'agent_ids': list([
'backup.local',
'hassio.local',
'test-agent',
]),
'include_addons': None,

View File

@ -529,6 +529,7 @@ def resolution_suggestions_for_issue_fixture(supervisor_client: AsyncMock) -> As
def supervisor_client() -> Generator[AsyncMock]:
"""Mock the supervisor client."""
mounts_info_mock = AsyncMock(spec_set=["default_backup_mount", "mounts"])
mounts_info_mock.default_backup_mount = None
mounts_info_mock.mounts = []
supervisor_client = AsyncMock()
supervisor_client.addons = AsyncMock()

View File

@ -0,0 +1,130 @@
# serializer version: 1
# name: test_config_load_config_info[storage_data0]
dict({
'id': 1,
'result': dict({
'config': dict({
'agents': dict({
}),
'create_backup': dict({
'agent_ids': list([
]),
'include_addons': None,
'include_all_addons': False,
'include_database': True,
'include_folders': None,
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'next_automatic_backup': None,
'next_automatic_backup_additional': False,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'time': None,
}),
}),
}),
'success': True,
'type': 'result',
})
# ---
# name: test_config_load_config_info[storage_data1]
dict({
'id': 1,
'result': dict({
'config': dict({
'agents': dict({
}),
'create_backup': dict({
'agent_ids': list([
'test-agent1',
'hassio.local',
'test-agent2',
]),
'include_addons': list([
'addon1',
'addon2',
]),
'include_all_addons': True,
'include_database': True,
'include_folders': list([
'media',
'share',
]),
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'next_automatic_backup': None,
'next_automatic_backup_additional': False,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'time': None,
}),
}),
}),
'success': True,
'type': 'result',
})
# ---
# name: test_config_load_config_info[storage_data2]
dict({
'id': 1,
'result': dict({
'config': dict({
'agents': dict({
}),
'create_backup': dict({
'agent_ids': list([
'test-agent1',
'hassio.local',
'test-agent2',
]),
'include_addons': list([
'addon1',
'addon2',
]),
'include_all_addons': False,
'include_database': True,
'include_folders': list([
'media',
'share',
]),
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'next_automatic_backup': None,
'next_automatic_backup_additional': False,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'time': None,
}),
}),
}),
'success': True,
'type': 'result',
})
# ---

View File

@ -30,6 +30,7 @@ from aiohasupervisor.models.backups import LOCATION_CLOUD_BACKUP, LOCATION_LOCAL
from aiohasupervisor.models.mounts import MountsInfo
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.backup import (
DOMAIN as BACKUP_DOMAIN,
@ -38,6 +39,7 @@ from homeassistant.components.backup import (
BackupAgent,
BackupAgentPlatformProtocol,
Folder,
store as backup_store,
)
from homeassistant.components.hassio import DOMAIN
from homeassistant.components.hassio.backup import RESTORE_JOB_ID_ENV
@ -2466,3 +2468,94 @@ async def test_restore_progress_after_restart_unknown_job(
assert response["success"]
assert response["result"]["last_non_idle_event"] is None
assert response["result"]["state"] == "idle"
@pytest.mark.parametrize(
"storage_data",
[
{},
{
"backup": {
"data": {
"backups": [],
"config": {
"agents": {},
"create_backup": {
"agent_ids": ["test-agent1", "hassio.local", "test-agent2"],
"include_addons": ["addon1", "addon2"],
"include_all_addons": True,
"include_database": True,
"include_folders": ["media", "share"],
"name": None,
"password": None,
},
"retention": {"copies": None, "days": None},
"last_attempted_automatic_backup": None,
"last_completed_automatic_backup": None,
"schedule": {
"days": [],
"recurrence": "never",
"state": "never",
"time": None,
},
},
},
"key": DOMAIN,
"version": backup_store.STORAGE_VERSION,
"minor_version": backup_store.STORAGE_VERSION_MINOR,
},
},
{
"backup": {
"data": {
"backups": [],
"config": {
"agents": {},
"create_backup": {
"agent_ids": ["test-agent1", "backup.local", "test-agent2"],
"include_addons": ["addon1", "addon2"],
"include_all_addons": False,
"include_database": True,
"include_folders": ["media", "share"],
"name": None,
"password": None,
},
"retention": {"copies": None, "days": None},
"last_attempted_automatic_backup": None,
"last_completed_automatic_backup": None,
"schedule": {
"days": [],
"recurrence": "never",
"state": "never",
"time": None,
},
},
},
"key": DOMAIN,
"version": backup_store.STORAGE_VERSION,
"minor_version": backup_store.STORAGE_VERSION_MINOR,
},
},
],
)
@pytest.mark.usefixtures("hassio_client")
async def test_config_load_config_info(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
freezer: FrozenDateTimeFactory,
snapshot: SnapshotAssertion,
hass_storage: dict[str, Any],
storage_data: dict[str, Any] | None,
) -> None:
"""Test loading stored backup config and reading it via config/info."""
client = await hass_ws_client(hass)
await hass.config.async_set_time_zone("Europe/Amsterdam")
freezer.move_to("2024-11-13T12:01:00+01:00")
hass_storage.update(storage_data)
assert await async_setup_component(hass, BACKUP_DOMAIN, {BACKUP_DOMAIN: {}})
await hass.async_block_till_done()
await client.send_json_auto_id({"type": "backup/config/info"})
assert await client.receive_json() == snapshot