From a2cf7ece7063d00edb4fddf3ad8825e5df1f14d9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 16 Aug 2019 12:47:32 +0200 Subject: [PATCH] Change handling with host files (#1223) --- hassio/addons/__init__.py | 18 +++++++++++ hassio/addons/addon.py | 4 +-- hassio/dns.py | 63 +++++++++++++++++++-------------------- hassio/tasks.py | 2 +- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/hassio/addons/__init__.py b/hassio/addons/__init__.py index c6e1a6fb7..6f669deb7 100644 --- a/hassio/addons/__init__.py +++ b/hassio/addons/__init__.py @@ -10,6 +10,7 @@ from ..coresys import CoreSys, CoreSysAttributes from ..exceptions import ( AddonsError, AddonsNotSupportedError, + CoreDNSError, DockerAPIError, HomeAssistantAPIError, HostAppArmorError, @@ -74,6 +75,9 @@ class AddonManager(CoreSysAttributes): if tasks: await asyncio.wait(tasks) + # Sync DNS + await self.sync_dns() + async def boot(self, stage: str) -> None: """Boot add-ons with mode auto.""" tasks = [] @@ -299,3 +303,17 @@ class AddonManager(CoreSysAttributes): _LOGGER.error("Can't repair %s", addon.slug) with suppress(AddonsError): await self.uninstall(addon.slug) + + async def sync_dns(self) -> None: + """Sync add-ons DNS names.""" + # Update hosts + for addon in self.installed: + if not await addon.is_running(): + continue + self.sys_dns.add_host( + ipv4=addon.ip_address, names=[addon.hostname], write=False + ) + + # Write hosts files + with suppress(CoreDNSError): + self.sys_dns.write_hosts() diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 1cd4769ba..05cea7914 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -1,7 +1,7 @@ """Init file for Hass.io add-ons.""" from contextlib import suppress from copy import deepcopy -from ipaddress import IPv4Address, ip_address +from ipaddress import IPv4Address import logging from pathlib import Path, PurePath import re @@ -81,8 +81,6 @@ class Addon(AddonModel): @property def ip_address(self) -> IPv4Address: """Return IP of Add-on instance.""" - if not self.is_installed: - return ip_address("0.0.0.0") return self.instance.ip_address @property diff --git a/hassio/dns.py b/hassio/dns.py index 2a4cad846..1a17c51a8 100644 --- a/hassio/dns.py +++ b/hassio/dns.py @@ -2,7 +2,7 @@ import asyncio import logging from contextlib import suppress -from ipaddress import IPv4Address, AddressValueError +from ipaddress import IPv4Address from pathlib import Path from string import Template from typing import Awaitable, Dict, List, Optional @@ -81,8 +81,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes): async def load(self) -> None: """Load DNS setup.""" - with suppress(CoreDNSError): - self._import_hosts() + self._init_hosts() # Check CoreDNS state try: @@ -181,13 +180,15 @@ class CoreDNS(JsonConfig, CoreSysAttributes): _LOGGER.error("Can't start CoreDNS plugin") raise CoreDNSError() from None - def reset(self) -> None: + async def reset(self) -> None: """Reset Config / Hosts.""" self.servers = DNS_SERVERS with suppress(OSError): self.hosts.unlink() - self._import_hosts() + self._init_hosts() + + await self.sys_addons.sync_dns() def _write_corefile(self) -> None: """Write CoreDNS config.""" @@ -207,43 +208,34 @@ class CoreDNS(JsonConfig, CoreSysAttributes): _LOGGER.error("Can't update corefile: %s", err) raise CoreDNSError() from None - def _import_hosts(self) -> None: + def _init_hosts(self) -> None: """Import hosts entry.""" # Generate Default - if not self.hosts.exists(): - self.add_host(self.sys_docker.network.supervisor, ["hassio", "supervisor"]) - self.add_host( - self.sys_docker.network.gateway, ["homeassistant", "home-assistant"] - ) - return + self.add_host( + self.sys_docker.network.supervisor, ["hassio", "supervisor"], write=False + ) + self.add_host( + self.sys_docker.network.gateway, + ["homeassistant", "home-assistant"], + write=False, + ) - # Import Exists host table - try: - with self.hosts.open("r") as hosts: - for line in hosts.readlines(): - try: - data = line.split(" ") - self._hosts[IPv4Address(data[0])] = data[1:] - except AddressValueError: - _LOGGER.warning("Fails to read %s", line) - - except OSError as err: - _LOGGER.error("Can't read hosts file: %s", err) - raise CoreDNSError() from None - - def _write_hosts(self) -> None: + def write_hosts(self) -> None: """Write hosts from memory to file.""" try: with self.hosts.open("w") as hosts: for address, hostnames in self._hosts.items(): host = " ".join(hostnames) - hosts.write(f"{address!s} {host}") + hosts.write(f"{address!s} {host}\n") except OSError as err: _LOGGER.error("Can't write hosts file: %s", err) raise CoreDNSError() from None - def add_host(self, ipv4: IPv4Address, names: List[str]) -> None: + def add_host(self, ipv4: IPv4Address, names: List[str], write: bool = True) -> None: """Add a new host entry.""" + if not ipv4 or ipv4 == IPv4Address("0.0.0.0"): + return + hostnames: List[str] = [] for name in names: hostnames.append(name) @@ -252,10 +244,14 @@ class CoreDNS(JsonConfig, CoreSysAttributes): self._hosts[ipv4] = hostnames _LOGGER.debug("Add Host entry %s -> %s", ipv4, hostnames) - self._write_hosts() + if write: + self.write_hosts() def delete_host( - self, ipv4: Optional[IPv4Address] = None, host: Optional[str] = None + self, + ipv4: Optional[IPv4Address] = None, + host: Optional[str] = None, + write: bool = True, ) -> None: """Remove a entry from hosts.""" if host: @@ -270,7 +266,8 @@ class CoreDNS(JsonConfig, CoreSysAttributes): _LOGGER.debug("Remove Host entry %s", ipv4) self._hosts.pop(ipv4, None) - self._write_hosts() + if write: + self.write_hosts() else: _LOGGER.warning("Can't remove Host entry: %s/%s", ipv4, host) @@ -336,7 +333,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes): try: with RESOLV_CONF.open("w") as resolv: for line in resolv_lines: - resolv.write(line) + resolv.write(f"{line}\n") except OSError as err: _LOGGER.error("Can't write local resolv: %s", err) raise CoreDNSError() from None diff --git a/hassio/tasks.py b/hassio/tasks.py index 13e21f5a4..3135364b7 100644 --- a/hassio/tasks.py +++ b/hassio/tasks.py @@ -228,7 +228,7 @@ class Tasks(CoreSysAttributes): if await self.sys_dns.is_fails(): _LOGGER.warning("CoreDNS plugin is in fails state / Reset config") - self.sys_dns.reset() + await self.sys_dns.reset() try: await self.sys_dns.start()