Merge pull request #2018 from home-assistant/dev

Release 240
This commit is contained in:
Pascal Vizeli 2020-09-05 13:11:36 +02:00 committed by GitHub
commit 979861b764
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 107 additions and 17 deletions

View File

@ -359,11 +359,17 @@ class AddonManager(CoreSysAttributes):
"""Sync add-ons DNS names.""" """Sync add-ons DNS names."""
# Update hosts # Update hosts
for addon in self.installed: for addon in self.installed:
if not await addon.instance.is_running(): try:
continue if not await addon.instance.is_running():
self.sys_plugins.dns.add_host( continue
ipv4=addon.ip_address, names=[addon.hostname], write=False except DockerAPIError as err:
) _LOGGER.warning("Add-on %s is corrupt: %s", addon.slug, err)
self.sys_core.healthy = False
self.sys_capture_exception(err)
else:
self.sys_plugins.dns.add_host(
ipv4=addon.ip_address, names=[addon.hostname], write=False
)
# Write hosts files # Write hosts files
with suppress(CoreDNSError): with suppress(CoreDNSError):

View File

@ -558,7 +558,7 @@ class Addon(AddonModel):
await self.instance.run() await self.instance.run()
except DockerAPIError as err: except DockerAPIError as err:
self.state = AddonState.ERROR self.state = AddonState.ERROR
raise AddonsError(err) from None raise AddonsError(err) from err
else: else:
self.state = AddonState.STARTED self.state = AddonState.STARTED

View File

@ -3,7 +3,7 @@ from enum import Enum
from ipaddress import ip_network from ipaddress import ip_network
from pathlib import Path from pathlib import Path
SUPERVISOR_VERSION = "239" SUPERVISOR_VERSION = "240"
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor.txt" URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor.txt"
@ -240,6 +240,7 @@ ATTR_SNAPSHOT_EXCLUDE = "snapshot_exclude"
ATTR_SNAPSHOTS = "snapshots" ATTR_SNAPSHOTS = "snapshots"
ATTR_SOURCE = "source" ATTR_SOURCE = "source"
ATTR_SQUASH = "squash" ATTR_SQUASH = "squash"
ATTR_SSID = "ssid"
ATTR_SSL = "ssl" ATTR_SSL = "ssl"
ATTR_STAGE = "stage" ATTR_STAGE = "stage"
ATTR_STARTUP = "startup" ATTR_STARTUP = "startup"

View File

@ -19,6 +19,8 @@ DBUS_OBJECT_HOSTNAME = "/org/freedesktop/hostname1"
DBUS_OBJECT_NM = "/org/freedesktop/NetworkManager" DBUS_OBJECT_NM = "/org/freedesktop/NetworkManager"
DBUS_OBJECT_SYSTEMD = "/org/freedesktop/systemd1" DBUS_OBJECT_SYSTEMD = "/org/freedesktop/systemd1"
DBUS_ATTR_802_WIRELESS = "802-11-wireless"
DBUS_ATTR_802_WIRELESS_SECURITY = "802-11-wireless-security"
DBUS_ATTR_ACTIVE_CONNECTIONS = "ActiveConnections" DBUS_ATTR_ACTIVE_CONNECTIONS = "ActiveConnections"
DBUS_ATTR_ADDRESS_DATA = "AddressData" DBUS_ATTR_ADDRESS_DATA = "AddressData"
DBUS_ATTR_BOOT_SLOT = "BootSlot" DBUS_ATTR_BOOT_SLOT = "BootSlot"

View File

@ -60,3 +60,11 @@ class NetworkDevice:
ip4_address: int = attr.ib() ip4_address: int = attr.ib()
device_type: int = attr.ib() device_type: int = attr.ib()
real: bool = attr.ib() real: bool = attr.ib()
@attr.s
class WirelessProperties:
"""WirelessProperties object for Network Manager."""
properties: dict = attr.ib()
security: dict = attr.ib()

View File

