mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-17 14:16:29 +00:00
Addons can access systemd journal logs (#2722)
* Added journald access to addons * Name change to journald and added tests
This commit is contained in:
parent
9e1f899274
commit
667672a20b
@ -32,6 +32,7 @@ from ..const import (
|
||||
ATTR_IMAGE,
|
||||
ATTR_INGRESS,
|
||||
ATTR_INIT,
|
||||
ATTR_JOURNALD,
|
||||
ATTR_KERNEL_MODULES,
|
||||
ATTR_LEGACY,
|
||||
ATTR_LOCATON,
|
||||
@ -550,6 +551,11 @@ class AddonModel(CoreSysAttributes, ABC):
|
||||
return None
|
||||
return UiOptions(self.coresys)(raw_schema)
|
||||
|
||||
@property
|
||||
def with_journald(self) -> bool:
|
||||
"""Return True if the add-on accesses the system journal."""
|
||||
return self.data[ATTR_JOURNALD]
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Compaired add-on objects."""
|
||||
if not isinstance(other, AddonModel):
|
||||
|
@ -45,6 +45,7 @@ from ..const import (
|
||||
ATTR_INGRESS_PORT,
|
||||
ATTR_INGRESS_TOKEN,
|
||||
ATTR_INIT,
|
||||
ATTR_JOURNALD,
|
||||
ATTR_KERNEL_MODULES,
|
||||
ATTR_LEGACY,
|
||||
ATTR_LOCATON,
|
||||
@ -299,6 +300,7 @@ _SCHEMA_ADDON_CONFIG = vol.Schema(
|
||||
vol.Optional(ATTR_TIMEOUT, default=10): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=10, max=300)
|
||||
),
|
||||
vol.Optional(ATTR_JOURNALD, default=False): vol.Boolean(),
|
||||
},
|
||||
extra=vol.REMOVE_EXTRA,
|
||||
)
|
||||
|
@ -27,6 +27,7 @@ MACHINE_ID = Path("/etc/machine-id")
|
||||
SOCKET_DBUS = Path("/run/dbus/system_bus_socket")
|
||||
SOCKET_DOCKER = Path("/run/docker.sock")
|
||||
RUN_SUPERVISOR_STATE = Path("/run/supervisor")
|
||||
SYSTEMD_JOURNAL = Path("/var/logs/journal")
|
||||
|
||||
DOCKER_NETWORK = "hassio"
|
||||
DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23")
|
||||
@ -279,6 +280,7 @@ ATTR_SUPERVISOR_INTERNET = "supervisor_internet"
|
||||
ATTR_SUPPORTED = "supported"
|
||||
ATTR_SUPPORTED_ARCH = "supported_arch"
|
||||
ATTR_SYSTEM = "system"
|
||||
ATTR_JOURNALD = "journald"
|
||||
ATTR_TIMEOUT = "timeout"
|
||||
ATTR_TIMEZONE = "timezone"
|
||||
ATTR_TITLE = "title"
|
||||
|
@ -26,6 +26,7 @@ from ..const import (
|
||||
MAP_SSL,
|
||||
SECURITY_DISABLE,
|
||||
SECURITY_PROFILE,
|
||||
SYSTEMD_JOURNAL,
|
||||
)
|
||||
from ..coresys import CoreSys
|
||||
from ..exceptions import CoreDNSError, DockerError, DockerNotFound, HardwareNotFound
|
||||
@ -413,6 +414,17 @@ class DockerAddon(DockerInterface):
|
||||
}
|
||||
)
|
||||
|
||||
# System Journal access
|
||||
if self.addon.with_journald:
|
||||
volumes.update(
|
||||
{
|
||||
str(SYSTEMD_JOURNAL): {
|
||||
"bind": str(SYSTEMD_JOURNAL),
|
||||
"mode": "ro",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return volumes
|
||||
|
||||
def _run(self) -> None:
|
||||
|
1
tests/docker/__init__.py
Normal file
1
tests/docker/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Docker tests."""
|
119
tests/docker/test_addon.py
Normal file
119
tests/docker/test_addon.py
Normal file
@ -0,0 +1,119 @@
|
||||
"""Test docker addon setup."""
|
||||
from typing import Dict
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from supervisor.addons import validate as vd
|
||||
from supervisor.addons.addon import Addon
|
||||
from supervisor.addons.model import Data
|
||||
from supervisor.const import SYSTEMD_JOURNAL
|
||||
from supervisor.coresys import CoreSys
|
||||
from supervisor.docker.addon import DockerAddon
|
||||
|
||||
from ..common import load_json_fixture
|
||||
|
||||
|
||||
@pytest.fixture(name="addonsdata_system")
|
||||
def fixture_addonsdata_system() -> Dict[str, Data]:
|
||||
"""Mock AddonsData.system."""
|
||||
with patch(
|
||||
"supervisor.addons.data.AddonsData.system", new_callable=PropertyMock
|
||||
) as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@pytest.fixture(name="addonsdata_user", autouse=True)
|
||||
def fixture_addonsdata_user() -> Dict[str, Data]:
|
||||
"""Mock AddonsData.user."""
|
||||
with patch(
|
||||
"supervisor.addons.data.AddonsData.user", new_callable=PropertyMock
|
||||
) as mock:
|
||||
mock.return_value = MagicMock()
|
||||
yield mock
|
||||
|
||||
|
||||
@pytest.fixture(name="os_environ", autouse=True)
|
||||
def fixture_os_environ():
|
||||
"""Mock os.environ."""
|
||||
with patch("supervisor.config.os.environ") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
def get_docker_addon(
|
||||
coresys: CoreSys, addonsdata_system: Dict[str, Data], config_file: str
|
||||
):
|
||||
"""Make and return docker addon object."""
|
||||
config = vd.SCHEMA_ADDON_CONFIG(load_json_fixture(config_file))
|
||||
slug = config.get("slug")
|
||||
addonsdata_system.return_value = {slug: config}
|
||||
|
||||
addon = Addon(coresys, config.get("slug"))
|
||||
docker_addon = DockerAddon(coresys, addon)
|
||||
return docker_addon
|
||||
|
||||
|
||||
def test_base_volumes_included(coresys: CoreSys, addonsdata_system: Dict[str, Data]):
|
||||
"""Dev and data volumes always included."""
|
||||
docker_addon = get_docker_addon(
|
||||
coresys, addonsdata_system, "basic-addon-config.json"
|
||||
)
|
||||
volumes = docker_addon.volumes
|
||||
|
||||
# Dev added as ro
|
||||
assert "/dev" in volumes
|
||||
assert volumes["/dev"]["bind"] == "/dev"
|
||||
assert volumes["/dev"]["mode"] == "ro"
|
||||
|
||||
# Data added as rw
|
||||
data_path = str(docker_addon.addon.path_extern_data)
|
||||
assert data_path in volumes
|
||||
assert volumes[data_path]["bind"] == "/data"
|
||||
assert volumes[data_path]["mode"] == "rw"
|
||||
|
||||
|
||||
def test_addon_map_folder_defaults(
|
||||
coresys: CoreSys, addonsdata_system: Dict[str, Data]
|
||||
):
|
||||
"""Validate defaults for mapped folders in addons."""
|
||||
docker_addon = get_docker_addon(
|
||||
coresys, addonsdata_system, "basic-addon-config.json"
|
||||
)
|
||||
volumes = docker_addon.volumes
|
||||
|
||||
# Config added and is marked rw
|
||||
config_path = str(docker_addon.sys_config.path_extern_homeassistant)
|
||||
assert config_path in volumes
|
||||
assert volumes[config_path]["bind"] == "/config"
|
||||
assert volumes[config_path]["mode"] == "rw"
|
||||
|
||||
# SSL added and defaults to ro
|
||||
ssl_path = str(docker_addon.sys_config.path_extern_ssl)
|
||||
assert ssl_path in volumes
|
||||
assert volumes[ssl_path]["bind"] == "/ssl"
|
||||
assert volumes[ssl_path]["mode"] == "ro"
|
||||
|
||||
# Share not mapped
|
||||
assert str(docker_addon.sys_config.path_extern_share) not in volumes
|
||||
|
||||
|
||||
def test_journald_addon(coresys: CoreSys, addonsdata_system: Dict[str, Data]):
|
||||
"""Validate volume for journald option."""
|
||||
docker_addon = get_docker_addon(
|
||||
coresys, addonsdata_system, "journald-addon-config.json"
|
||||
)
|
||||
volumes = docker_addon.volumes
|
||||
|
||||
assert str(SYSTEMD_JOURNAL) in volumes
|
||||
assert volumes.get(str(SYSTEMD_JOURNAL)).get("bind") == str(SYSTEMD_JOURNAL)
|
||||
assert volumes.get(str(SYSTEMD_JOURNAL)).get("mode") == "ro"
|
||||
|
||||
|
||||
def test_not_journald_addon(coresys: CoreSys, addonsdata_system: Dict[str, Data]):
|
||||
"""Validate journald option defaults off."""
|
||||
docker_addon = get_docker_addon(
|
||||
coresys, addonsdata_system, "basic-addon-config.json"
|
||||
)
|
||||
volumes = docker_addon.volumes
|
||||
|
||||
assert str(SYSTEMD_JOURNAL) not in volumes
|
13
tests/fixtures/journald-addon-config.json
vendored
Normal file
13
tests/fixtures/journald-addon-config.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Journald Add-on",
|
||||
"version": "1.0.1",
|
||||
"slug": "journald_addon",
|
||||
"description": "This is a Test Add-on that uses journald",
|
||||
"arch": ["amd64"],
|
||||
"url": "https://www.home-assistant.io/",
|
||||
"startup": "application",
|
||||
"boot": "auto",
|
||||
"journald": true,
|
||||
"options": {},
|
||||
"schema": {}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user