Support plugin requirements & mdns (#1638)

* Support plugin requirements & mdns

* better error handling

* Use debug from LogLevel

* fix lint

* fix logger

* fix test env

* Use new style

* fix typo
This commit is contained in:
Pascal Vizeli 2020-04-07 12:08:29 +02:00 committed by GitHub
parent e787e59b49
commit e2dc1a4471
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 85 additions and 23 deletions

View File

@ -96,7 +96,7 @@ function setup_test_env() {
-e SUPERVISOR_SHARE="/workspaces/test_supervisor" \ -e SUPERVISOR_SHARE="/workspaces/test_supervisor" \
-e SUPERVISOR_NAME=hassio_supervisor \ -e SUPERVISOR_NAME=hassio_supervisor \
-e SUPERVISOR_DEV=1 \ -e SUPERVISOR_DEV=1 \
-e HOMEASSISTANT_REPOSITORY="homeassistant/qemux86-64-homeassistant" \ -e SUPERVISOR_MACHINE="qemux86-64" \
homeassistant/amd64-hassio-supervisor:latest homeassistant/amd64-hassio-supervisor:latest
} }

View File

@ -38,11 +38,12 @@ from ..const import (
CONTENT_TYPE_BINARY, CONTENT_TYPE_BINARY,
SUPERVISOR_VERSION, SUPERVISOR_VERSION,
UpdateChannels, UpdateChannels,
LogLevel,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from ..utils.validate import validate_timezone from ..utils.validate import validate_timezone
from ..validate import log_level, repositories, wait_boot from ..validate import repositories, wait_boot
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -54,7 +55,7 @@ SCHEMA_OPTIONS = vol.Schema(
vol.Optional(ATTR_ADDONS_REPOSITORIES): repositories, vol.Optional(ATTR_ADDONS_REPOSITORIES): repositories,
vol.Optional(ATTR_TIMEZONE): validate_timezone, vol.Optional(ATTR_TIMEZONE): validate_timezone,
vol.Optional(ATTR_WAIT_BOOT): wait_boot, vol.Optional(ATTR_WAIT_BOOT): wait_boot,
vol.Optional(ATTR_LOGGING): log_level, vol.Optional(ATTR_LOGGING): vol.Coerce(LogLevel),
vol.Optional(ATTR_DEBUG): vol.Boolean(), vol.Optional(ATTR_DEBUG): vol.Boolean(),
vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(), vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(),
} }

View File

@ -12,12 +12,13 @@ from .api import RestAPI
from .arch import CpuArch from .arch import CpuArch
from .auth import Auth from .auth import Auth
from .const import ( from .const import (
SOCKET_DOCKER,
UpdateChannels,
ENV_SUPERVISOR_SHARE,
ENV_SUPERVISOR_NAME,
ENV_HOMEASSISTANT_REPOSITORY, ENV_HOMEASSISTANT_REPOSITORY,
ENV_SUPERVISOR_MACHINE, ENV_SUPERVISOR_MACHINE,
ENV_SUPERVISOR_NAME,
ENV_SUPERVISOR_SHARE,
SOCKET_DOCKER,
LogLevel,
UpdateChannels,
) )
from .core import Core from .core import Core
from .coresys import CoreSys from .coresys import CoreSys
@ -28,14 +29,14 @@ from .homeassistant import HomeAssistant
from .host import HostManager from .host import HostManager
from .hwmon import HwMonitor from .hwmon import HwMonitor
from .ingress import Ingress from .ingress import Ingress
from .plugins import PluginManager
from .secrets import SecretsManager
from .services import ServiceManager from .services import ServiceManager
from .snapshots import SnapshotManager from .snapshots import SnapshotManager
from .store import StoreManager from .store import StoreManager
from .supervisor import Supervisor from .supervisor import Supervisor
from .tasks import Tasks from .tasks import Tasks
from .updater import Updater from .updater import Updater
from .secrets import SecretsManager
from .plugins import PluginManager
from .utils.dt import fetch_timezone from .utils.dt import fetch_timezone
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -163,7 +164,7 @@ def initialize_system_data(coresys: CoreSys):
if bool(os.environ.get("SUPERVISOR_DEV", 0)): if bool(os.environ.get("SUPERVISOR_DEV", 0)):
_LOGGER.warning("SUPERVISOR_DEV is set") _LOGGER.warning("SUPERVISOR_DEV is set")
coresys.updater.channel = UpdateChannels.DEV coresys.updater.channel = UpdateChannels.DEV
coresys.config.logging = "debug" coresys.config.logging = LogLevel.DEBUG
coresys.config.debug = True coresys.config.debug = True

