Skip to content

Commit 4ebef9b

Browse files
committed
Merge tag 'refs/tags/2025.05.5'
2 parents 2f6d165 + ad2d6a3 commit 4ebef9b

File tree

17 files changed

+234
-31
lines changed

17 files changed

+234
-31
lines changed

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ ARG BUILD_FROM
22
FROM ${BUILD_FROM}
33

44
ENV \
5-
S6_READ_ONLY_ROOT=1 \
65
S6_SERVICES_GRACETIME=10000 \
76
SUPERVISOR_API=http://localhost \
87
CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1 \

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools~=80.8.0", "wheel~=0.46.1"]
2+
requires = ["setuptools~=80.9.0", "wheel~=0.46.1"]
33
build-backend = "setuptools.build_meta"
44

55
[project]

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
aiodns==3.4.0
2-
aiohttp==3.11.18
2+
aiohttp==3.12.4
33
atomicwrites-homeassistant==1.4.1
44
attrs==25.3.0
55
awesomeversion==24.6.0
@@ -8,7 +8,7 @@ brotli==1.1.0
88
ciso8601==2.3.2
99
colorlog==6.9.0
1010
cpe==1.3.1
11-
cryptography==45.0.2
11+
cryptography==45.0.3
1212
debugpy==1.8.14
1313
deepmerge==2.0
1414
dirhash==0.5.0
@@ -24,7 +24,7 @@ PyYAML==6.0.2
2424
requests==2.32.3
2525
securetar==2025.2.1
2626
sentry-sdk==2.29.1
27-
setuptools==80.8.0
27+
setuptools==80.9.0
2828
voluptuous==0.15.2
2929
dbus-fast==2.44.1
3030
zlib-fast==0.2.1

requirements_tests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
astroid==3.3.10
2-
coverage==7.8.1
2+
coverage==7.8.2
33
pre-commit==4.2.0
44
pylint==3.3.7
55
pytest-aiohttp==1.1.0

supervisor/__main__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,15 @@ def run_os_startup_check_cleanup() -> None:
6666
_LOGGER.info("Setting up Supervisor")
6767
loop.run_until_complete(coresys.core.setup())
6868

69-
loop.call_soon_threadsafe(loop.create_task, coresys.core.start())
70-
loop.call_soon_threadsafe(bootstrap.reg_signal, loop, coresys)
69+
bootstrap.register_signal_handlers(loop, coresys)
70+
71+
try:
72+
loop.run_until_complete(coresys.core.start())
73+
except Exception as err: # pylint: disable=broad-except
74+
# Supervisor itself is running at this point, just something didn't
75+
# start as expected. Log with traceback to get more insights for
76+
# such cases.
77+
_LOGGER.critical("Supervisor start failed: %s", err, exc_info=True)
7178

7279
try:
7380
_LOGGER.info("Running Supervisor")

