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:
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user