]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
systemd integration using pydbus
authorVasek Sraier <git@vakabus.cz>
Wed, 24 Feb 2021 22:00:49 +0000 (23:00 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 8 Apr 2022 14:17:51 +0000 (16:17 +0200)
manager/knot_resolver_manager/kresd_manager.py
manager/knot_resolver_manager/systemd.py
manager/poetry.lock
manager/pyproject.toml

index 59a83db7f90d019b1d29e2142ca2725979a16288..85acaa7b9c8bf6f041cd271d6a6c86a2d6ddd29e 100644 (file)
@@ -3,6 +3,9 @@ from uuid import uuid4
 from typing import List, Optional
 from strictyaml.representation import YAML
 
+from . import compat
+from . import systemd
+
 
 class Kresd:
     def __init__(self, kresd_id: Optional[str] = None):
@@ -16,13 +19,15 @@ class Kresd:
         raise NotImplementedError()
 
     async def start(self):
-        raise NotImplementedError()
+        await compat.asyncio_to_thread(systemd.start_unit, f"kresd@{self._id}.service")
 
     async def stop(self):
-        raise NotImplementedError()
+        await compat.asyncio_to_thread(systemd.stop_unit, f"kresd@{self._id}.service")
 
     async def restart(self):
-        raise NotImplementedError()
+        await compat.asyncio_to_thread(
+            systemd.restart_unit, f"kresd@{self._id}.service"
+        )
 
     def mark_for_restart(self):
         self._needs_restart = True
@@ -50,7 +55,12 @@ class KresdManager:
         await kresd.stop()
 
     async def _collect_already_running_children(self):
-        raise NotImplementedError()
+        units = await compat.asyncio_to_thread(systemd.list_units)
+        for unit in units:
+            u: str = unit
+            if u.startswith("kresd@") and u.endswith(".service"):
+                iden = u.replace("kresd@", "").replace(".service", "")
+                self._children.append(Kresd(kresd_id=iden))
 
     async def _rolling_restart(self):
         for kresd in self._children:
index 3e0b19cb3816fcd0d5325dd9e1ba3fa5fe68d6d7..e62c01f309cc4e1b7963edcb3b1e3713f4bbffef 100644 (file)
@@ -1,15 +1,51 @@
 from typing import List, Union
-import dbus
 from typing_extensions import Literal
 
+from pydbus import SystemBus
+from gi.repository import GLib
+
+# ugly global result variable, but this module will be used once in a every
+# process, so we should get away with it
+#
+# Used to storing result state of systemd's jobs
+result_state = None
+
+
+class SystemdException(Exception):
+    pass
+
 
 def _create_manager_interface():
-    bus = dbus.SystemBus()
-    systemd = bus.get_object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
+    bus = SystemBus()
+    systemd = bus.get(".systemd1")
+    return systemd
+
+
+def _wait_for_job_completion(systemd, job):
+    global result_state
+
+    loop = GLib.MainLoop()
+    systemd.JobRemoved.connect(_wait_for_job_completion_handler(loop, job))
+    result_state = None
+    loop.run()
+
+    if result_state != "done":
+        raise SystemdException(
+            f"Job completed with state '{result_state}' instead of expected 'done'"
+        )
+
 
-    manager = dbus.Interface(systemd, "org.freedesktop.systemd1.Manager")
+def _wait_for_job_completion_handler(loop, job_path):
+    def event_hander(_job_id, path, _unit, state):
+        global result_state
 
-    return manager
+        # if the job is no longer queued, stop the loop
+        if path == job_path:
+            result_state = state
+            loop.quit()
+        # otherwise do nothing
+
+    return event_hander
 
 
 def get_unit_file_state(
@@ -24,9 +60,22 @@ def list_units() -> List[str]:
     return [str(u[0]) for u in _create_manager_interface().ListUnits()]
 
 
-def list_jobs():
-    return _create_manager_interface().ListJobs()
+def restart_unit(unit_name: str):
+    systemd = _create_manager_interface()
+    job = systemd.RestartUnit(unit_name, "fail")
+
+    _wait_for_job_completion(systemd, job)
 
 
-def restart_unit(unit_name: str):
-    return _create_manager_interface().RestartUnit(unit_name, "fail")
+def start_unit(unit_name: str):
+    systemd = _create_manager_interface()
+    job = systemd.StartUnit(unit_name, "fail")
+
+    _wait_for_job_completion(systemd, job)
+
+
+def stop_unit(unit_name: str):
+    systemd = _create_manager_interface()
+    job = systemd.StopUnit(unit_name, "fail")
+
+    _wait_for_job_completion(systemd, job)
index 608aae901c9f6a3b9e8663e30d65d37c11f79879..5e3e2a910f687fa1a74c85e99fc92e007879fd22 100644 (file)
@@ -457,6 +457,14 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
+[[package]]
+name = "pycairo"
+version = "1.20.0"
+description = "Python interface for cairo"
+category = "main"
+optional = false
+python-versions = ">=3.6, <4"
+
 [[package]]
 name = "pycodestyle"
 version = "2.6.0"
@@ -465,6 +473,14 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
+[[package]]
+name = "pydbus"
+version = "0.6.0"
+description = "Pythonic DBus library"
+category = "main"
+optional = false
+python-versions = "*"
+
 [[package]]
 name = "pydocstyle"
 version = "5.1.1"
@@ -484,6 +500,17 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
+[[package]]
+name = "pygobject"
+version = "3.38.0"
+description = "Python bindings for GObject Introspection"
+category = "main"
+optional = false
+python-versions = ">=3.5, <4"
+
+[package.dependencies]
+pycairo = ">=1.11.1"
+
 [[package]]
 name = "pylint"
 version = "2.5.3"
@@ -846,7 +873,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.6.12"
-content-hash = "90a3b2334875dcde45ebbb46bff45b04e689ef28d37bdc560056e4fe365fde0c"
+content-hash = "f88e69a2748e50bd111eeda6d8e56c7cdbcea2f419830a697a54e5e8502a1403"
 
 [metadata.files]
 aiohttp = [
@@ -1162,10 +1189,25 @@ py = [
     {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
     {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
 ]
+pycairo = [
+    {file = "pycairo-1.20.0-cp36-cp36m-win32.whl", hash = "sha256:e5a3433690c473e073a9917dc8f1fc7dc8b9af7b201bf372894b8ad70d960c6d"},
+    {file = "pycairo-1.20.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a942614923b88ae75c794506d5c426fba9c46a055d3fdd3b8db7046b75c079cc"},
+    {file = "pycairo-1.20.0-cp37-cp37m-win32.whl", hash = "sha256:8cfa9578b745fb9cf2915ec580c2c50ebc2da00eac2cf4c4b54b63aa19da4b77"},
+    {file = "pycairo-1.20.0-cp37-cp37m-win_amd64.whl", hash = "sha256:273a33c56aba724ec42fe1d8f94c86c2e2660c1277470be9b04e5113d7c5b72d"},
+    {file = "pycairo-1.20.0-cp38-cp38-win32.whl", hash = "sha256:2088100a099c09c5e90bf247409ce6c98f51766b53bd13f96d6aac7addaa3e66"},
+    {file = "pycairo-1.20.0-cp38-cp38-win_amd64.whl", hash = "sha256:ceb1edcbeb48dabd5fbbdff2e4b429aa88ddc493d6ebafe78d94b050ac0749e2"},
+    {file = "pycairo-1.20.0-cp39-cp39-win32.whl", hash = "sha256:57a768f4edc8a9890d98070dd473a812ac3d046cef4bc1c817d68024dab9a9b4"},
+    {file = "pycairo-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:57166119e424d71eccdba6b318bd731bdabd17188e2ba10d4f315f7bf16ace3f"},
+    {file = "pycairo-1.20.0.tar.gz", hash = "sha256:5695a10cb7f9ae0d01f665b56602a845b0a8cb17e2123bfece10c2e58552468c"},
+]
 pycodestyle = [
     {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
     {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
 ]
+pydbus = [
+    {file = "pydbus-0.6.0-py2.py3-none-any.whl", hash = "sha256:66b80106352a718d80d6c681dc2a82588048e30b75aab933e4020eb0660bf85e"},
+    {file = "pydbus-0.6.0.tar.gz", hash = "sha256:4207162eff54223822c185da06c1ba8a34137a9602f3da5a528eedf3f78d0f2c"},
+]
 pydocstyle = [
     {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"},
     {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"},
@@ -1174,6 +1216,9 @@ pyflakes = [
     {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
     {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
 ]
+pygobject = [
+    {file = "PyGObject-3.38.0.tar.gz", hash = "sha256:051b950f509f2e9f125add96c1493bde987c527f7a0c15a1f7b69d6d1c3cd8e6"},
+]
 pylint = [
     {file = "pylint-2.5.3-py3-none-any.whl", hash = "sha256:d0ece7d223fe422088b0e8f13fa0a1e8eb745ebffcb8ed53d3e95394b6101a1c"},
     {file = "pylint-2.5.3.tar.gz", hash = "sha256:7dd78437f2d8d019717dbf287772d0b2dbdfd13fc016aa7faa08d67bccc46adc"},
index c5452773f5c2e46531fd1ed06e89203b5c143304..7841f3821270820e6a879c73acf96014426f5cb3 100644 (file)
@@ -10,6 +10,8 @@ authors = [
 python = "^3.6.12"
 aiohttp = "^3.6.12"
 strictyaml = "^1.3.2"
+pydbus = "^0.6.0"
+PyGObject = "^3.38.0"
 
 [tool.poetry.dev-dependencies]
 pytest = "^5.2"