update_manager: add support for extensions
While use of "unofficial" klippy extras an moonraker components is not officially supported, there is no harm in facilitating updates for these extensions in the update manager. This adds configuration which will restart either moonraker or klipper after an extension is updated. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
16737d086d
commit
c8042a5700
|
@ -9,6 +9,7 @@ import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
from .base_deploy import BaseDeploy
|
from .base_deploy import BaseDeploy
|
||||||
|
|
||||||
# Annotation imports
|
# Annotation imports
|
||||||
|
@ -79,8 +80,29 @@ class AppDeploy(BaseDeploy):
|
||||||
self.venv_args = config.get('venv_args', None)
|
self.venv_args = config.get('venv_args', None)
|
||||||
|
|
||||||
self.info_tags: List[str] = config.getlist("info_tags", [])
|
self.info_tags: List[str] = config.getlist("info_tags", [])
|
||||||
self.is_service = config.getboolean("is_system_service", True)
|
self.managed_services: List[str] = []
|
||||||
|
svc_default = []
|
||||||
|
if config.getboolean("is_system_service", True):
|
||||||
|
svc_default.append(self.name)
|
||||||
|
svc_choices = [self.name, "klipper", "moonraker"]
|
||||||
|
services: List[str] = config.getlist(
|
||||||
|
"managed_services", svc_default, separator=None
|
||||||
|
)
|
||||||
|
for svc in services:
|
||||||
|
if svc not in svc_choices:
|
||||||
|
raw = " ".join(services)
|
||||||
|
self.server.add_warning(
|
||||||
|
f"[{config.get_name()}]: Option 'restart_action: {raw}' "
|
||||||
|
f"contains an invalid value '{svc}'. All values must be "
|
||||||
|
f"one of the following choices: {svc_choices}"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
for svc in svc_choices:
|
||||||
|
if svc in services and svc not in self.managed_services:
|
||||||
|
self.managed_services.append(svc)
|
||||||
|
logging.debug(
|
||||||
|
f"Extension {self.name} managed services: {self.managed_services}"
|
||||||
|
)
|
||||||
# We need to fetch all potential options for an Application. Not
|
# We need to fetch all potential options for an Application. Not
|
||||||
# all options apply to each subtype, however we can't limit the
|
# all options apply to each subtype, however we can't limit the
|
||||||
# options in children if we want to switch between channels and
|
# options in children if we want to switch between channels and
|
||||||
|
@ -167,25 +189,30 @@ class AppDeploy(BaseDeploy):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
async def restart_service(self):
|
async def restart_service(self):
|
||||||
if not self.is_service:
|
if not self.managed_services:
|
||||||
self.notify_status(
|
|
||||||
"Application not configured as service, skipping restart")
|
|
||||||
return
|
return
|
||||||
if self.name == "moonraker":
|
is_full = self.cmd_helper.is_full_update()
|
||||||
# Launch restart async so the request can return
|
for svc in self.managed_services:
|
||||||
# before the server restarts
|
if is_full and svc != self.name:
|
||||||
event_loop = self.server.get_event_loop()
|
self.notify_status(f"Service {svc} restart postponed...")
|
||||||
event_loop.delay_callback(.1, self._do_restart)
|
self.cmd_helper.add_pending_restart(svc)
|
||||||
else:
|
continue
|
||||||
await self._do_restart()
|
self.cmd_helper.remove_pending_restart(svc)
|
||||||
|
self.notify_status(f"Restarting service {svc}...")
|
||||||
|
if svc == "moonraker":
|
||||||
|
# Launch restart async so the request can return
|
||||||
|
# before the server restarts
|
||||||
|
event_loop = self.server.get_event_loop()
|
||||||
|
event_loop.delay_callback(.1, self._do_restart, svc)
|
||||||
|
else:
|
||||||
|
await self._do_restart(svc)
|
||||||
|
|
||||||
async def _do_restart(self) -> None:
|
async def _do_restart(self, svc_name: str) -> None:
|
||||||
self.notify_status("Restarting Service...")
|
|
||||||
machine: Machine = self.server.lookup_component("machine")
|
machine: Machine = self.server.lookup_component("machine")
|
||||||
try:
|
try:
|
||||||
await machine.do_service_action("restart", self.name)
|
await machine.do_service_action("restart", svc_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
if self.name == "moonraker":
|
if svc_name == "moonraker":
|
||||||
# We will always get an error when restarting moonraker
|
# We will always get an error when restarting moonraker
|
||||||
# from within the child process, so ignore it
|
# from within the child process, so ignore it
|
||||||
return
|
return
|
||||||
|
|
|
@ -27,6 +27,7 @@ from typing import (
|
||||||
Any,
|
Any,
|
||||||
Awaitable,
|
Awaitable,
|
||||||
Optional,
|
Optional,
|
||||||
|
Set,
|
||||||
Tuple,
|
Tuple,
|
||||||
Type,
|
Type,
|
||||||
Union,
|
Union,
|
||||||
|
@ -324,10 +325,13 @@ class UpdateManager:
|
||||||
kupdater = self.updaters.get('klipper')
|
kupdater = self.updaters.get('klipper')
|
||||||
if isinstance(kupdater, AppDeploy):
|
if isinstance(kupdater, AppDeploy):
|
||||||
self.klippy_identified_evt = asyncio.Event()
|
self.klippy_identified_evt = asyncio.Event()
|
||||||
klippy_updated = True
|
check_restart = True
|
||||||
if not await self._check_need_reinstall(app_name):
|
if not await self._check_need_reinstall(app_name):
|
||||||
klippy_updated = await kupdater.update()
|
check_restart = await kupdater.update()
|
||||||
if klippy_updated:
|
if self.cmd_helper.needs_service_restart(app_name):
|
||||||
|
await kupdater.restart_service()
|
||||||
|
check_restart = True
|
||||||
|
if check_restart:
|
||||||
self.cmd_helper.notify_update_response(
|
self.cmd_helper.notify_update_response(
|
||||||
"Waiting for Klippy to reconnect (this may take"
|
"Waiting for Klippy to reconnect (this may take"
|
||||||
" up to 2 minutes)...")
|
" up to 2 minutes)...")
|
||||||
|
@ -344,8 +348,11 @@ class UpdateManager:
|
||||||
|
|
||||||
# Update Moonraker
|
# Update Moonraker
|
||||||
app_name = 'moonraker'
|
app_name = 'moonraker'
|
||||||
|
moon_updater = cast(AppDeploy, self.updaters["moonraker"])
|
||||||
if not await self._check_need_reinstall(app_name):
|
if not await self._check_need_reinstall(app_name):
|
||||||
await self.updaters['moonraker'].update()
|
await moon_updater.update()
|
||||||
|
if self.cmd_helper.needs_service_restart(app_name):
|
||||||
|
await moon_updater.restart_service()
|
||||||
self.cmd_helper.set_full_complete(True)
|
self.cmd_helper.set_full_complete(True)
|
||||||
self.cmd_helper.notify_update_response(
|
self.cmd_helper.notify_update_response(
|
||||||
"Full Update Complete", is_complete=True)
|
"Full Update Complete", is_complete=True)
|
||||||
|
@ -490,6 +497,7 @@ class CommandHelper:
|
||||||
self.cur_update_id: Optional[int] = None
|
self.cur_update_id: Optional[int] = None
|
||||||
self.full_update: bool = False
|
self.full_update: bool = False
|
||||||
self.full_complete: bool = False
|
self.full_complete: bool = False
|
||||||
|
self.pending_service_restarts: Set[str] = set()
|
||||||
|
|
||||||
def get_server(self) -> Server:
|
def get_server(self) -> Server:
|
||||||
return self.server
|
return self.server
|
||||||
|
@ -511,10 +519,18 @@ class CommandHelper:
|
||||||
self.cur_update_id = uid
|
self.cur_update_id = uid
|
||||||
self.full_update = app == "full"
|
self.full_update = app == "full"
|
||||||
self.full_complete = not self.full_update
|
self.full_complete = not self.full_update
|
||||||
|
self.pending_service_restarts.clear()
|
||||||
|
|
||||||
def is_full_update(self) -> bool:
|
def is_full_update(self) -> bool:
|
||||||
return self.full_update
|
return self.full_update
|
||||||
|
|
||||||
|
def add_pending_restart(self, svc_name: str) -> None:
|
||||||
|
self.pending_service_restarts.add(svc_name)
|
||||||
|
|
||||||
|
def remove_pending_restart(self, svc_name: str) -> None:
|
||||||
|
if svc_name in self.pending_service_restarts:
|
||||||
|
self.pending_service_restarts.remove(svc_name)
|
||||||
|
|
||||||
def set_full_complete(self, complete: bool = False):
|
def set_full_complete(self, complete: bool = False):
|
||||||
self.full_complete = complete
|
self.full_complete = complete
|
||||||
|
|
||||||
|
@ -522,6 +538,10 @@ class CommandHelper:
|
||||||
self.cur_update_app = self.cur_update_id = None
|
self.cur_update_app = self.cur_update_id = None
|
||||||
self.full_update = False
|
self.full_update = False
|
||||||
self.full_complete = False
|
self.full_complete = False
|
||||||
|
self.pending_service_restarts.clear()
|
||||||
|
|
||||||
|
def needs_service_restart(self, svc_name: str) -> bool:
|
||||||
|
return svc_name in self.pending_service_restarts
|
||||||
|
|
||||||
def is_app_updating(self, app_name: str) -> bool:
|
def is_app_updating(self, app_name: str) -> bool:
|
||||||
return self.cur_update_app == app_name
|
return self.cur_update_app == app_name
|
||||||
|
|
Loading…
Reference in New Issue