1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2025-12-20 02:18:59 +00:00
Files
supervisor/supervisor/resolution/evaluations/container.py
Mike Degatano aea15b65b7 Fix mypy issues in store, utils and all other source files (#5957)
* Fix mypy issues in store module

* Fix mypy issues in utils module

* Fix mypy issues in all remaining source files

* Fix ingress user typeddict

* Fixes from feedback

* Fix mypy issues after installing docker-types
2025-06-18 12:40:12 -04:00

107 lines
3.3 KiB
Python

"""Evaluation class for container."""
import logging
from docker.errors import DockerException
from requests import RequestException
from ...const import CoreState
from ...coresys import CoreSys
from ..const import (
ContextType,
IssueType,
SuggestionType,
UnhealthyReason,
UnsupportedReason,
)
from .base import EvaluateBase
_LOGGER: logging.Logger = logging.getLogger(__name__)
UNHEALTHY_IMAGES = [
"watchtower",
"ouroboros",
"portainer",
]
IGNORE_IMAGES = ["sha256"]
def setup(coresys: CoreSys) -> EvaluateBase:
"""Initialize evaluation-setup function."""
return EvaluateContainer(coresys)
class EvaluateContainer(EvaluateBase):
"""Evaluate container."""
def __init__(self, coresys: CoreSys) -> None:
"""Initialize the evaluation class."""
super().__init__(coresys)
self.coresys = coresys
self._images: set[str] = set()
@property
def reason(self) -> UnsupportedReason:
"""Return a UnsupportedReason enum."""
return UnsupportedReason.SOFTWARE
@property
def on_failure(self) -> str:
"""Return a string that is printed when self.evaluate is True."""
return f"Found unsupported images: {self._images}"
@property
def states(self) -> list[CoreState]:
"""Return a list of valid states when this evaluation can run."""
return [CoreState.RUNNING]
@property
def known_images(self) -> set[str]:
"""Return a set of all known images."""
return {
self.sys_homeassistant.image,
self.sys_supervisor.image or self.sys_supervisor.default_image,
*(plugin.image for plugin in self.sys_plugins.all_plugins if plugin.image),
*(addon.image for addon in self.sys_addons.installed if addon.image),
}
async def evaluate(self) -> bool:
"""Run evaluation."""
self.sys_resolution.evaluate.cached_images.clear()
self._images.clear()
try:
containers = await self.sys_run_in_executor(self.sys_docker.containers.list)
except (DockerException, RequestException) as err:
_LOGGER.error("Corrupt docker overlayfs detect: %s", err)
self.sys_resolution.create_issue(
IssueType.CORRUPT_DOCKER,
ContextType.SYSTEM,
suggestions=[SuggestionType.EXECUTE_REPAIR],
)
return False
images = {
image
for container in containers
if (config := container.attrs.get("Config")) is not None
and (image := config.get("Image")) is not None
}
for image in images:
self.sys_resolution.evaluate.cached_images.add(image)
image_name = image.partition(":")[0]
if image_name not in IGNORE_IMAGES and image_name not in self.known_images:
self._images.add(image_name)
if any(
image_name.split("/")[-1].startswith(unhealthy)
for unhealthy in UNHEALTHY_IMAGES
):
_LOGGER.error(
"Found image in unhealthy image list '%s' on the host",
image_name,
)
self.sys_resolution.add_unhealthy_reason(UnhealthyReason.DOCKER)
return len(self._images) != 0