mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-11-09 19:09:41 +00:00
Add systemd dbus
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user