Disable auto boot for add-ons with missconfig (#2057)

This commit is contained in:
Pascal Vizeli 2020-09-15 14:54:18 +02:00 committed by GitHub
parent 4da2715d14
commit 045a3ba416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 198 additions and 150 deletions

View File

@ -5,13 +5,17 @@ import logging
import tarfile
from typing import Dict, List, Optional, Union
from ..const import BOOT_AUTO, AddonStartup, AddonState
from ..const import AddonBoot, AddonStartup, AddonState
from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import (
AddonConfigurationError,
AddonsError,
AddonsNotSupportedError,
CoreDNSError,
DockerAPIError,
DockerError,
DockerNotFound,
DockerRequestError,
HomeAssistantAPIError,
HostAppArmorError,
)
@ -84,7 +88,7 @@ class AddonManager(CoreSysAttributes):
"""Boot add-ons with mode auto."""
tasks: List[Addon] = []
for addon in self.installed:
if addon.boot != BOOT_AUTO or addon.startup != stage:
if addon.boot != AddonBoot.AUTO or addon.startup != stage:
continue
tasks.append(addon)
@ -98,9 +102,17 @@ class AddonManager(CoreSysAttributes):
for addon in tasks:
try:
await addon.start()
except DockerRequestError:
pass
except (AddonConfigurationError, DockerAPIError, DockerNotFound):
addon.boot = AddonBoot.MANUAL
addon.save_persist()
except Exception as err: # pylint: disable=broad-except
_LOGGER.warning("Can't start Add-on %s: %s", addon.slug, err)
self.sys_capture_exception(err)
else:
continue
_LOGGER.warning("Can't start Add-on %s", addon.slug)
await asyncio.sleep(self.sys_config.wait_boot)
@ -153,7 +165,7 @@ class AddonManager(CoreSysAttributes):
try:
await addon.instance.install(store.version, store.image)
except DockerAPIError as err:
except DockerError as err:
self.data.uninstall(addon)
raise AddonsError() from err
else:
@ -174,7 +186,7 @@ class AddonManager(CoreSysAttributes):
try:
await addon.instance.remove()
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
else:
addon.state = AddonState.UNKNOWN
@ -245,9 +257,9 @@ class AddonManager(CoreSysAttributes):
await addon.instance.update(store.version, store.image)
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await addon.instance.cleanup()
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
else:
self.data.update(store)
@ -285,7 +297,7 @@ class AddonManager(CoreSysAttributes):
try:
await addon.instance.remove()
await addon.instance.install(addon.version)
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
else:
self.data.update(store)
@ -337,7 +349,7 @@ class AddonManager(CoreSysAttributes):
self.sys_docker.network.stale_cleanup, addon.instance.name
)
with suppress(DockerAPIError, KeyError):
with suppress(DockerError, KeyError):
# Need pull a image again
if not addon.need_build:
await addon.instance.install(addon.version, addon.image)
@ -362,7 +374,7 @@ class AddonManager(CoreSysAttributes):
try:
if not await addon.instance.is_running():
continue
except DockerAPIError as err:
except DockerError as err:
_LOGGER.warning("Add-on %s is corrupt: %s", addon.slug, err)
self.sys_core.healthy = False
self.sys_capture_exception(err)

View File

