Add systemd dbus

This commit is contained in:
Pascal Vizeli
2018-04-21 23:56:36 +02:00
parent 28f295a1e2
commit 69142b6fb0
3 changed files with 45 additions and 39 deletions

View File

@@ -11,6 +11,7 @@ from voluptuous.humanize import humanize_error
from ..const import (
JSON_RESULT, JSON_DATA, JSON_MESSAGE, RESULT_OK, RESULT_ERROR,
CONTENT_TYPE_BINARY)
from ..exceptions import HassioError
_LOGGER = logging.getLogger(__name__)
@@ -33,6 +34,8 @@ def api_process(method):
answer = await method(api, *args, **kwargs)
except RuntimeError as err:
return api_return_error(message=str(err))
except HassioError:
return api_return_error()
if isinstance(answer, dict):
return api_return_ok(data=answer)
@@ -45,30 +48,6 @@ def api_process(method):
return wrap_api
def api_process_hostcontrol(method):
"""Wrap HostControl calls to rest api."""
async def wrap_hostcontrol(api, *args, **kwargs):
"""Return host information."""
# pylint: disable=protected-access
if not api._host_control.active:
raise HTTPServiceUnavailable()
try:
answer = await method(api, *args, **kwargs)
except RuntimeError as err:
return api_return_error(message=str(err))
if isinstance(answer, dict):
return api_return_ok(data=answer)
elif answer is None:
return api_return_error("Function is not supported")
elif answer:
return api_return_ok()
return api_return_error()
return wrap_hostcontrol
def api_process_raw(content):
"""Wrap content_type into function."""
def wrap_method(method):
@@ -81,6 +60,9 @@ def api_process_raw(content):
except RuntimeError as err:
msg_data = str(err).encode()
msg_type = CONTENT_TYPE_BINARY
except HassioError:
msg_data = b''
msg_type = CONTENT_TYPE_BINARY
return web.Response(body=msg_data, content_type=msg_type)

View File

@@ -1,5 +1,5 @@
"""Interface to Systemd over dbus."""
from logging
import logging
from ..exceptions import HassioInternalError
from ..utils.gdbus import DBus, DBusError
@@ -7,7 +7,7 @@ from ..utils.gdbus import DBus, DBusError
_LOGGER = logging.getLogger(__name__)
DBUS_NAME = 'org.freedesktop.systemd1'
DBUS_OBJECT = '/org/freedesktop/systemd1/Manager'
DBUS_OBJECT = '/org/freedesktop/systemd1'
class Systemd(object):
@@ -17,18 +17,22 @@ class Systemd(object):
"""Initialize systemd."""
self.dbus = None
async def load(self):
@property
def is_connected(self):
"""Return True, if they is connected to dbus."""
return self.dbus is not None
async def connect(self):
"""Connect do bus."""
try:
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
except DBusError:
_LOGGER.warning("Can't connect to systemd")
return
async def reboot(self):
"""Reboot host computer."""
try:
await self.dbus.Reboot()
await self.dbus.Manager.Reboot()
except DBusError:
_LOGGER.error("Can't reboot host")
raise HassioInternalError() from None
@@ -36,7 +40,7 @@ class Systemd(object):
async def shutdown(self):
"""Shutdown host computer."""
try:
await self.dbus.PowerOff()
await self.dbus.Manager.PowerOff()
except DBusError:
_LOGGER.error("Can't PowerOff host")
raise HassioInternalError() from None

View File

@@ -8,8 +8,8 @@ _LOGGER = logging.getLogger(__name__)
INTROSPECT = ("gdbus introspect --system --dest {bus} "
"--object-path {obj} --xml")
CALL = ("gdbus call --system --dest {bus} --object-path {obj} "
"--method {obj}.{method} {args}")
CALL = ("gdbus call --system --dest {bus} --object-path {inf} "
"--method {inf}.{method} {args}")
class DBusError(Exception):
@@ -39,7 +39,7 @@ class DBus(object):
"""Initialize dbus object."""
self.bus_name = bus_name
self.object_path = object_path
self.methods = []
self.data = {}
@staticmethod
async def connect(bus_name, object_path):
@@ -73,19 +73,22 @@ class DBus(object):
raise DBusParseError() from None
# Read available methods
for method in xml.findall(".//method"):
self.methods.append(method.get('name'))
for interface in xml.findall("/node/interface"):
methods = []
for method in interface.findall("/method"):
methods.append(method.get('name'))
self.data[interface.get('name')] = methods
@staticmethod
def _gvariant(raw):
"""Parse GVariant input to python."""
return raw
async def _call_dbus(self, method, *args):
async def call_dbus(self, interface, method, *args):
"""Call a dbus method."""
command = shlex.split(CALL.format(
bus=self.bus_name,
obj=self.object_path,
inf=interface,
method=method,
args=" ".join(map(str, args))
))
@@ -124,9 +127,26 @@ class DBus(object):
# End
return data.decode()
def __getattr__(self, interface):
"""Mapping to dbus method."""
interface = f"{self.object_path}.{interface}"
if interface not in self.data:
raise AttributeError()
return DBusCallWrapper(self, interface)
class DBusCallWrapper(object):
"""Wrapper a DBus interface for a call."""
def __init__(self, dbus, interface):
"""Initialize wrapper."""
self.dbus = dbus
self.interface = interface
def __getattr__(self, name):
"""Mapping to dbus method."""
if name not in self.methods:
if name not in self.dbus.data[self.interface]:
raise AttributeError()
def _method_wrapper(*args):
@@ -134,6 +154,6 @@ class DBus(object):
Return a coroutine
"""
return self._call_dbus(name, *args)
return self.dbus.call_dbus(self.interface, self.name, *args)
return _method_wrapper