mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-27 11:06:32 +00:00
Direct import from docker modules to get better typing (#3266)
This commit is contained in:
parent
a902b55df7
commit
828cf773cc
@ -8,7 +8,12 @@ from typing import Any, Optional
|
|||||||
|
|
||||||
import attr
|
import attr
|
||||||
from awesomeversion import AwesomeVersion, AwesomeVersionCompare
|
from awesomeversion import AwesomeVersion, AwesomeVersionCompare
|
||||||
import docker
|
from docker import errors as docker_errors
|
||||||
|
from docker.api.client import APIClient
|
||||||
|
from docker.client import DockerClient
|
||||||
|
from docker.models.containers import Container, ContainerCollection
|
||||||
|
from docker.models.images import ImageCollection
|
||||||
|
from docker.models.networks import Network
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from ..const import (
|
from ..const import (
|
||||||
@ -90,7 +95,7 @@ class DockerAPI:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize Docker base wrapper."""
|
"""Initialize Docker base wrapper."""
|
||||||
self.docker: docker.DockerClient = docker.DockerClient(
|
self.docker: DockerClient = DockerClient(
|
||||||
base_url=f"unix:/{str(SOCKET_DOCKER)}", version="auto", timeout=900
|
base_url=f"unix:/{str(SOCKET_DOCKER)}", version="auto", timeout=900
|
||||||
)
|
)
|
||||||
self.network: DockerNetwork = DockerNetwork(self.docker)
|
self.network: DockerNetwork = DockerNetwork(self.docker)
|
||||||
@ -98,17 +103,17 @@ class DockerAPI:
|
|||||||
self.config: DockerConfig = DockerConfig()
|
self.config: DockerConfig = DockerConfig()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def images(self) -> docker.models.images.ImageCollection:
|
def images(self) -> ImageCollection:
|
||||||
"""Return API images."""
|
"""Return API images."""
|
||||||
return self.docker.images
|
return self.docker.images
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def containers(self) -> docker.models.containers.ContainerCollection:
|
def containers(self) -> ContainerCollection:
|
||||||
"""Return API containers."""
|
"""Return API containers."""
|
||||||
return self.docker.containers
|
return self.docker.containers
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def api(self) -> docker.APIClient:
|
def api(self) -> APIClient:
|
||||||
"""Return API containers."""
|
"""Return API containers."""
|
||||||
return self.docker.api
|
return self.docker.api
|
||||||
|
|
||||||
@ -124,7 +129,7 @@ class DockerAPI:
|
|||||||
dns: bool = True,
|
dns: bool = True,
|
||||||
ipv4: Optional[IPv4Address] = None,
|
ipv4: Optional[IPv4Address] = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> docker.models.containers.Container:
|
) -> Container:
|
||||||
"""Create a Docker container and run it.
|
"""Create a Docker container and run it.
|
||||||
|
|
||||||
Need run inside executor.
|
Need run inside executor.
|
||||||
@ -148,11 +153,11 @@ class DockerAPI:
|
|||||||
container = self.docker.containers.create(
|
container = self.docker.containers.create(
|
||||||
f"{image}:{tag}", use_config_proxy=False, **kwargs
|
f"{image}:{tag}", use_config_proxy=False, **kwargs
|
||||||
)
|
)
|
||||||
except docker.errors.NotFound as err:
|
except docker_errors.NotFound as err:
|
||||||
raise DockerNotFound(
|
raise DockerNotFound(
|
||||||
f"Image {image} not exists for {name}", _LOGGER.error
|
f"Image {image} not exists for {name}", _LOGGER.error
|
||||||
) from err
|
) from err
|
||||||
except docker.errors.DockerException as err:
|
except docker_errors.DockerException as err:
|
||||||
raise DockerAPIError(
|
raise DockerAPIError(
|
||||||
f"Can't create container from {name}: {err}", _LOGGER.error
|
f"Can't create container from {name}: {err}", _LOGGER.error
|
||||||
) from err
|
) from err
|
||||||
@ -172,9 +177,7 @@ class DockerAPI:
|
|||||||
with suppress(DockerError):
|
with suppress(DockerError):
|
||||||
self.network.detach_default_bridge(container)
|
self.network.detach_default_bridge(container)
|
||||||
else:
|
else:
|
||||||
host_network: docker.models.networks.Network = self.docker.networks.get(
|
host_network: Network = self.docker.networks.get(DOCKER_NETWORK_HOST)
|
||||||
DOCKER_NETWORK_HOST
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if container is register on host
|
# Check if container is register on host
|
||||||
# https://github.com/moby/moby/issues/23302
|
# https://github.com/moby/moby/issues/23302
|
||||||
@ -182,13 +185,13 @@ class DockerAPI:
|
|||||||
val.get("Name")
|
val.get("Name")
|
||||||
for val in host_network.attrs.get("Containers", {}).values()
|
for val in host_network.attrs.get("Containers", {}).values()
|
||||||
):
|
):
|
||||||
with suppress(docker.errors.NotFound):
|
with suppress(docker_errors.NotFound):
|
||||||
host_network.disconnect(name, force=True)
|
host_network.disconnect(name, force=True)
|
||||||
|
|
||||||
# Run container
|
# Run container
|
||||||
try:
|
try:
|
||||||
container.start()
|
container.start()
|
||||||
except docker.errors.DockerException as err:
|
except docker_errors.DockerException as err:
|
||||||
raise DockerAPIError(f"Can't start {name}: {err}", _LOGGER.error) from err
|
raise DockerAPIError(f"Can't start {name}: {err}", _LOGGER.error) from err
|
||||||
except requests.RequestException as err:
|
except requests.RequestException as err:
|
||||||
raise DockerRequestError(
|
raise DockerRequestError(
|
||||||
@ -196,7 +199,7 @@ class DockerAPI:
|
|||||||
) from err
|
) from err
|
||||||
|
|
||||||
# Update metadata
|
# Update metadata
|
||||||
with suppress(docker.errors.DockerException, requests.RequestException):
|
with suppress(docker_errors.DockerException, requests.RequestException):
|
||||||
container.reload()
|
container.reload()
|
||||||
|
|
||||||
return container
|
return container
|
||||||
@ -230,13 +233,13 @@ class DockerAPI:
|
|||||||
result = container.wait()
|
result = container.wait()
|
||||||
output = container.logs(stdout=stdout, stderr=stderr)
|
output = container.logs(stdout=stdout, stderr=stderr)
|
||||||
|
|
||||||
except (docker.errors.DockerException, requests.RequestException) as err:
|
except (docker_errors.DockerException, requests.RequestException) as err:
|
||||||
raise DockerError(f"Can't execute command: {err}", _LOGGER.error) from err
|
raise DockerError(f"Can't execute command: {err}", _LOGGER.error) from err
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# cleanup container
|
# cleanup container
|
||||||
if container:
|
if container:
|
||||||
with suppress(docker.errors.DockerException, requests.RequestException):
|
with suppress(docker_errors.DockerException, requests.RequestException):
|
||||||
container.remove(force=True)
|
container.remove(force=True)
|
||||||
|
|
||||||
return CommandReturn(result.get("StatusCode"), output)
|
return CommandReturn(result.get("StatusCode"), output)
|
||||||
@ -248,47 +251,47 @@ class DockerAPI:
|
|||||||
try:
|
try:
|
||||||
output = self.docker.api.prune_containers()
|
output = self.docker.api.prune_containers()
|
||||||
_LOGGER.debug("Containers prune: %s", output)
|
_LOGGER.debug("Containers prune: %s", output)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for containers prune: %s", err)
|
_LOGGER.warning("Error for containers prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Prune stale images")
|
_LOGGER.info("Prune stale images")
|
||||||
try:
|
try:
|
||||||
output = self.docker.api.prune_images(filters={"dangling": False})
|
output = self.docker.api.prune_images(filters={"dangling": False})
|
||||||
_LOGGER.debug("Images prune: %s", output)
|
_LOGGER.debug("Images prune: %s", output)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for images prune: %s", err)
|
_LOGGER.warning("Error for images prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Prune stale builds")
|
_LOGGER.info("Prune stale builds")
|
||||||
try:
|
try:
|
||||||
output = self.docker.api.prune_builds()
|
output = self.docker.api.prune_builds()
|
||||||
_LOGGER.debug("Builds prune: %s", output)
|
_LOGGER.debug("Builds prune: %s", output)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for builds prune: %s", err)
|
_LOGGER.warning("Error for builds prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Prune stale volumes")
|
_LOGGER.info("Prune stale volumes")
|
||||||
try:
|
try:
|
||||||
output = self.docker.api.prune_builds()
|
output = self.docker.api.prune_builds()
|
||||||
_LOGGER.debug("Volumes prune: %s", output)
|
_LOGGER.debug("Volumes prune: %s", output)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for volumes prune: %s", err)
|
_LOGGER.warning("Error for volumes prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Prune stale networks")
|
_LOGGER.info("Prune stale networks")
|
||||||
try:
|
try:
|
||||||
output = self.docker.api.prune_networks()
|
output = self.docker.api.prune_networks()
|
||||||
_LOGGER.debug("Networks prune: %s", output)
|
_LOGGER.debug("Networks prune: %s", output)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for networks prune: %s", err)
|
_LOGGER.warning("Error for networks prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Fix stale container on hassio network")
|
_LOGGER.info("Fix stale container on hassio network")
|
||||||
try:
|
try:
|
||||||
self.prune_networks(DOCKER_NETWORK)
|
self.prune_networks(DOCKER_NETWORK)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for networks hassio prune: %s", err)
|
_LOGGER.warning("Error for networks hassio prune: %s", err)
|
||||||
|
|
||||||
_LOGGER.info("Fix stale container on host network")
|
_LOGGER.info("Fix stale container on host network")
|
||||||
try:
|
try:
|
||||||
self.prune_networks(DOCKER_NETWORK_HOST)
|
self.prune_networks(DOCKER_NETWORK_HOST)
|
||||||
except docker.errors.APIError as err:
|
except docker_errors.APIError as err:
|
||||||
_LOGGER.warning("Error for networks host prune: %s", err)
|
_LOGGER.warning("Error for networks host prune: %s", err)
|
||||||
|
|
||||||
def prune_networks(self, network_name: str) -> None:
|
def prune_networks(self, network_name: str) -> None:
|
||||||
@ -296,21 +299,21 @@ class DockerAPI:
|
|||||||
|
|
||||||
Fix: https://github.com/moby/moby/issues/23302
|
Fix: https://github.com/moby/moby/issues/23302
|
||||||
"""
|
"""
|
||||||
network: docker.models.networks.Network = self.docker.networks.get(network_name)
|
network: Network = self.docker.networks.get(network_name)
|
||||||
|
|
||||||
for cid, data in network.attrs.get("Containers", {}).items():
|
for cid, data in network.attrs.get("Containers", {}).items():
|
||||||
try:
|
try:
|
||||||
self.docker.containers.get(cid)
|
self.docker.containers.get(cid)
|
||||||
continue
|
continue
|
||||||
except docker.errors.NotFound:
|
except docker_errors.NotFound:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Docker network %s is corrupt on container: %s", network_name, cid
|
"Docker network %s is corrupt on container: %s", network_name, cid
|
||||||
)
|
)
|
||||||
except (docker.errors.DockerException, requests.RequestException):
|
except (docker_errors.DockerException, requests.RequestException):
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Docker fatal error on container %s on %s", cid, network_name
|
"Docker fatal error on container %s on %s", cid, network_name
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with suppress(docker.errors.DockerException, requests.RequestException):
|
with suppress(docker_errors.DockerException, requests.RequestException):
|
||||||
network.disconnect(data.get("Name", cid), force=True)
|
network.disconnect(data.get("Name", cid), force=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user