@ -39,6 +39,7 @@ from ..const import (
ATTR_VERSION,
ATTR_WATCHDOG,
DNS_SUFFIX,
AddonBoot,
AddonStartup,
AddonState,
)
@ -49,7 +50,8 @@ from ..exceptions import (
AddonConfigurationError,
AddonsError,
AddonsNotSupportedError,
DockerAPIError,
DockerError,
DockerRequestError,
HostAppArmorError,
JsonFileError,
)
@ -98,7 +100,7 @@ class Addon(AddonModel):
async def load(self) -> None:
"""Async initialize of object."""
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.attach(tag=self.version)
# Evaluate state
@ -163,12 +165,12 @@ class Addon(AddonModel):
self.persist[ATTR_OPTIONS] = {} if value is None else deepcopy(value)
@property
def boot(self) -> bool:
def boot(self) -> AddonBoot:
"""Return boot config with prio local settings."""
return self.persist.get(ATTR_BOOT, super().boot)
@boot.setter
def boot(self, value: bool) -> None:
def boot(self, value: AddonBoot) -> None:
"""Store user boot options."""
self.persist[ATTR_BOOT] = value
@ -560,7 +562,10 @@ class Addon(AddonModel):
# Start Add-on
try:
await self.instance.run()
except DockerAPIError as err:
except DockerRequestError as err:
self.state = AddonState.STOPPED
raise AddonsError() from err
except DockerError as err:
self.state = AddonState.ERROR
raise AddonsError(err) from err
else:
@ -570,7 +575,9 @@ class Addon(AddonModel):
"""Stop add-on."""
try:
return await self.instance.stop()
except DockerAPIError as err:
except DockerRequestError as err:
raise AddonsError() from err
except DockerError as err:
self.state = AddonState.ERROR
raise AddonsError() from err
else:
@ -600,7 +607,7 @@ class Addon(AddonModel):
"""Return stats of container."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
async def write_stdin(self, data) -> None:
@ -614,7 +621,7 @@ class Addon(AddonModel):
try:
return await self.instance.write_stdin(data)
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
async def snapshot(self, tar_file: tarfile.TarFile) -> None:
@ -626,7 +633,7 @@ class Addon(AddonModel):
if self.need_build:
try:
await self.instance.export_image(temp_path.joinpath("image.tar"))
except DockerAPIError as err:
except DockerError as err:
raise AddonsError() from err
data = {
@ -728,18 +735,18 @@ class Addon(AddonModel):
image_file = Path(temp, "image.tar")
if image_file.is_file():
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.import_image(image_file)
else:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(version, restore_image)
await self.instance.cleanup()
elif self.instance.version != version or self.legacy:
_LOGGER.info("Restore/Update image for addon %s", self.slug)
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.update(version, restore_image)
else:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.stop()
# Restore data

View File

@ -66,6 +66,7 @@ from ..const import (
SECURITY_DEFAULT,
SECURITY_DISABLE,
SECURITY_PROFILE,
AddonBoot,
AddonStage,
AddonStartup,
)
@ -109,7 +110,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_OPTIONS]
@property
def boot(self) -> bool:
def boot(self) -> AddonBoot:
"""Return boot config with prio local settings."""
return self.data[ATTR_BOOT]

View File

@ -82,11 +82,10 @@ from ..const import (
ATTR_VIDEO,
ATTR_WATCHDOG,
ATTR_WEBUI,
BOOT_AUTO,
BOOT_MANUAL,
PRIVILEGED_ALL,
ROLE_ALL,
ROLE_DEFAULT,
AddonBoot,
AddonStage,
AddonStartup,
AddonState,
@ -193,7 +192,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()),
vol.Optional(ATTR_URL): vol.Url(),
vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.Coerce(AddonStartup)),
vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
vol.Required(ATTR_BOOT): vol.Coerce(AddonBoot),
vol.Optional(ATTR_INIT, default=True): vol.Boolean(),
vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(),
vol.Optional(ATTR_STAGE, default=AddonStage.STABLE): vol.Coerce(AddonStage),
@ -303,7 +302,7 @@ SCHEMA_ADDON_USER = vol.Schema(
),
vol.Optional(ATTR_OPTIONS, default=dict): dict,
vol.Optional(ATTR_AUTO_UPDATE, default=False): vol.Boolean(),
vol.Optional(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
vol.Optional(ATTR_BOOT): vol.Coerce(AddonBoot),
vol.Optional(ATTR_NETWORK): docker_ports,
vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(vol.Coerce(str)),
vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(vol.Coerce(str)),

View File

@ -91,12 +91,11 @@ from ..const import (
ATTR_VIDEO,
ATTR_WATCHDOG,
ATTR_WEBUI,
BOOT_AUTO,
BOOT_MANUAL,
CONTENT_TYPE_BINARY,
CONTENT_TYPE_PNG,
CONTENT_TYPE_TEXT,
REQUEST_FROM,
AddonBoot,
AddonState,
)
from ..coresys import CoreSysAttributes
@ -112,7 +111,7 @@ SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): vol.Coerce(str)})
# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema(
{
vol.Optional(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
vol.Optional(ATTR_BOOT): vol.Coerce(AddonBoot),
vol.Optional(ATTR_NETWORK): vol.Maybe(docker_ports),
vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(),
vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(vol.Coerce(str)),

View File

@ -277,9 +277,6 @@ PROVIDE_SERVICE = "provide"
NEED_SERVICE = "need"
WANT_SERVICE = "want"
BOOT_AUTO = "auto"
BOOT_MANUAL = "manual"
MAP_CONFIG = "config"
MAP_SSL = "ssl"
@ -352,6 +349,13 @@ CHAN_TYPE = "chan_type"
SUPERVISED_SUPPORTED_OS = ["Debian GNU/Linux 10 (buster)"]
class AddonBoot(str, Enum):
"""Boot mode for the add-on."""
AUTO = "auto"
MANUAL = "manual"
class AddonStartup(str, Enum):
"""Startup types of Add-on."""

View File

@ -15,7 +15,7 @@ from .const import (
)
from .coresys import CoreSys, CoreSysAttributes
from .exceptions import (
DockerAPIError,
DockerError,
HassioError,
HomeAssistantError,
SupervisorUpdateError,
@ -177,7 +177,7 @@ class Core(CoreSysAttributes):
if await self.sys_run_in_executor(self.sys_docker.check_denylist_images):
self.supported = False
self.healthy = False
except DockerAPIError:
except DockerError:
self.healthy = False
async def start(self):

View File

@ -11,7 +11,7 @@ from packaging import version as pkg_version
import requests
from ..const import DNS_SUFFIX, DOCKER_IMAGE_DENYLIST, SOCKET_DOCKER
from ..exceptions import DockerAPIError
from ..exceptions import DockerAPIError, DockerError, DockerNotFound, DockerRequestError
from .network import DockerNetwork
_LOGGER: logging.Logger = logging.getLogger(__name__)
@ -129,27 +129,36 @@ class DockerAPI:
container = self.docker.containers.create(
f"{image}:{version}", use_config_proxy=False, **kwargs
)
except (docker.errors.DockerException, requests.RequestException) as err:
except docker.errors.NotFound as err:
_LOGGER.error("Image %s not exists for %s", image, name)
raise DockerNotFound() from err
except docker.errors.DockerException as err:
_LOGGER.error("Can't create container from %s: %s", name, err)
raise DockerAPIError() from err
except requests.RequestException as err:
_LOGGER.error("Dockerd connection issue for %s: %s", name, err)
raise DockerRequestError() from err
# Attach network
if not network_mode:
alias = [hostname] if hostname else None
try:
self.network.attach_container(container, alias=alias, ipv4=ipv4)
except DockerAPIError:
except DockerError:
_LOGGER.warning("Can't attach %s to hassio-net!", name)
else:
with suppress(DockerAPIError):
with suppress(DockerError):
self.network.detach_default_bridge(container)
# Run container
try:
container.start()
except (docker.errors.DockerException, requests.RequestException) as err:
except docker.errors.DockerException as err:
_LOGGER.error("Can't start %s: %s", name, err)
raise DockerAPIError(err) from err
raise DockerAPIError() from err
except requests.RequestException as err:
_LOGGER.error("Dockerd connection issue for %s: %s", name, err)
raise DockerRequestError() from err
# Update metadata
with suppress(docker.errors.DockerException, requests.RequestException):
@ -187,7 +196,7 @@ class DockerAPI:
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't execute command: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
finally:
# cleanup container
@ -249,7 +258,7 @@ class DockerAPI:
denied_images.add(image_name)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Corrupt docker overlayfs detect: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
if not denied_images:
return False

View File

@ -26,7 +26,7 @@ from ..const import (
SECURITY_PROFILE,
)
from ..coresys import CoreSys
from ..exceptions import CoreDNSError, DockerAPIError
from ..exceptions import CoreDNSError, DockerError
from ..utils import process_lock
from .interface import DockerInterface
@ -419,7 +419,7 @@ class DockerAddon(DockerInterface):
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't build %s:%s: %s", self.image, tag, err)
raise DockerAPIError() from err
raise DockerError() from err
_LOGGER.info("Build %s:%s done", self.image, tag)
@ -437,7 +437,7 @@ class DockerAddon(DockerInterface):
image = self.sys_docker.api.get_image(f"{self.image}:{self.version}")
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't fetch image %s: %s", self.image, err)
raise DockerAPIError() from err
raise DockerError() from err
_LOGGER.info("Export image %s to %s", self.image, tar_file)
try:
@ -446,7 +446,7 @@ class DockerAddon(DockerInterface):
write_tar.write(chunk)
except (OSError, requests.RequestException) as err:
_LOGGER.error("Can't write tar file %s: %s", tar_file, err)
raise DockerAPIError() from err
raise DockerError() from err
_LOGGER.info("Export image %s done", self.image)
@ -467,12 +467,12 @@ class DockerAddon(DockerInterface):
docker_image = self.sys_docker.images.get(f"{self.image}:{self.version}")
except (docker.errors.DockerException, OSError) as err:
_LOGGER.error("Can't import image %s: %s", self.image, err)
raise DockerAPIError() from err
raise DockerError() from err
self._meta = docker_image.attrs
_LOGGER.info("Import image %s and version %s", tar_file, self.version)
with suppress(DockerAPIError):
with suppress(DockerError):
self._cleanup()
@process_lock
@ -486,7 +486,7 @@ class DockerAddon(DockerInterface):
Need run inside executor.
"""
if not self._is_running():
raise DockerAPIError()
raise DockerError()
try:
# Load needed docker objects
@ -494,7 +494,7 @@ class DockerAddon(DockerInterface):
socket = container.attach_socket(params={"stdin": 1, "stream": 1})
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't attach to %s stdin: %s", self.name, err)
raise DockerAPIError() from err
raise DockerError() from err
try:
# Write to stdin
@ -503,7 +503,7 @@ class DockerAddon(DockerInterface):
socket.close()
except OSError as err:
_LOGGER.error("Can't write to %s stdin: %s", self.name, err)
raise DockerAPIError() from err
raise DockerError() from err
def _stop(self, remove_container=True) -> None:
"""Stop/remove Docker container.

View File

@ -7,7 +7,7 @@ import docker
import requests
from ..const import ENV_TIME, ENV_TOKEN, ENV_TOKEN_HASSIO, LABEL_MACHINE, MACHINE_ID
from ..exceptions import DockerAPIError
from ..exceptions import DockerError
from .interface import CommandReturn, DockerInterface
_LOGGER: logging.Logger = logging.getLogger(__name__)
@ -177,7 +177,7 @@ class DockerHomeAssistant(DockerInterface):
except docker.errors.NotFound:
return False
except (docker.errors.DockerException, requests.RequestException):
return DockerAPIError()
return DockerError()
# we run on an old image, stop and start it
if docker_container.image.id != docker_image.id:

View File

@ -11,7 +11,7 @@ import requests
from . import CommandReturn
from ..const import LABEL_ARCH, LABEL_VERSION
from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import DockerAPIError
from ..exceptions import DockerAPIError, DockerError, DockerNotFound, DockerRequestError
from ..utils import process_lock
from .stats import DockerStats
@ -108,11 +108,11 @@ class DockerInterface(CoreSysAttributes):
"Available space in /data is: %s GiB",
free_space,
)
raise DockerAPIError() from err
raise DockerError() from err
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Unknown error with %s:%s -> %s", image, tag, err)
self.sys_capture_exception(err)
raise DockerAPIError() from err
raise DockerError() from err
else:
self._meta = docker_image.attrs
@ -146,8 +146,10 @@ class DockerInterface(CoreSysAttributes):
docker_container = self.sys_docker.containers.get(self.name)
except docker.errors.NotFound:
return False
except (docker.errors.DockerException, requests.RequestException) as err:
except docker.errors.DockerException as err:
raise DockerAPIError() from err
except requests.RequestException as err:
raise DockerRequestError() from err
return docker_container.status == "running"
@ -170,7 +172,7 @@ class DockerInterface(CoreSysAttributes):
# Successfull?
if not self._meta:
raise DockerAPIError()
raise DockerError()
_LOGGER.info("Attach to %s with version %s", self.image, self.version)
@process_lock
@ -200,7 +202,7 @@ class DockerInterface(CoreSysAttributes):
except docker.errors.NotFound:
return
except (docker.errors.DockerException, requests.RequestException) as err:
raise DockerAPIError() from err
raise DockerError() from err
if docker_container.status == "running":
_LOGGER.info("Stop %s application", self.name)
@ -226,14 +228,14 @@ class DockerInterface(CoreSysAttributes):
docker_container = self.sys_docker.containers.get(self.name)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("%s not found for starting up", self.name)
raise DockerAPIError() from err
raise DockerError() from err
_LOGGER.info("Start %s", self.name)
try:
docker_container.start()
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't start %s: %s", self.name, err)
raise DockerAPIError() from err
raise DockerError() from err
@process_lock
def remove(self) -> Awaitable[None]:
@ -246,7 +248,7 @@ class DockerInterface(CoreSysAttributes):
Needs run inside executor.
"""
# Cleanup container
with suppress(DockerAPIError):
with suppress(DockerError):
self._stop()
_LOGGER.info("Remove image %s with latest and %s", self.image, self.version)
@ -262,7 +264,7 @@ class DockerInterface(CoreSysAttributes):
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.warning("Can't remove image %s: %s", self.image, err)
raise DockerAPIError() from err
raise DockerError() from err
self._meta = None
@ -290,7 +292,7 @@ class DockerInterface(CoreSysAttributes):
self._install(tag, image=image, latest=latest)
# Stop container & cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
self._stop()
def logs(self) -> Awaitable[bytes]:
@ -331,14 +333,14 @@ class DockerInterface(CoreSysAttributes):
origin = self.sys_docker.images.get(f"{self.image}:{self.version}")
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.warning("Can't find %s for cleanup", self.image)
raise DockerAPIError() from err
raise DockerError() from err
# Cleanup Current
try:
images_list = self.sys_docker.images.list(name=self.image)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.waring("Corrupt docker overlayfs found: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
for image in images_list:
if origin.id == image.id:
@ -356,7 +358,7 @@ class DockerInterface(CoreSysAttributes):
images_list = self.sys_docker.images.list(name=old_image)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.waring("Corrupt docker overlayfs found: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
for image in images_list:
with suppress(docker.errors.DockerException, requests.RequestException):
@ -376,14 +378,14 @@ class DockerInterface(CoreSysAttributes):
try:
container = self.sys_docker.containers.get(self.name)
except (docker.errors.DockerException, requests.RequestException) as err:
raise DockerAPIError() from err
raise DockerError() from err
_LOGGER.info("Restart %s", self.image)
try:
container.restart(timeout=self.timeout)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.warning("Can't restart %s: %s", self.image, err)
raise DockerAPIError() from err
raise DockerError() from err
@process_lock
def execute_command(self, command: str) -> Awaitable[CommandReturn]:
@ -409,14 +411,14 @@ class DockerInterface(CoreSysAttributes):
try:
docker_container = self.sys_docker.containers.get(self.name)
except (docker.errors.DockerException, requests.RequestException) as err:
raise DockerAPIError() from err
raise DockerError() from err
try:
stats = docker_container.stats(stream=False)
return DockerStats(stats)
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't read stats from %s: %s", self.name, err)
raise DockerAPIError() from err
raise DockerError() from err
def is_failed(self) -> Awaitable[bool]:
"""Return True if Docker is failing state.
@ -435,7 +437,7 @@ class DockerInterface(CoreSysAttributes):
except docker.errors.NotFound:
return False
except (docker.errors.DockerException, requests.RequestException) as err:
raise DockerAPIError() from err
raise DockerError() from err
# container is not running
if docker_container.status != "exited":
@ -469,7 +471,10 @@ class DockerInterface(CoreSysAttributes):
except (docker.errors.DockerException, ValueError) as err:
_LOGGER.debug("No version found for %s", self.image)
raise DockerAPIError() from err
raise DockerNotFound() from err
except requests.RequestException as err:
_LOGGER.warning("Communication issues with dockerd on Host: %s", err)
raise DockerRequestError() from err
else:
_LOGGER.debug("Found %s versions: %s", self.image, available_version)

View File

@ -8,7 +8,7 @@ import docker
import requests
from ..const import DOCKER_NETWORK, DOCKER_NETWORK_MASK, DOCKER_NETWORK_RANGE
from ..exceptions import DockerAPIError
from ..exceptions import DockerError
_LOGGER: logging.Logger = logging.getLogger(__name__)
@ -113,7 +113,7 @@ class DockerNetwork:
self.network.connect(container, aliases=alias, ipv4_address=ipv4_address)
except docker.errors.APIError as err:
_LOGGER.error("Can't link container to hassio-net: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
self.network.reload()
@ -133,7 +133,7 @@ class DockerNetwork:
except docker.errors.APIError as err:
_LOGGER.warning("Can't disconnect container from default: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
def stale_cleanup(self, container_name: str):
"""Remove force a container from Network.

View File

@ -8,7 +8,7 @@ import docker
import requests
from ..coresys import CoreSysAttributes
from ..exceptions import DockerAPIError
from ..exceptions import DockerError
from .interface import DockerInterface
_LOGGER: logging.Logger = logging.getLogger(__name__)
@ -40,7 +40,7 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes):
try:
docker_container = self.sys_docker.containers.get(self.name)
except (docker.errors.DockerException, requests.RequestException) as err:
raise DockerAPIError() from err
raise DockerError() from err
self._meta = docker_container.attrs
_LOGGER.info(
@ -77,7 +77,7 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes):
docker_container.image.tag(self.image, tag="latest")
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't retag supervisor version: %s", err)
raise DockerAPIError() from err
raise DockerError() from err
def update_start_tag(self, image: str, version: str) -> Awaitable[None]:
"""Update start tag to new version."""
@ -104,4 +104,4 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes):
except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't fix start tag: %s", err)
raise DockerAPIError() from err
raise DockerError() from err

