Fix activating backup retention config on startup (#134523)

This commit is contained in:
Erik Montnemery 2025-01-03 10:29:29 +01:00 committed by GitHub
parent 46824a2a53
commit b78e39da2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 239 additions and 86 deletions

View File

@ -124,6 +124,7 @@ class BackupConfig:
def load(self, stored_config: StoredBackupConfig) -> None: def load(self, stored_config: StoredBackupConfig) -> None:
"""Load config.""" """Load config."""
self.data = BackupConfigData.from_dict(stored_config) self.data = BackupConfigData.from_dict(stored_config)
self.data.retention.apply(self._manager)
self.data.schedule.apply(self._manager) self.data.schedule.apply(self._manager)
async def update( async def update(
@ -160,8 +161,13 @@ class RetentionConfig:
def apply(self, manager: BackupManager) -> None: def apply(self, manager: BackupManager) -> None:
"""Apply backup retention configuration.""" """Apply backup retention configuration."""
if self.days is not None: if self.days is not None:
LOGGER.debug(
"Scheduling next automatic delete of backups older than %s in 1 day",
self.days,
)
self._schedule_next(manager) self._schedule_next(manager)
else: else:
LOGGER.debug("Unscheduling next automatic delete")
self._unschedule_next(manager) self._unschedule_next(manager)
def to_dict(self) -> StoredRetentionConfig: def to_dict(self) -> StoredRetentionConfig:

View File

@ -1173,7 +1173,7 @@ async def test_config_update_errors(
@pytest.mark.parametrize( @pytest.mark.parametrize(
( (
"command", "commands",
"last_completed_automatic_backup", "last_completed_automatic_backup",
"time_1", "time_1",
"time_2", "time_2",
@ -1186,11 +1186,8 @@ async def test_config_update_errors(
), ),
[ [
( (
{ # No config update
"type": "backup/config/update", [],
"create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "daily",
},
"2024-11-11T04:45:00+01:00", "2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00", "2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00", "2024-11-13T04:45:00+01:00",
@ -1202,11 +1199,32 @@ async def test_config_update_errors(
None, None,
), ),
( (
# Unchanged schedule
[
{
"type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "daily",
}
],
"2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
1,
2,
BACKUP_CALL,
None,
),
(
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "mon", "schedule": "mon",
}, }
],
"2024-11-11T04:45:00+01:00", "2024-11-11T04:45:00+01:00",
"2024-11-18T04:45:00+01:00", "2024-11-18T04:45:00+01:00",
"2024-11-25T04:45:00+01:00", "2024-11-25T04:45:00+01:00",
@ -1218,11 +1236,13 @@ async def test_config_update_errors(
None, None,
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "never", "schedule": "never",
}, }
],
"2024-11-11T04:45:00+01:00", "2024-11-11T04:45:00+01:00",
"2034-11-11T12:00:00+01:00", # ten years later and still no backups "2034-11-11T12:00:00+01:00", # ten years later and still no backups
"2034-11-11T13:00:00+01:00", "2034-11-11T13:00:00+01:00",
@ -1234,11 +1254,13 @@ async def test_config_update_errors(
None, None,
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "daily", "schedule": "daily",
}, }
],
"2024-10-26T04:45:00+01:00", "2024-10-26T04:45:00+01:00",
"2024-11-12T04:45:00+01:00", "2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00", "2024-11-13T04:45:00+01:00",
@ -1250,11 +1272,13 @@ async def test_config_update_errors(
None, None,
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "mon", "schedule": "mon",
}, }
],
"2024-10-26T04:45:00+01:00", "2024-10-26T04:45:00+01:00",
"2024-11-12T04:45:00+01:00", "2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00", "2024-11-13T04:45:00+01:00",
@ -1266,11 +1290,13 @@ async def test_config_update_errors(
None, None,
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "never", "schedule": "never",
}, }
],
"2024-10-26T04:45:00+01:00", "2024-10-26T04:45:00+01:00",
"2034-11-11T12:00:00+01:00", # ten years later and still no backups "2034-11-11T12:00:00+01:00", # ten years later and still no backups
"2034-11-12T12:00:00+01:00", "2034-11-12T12:00:00+01:00",
@ -1282,11 +1308,13 @@ async def test_config_update_errors(
None, None,
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "daily", "schedule": "daily",
}, }
],
"2024-11-11T04:45:00+01:00", "2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00", "2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00", "2024-11-13T04:45:00+01:00",
@ -1298,11 +1326,13 @@ async def test_config_update_errors(
[BackupReaderWriterError("Boom"), None], [BackupReaderWriterError("Boom"), None],
), ),
( (
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]}, "create_backup": {"agent_ids": ["test.test-agent"]},
"schedule": "daily", "schedule": "daily",
}, }
],
"2024-11-11T04:45:00+01:00", "2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00", "2024-11-12T04:45:00+01:00",
"2024-11-13T04:45:00+01:00", "2024-11-13T04:45:00+01:00",
@ -1321,7 +1351,7 @@ async def test_config_schedule_logic(
freezer: FrozenDateTimeFactory, freezer: FrozenDateTimeFactory,
hass_storage: dict[str, Any], hass_storage: dict[str, Any],
create_backup: AsyncMock, create_backup: AsyncMock,
command: dict[str, Any], commands: list[dict[str, Any]],
last_completed_automatic_backup: str, last_completed_automatic_backup: str,
time_1: str, time_1: str,
time_2: str, time_2: str,
@ -1338,7 +1368,7 @@ async def test_config_schedule_logic(
"backups": {}, "backups": {},
"config": { "config": {
"create_backup": { "create_backup": {
"agent_ids": ["test-agent"], "agent_ids": ["test.test-agent"],
"include_addons": ["test-addon"], "include_addons": ["test-addon"],
"include_all_addons": False, "include_all_addons": False,
"include_database": True, "include_database": True,
@ -1364,9 +1394,9 @@ async def test_config_schedule_logic(
await setup_backup_integration(hass, remote_agents=["test-agent"]) await setup_backup_integration(hass, remote_agents=["test-agent"])
await hass.async_block_till_done() await hass.async_block_till_done()
for command in commands:
await client.send_json_auto_id(command) await client.send_json_auto_id(command)
result = await client.receive_json() result = await client.receive_json()
assert result["success"] assert result["success"]
freezer.move_to(time_1) freezer.move_to(time_1)
@ -2097,7 +2127,8 @@ async def test_config_retention_copies_logic_manual_backup(
@pytest.mark.parametrize( @pytest.mark.parametrize(
( (
"command", "stored_retained_days",
"commands",
"backups", "backups",
"get_backups_agent_errors", "get_backups_agent_errors",
"delete_backup_agent_errors", "delete_backup_agent_errors",
@ -2109,13 +2140,77 @@ async def test_config_retention_copies_logic_manual_backup(
"delete_args_list", "delete_args_list",
), ),
[ [
# No config update - cleanup backups older than 2 days
( (
2,
[],
{
"backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
},
{},
{},
"2024-11-11T04:45:00+01:00",
"2024-11-11T12:00:00+01:00",
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
),
# No config update - No cleanup
(
None,
[],
{
"backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
},
{},
{},
"2024-11-11T04:45:00+01:00",
"2024-11-11T12:00:00+01:00",
"2024-11-12T12:00:00+01:00",
0,
0,
[],
),
# Unchanged config
(
2,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 2}, "retention": {"copies": None, "days": 2},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00", date="2024-11-10T04:45:00+01:00",
@ -2143,12 +2238,51 @@ async def test_config_retention_copies_logic_manual_backup(
[call("backup-1")], [call("backup-1")],
), ),
( (
None,
[
{
"type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 2},
"schedule": "never",
}
],
{
"backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
},
{},
{},
"2024-11-11T04:45:00+01:00",
"2024-11-11T12:00:00+01:00",
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
),
(
None,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 3}, "retention": {"copies": None, "days": 3},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00", date="2024-11-10T04:45:00+01:00",
@ -2176,12 +2310,15 @@ async def test_config_retention_copies_logic_manual_backup(
[], [],
), ),
( (
None,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 2}, "retention": {"copies": None, "days": 2},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-09T04:45:00+01:00", date="2024-11-09T04:45:00+01:00",
@ -2214,12 +2351,15 @@ async def test_config_retention_copies_logic_manual_backup(
[call("backup-1"), call("backup-2")], [call("backup-1"), call("backup-2")],
), ),
( (
None,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 2}, "retention": {"copies": None, "days": 2},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00", date="2024-11-10T04:45:00+01:00",
@ -2247,12 +2387,15 @@ async def test_config_retention_copies_logic_manual_backup(
[call("backup-1")], [call("backup-1")],
), ),
( (
None,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 2}, "retention": {"copies": None, "days": 2},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-10T04:45:00+01:00", date="2024-11-10T04:45:00+01:00",
@ -2280,12 +2423,15 @@ async def test_config_retention_copies_logic_manual_backup(
[call("backup-1")], [call("backup-1")],
), ),
( (
None,
[
{ {
"type": "backup/config/update", "type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]}, "create_backup": {"agent_ids": ["test-agent"]},
"retention": {"copies": None, "days": 0}, "retention": {"copies": None, "days": 0},
"schedule": "never", "schedule": "never",
}, }
],
{ {
"backup-1": MagicMock( "backup-1": MagicMock(
date="2024-11-09T04:45:00+01:00", date="2024-11-09T04:45:00+01:00",
@ -2326,7 +2472,8 @@ async def test_config_retention_days_logic(
hass_storage: dict[str, Any], hass_storage: dict[str, Any],
delete_backup: AsyncMock, delete_backup: AsyncMock,
get_backups: AsyncMock, get_backups: AsyncMock,
command: dict[str, Any], stored_retained_days: int | None,
commands: list[dict[str, Any]],
backups: dict[str, Any], backups: dict[str, Any],
get_backups_agent_errors: dict[str, Exception], get_backups_agent_errors: dict[str, Exception],
delete_backup_agent_errors: dict[str, Exception], delete_backup_agent_errors: dict[str, Exception],
@ -2351,7 +2498,7 @@ async def test_config_retention_days_logic(
"name": "test-name", "name": "test-name",
"password": "test-password", "password": "test-password",
}, },
"retention": {"copies": None, "days": None}, "retention": {"copies": None, "days": stored_retained_days},
"last_attempted_automatic_backup": None, "last_attempted_automatic_backup": None,
"last_completed_automatic_backup": last_backup_time, "last_completed_automatic_backup": last_backup_time,
"schedule": {"state": "never"}, "schedule": {"state": "never"},
@ -2370,9 +2517,9 @@ async def test_config_retention_days_logic(
await setup_backup_integration(hass) await setup_backup_integration(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
for command in commands:
await client.send_json_auto_id(command) await client.send_json_auto_id(command)
result = await client.receive_json() result = await client.receive_json()
assert result["success"] assert result["success"]
freezer.move_to(next_time) freezer.move_to(next_time)