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):
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
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:
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(
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)
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"
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"
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"
[metadata]
lock-version = "1.1"
python-versions = "^3.6.12"
-content-hash = "90a3b2334875dcde45ebbb46bff45b04e689ef28d37bdc560056e4fe365fde0c"
+content-hash = "f88e69a2748e50bd111eeda6d8e56c7cdbcea2f419830a697a54e5e8502a1403"
[metadata.files]
aiohttp = [
{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"},
{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"},
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"