View File

@ -238,10 +238,22 @@ class JsonFileError(HassioError):
# docker/api
class DockerAPIError(HassioError):
class DockerError(HassioError):
"""Docker API/Transport errors."""
class DockerAPIError(DockerError):
"""Docker API error."""
class DockerRequestError(DockerError):
"""Dockerd OS issues."""
class DockerNotFound(DockerError):
"""Docker object don't Exists."""
# Hardware

View File

@ -15,7 +15,7 @@ from packaging import version as pkg_version
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.homeassistant import DockerHomeAssistant
from ..docker.stats import DockerStats
from ..exceptions import DockerAPIError, HomeAssistantError, HomeAssistantUpdateError
from ..exceptions import DockerError, HomeAssistantError, HomeAssistantUpdateError
from ..utils import convert_to_ascii, process_lock
_LOGGER: logging.Logger = logging.getLogger(__name__)
@ -58,7 +58,7 @@ class HomeAssistantCore(CoreSysAttributes):
)
await self.instance.attach(tag=self.sys_homeassistant.version)
except DockerAPIError:
except DockerError:
_LOGGER.info(
"No Home Assistant Docker image %s found.", self.sys_homeassistant.image
)
@ -85,7 +85,7 @@ class HomeAssistantCore(CoreSysAttributes):
await self.instance.install(
LANDINGPAGE, image=self.sys_updater.image_homeassistant
)
except DockerAPIError:
except DockerError:
_LOGGER.warning("Fails install landingpage, retry after 30sec")
await asyncio.sleep(30)
except Exception as err: # pylint: disable=broad-except
@ -117,7 +117,7 @@ class HomeAssistantCore(CoreSysAttributes):
tag, image=self.sys_updater.image_homeassistant
)
break
except DockerAPIError:
except DockerError:
pass
except Exception as err: # pylint: disable=broad-except
self.sys_capture_exception(err)
@ -138,7 +138,7 @@ class HomeAssistantCore(CoreSysAttributes):
_LOGGER.error("Can't start Home Assistant!")
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup()
@process_lock
@ -162,7 +162,7 @@ class HomeAssistantCore(CoreSysAttributes):
await self.instance.update(
to_version, image=self.sys_updater.image_homeassistant
)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.warning("Update Home Assistant image failed")
raise HomeAssistantUpdateError() from err
else:
@ -175,7 +175,7 @@ class HomeAssistantCore(CoreSysAttributes):
# Successfull - last step
self.sys_homeassistant.save_data()
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Update Home Assistant
@ -212,7 +212,7 @@ class HomeAssistantCore(CoreSysAttributes):
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
raise HomeAssistantError() from err
await self._block_till_run(self.sys_homeassistant.version)
@ -228,7 +228,7 @@ class HomeAssistantCore(CoreSysAttributes):
if await self.instance.is_initialize():
try:
await self.instance.start()
except DockerAPIError as err:
except DockerError as err:
raise HomeAssistantError() from err
await self._block_till_run(self.sys_homeassistant.version)
@ -244,7 +244,7 @@ class HomeAssistantCore(CoreSysAttributes):
"""
try:
return await self.instance.stop(remove_container=False)
except DockerAPIError as err:
except DockerError as err:
raise HomeAssistantError() from err
@process_lock
@ -252,7 +252,7 @@ class HomeAssistantCore(CoreSysAttributes):
"""Restart Home Assistant Docker."""
try:
await self.instance.restart()
except DockerAPIError as err:
except DockerError as err:
raise HomeAssistantError() from err
await self._block_till_run(self.sys_homeassistant.version)
@ -260,7 +260,7 @@ class HomeAssistantCore(CoreSysAttributes):
@process_lock
async def rebuild(self) -> None:
"""Rebuild Home Assistant Docker container."""
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.stop()
await self._start()
@ -278,7 +278,7 @@ class HomeAssistantCore(CoreSysAttributes):
"""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise HomeAssistantError() from err
def is_running(self) -> Awaitable[bool]:
@ -407,5 +407,5 @@ class HomeAssistantCore(CoreSysAttributes):
# Pull image
try:
await self.instance.install(self.sys_homeassistant.version)
except DockerAPIError:
except DockerError:
_LOGGER.error("Repairing of Home Assistant failed")

