mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-19 07:06:30 +00:00
Soft restart supervisor (#2281)
* Add softrestart to supervisor * decouble * adjust logger * make sure it need run * Use job condition * add more job running
This commit is contained in:
parent
1427e0ae96
commit
7e94537e36
@ -1,5 +1,8 @@
|
||||
#!/usr/bin/execlineb -S0
|
||||
#!/usr/bin/execlineb -S1
|
||||
# ==============================================================================
|
||||
# Take down the S6 supervision tree when Supervisor fails
|
||||
# ==============================================================================
|
||||
if { s6-test ${1} -ne 100 }
|
||||
if { s6-test ${1} -ne 256 }
|
||||
|
||||
redirfd -w 2 /dev/null s6-svscanctl -t /var/run/s6/services
|
||||
|
@ -60,4 +60,4 @@ if __name__ == "__main__":
|
||||
loop.close()
|
||||
|
||||
_LOGGER.info("Closing Supervisor")
|
||||
sys.exit(0)
|
||||
sys.exit(coresys.core.exit_code)
|
||||
|
@ -251,6 +251,7 @@ class RestAPI(CoreSysAttributes):
|
||||
web.get("/supervisor/logs", api_supervisor.logs),
|
||||
web.post("/supervisor/update", api_supervisor.update),
|
||||
web.post("/supervisor/reload", api_supervisor.reload),
|
||||
web.post("/supervisor/restart", api_supervisor.restart),
|
||||
web.post("/supervisor/options", api_supervisor.options),
|
||||
web.post("/supervisor/repair", api_supervisor.repair),
|
||||
]
|
||||
|
@ -195,6 +195,11 @@ class APISupervisor(CoreSysAttributes):
|
||||
"""Try to repair the local setup / overlayfs."""
|
||||
return asyncio.shield(self.sys_core.repair())
|
||||
|
||||
@api_process
|
||||
def restart(self, request: web.Request) -> Awaitable[None]:
|
||||
"""Soft restart Supervisor."""
|
||||
return asyncio.shield(self.sys_supervisor.restart())
|
||||
|
||||
@api_process_raw(CONTENT_TYPE_BINARY)
|
||||
def logs(self, request: web.Request) -> Awaitable[bytes]:
|
||||
"""Return supervisor Docker logs."""
|
||||
|
@ -26,6 +26,7 @@ class Core(CoreSysAttributes):
|
||||
"""Initialize Supervisor object."""
|
||||
self.coresys: CoreSys = coresys
|
||||
self._state: Optional[CoreState] = None
|
||||
self.exit_code: int = 0
|
||||
|
||||
@property
|
||||
def state(self) -> CoreState:
|
||||
@ -257,7 +258,7 @@ class Core(CoreSysAttributes):
|
||||
_LOGGER.warning("Stage 2: Force Shutdown!")
|
||||
|
||||
self.state = CoreState.CLOSE
|
||||
_LOGGER.info("Supervisor is down")
|
||||
_LOGGER.info("Supervisor is down - %d", self.exit_code)
|
||||
self.sys_loop.stop()
|
||||
|
||||
async def shutdown(self):
|
||||
|
@ -20,6 +20,7 @@ class JobCondition(str, Enum):
|
||||
HEALTHY = "healthy"
|
||||
INTERNET_SYSTEM = "internet_system"
|
||||
INTERNET_HOST = "internet_host"
|
||||
RUNNING = "running"
|
||||
|
||||
|
||||
class Job:
|
||||
@ -83,6 +84,14 @@ class Job:
|
||||
)
|
||||
return False
|
||||
|
||||
if JobCondition.RUNNING in self.conditions:
|
||||
if self._coresys.core.state != CoreState.RUNNING:
|
||||
_LOGGER.warning(
|
||||
"'%s' blocked from execution, system is not running",
|
||||
self._method.__qualname__,
|
||||
)
|
||||
return False
|
||||
|
||||
if JobCondition.FREE_SPACE in self.conditions:
|
||||
free_space = self._coresys.host.info.free_space
|
||||
if free_space < MINIMUM_FREE_SPACE_THRESHOLD:
|
||||
|
@ -125,6 +125,7 @@ class Tasks(CoreSysAttributes):
|
||||
JobCondition.HEALTHY,
|
||||
JobCondition.FREE_SPACE,
|
||||
JobCondition.INTERNET_HOST,
|
||||
JobCondition.RUNNING,
|
||||
]
|
||||
)
|
||||
async def _update_addons(self):
|
||||
@ -150,7 +151,13 @@ class Tasks(CoreSysAttributes):
|
||||
except AddonsError:
|
||||
_LOGGER.error("Can't auto update Add-on %s", addon.slug)
|
||||
|
||||
@Job(conditions=[JobCondition.FREE_SPACE, JobCondition.INTERNET_HOST])
|
||||
@Job(
|
||||
conditions=[
|
||||
JobCondition.FREE_SPACE,
|
||||
JobCondition.INTERNET_HOST,
|
||||
JobCondition.RUNNING,
|
||||
]
|
||||
)
|
||||
async def _update_supervisor(self):
|
||||
"""Check and run update of Supervisor Supervisor."""
|
||||
if not self.sys_supervisor.need_update:
|
||||
@ -231,6 +238,7 @@ class Tasks(CoreSysAttributes):
|
||||
finally:
|
||||
self._cache[HASS_WATCHDOG_API] = 0
|
||||
|
||||
@Job(conditions=JobCondition.RUNNING)
|
||||
async def _update_cli(self):
|
||||
"""Check and run update of cli."""
|
||||
if not self.sys_plugins.cli.need_update:
|
||||
@ -241,6 +249,7 @@ class Tasks(CoreSysAttributes):
|
||||
)
|
||||
await self.sys_plugins.cli.update()
|
||||
|
||||
@Job(conditions=JobCondition.RUNNING)
|
||||
async def _update_dns(self):
|
||||
"""Check and run update of CoreDNS plugin."""
|
||||
if not self.sys_plugins.dns.need_update:
|
||||
@ -252,6 +261,7 @@ class Tasks(CoreSysAttributes):
|
||||
)
|
||||
await self.sys_plugins.dns.update()
|
||||
|
||||
@Job(conditions=JobCondition.RUNNING)
|
||||
async def _update_audio(self):
|
||||
"""Check and run update of PulseAudio plugin."""
|
||||
if not self.sys_plugins.audio.need_update:
|
||||
@ -263,6 +273,7 @@ class Tasks(CoreSysAttributes):
|
||||
)
|
||||
await self.sys_plugins.audio.update()
|
||||
|
||||
@Job(conditions=JobCondition.RUNNING)
|
||||
async def _update_observer(self):
|
||||
"""Check and run update of Observer plugin."""
|
||||
if not self.sys_plugins.observer.need_update:
|
||||
@ -274,6 +285,7 @@ class Tasks(CoreSysAttributes):
|
||||
)
|
||||
await self.sys_plugins.observer.update()
|
||||
|
||||
@Job(conditions=JobCondition.RUNNING)
|
||||
async def _update_multicast(self):
|
||||
"""Check and run update of multicast."""
|
||||
if not self.sys_plugins.multicast.need_update:
|
||||
|
@ -11,6 +11,8 @@ import aiohttp
|
||||
from aiohttp.client_exceptions import ClientError
|
||||
from packaging.version import parse as pkg_parse
|
||||
|
||||
from supervisor.jobs.decorator import Job, JobCondition
|
||||
|
||||
from .const import SUPERVISOR_VERSION, URL_HASSIO_APPARMOR
|
||||
from .coresys import CoreSys, CoreSysAttributes
|
||||
from .docker.stats import DockerStats
|
||||
@ -144,6 +146,12 @@ class Supervisor(CoreSysAttributes):
|
||||
await self.update_apparmor()
|
||||
self.sys_create_task(self.sys_core.stop())
|
||||
|
||||
@Job(conditions=[JobCondition.RUNNING])
|
||||
async def restart(self) -> None:
|
||||
"""Restart Supervisor soft."""
|
||||
self.sys_core.exit_code = 100
|
||||
self.sys_create_task(self.sys_core.stop())
|
||||
|
||||
@property
|
||||
def in_progress(self) -> bool:
|
||||
"""Return True if a task is in progress."""
|
||||
|
@ -181,3 +181,27 @@ async def test_exception_not_handle(coresys: CoreSys):
|
||||
|
||||
with pytest.raises(JobException):
|
||||
assert await test.execute()
|
||||
|
||||
|
||||
async def test_running(coresys: CoreSys):
|
||||
"""Test the running decorator."""
|
||||
|
||||
class TestClass:
|
||||
"""Test class."""
|
||||
|
||||
def __init__(self, coresys: CoreSys):
|
||||
"""Initialize the test class."""
|
||||
self.coresys = coresys
|
||||
|
||||
@Job(conditions=[JobCondition.RUNNING])
|
||||
async def execute(self):
|
||||
"""Execute the class method."""
|
||||
return True
|
||||
|
||||
test = TestClass(coresys)
|
||||
|
||||
coresys.core.state = CoreState.RUNNING
|
||||
assert await test.execute()
|
||||
|
||||
coresys.core.state = CoreState.FREEZE
|
||||
assert not await test.execute()
|
||||
|
Loading…
x
Reference in New Issue
Block a user