diff --git a/supervisor/api/network.py b/supervisor/api/network.py index bf0525992..993615528 100644 --- a/supervisor/api/network.py +++ b/supervisor/api/network.py @@ -30,6 +30,7 @@ from ..const import ( ATTR_PARENT, ATTR_PRIMARY, ATTR_PSK, + ATTR_READY, ATTR_SIGNAL, ATTR_SSID, ATTR_SUPERVISOR_INTERNET, @@ -89,6 +90,7 @@ def ipconfig_struct(config: IpConfig) -> dict[str, Any]: ATTR_ADDRESS: [address.with_prefixlen for address in config.address], ATTR_NAMESERVERS: [str(address) for address in config.nameservers], ATTR_GATEWAY: str(config.gateway) if config.gateway else None, + ATTR_READY: config.ready, } diff --git a/supervisor/const.py b/supervisor/const.py index 12a7c14f6..20709777f 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -251,6 +251,7 @@ ATTR_PROVIDERS = "providers" ATTR_PSK = "psk" ATTR_PWNED = "pwned" ATTR_RATING = "rating" +ATTR_READY = "ready" ATTR_REALTIME = "realtime" ATTR_REFRESH_TOKEN = "refresh_token" ATTR_REGISTRIES = "registries" diff --git a/supervisor/host/network.py b/supervisor/host/network.py index c1fb928ca..ec8cf294e 100644 --- a/supervisor/host/network.py +++ b/supervisor/host/network.py @@ -12,6 +12,7 @@ from ..const import ATTR_HOST_INTERNET from ..coresys import CoreSys, CoreSysAttributes from ..dbus.const import ( DBUS_SIGNAL_NM_CONNECTION_ACTIVE_CHANGED, + ConnectionStateFlags, ConnectionStateType, ConnectivityState, DeviceType, @@ -309,6 +310,7 @@ class IpConfig: address: list[IPv4Interface | IPv6Interface] = attr.ib() gateway: IPv4Address | IPv6Address | None = attr.ib() nameservers: list[IPv4Address | IPv6Address] = attr.ib() + ready: bool = attr.ib() @attr.s(slots=True) @@ -357,6 +359,14 @@ class Interface: if inet.settings and inet.settings.ipv6 else InterfaceMethod.DISABLED ) + ipv4_ready = ( + bool(inet.connection) + and ConnectionStateFlags.IP4_READY in inet.connection.state_flags + ) + ipv6_ready = ( + bool(inet.connection) + and ConnectionStateFlags.IP6_READY in inet.connection.state_flags + ) return Interface( inet.name, inet.settings is not None, @@ -368,17 +378,19 @@ class Interface: inet.connection.ipv4.address, inet.connection.ipv4.gateway, inet.connection.ipv4.nameservers, + ipv4_ready, ) if inet.connection and inet.connection.ipv4 - else IpConfig(ipv4_method, [], None, []), + else IpConfig(ipv4_method, [], None, [], ipv4_ready), IpConfig( ipv6_method, inet.connection.ipv6.address, inet.connection.ipv6.gateway, inet.connection.ipv6.nameservers, + ipv6_ready, ) if inet.connection and inet.connection.ipv6 - else IpConfig(ipv6_method, [], None, []), + else IpConfig(ipv6_method, [], None, [], ipv6_ready), Interface._map_nm_wifi(inet), Interface._map_nm_vlan(inet), ) diff --git a/tests/api/test_network.py b/tests/api/test_network.py index be545b8f1..4123dcf9f 100644 --- a/tests/api/test_network.py +++ b/tests/api/test_network.py @@ -31,12 +31,14 @@ async def test_api_network_info(api_client, coresys): "gateway": None, "method": "disabled", "nameservers": [], + "ready": False, } assert interface["ipv6"] == { "address": [], "gateway": None, "method": "disabled", "nameservers": [], + "ready": False, } assert result["data"]["docker"]["interface"] == DOCKER_NETWORK @@ -53,6 +55,7 @@ async def test_api_network_interface_info(api_client): assert result["data"]["ipv4"]["address"][-1] == "192.168.2.148/24" assert result["data"]["ipv4"]["gateway"] == "192.168.2.1" assert result["data"]["ipv4"]["nameservers"] == ["192.168.2.2"] + assert result["data"]["ipv4"]["ready"] is True assert ( result["data"]["ipv6"]["address"][0] == "2a03:169:3df5:0:6be9:2588:b26a:a679/64" ) @@ -65,6 +68,7 @@ async def test_api_network_interface_info(api_client): "2001:1620:2777:1::10", "2001:1620:2777:2::20", ] + assert result["data"]["ipv6"]["ready"] is True assert result["data"]["interface"] == TEST_INTERFACE @@ -76,6 +80,7 @@ async def test_api_network_interface_info_default(api_client): assert result["data"]["ipv4"]["address"][-1] == "192.168.2.148/24" assert result["data"]["ipv4"]["gateway"] == "192.168.2.1" assert result["data"]["ipv4"]["nameservers"] == ["192.168.2.2"] + assert result["data"]["ipv4"]["ready"] is True assert ( result["data"]["ipv6"]["address"][0] == "2a03:169:3df5:0:6be9:2588:b26a:a679/64" ) @@ -88,6 +93,7 @@ async def test_api_network_interface_info_default(api_client): "2001:1620:2777:1::10", "2001:1620:2777:2::20", ] + assert result["data"]["ipv6"]["ready"] is True assert result["data"]["interface"] == TEST_INTERFACE diff --git a/tests/host/test_network.py b/tests/host/test_network.py index ef348433a..343019967 100644 --- a/tests/host/test_network.py +++ b/tests/host/test_network.py @@ -29,10 +29,12 @@ async def test_load(coresys: CoreSys): assert coresys.host.network.interfaces[0].ipv4.gateway == IPv4Address( "192.168.2.1" ) + assert coresys.host.network.interfaces[0].ipv4.ready is True assert coresys.host.network.interfaces[0].ipv6.method == InterfaceMethod.AUTO assert coresys.host.network.interfaces[0].ipv6.gateway == IPv6Address( "fe80::da58:d7ff:fe00:9c69" ) + assert coresys.host.network.interfaces[0].ipv6.ready is True assert coresys.host.network.interfaces[1].name == "wlan0" assert coresys.host.network.interfaces[1].enabled is False @@ -52,8 +54,8 @@ async def test_load_with_disabled_methods(coresys: CoreSys): False, False, InterfaceType.ETHERNET, - IpConfig(InterfaceMethod.DISABLED, [], None, []), - IpConfig(InterfaceMethod.DISABLED, [], None, []), + IpConfig(InterfaceMethod.DISABLED, [], None, [], False), + IpConfig(InterfaceMethod.DISABLED, [], None, [], False), None, None, ),