View File

@ -15,7 +15,7 @@ from ..const import ATTR_IMAGE, ATTR_VERSION
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.audio import DockerAudio
from ..docker.stats import DockerStats
from ..exceptions import AudioError, AudioUpdateError, DockerAPIError
from ..exceptions import AudioError, AudioUpdateError, DockerError
from ..utils.json import JsonConfig
from .const import FILE_HASSIO_AUDIO
from .validate import SCHEMA_AUDIO_CONFIG
@ -92,7 +92,7 @@ class Audio(JsonConfig, CoreSysAttributes):
self.version = await self.instance.get_latest_version()
await self.instance.attach(tag=self.version)
except DockerAPIError:
except DockerError:
_LOGGER.info("No Audio plugin Docker image %s found.", self.instance.image)
# Install PulseAudio
@ -131,7 +131,7 @@ class Audio(JsonConfig, CoreSysAttributes):
await self.sys_updater.reload()
if self.latest_version:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(
self.latest_version, image=self.sys_updater.image_audio
)
@ -155,7 +155,7 @@ class Audio(JsonConfig, CoreSysAttributes):
try:
await self.instance.update(version, image=self.sys_updater.image_audio)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Audio update failed")
raise AudioUpdateError() from err
else:
@ -164,7 +164,7 @@ class Audio(JsonConfig, CoreSysAttributes):
self.save_data()
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Start Audio
@ -175,7 +175,7 @@ class Audio(JsonConfig, CoreSysAttributes):
_LOGGER.info("Restart Audio plugin")
try:
await self.instance.restart()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start Audio plugin")
raise AudioError() from err
@ -184,7 +184,7 @@ class Audio(JsonConfig, CoreSysAttributes):
_LOGGER.info("Start Audio plugin")
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start Audio plugin")
raise AudioError() from err
@ -193,7 +193,7 @@ class Audio(JsonConfig, CoreSysAttributes):
_LOGGER.info("Stop Audio plugin")
try:
await self.instance.stop()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't stop Audio plugin")
raise AudioError() from err
@ -208,7 +208,7 @@ class Audio(JsonConfig, CoreSysAttributes):
"""Return stats of CoreDNS."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise AudioError() from err
def is_running(self) -> Awaitable[bool]:
@ -226,7 +226,7 @@ class Audio(JsonConfig, CoreSysAttributes):
_LOGGER.info("Repair Audio %s", self.version)
try:
await self.instance.install(self.version)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Repairing of Audio failed")
self.sys_capture_exception(err)

View File

@ -12,7 +12,7 @@ from ..const import ATTR_ACCESS_TOKEN, ATTR_IMAGE, ATTR_VERSION
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.cli import DockerCli
from ..docker.stats import DockerStats
from ..exceptions import CliError, CliUpdateError, DockerAPIError
from ..exceptions import CliError, CliUpdateError, DockerError
from ..utils.json import JsonConfig
from .const import FILE_HASSIO_CLI
from .validate import SCHEMA_CLI_CONFIG
@ -80,7 +80,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
self.version = await self.instance.get_latest_version()
await self.instance.attach(tag=self.version)
except DockerAPIError:
except DockerError:
_LOGGER.info("No cli plugin Docker image %s found.", self.instance.image)
# Install cli
@ -105,7 +105,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
await self.sys_updater.reload()
if self.latest_version:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(
self.latest_version,
image=self.sys_updater.image_cli,
@ -133,7 +133,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
await self.instance.update(
version, image=self.sys_updater.image_cli, latest=True
)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("HA cli update failed")
raise CliUpdateError() from err
else:
@ -142,7 +142,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
self.save_data()
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Start cli
@ -158,7 +158,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
_LOGGER.info("Start cli plugin")
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start cli plugin")
raise CliError() from err
@ -167,7 +167,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
_LOGGER.info("Stop cli plugin")
try:
await self.instance.stop()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't stop cli plugin")
raise CliError() from err
@ -175,7 +175,7 @@ class HaCli(CoreSysAttributes, JsonConfig):
"""Return stats of cli."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise CliError() from err
def is_running(self) -> Awaitable[bool]:
@ -193,6 +193,6 @@ class HaCli(CoreSysAttributes, JsonConfig):
_LOGGER.info("Repair HA cli %s", self.version)
try:
await self.instance.install(self.version, latest=True)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Repairing of HA cli failed")
self.sys_capture_exception(err)

