mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-16 05:36:29 +00:00
Merge updates with existing network settings (#3570)
* Preserve network customizations over updates * Fix issues from testing * Test case to ensure updates generated correctly
This commit is contained in:
parent
88795c56f0
commit
32d1296da1
@ -37,6 +37,17 @@ ATTR_INTERFACE_NAME = "interface-name"
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _merge_settings_attribute(
|
||||
base_settings: Any, new_settings: Any, attribute: str
|
||||
) -> None:
|
||||
"""Merge settings attribute if present."""
|
||||
if attribute in new_settings:
|
||||
if attribute in base_settings:
|
||||
base_settings[attribute].update(new_settings[attribute])
|
||||
else:
|
||||
base_settings[attribute] = new_settings[attribute]
|
||||
|
||||
|
||||
class NetworkSetting(DBusInterfaceProxy):
|
||||
"""Network connection setting object for Network Manager.
|
||||
|
||||
@ -97,9 +108,23 @@ class NetworkSetting(DBusInterfaceProxy):
|
||||
return self.dbus.Settings.Connection.GetSettings()
|
||||
|
||||
@dbus_connected
|
||||
def update(self, settings: Any) -> Awaitable[None]:
|
||||
async def update(self, settings: Any) -> None:
|
||||
"""Update connection settings."""
|
||||
return self.dbus.Settings.Connection.Update(("a{sa{sv}}", settings))
|
||||
new_settings = (
|
||||
await self.dbus.Settings.Connection.GetSettings(remove_signature=False)
|
||||
)[0]
|
||||
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_CONNECTION)
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_802_ETHERNET)
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_802_WIRELESS)
|
||||
_merge_settings_attribute(
|
||||
new_settings, settings, CONF_ATTR_802_WIRELESS_SECURITY
|
||||
)
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_VLAN)
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_IPV4)
|
||||
_merge_settings_attribute(new_settings, settings, CONF_ATTR_IPV6)
|
||||
|
||||
return await self.dbus.Settings.Connection.Update(("a{sa{sv}}", new_settings))
|
||||
|
||||
@dbus_connected
|
||||
def delete(self) -> Awaitable[None]:
|
||||
|
@ -143,7 +143,9 @@ class DBus:
|
||||
|
||||
return signature, arg_list
|
||||
|
||||
async def call_dbus(self, method: str, *args: list[Any]) -> str:
|
||||
async def call_dbus(
|
||||
self, method: str, *args: list[Any], remove_signature: bool = True
|
||||
) -> str:
|
||||
"""Call a dbus method."""
|
||||
method_parts = method.split(".")
|
||||
|
||||
@ -172,7 +174,9 @@ class DBus:
|
||||
raise DBusFatalError(reply.body[0])
|
||||
raise DBusFatalError()
|
||||
|
||||
return _remove_dbus_signature(reply.body)
|
||||
if remove_signature:
|
||||
return _remove_dbus_signature(reply.body)
|
||||
return reply.body
|
||||
|
||||
async def get_properties(self, interface: str) -> dict[str, Any]:
|
||||
"""Read all properties from interface."""
|
||||
@ -225,12 +229,14 @@ class DBusCallWrapper:
|
||||
if interface not in self.dbus.methods:
|
||||
return DBusCallWrapper(self.dbus, interface)
|
||||
|
||||
def _method_wrapper(*args):
|
||||
def _method_wrapper(*args, remove_signature: bool = True):
|
||||
"""Wrap method.
|
||||
|
||||
Return a coroutine
|
||||
"""
|
||||
return self.dbus.call_dbus(interface, *args)
|
||||
return self.dbus.call_dbus(
|
||||
interface, *args, remove_signature=remove_signature
|
||||
)
|
||||
|
||||
return _method_wrapper
|
||||
|
||||
|
@ -114,7 +114,9 @@ def dbus() -> DBus:
|
||||
node = intr.Node.parse(load_fixture(f"{fixture}.{filetype}"))
|
||||
self._add_interfaces(node)
|
||||
|
||||
async def mock_call_dbus(self, method: str, *args: list[Any]):
|
||||
async def mock_call_dbus(
|
||||
self, method: str, *args: list[Any], remove_signature: bool = True
|
||||
):
|
||||
|
||||
fixture = self.object_path.replace("/", "_")[1:]
|
||||
fixture = f"{fixture}-{method.split('.')[-1]}"
|
||||
|
149
tests/dbus/network/setting/test_init.py
Normal file
149
tests/dbus/network/setting/test_init.py
Normal file
@ -0,0 +1,149 @@
|
||||
"""Test Network Manager Connection object."""
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from dbus_next.signature import Variant
|
||||
|
||||
from supervisor.coresys import CoreSys
|
||||
from supervisor.dbus.network.setting.generate import get_connection_from_interface
|
||||
from supervisor.host.network import Interface
|
||||
|
||||
from tests.const import TEST_INTERFACE
|
||||
|
||||
|
||||
async def mock_call_dbus_get_settings_signature(
|
||||
method: str, *args: list[Any], remove_signature: bool = True
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Call dbus method mock for get settings that keeps signature."""
|
||||
if (
|
||||
method == "org.freedesktop.NetworkManager.Settings.Connection.GetSettings"
|
||||
and not remove_signature
|
||||
):
|
||||
return [
|
||||
{
|
||||
"connection": {
|
||||
"id": Variant("s", "Wired connection 1"),
|
||||
"interface-name": Variant("s", "eth0"),
|
||||
"permissions": Variant("as", []),
|
||||
"timestamp": Variant("t", 1598125548),
|
||||
"type": Variant("s", "802-3-ethernet"),
|
||||
"uuid": Variant("s", "0c23631e-2118-355c-bbb0-8943229cb0d6"),
|
||||
},
|
||||
"ipv4": {
|
||||
"address-data": Variant(
|
||||
"aa{sv}",
|
||||
[
|
||||
{
|
||||
"address": Variant("s", "192.168.2.148"),
|
||||
"prefix": Variant("u", 24),
|
||||
}
|
||||
],
|
||||
),
|
||||
"addresses": Variant("aau", [[2483202240, 24, 16951488]]),
|
||||
"dns": Variant("au", [16951488]),
|
||||
"dns-search": Variant("as", []),
|
||||
"gateway": Variant("s", "192.168.2.1"),
|
||||
"method": Variant("s", "auto"),
|
||||
"route-data": Variant(
|
||||
"aa{sv}",
|
||||
[
|
||||
{
|
||||
"dest": Variant("s", "192.168.122.0"),
|
||||
"prefix": Variant("u", 24),
|
||||
"next-hop": Variant("s", "10.10.10.1"),
|
||||
}
|
||||
],
|
||||
),
|
||||
"routes": Variant("aau", [[8038592, 24, 17435146, 0]]),
|
||||
},
|
||||
"ipv6": {
|
||||
"address-data": Variant("aa{sv}", []),
|
||||
"addresses": Variant("a(ayuay)", []),
|
||||
"dns": Variant("au", []),
|
||||
"dns-search": Variant("as", []),
|
||||
"method": Variant("s", "auto"),
|
||||
"route-data": Variant("aa{sv}", []),
|
||||
"routes": Variant("aau", []),
|
||||
"addr-gen-mode": Variant("i", 0),
|
||||
},
|
||||
"proxy": {},
|
||||
"802-3-ethernet": {
|
||||
"auto-negotiate": Variant("b", False),
|
||||
"mac-address-blacklist": Variant("as", []),
|
||||
"s390-options": Variant("a{ss}", {}),
|
||||
},
|
||||
"802-11-wireless": {"ssid": Variant("ay", bytes([78, 69, 84, 84]))},
|
||||
}
|
||||
]
|
||||
else:
|
||||
assert method == "org.freedesktop.NetworkManager.Settings.Connection.Update"
|
||||
assert len(args[0]) == 2
|
||||
assert args[0][0] == "a{sa{sv}}"
|
||||
settings = args[0][1]
|
||||
|
||||
assert "connection" in settings
|
||||
assert settings["connection"]["id"] == Variant("s", "Supervisor eth0")
|
||||
assert settings["connection"]["interface-name"] == Variant("s", "eth0")
|
||||
assert settings["connection"]["uuid"] == Variant(
|
||||
"s", "0c23631e-2118-355c-bbb0-8943229cb0d6"
|
||||
)
|
||||
|
||||
assert "ipv4" in settings
|
||||
assert settings["ipv4"]["gateway"] == Variant("s", "192.168.2.1")
|
||||
assert settings["ipv4"]["method"] == Variant("s", "auto")
|
||||
assert settings["ipv4"]["dns"] == Variant("au", [16951488])
|
||||
assert len(settings["ipv4"]["address-data"].value) == 1
|
||||
assert settings["ipv4"]["address-data"].value[0]["address"] == Variant(
|
||||
"s", "192.168.2.148"
|
||||
)
|
||||
assert settings["ipv4"]["address-data"].value[0]["prefix"] == Variant("u", 24)
|
||||
assert len(settings["ipv4"]["route-data"].value) == 1
|
||||
assert settings["ipv4"]["route-data"].value[0]["dest"] == Variant(
|
||||
"s", "192.168.122.0"
|
||||
)
|
||||
assert settings["ipv4"]["route-data"].value[0]["prefix"] == Variant("u", 24)
|
||||
assert settings["ipv4"]["route-data"].value[0]["next-hop"] == Variant(
|
||||
"s", "10.10.10.1"
|
||||
)
|
||||
assert settings["ipv4"]["routes"] == Variant(
|
||||
"aau", [[8038592, 24, 17435146, 0]]
|
||||
)
|
||||
|
||||
assert "ipv6" in settings
|
||||
assert settings["ipv6"]["method"] == Variant("s", "auto")
|
||||
assert settings["ipv6"]["addr-gen-mode"] == Variant("i", 0)
|
||||
|
||||
assert "proxy" in settings
|
||||
|
||||
assert "802-3-ethernet" in settings
|
||||
assert settings["802-3-ethernet"]["auto-negotiate"] == Variant("b", False)
|
||||
|
||||
assert "802-11-wireless" in settings
|
||||
assert settings["802-11-wireless"]["ssid"] == Variant(
|
||||
"ay", bytes([78, 69, 84, 84])
|
||||
)
|
||||
assert "mode" not in settings["802-11-wireless"]
|
||||
assert "powersave" not in settings["802-11-wireless"]
|
||||
|
||||
assert "802-11-wireless-security" not in settings
|
||||
assert "vlan" not in settings
|
||||
|
||||
|
||||
async def test_update(coresys: CoreSys):
|
||||
"""Test network manager update."""
|
||||
await coresys.dbus.network.interfaces[TEST_INTERFACE].connect()
|
||||
interface = Interface.from_dbus_interface(
|
||||
coresys.dbus.network.interfaces[TEST_INTERFACE]
|
||||
)
|
||||
conn = get_connection_from_interface(
|
||||
interface,
|
||||
name=coresys.dbus.network.interfaces[TEST_INTERFACE].settings.connection.id,
|
||||
uuid=coresys.dbus.network.interfaces[TEST_INTERFACE].settings.connection.uuid,
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
coresys.dbus.network.interfaces[TEST_INTERFACE].settings.dbus,
|
||||
"call_dbus",
|
||||
new=mock_call_dbus_get_settings_signature,
|
||||
):
|
||||
await coresys.dbus.network.interfaces[TEST_INTERFACE].settings.update(conn)
|
@ -15,8 +15,10 @@
|
||||
"dns-search": [],
|
||||
"gateway": "192.168.2.1",
|
||||
"method": "auto",
|
||||
"route-data": [],
|
||||
"routes": []
|
||||
"route-data": [
|
||||
{ "dest": "192.168.122.0", "prefix": 24, "next-hop": "10.10.10.1" }
|
||||
],
|
||||
"routes": [[8038592, 24, 17435146, 0]]
|
||||
},
|
||||
"ipv6": {
|
||||
"address-data": [],
|
||||
@ -25,7 +27,8 @@
|
||||
"dns-search": [],
|
||||
"method": "auto",
|
||||
"route-data": [],
|
||||
"routes": []
|
||||
"routes": [],
|
||||
"addr-gen-mode": 0
|
||||
},
|
||||
"proxy": {},
|
||||
"802-3-ethernet": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user