Compare commits

...

16 Commits
205 ... 209

Author SHA1 Message Date
Pascal Vizeli
c8cb8aecf7 Merge pull request #1574 from home-assistant/dev
Release 209
2020-03-06 12:41:56 +01:00
Pascal Vizeli
73e8875018 Fix Issue with pulse folder (#1573)
* Fix Issue with pulse folder

* Fix config check
2020-03-06 12:32:29 +01:00
Pascal Vizeli
02aed9c084 Enforce Pulse client (#1572) 2020-03-05 15:54:23 +01:00
Pascal Vizeli
89148f8fff Bump packaging from 20.1 to 20.3 (#1570)
Bumps [packaging](https://github.com/pypa/packaging) from 20.1 to 20.3.
- [Release notes](https://github.com/pypa/packaging/releases)
- [Changelog](https://github.com/pypa/packaging/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pypa/packaging/compare/20.1...20.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-05 13:44:10 +01:00
Pascal Vizeli
6bde527f5c Bump version to 209 2020-03-04 19:09:20 +01:00
Pascal Vizeli
d62aabc01b Merge pull request #1567 from home-assistant/dev
Release 208
2020-03-04 19:08:12 +01:00
Pascal Vizeli
82299a3799 Fix udev error without privileged (#1566)
* Fix udev error without privileged

* Fix udev

* Remove context

* Update supervisor/hwmon.py

Co-Authored-By: Paulus Schoutsen <balloob@gmail.com>

* Update supervisor/hwmon.py

Co-Authored-By: Paulus Schoutsen <balloob@gmail.com>

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2020-03-04 18:55:07 +01:00
Pascal Vizeli
c02f30dd7e Enforce env check (#1565) 2020-03-04 18:15:10 +01:00
Pascal Vizeli
e91983adb4 Watchdog check in_progress for audio/dns (#1555) 2020-03-03 15:06:09 +01:00
Pascal Vizeli
ff88359429 Bump version to 208 2020-03-02 11:32:01 +01:00
Pascal Vizeli
5a60d5cbe8 Merge pull request #1554 from home-assistant/dev
Release 207
2020-03-02 11:31:26 +01:00
Pascal Vizeli
2b41ffe019 Bump version to 207 2020-03-01 17:52:35 +01:00
Pascal Vizeli
1c23e26f93 Check if SND is loaded (#1552)
* Check if SND is loaded

* add warning
2020-02-29 23:45:37 +01:00
Pascal Vizeli
3d555f951d Fix supervisor update flow with apparmor (#1551) 2020-02-29 23:07:34 +01:00
Bram Kragten
6d39b4d7cd Update audio.py (#1548) 2020-02-29 19:28:52 +01:00
Pascal Vizeli
4fe5d09f01 Bump version to 206 2020-02-29 12:19:42 +01:00
14 changed files with 69 additions and 48 deletions

View File

@@ -8,7 +8,7 @@ cryptography==2.8
docker==4.2.0 docker==4.2.0
gitpython==3.1.0 gitpython==3.1.0
jinja2==2.11.1 jinja2==2.11.1
packaging==20.1 packaging==20.3
ptvsd==4.3.2 ptvsd==4.3.2
pulsectl==20.2.4 pulsectl==20.2.4
pytz==2019.3 pytz==2019.3

View File

@@ -30,8 +30,7 @@ if __name__ == "__main__":
loop = initialize_event_loop() loop = initialize_event_loop()
# Check if all information are available to setup Supervisor # Check if all information are available to setup Supervisor
if not bootstrap.check_environment(): bootstrap.check_environment()
sys.exit(1)
# init executor pool # init executor pool
executor = ThreadPoolExecutor(thread_name_prefix="SyncWorker") executor = ThreadPoolExecutor(thread_name_prefix="SyncWorker")

View File

@@ -393,6 +393,11 @@ class Addon(AddonModel):
input_profile=self.audio_input, output_profile=self.audio_output 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: try:
with self.path_pulse.open("w") as config_file: with self.path_pulse.open("w") as config_file:
config_file.write(pulse_config) config_file.write(pulse_config)
@@ -400,11 +405,10 @@ class Addon(AddonModel):
_LOGGER.error( _LOGGER.error(
"Add-on %s can't write pulse/client.config: %s", self.slug, err "Add-on %s can't write pulse/client.config: %s", self.slug, err
) )
raise AddonsError() else:
_LOGGER.debug(
_LOGGER.debug( "Add-on %s write pulse/client.config: %s", self.slug, self.path_pulse
"Add-on %s write pulse/client.config: %s", self.slug, self.path_pulse )
)
async def install_apparmor(self) -> None: async def install_apparmor(self) -> None:
"""Install or Update AppArmor profile for Add-on.""" """Install or Update AppArmor profile for Add-on."""

View File

@@ -163,7 +163,7 @@ class APIAudio(CoreSysAttributes):
@api_process @api_process
async def set_profile(self, request: web.Request) -> None: async def set_profile(self, request: web.Request) -> None:
"""Set audio default sources.""" """Set audio default sources."""
body = await api_validate(SCHEMA_DEFAULT, request) body = await api_validate(SCHEMA_PROFILE, request)
await asyncio.shield( await asyncio.shield(
self.sys_host.sound.set_profile(body[ATTR_CARD], body[ATTR_NAME]) self.sys_host.sound.set_profile(body[ATTR_CARD], body[ATTR_NAME])

View File

@@ -188,13 +188,6 @@ class Audio(JsonConfig, CoreSysAttributes):
""" """
return self.instance.is_running() 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: async def repair(self) -> None:
"""Repair CoreDNS plugin.""" """Repair CoreDNS plugin."""
if await self.instance.exists(): if await self.instance.exists():

View File

@@ -197,7 +197,7 @@ def initialize_logging():
) )
def check_environment(): def check_environment() -> None:
"""Check if all environment are exists.""" """Check if all environment are exists."""
# check environment variables # check environment variables
for key in (ENV_SHARE, ENV_NAME, ENV_REPO): for key in (ENV_SHARE, ENV_NAME, ENV_REPO):
@@ -205,24 +205,18 @@ def check_environment():
os.environ[key] os.environ[key]
except KeyError: except KeyError:
_LOGGER.fatal("Can't find %s in env!", key) _LOGGER.fatal("Can't find %s in env!", key)
return False
# check docker socket # check docker socket
if not SOCKET_DOCKER.is_socket(): if not SOCKET_DOCKER.is_socket():
_LOGGER.fatal("Can't find Docker socket!") _LOGGER.fatal("Can't find Docker socket!")
return False
# check socat exec # check socat exec
if not shutil.which("socat"): if not shutil.which("socat"):
_LOGGER.fatal("Can't find socat!") _LOGGER.fatal("Can't find socat!")
return False
# check socat exec # check socat exec
if not shutil.which("gdbus"): if not shutil.which("gdbus"):
_LOGGER.fatal("Can't find gdbus!") _LOGGER.fatal("Can't find gdbus!")
return False
return True
def reg_signal(loop): def reg_signal(loop):

View File

@@ -3,7 +3,7 @@ from enum import Enum
from ipaddress import ip_network from ipaddress import ip_network
from pathlib import Path from pathlib import Path
SUPERVISOR_VERSION = "205" SUPERVISOR_VERSION = "209"
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" 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_DNS = Path(SUPERVISOR_DATA, "dns.json")
FILE_HASSIO_AUDIO = Path(SUPERVISOR_DATA, "audio.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 = "hassio"
DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23") DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23")

View File

@@ -1,6 +1,8 @@
"""Audio docker object.""" """Audio docker object."""
from contextlib import suppress from contextlib import suppress
import logging import logging
from pathlib import Path
from typing import Dict
from ..const import ENV_TIME from ..const import ENV_TIME
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
@@ -25,6 +27,22 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
"""Return name of Docker container.""" """Return name of Docker container."""
return AUDIO_DOCKER_NAME 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: def _run(self) -> None:
"""Run Docker image. """Run Docker image.
@@ -48,14 +66,7 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
detach=True, detach=True,
privileged=True, privileged=True,
environment={ENV_TIME: self.sys_timezone}, environment={ENV_TIME: self.sys_timezone},
volumes={ volumes=self.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"},
},
) )
self._meta = docker_container.attrs self._meta = docker_container.attrs

View File

@@ -135,7 +135,17 @@ class DockerHomeAssistant(DockerInterface):
detach=True, detach=True,
stdout=True, stdout=True,
stderr=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}, environment={ENV_TIME: self.sys_timezone},
) )

View File

@@ -8,6 +8,7 @@ import os
from pathlib import Path from pathlib import Path
import re import re
import secrets import secrets
import shutil
import time import time
from typing import Any, AsyncContextManager, Awaitable, Dict, Optional from typing import Any, AsyncContextManager, Awaitable, Dict, Optional
from uuid import UUID from uuid import UUID
@@ -237,12 +238,12 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
@property @property
def path_pulse(self): def path_pulse(self):
"""Return path to asound config.""" """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 @property
def path_extern_pulse(self): def path_extern_pulse(self):
"""Return path to asound config for Docker.""" """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 @property
def audio_output(self) -> Optional[str]: def audio_output(self) -> Optional[str]:
@@ -644,11 +645,15 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
input_profile=self.audio_input, output_profile=self.audio_output 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: try:
with self.path_pulse.open("w") as config_file: with self.path_pulse.open("w") as config_file:
config_file.write(pulse_config) config_file.write(pulse_config)
except OSError as err: except OSError as err:
_LOGGER.error("Home Assistant can't write pulse/client.config: %s", err) _LOGGER.error("Home Assistant can't write pulse/client.config: %s", err)
raise HomeAssistantError() else:
_LOGGER.info("Update pulse/client.config: %s", self.path_pulse)
_LOGGER.debug("Home Assistant write pulse/client.config: %s", self.path_pulse)

View File

@@ -73,7 +73,7 @@ class AppArmorControl(CoreSysAttributes):
# Copy to AppArmor folder # Copy to AppArmor folder
dest_profile = Path(self.sys_config.path_apparmor, profile_name) dest_profile = Path(self.sys_config.path_apparmor, profile_name)
try: try:
shutil.copy(profile_file, dest_profile) shutil.copyfile(profile_file, dest_profile)
except OSError as err: except OSError as err:
_LOGGER.error("Can't copy %s: %s", profile_file, err) _LOGGER.error("Can't copy %s: %s", profile_file, err)
raise HostAppArmorError() from None raise HostAppArmorError() from None

View File

@@ -19,20 +19,25 @@ class HwMonitor(CoreSysAttributes):
"""Initialize Hardware Monitor object.""" """Initialize Hardware Monitor object."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.context = pyudev.Context() self.context = pyudev.Context()
self.monitor = pyudev.Monitor.from_netlink(self.context) self.monitor: Optional[pyudev.Monitor] = None
self.observer: Optional[pyudev.MonitorObserver] = None self.observer: Optional[pyudev.MonitorObserver] = None
async def load(self) -> None: async def load(self) -> None:
"""Start hardware monitor.""" """Start hardware monitor."""
self.observer = pyudev.MonitorObserver(self.monitor, self._udev_events) try:
self.observer.start() self.monitor = pyudev.Monitor.from_netlink(self.context)
self.observer = pyudev.MonitorObserver(self.monitor, self._udev_events)
_LOGGER.info("Start Supervisor hardware monitor") 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: async def unload(self) -> None:
"""Shutdown sessions.""" """Shutdown sessions."""
if self.observer is None: if self.observer is None:
return return
self.observer.stop() self.observer.stop()
_LOGGER.info("Stop Supervisor hardware monitor") _LOGGER.info("Stop Supervisor hardware monitor")

View File

@@ -115,7 +115,7 @@ class Supervisor(CoreSysAttributes):
_LOGGER.info("Update Supervisor to version %s", version) _LOGGER.info("Update Supervisor to version %s", version)
try: try:
await self.instance.update(version, latest=True) await self.instance.install(version, image=None, latest=True)
except DockerAPIError: except DockerAPIError:
_LOGGER.error("Update of Supervisor fails!") _LOGGER.error("Update of Supervisor fails!")
raise SupervisorUpdateError() from None raise SupervisorUpdateError() from None

View File

@@ -228,7 +228,7 @@ class Tasks(CoreSysAttributes):
async def _watchdog_dns_docker(self): async def _watchdog_dns_docker(self):
"""Check running state of Docker and start if they is close.""" """Check running state of Docker and start if they is close."""
# if CoreDNS is active # 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 return
_LOGGER.warning("Watchdog found a problem with CoreDNS plugin!") _LOGGER.warning("Watchdog found a problem with CoreDNS plugin!")
@@ -244,7 +244,7 @@ class Tasks(CoreSysAttributes):
async def _watchdog_audio_docker(self): async def _watchdog_audio_docker(self):
"""Check running state of Docker and start if they is close.""" """Check running state of Docker and start if they is close."""
# if PulseAudio plugin is active # 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 return
_LOGGER.warning("Watchdog found a problem with PulseAudio plugin!") _LOGGER.warning("Watchdog found a problem with PulseAudio plugin!")