View File

@ -17,7 +17,7 @@ from ..const import ATTR_IMAGE, ATTR_SERVERS, ATTR_VERSION, DNS_SUFFIX, LogLevel
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.dns import DockerDNS
from ..docker.stats import DockerStats
from ..exceptions import CoreDNSError, CoreDNSUpdateError, DockerAPIError
from ..exceptions import CoreDNSError, CoreDNSUpdateError, DockerError
from ..utils.json import JsonConfig
from ..validate import dns_url
from .const import FILE_HASSIO_DNS
@ -120,7 +120,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
self.version = await self.instance.get_latest_version()
await self.instance.attach(tag=self.version)
except DockerAPIError:
except DockerError:
_LOGGER.info(
"No CoreDNS plugin Docker image %s found.", self.instance.image
)
@ -162,7 +162,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
await self.sys_updater.reload()
if self.latest_version:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(
self.latest_version, image=self.sys_updater.image_dns
)
@ -190,7 +190,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
# Update
try:
await self.instance.update(version, image=self.sys_updater.image_dns)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("CoreDNS update failed")
raise CoreDNSUpdateError() from err
else:
@ -199,7 +199,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
self.save_data()
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Start CoreDNS
@ -211,7 +211,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.info("Restart CoreDNS plugin")
try:
await self.instance.restart()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start CoreDNS plugin")
raise CoreDNSError() from err
@ -223,7 +223,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.info("Start CoreDNS plugin")
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start CoreDNS plugin")
raise CoreDNSError() from err
@ -232,7 +232,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.info("Stop CoreDNS plugin")
try:
await self.instance.stop()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't stop CoreDNS plugin")
raise CoreDNSError() from err
@ -389,7 +389,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
"""Return stats of CoreDNS."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise CoreDNSError() from err
def is_running(self) -> Awaitable[bool]:
@ -414,7 +414,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.info("Repair CoreDNS %s", self.version)
try:
await self.instance.install(self.version)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Repairing of CoreDNS failed")
self.sys_capture_exception(err)

View File

@ -11,7 +11,7 @@ from ..const import ATTR_IMAGE, ATTR_VERSION
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.multicast import DockerMulticast
from ..docker.stats import DockerStats
from ..exceptions import DockerAPIError, MulticastError, MulticastUpdateError
from ..exceptions import DockerError, MulticastError, MulticastUpdateError
from ..utils.json import JsonConfig
from .const import FILE_HASSIO_MULTICAST
from .validate import SCHEMA_MULTICAST_CONFIG
@ -74,7 +74,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
self.version = await self.instance.get_latest_version()
await self.instance.attach(tag=self.version)
except DockerAPIError:
except DockerError:
_LOGGER.info(
"No Multicast plugin Docker image %s found.", self.instance.image
)
@ -103,7 +103,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
await self.sys_updater.reload()
if self.latest_version:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(
self.latest_version, image=self.sys_updater.image_multicast
)
@ -128,7 +128,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
# Update
try:
await self.instance.update(version, image=self.sys_updater.image_multicast)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Multicast update failed")
raise MulticastUpdateError() from err
else:
@ -137,7 +137,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
self.save_data()
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Start Multicast plugin
@ -148,7 +148,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
_LOGGER.info("Restart Multicast plugin")
try:
await self.instance.restart()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start Multicast plugin")
raise MulticastError() from err
@ -157,7 +157,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
_LOGGER.info("Start Multicast plugin")
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start Multicast plugin")
raise MulticastError() from err
@ -166,7 +166,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
_LOGGER.info("Stop Multicast plugin")
try:
await self.instance.stop()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't stop Multicast plugin")
raise MulticastError() from err
@ -181,7 +181,7 @@ class Multicast(JsonConfig, CoreSysAttributes):
"""Return stats of Multicast."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise MulticastError() from err
def is_running(self) -> Awaitable[bool]:
@ -206,6 +206,6 @@ class Multicast(JsonConfig, CoreSysAttributes):
_LOGGER.info("Repair Multicast %s", self.version)
try:
await self.instance.install(self.version)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Repairing of Multicast failed")
self.sys_capture_exception(err)

