mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-19 07:06:30 +00:00
Add restart policy evaluation (#3886)
* Add restart policy evaluation * No container meta does not fail evaluation
This commit is contained in:
parent
c24b811180
commit
a5103cc329
@ -28,6 +28,15 @@ class ContainerState(str, Enum):
|
|||||||
UNKNOWN = "unknown"
|
UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
class RestartPolicy(str, Enum):
|
||||||
|
"""Restart policy of container."""
|
||||||
|
|
||||||
|
NO = "no"
|
||||||
|
ON_FAILURE = "on-failure"
|
||||||
|
UNLESS_STOPPED = "unless-stopped"
|
||||||
|
ALWAYS = "always"
|
||||||
|
|
||||||
|
|
||||||
DBUS_PATH = "/run/dbus"
|
DBUS_PATH = "/run/dbus"
|
||||||
DBUS_VOLUME = {"bind": DBUS_PATH, "mode": "ro"}
|
DBUS_VOLUME = {"bind": DBUS_PATH, "mode": "ro"}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ from ..exceptions import (
|
|||||||
)
|
)
|
||||||
from ..resolution.const import ContextType, IssueType, SuggestionType
|
from ..resolution.const import ContextType, IssueType, SuggestionType
|
||||||
from ..utils import process_lock
|
from ..utils import process_lock
|
||||||
from .const import ContainerState
|
from .const import ContainerState, RestartPolicy
|
||||||
from .manager import CommandReturn
|
from .manager import CommandReturn
|
||||||
from .monitor import DockerContainerStateEvent
|
from .monitor import DockerContainerStateEvent
|
||||||
from .stats import DockerStats
|
from .stats import DockerStats
|
||||||
@ -134,6 +134,15 @@ class DockerInterface(CoreSysAttributes):
|
|||||||
"""Return True if a task is in progress."""
|
"""Return True if a task is in progress."""
|
||||||
return self.lock.locked()
|
return self.lock.locked()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def restart_policy(self) -> RestartPolicy | None:
|
||||||
|
"""Return restart policy of container."""
|
||||||
|
if "RestartPolicy" not in self.meta_host:
|
||||||
|
return None
|
||||||
|
|
||||||
|
policy = self.meta_host["RestartPolicy"].get("Name")
|
||||||
|
return policy if policy else RestartPolicy.NO
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def security_opt(self) -> list[str]:
|
def security_opt(self) -> list[str]:
|
||||||
"""Control security options."""
|
"""Control security options."""
|
||||||
|
@ -3,7 +3,7 @@ import logging
|
|||||||
|
|
||||||
from ..const import DOCKER_NETWORK_MASK
|
from ..const import DOCKER_NETWORK_MASK
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from .const import ENV_TIME, ENV_TOKEN
|
from .const import ENV_TIME, ENV_TOKEN, RestartPolicy
|
||||||
from .interface import DockerInterface
|
from .interface import DockerInterface
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
@ -46,7 +46,7 @@ class DockerObserver(DockerInterface, CoreSysAttributes):
|
|||||||
hostname=self.name.replace("_", "-"),
|
hostname=self.name.replace("_", "-"),
|
||||||
detach=True,
|
detach=True,
|
||||||
security_opt=self.security_opt,
|
security_opt=self.security_opt,
|
||||||
restart_policy={"Name": "always"},
|
restart_policy={"Name": RestartPolicy.ALWAYS.value},
|
||||||
extra_hosts={"supervisor": self.sys_docker.network.supervisor},
|
extra_hosts={"supervisor": self.sys_docker.network.supervisor},
|
||||||
environment={
|
environment={
|
||||||
ENV_TIME: self.sys_timezone,
|
ENV_TIME: self.sys_timezone,
|
||||||
|
@ -45,6 +45,7 @@ class UnsupportedReason(str, Enum):
|
|||||||
OS = "os"
|
OS = "os"
|
||||||
OS_AGENT = "os_agent"
|
OS_AGENT = "os_agent"
|
||||||
PRIVILEGED = "privileged"
|
PRIVILEGED = "privileged"
|
||||||
|
RESTART_POLICY = "restart_policy"
|
||||||
SOFTWARE = "software"
|
SOFTWARE = "software"
|
||||||
SOURCE_MODS = "source_mods"
|
SOURCE_MODS = "source_mods"
|
||||||
SUPERVISOR_VERSION = "supervisor_version"
|
SUPERVISOR_VERSION = "supervisor_version"
|
||||||
|
72
supervisor/resolution/evaluations/restart_policy.py
Normal file
72
supervisor/resolution/evaluations/restart_policy.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
"""Evaluation class for restart policy."""
|
||||||
|
from supervisor.docker.const import RestartPolicy
|
||||||
|
from supervisor.docker.interface import DockerInterface
|
||||||
|
|
||||||
|
from ...const import CoreState
|
||||||
|
from ...coresys import CoreSys
|
||||||
|
from ..const import UnsupportedReason
|
||||||
|
from .base import EvaluateBase
|
||||||
|
|
||||||
|
|
||||||
|
def setup(coresys: CoreSys) -> EvaluateBase:
|
||||||
|
"""Initialize evaluation-setup function."""
|
||||||
|
return EvaluateRestartPolicy(coresys)
|
||||||
|
|
||||||
|
|
||||||
|
class EvaluateRestartPolicy(EvaluateBase):
|
||||||
|
"""Evaluate restart policy of containers."""
|
||||||
|
|
||||||
|
def __init__(self, coresys: CoreSys) -> None:
|
||||||
|
"""Initialize the evaluation class."""
|
||||||
|
super().__init__(coresys)
|
||||||
|
self.coresys = coresys
|
||||||
|
self._containers: list[str] = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reason(self) -> UnsupportedReason:
|
||||||
|
"""Return a UnsupportedReason enum."""
|
||||||
|
return UnsupportedReason.RESTART_POLICY
|
||||||
|
|
||||||
|
@property
|
||||||
|
def on_failure(self) -> str:
|
||||||
|
"""Return a string that is printed when self.evaluate is True."""
|
||||||
|
return f"Found containers with unsupported restart policy: {self._containers}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def states(self) -> list[CoreState]:
|
||||||
|
"""Return a list of valid states when this evaluation can run."""
|
||||||
|
return [CoreState.RUNNING]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def no_restart_expected(self) -> set[DockerInterface]:
|
||||||
|
"""Docker interfaces where no restart is expected policy."""
|
||||||
|
return {
|
||||||
|
self.sys_supervisor.instance,
|
||||||
|
self.sys_homeassistant.core.instance,
|
||||||
|
*{
|
||||||
|
plug.instance
|
||||||
|
for plug in self.sys_plugins.all_plugins
|
||||||
|
if plug != self.sys_plugins.observer
|
||||||
|
},
|
||||||
|
*{addon.instance for addon in self.sys_addons.installed},
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def always_restart_expected(self) -> set[DockerInterface]:
|
||||||
|
"""Docker interfaces where always restart is expected policy."""
|
||||||
|
return {self.sys_plugins.observer.instance}
|
||||||
|
|
||||||
|
async def evaluate(self) -> bool:
|
||||||
|
"""Run evaluation, return true if system fails."""
|
||||||
|
self._containers = {
|
||||||
|
instance.name
|
||||||
|
for instance in self.no_restart_expected
|
||||||
|
if instance.restart_policy and instance.restart_policy != RestartPolicy.NO
|
||||||
|
} | {
|
||||||
|
instance.name
|
||||||
|
for instance in self.always_restart_expected
|
||||||
|
if instance.restart_policy
|
||||||
|
and instance.restart_policy != RestartPolicy.ALWAYS
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(self._containers) > 0
|
253
tests/fixtures/container_attrs.json
vendored
Normal file
253
tests/fixtures/container_attrs.json
vendored
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
{
|
||||||
|
"Id": "986e5efadb228654f1719735e802fecc099136e4640155887946246a87fc584a",
|
||||||
|
"Created": "2022-09-21T18:54:13.269240742Z",
|
||||||
|
"Path": "/init",
|
||||||
|
"Args": [],
|
||||||
|
"State": {
|
||||||
|
"Status": "running",
|
||||||
|
"Running": true,
|
||||||
|
"Paused": false,
|
||||||
|
"Restarting": false,
|
||||||
|
"OOMKilled": false,
|
||||||
|
"Dead": false,
|
||||||
|
"Pid": 2723,
|
||||||
|
"ExitCode": 0,
|
||||||
|
"Error": "",
|
||||||
|
"StartedAt": "2022-09-21T18:54:14.124021953Z",
|
||||||
|
"FinishedAt": "0001-01-01T00:00:00Z"
|
||||||
|
},
|
||||||
|
"Image": "sha256:bc34c81c040474bdc005e52857c04103702b081f58b70d5dbcdfc8261a03a4d9",
|
||||||
|
"ResolvConfPath": "/mnt/data/docker/containers/986e5efadb228654f1719735e802fecc099136e4640155887946246a87fc584a/resolv.conf",
|
||||||
|
"HostnamePath": "/mnt/data/docker/containers/986e5efadb228654f1719735e802fecc099136e4640155887946246a87fc584a/hostname",
|
||||||
|
"HostsPath": "/mnt/data/docker/containers/986e5efadb228654f1719735e802fecc099136e4640155887946246a87fc584a/hosts",
|
||||||
|
"LogPath": "",
|
||||||
|
"Name": "/addon_core_mosquitto",
|
||||||
|
"RestartCount": 0,
|
||||||
|
"Driver": "overlay2",
|
||||||
|
"Platform": "linux",
|
||||||
|
"MountLabel": "",
|
||||||
|
"ProcessLabel": "",
|
||||||
|
"AppArmorProfile": "docker-default",
|
||||||
|
"ExecIDs": null,
|
||||||
|
"HostConfig": {
|
||||||
|
"Binds": [
|
||||||
|
"/dev:/dev:ro",
|
||||||
|
"/mnt/data/supervisor/addons/data/core_mosquitto:/data:rw",
|
||||||
|
"/mnt/data/supervisor/ssl:/ssl:ro",
|
||||||
|
"/mnt/data/supervisor/share:/share:ro"
|
||||||
|
],
|
||||||
|
"ContainerIDFile": "",
|
||||||
|
"LogConfig": { "Type": "journald", "Config": { "tag": "{{.Name}}" } },
|
||||||
|
"NetworkMode": "default",
|
||||||
|
"PortBindings": { "1883/tcp": [{ "HostIp": "", "HostPort": "1883" }] },
|
||||||
|
"RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
|
||||||
|
"AutoRemove": false,
|
||||||
|
"VolumeDriver": "",
|
||||||
|
"VolumesFrom": null,
|
||||||
|
"CapAdd": null,
|
||||||
|
"CapDrop": null,
|
||||||
|
"CgroupnsMode": "private",
|
||||||
|
"Dns": ["172.30.32.3"],
|
||||||
|
"DnsOptions": null,
|
||||||
|
"DnsSearch": ["local.hass.io"],
|
||||||
|
"ExtraHosts": ["hassio:172.30.32.2", "supervisor:172.30.32.2"],
|
||||||
|
"GroupAdd": null,
|
||||||
|
"IpcMode": "private",
|
||||||
|
"Cgroup": "",
|
||||||
|
"Links": null,
|
||||||
|
"OomScoreAdj": 200,
|
||||||
|
"PidMode": "",
|
||||||
|
"Privileged": false,
|
||||||
|
"PublishAllPorts": false,
|
||||||
|
"ReadonlyRootfs": false,
|
||||||
|
"SecurityOpt": ["seccomp=unconfined"],
|
||||||
|
"Tmpfs": { "/dev/shm": "" },
|
||||||
|
"UTSMode": "",
|
||||||
|
"UsernsMode": "",
|
||||||
|
"ShmSize": 67108864,
|
||||||
|
"Runtime": "runc",
|
||||||
|
"ConsoleSize": [0, 0],
|
||||||
|
"Isolation": "",
|
||||||
|
"CpuShares": 0,
|
||||||
|
"Memory": 0,
|
||||||
|
"NanoCpus": 0,
|
||||||
|
"CgroupParent": "",
|
||||||
|
"BlkioWeight": 0,
|
||||||
|
"BlkioWeightDevice": null,
|
||||||
|
"BlkioDeviceReadBps": null,
|
||||||
|
"BlkioDeviceWriteBps": null,
|
||||||
|
"BlkioDeviceReadIOps": null,
|
||||||
|
"BlkioDeviceWriteIOps": null,
|
||||||
|
"CpuPeriod": 0,
|
||||||
|
"CpuQuota": 0,
|
||||||
|
"CpuRealtimePeriod": 0,
|
||||||
|
"CpuRealtimeRuntime": 0,
|
||||||
|
"CpusetCpus": "",
|
||||||
|
"CpusetMems": "",
|
||||||
|
"Devices": null,
|
||||||
|
"DeviceCgroupRules": null,
|
||||||
|
"DeviceRequests": null,
|
||||||
|
"KernelMemory": 0,
|
||||||
|
"KernelMemoryTCP": 0,
|
||||||
|
"MemoryReservation": 0,
|
||||||
|
"MemorySwap": 0,
|
||||||
|
"MemorySwappiness": null,
|
||||||
|
"OomKillDisable": null,
|
||||||
|
"PidsLimit": null,
|
||||||
|
"Ulimits": null,
|
||||||
|
"CpuCount": 0,
|
||||||
|
"CpuPercent": 0,
|
||||||
|
"IOMaximumIOps": 0,
|
||||||
|
"IOMaximumBandwidth": 0,
|
||||||
|
"MaskedPaths": [
|
||||||
|
"/proc/asound",
|
||||||
|
"/proc/acpi",
|
||||||
|
"/proc/kcore",
|
||||||
|
"/proc/keys",
|
||||||
|
"/proc/latency_stats",
|
||||||
|
"/proc/timer_list",
|
||||||
|
"/proc/timer_stats",
|
||||||
|
"/proc/sched_debug",
|
||||||
|
"/proc/scsi",
|
||||||
|
"/sys/firmware"
|
||||||
|
],
|
||||||
|
"ReadonlyPaths": [
|
||||||
|
"/proc/bus",
|
||||||
|
"/proc/fs",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger"
|
||||||
|
],
|
||||||
|
"Init": false
|
||||||
|
},
|
||||||
|
"GraphDriver": {
|
||||||
|
"Data": {
|
||||||
|
"LowerDir": "/mnt/data/docker/overlay2/1b79280bcdd879c0df64ee41755c70610cf3b650cea299c6f30081338bf745e5-init/diff:/mnt/data/docker/overlay2/2c22d6a27a68fb384f85d4bb833f7ac7956fcbb93be9f731e6deb76bb9420011/diff:/mnt/data/docker/overlay2/42ce3dc994391b83f90bf599f887a8e0fdc2ee24cec9b14f491412f1dae11714/diff:/mnt/data/docker/overlay2/9f7c5f5a2aa9a324c75f9c54fbee648bee86d963c4ad6fde2cb3ca0d3f886287/diff:/mnt/data/docker/overlay2/8a4cd2bb72bb673a42186a1b94aaf1bbba1f1e35953fea91e6ccc2c08b0c7dc8/diff:/mnt/data/docker/overlay2/eb50a9462c19acb312d44e3455579f84f3ef256e410c4992554f1527fbd2b9dc/diff:/mnt/data/docker/overlay2/d38688df678f243a89c055f768b5ec80f1ce0686ed28940fcc4430edc5b311a0/diff",
|
||||||
|
"MergedDir": "/mnt/data/docker/overlay2/1b79280bcdd879c0df64ee41755c70610cf3b650cea299c6f30081338bf745e5/merged",
|
||||||
|
"UpperDir": "/mnt/data/docker/overlay2/1b79280bcdd879c0df64ee41755c70610cf3b650cea299c6f30081338bf745e5/diff",
|
||||||
|
"WorkDir": "/mnt/data/docker/overlay2/1b79280bcdd879c0df64ee41755c70610cf3b650cea299c6f30081338bf745e5/work"
|
||||||
|
},
|
||||||
|
"Name": "overlay2"
|
||||||
|
},
|
||||||
|
"Mounts": [
|
||||||
|
{
|
||||||
|
"Type": "bind",
|
||||||
|
"Source": "/dev",
|
||||||
|
"Destination": "/dev",
|
||||||
|
"Mode": "ro",
|
||||||
|
"RW": false,
|
||||||
|
"Propagation": "rprivate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Type": "bind",
|
||||||
|
"Source": "/mnt/data/supervisor/addons/data/core_mosquitto",
|
||||||
|
"Destination": "/data",
|
||||||
|
"Mode": "rw",
|
||||||
|
"RW": true,
|
||||||
|
"Propagation": "rprivate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Type": "bind",
|
||||||
|
"Source": "/mnt/data/supervisor/ssl",
|
||||||
|
"Destination": "/ssl",
|
||||||
|
"Mode": "ro",
|
||||||
|
"RW": false,
|
||||||
|
"Propagation": "rprivate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Type": "bind",
|
||||||
|
"Source": "/mnt/data/supervisor/share",
|
||||||
|
"Destination": "/share",
|
||||||
|
"Mode": "ro",
|
||||||
|
"RW": false,
|
||||||
|
"Propagation": "rprivate"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Config": {
|
||||||
|
"Hostname": "core-mosquitto",
|
||||||
|
"Domainname": "local.hass.io",
|
||||||
|
"User": "",
|
||||||
|
"AttachStdin": false,
|
||||||
|
"AttachStdout": false,
|
||||||
|
"AttachStderr": false,
|
||||||
|
"ExposedPorts": { "1883/tcp": {} },
|
||||||
|
"Tty": false,
|
||||||
|
"OpenStdin": false,
|
||||||
|
"StdinOnce": false,
|
||||||
|
"Env": [
|
||||||
|
"TZ=America/New_York",
|
||||||
|
"SUPERVISOR_TOKEN=abc123",
|
||||||
|
"HASSIO_TOKEN=abc123",
|
||||||
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
"LANG=C.UTF-8",
|
||||||
|
"DEBIAN_FRONTEND=noninteractive",
|
||||||
|
"CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt",
|
||||||
|
"S6_BEHAVIOUR_IF_STAGE2_FAILS=2",
|
||||||
|
"S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0",
|
||||||
|
"S6_CMD_WAIT_FOR_SERVICES=1"
|
||||||
|
],
|
||||||
|
"Cmd": null,
|
||||||
|
"Image": "homeassistant/aarch64-addon-mosquitto:6.1.3",
|
||||||
|
"Volumes": { "/data": {}, "/dev": {}, "/share": {}, "/ssl": {} },
|
||||||
|
"WorkingDir": "/",
|
||||||
|
"Entrypoint": ["/init"],
|
||||||
|
"OnBuild": null,
|
||||||
|
"Labels": {
|
||||||
|
"io.hass.arch": "aarch64",
|
||||||
|
"io.hass.base.arch": "aarch64",
|
||||||
|
"io.hass.base.image": "arm64v8/debian:bullseye-slim",
|
||||||
|
"io.hass.base.name": "debian",
|
||||||
|
"io.hass.base.version": "2022.08.0",
|
||||||
|
"io.hass.description": "An Open Source MQTT broker",
|
||||||
|
"io.hass.name": "Mosquitto broker",
|
||||||
|
"io.hass.type": "addon",
|
||||||
|
"io.hass.url": "https://github.com/home-assistant/hassio-addons/tree/master/mosquitto",
|
||||||
|
"io.hass.version": "6.1.3",
|
||||||
|
"org.opencontainers.image.created": "2022-08-30 07:33:03+00:00",
|
||||||
|
"org.opencontainers.image.source": "https://github.com/home-assistant/docker-base",
|
||||||
|
"org.opencontainers.image.version": "6.1.3",
|
||||||
|
"supervisor_managed": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkSettings": {
|
||||||
|
"Bridge": "",
|
||||||
|
"SandboxID": "067cd11a63f96d227dcc0f01d3e4f5053c368021becd0b4b2da4f301cfda3d29",
|
||||||
|
"HairpinMode": false,
|
||||||
|
"LinkLocalIPv6Address": "",
|
||||||
|
"LinkLocalIPv6PrefixLen": 0,
|
||||||
|
"Ports": {
|
||||||
|
"1883/tcp": [
|
||||||
|
{ "HostIp": "0.0.0.0", "HostPort": "1883" },
|
||||||
|
{ "HostIp": "::", "HostPort": "1883" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SandboxKey": "/var/run/docker/netns/067cd11a63f9",
|
||||||
|
"SecondaryIPAddresses": null,
|
||||||
|
"SecondaryIPv6Addresses": null,
|
||||||
|
"EndpointID": "",
|
||||||
|
"Gateway": "",
|
||||||
|
"GlobalIPv6Address": "",
|
||||||
|
"GlobalIPv6PrefixLen": 0,
|
||||||
|
"IPAddress": "",
|
||||||
|
"IPPrefixLen": 0,
|
||||||
|
"IPv6Gateway": "",
|
||||||
|
"MacAddress": "",
|
||||||
|
"Networks": {
|
||||||
|
"hassio": {
|
||||||
|
"IPAMConfig": null,
|
||||||
|
"Links": null,
|
||||||
|
"Aliases": ["core-mosquitto", "986e5efadb22"],
|
||||||
|
"NetworkID": "cd10b1eb5f4a1cd5179839f81ccdadd29545eaa0b921454d1a2e0452c12d6935",
|
||||||
|
"EndpointID": "9b2c58f4595618241bb45df028c95f2713bb0b1b6326d3bdab2366e2caadbe7b",
|
||||||
|
"Gateway": "172.30.32.1",
|
||||||
|
"IPAddress": "172.30.33.1",
|
||||||
|
"IPPrefixLen": 23,
|
||||||
|
"IPv6Gateway": "",
|
||||||
|
"GlobalIPv6Address": "",
|
||||||
|
"GlobalIPv6PrefixLen": 0,
|
||||||
|
"MacAddress": "02:42:ac:1e:21:01",
|
||||||
|
"DriverOpts": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
tests/resolution/evaluation/test_restart_policy.py
Normal file
81
tests/resolution/evaluation/test_restart_policy.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
"""Test evaluate restart policy.."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
|
from supervisor.addons.addon import Addon
|
||||||
|
from supervisor.const import CoreState
|
||||||
|
from supervisor.coresys import CoreSys
|
||||||
|
from supervisor.resolution.evaluations.restart_policy import EvaluateRestartPolicy
|
||||||
|
|
||||||
|
from tests.common import load_json_fixture
|
||||||
|
|
||||||
|
TEST_VERSION = AwesomeVersion("1.0.0")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_evaluation(coresys: CoreSys, install_addon_ssh: Addon):
|
||||||
|
"""Test evaluation."""
|
||||||
|
restart_policy = EvaluateRestartPolicy(coresys)
|
||||||
|
coresys.core.state = CoreState.RUNNING
|
||||||
|
|
||||||
|
await restart_policy()
|
||||||
|
assert restart_policy.reason not in coresys.resolution.unsupported
|
||||||
|
|
||||||
|
no_restart_attrs = load_json_fixture("container_attrs.json")
|
||||||
|
always_restart_attrs = load_json_fixture("container_attrs.json")
|
||||||
|
always_restart_attrs["HostConfig"]["RestartPolicy"]["Name"] = "always"
|
||||||
|
addon_attrs = no_restart_attrs
|
||||||
|
observer_attrs = always_restart_attrs
|
||||||
|
|
||||||
|
def get_container(name: str):
|
||||||
|
meta = MagicMock()
|
||||||
|
meta.attrs = observer_attrs if name == "hassio_observer" else addon_attrs
|
||||||
|
return meta
|
||||||
|
|
||||||
|
coresys.docker.containers.get = get_container
|
||||||
|
await coresys.plugins.observer.instance.attach(TEST_VERSION)
|
||||||
|
await install_addon_ssh.instance.attach(TEST_VERSION)
|
||||||
|
|
||||||
|
await restart_policy()
|
||||||
|
assert restart_policy.reason not in coresys.resolution.unsupported
|
||||||
|
|
||||||
|
addon_attrs = always_restart_attrs
|
||||||
|
await install_addon_ssh.instance.attach(TEST_VERSION)
|
||||||
|
await restart_policy()
|
||||||
|
assert restart_policy.reason in coresys.resolution.unsupported
|
||||||
|
|
||||||
|
addon_attrs = no_restart_attrs
|
||||||
|
await install_addon_ssh.instance.attach(TEST_VERSION)
|
||||||
|
await restart_policy()
|
||||||
|
assert restart_policy.reason not in coresys.resolution.unsupported
|
||||||
|
|
||||||
|
observer_attrs = no_restart_attrs
|
||||||
|
await coresys.plugins.observer.instance.attach(TEST_VERSION)
|
||||||
|
await restart_policy()
|
||||||
|
assert restart_policy.reason in coresys.resolution.unsupported
|
||||||
|
|
||||||
|
|
||||||
|
async def test_did_run(coresys: CoreSys):
|
||||||
|
"""Test that the evaluation ran as expected."""
|
||||||
|
restart_policy = EvaluateRestartPolicy(coresys)
|
||||||
|
should_run = restart_policy.states
|
||||||
|
should_not_run = [state for state in CoreState if state not in should_run]
|
||||||
|
assert len(should_run) != 0
|
||||||
|
assert len(should_not_run) != 0
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"supervisor.resolution.evaluations.restart_policy.EvaluateRestartPolicy.evaluate",
|
||||||
|
return_value=False,
|
||||||
|
) as evaluate:
|
||||||
|
for state in should_run:
|
||||||
|
coresys.core.state = state
|
||||||
|
await restart_policy()
|
||||||
|
evaluate.assert_called_once()
|
||||||
|
evaluate.reset_mock()
|
||||||
|
|
||||||
|
for state in should_not_run:
|
||||||
|
coresys.core.state = state
|
||||||
|
await restart_policy()
|
||||||
|
evaluate.assert_not_called()
|
||||||
|
evaluate.reset_mock()
|
Loading…
x
Reference in New Issue
Block a user