diff --git a/supervisor/addons/__init__.py b/supervisor/addons/__init__.py index 4480e48bf..f3902e8b2 100644 --- a/supervisor/addons/__init__.py +++ b/supervisor/addons/__init__.py @@ -18,6 +18,7 @@ from ..exceptions import ( HomeAssistantAPIError, HostAppArmorError, ) +from ..jobs.decorator import Job, JobCondition from ..resolution.const import ContextType, IssueType, SuggestionType from ..store.addon import AddonStore from ..utils import check_exception_chain @@ -141,6 +142,13 @@ class AddonManager(CoreSysAttributes): _LOGGER.warning("Can't stop Add-on %s: %s", addon.slug, err) self.sys_capture_exception(err) + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.INTERNET_HOST, + JobCondition.HEALTHY, + ] + ) async def install(self, slug: str) -> None: """Install an add-on.""" if slug in self.local: @@ -235,6 +243,13 @@ class AddonManager(CoreSysAttributes): _LOGGER.info("Add-on '%s' successfully removed", slug) + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.INTERNET_HOST, + JobCondition.HEALTHY, + ] + ) async def update(self, slug: str) -> None: """Update add-on.""" if slug not in self.local: @@ -277,6 +292,13 @@ class AddonManager(CoreSysAttributes): if last_state == AddonState.STARTED: await addon.start() + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.INTERNET_HOST, + JobCondition.HEALTHY, + ] + ) async def rebuild(self, slug: str) -> None: """Perform a rebuild of local build add-on.""" if slug not in self.local: @@ -312,6 +334,13 @@ class AddonManager(CoreSysAttributes): if last_state == AddonState.STARTED: await addon.start() + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.INTERNET_HOST, + JobCondition.HEALTHY, + ] + ) async def restore(self, slug: str, tar_file: tarfile.TarFile) -> None: """Restore state of an add-on.""" if slug not in self.local: @@ -334,6 +363,7 @@ class AddonManager(CoreSysAttributes): with suppress(HomeAssistantAPIError): await self.sys_ingress.update_hass_panel(addon) + @Job(conditions=[JobCondition.FREE_SPACE, JobCondition.INTERNET_HOST]) async def repair(self) -> None: """Repair local add-ons.""" needs_repair: List[Addon] = [] diff --git a/supervisor/docker/interface.py b/supervisor/docker/interface.py index 521a13627..8bf16ed85 100644 --- a/supervisor/docker/interface.py +++ b/supervisor/docker/interface.py @@ -156,14 +156,7 @@ class DockerInterface(CoreSysAttributes): docker_image.tag(image, tag="latest") except docker.errors.APIError as err: _LOGGER.error("Can't install %s:%s -> %s.", image, tag, err) - if err.status_code == 404: - free_space = self.sys_host.info.free_space - _LOGGER.info( - "This error is often caused by not having enough disk space available. " - "Available space in /data is: %s GiB", - free_space, - ) - elif err.status_code == 429: + if err.status_code == 429: self.sys_resolution.create_issue( IssueType.DOCKER_RATELIMIT, ContextType.SYSTEM, diff --git a/supervisor/homeassistant/core.py b/supervisor/homeassistant/core.py index a1600ef57..97b71a7fe 100644 --- a/supervisor/homeassistant/core.py +++ b/supervisor/homeassistant/core.py @@ -21,6 +21,7 @@ from ..exceptions import ( HomeAssistantError, HomeAssistantUpdateError, ) +from ..jobs.decorator import Job, JobCondition from ..resolution.const import ContextType, IssueType from ..utils import convert_to_ascii, process_lock @@ -152,6 +153,13 @@ class HomeAssistantCore(CoreSysAttributes): await self.instance.cleanup() @process_lock + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.HEALTHY, + JobCondition.INTERNET_HOST, + ] + ) async def update(self, version: Optional[str] = None) -> None: """Update HomeAssistant version.""" version = version or self.sys_homeassistant.latest_version @@ -409,6 +417,12 @@ class HomeAssistantCore(CoreSysAttributes): self._error_state = True raise HomeAssistantCrashError() + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.INTERNET_HOST, + ] + ) async def repair(self): """Repair local Home Assistant data.""" if await self.instance.exists(): diff --git a/supervisor/snapshots/__init__.py b/supervisor/snapshots/__init__.py index f477a105a..bd68f1595 100644 --- a/supervisor/snapshots/__init__.py +++ b/supervisor/snapshots/__init__.py @@ -7,6 +7,7 @@ from typing import Set from ..const import FOLDER_HOMEASSISTANT, SNAPSHOT_FULL, SNAPSHOT_PARTIAL, CoreState from ..coresys import CoreSysAttributes from ..exceptions import AddonsError +from ..jobs.decorator import Job, JobCondition from ..utils.dt import utcnow from .snapshot import Snapshot from .utils import create_slug @@ -121,6 +122,7 @@ class SnapshotManager(CoreSysAttributes): self.snapshots_obj[snapshot.slug] = snapshot return snapshot + @Job(conditions=[JobCondition.FREE_SPACE, JobCondition.HEALTHY]) async def do_snapshot_full(self, name="", password=None): """Create a full snapshot.""" if self.lock.locked(): @@ -156,6 +158,7 @@ class SnapshotManager(CoreSysAttributes): self.sys_core.state = CoreState.RUNNING self.lock.release() + @Job(conditions=[JobCondition.FREE_SPACE, JobCondition.HEALTHY]) async def do_snapshot_partial( self, name="", addons=None, folders=None, password=None ): @@ -207,6 +210,14 @@ class SnapshotManager(CoreSysAttributes): self.sys_core.state = CoreState.RUNNING self.lock.release() + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.HEALTHY, + JobCondition.INTERNET_HOST, + JobCondition.INTERNET_SYSTEM, + ] + ) async def do_restore_full(self, snapshot, password=None): """Restore a snapshot.""" if self.lock.locked(): @@ -283,6 +294,14 @@ class SnapshotManager(CoreSysAttributes): self.sys_core.state = CoreState.RUNNING self.lock.release() + @Job( + conditions=[ + JobCondition.FREE_SPACE, + JobCondition.HEALTHY, + JobCondition.INTERNET_HOST, + JobCondition.INTERNET_SYSTEM, + ] + ) async def do_restore_partial( self, snapshot, homeassistant=False, addons=None, folders=None, password=None ):