View File

@ -12,7 +12,7 @@ from ..const import ATTR_ACCESS_TOKEN, ATTR_IMAGE, ATTR_VERSION
from ..coresys import CoreSys, CoreSysAttributes
from ..docker.observer import DockerObserver
from ..docker.stats import DockerStats
from ..exceptions import DockerAPIError, ObserverError, ObserverUpdateError
from ..exceptions import DockerError, ObserverError, ObserverUpdateError
from ..utils.json import JsonConfig
from .const import FILE_HASSIO_OBSERVER
from .validate import SCHEMA_OBSERVER_CONFIG
@ -80,7 +80,7 @@ class Observer(CoreSysAttributes, JsonConfig):
self.version = await self.instance.get_latest_version()
await self.instance.attach(tag=self.version)
except DockerAPIError:
except DockerError:
_LOGGER.info(
"No observer plugin Docker image %s found.", self.instance.image
)
@ -107,7 +107,7 @@ class Observer(CoreSysAttributes, JsonConfig):
await self.sys_updater.reload()
if self.latest_version:
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.install(
self.latest_version, image=self.sys_updater.image_observer
)
@ -131,7 +131,7 @@ class Observer(CoreSysAttributes, JsonConfig):
try:
await self.instance.update(version, image=self.sys_updater.image_observer)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("HA observer update failed")
raise ObserverUpdateError() from err
else:
@ -140,7 +140,7 @@ class Observer(CoreSysAttributes, JsonConfig):
self.save_data()
# Cleanup
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup(old_image=old_image)
# Start observer
@ -157,7 +157,7 @@ class Observer(CoreSysAttributes, JsonConfig):
_LOGGER.info("Start observer plugin")
try:
await self.instance.run()
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Can't start observer plugin")
raise ObserverError() from err
@ -165,7 +165,7 @@ class Observer(CoreSysAttributes, JsonConfig):
"""Return stats of observer."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise ObserverError() from err
def is_running(self) -> Awaitable[bool]:
@ -183,6 +183,6 @@ class Observer(CoreSysAttributes, JsonConfig):
_LOGGER.info("Repair HA observer %s", self.version)
try:
await self.instance.install(self.version)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Repairing of HA observer failed")
self.sys_capture_exception(err)

View File

@ -14,7 +14,7 @@ from .coresys import CoreSys, CoreSysAttributes
from .docker.stats import DockerStats
from .docker.supervisor import DockerSupervisor
from .exceptions import (
DockerAPIError,
DockerError,
HostAppArmorError,
SupervisorError,
SupervisorUpdateError,
@ -35,10 +35,10 @@ class Supervisor(CoreSysAttributes):
"""Prepare Home Assistant object."""
try:
await self.instance.attach(tag="latest")
except DockerAPIError:
except DockerError:
_LOGGER.critical("Can't setup Supervisor Docker container!")
with suppress(DockerAPIError):
with suppress(DockerError):
await self.instance.cleanup()
@property
@ -115,7 +115,7 @@ class Supervisor(CoreSysAttributes):
await self.instance.update_start_tag(
self.sys_updater.image_supervisor, version
)
except DockerAPIError as err:
except DockerError as err:
_LOGGER.error("Update of Supervisor failed!")
raise SupervisorUpdateError() from err
else:
@ -142,7 +142,7 @@ class Supervisor(CoreSysAttributes):
"""Return stats of Supervisor."""
try:
return await self.instance.stats()
except DockerAPIError as err:
except DockerError as err:
raise SupervisorError() from err
async def repair(self):
@ -153,5 +153,5 @@ class Supervisor(CoreSysAttributes):
_LOGGER.info("Repair Supervisor %s", self.version)
try:
await self.instance.retag()
except DockerAPIError:
except DockerError:
_LOGGER.error("Repairing of Supervisor failed")