From fe6634551a707c07ddb9b90a5259637a800b9c33 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 15 Aug 2020 23:01:10 +0200 Subject: [PATCH] Catch requests with docker exceptions (#1926) --- supervisor/docker/__init__.py | 11 ++++--- supervisor/docker/addon.py | 11 +++---- supervisor/docker/audio.py | 5 +-- supervisor/docker/cli.py | 5 +-- supervisor/docker/dns.py | 5 +-- supervisor/docker/homeassistant.py | 9 +++--- supervisor/docker/interface.py | 50 ++++++++++++++++++------------ supervisor/docker/multicast.py | 5 +-- supervisor/docker/network.py | 9 ++++-- supervisor/docker/supervisor.py | 7 +++-- 10 files changed, 60 insertions(+), 57 deletions(-) diff --git a/supervisor/docker/__init__.py b/supervisor/docker/__init__.py index 06fabbe9d..0edab3b37 100644 --- a/supervisor/docker/__init__.py +++ b/supervisor/docker/__init__.py @@ -8,6 +8,7 @@ from typing import Any, Dict, Optional import attr import docker from packaging import version as pkg_version +import requests from ..const import DNS_SUFFIX, DOCKER_IMAGE_DENYLIST, SOCKET_DOCKER from ..exceptions import DockerAPIError @@ -128,7 +129,7 @@ class DockerAPI: container = self.docker.containers.create( f"{image}:{version}", use_config_proxy=False, **kwargs ) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't create container from %s: %s", name, err) raise DockerAPIError() @@ -146,12 +147,12 @@ class DockerAPI: # Run container try: container.start() - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't start %s: %s", name, err) raise DockerAPIError() # Update metadata - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): container.reload() return container @@ -184,13 +185,13 @@ class DockerAPI: result = container.wait() output = container.logs(stdout=stdout, stderr=stderr) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't execute command: %s", err) raise DockerAPIError() finally: # cleanup container - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): container.remove(force=True) return CommandReturn(result.get("StatusCode"), output) diff --git a/supervisor/docker/addon.py b/supervisor/docker/addon.py index 2a115056d..512bb6499 100644 --- a/supervisor/docker/addon.py +++ b/supervisor/docker/addon.py @@ -334,8 +334,7 @@ class DockerAddon(DockerInterface): _LOGGER.warning("%s run with disabled protected mode!", self.addon.name) # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( @@ -396,7 +395,7 @@ class DockerAddon(DockerInterface): # Update meta data self._meta = image.attrs - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't build %s:%s: %s", self.image, tag, err) raise DockerAPIError() @@ -414,7 +413,7 @@ class DockerAddon(DockerInterface): """ try: image = self.sys_docker.api.get_image(f"{self.image}:{self.version}") - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't fetch image %s: %s", self.image, err) raise DockerAPIError() @@ -423,7 +422,7 @@ class DockerAddon(DockerInterface): with tar_file.open("wb") as write_tar: for chunk in image: write_tar.write(chunk) - except (OSError, requests.exceptions.ReadTimeout) as err: + except (OSError, requests.RequestException) as err: _LOGGER.error("Can't write tar file %s: %s", tar_file, err) raise DockerAPIError() @@ -471,7 +470,7 @@ class DockerAddon(DockerInterface): # Load needed docker objects container = self.sys_docker.containers.get(self.name) socket = container.attach_socket(params={"stdin": 1, "stream": 1}) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't attach to %s stdin: %s", self.name, err) raise DockerAPIError() diff --git a/supervisor/docker/audio.py b/supervisor/docker/audio.py index aea0d4d89..b98c47c16 100644 --- a/supervisor/docker/audio.py +++ b/supervisor/docker/audio.py @@ -1,12 +1,10 @@ """Audio docker object.""" -from contextlib import suppress import logging from pathlib import Path from typing import Dict from ..const import ENV_TIME, MACHINE_ID from ..coresys import CoreSysAttributes -from ..exceptions import DockerAPIError from .interface import DockerInterface _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -56,8 +54,7 @@ class DockerAudio(DockerInterface, CoreSysAttributes): return # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( diff --git a/supervisor/docker/cli.py b/supervisor/docker/cli.py index 13b5595ec..6ce6e1140 100644 --- a/supervisor/docker/cli.py +++ b/supervisor/docker/cli.py @@ -1,10 +1,8 @@ """HA Cli docker object.""" -from contextlib import suppress import logging from ..const import ENV_TIME, ENV_TOKEN from ..coresys import CoreSysAttributes -from ..exceptions import DockerAPIError from .interface import DockerInterface _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -34,8 +32,7 @@ class DockerCli(DockerInterface, CoreSysAttributes): return # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( diff --git a/supervisor/docker/dns.py b/supervisor/docker/dns.py index 83dae412f..d664261cc 100644 --- a/supervisor/docker/dns.py +++ b/supervisor/docker/dns.py @@ -1,10 +1,8 @@ """DNS docker object.""" -from contextlib import suppress import logging from ..const import ENV_TIME from ..coresys import CoreSysAttributes -from ..exceptions import DockerAPIError from .interface import DockerInterface _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -34,8 +32,7 @@ class DockerDNS(DockerInterface, CoreSysAttributes): return # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( diff --git a/supervisor/docker/homeassistant.py b/supervisor/docker/homeassistant.py index 034b28210..6b2c7f715 100644 --- a/supervisor/docker/homeassistant.py +++ b/supervisor/docker/homeassistant.py @@ -1,10 +1,10 @@ """Init file for Supervisor Docker object.""" -from contextlib import suppress from ipaddress import IPv4Address import logging from typing import Awaitable, Dict, Optional import docker +import requests from ..const import ENV_TIME, ENV_TOKEN, ENV_TOKEN_OLD, LABEL_MACHINE, MACHINE_ID from ..exceptions import DockerAPIError @@ -98,8 +98,7 @@ class DockerHomeAssistant(DockerInterface): return # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( @@ -167,8 +166,10 @@ class DockerHomeAssistant(DockerInterface): docker_image = self.sys_docker.images.get( f"{self.image}:{self.sys_homeassistant.version}" ) - except docker.errors.DockerException: + except docker.errors.NotFound: return False + except (docker.errors.DockerException, requests.RequestException): + return DockerAPIError() # we run on an old image, stop and start it if docker_container.image.id != docker_image.id: diff --git a/supervisor/docker/interface.py b/supervisor/docker/interface.py index 85da16e90..26c9a233b 100644 --- a/supervisor/docker/interface.py +++ b/supervisor/docker/interface.py @@ -5,6 +5,7 @@ import logging from typing import Any, Awaitable, Dict, List, Optional import docker +import requests from . import CommandReturn from ..const import LABEL_ARCH, LABEL_VERSION @@ -107,6 +108,10 @@ class DockerInterface(CoreSysAttributes): free_space, ) raise DockerAPIError() + 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() else: self._meta = docker_image.attrs @@ -119,7 +124,7 @@ class DockerInterface(CoreSysAttributes): Need run inside executor. """ - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): self.sys_docker.images.get(f"{self.image}:{self.version}") return True return False @@ -138,8 +143,10 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except docker.errors.NotFound: return False + except (docker.errors.DockerException, requests.RequestException): + raise DockerAPIError() return docker_container.status == "running" @@ -153,10 +160,10 @@ class DockerInterface(CoreSysAttributes): Need run inside executor. """ - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): self._meta = self.sys_docker.containers.get(self.name).attrs - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): if not self._meta and self.image: self._meta = self.sys_docker.images.get(f"{self.image}:{tag}").attrs @@ -189,16 +196,18 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except docker.errors.NotFound: + return + except (docker.errors.DockerException, requests.RequestException): raise DockerAPIError() if docker_container.status == "running": _LOGGER.info("Stop %s application", self.name) - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): docker_container.stop(timeout=self.timeout) if remove_container: - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): _LOGGER.info("Clean %s application", self.name) docker_container.remove(force=True) @@ -214,13 +223,14 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): + _LOGGER.error("%s not found for starting up", self.name) raise DockerAPIError() _LOGGER.info("Start %s", self.name) try: docker_container.start() - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't start %s: %s", self.name, err) raise DockerAPIError() @@ -249,7 +259,7 @@ class DockerInterface(CoreSysAttributes): image=f"{self.image}:{self.version}", force=True ) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.warning("Can't remove image %s: %s", self.image, err) raise DockerAPIError() @@ -296,12 +306,12 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): return b"" try: return docker_container.logs(tail=100, stdout=True, stderr=True) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.warning("Can't grep logs from %s: %s", self.image, err) return b"" @@ -318,7 +328,7 @@ class DockerInterface(CoreSysAttributes): """ try: origin = self.sys_docker.images.get(f"{self.image}:{self.version}") - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): _LOGGER.warning("Can't find %s for cleanup", self.image) raise DockerAPIError() @@ -327,7 +337,7 @@ class DockerInterface(CoreSysAttributes): if origin.id == image.id: continue - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): _LOGGER.info("Cleanup images: %s", image.tags) self.sys_docker.images.remove(image.id, force=True) @@ -336,7 +346,7 @@ class DockerInterface(CoreSysAttributes): return for image in self.sys_docker.images.list(name=old_image): - with suppress(docker.errors.DockerException): + with suppress(docker.errors.DockerException, requests.RequestException): _LOGGER.info("Cleanup images: %s", image.tags) self.sys_docker.images.remove(image.id, force=True) @@ -352,13 +362,13 @@ class DockerInterface(CoreSysAttributes): """ try: container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): raise DockerAPIError() _LOGGER.info("Restart %s", self.image) try: container.restart(timeout=self.timeout) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.warning("Can't restart %s: %s", self.image, err) raise DockerAPIError() @@ -385,13 +395,13 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): raise DockerAPIError() try: stats = docker_container.stats(stream=False) return DockerStats(stats) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't read stats from %s: %s", self.name, err) raise DockerAPIError() @@ -409,7 +419,7 @@ class DockerInterface(CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): return False # container is not running diff --git a/supervisor/docker/multicast.py b/supervisor/docker/multicast.py index f6e8f8cdd..f0de4accf 100644 --- a/supervisor/docker/multicast.py +++ b/supervisor/docker/multicast.py @@ -1,10 +1,8 @@ """HA Cli docker object.""" -from contextlib import suppress import logging from ..const import ENV_TIME from ..coresys import CoreSysAttributes -from ..exceptions import DockerAPIError from .interface import DockerInterface _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -34,8 +32,7 @@ class DockerMulticast(DockerInterface, CoreSysAttributes): return # Cleanup - with suppress(DockerAPIError): - self._stop() + self._stop() # Create & Run container docker_container = self.sys_docker.run( diff --git a/supervisor/docker/network.py b/supervisor/docker/network.py index dc683c714..d6eb7ceec 100644 --- a/supervisor/docker/network.py +++ b/supervisor/docker/network.py @@ -5,6 +5,7 @@ import logging from typing import List, Optional import docker +import requests from ..const import DOCKER_NETWORK, DOCKER_NETWORK_MASK, DOCKER_NETWORK_RANGE from ..exceptions import DockerAPIError @@ -35,9 +36,11 @@ class DockerNetwork: for cid, data in self.network.attrs.get("Containers", {}).items(): try: containers.append(self.docker.containers.get(cid)) - except docker.errors.APIError as err: - _LOGGER.warning("Docker network is corrupt! %s - run autofix", err) + except docker.errors.NotFound: + _LOGGER.warning("Docker network is corrupt! %s - run autofix", cid) self.stale_cleanup(data.get("Name", cid)) + except (docker.errors.DockerException, requests.RequestException) as err: + _LOGGER.error("Unknown error with container lookup %s", err) return containers @@ -132,5 +135,5 @@ class DockerNetwork: Fix: https://github.com/moby/moby/issues/23302 """ - with suppress(docker.errors.APIError): + with suppress(docker.errors.DockerException, requests.RequestException): self.network.disconnect(container_name, force=True) diff --git a/supervisor/docker/supervisor.py b/supervisor/docker/supervisor.py index 88ff24977..fe6b67043 100644 --- a/supervisor/docker/supervisor.py +++ b/supervisor/docker/supervisor.py @@ -5,6 +5,7 @@ import os from typing import Awaitable import docker +import requests from ..coresys import CoreSysAttributes from ..exceptions import DockerAPIError @@ -38,7 +39,7 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes): """ try: docker_container = self.sys_docker.containers.get(self.name) - except docker.errors.DockerException: + except (docker.errors.DockerException, requests.RequestException): raise DockerAPIError() self._meta = docker_container.attrs @@ -74,7 +75,7 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes): docker_container.image.tag(self.image, tag=self.version) docker_container.image.tag(self.image, tag="latest") - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't retag supervisor version: %s", err) raise DockerAPIError() @@ -101,6 +102,6 @@ class DockerSupervisor(DockerInterface, CoreSysAttributes): continue docker_image.tag(start_image, start_tag) - except docker.errors.DockerException as err: + except (docker.errors.DockerException, requests.RequestException) as err: _LOGGER.error("Can't fix start tag: %s", err) raise DockerAPIError()