mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-06-21 01:16:29 +00:00
D-Bus NetworkManager improvements (#3243)
* Introduce enum for network connectivity * Differentiate between Bus Name and Interface consts The Bus names and interfaces look quite similar in D-Bus: Both use dots to separate words. Usually all interfaces available below a certan Bus name start with the Bus name. Quite often the Bus name itself is also available as an interface. However, those are different things. To avoid confusion, add the type of const to the const name. * Remove unused const * Disconnect D-Bus when not used Make sure Python disconnects from D-Bus when objects get destroyed. This avoids exhausting D-Bus connection limit which causes the following error message: [system] The maximum number of active connections for UID 0 has been reached (max_connections_per_user=256) * Filter signals by object as well Make sure we only listen to signals on that particular object. Also support filtering messages via message filter callback. * Explicitly wait until Connection is activated Wait for activated or raise an error. This avoids too early/errornous updates when state of the connection changes to "activating" or similar intermediate signal states. Fixes: #2639 * Fix VLAN configuration * Add link to D-Bus object documentation * Fix network settings update test * Make MessageBus object optional
This commit is contained in:
parent
e2f39059c6
commit
435f479984
@ -280,7 +280,6 @@ ATTR_SIZE = "size"
|
|||||||
ATTR_SLUG = "slug"
|
ATTR_SLUG = "slug"
|
||||||
ATTR_SOURCE = "source"
|
ATTR_SOURCE = "source"
|
||||||
ATTR_SQUASH = "squash"
|
ATTR_SQUASH = "squash"
|
||||||
ATTR_SSD = "ssid"
|
|
||||||
ATTR_SSID = "ssid"
|
ATTR_SSID = "ssid"
|
||||||
ATTR_SSL = "ssl"
|
ATTR_SSL = "ssl"
|
||||||
ATTR_STAGE = "stage"
|
ATTR_STAGE = "stage"
|
||||||
|
@ -10,6 +10,7 @@ from ...utils.dbus import DBus
|
|||||||
from ..const import (
|
from ..const import (
|
||||||
DBUS_ATTR_DIAGNOSTICS,
|
DBUS_ATTR_DIAGNOSTICS,
|
||||||
DBUS_ATTR_VERSION,
|
DBUS_ATTR_VERSION,
|
||||||
|
DBUS_IFACE_HAOS,
|
||||||
DBUS_NAME_HAOS,
|
DBUS_NAME_HAOS,
|
||||||
DBUS_OBJECT_HAOS,
|
DBUS_OBJECT_HAOS,
|
||||||
)
|
)
|
||||||
@ -74,7 +75,7 @@ class OSAgent(DBusInterface):
|
|||||||
def diagnostics(self, value: bool) -> None:
|
def diagnostics(self, value: bool) -> None:
|
||||||
"""Enable or disable OS-Agent diagnostics."""
|
"""Enable or disable OS-Agent diagnostics."""
|
||||||
asyncio.create_task(
|
asyncio.create_task(
|
||||||
self.dbus.set_property(DBUS_NAME_HAOS, DBUS_ATTR_DIAGNOSTICS, value)
|
self.dbus.set_property(DBUS_IFACE_HAOS, DBUS_ATTR_DIAGNOSTICS, value)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
@ -95,6 +96,6 @@ class OSAgent(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_HAOS)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_HAOS)
|
||||||
await self.apparmor.update()
|
await self.apparmor.update()
|
||||||
await self.datadisk.update()
|
await self.datadisk.update()
|
||||||
|
@ -7,8 +7,8 @@ from awesomeversion import AwesomeVersion
|
|||||||
from ...utils.dbus import DBus
|
from ...utils.dbus import DBus
|
||||||
from ..const import (
|
from ..const import (
|
||||||
DBUS_ATTR_PARSER_VERSION,
|
DBUS_ATTR_PARSER_VERSION,
|
||||||
|
DBUS_IFACE_HAOS_APPARMOR,
|
||||||
DBUS_NAME_HAOS,
|
DBUS_NAME_HAOS,
|
||||||
DBUS_NAME_HAOS_APPARMOR,
|
|
||||||
DBUS_OBJECT_HAOS_APPARMOR,
|
DBUS_OBJECT_HAOS_APPARMOR,
|
||||||
)
|
)
|
||||||
from ..interface import DBusInterface, dbus_property
|
from ..interface import DBusInterface, dbus_property
|
||||||
@ -35,7 +35,7 @@ class AppArmor(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_HAOS_APPARMOR)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_HAOS_APPARMOR)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def load_profile(self, profile: Path, cache: Path) -> None:
|
async def load_profile(self, profile: Path, cache: Path) -> None:
|
||||||
|
@ -5,8 +5,8 @@ from typing import Any
|
|||||||
from ...utils.dbus import DBus
|
from ...utils.dbus import DBus
|
||||||
from ..const import (
|
from ..const import (
|
||||||
DBUS_ATTR_CURRENT_DEVICE,
|
DBUS_ATTR_CURRENT_DEVICE,
|
||||||
|
DBUS_IFACE_HAOS_DATADISK,
|
||||||
DBUS_NAME_HAOS,
|
DBUS_NAME_HAOS,
|
||||||
DBUS_NAME_HAOS_DATADISK,
|
|
||||||
DBUS_OBJECT_HAOS_DATADISK,
|
DBUS_OBJECT_HAOS_DATADISK,
|
||||||
)
|
)
|
||||||
from ..interface import DBusInterface, dbus_property
|
from ..interface import DBusInterface, dbus_property
|
||||||
@ -33,7 +33,7 @@ class DataDisk(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_HAOS_DATADISK)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_HAOS_DATADISK)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def change_device(self, device: Path) -> None:
|
async def change_device(self, device: Path) -> None:
|
||||||
|
@ -1,32 +1,37 @@
|
|||||||
"""Constants for DBUS."""
|
"""Constants for DBUS."""
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
DBUS_NAME_ACCESSPOINT = "org.freedesktop.NetworkManager.AccessPoint"
|
|
||||||
DBUS_NAME_CONNECTION_ACTIVE = "org.freedesktop.NetworkManager.Connection.Active"
|
|
||||||
DBUS_NAME_DEVICE = "org.freedesktop.NetworkManager.Device"
|
|
||||||
DBUS_NAME_DEVICE_WIRELESS = "org.freedesktop.NetworkManager.Device.Wireless"
|
|
||||||
DBUS_NAME_DNS = "org.freedesktop.NetworkManager.DnsManager"
|
|
||||||
DBUS_NAME_HAOS = "io.hass.os"
|
DBUS_NAME_HAOS = "io.hass.os"
|
||||||
DBUS_NAME_HAOS_APPARMOR = "io.hass.os.AppArmor"
|
|
||||||
DBUS_NAME_HAOS_CGROUP = "io.hass.os.CGroup"
|
|
||||||
DBUS_NAME_HAOS_DATADISK = "io.hass.os.DataDisk"
|
|
||||||
DBUS_NAME_HAOS_SYSTEM = "io.hass.os.System"
|
|
||||||
DBUS_NAME_HOSTNAME = "org.freedesktop.hostname1"
|
DBUS_NAME_HOSTNAME = "org.freedesktop.hostname1"
|
||||||
DBUS_NAME_IP4CONFIG = "org.freedesktop.NetworkManager.IP4Config"
|
|
||||||
DBUS_NAME_IP6CONFIG = "org.freedesktop.NetworkManager.IP6Config"
|
|
||||||
DBUS_NAME_LOGIND = "org.freedesktop.login1"
|
DBUS_NAME_LOGIND = "org.freedesktop.login1"
|
||||||
DBUS_NAME_NM = "org.freedesktop.NetworkManager"
|
DBUS_NAME_NM = "org.freedesktop.NetworkManager"
|
||||||
DBUS_NAME_NM_CONNECTION_ACTIVE_CHANGED = (
|
|
||||||
"org.freedesktop.NetworkManager.Connection.Active.StateChanged"
|
|
||||||
)
|
|
||||||
DBUS_NAME_RAUC = "de.pengutronix.rauc"
|
DBUS_NAME_RAUC = "de.pengutronix.rauc"
|
||||||
DBUS_NAME_RAUC_INSTALLER = "de.pengutronix.rauc.Installer"
|
|
||||||
DBUS_NAME_RAUC_INSTALLER_COMPLETED = "de.pengutronix.rauc.Installer.Completed"
|
|
||||||
DBUS_NAME_SETTINGS_CONNECTION = "org.freedesktop.NetworkManager.Settings.Connection"
|
|
||||||
DBUS_NAME_SYSTEMD = "org.freedesktop.systemd1"
|
DBUS_NAME_SYSTEMD = "org.freedesktop.systemd1"
|
||||||
DBUS_NAME_SYSTEMD_MANAGER = "org.freedesktop.systemd1.Manager"
|
|
||||||
DBUS_NAME_TIMEDATE = "org.freedesktop.timedate1"
|
DBUS_NAME_TIMEDATE = "org.freedesktop.timedate1"
|
||||||
|
|
||||||
|
DBUS_IFACE_ACCESSPOINT = "org.freedesktop.NetworkManager.AccessPoint"
|
||||||
|
DBUS_IFACE_CONNECTION_ACTIVE = "org.freedesktop.NetworkManager.Connection.Active"
|
||||||
|
DBUS_IFACE_DEVICE = "org.freedesktop.NetworkManager.Device"
|
||||||
|
DBUS_IFACE_DEVICE_WIRELESS = "org.freedesktop.NetworkManager.Device.Wireless"
|
||||||
|
DBUS_IFACE_DNS = "org.freedesktop.NetworkManager.DnsManager"
|
||||||
|
DBUS_IFACE_HAOS = "io.hass.os"
|
||||||
|
DBUS_IFACE_HAOS_APPARMOR = "io.hass.os.AppArmor"
|
||||||
|
DBUS_IFACE_HAOS_CGROUP = "io.hass.os.CGroup"
|
||||||
|
DBUS_IFACE_HAOS_DATADISK = "io.hass.os.DataDisk"
|
||||||
|
DBUS_IFACE_HAOS_SYSTEM = "io.hass.os.System"
|
||||||
|
DBUS_IFACE_HOSTNAME = "org.freedesktop.hostname1"
|
||||||
|
DBUS_IFACE_IP4CONFIG = "org.freedesktop.NetworkManager.IP4Config"
|
||||||
|
DBUS_IFACE_IP6CONFIG = "org.freedesktop.NetworkManager.IP6Config"
|
||||||
|
DBUS_IFACE_NM = "org.freedesktop.NetworkManager"
|
||||||
|
DBUS_IFACE_RAUC_INSTALLER = "de.pengutronix.rauc.Installer"
|
||||||
|
DBUS_IFACE_SETTINGS_CONNECTION = "org.freedesktop.NetworkManager.Settings.Connection"
|
||||||
|
DBUS_IFACE_SYSTEMD_MANAGER = "org.freedesktop.systemd1.Manager"
|
||||||
|
DBUS_IFACE_TIMEDATE = "org.freedesktop.timedate1"
|
||||||
|
|
||||||
|
DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED = (
|
||||||
|
"org.freedesktop.NetworkManager.Connection.Active.StateChanged"
|
||||||
|
)
|
||||||
|
DBUS_SIGNAL_RAUC_INSTALLER_COMPLETED = "de.pengutronix.rauc.Installer.Completed"
|
||||||
|
|
||||||
DBUS_OBJECT_BASE = "/"
|
DBUS_OBJECT_BASE = "/"
|
||||||
DBUS_OBJECT_DNS = "/org/freedesktop/NetworkManager/DnsManager"
|
DBUS_OBJECT_DNS = "/org/freedesktop/NetworkManager/DnsManager"
|
||||||
@ -135,6 +140,19 @@ class ConnectionStateType(int, Enum):
|
|||||||
DEACTIVATED = 4
|
DEACTIVATED = 4
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectivityState(int, Enum):
|
||||||
|
"""Network connectvity.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMConnectivityState
|
||||||
|
"""
|
||||||
|
|
||||||
|
CONNECTIVITY_UNKNOWN = 0
|
||||||
|
CONNECTIVITY_NONE = 1
|
||||||
|
CONNECTIVITY_PORTAL = 2
|
||||||
|
CONNECTIVITY_LIMITED = 3
|
||||||
|
CONNECTIVITY_FULL = 4
|
||||||
|
|
||||||
|
|
||||||
class DeviceType(int, Enum):
|
class DeviceType(int, Enum):
|
||||||
"""Device types.
|
"""Device types.
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ from .const import (
|
|||||||
DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME,
|
DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME,
|
||||||
DBUS_ATTR_STATIC_HOSTNAME,
|
DBUS_ATTR_STATIC_HOSTNAME,
|
||||||
DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME,
|
DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME,
|
||||||
|
DBUS_IFACE_HOSTNAME,
|
||||||
DBUS_NAME_HOSTNAME,
|
DBUS_NAME_HOSTNAME,
|
||||||
DBUS_OBJECT_HOSTNAME,
|
DBUS_OBJECT_HOSTNAME,
|
||||||
)
|
)
|
||||||
@ -87,4 +88,4 @@ class Hostname(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_HOSTNAME)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_HOSTNAME)
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
"""Network Manager implementation for DBUS."""
|
"""Network Manager implementation for DBUS."""
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Awaitable
|
from typing import Any, Awaitable
|
||||||
|
|
||||||
from awesomeversion import AwesomeVersion, AwesomeVersionException
|
from awesomeversion import AwesomeVersion, AwesomeVersionException
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
|
||||||
|
from supervisor.dbus.network.connection import NetworkConnection
|
||||||
|
from supervisor.dbus.network.setting import NetworkSetting
|
||||||
|
|
||||||
from ...exceptions import (
|
from ...exceptions import (
|
||||||
DBusError,
|
DBusError,
|
||||||
DBusFatalError,
|
DBusFatalError,
|
||||||
@ -17,6 +21,7 @@ from ..const import (
|
|||||||
DBUS_ATTR_DEVICES,
|
DBUS_ATTR_DEVICES,
|
||||||
DBUS_ATTR_PRIMARY_CONNECTION,
|
DBUS_ATTR_PRIMARY_CONNECTION,
|
||||||
DBUS_ATTR_VERSION,
|
DBUS_ATTR_VERSION,
|
||||||
|
DBUS_IFACE_NM,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
DBUS_OBJECT_BASE,
|
DBUS_OBJECT_BASE,
|
||||||
DBUS_OBJECT_NM,
|
DBUS_OBJECT_NM,
|
||||||
@ -34,7 +39,10 @@ MINIMAL_VERSION = AwesomeVersion("1.14.6")
|
|||||||
|
|
||||||
|
|
||||||
class NetworkManager(DBusInterface):
|
class NetworkManager(DBusInterface):
|
||||||
"""Handle D-Bus interface for Network Manager."""
|
"""Handle D-Bus interface for Network Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
|
||||||
|
"""
|
||||||
|
|
||||||
name = DBUS_NAME_NM
|
name = DBUS_NAME_NM
|
||||||
|
|
||||||
@ -72,23 +80,32 @@ class NetworkManager(DBusInterface):
|
|||||||
return AwesomeVersion(self.properties[DBUS_ATTR_VERSION])
|
return AwesomeVersion(self.properties[DBUS_ATTR_VERSION])
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
def activate_connection(
|
async def activate_connection(
|
||||||
self, connection_object: str, device_object: str
|
self, connection_object: str, device_object: str
|
||||||
) -> Awaitable[Any]:
|
) -> NetworkConnection:
|
||||||
"""Activate a connction on a device."""
|
"""Activate a connction on a device."""
|
||||||
return self.dbus.ActivateConnection(
|
result = await self.dbus.ActivateConnection(
|
||||||
("o", connection_object), ("o", device_object), ("o", DBUS_OBJECT_BASE)
|
("o", connection_object), ("o", device_object), ("o", DBUS_OBJECT_BASE)
|
||||||
)
|
)
|
||||||
|
obj_active_con = result[0]
|
||||||
|
active_con = NetworkConnection(obj_active_con)
|
||||||
|
await active_con.connect()
|
||||||
|
return active_con
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
def add_and_activate_connection(
|
async def add_and_activate_connection(
|
||||||
self, settings: Any, device_object: str
|
self, settings: Any, device_object: str
|
||||||
) -> Awaitable[Any]:
|
) -> tuple[NetworkSetting, NetworkConnection]:
|
||||||
"""Activate a connction on a device."""
|
"""Activate a connction on a device."""
|
||||||
return self.dbus.AddAndActivateConnection(
|
obj_con_setting, obj_active_con = await self.dbus.AddAndActivateConnection(
|
||||||
("a{sa{sv}}", settings), ("o", device_object), ("o", DBUS_OBJECT_BASE)
|
("a{sa{sv}}", settings), ("o", device_object), ("o", DBUS_OBJECT_BASE)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
con_setting = NetworkSetting(obj_con_setting)
|
||||||
|
active_con = NetworkConnection(obj_active_con)
|
||||||
|
await asyncio.gather(con_setting.connect(), active_con.connect())
|
||||||
|
return con_setting, active_con
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def check_connectivity(self) -> Awaitable[Any]:
|
async def check_connectivity(self) -> Awaitable[Any]:
|
||||||
"""Check the connectivity of the host."""
|
"""Check the connectivity of the host."""
|
||||||
@ -118,7 +135,7 @@ class NetworkManager(DBusInterface):
|
|||||||
|
|
||||||
async def _validate_version(self) -> None:
|
async def _validate_version(self) -> None:
|
||||||
"""Validate Version of NetworkManager."""
|
"""Validate Version of NetworkManager."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_NM)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_NM)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.version >= MINIMAL_VERSION:
|
if self.version >= MINIMAL_VERSION:
|
||||||
@ -134,7 +151,7 @@ class NetworkManager(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_NM)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_NM)
|
||||||
|
|
||||||
await self.dns.update()
|
await self.dns.update()
|
||||||
|
|
||||||
|
@ -7,14 +7,17 @@ from ..const import (
|
|||||||
DBUS_ATTR_MODE,
|
DBUS_ATTR_MODE,
|
||||||
DBUS_ATTR_SSID,
|
DBUS_ATTR_SSID,
|
||||||
DBUS_ATTR_STRENGTH,
|
DBUS_ATTR_STRENGTH,
|
||||||
DBUS_NAME_ACCESSPOINT,
|
DBUS_IFACE_ACCESSPOINT,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
)
|
)
|
||||||
from ..interface import DBusInterfaceProxy
|
from ..interface import DBusInterfaceProxy
|
||||||
|
|
||||||
|
|
||||||
class NetworkWirelessAP(DBusInterfaceProxy):
|
class NetworkWirelessAP(DBusInterfaceProxy):
|
||||||
"""NetworkWireless AP object for Network Manager."""
|
"""NetworkWireless AP object for Network Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.AccessPoint.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, object_path: str) -> None:
|
def __init__(self, object_path: str) -> None:
|
||||||
"""Initialize NetworkWireless AP object."""
|
"""Initialize NetworkWireless AP object."""
|
||||||
@ -49,4 +52,4 @@ class NetworkWirelessAP(DBusInterfaceProxy):
|
|||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
"""Get connection information."""
|
"""Get connection information."""
|
||||||
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_ACCESSPOINT)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_ACCESSPOINT)
|
||||||
|
@ -16,18 +16,22 @@ from ..const import (
|
|||||||
DBUS_ATTR_STATE,
|
DBUS_ATTR_STATE,
|
||||||
DBUS_ATTR_TYPE,
|
DBUS_ATTR_TYPE,
|
||||||
DBUS_ATTR_UUID,
|
DBUS_ATTR_UUID,
|
||||||
DBUS_NAME_CONNECTION_ACTIVE,
|
DBUS_IFACE_CONNECTION_ACTIVE,
|
||||||
DBUS_NAME_IP4CONFIG,
|
DBUS_IFACE_IP4CONFIG,
|
||||||
DBUS_NAME_IP6CONFIG,
|
DBUS_IFACE_IP6CONFIG,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
DBUS_OBJECT_BASE,
|
DBUS_OBJECT_BASE,
|
||||||
|
ConnectionStateType,
|
||||||
)
|
)
|
||||||
from ..interface import DBusInterfaceProxy
|
from ..interface import DBusInterfaceProxy
|
||||||
from .configuration import IpConfiguration
|
from .configuration import IpConfiguration
|
||||||
|
|
||||||
|
|
||||||
class NetworkConnection(DBusInterfaceProxy):
|
class NetworkConnection(DBusInterfaceProxy):
|
||||||
"""NetworkConnection object for Network Manager."""
|
"""Active network connection object for Network Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Connection.Active.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, object_path: str) -> None:
|
def __init__(self, object_path: str) -> None:
|
||||||
"""Initialize NetworkConnection object."""
|
"""Initialize NetworkConnection object."""
|
||||||
@ -53,7 +57,7 @@ class NetworkConnection(DBusInterfaceProxy):
|
|||||||
return self.properties[DBUS_ATTR_UUID]
|
return self.properties[DBUS_ATTR_UUID]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> int:
|
def state(self) -> ConnectionStateType:
|
||||||
"""Return the state of the connection."""
|
"""Return the state of the connection."""
|
||||||
return self.properties[DBUS_ATTR_STATE]
|
return self.properties[DBUS_ATTR_STATE]
|
||||||
|
|
||||||
@ -75,12 +79,12 @@ class NetworkConnection(DBusInterfaceProxy):
|
|||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
"""Get connection information."""
|
"""Get connection information."""
|
||||||
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_CONNECTION_ACTIVE)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_CONNECTION_ACTIVE)
|
||||||
|
|
||||||
# IPv4
|
# IPv4
|
||||||
if self.properties[DBUS_ATTR_IP4CONFIG] != DBUS_OBJECT_BASE:
|
if self.properties[DBUS_ATTR_IP4CONFIG] != DBUS_OBJECT_BASE:
|
||||||
ip4 = await DBus.connect(DBUS_NAME_NM, self.properties[DBUS_ATTR_IP4CONFIG])
|
ip4 = await DBus.connect(DBUS_NAME_NM, self.properties[DBUS_ATTR_IP4CONFIG])
|
||||||
ip4_data = await ip4.get_properties(DBUS_NAME_IP4CONFIG)
|
ip4_data = await ip4.get_properties(DBUS_IFACE_IP4CONFIG)
|
||||||
|
|
||||||
self._ipv4 = IpConfiguration(
|
self._ipv4 = IpConfiguration(
|
||||||
ip_address(ip4_data[DBUS_ATTR_GATEWAY])
|
ip_address(ip4_data[DBUS_ATTR_GATEWAY])
|
||||||
@ -99,7 +103,7 @@ class NetworkConnection(DBusInterfaceProxy):
|
|||||||
# IPv6
|
# IPv6
|
||||||
if self.properties[DBUS_ATTR_IP6CONFIG] != DBUS_OBJECT_BASE:
|
if self.properties[DBUS_ATTR_IP6CONFIG] != DBUS_OBJECT_BASE:
|
||||||
ip6 = await DBus.connect(DBUS_NAME_NM, self.properties[DBUS_ATTR_IP6CONFIG])
|
ip6 = await DBus.connect(DBUS_NAME_NM, self.properties[DBUS_ATTR_IP6CONFIG])
|
||||||
ip6_data = await ip6.get_properties(DBUS_NAME_IP6CONFIG)
|
ip6_data = await ip6.get_properties(DBUS_IFACE_IP6CONFIG)
|
||||||
|
|
||||||
self._ipv6 = IpConfiguration(
|
self._ipv6 = IpConfiguration(
|
||||||
ip_address(ip6_data[DBUS_ATTR_GATEWAY])
|
ip_address(ip6_data[DBUS_ATTR_GATEWAY])
|
||||||
|
@ -16,7 +16,7 @@ from ..const import (
|
|||||||
DBUS_ATTR_CONFIGURATION,
|
DBUS_ATTR_CONFIGURATION,
|
||||||
DBUS_ATTR_MODE,
|
DBUS_ATTR_MODE,
|
||||||
DBUS_ATTR_RCMANAGER,
|
DBUS_ATTR_RCMANAGER,
|
||||||
DBUS_NAME_DNS,
|
DBUS_IFACE_DNS,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
DBUS_OBJECT_DNS,
|
DBUS_OBJECT_DNS,
|
||||||
)
|
)
|
||||||
@ -28,7 +28,10 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class NetworkManagerDNS(DBusInterface):
|
class NetworkManagerDNS(DBusInterface):
|
||||||
"""Handle D-Bus interface for NMI DnsManager."""
|
"""Handle D-Bus interface for NM DnsManager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.DnsManager.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""Initialize Properties."""
|
"""Initialize Properties."""
|
||||||
@ -65,7 +68,7 @@ class NetworkManagerDNS(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
data = await self.dbus.get_properties(DBUS_NAME_DNS)
|
data = await self.dbus.get_properties(DBUS_IFACE_DNS)
|
||||||
if not data:
|
if not data:
|
||||||
_LOGGER.warning("Can't get properties for DnsManager")
|
_LOGGER.warning("Can't get properties for DnsManager")
|
||||||
return
|
return
|
||||||
|
@ -8,7 +8,7 @@ from ..const import (
|
|||||||
DBUS_ATTR_DEVICE_TYPE,
|
DBUS_ATTR_DEVICE_TYPE,
|
||||||
DBUS_ATTR_DRIVER,
|
DBUS_ATTR_DRIVER,
|
||||||
DBUS_ATTR_MANAGED,
|
DBUS_ATTR_MANAGED,
|
||||||
DBUS_NAME_DEVICE,
|
DBUS_IFACE_DEVICE,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
DBUS_OBJECT_BASE,
|
DBUS_OBJECT_BASE,
|
||||||
DeviceType,
|
DeviceType,
|
||||||
@ -20,7 +20,10 @@ from .wireless import NetworkWireless
|
|||||||
|
|
||||||
|
|
||||||
class NetworkInterface(DBusInterfaceProxy):
|
class NetworkInterface(DBusInterfaceProxy):
|
||||||
"""NetworkInterface object for Network Manager."""
|
"""NetworkInterface object represents Network Manager Device objects.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Device.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, nm_dbus: DBus, object_path: str) -> None:
|
def __init__(self, nm_dbus: DBus, object_path: str) -> None:
|
||||||
"""Initialize NetworkConnection object."""
|
"""Initialize NetworkConnection object."""
|
||||||
@ -72,13 +75,13 @@ class NetworkInterface(DBusInterfaceProxy):
|
|||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
"""Get device information."""
|
"""Get device information."""
|
||||||
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_DEVICE)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_DEVICE)
|
||||||
|
|
||||||
# Abort if device is not managed
|
# Abort if device is not managed
|
||||||
if not self.managed:
|
if not self.managed:
|
||||||
return
|
return
|
||||||
|
|
||||||
# If connection exists
|
# If active connection exists
|
||||||
if self.properties[DBUS_ATTR_ACTIVE_CONNECTION] != DBUS_OBJECT_BASE:
|
if self.properties[DBUS_ATTR_ACTIVE_CONNECTION] != DBUS_OBJECT_BASE:
|
||||||
self._connection = NetworkConnection(
|
self._connection = NetworkConnection(
|
||||||
self.properties[DBUS_ATTR_ACTIVE_CONNECTION]
|
self.properties[DBUS_ATTR_ACTIVE_CONNECTION]
|
||||||
|
@ -38,7 +38,10 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class NetworkSetting(DBusInterfaceProxy):
|
class NetworkSetting(DBusInterfaceProxy):
|
||||||
"""NetworkConnection object for Network Manager."""
|
"""Network connection setting object for Network Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, object_path: str) -> None:
|
def __init__(self, object_path: str) -> None:
|
||||||
"""Initialize NetworkConnection object."""
|
"""Initialize NetworkConnection object."""
|
||||||
@ -108,6 +111,8 @@ class NetworkSetting(DBusInterfaceProxy):
|
|||||||
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
||||||
data = (await self.get_settings())[0]
|
data = (await self.get_settings())[0]
|
||||||
|
|
||||||
|
# Get configuration settings we care about
|
||||||
|
# See: https://developer-old.gnome.org/NetworkManager/stable/ch01.html
|
||||||
if CONF_ATTR_CONNECTION in data:
|
if CONF_ATTR_CONNECTION in data:
|
||||||
self._connection = ConnectionProperties(
|
self._connection = ConnectionProperties(
|
||||||
data[CONF_ATTR_CONNECTION].get(ATTR_ID),
|
data[CONF_ATTR_CONNECTION].get(ATTR_ID),
|
||||||
|
@ -47,18 +47,20 @@ def get_connection_from_interface(
|
|||||||
|
|
||||||
connection = {
|
connection = {
|
||||||
"id": Variant("s", name),
|
"id": Variant("s", name),
|
||||||
"interface-name": Variant("s", interface.name),
|
|
||||||
"type": Variant("s", iftype),
|
"type": Variant("s", iftype),
|
||||||
"uuid": Variant("s", uuid),
|
"uuid": Variant("s", uuid),
|
||||||
"llmnr": Variant("i", 2),
|
"llmnr": Variant("i", 2),
|
||||||
"mdns": Variant("i", 2),
|
"mdns": Variant("i", 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interface.type != InterfaceType.VLAN:
|
||||||
|
connection["interface-name"] = Variant("s", interface.name)
|
||||||
|
|
||||||
conn = {}
|
conn = {}
|
||||||
conn[CONF_ATTR_CONNECTION] = connection
|
conn[CONF_ATTR_CONNECTION] = connection
|
||||||
|
|
||||||
ipv4 = {}
|
ipv4 = {}
|
||||||
if interface.ipv4.method == InterfaceMethod.AUTO:
|
if not interface.ipv4 or interface.ipv4.method == InterfaceMethod.AUTO:
|
||||||
ipv4["method"] = Variant("s", "auto")
|
ipv4["method"] = Variant("s", "auto")
|
||||||
elif interface.ipv4.method == InterfaceMethod.DISABLED:
|
elif interface.ipv4.method == InterfaceMethod.DISABLED:
|
||||||
ipv4["method"] = Variant("s", "disabled")
|
ipv4["method"] = Variant("s", "disabled")
|
||||||
@ -87,7 +89,7 @@ def get_connection_from_interface(
|
|||||||
conn[CONF_ATTR_IPV4] = ipv4
|
conn[CONF_ATTR_IPV4] = ipv4
|
||||||
|
|
||||||
ipv6 = {}
|
ipv6 = {}
|
||||||
if interface.ipv6.method == InterfaceMethod.AUTO:
|
if not interface.ipv6 or interface.ipv6.method == InterfaceMethod.AUTO:
|
||||||
ipv6["method"] = Variant("s", "auto")
|
ipv6["method"] = Variant("s", "auto")
|
||||||
elif interface.ipv6.method == InterfaceMethod.DISABLED:
|
elif interface.ipv6.method == InterfaceMethod.DISABLED:
|
||||||
ipv6["method"] = Variant("s", "disabled")
|
ipv6["method"] = Variant("s", "disabled")
|
||||||
@ -109,7 +111,7 @@ def get_connection_from_interface(
|
|||||||
)
|
)
|
||||||
|
|
||||||
ipv6["address-data"] = Variant("(a{sv})", adressdata)
|
ipv6["address-data"] = Variant("(a{sv})", adressdata)
|
||||||
ipv4["gateway"] = Variant("s", str(interface.ipv6.gateway))
|
ipv6["gateway"] = Variant("s", str(interface.ipv6.gateway))
|
||||||
|
|
||||||
conn[CONF_ATTR_IPV6] = ipv6
|
conn[CONF_ATTR_IPV6] = ipv6
|
||||||
|
|
||||||
|
@ -12,7 +12,10 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class NetworkManagerSettings(DBusInterface):
|
class NetworkManagerSettings(DBusInterface):
|
||||||
"""Handle D-Bus interface for Network Manager."""
|
"""Handle D-Bus interface for Network Manager Connection Settings Profile Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Settings.html
|
||||||
|
"""
|
||||||
|
|
||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
"""Connect to system's D-Bus."""
|
"""Connect to system's D-Bus."""
|
||||||
|
@ -4,7 +4,7 @@ from typing import Any, Awaitable, Optional
|
|||||||
from ...utils.dbus import DBus
|
from ...utils.dbus import DBus
|
||||||
from ..const import (
|
from ..const import (
|
||||||
DBUS_ATTR_ACTIVE_ACCESSPOINT,
|
DBUS_ATTR_ACTIVE_ACCESSPOINT,
|
||||||
DBUS_NAME_DEVICE_WIRELESS,
|
DBUS_IFACE_DEVICE_WIRELESS,
|
||||||
DBUS_NAME_NM,
|
DBUS_NAME_NM,
|
||||||
DBUS_OBJECT_BASE,
|
DBUS_OBJECT_BASE,
|
||||||
)
|
)
|
||||||
@ -14,7 +14,10 @@ from .accesspoint import NetworkWirelessAP
|
|||||||
|
|
||||||
|
|
||||||
class NetworkWireless(DBusInterfaceProxy):
|
class NetworkWireless(DBusInterfaceProxy):
|
||||||
"""NetworkWireless object for Network Manager."""
|
"""Wireless object for Network Manager.
|
||||||
|
|
||||||
|
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, object_path: str) -> None:
|
def __init__(self, object_path: str) -> None:
|
||||||
"""Initialize NetworkConnection object."""
|
"""Initialize NetworkConnection object."""
|
||||||
@ -41,7 +44,7 @@ class NetworkWireless(DBusInterfaceProxy):
|
|||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
"""Get connection information."""
|
"""Get connection information."""
|
||||||
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
self.dbus = await DBus.connect(DBUS_NAME_NM, self.object_path)
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_DEVICE_WIRELESS)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_DEVICE_WIRELESS)
|
||||||
|
|
||||||
# Get details from current active
|
# Get details from current active
|
||||||
if self.properties[DBUS_ATTR_ACTIVE_ACCESSPOINT] != DBUS_OBJECT_BASE:
|
if self.properties[DBUS_ATTR_ACTIVE_ACCESSPOINT] != DBUS_OBJECT_BASE:
|
||||||
|
@ -10,10 +10,10 @@ from .const import (
|
|||||||
DBUS_ATTR_LAST_ERROR,
|
DBUS_ATTR_LAST_ERROR,
|
||||||
DBUS_ATTR_OPERATION,
|
DBUS_ATTR_OPERATION,
|
||||||
DBUS_ATTR_VARIANT,
|
DBUS_ATTR_VARIANT,
|
||||||
|
DBUS_IFACE_RAUC_INSTALLER,
|
||||||
DBUS_NAME_RAUC,
|
DBUS_NAME_RAUC,
|
||||||
DBUS_NAME_RAUC_INSTALLER,
|
|
||||||
DBUS_NAME_RAUC_INSTALLER_COMPLETED,
|
|
||||||
DBUS_OBJECT_BASE,
|
DBUS_OBJECT_BASE,
|
||||||
|
DBUS_SIGNAL_RAUC_INSTALLER_COMPLETED,
|
||||||
RaucState,
|
RaucState,
|
||||||
)
|
)
|
||||||
from .interface import DBusInterface
|
from .interface import DBusInterface
|
||||||
@ -91,7 +91,7 @@ class Rauc(DBusInterface):
|
|||||||
|
|
||||||
Return a coroutine.
|
Return a coroutine.
|
||||||
"""
|
"""
|
||||||
return self.dbus.wait_signal(DBUS_NAME_RAUC_INSTALLER_COMPLETED)
|
return self.dbus.wait_signal(DBUS_SIGNAL_RAUC_INSTALLER_COMPLETED)
|
||||||
|
|
||||||
@dbus_connected
|
@dbus_connected
|
||||||
def mark(self, state: RaucState, slot_identifier: str):
|
def mark(self, state: RaucState, slot_identifier: str):
|
||||||
@ -104,7 +104,7 @@ class Rauc(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
data = await self.dbus.get_properties(DBUS_NAME_RAUC_INSTALLER)
|
data = await self.dbus.get_properties(DBUS_IFACE_RAUC_INSTALLER)
|
||||||
if not data:
|
if not data:
|
||||||
_LOGGER.warning("Can't get properties for rauc")
|
_LOGGER.warning("Can't get properties for rauc")
|
||||||
return
|
return
|
||||||
|
@ -10,8 +10,8 @@ from .const import (
|
|||||||
DBUS_ATTR_KERNEL_TIMESTAMP_MONOTONIC,
|
DBUS_ATTR_KERNEL_TIMESTAMP_MONOTONIC,
|
||||||
DBUS_ATTR_LOADER_TIMESTAMP_MONOTONIC,
|
DBUS_ATTR_LOADER_TIMESTAMP_MONOTONIC,
|
||||||
DBUS_ATTR_USERSPACE_TIMESTAMP_MONOTONIC,
|
DBUS_ATTR_USERSPACE_TIMESTAMP_MONOTONIC,
|
||||||
|
DBUS_IFACE_SYSTEMD_MANAGER,
|
||||||
DBUS_NAME_SYSTEMD,
|
DBUS_NAME_SYSTEMD,
|
||||||
DBUS_NAME_SYSTEMD_MANAGER,
|
|
||||||
DBUS_OBJECT_SYSTEMD,
|
DBUS_OBJECT_SYSTEMD,
|
||||||
)
|
)
|
||||||
from .interface import DBusInterface, dbus_property
|
from .interface import DBusInterface, dbus_property
|
||||||
@ -116,4 +116,4 @@ class Systemd(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_SYSTEMD_MANAGER)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_SYSTEMD_MANAGER)
|
||||||
|
@ -12,6 +12,7 @@ from .const import (
|
|||||||
DBUS_ATTR_NTPSYNCHRONIZED,
|
DBUS_ATTR_NTPSYNCHRONIZED,
|
||||||
DBUS_ATTR_TIMEUSEC,
|
DBUS_ATTR_TIMEUSEC,
|
||||||
DBUS_ATTR_TIMEZONE,
|
DBUS_ATTR_TIMEZONE,
|
||||||
|
DBUS_IFACE_TIMEDATE,
|
||||||
DBUS_NAME_TIMEDATE,
|
DBUS_NAME_TIMEDATE,
|
||||||
DBUS_OBJECT_TIMEDATE,
|
DBUS_OBJECT_TIMEDATE,
|
||||||
)
|
)
|
||||||
@ -90,4 +91,4 @@ class TimeDate(DBusInterface):
|
|||||||
@dbus_connected
|
@dbus_connected
|
||||||
async def update(self):
|
async def update(self):
|
||||||
"""Update Properties."""
|
"""Update Properties."""
|
||||||
self.properties = await self.dbus.get_properties(DBUS_NAME_TIMEDATE)
|
self.properties = await self.dbus.get_properties(DBUS_IFACE_TIMEDATE)
|
||||||
|
@ -10,8 +10,9 @@ import attr
|
|||||||
from ..const import ATTR_HOST_INTERNET
|
from ..const import ATTR_HOST_INTERNET
|
||||||
from ..coresys import CoreSys, CoreSysAttributes
|
from ..coresys import CoreSys, CoreSysAttributes
|
||||||
from ..dbus.const import (
|
from ..dbus.const import (
|
||||||
DBUS_NAME_NM_CONNECTION_ACTIVE_CHANGED,
|
DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED,
|
||||||
ConnectionStateType,
|
ConnectionStateType,
|
||||||
|
ConnectivityState,
|
||||||
DeviceType,
|
DeviceType,
|
||||||
InterfaceMethod as NMInterfaceMethod,
|
InterfaceMethod as NMInterfaceMethod,
|
||||||
WirelessMethodType,
|
WirelessMethodType,
|
||||||
@ -77,18 +78,15 @@ class NetworkManager(CoreSysAttributes):
|
|||||||
return list(dict.fromkeys(servers))
|
return list(dict.fromkeys(servers))
|
||||||
|
|
||||||
async def check_connectivity(self):
|
async def check_connectivity(self):
|
||||||
"""Check the internet connection.
|
"""Check the internet connection."""
|
||||||
|
|
||||||
ConnectionState 4 == FULL (has internet)
|
|
||||||
https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMConnectivityState
|
|
||||||
"""
|
|
||||||
if not self.sys_dbus.network.connectivity_enabled:
|
if not self.sys_dbus.network.connectivity_enabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check connectivity
|
# Check connectivity
|
||||||
try:
|
try:
|
||||||
state = await self.sys_dbus.network.check_connectivity()
|
state = await self.sys_dbus.network.check_connectivity()
|
||||||
self.connectivity = state[0] == 4
|
self.connectivity = state[0] == ConnectivityState.CONNECTIVITY_FULL
|
||||||
except DBusError as err:
|
except DBusError as err:
|
||||||
_LOGGER.warning("Can't update connectivity information: %s", err)
|
_LOGGER.warning("Can't update connectivity information: %s", err)
|
||||||
self.connectivity = False
|
self.connectivity = False
|
||||||
@ -119,6 +117,7 @@ class NetworkManager(CoreSysAttributes):
|
|||||||
async def apply_changes(self, interface: Interface) -> None:
|
async def apply_changes(self, interface: Interface) -> None:
|
||||||
"""Apply Interface changes to host."""
|
"""Apply Interface changes to host."""
|
||||||
inet = self.sys_dbus.network.interfaces.get(interface.name)
|
inet = self.sys_dbus.network.interfaces.get(interface.name)
|
||||||
|
con: NetworkConnection = None
|
||||||
|
|
||||||
# Update exist configuration
|
# Update exist configuration
|
||||||
if (
|
if (
|
||||||
@ -136,9 +135,13 @@ class NetworkManager(CoreSysAttributes):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
await inet.settings.update(settings)
|
await inet.settings.update(settings)
|
||||||
await self.sys_dbus.network.activate_connection(
|
con = await self.sys_dbus.network.activate_connection(
|
||||||
inet.settings.object_path, inet.object_path
|
inet.settings.object_path, inet.object_path
|
||||||
)
|
)
|
||||||
|
_LOGGER.debug(
|
||||||
|
"activate_connection returns %s",
|
||||||
|
con.object_path,
|
||||||
|
)
|
||||||
except DBusError as err:
|
except DBusError as err:
|
||||||
raise HostNetworkError(
|
raise HostNetworkError(
|
||||||
f"Can't update config on {interface.name}: {err}", _LOGGER.error
|
f"Can't update config on {interface.name}: {err}", _LOGGER.error
|
||||||
@ -150,10 +153,13 @@ class NetworkManager(CoreSysAttributes):
|
|||||||
settings = get_connection_from_interface(interface)
|
settings = get_connection_from_interface(interface)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_con = await self.sys_dbus.network.add_and_activate_connection(
|
settings, con = await self.sys_dbus.network.add_and_activate_connection(
|
||||||
settings, inet.object_path
|
settings, inet.object_path
|
||||||
)
|
)
|
||||||
_LOGGER.debug("add_and_activate_connection returns %s", new_con)
|
_LOGGER.debug(
|
||||||
|
"add_and_activate_connection returns %s",
|
||||||
|
con.object_path,
|
||||||
|
)
|
||||||
except DBusError as err:
|
except DBusError as err:
|
||||||
raise HostNetworkError(
|
raise HostNetworkError(
|
||||||
f"Can't create config and activate {interface.name}: {err}",
|
f"Can't create config and activate {interface.name}: {err}",
|
||||||
@ -184,11 +190,26 @@ class NetworkManager(CoreSysAttributes):
|
|||||||
"Requested Network interface update is not possible", _LOGGER.warning
|
"Requested Network interface update is not possible", _LOGGER.warning
|
||||||
)
|
)
|
||||||
|
|
||||||
# This signal is fired twice: Activating -> Activated. It seems we miss the first
|
if con:
|
||||||
# "usually"... We should filter by state and explicitly wait for the second.
|
# Only consider activated or deactivated signals, continue waiting on others
|
||||||
await self.sys_dbus.network.dbus.wait_signal(
|
def message_filter(msg_body):
|
||||||
DBUS_NAME_NM_CONNECTION_ACTIVE_CHANGED
|
state: ConnectionStateType = msg_body[0]
|
||||||
)
|
if state == ConnectionStateType.DEACTIVATED:
|
||||||
|
return True
|
||||||
|
elif state == ConnectionStateType.ACTIVATED:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
result = await con.dbus.wait_signal(
|
||||||
|
DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED, message_filter
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER.debug("StateChanged signal received, result: %s", str(result))
|
||||||
|
state: ConnectionStateType = result[0]
|
||||||
|
if state != ConnectionStateType.ACTIVATED:
|
||||||
|
raise HostNetworkError(
|
||||||
|
"Activating connection failed, check connection settings."
|
||||||
|
)
|
||||||
|
|
||||||
await self.update()
|
await self.update()
|
||||||
|
|
||||||
|
@ -49,7 +49,12 @@ class DBus:
|
|||||||
self.object_path: str = object_path
|
self.object_path: str = object_path
|
||||||
self.methods: set[str] = set()
|
self.methods: set[str] = set()
|
||||||
self.signals: set[str] = set()
|
self.signals: set[str] = set()
|
||||||
self._bus: MessageBus = None
|
self._bus: MessageBus | None = None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""Delete dbus object."""
|
||||||
|
if self._bus:
|
||||||
|
self._bus.disconnect()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def connect(bus_name: str, object_path: str) -> DBus:
|
async def connect(bus_name: str, object_path: str) -> DBus:
|
||||||
@ -171,13 +176,14 @@ class DBus:
|
|||||||
_LOGGER.error("No Set attribute %s for %s", name, interface)
|
_LOGGER.error("No Set attribute %s for %s", name, interface)
|
||||||
raise DBusFatalError() from err
|
raise DBusFatalError() from err
|
||||||
|
|
||||||
async def wait_signal(self, signal):
|
async def wait_signal(self, signal_member, message_filter=None) -> Any:
|
||||||
"""Wait for single event."""
|
"""Wait for signal on this object."""
|
||||||
signal_parts = signal.split(".")
|
signal_parts = signal_member.split(".")
|
||||||
interface = ".".join(signal_parts[:-1])
|
interface = ".".join(signal_parts[:-1])
|
||||||
member = signal_parts[-1]
|
member = signal_parts[-1]
|
||||||
|
match = f"type='signal',interface={interface},member={member},path={self.object_path}"
|
||||||
|
|
||||||
_LOGGER.debug("Wait for signal %s", signal)
|
_LOGGER.debug("Install match for signal %s", signal_member)
|
||||||
await self._bus.call(
|
await self._bus.call(
|
||||||
Message(
|
Message(
|
||||||
destination="org.freedesktop.DBus",
|
destination="org.freedesktop.DBus",
|
||||||
@ -185,7 +191,7 @@ class DBus:
|
|||||||
path="/org/freedesktop/DBus",
|
path="/org/freedesktop/DBus",
|
||||||
member="AddMatch",
|
member="AddMatch",
|
||||||
signature="s",
|
signature="s",
|
||||||
body=[f"type='signal',interface={interface},member={member}"],
|
body=[match],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -197,21 +203,44 @@ class DBus:
|
|||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Signal message received %s, %s %s", msg, msg.interface, msg.member
|
"Signal message received %s, %s.%s object %s",
|
||||||
|
msg.body,
|
||||||
|
msg.interface,
|
||||||
|
msg.member,
|
||||||
|
msg.path,
|
||||||
)
|
)
|
||||||
if msg.interface != interface or msg.member != member:
|
if (
|
||||||
|
msg.interface != interface
|
||||||
|
or msg.member != member
|
||||||
|
or msg.path != self.object_path
|
||||||
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Avoid race condition: We already received signal but handler not yet removed.
|
# Avoid race condition: We already received signal but handler not yet removed.
|
||||||
if future.done():
|
if future.done():
|
||||||
return
|
return
|
||||||
|
|
||||||
future.set_result(_remove_dbus_signature(msg.body))
|
msg_body = _remove_dbus_signature(msg.body)
|
||||||
|
if message_filter and not message_filter(msg_body):
|
||||||
|
return
|
||||||
|
|
||||||
|
future.set_result(msg_body)
|
||||||
|
|
||||||
self._bus.add_message_handler(message_handler)
|
self._bus.add_message_handler(message_handler)
|
||||||
result = await future
|
result = await future
|
||||||
self._bus.remove_message_handler(message_handler)
|
self._bus.remove_message_handler(message_handler)
|
||||||
|
|
||||||
|
await self._bus.call(
|
||||||
|
Message(
|
||||||
|
destination="org.freedesktop.DBus",
|
||||||
|
interface="org.freedesktop.DBus",
|
||||||
|
path="/org/freedesktop/DBus",
|
||||||
|
member="RemoveMatch",
|
||||||
|
signature="s",
|
||||||
|
body=[match],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def __getattr__(self, name: str) -> DBusCallWrapper:
|
def __getattr__(self, name: str) -> DBusCallWrapper:
|
||||||
|
@ -18,6 +18,7 @@ from supervisor.api import RestAPI
|
|||||||
from supervisor.bootstrap import initialize_coresys
|
from supervisor.bootstrap import initialize_coresys
|
||||||
from supervisor.const import REQUEST_FROM
|
from supervisor.const import REQUEST_FROM
|
||||||
from supervisor.coresys import CoreSys
|
from supervisor.coresys import CoreSys
|
||||||
|
from supervisor.dbus.const import DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED
|
||||||
from supervisor.dbus.network import NetworkManager
|
from supervisor.dbus.network import NetworkManager
|
||||||
from supervisor.docker import DockerAPI
|
from supervisor.docker import DockerAPI
|
||||||
from supervisor.store.addon import AddonStore
|
from supervisor.store.addon import AddonStore
|
||||||
@ -79,8 +80,9 @@ def dbus() -> DBus:
|
|||||||
|
|
||||||
return load_json_fixture(f"{fixture}.json")
|
return load_json_fixture(f"{fixture}.json")
|
||||||
|
|
||||||
async def mock_wait_signal(_, __):
|
async def mock_wait_signal(_, signal_method, ___):
|
||||||
pass
|
if signal_method == DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED:
|
||||||
|
return [2, 0]
|
||||||
|
|
||||||
async def mock_init_proxy(self):
|
async def mock_init_proxy(self):
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
[]
|
[ "/org/freedesktop/NetworkManager/Settings/1", "/org/freedesktop/NetworkManager/ActiveConnection/1" ]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user