Change handling with host files (#1223)

This commit is contained in:
Pascal Vizeli 2019-08-16 12:47:32 +02:00 committed by GitHub
parent 734fe3afde
commit a2cf7ece70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 37 deletions

View File

@ -10,6 +10,7 @@ from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import ( from ..exceptions import (
AddonsError, AddonsError,
AddonsNotSupportedError, AddonsNotSupportedError,
CoreDNSError,
DockerAPIError, DockerAPIError,
HomeAssistantAPIError, HomeAssistantAPIError,
HostAppArmorError, HostAppArmorError,
@ -74,6 +75,9 @@ class AddonManager(CoreSysAttributes):
if tasks: if tasks:
await asyncio.wait(tasks) await asyncio.wait(tasks)
# Sync DNS
await self.sync_dns()
async def boot(self, stage: str) -> None: async def boot(self, stage: str) -> None:
"""Boot add-ons with mode auto.""" """Boot add-ons with mode auto."""
tasks = [] tasks = []
@ -299,3 +303,17 @@ class AddonManager(CoreSysAttributes):
_LOGGER.error("Can't repair %s", addon.slug) _LOGGER.error("Can't repair %s", addon.slug)
with suppress(AddonsError): with suppress(AddonsError):
await self.uninstall(addon.slug) 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()

View File

@ -1,7 +1,7 @@
"""Init file for Hass.io add-ons.""" """Init file for Hass.io add-ons."""
from contextlib import suppress from contextlib import suppress
from copy import deepcopy from copy import deepcopy
from ipaddress import IPv4Address, ip_address from ipaddress import IPv4Address
import logging import logging
from pathlib import Path, PurePath from pathlib import Path, PurePath
import re import re
@ -81,8 +81,6 @@ class Addon(AddonModel):
@property @property
def ip_address(self) -> IPv4Address: def ip_address(self) -> IPv4Address:
"""Return IP of Add-on instance.""" """Return IP of Add-on instance."""
if not self.is_installed:
return ip_address("0.0.0.0")
return self.instance.ip_address return self.instance.ip_address
@property @property

View File

@ -2,7 +2,7 @@
import asyncio import asyncio
import logging import logging
from contextlib import suppress from contextlib import suppress
from ipaddress import IPv4Address, AddressValueError from ipaddress import IPv4Address
from pathlib import Path from pathlib import Path
from string import Template from string import Template
from typing import Awaitable, Dict, List, Optional from typing import Awaitable, Dict, List, Optional
@ -81,8 +81,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
async def load(self) -> None: async def load(self) -> None:
"""Load DNS setup.""" """Load DNS setup."""
with suppress(CoreDNSError): self._init_hosts()
self._import_hosts()
# Check CoreDNS state # Check CoreDNS state
try: try:
@ -181,13 +180,15 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.error("Can't start CoreDNS plugin") _LOGGER.error("Can't start CoreDNS plugin")
raise CoreDNSError() from None raise CoreDNSError() from None
def reset(self) -> None: async def reset(self) -> None:
"""Reset Config / Hosts.""" """Reset Config / Hosts."""
self.servers = DNS_SERVERS self.servers = DNS_SERVERS
with suppress(OSError): with suppress(OSError):
self.hosts.unlink() self.hosts.unlink()
self._import_hosts() self._init_hosts()
await self.sys_addons.sync_dns()
def _write_corefile(self) -> None: def _write_corefile(self) -> None:
"""Write CoreDNS config.""" """Write CoreDNS config."""
@ -207,43 +208,34 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.error("Can't update corefile: %s", err) _LOGGER.error("Can't update corefile: %s", err)
raise CoreDNSError() from None raise CoreDNSError() from None
def _import_hosts(self) -> None: def _init_hosts(self) -> None:
"""Import hosts entry.""" """Import hosts entry."""
# Generate Default # Generate Default
if not self.hosts.exists():
self.add_host(self.sys_docker.network.supervisor, ["hassio", "supervisor"])
self.add_host( self.add_host(
self.sys_docker.network.gateway, ["homeassistant", "home-assistant"] self.sys_docker.network.supervisor, ["hassio", "supervisor"], write=False
)
self.add_host(
self.sys_docker.network.gateway,
["homeassistant", "home-assistant"],
write=False,
) )
return
# Import Exists host table def write_hosts(self) -> None:
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:
"""Write hosts from memory to file.""" """Write hosts from memory to file."""
try: try:
with self.hosts.open("w") as hosts: with self.hosts.open("w") as hosts:
for address, hostnames in self._hosts.items(): for address, hostnames in self._hosts.items():
host = " ".join(hostnames) host = " ".join(hostnames)
hosts.write(f"{address!s} {host}") hosts.write(f"{address!s} {host}\n")
except OSError as err: except OSError as err:
_LOGGER.error("Can't write hosts file: %s", err) _LOGGER.error("Can't write hosts file: %s", err)
raise CoreDNSError() from None 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.""" """Add a new host entry."""
if not ipv4 or ipv4 == IPv4Address("0.0.0.0"):
return
hostnames: List[str] = [] hostnames: List[str] = []
for name in names: for name in names:
hostnames.append(name) hostnames.append(name)
@ -252,10 +244,14 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
self._hosts[ipv4] = hostnames self._hosts[ipv4] = hostnames
_LOGGER.debug("Add Host entry %s -> %s", ipv4, hostnames) _LOGGER.debug("Add Host entry %s -> %s", ipv4, hostnames)
self._write_hosts() if write:
self.write_hosts()
def delete_host( 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: ) -> None:
"""Remove a entry from hosts.""" """Remove a entry from hosts."""
if host: if host:
@ -270,7 +266,8 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
_LOGGER.debug("Remove Host entry %s", ipv4) _LOGGER.debug("Remove Host entry %s", ipv4)
self._hosts.pop(ipv4, None) self._hosts.pop(ipv4, None)
self._write_hosts() if write:
self.write_hosts()
else: else:
_LOGGER.warning("Can't remove Host entry: %s/%s", ipv4, host) _LOGGER.warning("Can't remove Host entry: %s/%s", ipv4, host)
@ -336,7 +333,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
try: try:
with RESOLV_CONF.open("w") as resolv: with RESOLV_CONF.open("w") as resolv:
for line in resolv_lines: for line in resolv_lines:
resolv.write(line) resolv.write(f"{line}\n")
except OSError as err: except OSError as err:
_LOGGER.error("Can't write local resolv: %s", err) _LOGGER.error("Can't write local resolv: %s", err)
raise CoreDNSError() from None raise CoreDNSError() from None

View File

@ -228,7 +228,7 @@ class Tasks(CoreSysAttributes):
if await self.sys_dns.is_fails(): if await self.sys_dns.is_fails():
_LOGGER.warning("CoreDNS plugin is in fails state / Reset config") _LOGGER.warning("CoreDNS plugin is in fails state / Reset config")
self.sys_dns.reset() await self.sys_dns.reset()
try: try:
await self.sys_dns.start() await self.sys_dns.start()