1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 21:06:19 +00:00

Allow creating backup if at least one agent is available (#137409)

This commit is contained in:
Erik Montnemery
2025-02-05 10:14:39 +01:00
committed by GitHub
parent 7ad0438a4e
commit bfbf95f515
2 changed files with 114 additions and 22 deletions

View File

@@ -9,6 +9,7 @@ from dataclasses import dataclass, replace
from enum import StrEnum
import hashlib
import io
from itertools import chain
import json
from pathlib import Path, PurePath
import shutil
@@ -827,7 +828,7 @@ class BackupManager:
password=None,
)
await written_backup.release_stream()
self.known_backups.add(written_backup.backup, agent_errors)
self.known_backups.add(written_backup.backup, agent_errors, [])
return written_backup.backup.backup_id
async def async_create_backup(
@@ -951,12 +952,23 @@ class BackupManager:
with_automatic_settings: bool,
) -> NewBackup:
"""Initiate generating a backup."""
if not agent_ids:
raise BackupManagerError("At least one agent must be selected")
if invalid_agents := [
unavailable_agents = [
agent_id for agent_id in agent_ids if agent_id not in self.backup_agents
]:
raise BackupManagerError(f"Invalid agents selected: {invalid_agents}")
]
if not (
available_agents := [
agent_id for agent_id in agent_ids if agent_id in self.backup_agents
]
):
raise BackupManagerError(
f"At least one available backup agent must be selected, got {agent_ids}"
)
if unavailable_agents:
LOGGER.warning(
"Backup agents %s are not available, will backupp to %s",
unavailable_agents,
available_agents,
)
if include_all_addons and include_addons:
raise BackupManagerError(
"Cannot include all addons and specify specific addons"
@@ -973,7 +985,7 @@ class BackupManager:
new_backup,
self._backup_task,
) = await self._reader_writer.async_create_backup(
agent_ids=agent_ids,
agent_ids=available_agents,
backup_name=backup_name,
extra_metadata=extra_metadata
| {
@@ -992,7 +1004,9 @@ class BackupManager:
raise BackupManagerError(str(err)) from err
backup_finish_task = self._backup_finish_task = self.hass.async_create_task(
self._async_finish_backup(agent_ids, with_automatic_settings, password),
self._async_finish_backup(
available_agents, unavailable_agents, with_automatic_settings, password
),
name="backup_manager_finish_backup",
)
if not raise_task_error:
@@ -1009,7 +1023,11 @@ class BackupManager:
return new_backup
async def _async_finish_backup(
self, agent_ids: list[str], with_automatic_settings: bool, password: str | None
self,
available_agents: list[str],
unavailable_agents: list[str],
with_automatic_settings: bool,
password: str | None,
) -> None:
"""Finish a backup."""
if TYPE_CHECKING:
@@ -1028,7 +1046,7 @@ class BackupManager:
LOGGER.debug(
"Generated new backup with backup_id %s, uploading to agents %s",
written_backup.backup.backup_id,
agent_ids,
available_agents,
)
self.async_on_backup_event(
CreateBackupEvent(
@@ -1041,13 +1059,15 @@ class BackupManager:
try:
agent_errors = await self._async_upload_backup(
backup=written_backup.backup,
agent_ids=agent_ids,
agent_ids=available_agents,
open_stream=written_backup.open_stream,
password=password,
)
finally:
await written_backup.release_stream()
self.known_backups.add(written_backup.backup, agent_errors)
self.known_backups.add(
written_backup.backup, agent_errors, unavailable_agents
)
if not agent_errors:
if with_automatic_settings:
# create backup was successful, update last_completed_automatic_backup
@@ -1056,7 +1076,7 @@ class BackupManager:
backup_success = True
if with_automatic_settings:
self._update_issue_after_agent_upload(agent_errors)
self._update_issue_after_agent_upload(agent_errors, unavailable_agents)
# delete old backups more numerous than copies
# try this regardless of agent errors above
await delete_backups_exceeding_configured_count(self)
@@ -1216,10 +1236,10 @@ class BackupManager:
)
def _update_issue_after_agent_upload(
self, agent_errors: dict[str, Exception]
self, agent_errors: dict[str, Exception], unavailable_agents: list[str]
) -> None:
"""Update issue registry after a backup is uploaded to agents."""
if not agent_errors:
if not agent_errors and not unavailable_agents:
ir.async_delete_issue(self.hass, DOMAIN, "automatic_backup_failed")
return
ir.async_create_issue(
@@ -1233,7 +1253,13 @@ class BackupManager:
translation_key="automatic_backup_failed_upload_agents",
translation_placeholders={
"failed_agents": ", ".join(
self.backup_agents[agent_id].name for agent_id in agent_errors
chain(
(
self.backup_agents[agent_id].name
for agent_id in agent_errors
),
unavailable_agents,
)
)
},
)
@@ -1302,11 +1328,12 @@ class KnownBackups:
self,
backup: AgentBackup,
agent_errors: dict[str, Exception],
unavailable_agents: list[str],
) -> None:
"""Add a backup."""
self._backups[backup.backup_id] = KnownBackup(
backup_id=backup.backup_id,
failed_agent_ids=list(agent_errors),
failed_agent_ids=list(chain(agent_errors, unavailable_agents)),
)
self._manager.store.save()