View File

@ -15,6 +15,7 @@ from .const import (
ENV_SUPERVISOR_SHARE, ENV_SUPERVISOR_SHARE,
FILE_HASSIO_CONFIG, FILE_HASSIO_CONFIG,
SUPERVISOR_DATA, SUPERVISOR_DATA,
LogLevel,
) )
from .utils.dt import parse_datetime from .utils.dt import parse_datetime
from .utils.json import JsonConfig from .utils.json import JsonConfig
@ -89,19 +90,19 @@ class CoreConfig(JsonConfig):
self._data[ATTR_DEBUG_BLOCK] = value self._data[ATTR_DEBUG_BLOCK] = value
@property @property
def logging(self) -> str: def logging(self) -> LogLevel:
"""Return log level of system.""" """Return log level of system."""
return self._data[ATTR_LOGGING] return self._data[ATTR_LOGGING]
@logging.setter @logging.setter
def logging(self, value: str): def logging(self, value: LogLevel):
"""Set system log level.""" """Set system log level."""
self._data[ATTR_LOGGING] = value self._data[ATTR_LOGGING] = value
self.modify_log_level() self.modify_log_level()
def modify_log_level(self) -> None: def modify_log_level(self) -> None:
"""Change log level.""" """Change log level."""
lvl = getattr(logging, self.logging.upper()) lvl = getattr(logging, str(self.logging.value).upper())
logging.getLogger("supervisor").setLevel(lvl) logging.getLogger("supervisor").setLevel(lvl)
@property @property

View File

@ -361,3 +361,13 @@ class CoreStates(str, Enum):
STARTUP = "startup" STARTUP = "startup"
RUNNING = "running" RUNNING = "running"
FREEZE = "freeze" FREEZE = "freeze"
class LogLevel(str, Enum):
"""Logging level of system."""
DEBUG = "debug"
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"

View File

