update_manager: make sure than all updaters are intialized before updating status

It is possible that a status request can occur while an updater is checking intial state.  Use an event to wait on initializing before returning the status request.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2020-12-19 07:40:23 -05:00
parent 653c9190c4
commit 6898ff8ab6
1 changed files with 34 additions and 14 deletions

View File

@ -15,6 +15,7 @@ import asyncio
import tornado.gen import tornado.gen
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.httpclient import AsyncHTTPClient, HTTPRequest
from tornado.locks import Event
MOONRAKER_PATH = os.path.normpath(os.path.join( MOONRAKER_PATH = os.path.normpath(os.path.join(
os.path.dirname(__file__), "../..")) os.path.dirname(__file__), "../.."))
@ -89,12 +90,6 @@ class UpdateManager:
env = kinfo['python_path'] env = kinfo['python_path']
self.updaters['klipper'] = GitUpdater(self, "klipper", kpath, env) self.updaters['klipper'] = GitUpdater(self, "klipper", kpath, env)
async def _refresh_git_repo_state(self):
for updater in self.updaters.values():
ret = updater.refresh_update_state()
if asyncio.iscoroutine(ret):
await ret
async def _handle_update_request(self, web_request): async def _handle_update_request(self, web_request):
app = web_request.get_endpoint().split("/")[-1] app = web_request.get_endpoint().split("/")[-1]
inc_deps = web_request.get_boolean('include_deps', False) inc_deps = web_request.get_boolean('include_deps', False)
@ -113,10 +108,14 @@ class UpdateManager:
return "ok" return "ok"
async def _handle_status_request(self, web_request): async def _handle_status_request(self, web_request):
if web_request.get_boolean('refresh', False): refresh = web_request.get_boolean('refresh', False)
await self._refresh_git_repo_state()
vinfo = {} vinfo = {}
for name, updater in self.updaters.items(): for name, updater in self.updaters.items():
await updater.check_initialized(10.)
if refresh:
ret = updater.refresh()
if asyncio.iscoroutine(ret):
await ret
if hasattr(updater, "get_update_status"): if hasattr(updater, "get_update_status"):
vinfo[name] = updater.get_update_status() vinfo[name] = updater.get_update_status()
return { return {
@ -195,8 +194,9 @@ class GitUpdater:
self.repo_path = path self.repo_path = path
self.env = env self.env = env
self.version = self.cur_hash = self.remote_hash = "?" self.version = self.cur_hash = self.remote_hash = "?"
self.init_evt = Event()
self.is_valid = self.is_dirty = False self.is_valid = self.is_dirty = False
IOLoop.current().spawn_callback(self.refresh_update_state) IOLoop.current().spawn_callback(self.refresh)
def _get_version_info(self): def _get_version_info(self):
ver_path = os.path.join(self.repo_path, "scripts/version.txt") ver_path = os.path.join(self.repo_path, "scripts/version.txt")
@ -234,7 +234,14 @@ class GitUpdater:
logging.debug(log_msg) logging.debug(log_msg)
self.notify_update_response(log_msg, is_complete) self.notify_update_response(log_msg, is_complete)
async def refresh_update_state(self): async def check_initialized(self, timeout=None):
if self.init_evt.is_set():
return
if timeout is not None:
to = IOLoop.current.time() + timeout
await self.init_evt.wait(to)
async def refresh(self):
self.is_valid = False self.is_valid = False
self.cur_hash = "?" self.cur_hash = "?"
try: try:
@ -277,6 +284,7 @@ class GitUpdater:
await self.check_remote_version() await self.check_remote_version()
except Exception: except Exception:
pass pass
self.init_evt.set()
async def check_remote_version(self): async def check_remote_version(self):
repo_url = REPO_DATA[self.name]['repo_url'] repo_url = REPO_DATA[self.name]['repo_url']
@ -408,11 +416,14 @@ class PackageUpdater:
self.execute_cmd = umgr.execute_cmd self.execute_cmd = umgr.execute_cmd
self.notify_update_response = umgr.notify_update_response self.notify_update_response = umgr.notify_update_response
def refresh_update_state(self): def refresh(self):
# TODO: We should be able to determine if packages need to be # TODO: We should be able to determine if packages need to be
# updated here # updated here
pass pass
async def check_initialized(self, timeout=None):
pass
async def update(self, *args): async def update(self, *args):
self.notify_update_response("Updating packages...") self.notify_update_response("Updating packages...")
try: try:
@ -434,11 +445,12 @@ class ClientUpdater:
self.name = self.repo.split("/")[-1] self.name = self.repo.split("/")[-1]
self.path = path self.path = path
self.version = self.remote_version = self.dl_url = "?" self.version = self.remote_version = self.dl_url = "?"
self.init_evt = Event()
self._get_local_version() self._get_local_version()
logging.info(f"\nInitializing Client Updater: '{self.name}'," logging.info(f"\nInitializing Client Updater: '{self.name}',"
f"\nversion: {self.version}" f"\nversion: {self.version}"
f"\npath: {self.path}") f"\npath: {self.path}")
IOLoop.current().spawn_callback(self.refresh_update_state) IOLoop.current().spawn_callback(self.refresh)
def _get_local_version(self): def _get_local_version(self):
version_path = os.path.join(self.path, ".version") version_path = os.path.join(self.path, ".version")
@ -447,7 +459,14 @@ class ClientUpdater:
v = f.read() v = f.read()
self.version = v.strip() self.version = v.strip()
async def refresh_update_state(self): async def check_initialized(self, timeout=None):
if self.init_evt.is_set():
return
if timeout is not None:
to = IOLoop.current.time() + timeout
await self.init_evt.wait(to)
async def refresh(self):
# Local state # Local state
self._get_local_version() self._get_local_version()
@ -465,10 +484,11 @@ class ClientUpdater:
f"Github client Info Received: {self.name}, " f"Github client Info Received: {self.name}, "
f"version: {self.remote_version} " f"version: {self.remote_version} "
f"url: {self.dl_url}") f"url: {self.dl_url}")
self.init_evt.set()
async def update(self, *args): async def update(self, *args):
if self.remote_version == "?": if self.remote_version == "?":
await self.check_remote_version() await self.refresh()
if self.remote_version == "?": if self.remote_version == "?":
raise self.server.error( raise self.server.error(
f"Client {self.repo}: Unable to locate update") f"Client {self.repo}: Unable to locate update")