diff --git a/homeassistant/components/backup/__init__.py b/homeassistant/components/backup/__init__.py index 1b19b185b4f..a5159086945 100644 --- a/homeassistant/components/backup/__init__.py +++ b/homeassistant/components/backup/__init__.py @@ -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", diff --git a/homeassistant/components/hassio/backup.py b/homeassistant/components/hassio/backup.py index 9c0511a93fe..e7d169c142c 100644 --- a/homeassistant/components/hassio/backup.py +++ b/homeassistant/components/hassio/backup.py @@ -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( diff --git a/tests/components/backup/snapshots/test_websocket.ambr b/tests/components/backup/snapshots/test_websocket.ambr index d9ed5128e1d..742fec4c3f3 100644 --- a/tests/components/backup/snapshots/test_websocket.ambr +++ b/tests/components/backup/snapshots/test_websocket.ambr @@ -625,7 +625,7 @@ }), 'create_backup': dict({ 'agent_ids': list([ - 'backup.local', + 'hassio.local', 'test-agent', ]), 'include_addons': None, diff --git a/tests/components/conftest.py b/tests/components/conftest.py index ebf390e30d7..dd6776a1cad 100644 --- a/tests/components/conftest.py +++ b/tests/components/conftest.py @@ -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() diff --git a/tests/components/hassio/snapshots/test_backup.ambr b/tests/components/hassio/snapshots/test_backup.ambr new file mode 100644 index 00000000000..a2f33bf9624 --- /dev/null +++ b/tests/components/hassio/snapshots/test_backup.ambr @@ -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', + }) +# --- diff --git a/tests/components/hassio/test_backup.py b/tests/components/hassio/test_backup.py index 7547e3e3586..6a66d249dd1 100644 --- a/tests/components/hassio/test_backup.py +++ b/tests/components/hassio/test_backup.py @@ -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