supervisor/bootstrap.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Bootstrap Supervisor."""
22

33
# ruff: noqa: T100
4+
import asyncio
45
from importlib import import_module
56
import logging
67
import os
@@ -284,8 +285,8 @@ def check_environment() -> None:
284285
_LOGGER.critical("Can't find Docker socket!")
285286

286287

287-
def reg_signal(loop, coresys: CoreSys) -> None:
288-
"""Register SIGTERM and SIGKILL to stop system."""
288+
def register_signal_handlers(loop: asyncio.BaseEventLoop, coresys: CoreSys) -> None:
289+
"""Register SIGTERM, SIGHUP and SIGKILL to stop the Supervisor."""
289290
try:
290291
loop.add_signal_handler(
291292
signal.SIGTERM, lambda: loop.create_task(coresys.core.stop())

supervisor/core.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ async def setup(self):
188188
await setup_task
189189
except Exception as err: # pylint: disable=broad-except
190190
_LOGGER.critical(
191-
"Fatal error happening on load Task %s: %s", setup_task, err
191+
"Fatal error happening on load Task %s: %s",
192+
setup_task,
193+
err,
194+
exc_info=True,
192195
)
193196
self.sys_resolution.add_unhealthy_reason(UnhealthyReason.SETUP)
194197
await async_capture_exception(err)
@@ -237,10 +240,10 @@ async def start(self):
237240
await self.sys_supervisor.update()
238241
return
239242

240-
# Start addon mark as initialize
241-
await self.sys_addons.boot(AddonStartup.INITIALIZE)
242-
243243
try:
244+
# Start addon mark as initialize
245+
await self.sys_addons.boot(AddonStartup.INITIALIZE)
246+
244247
# HomeAssistant is already running, only Supervisor restarted
245248
if await self.sys_hardware.helper.last_boot() == self.sys_config.last_boot:
246249
_LOGGER.info("Detected Supervisor restart")

supervisor/host/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class LogFormat(StrEnum):
8080

8181
JOURNAL = "application/vnd.fdo.journal"
8282
JSON = "application/json"
83+
JSON_SEQ = "application/json-seq"
8384
TEXT = "text/plain"
8485

8586

supervisor/host/logs.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
HostServiceError,
2626
)
2727
from ..utils.json import read_json_file
28+
from ..utils.systemd_journal import journal_boots_reader
2829
from .const import PARAM_BOOT_ID, PARAM_SYSLOG_IDENTIFIER, LogFormat
2930

3031
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -108,12 +109,8 @@ async def get_boot_id(self, offset: int = 0) -> str:
108109

109110
return boot_ids[offset]
110111

111-
async def get_boot_ids(self) -> list[str]:
112-
"""Get boot IDs from oldest to newest."""
113-
if self._boot_ids:
114-
# Doesn't change without a reboot, no reason to query again once cached
115-
return self._boot_ids
116-
112+
async def _get_boot_ids_legacy(self) -> list[str]:
113+
"""Get boots IDs using suboptimal method where /boots is not available."""
117114
try:
118115
async with self.journald_logs(
119116
params=BOOT_IDS_QUERY,
@@ -142,13 +139,51 @@ async def get_boot_ids(self) -> list[str]:
142139
_LOGGER.error,
143140
) from err
144141

145-
self._boot_ids = []
142+
_boot_ids = []
146143
for entry in text.split("\n"):
147-
if (
148-
entry
149-
and (boot_id := json.loads(entry)[PARAM_BOOT_ID]) not in self._boot_ids
150-
):
151-
self._boot_ids.append(boot_id)
144+
if entry and (boot_id := json.loads(entry)[PARAM_BOOT_ID]) not in _boot_ids:
145+
_boot_ids.append(boot_id)
146+
147+
return _boot_ids
148+
149+
async def _get_boot_ids_native(self):
150+
"""Get boot IDs using /boots endpoint."""
151+
try:
152+
async with self.journald_logs(
153+
path="/boots",
154+
accept=LogFormat.JSON_SEQ,
155+
timeout=ClientTimeout(total=20),
156+
) as resp:
157+
if resp.status != 200:
158+
raise HostLogError(
159+
f"Got HTTP {resp.status} from /boots.",
160+
_LOGGER.debug,
161+
)
162+
# Don't rely solely on the order of boots in the response,
163+
# sort the boots by index returned in the response.
164+
boot_id_tuples = [boot async for boot in journal_boots_reader(resp)]
165+
return [
166+
boot_id for _, boot_id in sorted(boot_id_tuples, key=lambda x: x[0])
167+
]
168+
except (ClientError, TimeoutError) as err:
169+
raise HostLogError(
170+
"Could not get a list of boot IDs from systemd-journal-gatewayd",
171+
_LOGGER.error,
172+
) from err
173+
174+
async def get_boot_ids(self) -> list[str]:
175+
"""Get boot IDs from oldest to newest."""
176+
if self._boot_ids:
177+
# Doesn't change without a reboot, no reason to query again once cached
178+
return self._boot_ids
179+
180+
try:
181+
self._boot_ids = await self._get_boot_ids_native()
182+
except HostLogError:
183+
_LOGGER.info(
184+
"Could not get /boots from systemd-journal-gatewayd, using fallback."
185+
)
186+
self._boot_ids = await self._get_boot_ids_legacy()
152187

153188
return self._boot_ids
154189

supervisor/host/network.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ async def _check_connectivity_changed(
158158
DBUS_ATTR_PRIMARY_CONNECTION in changed
159159
and changed[DBUS_ATTR_PRIMARY_CONNECTION]
160160
and changed[DBUS_ATTR_PRIMARY_CONNECTION] != DBUS_OBJECT_BASE
161+
and await self.sys_plugins.dns.is_running()
161162
):
162163
await self.sys_plugins.dns.restart()
163164

0 commit comments

Comments
 (0)