mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-09-08 04:36:21 +00:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c8cb8aecf7 | ||
![]() |
73e8875018 | ||
![]() |
02aed9c084 | ||
![]() |
89148f8fff | ||
![]() |
6bde527f5c | ||
![]() |
d62aabc01b | ||
![]() |
82299a3799 | ||
![]() |
c02f30dd7e | ||
![]() |
e91983adb4 | ||
![]() |
ff88359429 | ||
![]() |
5a60d5cbe8 | ||
![]() |
2b41ffe019 | ||
![]() |
1c23e26f93 | ||
![]() |
3d555f951d | ||
![]() |
6d39b4d7cd | ||
![]() |
4fe5d09f01 |
@@ -8,7 +8,7 @@ cryptography==2.8
|
||||
docker==4.2.0
|
||||
gitpython==3.1.0
|
||||
jinja2==2.11.1
|
||||
packaging==20.1
|
||||
packaging==20.3
|
||||
ptvsd==4.3.2
|
||||
pulsectl==20.2.4
|
||||
pytz==2019.3
|
||||
|
@@ -30,8 +30,7 @@ if __name__ == "__main__":
|
||||
loop = initialize_event_loop()
|
||||
|
||||
# Check if all information are available to setup Supervisor
|
||||
if not bootstrap.check_environment():
|
||||
sys.exit(1)
|
||||
bootstrap.check_environment()
|
||||
|
||||
# init executor pool
|
||||
executor = ThreadPoolExecutor(thread_name_prefix="SyncWorker")
|
||||
|
@@ -393,6 +393,11 @@ class Addon(AddonModel):
|
||||
input_profile=self.audio_input, output_profile=self.audio_output
|
||||
)
|
||||
|
||||
# Cleanup wrong maps
|
||||
if self.path_pulse.is_dir():
|
||||
shutil.rmtree(self.path_pulse, ignore_errors=True)
|
||||
|
||||
# Write pulse config
|
||||
try:
|
||||
with self.path_pulse.open("w") as config_file:
|
||||
config_file.write(pulse_config)
|
||||
@@ -400,11 +405,10 @@ class Addon(AddonModel):
|
||||
_LOGGER.error(
|
||||
"Add-on %s can't write pulse/client.config: %s", self.slug, err
|
||||
)
|
||||
raise AddonsError()
|
||||
|
||||
_LOGGER.debug(
|
||||
"Add-on %s write pulse/client.config: %s", self.slug, self.path_pulse
|
||||
)
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Add-on %s write pulse/client.config: %s", self.slug, self.path_pulse
|
||||
)
|
||||
|
||||
async def install_apparmor(self) -> None:
|
||||
"""Install or Update AppArmor profile for Add-on."""
|
||||
|
@@ -163,7 +163,7 @@ class APIAudio(CoreSysAttributes):
|
||||
@api_process
|
||||
async def set_profile(self, request: web.Request) -> None:
|
||||
"""Set audio default sources."""
|
||||
body = await api_validate(SCHEMA_DEFAULT, request)
|
||||
body = await api_validate(SCHEMA_PROFILE, request)
|
||||
|
||||
await asyncio.shield(
|
||||
self.sys_host.sound.set_profile(body[ATTR_CARD], body[ATTR_NAME])
|
||||
|
@@ -188,13 +188,6 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
"""
|
||||
return self.instance.is_running()
|
||||
|
||||
def is_fails(self) -> Awaitable[bool]:
|
||||
"""Return True if a Docker container is fails state.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.instance.is_fails()
|
||||
|
||||
async def repair(self) -> None:
|
||||
"""Repair CoreDNS plugin."""
|
||||
if await self.instance.exists():
|
||||
|
@@ -197,7 +197,7 @@ def initialize_logging():
|
||||
)
|
||||
|
||||
|
||||
def check_environment():
|
||||
def check_environment() -> None:
|
||||
"""Check if all environment are exists."""
|
||||
# check environment variables
|
||||
for key in (ENV_SHARE, ENV_NAME, ENV_REPO):
|
||||
@@ -205,24 +205,18 @@ def check_environment():
|
||||
os.environ[key]
|
||||
except KeyError:
|
||||
_LOGGER.fatal("Can't find %s in env!", key)
|
||||
return False
|
||||
|
||||
# check docker socket
|
||||
if not SOCKET_DOCKER.is_socket():
|
||||
_LOGGER.fatal("Can't find Docker socket!")
|
||||
return False
|
||||
|
||||
# check socat exec
|
||||
if not shutil.which("socat"):
|
||||
_LOGGER.fatal("Can't find socat!")
|
||||
return False
|
||||
|
||||
# check socat exec
|
||||
if not shutil.which("gdbus"):
|
||||
_LOGGER.fatal("Can't find gdbus!")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def reg_signal(loop):
|
||||
|
@@ -3,7 +3,7 @@ from enum import Enum
|
||||
from ipaddress import ip_network
|
||||
from pathlib import Path
|
||||
|
||||
SUPERVISOR_VERSION = "205"
|
||||
SUPERVISOR_VERSION = "209"
|
||||
|
||||
|
||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
||||
@@ -28,7 +28,7 @@ FILE_HASSIO_INGRESS = Path(SUPERVISOR_DATA, "ingress.json")
|
||||
FILE_HASSIO_DNS = Path(SUPERVISOR_DATA, "dns.json")
|
||||
FILE_HASSIO_AUDIO = Path(SUPERVISOR_DATA, "audio.json")
|
||||
|
||||
SOCKET_DOCKER = Path("/var/run/docker.sock")
|
||||
SOCKET_DOCKER = Path("/run/docker.sock")
|
||||
|
||||
DOCKER_NETWORK = "hassio"
|
||||
DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23")
|
||||
|
@@ -1,6 +1,8 @@
|
||||
"""Audio docker object."""
|
||||
from contextlib import suppress
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
from ..const import ENV_TIME
|
||||
from ..coresys import CoreSysAttributes
|
||||
@@ -25,6 +27,22 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
|
||||
"""Return name of Docker container."""
|
||||
return AUDIO_DOCKER_NAME
|
||||
|
||||
@property
|
||||
def volumes(self) -> Dict[str, Dict[str, str]]:
|
||||
"""Return Volumes for the mount."""
|
||||
volumes = {
|
||||
str(self.sys_config.path_extern_audio): {"bind": "/data", "mode": "rw"},
|
||||
"/etc/group": {"bind": "/host/group", "mode": "ro"},
|
||||
}
|
||||
|
||||
# SND support
|
||||
if Path("/dev/snd").exists():
|
||||
volumes.update({"/dev/snd": {"bind": "/dev/snd", "mode": "rw"}})
|
||||
else:
|
||||
_LOGGER.warning("Kernel have no audio support in")
|
||||
|
||||
return volumes
|
||||
|
||||
def _run(self) -> None:
|
||||
"""Run Docker image.
|
||||
|
||||
@@ -48,14 +66,7 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
|
||||
detach=True,
|
||||
privileged=True,
|
||||
environment={ENV_TIME: self.sys_timezone},
|
||||
volumes={
|
||||
str(self.sys_config.path_extern_audio): {
|
||||
"bind": "/data",
|
||||
"mode": "rw",
|
||||
},
|
||||
"/dev/snd": {"bind": "/dev/snd", "mode": "rw"},
|
||||
"/etc/group": {"bind": "/host/group", "mode": "ro"},
|
||||
},
|
||||
volumes=self.volumes,
|
||||
)
|
||||
|
||||
self._meta = docker_container.attrs
|
||||
|
@@ -135,7 +135,17 @@ class DockerHomeAssistant(DockerInterface):
|
||||
detach=True,
|
||||
stdout=True,
|
||||
stderr=True,
|
||||
volumes=self.volumes,
|
||||
volumes={
|
||||
str(self.sys_config.path_extern_homeassistant): {
|
||||
"bind": "/config",
|
||||
"mode": "rw",
|
||||
},
|
||||
str(self.sys_config.path_extern_ssl): {"bind": "/ssl", "mode": "ro"},
|
||||
str(self.sys_config.path_extern_share): {
|
||||
"bind": "/share",
|
||||
"mode": "ro",
|
||||
},
|
||||
},
|
||||
environment={ENV_TIME: self.sys_timezone},
|
||||
)
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import secrets
|
||||
import shutil
|
||||
import time
|
||||
from typing import Any, AsyncContextManager, Awaitable, Dict, Optional
|
||||
from uuid import UUID
|
||||
@@ -237,12 +238,12 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
@property
|
||||
def path_pulse(self):
|
||||
"""Return path to asound config."""
|
||||
return Path(self.sys_config.path_tmp, f"homeassistant_pulse")
|
||||
return Path(self.sys_config.path_tmp, "homeassistant_pulse")
|
||||
|
||||
@property
|
||||
def path_extern_pulse(self):
|
||||
"""Return path to asound config for Docker."""
|
||||
return Path(self.sys_config.path_extern_tmp, f"homeassistant_pulse")
|
||||
return Path(self.sys_config.path_extern_tmp, "homeassistant_pulse")
|
||||
|
||||
@property
|
||||
def audio_output(self) -> Optional[str]:
|
||||
@@ -644,11 +645,15 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
input_profile=self.audio_input, output_profile=self.audio_output
|
||||
)
|
||||
|
||||
# Cleanup wrong maps
|
||||
if self.path_pulse.is_dir():
|
||||
shutil.rmtree(self.path_pulse, ignore_errors=True)
|
||||
|
||||
# Write pulse config
|
||||
try:
|
||||
with self.path_pulse.open("w") as config_file:
|
||||
config_file.write(pulse_config)
|
||||
except OSError as err:
|
||||
_LOGGER.error("Home Assistant can't write pulse/client.config: %s", err)
|
||||
raise HomeAssistantError()
|
||||
|
||||
_LOGGER.debug("Home Assistant write pulse/client.config: %s", self.path_pulse)
|
||||
else:
|
||||
_LOGGER.info("Update pulse/client.config: %s", self.path_pulse)
|
||||
|
@@ -73,7 +73,7 @@ class AppArmorControl(CoreSysAttributes):
|
||||
# Copy to AppArmor folder
|
||||
dest_profile = Path(self.sys_config.path_apparmor, profile_name)
|
||||
try:
|
||||
shutil.copy(profile_file, dest_profile)
|
||||
shutil.copyfile(profile_file, dest_profile)
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't copy %s: %s", profile_file, err)
|
||||
raise HostAppArmorError() from None
|
||||
|
@@ -19,20 +19,25 @@ class HwMonitor(CoreSysAttributes):
|
||||
"""Initialize Hardware Monitor object."""
|
||||
self.coresys: CoreSys = coresys
|
||||
self.context = pyudev.Context()
|
||||
self.monitor = pyudev.Monitor.from_netlink(self.context)
|
||||
self.monitor: Optional[pyudev.Monitor] = None
|
||||
self.observer: Optional[pyudev.MonitorObserver] = None
|
||||
|
||||
async def load(self) -> None:
|
||||
"""Start hardware monitor."""
|
||||
self.observer = pyudev.MonitorObserver(self.monitor, self._udev_events)
|
||||
self.observer.start()
|
||||
|
||||
_LOGGER.info("Start Supervisor hardware monitor")
|
||||
try:
|
||||
self.monitor = pyudev.Monitor.from_netlink(self.context)
|
||||
self.observer = pyudev.MonitorObserver(self.monitor, self._udev_events)
|
||||
except OSError:
|
||||
_LOGGER.fatal("Not privileged to run udev. Update your installation!")
|
||||
else:
|
||||
self.observer.start()
|
||||
_LOGGER.info("Started Supervisor hardware monitor")
|
||||
|
||||
async def unload(self) -> None:
|
||||
"""Shutdown sessions."""
|
||||
if self.observer is None:
|
||||
return
|
||||
|
||||
self.observer.stop()
|
||||
_LOGGER.info("Stop Supervisor hardware monitor")
|
||||
|
||||
|
@@ -115,7 +115,7 @@ class Supervisor(CoreSysAttributes):
|
||||
|
||||
_LOGGER.info("Update Supervisor to version %s", version)
|
||||
try:
|
||||
await self.instance.update(version, latest=True)
|
||||
await self.instance.install(version, image=None, latest=True)
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("Update of Supervisor fails!")
|
||||
raise SupervisorUpdateError() from None
|
||||
|
@@ -228,7 +228,7 @@ class Tasks(CoreSysAttributes):
|
||||
async def _watchdog_dns_docker(self):
|
||||
"""Check running state of Docker and start if they is close."""
|
||||
# if CoreDNS is active
|
||||
if await self.sys_dns.is_running():
|
||||
if await self.sys_dns.is_running() or self.sys_dns.in_progress:
|
||||
return
|
||||
_LOGGER.warning("Watchdog found a problem with CoreDNS plugin!")
|
||||
|
||||
@@ -244,7 +244,7 @@ class Tasks(CoreSysAttributes):
|
||||
async def _watchdog_audio_docker(self):
|
||||
"""Check running state of Docker and start if they is close."""
|
||||
# if PulseAudio plugin is active
|
||||
if await self.sys_audio.is_running():
|
||||
if await self.sys_audio.is_running() or self.sys_audio.in_progress:
|
||||
return
|
||||
_LOGGER.warning("Watchdog found a problem with PulseAudio plugin!")
|
||||
|
||||
|
Reference in New Issue
Block a user