MVP: Add Network Manager context (#1937)

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
This commit is contained in:
Joakim Sørensen 2020-08-24 16:58:02 +02:00 committed by GitHub
parent 1e953167b6
commit 9bcb15dbc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1719 additions and 269 deletions

59
API.md
View File

@ -442,6 +442,65 @@ Proxy to Home Assistant Core websocket.
}
```
### Network
Network operations over the API
#### GET `/network/info`
Get network information
```json
{
"interfaces": {
"enp0s31f6": {
"ip_address": "192.168.2.148/24",
"gateway": "192.168.2.1",
"id": "Wired connection 1",
"type": "802-3-ethernet",
"nameservers": ["192.168.2.1"],
"method": "static",
"primary": true
}
}
}
```
#### GET `/network/{interface}/info`
Get information for a single interface
```json
{
"ip_address": "192.168.2.148/24",
"gateway": "192.168.2.1",
"id": "Wired connection 1",
"type": "802-3-ethernet",
"nameservers": ["192.168.2.1"],
"method": "dhcp",
"primary": true
}
```
#### POST `/network/{interface}/update`
Update information for a single interface
**Options:**
| Option | Description |
| --------- | ---------------------------------------------------------------------- |
| `address` | The new IP address for the interface in the X.X.X.X/XX format |
| `dns` | Comma seperated list of DNS servers to use |
| `gateway` | The gateway the interface should use |
| `method` | Set if the interface should use DHCP or not, can be `dhcp` or `static` |
_All options are optional._
**NB!: If you change the `address` or `gateway` you may need to reconnect to the new address**
The result will be a updated object.
### RESTful for API add-ons
If an add-on will call itself, you can use `/addons/self/...`.

View File

@ -7,6 +7,7 @@ pre-commit==2.7.1
pydocstyle==5.1.0
pylint==2.6.0
pytest-aiohttp==0.3.0
pytest-asyncio==0.12.0 # NB!: Versions over 0.12.0 breaks pytest-aiohttp (https://github.com/aio-libs/pytest-aiohttp/issues/16)
pytest-cov==2.10.1
pytest-timeout==1.4.2
pytest==6.0.1

View File

@ -18,6 +18,7 @@ from .host import APIHost
from .info import APIInfo
from .ingress import APIIngress
from .multicast import APIMulticast
from .network import APINetwork
from .os import APIOS
from .proxy import APIProxy
from .security import SecurityMiddleware
@ -54,6 +55,7 @@ class RestAPI(CoreSysAttributes):
self._register_os()
self._register_cli()
self._register_multicast()
self._register_network()
self._register_hardware()
self._register_homeassistant()
self._register_proxy()
@ -89,6 +91,24 @@ class RestAPI(CoreSysAttributes):
]
)
def _register_network(self) -> None:
"""Register network functions."""
api_network = APINetwork()
api_network.coresys = self.coresys
self.webapp.add_routes(
[
web.get("/network/info", api_network.info),
web.get(
"/network/interface/{interface}/info", api_network.interface_info
),
web.post(
"/network/interface/{interface}/update",
api_network.interface_update,
),
]
)
def _register_os(self) -> None:
"""Register OS functions."""
api_os = APIOS()

View File

@ -1,6 +1,5 @@
"""Init file for Supervisor host RESTful API."""
import asyncio
import logging
from typing import Awaitable
from aiohttp import web
@ -26,8 +25,6 @@ from ..const import (
from ..coresys import CoreSysAttributes
from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__)
SERVICE = "service"
SCHEMA_OPTIONS = vol.Schema({vol.Optional(ATTR_HOSTNAME): vol.Coerce(str)})

98
supervisor/api/network.py Normal file
View File

@ -0,0 +1,98 @@
"""REST API for network."""
import asyncio
from typing import Any, Dict
from aiohttp import web
import voluptuous as vol
from ..const import (
ATTR_ADDRESS,
ATTR_DNS,
ATTR_GATEWAY,
ATTR_ID,
ATTR_INTERFACE,
ATTR_INTERFACES,
ATTR_IP_ADDRESS,
ATTR_METHOD,
ATTR_METHODS,
ATTR_NAMESERVERS,
ATTR_PRIMARY,
ATTR_TYPE,
)
from ..coresys import CoreSysAttributes
from ..dbus.const import InterfaceMethodSimple
from ..dbus.network.interface import NetworkInterface
from ..dbus.network.utils import int2ip
from ..exceptions import APIError
from .utils import api_process, api_validate
SCHEMA_UPDATE = vol.Schema(
{
vol.Optional(ATTR_ADDRESS): vol.Coerce(str),
vol.Optional(ATTR_METHOD): vol.In(ATTR_METHODS),
vol.Optional(ATTR_GATEWAY): vol.Coerce(str),
vol.Optional(ATTR_DNS): [str],
}
)
def interface_information(interface: NetworkInterface) -> dict:
"""Return a dict with information of a interface to be used in th API."""
return {
ATTR_IP_ADDRESS: f"{interface.ip_address}/{interface.prefix}",
ATTR_GATEWAY: interface.gateway,
ATTR_ID: interface.id,
ATTR_TYPE: interface.type,
ATTR_NAMESERVERS: [int2ip(x) for x in interface.nameservers],
ATTR_METHOD: InterfaceMethodSimple.DHCP
if interface.method == "auto"
else InterfaceMethodSimple.STATIC,
ATTR_PRIMARY: interface.primary,
}
class APINetwork(CoreSysAttributes):
"""Handle REST API for network."""
@api_process
async def info(self, request: web.Request) -> Dict[str, Any]:
"""Return network information."""
interfaces = {}
for interface in self.sys_host.network.interfaces:
interfaces[
self.sys_host.network.interfaces[interface].name
] = interface_information(self.sys_host.network.interfaces[interface])
return {ATTR_INTERFACES: interfaces}
@api_process
async def interface_info(self, request: web.Request) -> Dict[str, Any]:
"""Return network information for a interface."""
req_interface = request.match_info.get(ATTR_INTERFACE)
for interface in self.sys_host.network.interfaces:
if req_interface == self.sys_host.network.interfaces[interface].name:
return interface_information(
self.sys_host.network.interfaces[interface]
)
return {}
@api_process
async def interface_update(self, request: web.Request) -> Dict[str, Any]:
"""Update the configuration of an interface."""
req_interface = request.match_info.get(ATTR_INTERFACE)
if not self.sys_host.network.interfaces.get(req_interface):
raise APIError(f"Interface {req_interface} does not exsist")
args = await api_validate(SCHEMA_UPDATE, request)
if not args:
raise APIError("You need to supply at least one option to update")
await asyncio.shield(
self.sys_host.network.interfaces[req_interface].update_settings(**args)
)
await asyncio.shield(self.sys_host.network.update())
return await asyncio.shield(self.interface_info(request))

View File

@ -6,8 +6,8 @@ from pathlib import Path
SUPERVISOR_VERSION = "236"
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
URL_HASSIO_VERSION = "https://version.home-assistant.io/{channel}.json"
URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor.txt"
URL_HASSIO_VERSION = "https://version.home-assistant.io/{channel}.json"
URL_HASSOS_OTA = (
"https://github.com/home-assistant/operating-system/releases/download/"
@ -16,22 +16,22 @@ URL_HASSOS_OTA = (
SUPERVISOR_DATA = Path("/data")
FILE_HASSIO_AUTH = Path(SUPERVISOR_DATA, "auth.json")
FILE_HASSIO_ADDONS = Path(SUPERVISOR_DATA, "addons.json")
FILE_HASSIO_CONFIG = Path(SUPERVISOR_DATA, "config.json")
FILE_HASSIO_HOMEASSISTANT = Path(SUPERVISOR_DATA, "homeassistant.json")
FILE_HASSIO_UPDATER = Path(SUPERVISOR_DATA, "updater.json")
FILE_HASSIO_SERVICES = Path(SUPERVISOR_DATA, "services.json")
FILE_HASSIO_DISCOVERY = Path(SUPERVISOR_DATA, "discovery.json")
FILE_HASSIO_INGRESS = Path(SUPERVISOR_DATA, "ingress.json")
FILE_HASSIO_DNS = Path(SUPERVISOR_DATA, "dns.json")
FILE_HASSIO_AUDIO = Path(SUPERVISOR_DATA, "audio.json")
FILE_HASSIO_AUTH = Path(SUPERVISOR_DATA, "auth.json")
FILE_HASSIO_CLI = Path(SUPERVISOR_DATA, "cli.json")
FILE_HASSIO_CONFIG = Path(SUPERVISOR_DATA, "config.json")
FILE_HASSIO_DISCOVERY = Path(SUPERVISOR_DATA, "discovery.json")
FILE_HASSIO_DNS = Path(SUPERVISOR_DATA, "dns.json")
FILE_HASSIO_HOMEASSISTANT = Path(SUPERVISOR_DATA, "homeassistant.json")
FILE_HASSIO_INGRESS = Path(SUPERVISOR_DATA, "ingress.json")
FILE_HASSIO_MULTICAST = Path(SUPERVISOR_DATA, "multicast.json")
FILE_HASSIO_SERVICES = Path(SUPERVISOR_DATA, "services.json")
FILE_HASSIO_UPDATER = Path(SUPERVISOR_DATA, "updater.json")
MACHINE_ID = Path("/etc/machine-id")
SOCKET_DOCKER = Path("/run/docker.sock")
SOCKET_DBUS = Path("/run/dbus/system_bus_socket")
SOCKET_DOCKER = Path("/run/docker.sock")
DOCKER_NETWORK = "hassio"
DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23")
@ -44,216 +44,233 @@ DOCKER_IMAGE_DENYLIST = [
DNS_SUFFIX = "local.hass.io"
LABEL_VERSION = "io.hass.version"
LABEL_ARCH = "io.hass.arch"
LABEL_TYPE = "io.hass.type"
LABEL_MACHINE = "io.hass.machine"
LABEL_TYPE = "io.hass.type"
LABEL_VERSION = "io.hass.version"
META_ADDON = "addon"
META_SUPERVISOR = "supervisor"
META_HOMEASSISTANT = "homeassistant"
META_SUPERVISOR = "supervisor"
JSON_RESULT = "result"
JSON_DATA = "data"
JSON_MESSAGE = "message"
JSON_RESULT = "result"
RESULT_ERROR = "error"
RESULT_OK = "ok"
CONTENT_TYPE_BINARY = "application/octet-stream"
CONTENT_TYPE_PNG = "image/png"
CONTENT_TYPE_JSON = "application/json"
CONTENT_TYPE_TEXT = "text/plain"
CONTENT_TYPE_PNG = "image/png"
CONTENT_TYPE_TAR = "application/tar"
CONTENT_TYPE_TEXT = "text/plain"
CONTENT_TYPE_URL = "application/x-www-form-urlencoded"
COOKIE_INGRESS = "ingress_session"
HEADER_TOKEN = "X-Supervisor-Token"
HEADER_TOKEN_OLD = "X-Hassio-Key"
ENV_TOKEN_OLD = "HASSIO_TOKEN"
ENV_TOKEN = "SUPERVISOR_TOKEN"
ENV_TIME = "TZ"
ENV_TOKEN = "SUPERVISOR_TOKEN"
ENV_TOKEN_OLD = "HASSIO_TOKEN"
ENV_HOMEASSISTANT_REPOSITORY = "HOMEASSISTANT_REPOSITORY"
ENV_SUPERVISOR_SHARE = "SUPERVISOR_SHARE"
ENV_SUPERVISOR_NAME = "SUPERVISOR_NAME"
ENV_SUPERVISOR_MACHINE = "SUPERVISOR_MACHINE"
ENV_SUPERVISOR_DEV = "SUPERVISOR_DEV"
ENV_SUPERVISOR_MACHINE = "SUPERVISOR_MACHINE"
ENV_SUPERVISOR_NAME = "SUPERVISOR_NAME"
ENV_SUPERVISOR_SHARE = "SUPERVISOR_SHARE"
REQUEST_FROM = "HASSIO_FROM"
ATTR_DOCKER = "docker"
ATTR_SUPERVISOR = "supervisor"
ATTR_MACHINE = "machine"
ATTR_MULTICAST = "multicast"
ATTR_WAIT_BOOT = "wait_boot"
ATTR_DEPLOYMENT = "deployment"
ATTR_WATCHDOG = "watchdog"
ATTR_CHANGELOG = "changelog"
ATTR_LOGGING = "logging"
ATTR_DATE = "date"
ATTR_ARCH = "arch"
ATTR_LONG_DESCRIPTION = "long_description"
ATTR_HOSTNAME = "hostname"
ATTR_TIMEZONE = "timezone"
ATTR_ARGS = "args"
ATTR_OPERATING_SYSTEM = "operating_system"
ATTR_CHASSIS = "chassis"
ATTR_TYPE = "type"
ATTR_SOURCE = "source"
ATTR_FEATURES = "features"
ATTR_ACCESS_TOKEN = "access_token"
ATTR_ACTIVE = "active"
ATTR_ADDON = "addon"
ATTR_ADDONS = "addons"
ATTR_PROVIDERS = "providers"
ATTR_VERSION = "version"
ATTR_VERSION_LATEST = "version_latest"
ATTR_AUTO_UART = "auto_uart"
ATTR_USB = "usb"
ATTR_LAST_BOOT = "last_boot"
ATTR_CHANNEL = "channel"
ATTR_NAME = "name"
ATTR_SLUG = "slug"
ATTR_DESCRIPTON = "description"
ATTR_STARTUP = "startup"
ATTR_BOOT = "boot"
ATTR_PORTS = "ports"
ATTR_PORTS_DESCRIPTION = "ports_description"
ATTR_PORT = "port"
ATTR_SSL = "ssl"
ATTR_MAP = "map"
ATTR_WEBUI = "webui"
ATTR_OPTIONS = "options"
ATTR_INSTALLED = "installed"
ATTR_DETACHED = "detached"
ATTR_STATE = "state"
ATTR_SCHEMA = "schema"
ATTR_IMAGE = "image"
ATTR_ICON = "icon"
ATTR_LOGO = "logo"
ATTR_STDIN = "stdin"
ATTR_ADDONS_CUSTOM_LIST = "addons_custom_list"
ATTR_ADDONS_REPOSITORIES = "addons_repositories"
ATTR_REPOSITORY = "repository"
ATTR_REPOSITORIES = "repositories"
ATTR_URL = "url"
ATTR_MAINTAINER = "maintainer"
ATTR_PASSWORD = "password"
ATTR_TOTP = "totp"
ATTR_INITIALIZE = "initialize"
ATTR_LOCATON = "location"
ATTR_BUILD = "build"
ATTR_DEVICES = "devices"
ATTR_ENVIRONMENT = "environment"
ATTR_HOST_NETWORK = "host_network"
ATTR_HOST_PID = "host_pid"
ATTR_HOST_IPC = "host_ipc"
ATTR_HOST_DBUS = "host_dbus"
ATTR_NETWORK = "network"
ATTR_NETWORK_DESCRIPTION = "network_description"
ATTR_TMPFS = "tmpfs"
ATTR_PRIVILEGED = "privileged"
ATTR_USER = "user"
ATTR_SYSTEM = "system"
ATTR_SNAPSHOTS = "snapshots"
ATTR_HOMEASSISTANT = "homeassistant"
ATTR_HASSIO_API = "hassio_api"
ATTR_HOMEASSISTANT_API = "homeassistant_api"
ATTR_UUID = "uuid"
ATTR_FOLDERS = "folders"
ATTR_SIZE = "size"
ATTR_TYPE = "type"
ATTR_TIMEOUT = "timeout"
ATTR_AUTO_UPDATE = "auto_update"
ATTR_VIDEO = "video"
ATTR_ADDRESS = "address"
ATTR_ADDRESS_DATA = "address-data"
ATTR_ADMIN = "admin"
ATTR_ADVANCED = "advanced"
ATTR_APPARMOR = "apparmor"
ATTR_APPLICATION = "application"
ATTR_ARCH = "arch"
ATTR_ARGS = "args"
ATTR_AUDIO = "audio"
ATTR_AUDIO_INPUT = "audio_input"
ATTR_AUDIO_OUTPUT = "audio_output"
ATTR_INPUT = "input"
ATTR_OUTPUT = "output"
ATTR_AUTH_API = "auth_api"
ATTR_AUTO_UART = "auto_uart"
ATTR_AUTO_UPDATE = "auto_update"
ATTR_AVAILABLE = "available"
ATTR_BLK_READ = "blk_read"
ATTR_BLK_WRITE = "blk_write"
ATTR_BOARD = "board"
ATTR_BOOT = "boot"
ATTR_BRANCH = "branch"
ATTR_BUILD = "build"
ATTR_BUILD_FROM = "build_from"
ATTR_CARD = "card"
ATTR_CHANGELOG = "changelog"
ATTR_CHANNEL = "channel"
ATTR_CHASSIS = "chassis"
ATTR_CLI = "cli"
ATTR_CONFIG = "config"
ATTR_CONNECTIONS = "connections"
ATTR_CPE = "cpe"
ATTR_CPU_PERCENT = "cpu_percent"
ATTR_CRYPTO = "crypto"
ATTR_DATE = "date"
ATTR_DEBUG = "debug"
ATTR_DEBUG_BLOCK = "debug_block"
ATTR_DEFAULT = "default"
ATTR_DEPLOYMENT = "deployment"
ATTR_DESCRIPTON = "description"
ATTR_DETACHED = "detached"
ATTR_DEVICES = "devices"
ATTR_DEVICETREE = "devicetree"
ATTR_DIAGNOSTICS = "diagnostics"
ATTR_DISCOVERY = "discovery"
ATTR_DISK = "disk"
ATTR_DISK_FREE = "disk_free"
ATTR_DISK_TOTAL = "disk_total"
ATTR_DISK_USED = "disk_used"
ATTR_SERIAL = "serial"
ATTR_SECURITY = "security"
ATTR_BUILD_FROM = "build_from"
ATTR_SQUASH = "squash"
ATTR_GPIO = "gpio"
ATTR_LEGACY = "legacy"
ATTR_ADDONS_CUSTOM_LIST = "addons_custom_list"
ATTR_CPU_PERCENT = "cpu_percent"
ATTR_NETWORK_RX = "network_rx"
ATTR_NETWORK_TX = "network_tx"
ATTR_MEMORY_LIMIT = "memory_limit"
ATTR_MEMORY_USAGE = "memory_usage"
ATTR_MEMORY_PERCENT = "memory_percent"
ATTR_BLK_READ = "blk_read"
ATTR_BLK_WRITE = "blk_write"
ATTR_ADDON = "addon"
ATTR_AVAILABLE = "available"
ATTR_HOST = "host"
ATTR_USERNAME = "username"
ATTR_DISCOVERY = "discovery"
ATTR_CONFIG = "config"
ATTR_SERVICES = "services"
ATTR_SERVICE = "service"
ATTR_DISCOVERY = "discovery"
ATTR_PROTECTED = "protected"
ATTR_CRYPTO = "crypto"
ATTR_BRANCH = "branch"
ATTR_KERNEL = "kernel"
ATTR_APPARMOR = "apparmor"
ATTR_DEVICETREE = "devicetree"
ATTR_CPE = "cpe"
ATTR_BOARD = "board"
ATTR_HASSOS = "hassos"
ATTR_REFRESH_TOKEN = "refresh_token"
ATTR_ACCESS_TOKEN = "access_token"
ATTR_DNS = "dns"
ATTR_DOCKER = "docker"
ATTR_DOCKER_API = "docker_api"
ATTR_DOCUMENTATION = "documentation"
ATTR_DOMAINS = "domains"
ATTR_ENABLE = "enable"
ATTR_ENVIRONMENT = "environment"
ATTR_FEATURES = "features"
ATTR_FILENAME = "filename"
ATTR_FLAGS = "flags"
ATTR_FOLDERS = "folders"
ATTR_FULL_ACCESS = "full_access"
ATTR_PROTECTED = "protected"
ATTR_RATING = "rating"
ATTR_GATEWAY = "gateway"
ATTR_GPIO = "gpio"
ATTR_HASSIO_API = "hassio_api"
ATTR_HASSIO_ROLE = "hassio_role"
ATTR_SUPERVISOR = "supervisor"
ATTR_AUTH_API = "auth_api"
ATTR_KERNEL_MODULES = "kernel_modules"
ATTR_SUPPORTED_ARCH = "supported_arch"
ATTR_HASSOS = "hassos"
ATTR_HEALTHY = "healthy"
ATTR_HOMEASSISTANT = "homeassistant"
ATTR_HOMEASSISTANT_API = "homeassistant_api"
ATTR_HOST = "host"
ATTR_HOST_DBUS = "host_dbus"
ATTR_HOST_IPC = "host_ipc"
ATTR_HOST_NETWORK = "host_network"
ATTR_HOST_PID = "host_pid"
ATTR_HOSTNAME = "hostname"
ATTR_ICON = "icon"
ATTR_ID = "id"
ATTR_IMAGE = "image"
ATTR_INDEX = "index"
ATTR_INGRESS = "ingress"
ATTR_INGRESS_PORT = "ingress_port"
ATTR_INGRESS_ENTRY = "ingress_entry"
ATTR_INGRESS_PANEL = "ingress_panel"
ATTR_INGRESS_PORT = "ingress_port"
ATTR_INGRESS_TOKEN = "ingress_token"
ATTR_INGRESS_URL = "ingress_url"
ATTR_INGRESS_PANEL = "ingress_panel"
ATTR_INIT = "init"
ATTR_INITIALIZE = "initialize"
ATTR_INPUT = "input"
ATTR_INSTALLED = "installed"
ATTR_INTERFACE = "interface"
ATTR_INTERFACES = "interfaces"
ATTR_IP_ADDRESS = "ip_address"
ATTR_IPV4 = "ipv4"
ATTR_KERNEL = "kernel"
ATTR_KERNEL_MODULES = "kernel_modules"
ATTR_LAST_BOOT = "last_boot"
ATTR_LEGACY = "legacy"
ATTR_LOCALS = "locals"
ATTR_LOCATON = "location"
ATTR_LOGGING = "logging"
ATTR_LOGO = "logo"
ATTR_LONG_DESCRIPTION = "long_description"
ATTR_MACHINE = "machine"
ATTR_MAINTAINER = "maintainer"
ATTR_MAP = "map"
ATTR_MEMORY_LIMIT = "memory_limit"
ATTR_MEMORY_PERCENT = "memory_percent"
ATTR_MEMORY_USAGE = "memory_usage"
ATTR_METHOD = "method"
ATTR_METHODS = ["dhcp", "static"]
ATTR_MODE = "mode"
ATTR_MULTICAST = "multicast"
ATTR_NAME = "name"
ATTR_NAMESERVERS = "nameservers"
ATTR_NETWORK = "network"
ATTR_NETWORK_DESCRIPTION = "network_description"
ATTR_NETWORK_RX = "network_rx"
ATTR_NETWORK_TX = "network_tx"
ATTR_OPERATING_SYSTEM = "operating_system"
ATTR_OPTIONS = "options"
ATTR_OUTPUT = "output"
ATTR_PANEL_ADMIN = "panel_admin"
ATTR_PANEL_ICON = "panel_icon"
ATTR_PANEL_TITLE = "panel_title"
ATTR_PANEL_ADMIN = "panel_admin"
ATTR_TITLE = "title"
ATTR_ENABLE = "enable"
ATTR_IP_ADDRESS = "ip_address"
ATTR_SESSION = "session"
ATTR_ADMIN = "admin"
ATTR_PANELS = "panels"
ATTR_DEBUG = "debug"
ATTR_DEBUG_BLOCK = "debug_block"
ATTR_DNS = "dns"
ATTR_PASSWORD = "password"
ATTR_PORT = "port"
ATTR_PORTS = "ports"
ATTR_PORTS_DESCRIPTION = "ports_description"
ATTR_PREFIX = "prefix"
ATTR_PRIMARY = "primary"
ATTR_PRIORITY = "priority"
ATTR_PRIVILEGED = "privileged"
ATTR_PROTECTED = "protected"
ATTR_PROVIDERS = "providers"
ATTR_RATING = "rating"
ATTR_REFRESH_TOKEN = "refresh_token"
ATTR_REPOSITORIES = "repositories"
ATTR_REPOSITORY = "repository"
ATTR_SCHEMA = "schema"
ATTR_SECURITY = "security"
ATTR_SERIAL = "serial"
ATTR_SERVERS = "servers"
ATTR_LOCALS = "locals"
ATTR_UDEV = "udev"
ATTR_VALUE = "value"
ATTR_SERVICE = "service"
ATTR_SERVICES = "services"
ATTR_SESSION = "session"
ATTR_SIZE = "size"
ATTR_SLUG = "slug"
ATTR_SNAPSHOT_EXCLUDE = "snapshot_exclude"
ATTR_DOCUMENTATION = "documentation"
ATTR_ADVANCED = "advanced"
ATTR_SNAPSHOTS = "snapshots"
ATTR_SOURCE = "source"
ATTR_SQUASH = "squash"
ATTR_SSL = "ssl"
ATTR_STAGE = "stage"
ATTR_CLI = "cli"
ATTR_DEFAULT = "default"
ATTR_VOLUME = "volume"
ATTR_CARD = "card"
ATTR_INDEX = "index"
ATTR_ACTIVE = "active"
ATTR_APPLICATION = "application"
ATTR_INIT = "init"
ATTR_DIAGNOSTICS = "diagnostics"
ATTR_HEALTHY = "healthy"
ATTR_STARTUP = "startup"
ATTR_STATE = "state"
ATTR_STATIC = "static"
ATTR_STDIN = "stdin"
ATTR_SUPERVISOR = "supervisor"
ATTR_SUPPORTED = "supported"
ATTR_SUPPORTED_ARCH = "supported_arch"
ATTR_SYSTEM = "system"
ATTR_TIMEOUT = "timeout"
ATTR_TIMEZONE = "timezone"
ATTR_TITLE = "title"
ATTR_TMPFS = "tmpfs"
ATTR_TOTP = "totp"
ATTR_TYPE = "type"
ATTR_UDEV = "udev"
ATTR_UNSAVED = "unsaved"
ATTR_URL = "url"
ATTR_USB = "usb"
ATTR_USER = "user"
ATTR_USERNAME = "username"
ATTR_UUID = "uuid"
ATTR_VALUE = "value"
ATTR_VERSION = "version"
ATTR_VERSION_LATEST = "version_latest"
ATTR_VIDEO = "video"
ATTR_VOLUME = "volume"
ATTR_VPN = "vpn"
ATTR_WAIT_BOOT = "wait_boot"
ATTR_WATCHDOG = "watchdog"
ATTR_WEBUI = "webui"
PROVIDE_SERVICE = "provide"
NEED_SERVICE = "need"
@ -297,16 +314,16 @@ SECURITY_PROFILE = "profile"
SECURITY_DEFAULT = "default"
SECURITY_DISABLE = "disable"
PRIVILEGED_DAC_READ_SEARCH = "DAC_READ_SEARCH"
PRIVILEGED_IPC_LOCK = "IPC_LOCK"
PRIVILEGED_NET_ADMIN = "NET_ADMIN"
PRIVILEGED_SYS_ADMIN = "SYS_ADMIN"
PRIVILEGED_SYS_RAWIO = "SYS_RAWIO"
PRIVILEGED_IPC_LOCK = "IPC_LOCK"
PRIVILEGED_SYS_TIME = "SYS_TIME"
PRIVILEGED_SYS_NICE = "SYS_NICE"
PRIVILEGED_SYS_MODULE = "SYS_MODULE"
PRIVILEGED_SYS_RESOURCE = "SYS_RESOURCE"
PRIVILEGED_SYS_NICE = "SYS_NICE"
PRIVILEGED_SYS_PTRACE = "SYS_PTRACE"
PRIVILEGED_DAC_READ_SEARCH = "DAC_READ_SEARCH"
PRIVILEGED_SYS_RAWIO = "SYS_RAWIO"
PRIVILEGED_SYS_RESOURCE = "SYS_RESOURCE"
PRIVILEGED_SYS_TIME = "SYS_TIME"
PRIVILEGED_ALL = [
PRIVILEGED_NET_ADMIN,

View File

@ -134,9 +134,9 @@ class Core(CoreSysAttributes):
if not self.sys_dbus.hostname.is_connected:
self.supported = False
_LOGGER.error("Hostname DBUS is not connected")
if not self.sys_dbus.nmi_dns.is_connected:
if not self.sys_dbus.network.is_connected:
self.supported = False
_LOGGER.error("NetworkManager DNS DBUS is not connected")
_LOGGER.error("NetworkManager is not connected")
if not self.sys_dbus.systemd.is_connected:
self.supported = False
_LOGGER.error("Systemd DBUS is not connected")

View File

@ -4,7 +4,7 @@ import logging
from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import DBusNotConnectedError
from .hostname import Hostname
from .nmi_dns import NMIDnsManager
from .network import NetworkManager
from .rauc import Rauc
from .systemd import Systemd
@ -21,7 +21,7 @@ class DBusManager(CoreSysAttributes):
self._systemd: Systemd = Systemd()
self._hostname: Hostname = Hostname()
self._rauc: Rauc = Rauc()
self._nmi_dns: NMIDnsManager = NMIDnsManager()
self._network: NetworkManager = NetworkManager()
@property
def systemd(self) -> Systemd:
@ -39,9 +39,9 @@ class DBusManager(CoreSysAttributes):
return self._rauc
@property
def nmi_dns(self) -> NMIDnsManager:
"""Return NetworkManager DNS interface."""
return self._nmi_dns
def network(self) -> NetworkManager:
"""Return NetworkManager interface."""
return self._network
async def load(self) -> None:
"""Connect interfaces to D-Bus."""
@ -50,7 +50,7 @@ class DBusManager(CoreSysAttributes):
await self.systemd.connect()
await self.hostname.connect()
await self.rauc.connect()
await self.nmi_dns.connect()
await self.network.connect()
except DBusNotConnectedError:
_LOGGER.error(
"No DBus support from Host. Disabled any kind of host control!"

74
supervisor/dbus/const.py Normal file
View File

@ -0,0 +1,74 @@
"""Constants for DBUS."""
from enum import Enum
DBUS_NAME_CONNECTION_ACTIVE = "org.freedesktop.NetworkManager.Connection.Active"
DBUS_NAME_DEVICE = "org.freedesktop.NetworkManager.Device"
DBUS_NAME_DNS = "org.freedesktop.NetworkManager.DnsManager"
DBUS_NAME_HOSTNAME = "org.freedesktop.hostname1"
DBUS_NAME_IP4CONFIG = "org.freedesktop.NetworkManager.IP4Config"
DBUS_NAME_NM = "org.freedesktop.NetworkManager"
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_OBJECT_BASE = "/"
DBUS_OBJECT_DNS = "/org/freedesktop/NetworkManager/DnsManager"
DBUS_OBJECT_HOSTNAME = "/org/freedesktop/hostname1"
DBUS_OBJECT_NM = "/org/freedesktop/NetworkManager"
DBUS_OBJECT_SYSTEMD = "/org/freedesktop/systemd1"
DBUS_ATTR_ACTIVE_CONNECTIONS = "ActiveConnections"
DBUS_ATTR_ADDRESS_DATA = "AddressData"
DBUS_ATTR_BOOT_SLOT = "BootSlot"
DBUS_ATTR_CHASSIS = "Chassis"
DBUS_ATTR_COMPATIBLE = "Compatible"
DBUS_ATTR_CONFIGURATION = "Configuration"
DBUS_ATTR_CONNECTION = "Connection"
DBUS_ATTR_DEFAULT = "Default"
DBUS_ATTR_DEPLOYMENT = "Deployment"
DBUS_ATTR_DEVICE_INTERFACE = "Interface"
DBUS_ATTR_DEVICE_TYPE = "DeviceType"
DBUS_ATTR_DEVICES = "Devices"
DBUS_ATTR_GATEWAY = "Gateway"
DBUS_ATTR_ID = "Id"
DBUS_ATTR_IP4ADDRESS = "Ip4Address"
DBUS_ATTR_IP4CONFIG = "Ip4Config"
DBUS_ATTR_KERNEL_RELEASE = "KernelRelease"
DBUS_ATTR_LAST_ERROR = "LastError"
DBUS_ATTR_MODE = "Mode"
DBUS_ATTR_NAMESERVERS = "Nameservers"
DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME = "OperatingSystemPrettyName"
DBUS_ATTR_OPERATION = "Operation"
DBUS_ATTR_PRIMARY_CONNECTION = "PrimaryConnection"
DBUS_ATTR_RCMANAGER = "RcManager"
DBUS_ATTR_REAL = "Real"
DBUS_ATTR_STATE = "State"
DBUS_ATTR_STATIC_HOSTNAME = "StaticHostname"
DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME = "OperatingSystemCPEName"
DBUS_ATTR_TYPE = "Type"
DBUS_ATTR_UUID = "Uuid"
DBUS_ATTR_VARIANT = "Variant"
class RaucState(str, Enum):
"""Rauc slot states."""
GOOD = "good"
BAD = "bad"
ACTIVE = "active"
class InterfaceMethod(str, Enum):
"""Interface method simple."""
AUTO = "auto"
MANUAL = "manual"
class InterfaceMethodSimple(str, Enum):
"""Interface method."""
DHCP = "dhcp"
STATIC = "static"

View File

@ -4,14 +4,21 @@ from typing import Optional
from ..exceptions import DBusError, DBusInterfaceError
from ..utils.gdbus import DBus
from .const import (
DBUS_ATTR_CHASSIS,
DBUS_ATTR_DEPLOYMENT,
DBUS_ATTR_KERNEL_RELEASE,
DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME,
DBUS_ATTR_STATIC_HOSTNAME,
DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME,
DBUS_NAME_HOSTNAME,
DBUS_OBJECT_HOSTNAME,
)
from .interface import DBusInterface
from .utils import dbus_connected
_LOGGER: logging.Logger = logging.getLogger(__name__)
DBUS_NAME = "org.freedesktop.hostname1"
DBUS_OBJECT = "/org/freedesktop/hostname1"
class Hostname(DBusInterface):
"""Handle D-Bus interface for hostname/system."""
@ -28,7 +35,7 @@ class Hostname(DBusInterface):
async def connect(self):
"""Connect to system's D-Bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
self.dbus = await DBus.connect(DBUS_NAME_HOSTNAME, DBUS_OBJECT_HOSTNAME)
except DBusError:
_LOGGER.warning("Can't connect to hostname")
except DBusInterfaceError:
@ -77,14 +84,14 @@ class Hostname(DBusInterface):
@dbus_connected
async def update(self):
"""Update Properties."""
data = await self.dbus.get_properties(DBUS_NAME)
data = await self.dbus.get_properties(DBUS_NAME_HOSTNAME)
if not data:
_LOGGER.warning("Can't get properties for Hostname")
return
self._hostname = data.get("StaticHostname")
self._chassis = data.get("Chassis")
self._deployment = data.get("Deployment")
self._kernel = data.get("KernelRelease")
self._operating_system = data.get("OperatingSystemPrettyName")
self._cpe = data.get("OperatingSystemCPEName")
self._hostname = data.get(DBUS_ATTR_STATIC_HOSTNAME)
self._chassis = data.get(DBUS_ATTR_CHASSIS)
self._deployment = data.get(DBUS_ATTR_DEPLOYMENT)
self._kernel = data.get(DBUS_ATTR_KERNEL_RELEASE)
self._operating_system = data.get(DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME)
self._cpe = data.get(DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME)

View File

@ -0,0 +1,80 @@
"""Network Manager implementation for DBUS."""
import logging
from typing import Dict, Optional
from ...exceptions import DBusError, DBusInterfaceError
from ...utils.gdbus import DBus
from ..const import (
DBUS_ATTR_ACTIVE_CONNECTIONS,
DBUS_ATTR_PRIMARY_CONNECTION,
DBUS_NAME_NM,
DBUS_OBJECT_NM,
)
from ..interface import DBusInterface
from ..utils import dbus_connected
from .dns import NetworkManagerDNS
from .interface import NetworkInterface
_LOGGER: logging.Logger = logging.getLogger(__name__)
class NetworkManager(DBusInterface):
"""Handle D-Bus interface for Network Manager."""
def __init__(self) -> None:
"""Initialize Properties."""
self._dns: NetworkManagerDNS = NetworkManagerDNS()
self._interfaces: Optional[Dict[str, NetworkInterface]] = []
@property
def dns(self) -> NetworkManagerDNS:
"""Return NetworkManager DNS interface."""
return self._dns
@property
def interfaces(self) -> Dict[str, NetworkInterface]:
"""Return a dictionary of active interfaces."""
return self._interfaces
async def connect(self) -> None:
"""Connect to system's D-Bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME_NM, DBUS_OBJECT_NM)
await self.dns.connect()
except DBusError:
_LOGGER.warning("Can't connect to Network Manager")
except DBusInterfaceError:
_LOGGER.warning(
"No Network Manager support on the host. Local network functions have been disabled."
)
@dbus_connected
async def update(self):
"""Update Properties."""
await self.dns.update()
data = await self.dbus.get_properties(DBUS_NAME_NM)
if not data:
_LOGGER.warning("Can't get properties for Network Manager")
return
self._interfaces = {}
for connection in data.get(DBUS_ATTR_ACTIVE_CONNECTIONS, []):
interface = NetworkInterface()
await interface.connect(self.dbus, connection)
if not interface.connection.default:
continue
try:
await interface.connection.update_information()
except IndexError:
continue
if interface.connection.object_path == data.get(
DBUS_ATTR_PRIMARY_CONNECTION
):
interface.connection.primary = True
self._interfaces[interface.name] = interface

View File

@ -0,0 +1,62 @@
"""NetworkConnection object4s for Network Manager."""
from typing import List
import attr
from ...utils.gdbus import DBus
class NetworkAttributes:
"""NetworkAttributes object for Network Manager."""
def __init__(self, object_path: str, properties: dict) -> None:
"""Initialize NetworkAttributes object."""
self._properties = properties
self.object_path = object_path
@attr.s
class AddressData:
"""AddressData object for Network Manager."""
address: str = attr.ib()
prefix: int = attr.ib()
@attr.s
class IpConfiguration:
"""NetworkSettingsIPConfig object for Network Manager."""
gateway: str = attr.ib()
method: str = attr.ib()
nameservers: List[int] = attr.ib()
address_data: AddressData = attr.ib()
@attr.s
class DNSConfiguration:
"""DNS configuration Object."""
nameservers: List[str] = attr.ib()
domains: List[str] = attr.ib()
interface: str = attr.ib()
priority: int = attr.ib()
vpn: bool = attr.ib()
@attr.s
class NetworkSettings:
"""NetworkSettings object for Network Manager."""
dbus: DBus = attr.ib()
@attr.s
class NetworkDevice:
"""Device properties."""
dbus: DBus = attr.ib()
interface: str = attr.ib()
ip4_address: int = attr.ib()
device_type: int = attr.ib()
real: bool = attr.ib()

View File

@ -0,0 +1,124 @@
"""Connection object for Network Manager."""
from typing import Optional
from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX
from ...utils.gdbus import DBus
from ..const import (
DBUS_ATTR_ADDRESS_DATA,
DBUS_ATTR_CONNECTION,
DBUS_ATTR_DEFAULT,
DBUS_ATTR_DEVICE_INTERFACE,
DBUS_ATTR_DEVICE_TYPE,
DBUS_ATTR_DEVICES,
DBUS_ATTR_GATEWAY,
DBUS_ATTR_ID,
DBUS_ATTR_IP4ADDRESS,
DBUS_ATTR_IP4CONFIG,
DBUS_ATTR_NAMESERVERS,
DBUS_ATTR_REAL,
DBUS_ATTR_STATE,
DBUS_ATTR_TYPE,
DBUS_ATTR_UUID,
DBUS_NAME_DEVICE,
DBUS_NAME_IP4CONFIG,
DBUS_NAME_NM,
)
from .configuration import (
AddressData,
IpConfiguration,
NetworkAttributes,
NetworkDevice,
NetworkSettings,
)
class NetworkConnection(NetworkAttributes):
"""NetworkConnection object for Network Manager."""
def __init__(self, object_path: str, properties: dict) -> None:
"""Initialize NetworkConnection object."""
super().__init__(object_path, properties)
self._device_dbus: DBus = None
self._settings_dbus: DBus = None
self._settings: Optional[NetworkSettings] = None
self._ip4_config: Optional[IpConfiguration] = None
self._device: Optional[NetworkDevice]
self.primary: bool = False
@property
def settings(self) -> NetworkSettings:
"""Return a settings object for the connection."""
return self._settings
@property
def device(self) -> NetworkDevice:
"""Return the device used in the connection."""
return self._device
@property
def default(self) -> bool:
"""Return a boolean connection is marked as default."""
return self._properties[DBUS_ATTR_DEFAULT]
@property
def id(self) -> str:
"""Return the id of the connection."""
return self._properties[DBUS_ATTR_ID]
@property
def type(self) -> str:
"""Return the type of the connection."""
return self._properties[DBUS_ATTR_TYPE]
@property
def ip4_config(self) -> IpConfiguration:
"""Return a ip configuration object for the connection."""
return self._ip4_config
@property
def uuid(self) -> str:
"""Return the uuid of the connection."""
return self._properties[DBUS_ATTR_UUID]
@property
def state(self) -> int:
"""
Return the state of the connection.
https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMActiveConnectionState
"""
return self._properties[DBUS_ATTR_STATE]
async def update_information(self):
"""Update the information for childs ."""
settings = await DBus.connect(
DBUS_NAME_NM, self._properties[DBUS_ATTR_CONNECTION]
)
device = await DBus.connect(
DBUS_NAME_NM, self._properties[DBUS_ATTR_DEVICES][0]
)
ip4 = await DBus.connect(DBUS_NAME_NM, self._properties[DBUS_ATTR_IP4CONFIG])
data = (await settings.Settings.Connection.GetSettings())[0]
device_data = await device.get_properties(DBUS_NAME_DEVICE)
ip4_data = await ip4.get_properties(DBUS_NAME_IP4CONFIG)
self._settings = NetworkSettings(settings)
self._ip4_config = IpConfiguration(
ip4_data.get(DBUS_ATTR_GATEWAY),
data[ATTR_IPV4].get(ATTR_METHOD),
ip4_data.get(DBUS_ATTR_NAMESERVERS),
AddressData(
ip4_data.get(DBUS_ATTR_ADDRESS_DATA)[0].get(ATTR_ADDRESS),
ip4_data.get(DBUS_ATTR_ADDRESS_DATA)[0].get(ATTR_PREFIX),
),
)
self._device = NetworkDevice(
device,
device_data.get(DBUS_ATTR_DEVICE_INTERFACE),
device_data.get(DBUS_ATTR_IP4ADDRESS),
device_data.get(DBUS_ATTR_DEVICE_TYPE),
device_data.get(DBUS_ATTR_REAL),
)

View File

@ -2,31 +2,31 @@
import logging
from typing import List, Optional
import attr
from ..exceptions import DBusError, DBusInterfaceError
from ..utils.gdbus import DBus
from .interface import DBusInterface
from .utils import dbus_connected
from ...const import (
ATTR_DOMAINS,
ATTR_INTERFACE,
ATTR_NAMESERVERS,
ATTR_PRIORITY,
ATTR_VPN,
)
from ...exceptions import DBusError, DBusInterfaceError
from ...utils.gdbus import DBus
from ..const import (
DBUS_ATTR_CONFIGURATION,
DBUS_ATTR_MODE,
DBUS_ATTR_RCMANAGER,
DBUS_NAME_DNS,
DBUS_NAME_NM,
DBUS_OBJECT_DNS,
)
from ..interface import DBusInterface
from ..utils import dbus_connected
from .configuration import DNSConfiguration
_LOGGER: logging.Logger = logging.getLogger(__name__)
DBUS_NAME = "org.freedesktop.NetworkManager"
DBUS_OBJECT = "/org/freedesktop/NetworkManager/DnsManager"
@attr.s
class DNSConfiguration:
"""NMI DnsManager configuration Object."""
nameservers: List[str] = attr.ib()
domains: List[str] = attr.ib()
interface: str = attr.ib()
priority: int = attr.ib()
vpn: bool = attr.ib()
class NMIDnsManager(DBusInterface):
class NetworkManagerDNS(DBusInterface):
"""Handle D-Bus interface for NMI DnsManager."""
def __init__(self) -> None:
@ -53,7 +53,7 @@ class NMIDnsManager(DBusInterface):
async def connect(self) -> None:
"""Connect to system's D-Bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
self.dbus = await DBus.connect(DBUS_NAME_NM, DBUS_OBJECT_DNS)
except DBusError:
_LOGGER.warning("Can't connect to DnsManager")
except DBusInterfaceError:
@ -64,22 +64,22 @@ class NMIDnsManager(DBusInterface):
@dbus_connected
async def update(self):
"""Update Properties."""
data = await self.dbus.get_properties(f"{DBUS_NAME}.DnsManager")
data = await self.dbus.get_properties(DBUS_NAME_DNS)
if not data:
_LOGGER.warning("Can't get properties for NMI DnsManager")
_LOGGER.warning("Can't get properties for DnsManager")
return
self._mode = data.get("Mode")
self._rc_manager = data.get("RcManager")
self._mode = data.get(DBUS_ATTR_MODE)
self._rc_manager = data.get(DBUS_ATTR_RCMANAGER)
# Parse configuraton
self._configuration.clear()
for config in data.get("Configuration", []):
dns = DNSConfiguration(
config.get("nameservers"),
config.get("domains"),
config.get("interface"),
config.get("priority"),
config.get("vpn"),
self._configuration = [
DNSConfiguration(
config.get(ATTR_NAMESERVERS),
config.get(ATTR_DOMAINS),
config.get(ATTR_INTERFACE),
config.get(ATTR_PRIORITY),
config.get(ATTR_VPN),
)
self._configuration.append(dns)
for config in data.get(DBUS_ATTR_CONFIGURATION, [])
]

View File

@ -0,0 +1,129 @@
"""NetworkInterface object for Network Manager."""
from ...const import ATTR_ADDRESS, ATTR_DNS, ATTR_GATEWAY, ATTR_METHOD, ATTR_PREFIX
from ...utils.gdbus import DBus
from ..const import (
DBUS_NAME_CONNECTION_ACTIVE,
DBUS_NAME_NM,
DBUS_OBJECT_BASE,
InterfaceMethod,
)
from .connection import NetworkConnection
from .utils import ip2int
class NetworkInterface:
"""NetworkInterface object for Network Manager, this serves as a proxy to other objects."""
def __init__(self) -> None:
"""Initialize NetworkConnection object."""
self._connection = None
self._nm_dbus = None
@property
def nm_dbus(self) -> DBus:
"""Return the NM DBus connection."""
return self._nm_dbus
@property
def connection(self) -> NetworkConnection:
"""Return the connection used for this interface."""
return self._connection
@property
def name(self) -> str:
"""Return the interface name."""
return self.connection.device.interface
@property
def primary(self) -> bool:
"""Return true if it's the primary interfac."""
return self.connection.primary
@property
def ip_address(self) -> str:
"""Return the ip_address."""
return self.connection.ip4_config.address_data.address
@property
def prefix(self) -> str:
"""Return the network prefix."""
return self.connection.ip4_config.address_data.prefix
@property
def type(self) -> str:
"""Return the interface type."""
return self.connection.type
@property
def id(self) -> str:
"""Return the interface id."""
return self.connection.id
@property
def method(self) -> InterfaceMethod:
"""Return the interface method."""
return InterfaceMethod(self.connection.ip4_config.method)
@property
def gateway(self) -> str:
"""Return the gateway."""
return self.connection.ip4_config.gateway
@property
def nameservers(self) -> str:
"""Return the nameservers."""
return self.connection.ip4_config.nameservers
async def connect(self, nm_dbus: DBus, connection_object: str) -> None:
"""Get connection information."""
self._nm_dbus = nm_dbus
connection_bus = await DBus.connect(DBUS_NAME_NM, connection_object)
connection_properties = await connection_bus.get_properties(
DBUS_NAME_CONNECTION_ACTIVE
)
self._connection = NetworkConnection(connection_object, connection_properties)
async def update_settings(self, **kwargs) -> None:
"""Update IP configuration used for this interface."""
if kwargs.get(ATTR_DNS):
kwargs[ATTR_DNS] = [ip2int(x.strip()) for x in kwargs[ATTR_DNS]]
if kwargs.get(ATTR_METHOD):
kwargs[ATTR_METHOD] = (
InterfaceMethod.MANUAL
if kwargs[ATTR_METHOD] == "static"
else InterfaceMethod.AUTO
)
if kwargs.get(ATTR_ADDRESS):
if "/" in kwargs[ATTR_ADDRESS]:
kwargs[ATTR_PREFIX] = kwargs[ATTR_ADDRESS].split("/")[-1]
kwargs[ATTR_ADDRESS] = kwargs[ATTR_ADDRESS].split("/")[0]
kwargs[ATTR_METHOD] = InterfaceMethod.MANUAL
await self.connection.settings.dbus.Settings.Connection.Update(
f"""{{
'connection':
{{
'id': <'{self.id}'>,
'type': <'{self.type}'>
}},
'ipv4':
{{
'method': <'{kwargs.get(ATTR_METHOD, self.method)}'>,
'dns': <[{",".join([f"uint32 {x}" for x in kwargs.get(ATTR_DNS, self.nameservers)])}]>,
'address-data': <[
{{
'address': <'{kwargs.get(ATTR_ADDRESS, self.ip_address)}'>,
'prefix': <uint32 {kwargs.get(ATTR_PREFIX, self.prefix)}>
}}]>,
'gateway': <'{kwargs.get(ATTR_GATEWAY, self.gateway)}'>
}}
}}"""
)
await self.nm_dbus.ActivateConnection(
self.connection.settings.dbus.object_path,
self.connection.device.dbus.object_path,
DBUS_OBJECT_BASE,
)

View File

@ -0,0 +1,14 @@
"""Network utils."""
from ipaddress import ip_address
# Return a 32bit representation of a IP Address
def ip2int(address: str) -> int:
"""Return a 32bit representation for a IP address."""
return int(ip_address(".".join(address.split(".")[::-1])))
def int2ip(bitaddress: int) -> int:
"""Return a IP Address object from a 32bit representation."""
return ".".join([str(bitaddress >> (i << 3) & 0xFF) for i in range(0, 4)])

View File

@ -1,26 +1,26 @@
"""D-Bus interface for rauc."""
from enum import Enum
import logging
from typing import Optional
from ..exceptions import DBusError, DBusInterfaceError
from ..utils.gdbus import DBus
from .const import (
DBUS_ATTR_BOOT_SLOT,
DBUS_ATTR_COMPATIBLE,
DBUS_ATTR_LAST_ERROR,
DBUS_ATTR_OPERATION,
DBUS_ATTR_VARIANT,
DBUS_NAME_RAUC,
DBUS_NAME_RAUC_INSTALLER,
DBUS_NAME_RAUC_INSTALLER_COMPLETED,
DBUS_OBJECT_BASE,
RaucState,
)
from .interface import DBusInterface
from .utils import dbus_connected
_LOGGER: logging.Logger = logging.getLogger(__name__)
DBUS_NAME = "de.pengutronix.rauc"
DBUS_OBJECT = "/"
class RaucState(str, Enum):
"""Rauc slot states."""
GOOD = "good"
BAD = "bad"
ACTIVE = "active"
class Rauc(DBusInterface):
"""Handle D-Bus interface for rauc."""
@ -36,7 +36,7 @@ class Rauc(DBusInterface):
async def connect(self):
"""Connect to D-Bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
self.dbus = await DBus.connect(DBUS_NAME_RAUC, DBUS_OBJECT_BASE)
except DBusError:
_LOGGER.warning("Can't connect to rauc")
except DBusInterfaceError:
@ -89,7 +89,7 @@ class Rauc(DBusInterface):
Return a coroutine.
"""
return self.dbus.wait_signal(f"{DBUS_NAME}.Installer.Completed")
return self.dbus.wait_signal(DBUS_NAME_RAUC_INSTALLER_COMPLETED)
@dbus_connected
def mark(self, state: RaucState, slot_identifier: str):
@ -102,13 +102,13 @@ class Rauc(DBusInterface):
@dbus_connected
async def update(self):
"""Update Properties."""
data = await self.dbus.get_properties(f"{DBUS_NAME}.Installer")
data = await self.dbus.get_properties(DBUS_NAME_RAUC_INSTALLER)
if not data:
_LOGGER.warning("Can't get properties for rauc")
return
self._operation = data.get("Operation")
self._last_error = data.get("LastError")
self._compatible = data.get("Compatible")
self._variant = data.get("Variant")
self._boot_slot = data.get("BootSlot")
self._operation = data.get(DBUS_ATTR_OPERATION)
self._last_error = data.get(DBUS_ATTR_LAST_ERROR)
self._compatible = data.get(DBUS_ATTR_COMPATIBLE)
self._variant = data.get(DBUS_ATTR_VARIANT)
self._boot_slot = data.get(DBUS_ATTR_BOOT_SLOT)

View File

@ -3,14 +3,12 @@ import logging
from ..exceptions import DBusError, DBusInterfaceError
from ..utils.gdbus import DBus
from .const import DBUS_NAME_SYSTEMD, DBUS_OBJECT_SYSTEMD
from .interface import DBusInterface
from .utils import dbus_connected
_LOGGER: logging.Logger = logging.getLogger(__name__)
DBUS_NAME = "org.freedesktop.systemd1"
DBUS_OBJECT = "/org/freedesktop/systemd1"
class Systemd(DBusInterface):
"""Systemd function handler."""
@ -18,7 +16,7 @@ class Systemd(DBusInterface):
async def connect(self):
"""Connect to D-Bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
self.dbus = await DBus.connect(DBUS_NAME_SYSTEMD, DBUS_OBJECT_SYSTEMD)
except DBusError:
_LOGGER.warning("Can't connect to systemd")
except DBusInterfaceError:

View File

@ -89,7 +89,7 @@ class HostManager(CoreSysAttributes):
if self.sys_dbus.systemd.is_connected:
await self.services.update()
if self.sys_dbus.nmi_dns.is_connected:
if self.sys_dbus.network.is_connected:
await self.network.update()
with suppress(PulseAudioError):

View File

@ -1,6 +1,8 @@
"""Info control for host."""
import logging
from typing import List
from typing import Dict, List
from supervisor.dbus.network.interface import NetworkInterface
from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import DBusError, DBusNotConnectedError, HostNotSupportedError
@ -15,12 +17,17 @@ class NetworkManager(CoreSysAttributes):
"""Initialize system center handling."""
self.coresys: CoreSys = coresys
@property
def interfaces(self) -> Dict[str, NetworkInterface]:
"""Return a dictionary of active interfaces."""
return self.sys_dbus.network.interfaces
@property
def dns_servers(self) -> List[str]:
"""Return a list of local DNS servers."""
# Read all local dns servers
servers: List[str] = []
for config in self.sys_dbus.nmi_dns.configuration:
for config in self.sys_dbus.network.dns.configuration:
if config.vpn or not config.nameservers:
continue
servers.extend(config.nameservers)
@ -29,11 +36,11 @@ class NetworkManager(CoreSysAttributes):
async def update(self):
"""Update properties over dbus."""
_LOGGER.info("Update local network DNS information")
_LOGGER.info("Update local network information")
try:
await self.sys_dbus.nmi_dns.update()
await self.sys_dbus.network.update()
except DBusError:
_LOGGER.warning("Can't update host DNS system information!")
_LOGGER.warning("Can't update network information!")
except DBusNotConnectedError as err:
_LOGGER.error("No hostname D-Bus connection available")
raise HostNotSupportedError() from err

View File

@ -22,7 +22,7 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
# Use to convert GVariant into json
RE_GVARIANT_TYPE: re.Pattern[Any] = re.compile(
r"\"[^\"\\]*(?:\\.[^\"\\]*)*\"|(boolean|byte|int16|uint16|int32|uint32|handle|int64|uint64|double|"
r"string|objectpath|signature|@[asviumodf\{\}]+) "
r"string|objectpath|signature|@[asviumodfy\{\}\(\)]+) "
)
RE_GVARIANT_VARIANT: re.Pattern[Any] = re.compile(r"\"[^\"\\]*(?:\\.[^\"\\]*)*\"|(<|>)")
RE_GVARIANT_STRING_ESC: re.Pattern[Any] = re.compile(
@ -73,7 +73,7 @@ class DBus:
# pylint: disable=protected-access
await self._init_proxy()
_LOGGER.info("Connect to dbus: %s - %s", bus_name, object_path)
_LOGGER.debug("Connect to dbus: %s - %s", bus_name, object_path)
return self
async def _init_proxy(self) -> None:
@ -167,7 +167,7 @@ class DBus:
)
# Run command
_LOGGER.info("Call %s on %s", method, self.object_path)
_LOGGER.debug("Call %s on %s", method, self.object_path)
data = await self._send(command)
# Parse and return data

60
tests/api/test_network.py Normal file
View File

@ -0,0 +1,60 @@
"""Test NetwrokInterface API."""
import pytest
from tests.const import TEST_INTERFACE
@pytest.mark.asyncio
async def test_api_network_info(api_client):
"""Test network manager api."""
resp = await api_client.get("/network/info")
result = await resp.json()
assert TEST_INTERFACE in result["data"]["interfaces"]
@pytest.mark.asyncio
async def test_api_network_interface_info(api_client):
"""Test network manager api."""
resp = await api_client.get(f"/network/interface/{TEST_INTERFACE}/info")
result = await resp.json()
assert result["data"]["ip_address"] == "192.168.2.148/24"
@pytest.mark.asyncio
async def test_api_network_interface_update(api_client):
"""Test network manager api."""
resp = await api_client.post(
f"/network/interface/{TEST_INTERFACE}/update",
json={"method": "static", "dns": ["1.1.1.1"], "address": "192.168.2.148/24"},
)
result = await resp.json()
assert result["result"] == "ok"
@pytest.mark.asyncio
async def test_api_network_interface_info_invalid(api_client):
"""Test network manager api."""
resp = await api_client.get("/network/interface/invalid/info")
result = await resp.json()
assert not result["data"]
@pytest.mark.asyncio
async def test_api_network_interface_update_invalid(api_client):
"""Test network manager api."""
resp = await api_client.post("/network/interface/invalid/update", json={})
result = await resp.json()
assert result["message"] == "Interface invalid does not exsist"
resp = await api_client.post(f"/network/interface/{TEST_INTERFACE}/update", json={})
result = await resp.json()
assert result["message"] == "You need to supply at least one option to update"
resp = await api_client.post(
f"/network/interface/{TEST_INTERFACE}/update", json={"dns": "1.1.1.1"}
)
result = await resp.json()
assert (
result["message"]
== "expected a list for dictionary value @ data['dns']. Got '1.1.1.1'"
)

View File

@ -3,7 +3,13 @@ import json
from pathlib import Path
def load_json_fixture(filename):
"""Load a fixture."""
def load_json_fixture(filename: str) -> dict:
"""Load a json fixture."""
path = Path(Path(__file__).parent.joinpath("fixtures"), filename)
return json.loads(path.read_text())
def load_fixture(filename: str) -> str:
"""Load a fixture."""
path = Path(Path(__file__).parent.joinpath("fixtures"), filename)
return path.read_text()

View File

@ -2,16 +2,25 @@
from unittest.mock import MagicMock, PropertyMock, patch
from uuid import uuid4
from aiohttp import web
from aiohttp.test_utils import TestClient
import pytest
from supervisor.api import RestAPI
from supervisor.bootstrap import initialize_coresys
from supervisor.coresys import CoreSys
from supervisor.dbus.const import DBUS_NAME_NM, DBUS_OBJECT_BASE
from supervisor.dbus.network import NetworkManager
from supervisor.docker import DockerAPI
from supervisor.utils.gdbus import DBus
from tests.common import load_fixture, load_json_fixture
# pylint: disable=redefined-outer-name, protected-access
@pytest.fixture
def docker():
def docker() -> DockerAPI:
"""Mock DockerAPI."""
images = [MagicMock(tags=["homeassistant/amd64-hassio-supervisor:latest"])]
@ -28,12 +37,52 @@ def docker():
@pytest.fixture
async def coresys(loop, docker):
def dbus() -> DBus:
"""Mock DBUS."""
async def mock_get_properties(_, interface):
return load_json_fixture(f"{interface.replace('.', '_')}.json")
async def mock_send(_, command):
filetype = "xml" if "--xml" in command else "fixture"
fixture = f"{command[6].replace('/', '_')[1:]}.{filetype}"
return load_fixture(fixture)
with patch("supervisor.utils.gdbus.DBus._send", new=mock_send), patch(
"supervisor.dbus.interface.DBusInterface.is_connected", return_value=True,
), patch("supervisor.utils.gdbus.DBus.get_properties", new=mock_get_properties):
dbus_obj = DBus(DBUS_NAME_NM, DBUS_OBJECT_BASE)
yield dbus_obj
@pytest.fixture
async def network_manager(dbus) -> NetworkManager:
"""Mock NetworkManager."""
async def dns_update():
pass
with patch("supervisor.dbus.network.NetworkManager.dns", return_value=MagicMock()):
nm_obj = NetworkManager()
nm_obj.dns.update = dns_update
nm_obj.dbus = dbus
await nm_obj.connect()
await nm_obj.update()
yield nm_obj
@pytest.fixture
async def coresys(loop, docker, dbus, network_manager, aiohttp_client) -> CoreSys:
"""Create a CoreSys Mock."""
with patch("supervisor.bootstrap.initialize_system_data"), patch(
"supervisor.bootstrap.setup_diagnostics"
), patch(
"supervisor.bootstrap.fetch_timezone", return_value="Europe/Zurich",
), patch(
"aiohttp.ClientSession", return_value=TestClient.session,
):
coresys_obj = await initialize_coresys()
@ -42,6 +91,8 @@ async def coresys(loop, docker):
coresys_obj._machine = "qemux86-64"
coresys_obj._machine_id = uuid4()
coresys_obj._dbus = dbus
coresys_obj._dbus.network = network_manager
yield coresys_obj
@ -61,3 +112,12 @@ def sys_supervisor():
) as mock:
mock.return_value = MagicMock()
yield MagicMock
@pytest.fixture
async def api_client(aiohttp_client, coresys):
"""Fixture for RestAPI client."""
api = RestAPI(coresys)
api.webapp = web.Application()
await api.load()
yield await aiohttp_client(api.webapp)

3
tests/const.py Normal file
View File

@ -0,0 +1,3 @@
"""Consts for tests."""
TEST_INTERFACE = "eth0"

View File

@ -0,0 +1,15 @@
"""Test NetwrokInterface."""
import pytest
from supervisor.dbus.network import NetworkManager
from tests.const import TEST_INTERFACE
@pytest.mark.asyncio
async def test_network_interface(network_manager: NetworkManager):
"""Test network interface."""
interface = network_manager.interfaces[TEST_INTERFACE]
assert interface.name == TEST_INTERFACE
assert interface.connection.state == 2
assert interface.connection.uuid == "0c23631e-2118-355c-bbb0-8943229cb0d6"

View File

@ -0,0 +1,12 @@
"""Test NetwrokInterface."""
import pytest
from supervisor.dbus.network import NetworkManager
from tests.const import TEST_INTERFACE
@pytest.mark.asyncio
async def test_network_manager(network_manager: NetworkManager):
"""Test network manager update."""
assert TEST_INTERFACE in network_manager.interfaces

View File

@ -0,0 +1,12 @@
"""Test network utils."""
from supervisor.dbus.network.utils import int2ip, ip2int
def test_int2ip():
"""Test int2ip."""
assert int2ip(16885952) == "192.168.1.1"
def test_ip2int():
"""Test ip2int."""
assert ip2int("192.168.1.1") == 16885952

View File

@ -0,0 +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} {}>}},)

View File

@ -0,0 +1,29 @@
{
"Devices": ["/org/freedesktop/NetworkManager/Devices/1"],
"AllDevices": [
"/org/freedesktop/NetworkManager/Devices/1",
"/org/freedesktop/NetworkManager/Devices/2"
],
"Checkpoints": [],
"NetworkingEnabled": true,
"WirelessEnabled": true,
"WirelessHardwareEnabled": true,
"WwanEnabled": true,
"WwanHardwareEnabled": true,
"WimaxEnabled": false,
"WimaxHardwareEnabled": false,
"ActiveConnections": ["/org/freedesktop/NetworkManager/ActiveConnection/1"],
"PrimaryConnection": "/org/freedesktop/NetworkManager/ActiveConnection/1",
"PrimaryConnectionType": "802-3-ethernet",
"Metered": 4,
"ActivatingConnection": "/",
"Startup": false,
"Version": "1.22.10",
"Capabilities": [1],
"State": 70,
"Connectivity": 4,
"ConnectivityCheckAvailable": true,
"ConnectivityCheckEnabled": true,
"ConnectivityCheckUri": "http://connectivity-check.ubuntu.com/",
"GlobalDnsConfiguration": {}
}

View File

@ -0,0 +1,162 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager">
<method name="Reload">
<arg type="u" name="flags" direction="in"/>
</method>
<method name="GetDevices">
<arg type="ao" name="devices" direction="out"/>
</method>
<method name="GetAllDevices">
<arg type="ao" name="devices" direction="out"/>
</method>
<method name="GetDeviceByIpIface">
<arg type="s" name="iface" direction="in"/>
<arg type="o" name="device" direction="out"/>
</method>
<method name="ActivateConnection">
<arg type="o" name="connection" direction="in"/>
<arg type="o" name="device" direction="in"/>
<arg type="o" name="specific_object" direction="in"/>
<arg type="o" name="active_connection" direction="out"/>
</method>
<method name="AddAndActivateConnection">
<arg type="a{sa{sv}}" name="connection" direction="in"/>
<arg type="o" name="device" direction="in"/>
<arg type="o" name="specific_object" direction="in"/>
<arg type="o" name="path" direction="out"/>
<arg type="o" name="active_connection" direction="out"/>
</method>
<method name="AddAndActivateConnection2">
<arg type="a{sa{sv}}" name="connection" direction="in"/>
<arg type="o" name="device" direction="in"/>
<arg type="o" name="specific_object" direction="in"/>
<arg type="a{sv}" name="options" direction="in"/>
<arg type="o" name="path" direction="out"/>
<arg type="o" name="active_connection" direction="out"/>
<arg type="a{sv}" name="result" direction="out"/>
</method>
<method name="DeactivateConnection">
<arg type="o" name="active_connection" direction="in"/>
</method>
<method name="Sleep">
<arg type="b" name="sleep" direction="in"/>
</method>
<method name="Enable">
<arg type="b" name="enable" direction="in"/>
</method>
<method name="GetPermissions">
<arg type="a{ss}" name="permissions" direction="out"/>
</method>
<method name="SetLogging">
<arg type="s" name="level" direction="in"/>
<arg type="s" name="domains" direction="in"/>
</method>
<method name="GetLogging">
<arg type="s" name="level" direction="out"/>
<arg type="s" name="domains" direction="out"/>
</method>
<method name="CheckConnectivity">
<arg type="u" name="connectivity" direction="out"/>
</method>
<method name="state">
<arg type="u" name="state" direction="out"/>
</method>
<method name="CheckpointCreate">
<arg type="ao" name="devices" direction="in"/>
<arg type="u" name="rollback_timeout" direction="in"/>
<arg type="u" name="flags" direction="in"/>
<arg type="o" name="checkpoint" direction="out"/>
</method>
<method name="CheckpointDestroy">
<arg type="o" name="checkpoint" direction="in"/>
</method>
<method name="CheckpointRollback">
<arg type="o" name="checkpoint" direction="in"/>
<arg type="a{su}" name="result" direction="out"/>
</method>
<method name="CheckpointAdjustRollbackTimeout">
<arg type="o" name="checkpoint" direction="in"/>
<arg type="u" name="add_timeout" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<signal name="CheckPermissions"/>
<signal name="StateChanged">
<arg type="u" name="state"/>
</signal>
<signal name="DeviceAdded">
<arg type="o" name="device_path"/>
</signal>
<signal name="DeviceRemoved">
<arg type="o" name="device_path"/>
</signal>
<property type="ao" name="Devices" access="read"/>
<property type="ao" name="AllDevices" access="read"/>
<property type="ao" name="Checkpoints" access="read"/>
<property type="b" name="NetworkingEnabled" access="read"/>
<property type="b" name="WirelessEnabled" access="readwrite"/>
<property type="b" name="WirelessHardwareEnabled" access="read"/>
<property type="b" name="WwanEnabled" access="readwrite"/>
<property type="b" name="WwanHardwareEnabled" access="read"/>
<property type="b" name="WimaxEnabled" access="readwrite"/>
<property type="b" name="WimaxHardwareEnabled" access="read"/>
<property type="ao" name="ActiveConnections" access="read"/>
<property type="o" name="PrimaryConnection" access="read"/>
<property type="s" name="PrimaryConnectionType" access="read"/>
<property type="u" name="Metered" access="read"/>
<property type="o" name="ActivatingConnection" access="read"/>
<property type="b" name="Startup" access="read"/>
<property type="s" name="Version" access="read"/>
<property type="u" name="Capabilities" access="read"/>
<property type="u" name="State" access="read"/>
<property type="u" name="Connectivity" access="read"/>
<property type="b" name="ConnectivityCheckAvailable" access="read"/>
<property type="b" name="ConnectivityCheckEnabled" access="readwrite"/>
<property type="s" name="ConnectivityCheckUri" access="read"/>
<property type="a{sv}" name="GlobalDnsConfiguration" access="readwrite"/>
</interface>
<node name="IP4Config"/>
<node name="ActiveConnection"/>
<node name="AgentManager"/>
<node name="Devices"/>
<node name="DHCP4Config"/>
<node name="DnsManager"/>
<node name="IP6Config"/>
<node name="Settings"/>
</node>

View File

@ -0,0 +1,62 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager.Connection.Active">
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<signal name="StateChanged">
<arg type="u" name="state"/>
<arg type="u" name="reason"/>
</signal>
<property type="o" name="Connection" access="read"/>
<property type="o" name="SpecificObject" access="read"/>
<property type="s" name="Id" access="read"/>
<property type="s" name="Uuid" access="read"/>
<property type="s" name="Type" access="read"/>
<property type="ao" name="Devices" access="read"/>
<property type="u" name="State" access="read"/>
<property type="u" name="StateFlags" access="read"/>
<property type="b" name="Default" access="read"/>
<property type="o" name="Ip4Config" access="read"/>
<property type="o" name="Dhcp4Config" access="read"/>
<property type="b" name="Default6" access="read"/>
<property type="o" name="Ip6Config" access="read"/>
<property type="o" name="Dhcp6Config" access="read"/>
<property type="b" name="Vpn" access="read"/>
<property type="o" name="Master" access="read"/>
</interface>
</node>

View File

@ -0,0 +1,18 @@
{
"Connection": "/org/freedesktop/NetworkManager/Settings/1",
"SpecificObject": "/",
"Id": "Wired connection 1",
"Uuid": "0c23631e-2118-355c-bbb0-8943229cb0d6",
"Type": "802-3-ethernet",
"Devices": ["/org/freedesktop/NetworkManager/Devices/1"],
"State": 2,
"StateFlags": 12,
"Default": true,
"Ip4Config": "/org/freedesktop/NetworkManager/IP4Config/1",
"Dhcp4Config": "/org/freedesktop/NetworkManager/DHCP4Config/1",
"Default6": false,
"Ip6Config": "/org/freedesktop/NetworkManager/IP6Config/1",
"Dhcp6Config": "/",
"Vpn": false,
"Master": "/"
}

View File

@ -0,0 +1,31 @@
{
"Udi": "/sys/devices/pci0000:00/0000:00:1f.6/net/eth0",
"Interface": "eth0",
"IpInterface": "eth0",
"Driver": "e1000e",
"DriverVersion": "3.2.6-k",
"FirmwareVersion": "0.7-4",
"Capabilities": 3,
"Ip4Address": 2499979456,
"State": 100,
"StateReason": [100, 0],
"ActiveConnection": "/org/freedesktop/NetworkManager/ActiveConnection/1",
"Ip4Config": "/org/freedesktop/NetworkManager/IP4Config/1",
"Dhcp4Config": "/org/freedesktop/NetworkManager/DHCP4Config/1",
"Ip6Config": "/org/freedesktop/NetworkManager/IP6Config/1",
"Dhcp6Config": "/",
"Managed": true,
"Autoconnect": true,
"FirmwareMissing": false,
"NmPluginMissing": false,
"DeviceType": 1,
"AvailableConnections": ["/org/freedesktop/NetworkManager/Settings/1"],
"PhysicalPortId": "",
"Mtu": 1500,
"Metered": 4,
"LldpNeighbors": [],
"Real": true,
"Ip4Connectivity": 4,
"Ip6Connectivity": 3,
"InterfaceFlags": 65539
}

View File

@ -0,0 +1,103 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager.Device.Statistics">
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<property type="u" name="RefreshRateMs" access="readwrite"/>
<property type="t" name="TxBytes" access="read"/>
<property type="t" name="RxBytes" access="read"/>
</interface>
<interface name="org.freedesktop.NetworkManager.Device">
<method name="Reapply">
<arg type="a{sa{sv}}" name="connection" direction="in"/>
<arg type="t" name="version_id" direction="in"/>
<arg type="u" name="flags" direction="in"/>
</method>
<method name="GetAppliedConnection">
<arg type="u" name="flags" direction="in"/>
<arg type="a{sa{sv}}" name="connection" direction="out"/>
<arg type="t" name="version_id" direction="out"/>
</method>
<method name="Disconnect"/>
<method name="Delete"/>
<signal name="StateChanged">
<arg type="u" name="new_state"/>
<arg type="u" name="old_state"/>
<arg type="u" name="reason"/>
</signal>
<property type="s" name="Udi" access="read"/>
<property type="s" name="Interface" access="read"/>
<property type="s" name="IpInterface" access="read"/>
<property type="s" name="Driver" access="read"/>
<property type="s" name="DriverVersion" access="read"/>
<property type="s" name="FirmwareVersion" access="read"/>
<property type="u" name="Capabilities" access="read"/>
<property type="u" name="Ip4Address" access="read"/>
<property type="u" name="State" access="read"/>
<property type="(uu)" name="StateReason" access="read"/>
<property type="o" name="ActiveConnection" access="read"/>
<property type="o" name="Ip4Config" access="read"/>
<property type="o" name="Dhcp4Config" access="read"/>
<property type="o" name="Ip6Config" access="read"/>
<property type="o" name="Dhcp6Config" access="read"/>
<property type="b" name="Managed" access="readwrite"/>
<property type="b" name="Autoconnect" access="readwrite"/>
<property type="b" name="FirmwareMissing" access="read"/>
<property type="b" name="NmPluginMissing" access="read"/>
<property type="u" name="DeviceType" access="read"/>
<property type="ao" name="AvailableConnections" access="read"/>
<property type="s" name="PhysicalPortId" access="read"/>
<property type="u" name="Mtu" access="read"/>
<property type="u" name="Metered" access="read"/>
<property type="aa{sv}" name="LldpNeighbors" access="read"/>
<property type="b" name="Real" access="read"/>
<property type="u" name="Ip4Connectivity" access="read"/>
<property type="u" name="Ip6Connectivity" access="read"/>
<property type="u" name="InterfaceFlags" access="read"/>
</interface>
<interface name="org.freedesktop.NetworkManager.Device.Wired">
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<property type="s" name="HwAddress" access="read"/>
<property type="s" name="PermHwAddress" access="read"/>
<property type="u" name="Speed" access="read"/>
<property type="as" name="S390Subchannels" access="read"/>
<property type="b" name="Carrier" access="read"/>
</interface>
</node>

View File

@ -0,0 +1,42 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager.DnsManager">
<property type="s" name="Mode" access="read"/>
<property type="s" name="RcManager" access="read"/>
<property type="aa{sv}" name="Configuration" access="read"/>
</interface>
</node>

View File

@ -0,0 +1,22 @@
{
"Addresses": [[2499979456, 24, 16951488]],
"AddressData": [{ "address": "192.168.2.148", "prefix": 24 }],
"Gateway": "192.168.2.1",
"Routes": [
[174272, 24, 0, 100],
[65193, 16, 0, 1000]
],
"RouteData": [
{ "dest": "192.168.2.0", "prefix": 24, "metric": 100 },
{ "dest": "169.254.0.0", "prefix": 16, "metric": 1000 },
{ "dest": "0.0.0.0", "prefix": 0, "next-hop": "192.168.2.1", "metric": 100 }
],
"NameserverData": [{ "address": "192.168.2.1" }],
"Nameservers": [16951488],
"Domains": [],
"Searches": [],
"DnsOptions": [],
"DnsPriority": 100,
"WinsServerData": [],
"WinsServers": []
}

View File

@ -0,0 +1,55 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager.IP4Config">
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<property type="aau" name="Addresses" access="read"/>
<property type="aa{sv}" name="AddressData" access="read"/>
<property type="s" name="Gateway" access="read"/>
<property type="aau" name="Routes" access="read"/>
<property type="aa{sv}" name="RouteData" access="read"/>
<property type="aa{sv}" name="NameserverData" access="read"/>
<property type="au" name="Nameservers" access="read"/>
<property type="as" name="Domains" access="read"/>
<property type="as" name="Searches" access="read"/>
<property type="as" name="DnsOptions" access="read"/>
<property type="i" name="DnsPriority" access="read"/>
<property type="as" name="WinsServerData" access="read"/>
<property type="au" name="WinsServers" access="read"/>
</interface>
</node>

View File

@ -0,0 +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} {}>}},)

View File

@ -0,0 +1,69 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.64.3 -->
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg type="s" name="xml_data" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.NetworkManager.Settings.Connection">
<method name="Update">
<arg type="a{sa{sv}}" name="properties" direction="in"/>
</method>
<method name="UpdateUnsaved">
<arg type="a{sa{sv}}" name="properties" direction="in"/>
</method>
<method name="Delete"/>
<method name="GetSettings">
<arg type="a{sa{sv}}" name="settings" direction="out"/>
</method>
<method name="GetSecrets">
<arg type="s" name="setting_name" direction="in"/>
<arg type="a{sa{sv}}" name="secrets" direction="out"/>
</method>
<method name="ClearSecrets"/>
<method name="Save"/>
<method name="Update2">
<arg type="a{sa{sv}}" name="settings" direction="in"/>
<arg type="u" name="flags" direction="in"/>
<arg type="a{sv}" name="args" direction="in"/>
<arg type="a{sv}" name="result" direction="out"/>
</method>
<signal name="PropertiesChanged">
<arg type="a{sv}" name="properties"/>
</signal>
<signal name="Updated"/>
<signal name="Removed"/>
<property type="b" name="Unsaved" access="read"/>
<property type="u" name="Flags" access="read"/>
<property type="s" name="Filename" access="read"/>
</interface>
</node>