mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-26 02:26:30 +00:00
commit
ed45f27f3e
@ -43,6 +43,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
# Install Python dependencies from requirements.txt if it exists
|
||||
COPY requirements.txt requirements_tests.txt ./
|
||||
RUN pip3 install -r requirements.txt -r requirements_tests.txt \
|
||||
RUN pip3 install -U setuptools pip \
|
||||
&& pip3 install -r requirements.txt -r requirements_tests.txt \
|
||||
&& pip3 install tox \
|
||||
&& rm -f requirements.txt requirements_tests.txt
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit faee2c3e1b16aa758a802b43d39bcb7032bcf722
|
||||
Subproject commit 0c7c536f73bc8c73aea8c2c3f89114bdd62b9551
|
@ -1,6 +1,6 @@
|
||||
aiohttp==3.6.2
|
||||
async_timeout==3.0.1
|
||||
attrs==20.1.0
|
||||
attrs==20.2.0
|
||||
cchardet==2.1.6
|
||||
colorlog==4.2.1
|
||||
cpe==1.2.1
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Start Service service
|
||||
# Start Supervisor service
|
||||
# ==============================================================================
|
||||
export LD_PRELOAD="/usr/local/lib/libjemalloc.so.2"
|
||||
|
||||
exec python3 -m supervisor
|
||||
exec python3 -m supervisor
|
||||
|
8
rootfs/etc/services.d/watchdog/finish
Normal file
8
rootfs/etc/services.d/watchdog/finish
Normal file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/execlineb -S1
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree when Watchdog fails
|
||||
# ==============================================================================
|
||||
if { s6-test ${1} -ne 0 }
|
||||
if { s6-test ${1} -ne 256 }
|
||||
|
||||
s6-svscanctl -t /var/run/s6/services
|
34
rootfs/etc/services.d/watchdog/run
Normal file
34
rootfs/etc/services.d/watchdog/run
Normal file
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Start Watchdog service
|
||||
# ==============================================================================
|
||||
declare failed_count=0
|
||||
declare supervisor_state
|
||||
|
||||
bashio::log.info "Start local supervisor watchdog..."
|
||||
|
||||
while [[ failed_count -lt 2 ]];
|
||||
do
|
||||
sleep 300
|
||||
supervisor_state="$(cat /run/supervisor)"
|
||||
|
||||
if [[ "${supervisor_state}" = "running" ]]; then
|
||||
|
||||
# Check API
|
||||
if bashio::supervisor.ping; then
|
||||
failed_count=0
|
||||
else
|
||||
bashio::log.warning "Maybe found an issue on API healthy"
|
||||
((failed_count++))
|
||||
fi
|
||||
|
||||
elif [[ "close stopping" = *"${supervisor_state}"* ]]; then
|
||||
bashio::log.warning "Maybe found an issue on shutdown"
|
||||
((failed_count++))
|
||||
else
|
||||
failed_count=0
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
basio::exit.nok "Watchdog detect issue with Supervisor - take container down!"
|
@ -47,15 +47,12 @@ if __name__ == "__main__":
|
||||
loop.run_until_complete(coresys.core.setup())
|
||||
|
||||
loop.call_soon_threadsafe(loop.create_task, coresys.core.start())
|
||||
loop.call_soon_threadsafe(bootstrap.reg_signal, loop)
|
||||
loop.call_soon_threadsafe(bootstrap.reg_signal, loop, coresys)
|
||||
|
||||
try:
|
||||
_LOGGER.info("Run Supervisor")
|
||||
loop.run_forever()
|
||||
finally:
|
||||
_LOGGER.info("Stopping Supervisor")
|
||||
loop.run_until_complete(coresys.core.stop())
|
||||
executor.shutdown(wait=False)
|
||||
loop.close()
|
||||
|
||||
_LOGGER.info("Close Supervisor")
|
||||
|
@ -87,6 +87,10 @@ class Addon(AddonModel):
|
||||
self.instance: DockerAddon = DockerAddon(coresys, self)
|
||||
self.state: AddonState = AddonState.UNKNOWN
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return internal representation."""
|
||||
return f"<Addon: {self.slug}>"
|
||||
|
||||
@property
|
||||
def in_progress(self) -> bool:
|
||||
"""Return True if a task is in progress."""
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
try {
|
||||
new Function("import('/api/hassio/app/frontend_latest/entrypoint.e3f59ee9.js')")();
|
||||
new Function("import('/api/hassio/app/frontend_latest/entrypoint.babc4122.js')")();
|
||||
} catch (err) {
|
||||
var el = document.createElement('script');
|
||||
el.src = '/api/hassio/app/frontend_es5/entrypoint.6086a806.js';
|
||||
el.src = '/api/hassio/app/frontend_es5/entrypoint.028a6bad.js';
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.2b6daa2d9335da34f364.js","sources":["webpack:///chunk.2b6daa2d9335da34f364.js"],"mappings":"AAAA","sourceRoot":""}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.2d61d2e5cad84705d92e.js","sources":["webpack:///chunk.2d61d2e5cad84705d92e.js"],"mappings":";AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.3e7c27cbbb8b44bddd5f.js","sources":["webpack:///chunk.3e7c27cbbb8b44bddd5f.js"],"mappings":";AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.4e329b1d42b5358fbe1a.js","sources":["webpack:///chunk.4e329b1d42b5358fbe1a.js"],"mappings":"AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.a0bbc7b092a109a89b49.js","sources":["webpack:///chunk.a0bbc7b092a109a89b49.js"],"mappings":"AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.c1d54f5585b325a620ff.js","sources":["webpack:///chunk.c1d54f5585b325a620ff.js"],"mappings":"AAAA","sourceRoot":""}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.cddd872dbf23dca66986.js","sources":["webpack:///chunk.cddd872dbf23dca66986.js"],"mappings":"AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.d7c7c8539f98733903e7.js","sources":["webpack:///chunk.d7c7c8539f98733903e7.js"],"mappings":"AAAA","sourceRoot":""}
|
3
supervisor/api/panel/frontend_es5/entrypoint.028a6bad.js
Normal file
3
supervisor/api/panel/frontend_es5/entrypoint.028a6bad.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/frontend_es5/entrypoint.028a6bad.js.gz
Normal file
BIN
supervisor/api/panel/frontend_es5/entrypoint.028a6bad.js.gz
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"entrypoint.028a6bad.js","sources":["webpack:///entrypoint.028a6bad.js"],"mappings":";AAAA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"entrypoint.6086a806.js","sources":["webpack:///entrypoint.6086a806.js"],"mappings":";AAAA","sourceRoot":""}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"entrypoint.js": "/api/hassio/app/frontend_es5/entrypoint.6086a806.js"
|
||||
"entrypoint.js": "/api/hassio/app/frontend_es5/entrypoint.028a6bad.js"
|
||||
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.65999be5697048c06838.js","sources":["webpack:///chunk.65999be5697048c06838.js"],"mappings":"AAAA;;AAsIA;AACA;;AAEA;;AAEA;;AAEA;AAhBA;AACA;;AAEA;AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0HA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.6bb7ce5727199e27cab7.js","sources":["webpack:///chunk.6bb7ce5727199e27cab7.js"],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAy7EA","sourceRoot":""}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.7cb0e1ca56f17d2a6349.js","sources":["webpack:///chunk.7cb0e1ca56f17d2a6349.js"],"mappings":"AAAA;;;AAiHA;AACA;;AAEA;;AATA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1 @@
|
||||
{"version":3,"file":"chunk.857ff7ed2c02915f8deb.js","sources":["webpack:///chunk.857ff7ed2c02915f8deb.js"],"mappings":"AAAA;;;AAiHA;AACA;;AAEA;;AATA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1 +1 @@
|
||||
{"version":3,"file":"chunk.bf7e6600f8be3c723cd9.js","sources":["webpack:///chunk.bf7e6600f8be3c723cd9.js"],"mappings":"AAAA;;;AAoMA;AACA;;;AAGA;;;;;AAKA;;AAEA;AAEA;AACA;;;;;;;AAQA;;;;;AAKA;;AAEA;AAEA;AACA;;;;;;;AAQA;;;;;AAOA;;;;;;;;;;;;;;;;AAuBA;AAinBA;;AAEA;;AAEA;AACA;;AAIA;AA0IA;;;;AAIA;;AAEA;AACA;;;AAGA;;;;AAIA;AACA;;;;;;AAQA;;;;;;;;;;;;;;;;;;;;;;AA6HA;;;AAyGA;AACA;;;;;;;;AAQA;;AAGA;;;AAGA;;AAEA;AACA;;;;AAIA;;;;;;;AAQA;;;AAGA;;;;;AAvCA;;;;;;;;;;;;;;;AA8KA;;;AAkFA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AApBA;;;;;;;;;;;AA4CA;;;AA8GA;;AAEA;;;;AARA;;;;;;;;;;;;AAiCA;;AAiCA;AACA;AACA;;;AAMA;;;;AA6IA;;;AAMA;AACA;;;AAGA;;AAEA;;AAKA;;AAEA;;AAEA;;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6EA;AAsLA;;;;AAIA;AACA;AACA;AACA;;;AAGA;;;;;;;;AAQA;AACA;AACA;;;;AAIA;AACA;;;AAGA;;;AAGA;AACA;;;;;;;AAOA;;;;;;;;;AASA;;AAEA;AACA;;;;AAIA;;AAEA;;;;AAIA;;;AAGA;;;;AAIA;AACA;AACA;;;AAGA;;;;;;AAMA;;AAEA;AACA;;;;AAIA;;;AAGA;;AAEA;;AAEA;AACA;AAIA;;;;;;AAMA;;AAEA;AACA;;AAEA;AAKA;;AAEA;;;;AAIA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;AACA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;;AAMA;;;AAGA;;;AAGA;;AAEA;;;;;;;;AAQA;AACA;;;;;AAKA;AACA;;;;;;;;AAQA;AACA;;;;AAIA;AACA;AACA;;;;;;;;;AASA;AACA;;;;AAIA;AACA;AACA;;;;;AAKA;;;AAGA;AACA;AACA;;;;AAIA;AACA;AACA;;;;;;;;AAQA;AACA;;;;AAIA;;AAEA;AACA;;;AAGA;AACA;;;AAGA;AACA;;;;;;AAMA;AACA;;;;AAIA;AACA;;;;AAIA;;AAEA;;;;;;;;;;AAUA;AACA;AACA;;;AAGA;;;AAGA;;;;AAIA;;;AAGA;AACA;;;;AAIA;AACA;AACA;;;;;;AAMA;AACA;;;;;;;;AAQA;;;;AAIA;;;;AAIA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAocA;;;AAoFA;AACA;AACA;;;AARA;;;;;;AA4BA;AAqGA;;AAEA;;AAEA;AACA;AACA;;;AAGA;;;AAKA;;;;;;;;;AAgBA;;;AAiGA;AACA;;;AAPA;;;;;;AA2BA;;AAmQA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA","sourceRoot":""}
|
||||
{"version":3,"file":"chunk.9a51b75455a6b146cba2.js","sources":["webpack:///chunk.9a51b75455a6b146cba2.js"],"mappings":"AAAA;;;AAoMA;AACA;;;AAGA;;;;;AAKA;;AAEA;AAEA;AACA;;;;;;;AAQA;;;;;AAKA;;AAEA;AAEA;AACA;;;;;;;AAQA;;;;;AAOA;;;;;;;;;;;;;;;;AAuBA;AAinBA;;AAEA;;AAEA;AACA;;AAIA;AA0IA;;;;AAIA;;AAEA;AACA;;;AAGA;;;;AAIA;AACA;;;;;;AAQA;;;;;;;;;;;;;;;;;;;;;;AA6HA;;;AAyGA;AACA;;;;;;;;AAQA;;AAGA;;;AAGA;;AAEA;AACA;;;;AAIA;;;;;;;AAQA;;;AAGA;;;;;AAvCA;;;;;;;;;;;;;;;AA8KA;;;AAkFA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AApBA;;;;;;;;;;;AA4CA;;;AA8GA;;AAEA;;;;AARA;;;;;;;;;;;;AAiCA;;AAiCA;AACA;AACA;;;AAMA;;;;AA6IA;;;AAMA;AACA;;;AAGA;;AAEA;;AAKA;;AAEA;;AAEA;;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6EA;AAsLA;;;;AAIA;AACA;AACA;AACA;;;AAGA;;;;;;;;AAQA;AACA;AACA;;;;AAIA;AACA;;;AAGA;;;AAGA;AACA;;;;;;;AAOA;;;;;;;;;AASA;;AAEA;AACA;;;;AAIA;;AAEA;;;;AAIA;;;AAGA;;;;AAIA;AACA;AACA;;;AAGA;;;;;;AAMA;;AAEA;AACA;;;;AAIA;;;AAGA;;AAEA;;AAEA;AACA;AAIA;;;;;;AAMA;;AAEA;AACA;;AAEA;AAKA;;AAEA;;;;AAIA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;AACA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;AAKA;;AAEA;AACA;;AAEA;;;;;;AAMA;;;AAGA;;;AAGA;;AAEA;;;;;;;;AAQA;AACA;;;;;AAKA;AACA;;;;;;;;AAQA;AACA;;;;AAIA;AACA;AACA;;;;;;;;;AASA;AACA;;;;AAIA;AACA;AACA;;;;;AAKA;;;AAGA;AACA;AACA;;;;AAIA;AACA;AACA;;;;;;;;AAQA;AACA;;;;AAIA;;AAEA;AACA;;;AAGA;AACA;;;AAGA;AACA;;;;;;AAMA;AACA;;;;AAIA;AACA;;;;AAIA;;AAEA;;;;;;;;;;AAUA;AACA;AACA;;;AAGA;;;AAGA;;;;AAIA;;;AAGA;AACA;;;;AAIA;AACA;AACA;;;;;;AAMA;AACA;;;;;;;;AAQA;;;;AAIA;;;;AAIA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAocA;;;AAoFA;AACA;AACA;;;AARA;;;;;;AA4BA;AAqGA;;AAEA;;AAEA;AACA;AACA;;;AAGA;;;AAKA;;;;;;;;;AAgBA;;;AAiGA;AACA;;;AAPA;;;;;;AA2BA;;AAmQA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA","sourceRoot":""}
|
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.ca3bb0345abd1f0a8178.js","sources":["webpack:///chunk.ca3bb0345abd1f0a8178.js"],"mappings":"AAAA;;AAsIA;AACA;;AAEA;;AAEA;;AAEA;AAhBA;AACA;;AAEA;AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0HA","sourceRoot":""}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"version":3,"file":"chunk.d854c37ea42bebe8601c.js","sources":["webpack:///chunk.d854c37ea42bebe8601c.js"],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAy7EA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/frontend_latest/entrypoint.babc4122.js.gz
Normal file
BIN
supervisor/api/panel/frontend_latest/entrypoint.babc4122.js.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,3 +1,3 @@
|
||||
{
|
||||
"entrypoint.js": "/api/hassio/app/frontend_latest/entrypoint.e3f59ee9.js"
|
||||
"entrypoint.js": "/api/hassio/app/frontend_latest/entrypoint.babc4122.js"
|
||||
}
|
@ -240,20 +240,26 @@ def check_environment() -> None:
|
||||
_LOGGER.critical("Can't find gdbus!")
|
||||
|
||||
|
||||
def reg_signal(loop) -> None:
|
||||
def reg_signal(loop, coresys: CoreSys) -> None:
|
||||
"""Register SIGTERM and SIGKILL to stop system."""
|
||||
try:
|
||||
loop.add_signal_handler(signal.SIGTERM, lambda: loop.call_soon(loop.stop))
|
||||
loop.add_signal_handler(
|
||||
signal.SIGTERM, lambda: loop.create_task(coresys.core.stop())
|
||||
)
|
||||
except (ValueError, RuntimeError):
|
||||
_LOGGER.warning("Could not bind to SIGTERM")
|
||||
|
||||
try:
|
||||
loop.add_signal_handler(signal.SIGHUP, lambda: loop.call_soon(loop.stop))
|
||||
loop.add_signal_handler(
|
||||
signal.SIGHUP, lambda: loop.create_task(coresys.core.stop())
|
||||
)
|
||||
except (ValueError, RuntimeError):
|
||||
_LOGGER.warning("Could not bind to SIGHUP")
|
||||
|
||||
try:
|
||||
loop.add_signal_handler(signal.SIGINT, lambda: loop.call_soon(loop.stop))
|
||||
loop.add_signal_handler(
|
||||
signal.SIGINT, lambda: loop.create_task(coresys.core.stop())
|
||||
)
|
||||
except (ValueError, RuntimeError):
|
||||
_LOGGER.warning("Could not bind to SIGINT")
|
||||
|
||||
|
@ -3,7 +3,7 @@ from enum import Enum
|
||||
from ipaddress import ip_network
|
||||
from pathlib import Path
|
||||
|
||||
SUPERVISOR_VERSION = "240"
|
||||
SUPERVISOR_VERSION = "241"
|
||||
|
||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
||||
URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor.txt"
|
||||
@ -32,6 +32,7 @@ FILE_HASSIO_UPDATER = Path(SUPERVISOR_DATA, "updater.json")
|
||||
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")
|
||||
|
||||
DOCKER_NETWORK = "hassio"
|
||||
DOCKER_NETWORK_MASK = ip_network("172.30.32.0/23")
|
||||
@ -395,7 +396,9 @@ class CoreState(str, Enum):
|
||||
STARTUP = "startup"
|
||||
RUNNING = "running"
|
||||
FREEZE = "freeze"
|
||||
SHUTDOWN = "shutdown"
|
||||
STOPPING = "stopping"
|
||||
CLOSE = "close"
|
||||
|
||||
|
||||
class LogLevel(str, Enum):
|
||||
|
@ -2,10 +2,17 @@
|
||||
import asyncio
|
||||
from contextlib import suppress
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import async_timeout
|
||||
|
||||
from .const import SOCKET_DBUS, SUPERVISED_SUPPORTED_OS, AddonStartup, CoreState
|
||||
from .const import (
|
||||
RUN_SUPERVISOR_STATE,
|
||||
SOCKET_DBUS,
|
||||
SUPERVISED_SUPPORTED_OS,
|
||||
AddonStartup,
|
||||
CoreState,
|
||||
)
|
||||
from .coresys import CoreSys, CoreSysAttributes
|
||||
from .exceptions import (
|
||||
DockerAPIError,
|
||||
@ -23,12 +30,31 @@ class Core(CoreSysAttributes):
|
||||
def __init__(self, coresys: CoreSys):
|
||||
"""Initialize Supervisor object."""
|
||||
self.coresys: CoreSys = coresys
|
||||
self.state: CoreState = CoreState.INITIALIZE
|
||||
self.healthy: bool = True
|
||||
self.supported: bool = True
|
||||
|
||||
self._state: Optional[CoreState] = None
|
||||
|
||||
@property
|
||||
def state(self) -> CoreState:
|
||||
"""Return state of the core."""
|
||||
return self._state
|
||||
|
||||
@state.setter
|
||||
def state(self, new_state: CoreState) -> None:
|
||||
"""Set core into new state."""
|
||||
try:
|
||||
RUN_SUPERVISOR_STATE.write_text(new_state.value)
|
||||
except OSError as err:
|
||||
_LOGGER.warning("Can't update supervisor state %s: %s", new_state, err)
|
||||
finally:
|
||||
self._state = new_state
|
||||
|
||||
async def connect(self):
|
||||
"""Connect Supervisor container."""
|
||||
self.state = CoreState.INITIALIZE
|
||||
|
||||
# Load information from container
|
||||
await self.sys_supervisor.load()
|
||||
|
||||
# If host docker is supported?
|
||||
@ -241,8 +267,10 @@ class Core(CoreSysAttributes):
|
||||
async def stop(self):
|
||||
"""Stop a running orchestration."""
|
||||
# store new last boot / prevent time adjustments
|
||||
if self.state == CoreState.RUNNING:
|
||||
if self.state in (CoreState.RUNNING, CoreState.SHUTDOWN):
|
||||
self._update_last_boot()
|
||||
if self.state in (CoreState.STOPPING, CoreState.CLOSE):
|
||||
return
|
||||
|
||||
# don't process scheduler anymore
|
||||
self.state = CoreState.STOPPING
|
||||
@ -269,12 +297,14 @@ class Core(CoreSysAttributes):
|
||||
_LOGGER.warning("Stage 2: Force Shutdown!")
|
||||
|
||||
_LOGGER.info("Supervisor is down")
|
||||
self.state = CoreState.CLOSE
|
||||
self.sys_loop.stop()
|
||||
|
||||
async def shutdown(self):
|
||||
"""Shutdown all running containers in correct order."""
|
||||
# don't process scheduler anymore
|
||||
if self.state == CoreState.RUNNING:
|
||||
self.state = CoreState.STOPPING
|
||||
self.state = CoreState.SHUTDOWN
|
||||
|
||||
# Shutdown Application Add-ons, using Home Assistant API
|
||||
await self.sys_addons.shutdown(AddonStartup.APPLICATION)
|
||||
@ -289,7 +319,7 @@ class Core(CoreSysAttributes):
|
||||
await self.sys_addons.shutdown(AddonStartup.INITIALIZE)
|
||||
|
||||
# Shutdown all Plugins
|
||||
if self.state == CoreState.STOPPING:
|
||||
if self.state in (CoreState.STOPPING, CoreState.SHUTDOWN):
|
||||
await self.sys_plugins.shutdown()
|
||||
|
||||
def _update_last_boot(self):
|
||||
|
@ -68,3 +68,4 @@ class WirelessProperties:
|
||||
|
||||
properties: dict = attr.ib()
|
||||
security: dict = attr.ib()
|
||||
ssid: str = attr.ib()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Connection object for Network Manager."""
|
||||
from typing import Optional
|
||||
|
||||
from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX
|
||||
from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX, ATTR_SSID
|
||||
from ...utils.gdbus import DBus
|
||||
from ..const import (
|
||||
DBUS_ATTR_802_WIRELESS,
|
||||
@ -134,6 +134,7 @@ class NetworkConnection(NetworkAttributes):
|
||||
self._wireless = WirelessProperties(
|
||||
data.get(DBUS_ATTR_802_WIRELESS, {}),
|
||||
data.get(DBUS_ATTR_802_WIRELESS_SECURITY, {}),
|
||||
bytes(data.get(DBUS_ATTR_802_WIRELESS, {}).get(ATTR_SSID, [])).decode(),
|
||||
)
|
||||
|
||||
self._device = NetworkDevice(
|
||||
|
@ -35,10 +35,7 @@ def interface_update_payload(interface, **kwargs) -> str:
|
||||
kwargs[ATTR_SSID] = ", ".join(
|
||||
[
|
||||
f"0x{x}"
|
||||
for x in interface.connection.wireless.properties[ATTR_SSID]
|
||||
.encode()
|
||||
.hex(",")
|
||||
.split(",")
|
||||
for x in interface.connection.wireless.ssid.encode().hex(",").split(",")
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -61,7 +61,10 @@ class Scheduler(CoreSysAttributes):
|
||||
if self.sys_core.state == CoreState.RUNNING:
|
||||
await task.coro_callback()
|
||||
finally:
|
||||
if task.repeat and self.sys_core.state != CoreState.STOPPING:
|
||||
if task.repeat and self.sys_core.state not in (
|
||||
CoreState.STOPPING,
|
||||
CoreState.CLOSE,
|
||||
):
|
||||
self._schedule_task(task)
|
||||
else:
|
||||
self._tasks.remove(task)
|
||||
|
@ -9,6 +9,10 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
class AddonStore(AddonModel):
|
||||
"""Hold data for add-on inside Supervisor."""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return internal representation."""
|
||||
return f"<Store: {self.slug}>"
|
||||
|
||||
@property
|
||||
def data(self) -> Data:
|
||||
"""Return add-on data/config."""
|
||||
|
@ -75,7 +75,12 @@ class StoreData(CoreSysAttributes):
|
||||
def _read_addons_folder(self, path, repository):
|
||||
"""Read data from add-ons folder."""
|
||||
try:
|
||||
addon_list = path.glob("**/config.json")
|
||||
# Generate a list without artefact, safe for corruptions
|
||||
addon_list = [
|
||||
addon
|
||||
for addon in path.glob("**/config.json")
|
||||
if ".git" not in addon.parts
|
||||
]
|
||||
except OSError as err:
|
||||
self.sys_core.healthy = False
|
||||
_LOGGER.critical(
|
||||
@ -85,10 +90,6 @@ class StoreData(CoreSysAttributes):
|
||||
return
|
||||
|
||||
for addon in addon_list:
|
||||
# Ingore git artefacts
|
||||
if ".git" in addon.parts:
|
||||
continue
|
||||
|
||||
try:
|
||||
addon_config = read_json_file(addon)
|
||||
except JsonFileError:
|
||||
|
@ -124,7 +124,7 @@ class Supervisor(CoreSysAttributes):
|
||||
|
||||
with suppress(SupervisorError):
|
||||
await self.update_apparmor()
|
||||
self.sys_loop.call_later(5, self.sys_loop.stop)
|
||||
self.sys_create_task(self.sys_core.stop())
|
||||
|
||||
@property
|
||||
def in_progress(self) -> bool:
|
||||
|
@ -10,6 +10,8 @@ from signal import SIGINT
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import sentry_sdk
|
||||
|
||||
from ..exceptions import (
|
||||
DBusFatalError,
|
||||
DBusInterfaceError,
|
||||
@ -31,7 +33,7 @@ RE_GVARIANT_STRING_ESC: re.Pattern[Any] = re.compile(
|
||||
RE_GVARIANT_STRING: re.Pattern[Any] = re.compile(
|
||||
r"(?<=(?: |{|\[|\(|<))'(.*?)'(?=(?:|]|}|,|\)|>))"
|
||||
)
|
||||
RE_GVARIANT_BINARY: re.Pattern[Any] = re.compile(r"<\[byte (.*?)\]>")
|
||||
RE_GVARIANT_BINARY: re.Pattern[Any] = re.compile(r"\[byte (.*?)\]")
|
||||
RE_GVARIANT_TUPLE_O: re.Pattern[Any] = re.compile(r"\"[^\"\\]*(?:\\.[^\"\\]*)*\"|(\()")
|
||||
RE_GVARIANT_TUPLE_C: re.Pattern[Any] = re.compile(
|
||||
r"\"[^\"\\]*(?:\\.[^\"\\]*)*\"|(,?\))"
|
||||
@ -61,12 +63,7 @@ DBUS_METHOD_GETALL: str = "org.freedesktop.DBus.Properties.GetAll"
|
||||
def _convert_bytes(value: str) -> str:
|
||||
"""Convert bytes to string or byte-array."""
|
||||
data: bytes = bytes(int(char, 0) for char in value.split(", "))
|
||||
try:
|
||||
text = data.decode()
|
||||
except UnicodeDecodeError:
|
||||
return f"<[{', '.join(str(char) for char in data)}]>"
|
||||
|
||||
return f"<'{text}'>"
|
||||
return f"[{', '.join(str(char) for char in data)}]"
|
||||
|
||||
|
||||
class DBus:
|
||||
@ -153,7 +150,8 @@ class DBus:
|
||||
try:
|
||||
return json.loads(json_raw)
|
||||
except json.JSONDecodeError as err:
|
||||
_LOGGER.critical("Can't parse '%s': '%s' - %s", json_raw, raw, err)
|
||||
_LOGGER.error("Can't parse '%s': '%s' - %s", json_raw, raw, err)
|
||||
sentry_sdk.capture_exception(err)
|
||||
raise DBusParseError() from err
|
||||
|
||||
@staticmethod
|
||||
|
@ -90,11 +90,15 @@ async def coresys(loop, docker, dbus, network_manager, aiohttp_client) -> CoreSy
|
||||
):
|
||||
coresys_obj = await initialize_coresys()
|
||||
|
||||
# Mock save json
|
||||
coresys_obj.ingress.save_data = MagicMock()
|
||||
coresys_obj.arch._default_arch = "amd64"
|
||||
|
||||
# Mock test client
|
||||
coresys_obj.arch._default_arch = "amd64"
|
||||
coresys_obj._machine = "qemux86-64"
|
||||
coresys_obj._machine_id = uuid4()
|
||||
|
||||
# Mock host communication
|
||||
coresys_obj._dbus = dbus
|
||||
coresys_obj._dbus.network = network_manager
|
||||
|
||||
|
@ -32,4 +32,4 @@ async def test_interface_update_payload_wireless(network_interface):
|
||||
)
|
||||
assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual"
|
||||
assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1"
|
||||
assert DBus.parse_gvariant(data)["802-11-wireless"]["ssid"] == "NETT"
|
||||
assert DBus.parse_gvariant(data)["802-11-wireless"]["ssid"] == [78, 69, 84, 84]
|
||||
|
33
tests/test_core_state.py
Normal file
33
tests/test_core_state.py
Normal file
@ -0,0 +1,33 @@
|
||||
"""Testing handling with CoreState."""
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from supervisor.const import CoreState
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def run_dir():
|
||||
"""Fixture to inject hassio env."""
|
||||
with patch(
|
||||
"supervisor.core.RUN_SUPERVISOR_STATE"
|
||||
) as mock_run, TemporaryDirectory() as tmp_run:
|
||||
tmp_state = Path(tmp_run, "supervisor")
|
||||
mock_run.write_text = tmp_state.write_text
|
||||
yield tmp_state
|
||||
|
||||
|
||||
def test_write_state(run_dir, coresys):
|
||||
"""Test write corestate to /run/supervisor."""
|
||||
|
||||
coresys.core.state = CoreState.RUNNING
|
||||
|
||||
assert run_dir.read_text() == CoreState.RUNNING.value
|
||||
|
||||
coresys.core.state = CoreState.SHUTDOWN
|
||||
|
||||
assert run_dir.read_text() == CoreState.SHUTDOWN.value
|
@ -325,7 +325,7 @@ def test_networkmanager_binary_data():
|
||||
"mode": "infrastructure",
|
||||
"security": "802-11-wireless-security",
|
||||
"seen-bssids": ["7C:2E:BD:98:1B:06"],
|
||||
"ssid": "NETT",
|
||||
"ssid": [78, 69, 84, 84],
|
||||
},
|
||||
"connection": {
|
||||
"id": "NETT",
|
||||
@ -370,7 +370,7 @@ def test_networkmanager_binary_data():
|
||||
"mode": "infrastructure",
|
||||
"security": "802-11-wireless-security",
|
||||
"seen-bssids": ["7C:2E:BD:98:1B:06"],
|
||||
"ssid": "NETT",
|
||||
"ssid": [78, 69, 84, 84],
|
||||
},
|
||||
"802-11-wireless-security": {"auth-alg": "open", "key-mgmt": "wpa-psk"},
|
||||
"connection": {
|
||||
@ -402,3 +402,23 @@ def test_networkmanager_binary_data():
|
||||
"proxy": {},
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_v6():
|
||||
"""Test IPv6 Property."""
|
||||
raw = "({'addresses': <[([byte 0x20, 0x01, 0x04, 0x70, 0x79, 0x2d, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10], uint32 64, [byte 0x20, 0x01, 0x04, 0x70, 0x79, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])]>, 'dns': <[[byte 0x20, 0x01, 0x04, 0x70, 0x79, 0x2d, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05]]>})"
|
||||
|
||||
data = DBus.parse_gvariant(raw)
|
||||
|
||||
assert data == [
|
||||
{
|
||||
"addresses": [
|
||||
[
|
||||
[32, 1, 4, 112, 121, 45, 0, 1, 0, 18, 0, 0, 0, 0, 0, 16],
|
||||
64,
|
||||
[32, 1, 4, 112, 121, 45, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
]
|
||||
],
|
||||
"dns": [[32, 1, 4, 112, 121, 45, 0, 1, 0, 18, 0, 0, 0, 0, 0, 5]],
|
||||
}
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user