@ -2,26 +2,29 @@
log log
errors errors
loop loop
{% if debug %}debug{% endif %}
hosts /config/hosts { hosts /config/hosts {
fallthrough fallthrough
} }
template ANY AAAA local.hass.io hassio { template ANY AAAA local.hass.io hassio {
rcode NOERROR rcode NOERROR
} }
forward . {{ locals | join(" ") }} dns://127.0.0.1:5353 { mdns
forward . {{ locals | join(" ") }} dns://127.0.0.1:5553 {
except local.hass.io except local.hass.io
policy sequential policy sequential
health_check 5s health_check 5s
} }
fallback REFUSED . dns://127.0.0.1:5353 fallback REFUSED . dns://127.0.0.1:5553
fallback SERVFAIL . dns://127.0.0.1:5353 fallback SERVFAIL . dns://127.0.0.1:5553
fallback NXDOMAIN . dns://127.0.0.1:5353 fallback NXDOMAIN . dns://127.0.0.1:5553
cache 10 cache 10
} }
.:5353 { .:5553 {
log log
errors errors
{% if debug %}debug{% endif %}
forward . tls://1.1.1.1 tls://1.0.0.1 { forward . tls://1.1.1.1 tls://1.0.0.1 {
tls_servername cloudflare-dns.com tls_servername cloudflare-dns.com
except local.hass.io except local.hass.io

View File

@ -3,6 +3,7 @@ import asyncio
import logging import logging
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import HassioError
from .audio import Audio from .audio import Audio
from .cli import HaCli from .cli import HaCli
from .dns import CoreDNS from .dns import CoreDNS
@ -14,6 +15,11 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
class PluginManager(CoreSysAttributes): class PluginManager(CoreSysAttributes):
"""Manage supported function for plugins.""" """Manage supported function for plugins."""
required_cli: int = 24
required_dns: int = 5
required_audio: int = 14
required_multicast: int = 2
def __init__(self, coresys: CoreSys): def __init__(self, coresys: CoreSys):
"""Initialize plugin manager.""" """Initialize plugin manager."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
@ -49,6 +55,37 @@ class PluginManager(CoreSysAttributes):
[self.dns.load(), self.audio.load(), self.cli.load(), self.multicast.load()] [self.dns.load(), self.audio.load(), self.cli.load(), self.multicast.load()]
) )
# Check requirements
for plugin, required_version in (
(self._audio, self.required_audio),
(self._dns, self.required_dns),
(self._cli, self.required_cli),
(self._multicast, self.required_multicast),
):
# Check if need an update
try:
if int(plugin.version) >= required_version:
continue
except TypeError:
_LOGGER.warning(
"Somethings going wrong with requirements on %s",
type(plugin).__name__,
)
_LOGGER.info(
"Requirement need update for %s - %i",
type(plugin).__name__,
required_version,
)
try:
await plugin.update(version=str(required_version))
except HassioError:
_LOGGER.error(
"Can't update %s to %i but it's a reuirement, the Supervisor is not health now!",
type(plugin).__name__,
required_version,
)
async def repair(self): async def repair(self):
"""Repair Supervisor plugins.""" """Repair Supervisor plugins."""
await asyncio.wait( await asyncio.wait(

View File

@ -13,15 +13,22 @@ import attr
import jinja2 import jinja2
import voluptuous as vol import voluptuous as vol
from ..const import ATTR_IMAGE, ATTR_SERVERS, ATTR_VERSION, DNS_SUFFIX, FILE_HASSIO_DNS from ..const import (
ATTR_IMAGE,
ATTR_SERVERS,
ATTR_VERSION,
DNS_SUFFIX,
FILE_HASSIO_DNS,
LogLevel,
)
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..docker.dns import DockerDNS from ..docker.dns import DockerDNS
from ..docker.stats import DockerStats from ..docker.stats import DockerStats
from ..exceptions import CoreDNSError, CoreDNSUpdateError, DockerAPIError from ..exceptions import CoreDNSError, CoreDNSUpdateError, DockerAPIError
from ..misc.forwarder import DNSForward from ..misc.forwarder import DNSForward
from ..utils.json import JsonConfig from ..utils.json import JsonConfig
from .validate import SCHEMA_DNS_CONFIG
from ..validate import dns_url from ..validate import dns_url
from .validate import SCHEMA_DNS_CONFIG
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -301,7 +308,9 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.warning("Ignore invalid DNS Server: %s", server) _LOGGER.warning("Ignore invalid DNS Server: %s", server)
# Generate config file # Generate config file
data = self.coredns_template.render(locals=dns_servers) data = self.coredns_template.render(
locals=dns_servers, debug=self.sys_config.logging == LogLevel.DEBUG
)
try: try:
self.corefile.write_text(data) self.corefile.write_text(data)

View File

@ -34,6 +34,7 @@ from .const import (
ATTR_VERSION, ATTR_VERSION,
ATTR_WAIT_BOOT, ATTR_WAIT_BOOT,
ATTR_WATCHDOG, ATTR_WATCHDOG,
LogLevel,
UpdateChannels, UpdateChannels,
) )
from .utils.validate import validate_timezone from .utils.validate import validate_timezone
@ -48,7 +49,6 @@ docker_image = vol.Match(r"^[\w{}]+/[\-\w{}]+$")
uuid_match = vol.Match(r"^[0-9a-f]{32}$") uuid_match = vol.Match(r"^[0-9a-f]{32}$")
sha256 = vol.Match(r"^[0-9a-f]{64}$") sha256 = vol.Match(r"^[0-9a-f]{64}$")
token = vol.Match(r"^[0-9a-f]{32,256}$") token = vol.Match(r"^[0-9a-f]{32,256}$")
log_level = vol.In(["debug", "info", "warning", "error", "critical"])
def dns_url(url: str) -> str: def dns_url(url: str) -> str:
@ -156,7 +156,7 @@ SCHEMA_SUPERVISOR_CONFIG = vol.Schema(
default=["https://github.com/hassio-addons/repository"], default=["https://github.com/hassio-addons/repository"],
): repositories, ): repositories,
vol.Optional(ATTR_WAIT_BOOT, default=5): wait_boot, vol.Optional(ATTR_WAIT_BOOT, default=5): wait_boot,
vol.Optional(ATTR_LOGGING, default="info"): log_level, vol.Optional(ATTR_LOGGING, default=LogLevel.INFO): vol.Coerce(LogLevel),
vol.Optional(ATTR_DEBUG, default=False): vol.Boolean(), vol.Optional(ATTR_DEBUG, default=False): vol.Boolean(),
vol.Optional(ATTR_DEBUG_BLOCK, default=False): vol.Boolean(), vol.Optional(ATTR_DEBUG_BLOCK, default=False): vol.Boolean(),
}, },