mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-12-11 04:12:26 -06:00
201 lines
6.2 KiB
Python
201 lines
6.2 KiB
Python
"""Host function like audio, D-Bus or systemd."""
|
|
|
|
from contextlib import suppress
|
|
from functools import lru_cache
|
|
import logging
|
|
from typing import Self
|
|
|
|
from awesomeversion import AwesomeVersion
|
|
|
|
from ..const import BusEvent
|
|
from ..coresys import CoreSys, CoreSysAttributes
|
|
from ..exceptions import HassioError, HostLogError, HostNvmeError, PulseAudioError
|
|
from ..hardware.const import PolicyGroup
|
|
from ..hardware.data import Device
|
|
from .apparmor import AppArmorControl
|
|
from .const import HostFeature
|
|
from .control import SystemControl
|
|
from .info import InfoCenter
|
|
from .logs import LogsControl
|
|
from .network import NetworkManager
|
|
from .nvme.manager import NvmeManager
|
|
from .services import ServiceManager
|
|
from .sound import SoundControl
|
|
|
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
|
|
|
|
|
class HostManager(CoreSysAttributes):
|
|
"""Manage supported function from host."""
|
|
|
|
def __init__(self, coresys: CoreSys):
|
|
"""Initialize Host manager."""
|
|
self.coresys: CoreSys = coresys
|
|
|
|
self._apparmor: AppArmorControl = AppArmorControl(coresys)
|
|
self._control: SystemControl = SystemControl(coresys)
|
|
self._info: InfoCenter = InfoCenter(coresys)
|
|
self._services: ServiceManager = ServiceManager(coresys)
|
|
self._network: NetworkManager = NetworkManager(coresys)
|
|
self._sound: SoundControl = SoundControl(coresys)
|
|
self._logs: LogsControl = LogsControl(coresys)
|
|
self._nvme: NvmeManager = NvmeManager()
|
|
|
|
async def post_init(self) -> Self:
|
|
"""Post init actions that must occur in event loop."""
|
|
await self._logs.post_init()
|
|
return self
|
|
|
|
@property
|
|
def apparmor(self) -> AppArmorControl:
|
|
"""Return host AppArmor handler."""
|
|
return self._apparmor
|
|
|
|
@property
|
|
def control(self) -> SystemControl:
|
|
"""Return host control handler."""
|
|
return self._control
|
|
|
|
@property
|
|
def info(self) -> InfoCenter:
|
|
"""Return host info handler."""
|
|
return self._info
|
|
|
|
@property
|
|
def services(self) -> ServiceManager:
|
|
"""Return host services handler."""
|
|
return self._services
|
|
|
|
@property
|
|
def network(self) -> NetworkManager:
|
|
"""Return host NetworkManager handler."""
|
|
return self._network
|
|
|
|
@property
|
|
def sound(self) -> SoundControl:
|
|
"""Return host PulseAudio control."""
|
|
return self._sound
|
|
|
|
@property
|
|
def logs(self) -> LogsControl:
|
|
"""Return host logs handler."""
|
|
return self._logs
|
|
|
|
@property
|
|
def nvme(self) -> NvmeManager:
|
|
"""Return NVME device manager."""
|
|
return self._nvme
|
|
|
|
@property
|
|
def features(self) -> list[HostFeature]:
|
|
"""Return a list of host features."""
|
|
return self.supported_features()
|
|
|
|
@lru_cache(maxsize=128)
|
|
def supported_features(self) -> list[HostFeature]:
|
|
"""Return a list of supported host features."""
|
|
features = []
|
|
|
|
if self.sys_dbus.systemd.is_connected:
|
|
features.extend(
|
|
[HostFeature.REBOOT, HostFeature.SHUTDOWN, HostFeature.SERVICES]
|
|
)
|
|
|
|
if self.sys_dbus.network.is_connected and self.sys_dbus.network.interfaces:
|
|
features.append(HostFeature.NETWORK)
|
|
|
|
if self.sys_dbus.hostname.is_connected:
|
|
features.append(HostFeature.HOSTNAME)
|
|
|
|
if self.sys_dbus.timedate.is_connected:
|
|
features.append(HostFeature.TIMEDATE)
|
|
|
|
if self.sys_dbus.agent.is_connected:
|
|
features.append(HostFeature.OS_AGENT)
|
|
|
|
if self.sys_os.available:
|
|
features.append(HostFeature.HAOS)
|
|
|
|
if self.sys_dbus.resolved.is_connected:
|
|
features.append(HostFeature.RESOLVED)
|
|
|
|
if self.logs.available:
|
|
features.append(HostFeature.JOURNAL)
|
|
|
|
if self.sys_dbus.udisks2.is_connected:
|
|
features.append(HostFeature.DISK)
|
|
|
|
if self.nvme.devices:
|
|
features.append(HostFeature.NVME)
|
|
|
|
# Support added in OS10. Propagation mode changed on mount in 10.2 to support this
|
|
if (
|
|
self.sys_dbus.systemd.is_connected
|
|
and self.sys_supervisor.instance.host_mounts_available
|
|
and (
|
|
not self.sys_os.available
|
|
or self.sys_os.version >= AwesomeVersion("10.2")
|
|
)
|
|
):
|
|
features.append(HostFeature.MOUNT)
|
|
|
|
return features
|
|
|
|
async def reload(self):
|
|
"""Reload host functions."""
|
|
await self.info.update()
|
|
await self.sys_os.reload()
|
|
|
|
if self.sys_dbus.systemd.is_connected:
|
|
await self.services.update()
|
|
|
|
if self.sys_dbus.network.is_connected:
|
|
await self.network.update()
|
|
|
|
if self.sys_dbus.agent.is_connected:
|
|
await self.sys_dbus.agent.update()
|
|
|
|
if self.sys_dbus.udisks2.is_connected:
|
|
await self.sys_dbus.udisks2.update()
|
|
|
|
with suppress(PulseAudioError):
|
|
await self.sound.update()
|
|
|
|
with suppress(HostNvmeError):
|
|
await self.nvme.update()
|
|
|
|
_LOGGER.info("Host information reload completed")
|
|
self.supported_features.cache_clear() # pylint: disable=no-member
|
|
|
|
async def load(self):
|
|
"""Load host information."""
|
|
with suppress(HassioError):
|
|
if self.sys_dbus.systemd.is_connected:
|
|
await self.services.update()
|
|
|
|
with suppress(PulseAudioError):
|
|
await self.sound.update()
|
|
|
|
with suppress(HostLogError):
|
|
await self.logs.load()
|
|
|
|
await self.network.load()
|
|
await self.nvme.load()
|
|
|
|
# Register for events
|
|
self.sys_bus.register_event(BusEvent.HARDWARE_NEW_DEVICE, self._hardware_events)
|
|
self.sys_bus.register_event(
|
|
BusEvent.HARDWARE_REMOVE_DEVICE, self._hardware_events
|
|
)
|
|
|
|
# Load profile data
|
|
try:
|
|
await self.apparmor.load()
|
|
except HassioError as err:
|
|
_LOGGER.warning("Loading host AppArmor on start failed: %s", err)
|
|
|
|
async def _hardware_events(self, device: Device) -> None:
|
|
"""Process hardware requests."""
|
|
if self.sys_hardware.policy.is_match_cgroup(PolicyGroup.AUDIO, device):
|
|
await self.sound.update(reload_pulse=True)
|