@ -4,6 +4,8 @@ from typing import Optional
from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX
from ...utils.gdbus import DBus from ...utils.gdbus import DBus
from ..const import ( from ..const import (
DBUS_ATTR_802_WIRELESS,
DBUS_ATTR_802_WIRELESS_SECURITY,
DBUS_ATTR_ADDRESS_DATA, DBUS_ATTR_ADDRESS_DATA,
DBUS_ATTR_CONNECTION, DBUS_ATTR_CONNECTION,
DBUS_ATTR_DEFAULT, DBUS_ATTR_DEFAULT,
@ -23,6 +25,7 @@ from ..const import (
DBUS_NAME_IP4CONFIG, DBUS_NAME_IP4CONFIG,
DBUS_NAME_NM, DBUS_NAME_NM,
DBUS_OBJECT_BASE, DBUS_OBJECT_BASE,
ConnectionType,
) )
from .configuration import ( from .configuration import (
AddressData, AddressData,
@ -30,6 +33,7 @@ from .configuration import (
NetworkAttributes, NetworkAttributes,
NetworkDevice, NetworkDevice,
NetworkSettings, NetworkSettings,
WirelessProperties,
) )
@ -44,6 +48,7 @@ class NetworkConnection(NetworkAttributes):
self._settings: Optional[NetworkSettings] = None self._settings: Optional[NetworkSettings] = None
self._ip4_config: Optional[IpConfiguration] = None self._ip4_config: Optional[IpConfiguration] = None
self._device: Optional[NetworkDevice] self._device: Optional[NetworkDevice]
self._wireless: Optional[WirelessProperties] = None
self.primary: bool = False self.primary: bool = False
@property @property
@ -81,6 +86,13 @@ class NetworkConnection(NetworkAttributes):
"""Return the uuid of the connection.""" """Return the uuid of the connection."""
return self._properties[DBUS_ATTR_UUID] return self._properties[DBUS_ATTR_UUID]
@property
def wireless(self) -> str:
"""Return wireless properties if any."""
if self.type != ConnectionType.WIRELESS:
return None
return self._wireless
@property @property
def state(self) -> int: def state(self) -> int:
""" """
@ -119,6 +131,11 @@ class NetworkConnection(NetworkAttributes):
), ),
) )
self._wireless = WirelessProperties(
data.get(DBUS_ATTR_802_WIRELESS, {}),
data.get(DBUS_ATTR_802_WIRELESS_SECURITY, {}),
)
self._device = NetworkDevice( self._device = NetworkDevice(
device, device,
device_data.get(DBUS_ATTR_DEVICE_INTERFACE), device_data.get(DBUS_ATTR_DEVICE_INTERFACE),

View File

@ -4,6 +4,7 @@ from ..const import (
DBUS_NAME_CONNECTION_ACTIVE, DBUS_NAME_CONNECTION_ACTIVE,
DBUS_NAME_NM, DBUS_NAME_NM,
DBUS_OBJECT_BASE, DBUS_OBJECT_BASE,
ConnectionType,
InterfaceMethod, InterfaceMethod,
) )
from ..payloads.generate import interface_update_payload from ..payloads.generate import interface_update_payload
@ -49,7 +50,7 @@ class NetworkInterface:
return self.connection.ip4_config.address_data.prefix return self.connection.ip4_config.address_data.prefix
@property @property
def type(self) -> str: def type(self) -> ConnectionType:
"""Return the interface type.""" """Return the interface type."""
return self.connection.type return self.connection.type

View File

@ -3,8 +3,8 @@ from pathlib import Path
import jinja2 import jinja2
from ...const import ATTR_ADDRESS, ATTR_DNS, ATTR_METHOD, ATTR_PREFIX from ...const import ATTR_ADDRESS, ATTR_DNS, ATTR_METHOD, ATTR_PREFIX, ATTR_SSID
from ..const import InterfaceMethod from ..const import ConnectionType, InterfaceMethod
from ..network.utils import ip2int from ..network.utils import ip2int
INTERFACE_UPDATE_TEMPLATE: Path = ( INTERFACE_UPDATE_TEMPLATE: Path = (
@ -31,4 +31,15 @@ def interface_update_payload(interface, **kwargs) -> str:
kwargs[ATTR_ADDRESS] = kwargs[ATTR_ADDRESS].split("/")[0] kwargs[ATTR_ADDRESS] = kwargs[ATTR_ADDRESS].split("/")[0]
kwargs[ATTR_METHOD] = InterfaceMethod.MANUAL kwargs[ATTR_METHOD] = InterfaceMethod.MANUAL
if interface.type == ConnectionType.WIRELESS:
kwargs[ATTR_SSID] = ", ".join(
[
f"0x{x}"
for x in interface.connection.wireless.properties[ATTR_SSID]
.encode()
.hex(",")
.split(",")
]
)
return template.render(interface=interface, options=kwargs) return template.render(interface=interface, options=kwargs)

View File

@ -23,4 +23,18 @@
'gateway': <'{{ options.get("gateway", interface.gateway) }}'> 'gateway': <'{{ options.get("gateway", interface.gateway) }}'>
} }
{% endif %} {% endif %}
{% if interface.type == "802-11-wireless" %}
,
'802-11-wireless':
{
'security': <'802-11-wireless-security'>,
'ssid': <[byte {{ options.ssid }}]>
},
'802-11-wireless-security':
{
'auth-alg': <'{{ interface.connection.wireless.security['auth-alg'] }}'>,
'key-mgmt': <'{{ interface.connection.wireless.security['key-mgmt'] }}'>
}
{% endif %}
} }

