summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Devaev <[email protected]>2022-04-23 18:28:13 +0300
committerMaxim Devaev <[email protected]>2022-04-23 18:28:13 +0300
commitd83e32fc514d1c60ef4e389493a3e4b953061bd4 (patch)
tree4983094a8ec1a907be4ddd9a5bfea85e7d7ca76b
parente566364b75a140e0eed97f0feff8aa6eeaf2a786 (diff)
using dbus_next
-rw-r--r--PKGBUILD1
-rw-r--r--kvmd/apps/kvmd/info/extras.py66
-rw-r--r--kvmd/apps/kvmd/info/fan.py12
-rw-r--r--kvmd/apps/kvmd/sysunit.py93
-rw-r--r--testenv/Dockerfile1
5 files changed, 121 insertions, 52 deletions
diff --git a/PKGBUILD b/PKGBUILD
index d90ea10d..c9fd53cd 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -50,6 +50,7 @@ depends=(
python-netifaces
python-systemd
python-dbus
+ python-dbus-next
python-pygments
python-pyghmi
python-pam
diff --git a/kvmd/apps/kvmd/info/extras.py b/kvmd/apps/kvmd/info/extras.py
index 35265a82..37bf3ff7 100644
--- a/kvmd/apps/kvmd/info/extras.py
+++ b/kvmd/apps/kvmd/info/extras.py
@@ -22,6 +22,7 @@
import os
import re
+import asyncio
from typing import Dict
from typing import Optional
@@ -31,9 +32,10 @@ from ....logging import get_logger
from ....yamlconf import Section
from ....yamlconf.loader import load_yaml_file
+from .... import tools
from .... import aiotools
-from ..sysunit import get_service_status
+from .. import sysunit
from .base import BaseInfoSubmanager
@@ -44,37 +46,57 @@ class ExtrasInfoSubmanager(BaseInfoSubmanager):
self.__global_config = global_config
async def get_state(self) -> Optional[Dict]:
- return (await aiotools.run_async(self.__inner_get_state))
-
- # =====
-
- def __inner_get_state(self) -> Optional[Dict]:
try:
- extras_path = self.__global_config.kvmd.info.extras
+ sui = sysunit.SystemdUnitInfo()
+ await sui.open()
+ except Exception as err:
+ get_logger(0).error("Can't open systemd bus to get extras state: %s", tools.efmt(err))
+ sui = None
+ try:
extras: Dict[str, Dict] = {}
- for name in os.listdir(extras_path):
- if name[0] != "." and os.path.isdir(os.path.join(extras_path, name)):
- app = re.sub(r"[^a-zA-Z0-9_]+", "_", name)
- extras[app] = load_yaml_file(os.path.join(extras_path, name, "manifest.yaml"))
- self.__rewrite_app_daemon(extras[app])
- self.__rewrite_app_port(extras[app])
+ for extra in (await asyncio.gather(*[
+ self.__read_extra(sui, name)
+ for name in os.listdir(self.__get_extras_path())
+ if name[0] != "." and os.path.isdir(self.__get_extras_path(name))
+ ])):
+ extras.update(extra)
return extras
except Exception:
- get_logger(0).exception("Can't parse extras")
+ get_logger(0).exception("Can't read extras")
return None
+ finally:
+ if sui is not None:
+ await sui.close()
+
+ def __get_extras_path(self, *parts: str) -> str:
+ return os.path.join(self.__global_config.kvmd.info.extras, *parts)
+
+ async def __read_extra(self, sui: Optional[sysunit.SystemdUnitInfo], name: str) -> Dict:
+ try:
+ extra = await aiotools.run_async(load_yaml_file, self.__get_extras_path(name, "manifest.yaml"))
+ await self.__rewrite_app_daemon(sui, extra)
+ self.__rewrite_app_port(extra)
+ return {re.sub(r"[^a-zA-Z0-9_]+", "_", name): extra}
+ except Exception:
+ get_logger(0).exception("Can't read extra %r", name)
+ return {}
- def __rewrite_app_daemon(self, extras: Dict) -> None:
- daemon = extras.get("daemon", "")
+ async def __rewrite_app_daemon(self, sui: Optional[sysunit.SystemdUnitInfo], extra: Dict) -> None:
+ daemon = extra.get("daemon", "")
if isinstance(daemon, str) and daemon.strip():
- status = get_service_status(daemon)
- (extras["enabled"], extras["started"]) = (status if status is not None else (False, False))
+ extra["enabled"] = extra["started"] = False
+ if sui is not None:
+ try:
+ (extra["enabled"], extra["started"]) = await sui.get_status(daemon)
+ except Exception as err:
+ get_logger(0).error("Can't get info about the service %r: %s", daemon, tools.efmt(err))
- def __rewrite_app_port(self, extras: Dict) -> None:
- port_path = extras.get("port", "")
+ def __rewrite_app_port(self, extra: Dict) -> None:
+ port_path = extra.get("port", "")
if isinstance(port_path, str) and port_path.strip():
- extras["port"] = 0
+ extra["port"] = 0
config = self.__global_config
for item in filter(None, map(str.strip, port_path.split("/"))):
config = getattr(config, item, None) # type: ignore
if isinstance(config, int):
- extras["port"] = config
+ extra["port"] = config
diff --git a/kvmd/apps/kvmd/info/fan.py b/kvmd/apps/kvmd/info/fan.py
index 1e323d04..afa7afce 100644
--- a/kvmd/apps/kvmd/info/fan.py
+++ b/kvmd/apps/kvmd/info/fan.py
@@ -31,10 +31,11 @@ import aiohttp
from ....logging import get_logger
+from .... import tools
from .... import aiotools
from .... import htclient
-from ..sysunit import get_service_status
+from .. import sysunit
from .base import BaseInfoSubmanager
@@ -84,9 +85,12 @@ class FanInfoSubmanager(BaseInfoSubmanager):
async def __get_monitored(self) -> bool:
if self.__unix_path:
- status = await aiotools.run_async(get_service_status, self.__daemon)
- if status is not None:
- return (status[0] or status[1])
+ try:
+ async with sysunit.SystemdUnitInfo() as sui:
+ status = await sui.get_status(self.__daemon)
+ return (status[0] or status[1])
+ except Exception as err:
+ get_logger(0).error("Can't get info about the service %r: %s", self.__daemon, tools.efmt(err))
return False
async def __get_fan_state(self) -> Optional[Dict]:
diff --git a/kvmd/apps/kvmd/sysunit.py b/kvmd/apps/kvmd/sysunit.py
index afd04705..dea5e961 100644
--- a/kvmd/apps/kvmd/sysunit.py
+++ b/kvmd/apps/kvmd/sysunit.py
@@ -20,37 +20,78 @@
# ========================================================================== #
-import contextlib
+import types
from typing import Tuple
+from typing import Type
from typing import Optional
-import dbus # pylint: disable=import-error
-import dbus.exceptions
+import dbus_next
+import dbus_next.aio
+import dbus_next.aio.proxy_object
+import dbus_next.introspection
+import dbus_next.errors
-from ...logging import get_logger
-from ... import tools
+# =====
+class SystemdUnitInfo:
+ def __init__(self) -> None:
+ self.__bus: Optional[dbus_next.aio.MessageBus] = None
+ self.__intr: Optional[dbus_next.introspection.Node] = None
+ self.__manager: Optional[dbus_next.aio.proxy_object.ProxyInterface] = None
+ async def get_status(self, name: str) -> Tuple[bool, bool]:
+ assert self.__bus is not None
+ assert self.__intr is not None
+ assert self.__manager is not None
-# =====
-def get_service_status(name: str) -> Optional[Tuple[bool, bool]]:
- if not name.endswith(".service"):
- name += ".service"
- try:
- with contextlib.closing(dbus.SystemBus()) as bus:
- systemd = bus.get_object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") # pylint: disable=no-member
- manager = dbus.Interface(systemd, dbus_interface="org.freedesktop.systemd1.Manager")
- try:
- unit_proxy = bus.get_object("org.freedesktop.systemd1", manager.GetUnit(name)) # pylint: disable=no-member
- unit_properties = dbus.Interface(unit_proxy, dbus_interface="org.freedesktop.DBus.Properties")
- started = (unit_properties.Get("org.freedesktop.systemd1.Unit", "ActiveState") == "active")
- except dbus.exceptions.DBusException as err:
- if "NoSuchUnit" not in str(err):
- raise
- started = False
- enabled = (manager.GetUnitFileState(name) in ["enabled", "enabled-runtime", "static", "indirect", "generated"])
- return (enabled, started)
- except Exception as err:
- get_logger(0).error("Can't get info about the service %r: %s", name, tools.efmt(err))
- return None
+ if not name.endswith(".service"):
+ name += ".service"
+
+ try:
+ unit_p = await self.__manager.call_get_unit(name) # type: ignore
+ unit = self.__bus.get_proxy_object("org.freedesktop.systemd1", unit_p, self.__intr)
+ unit_props = unit.get_interface("org.freedesktop.DBus.Properties")
+ started = ((await unit_props.call_get("org.freedesktop.systemd1.Unit", "ActiveState")).value == "active") # type: ignore
+ except dbus_next.errors.DBusError as err:
+ if err.type != "org.freedesktop.systemd1.NoSuchUnit":
+ raise
+ started = False
+ enabled = ((await self.__manager.call_get_unit_file_state(name)) in [ # type: ignore
+ "enabled",
+ "enabled-runtime",
+ "static",
+ "indirect",
+ "generated",
+ ])
+ return (enabled, started)
+
+ async def open(self) -> None:
+ self.__bus = await dbus_next.aio.MessageBus(bus_type=dbus_next.BusType.SYSTEM).connect()
+ self.__intr = await self.__bus.introspect("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
+ systemd = self.__bus.get_proxy_object("org.freedesktop.systemd1", "/org/freedesktop/systemd1", self.__intr)
+ self.__manager = systemd.get_interface("org.freedesktop.systemd1.Manager")
+
+ async def __aenter__(self) -> "SystemdUnitInfo":
+ await self.open()
+ return self
+
+ async def close(self) -> None:
+ try:
+ if self.__bus is not None:
+ self.__bus.disconnect()
+ await self.__bus.wait_for_disconnect()
+ except Exception:
+ pass
+ self.__manager = None
+ self.__intr = None
+ self.__bus = None
+
+ async def __aexit__(
+ self,
+ _exc_type: Type[BaseException],
+ _exc: BaseException,
+ _tb: types.TracebackType,
+ ) -> None:
+
+ await self.close()
diff --git a/testenv/Dockerfile b/testenv/Dockerfile
index 44c975f3..d8122fae 100644
--- a/testenv/Dockerfile
+++ b/testenv/Dockerfile
@@ -45,6 +45,7 @@ RUN pacman --noconfirm --ask=4 -Syy \
python-netifaces \
python-systemd \
python-dbus \
+ python-dbus-next \
python-pygments \
python-pam \
python-pillow \