View File

@ -149,7 +149,7 @@ class DockerAPI:
container.start() container.start()
except (docker.errors.DockerException, requests.RequestException) as err: except (docker.errors.DockerException, requests.RequestException) as err:
_LOGGER.error("Can't start %s: %s", name, err) _LOGGER.error("Can't start %s: %s", name, err)
raise DockerAPIError(err) from None raise DockerAPIError(err) from err
# Update metadata # Update metadata
with suppress(docker.errors.DockerException, requests.RequestException): with suppress(docker.errors.DockerException, requests.RequestException):

View File

@ -308,7 +308,7 @@ class Tasks(CoreSysAttributes):
try: try:
await addon.start() await addon.start()
except AddonsError as err: except AddonsError as err:
_LOGGER.error("Watchdog %s reanimation failed!", addon.slug) _LOGGER.error("Watchdog %s reanimation failed with %s", addon.slug, err)
self.sys_capture_exception(err) self.sys_capture_exception(err)
async def _watchdog_addon_application(self): async def _watchdog_addon_application(self):
@ -338,7 +338,7 @@ class Tasks(CoreSysAttributes):
try: try:
await addon.restart() await addon.restart()
except AddonsError as err: except AddonsError as err:
_LOGGER.error("Watchdog %s reanimation failed!", addon.slug) _LOGGER.error("Watchdog %s reanimation failed with %s", addon.slug, err)
self.sys_capture_exception(err) self.sys_capture_exception(err)
finally: finally:
self._cache[addon.slug] = 0 self._cache[addon.slug] = 0

View File

@ -74,7 +74,21 @@ class StoreData(CoreSysAttributes):
def _read_addons_folder(self, path, repository): def _read_addons_folder(self, path, repository):
"""Read data from add-ons folder.""" """Read data from add-ons folder."""
for addon in path.glob("**/config.json"): try:
addon_list = path.glob("**/config.json")
except OSError as err:
self.sys_core.healthy = False
_LOGGER.critical(
"Can't process %s because of Filesystem issues: %s", repository, err
)
self.sys_capture_exception(err)
return
for addon in addon_list:
# Ingore git artefacts
if ".git" in addon.parts:
continue
try: try:
addon_config = read_json_file(addon) addon_config = read_json_file(addon)
except JsonFileError: except JsonFileError:

View File

@ -1,12 +1,13 @@
"""Test interface update payload.""" """Test interface update payload."""
import pytest import pytest
from supervisor.dbus.const import ConnectionType
from supervisor.dbus.payloads.generate import interface_update_payload from supervisor.dbus.payloads.generate import interface_update_payload
from supervisor.utils.gdbus import DBus from supervisor.utils.gdbus import DBus
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_interface_update_payload(network_interface): async def test_interface_update_payload_ethernet(network_interface):
"""Test interface update payload.""" """Test interface update payload."""
data = interface_update_payload(network_interface, **{"method": "auto"}) data = interface_update_payload(network_interface, **{"method": "auto"})
assert DBus.parse_gvariant(data)["ipv4"]["method"] == "auto" assert DBus.parse_gvariant(data)["ipv4"]["method"] == "auto"
@ -17,3 +18,18 @@ async def test_interface_update_payload(network_interface):
assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual" assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual"
assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1" assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1"
assert DBus.parse_gvariant(data)["ipv4"]["dns"] == [16843009, 16777217] assert DBus.parse_gvariant(data)["ipv4"]["dns"] == [16843009, 16777217]
@pytest.mark.asyncio
async def test_interface_update_payload_wireless(network_interface):
"""Test interface update payload."""
network_interface.connection._properties["Type"] = ConnectionType.WIRELESS
data = interface_update_payload(network_interface, **{"method": "auto"})
assert DBus.parse_gvariant(data)["ipv4"]["method"] == "auto"
data = interface_update_payload(
network_interface, **{"address": "1.1.1.1", "dns": ["1.1.1.1", "1.0.0.1"]}
)
assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual"
assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1"
assert DBus.parse_gvariant(data)["802-11-wireless"]["ssid"] == "NETT"

View File

@ -1 +1 @@
({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': <uint64 1598125548>, 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': <uint32 24>}]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': <false>, 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}},) ({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': <uint64 1598125548>, 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': <uint32 24>}]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': <false>, 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}, '802-11-wireless': {'ssid': <[byte 0x4e, 0x45, 0x54, 0x54]>}},)

View File

@ -1 +1 @@
({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': <uint64 1598125548>, 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': <uint32 24>}]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': <false>, 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}},) ({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': <uint64 1598125548>, 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': <uint32 24>}]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': <false>, 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}, '802-11-wireless': {'ssid': <[byte 0x4e, 0x45, 0x54, 0x54]>}},)