update_manager: create a CommandHelper class
This class handles running shell commands and sending http API requests. Each updater class shares an instance of the command helper rather than the UpdateManager instance. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
22b3a953c5
commit
9632465a78
|
@ -39,20 +39,18 @@ class UpdateManager:
|
||||||
self.server = config.get_server()
|
self.server = config.get_server()
|
||||||
self.config = config
|
self.config = config
|
||||||
self.config.read_supplemental_config(SUPPLEMENTAL_CFG_PATH)
|
self.config.read_supplemental_config(SUPPLEMENTAL_CFG_PATH)
|
||||||
self.repo_debug = config.getboolean('enable_repo_debug', False)
|
|
||||||
auto_refresh_enabled = config.getboolean('enable_auto_refresh', False)
|
auto_refresh_enabled = config.getboolean('enable_auto_refresh', False)
|
||||||
self.distro = config.get('distro', "debian").lower()
|
self.distro = config.get('distro', "debian").lower()
|
||||||
if self.distro not in SUPPORTED_DISTROS:
|
if self.distro not in SUPPORTED_DISTROS:
|
||||||
raise config.error(f"Unsupported distro: {self.distro}")
|
raise config.error(f"Unsupported distro: {self.distro}")
|
||||||
if self.repo_debug:
|
self.cmd_helper = CommandHelper(config)
|
||||||
logging.warn("UPDATE MANAGER: REPO DEBUG ENABLED")
|
|
||||||
env = sys.executable
|
env = sys.executable
|
||||||
mooncfg = self.config[f"update_manager static {self.distro} moonraker"]
|
mooncfg = self.config[f"update_manager static {self.distro} moonraker"]
|
||||||
self.updaters = {
|
self.updaters = {
|
||||||
"system": PackageUpdater(self),
|
"system": PackageUpdater(self.cmd_helper),
|
||||||
"moonraker": GitUpdater(self, mooncfg, MOONRAKER_PATH, env)
|
"moonraker": GitUpdater(mooncfg, self.cmd_helper,
|
||||||
|
MOONRAKER_PATH, env)
|
||||||
}
|
}
|
||||||
self.current_update = None
|
|
||||||
# TODO: Check for client config in [update_manager]. This is
|
# TODO: Check for client config in [update_manager]. This is
|
||||||
# deprecated and will be removed.
|
# deprecated and will be removed.
|
||||||
client_repo = config.get("client_repo", None)
|
client_repo = config.get("client_repo", None)
|
||||||
|
@ -60,7 +58,8 @@ class UpdateManager:
|
||||||
client_path = config.get("client_path")
|
client_path = config.get("client_path")
|
||||||
name = client_repo.split("/")[-1]
|
name = client_repo.split("/")[-1]
|
||||||
self.updaters[name] = WebUpdater(
|
self.updaters[name] = WebUpdater(
|
||||||
self, {'repo': client_repo, 'path': client_path})
|
{'repo': client_repo, 'path': client_path},
|
||||||
|
self.cmd_helper)
|
||||||
client_sections = self.config.get_prefix_sections(
|
client_sections = self.config.get_prefix_sections(
|
||||||
"update_manager client")
|
"update_manager client")
|
||||||
for section in client_sections:
|
for section in client_sections:
|
||||||
|
@ -71,18 +70,13 @@ class UpdateManager:
|
||||||
% (name,))
|
% (name,))
|
||||||
client_type = cfg.get("type")
|
client_type = cfg.get("type")
|
||||||
if client_type == "git_repo":
|
if client_type == "git_repo":
|
||||||
self.updaters[name] = GitUpdater(self, cfg)
|
self.updaters[name] = GitUpdater(cfg, self.cmd_helper)
|
||||||
elif client_type == "web":
|
elif client_type == "web":
|
||||||
self.updaters[name] = WebUpdater(self, cfg)
|
self.updaters[name] = WebUpdater(cfg, self.cmd_helper)
|
||||||
else:
|
else:
|
||||||
raise config.error("Invalid type '%s' for section [%s]"
|
raise config.error("Invalid type '%s' for section [%s]"
|
||||||
% (client_type, section))
|
% (client_type, section))
|
||||||
|
|
||||||
# GitHub API Rate Limit Tracking
|
|
||||||
self.gh_rate_limit = None
|
|
||||||
self.gh_limit_remaining = None
|
|
||||||
self.gh_limit_reset_time = None
|
|
||||||
self.gh_init_evt = Event()
|
|
||||||
self.cmd_request_lock = Lock()
|
self.cmd_request_lock = Lock()
|
||||||
self.is_refreshing = False
|
self.is_refreshing = False
|
||||||
|
|
||||||
|
@ -94,9 +88,6 @@ class UpdateManager:
|
||||||
self._handle_auto_refresh, UPDATE_REFRESH_INTERVAL_MS)
|
self._handle_auto_refresh, UPDATE_REFRESH_INTERVAL_MS)
|
||||||
self.refresh_cb.start()
|
self.refresh_cb.start()
|
||||||
|
|
||||||
AsyncHTTPClient.configure(None, defaults=dict(user_agent="Moonraker"))
|
|
||||||
self.http_client = AsyncHTTPClient()
|
|
||||||
|
|
||||||
self.server.register_endpoint(
|
self.server.register_endpoint(
|
||||||
"/machine/update/moonraker", ["POST"],
|
"/machine/update/moonraker", ["POST"],
|
||||||
self._handle_update_request)
|
self._handle_update_request)
|
||||||
|
@ -124,7 +115,7 @@ class UpdateManager:
|
||||||
|
|
||||||
async def _initalize_updaters(self, initial_updaters):
|
async def _initalize_updaters(self, initial_updaters):
|
||||||
self.is_refreshing = True
|
self.is_refreshing = True
|
||||||
await self._init_api_rate_limit()
|
await self.cmd_helper.init_api_rate_limit()
|
||||||
for updater in initial_updaters:
|
for updater in initial_updaters:
|
||||||
if isinstance(updater, PackageUpdater):
|
if isinstance(updater, PackageUpdater):
|
||||||
ret = updater.refresh(False)
|
ret = updater.refresh(False)
|
||||||
|
@ -147,7 +138,7 @@ class UpdateManager:
|
||||||
# Current Klipper Updater is valid
|
# Current Klipper Updater is valid
|
||||||
return
|
return
|
||||||
kcfg = self.config[f"update_manager static {self.distro} klipper"]
|
kcfg = self.config[f"update_manager static {self.distro} klipper"]
|
||||||
self.updaters['klipper'] = GitUpdater(self, kcfg, kpath, env)
|
self.updaters['klipper'] = GitUpdater(kcfg, self.cmd_helper, kpath, env)
|
||||||
await self.updaters['klipper'].refresh()
|
await self.updaters['klipper'].refresh()
|
||||||
|
|
||||||
async def _check_klippy_printing(self):
|
async def _check_klippy_printing(self):
|
||||||
|
@ -188,12 +179,9 @@ class UpdateManager:
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
self.is_refreshing = False
|
self.is_refreshing = False
|
||||||
uinfo = {
|
uinfo = self.cmd_helper.get_rate_limit_stats()
|
||||||
'version_info': vinfo,
|
uinfo['version_info'] = vinfo
|
||||||
'github_rate_limit': self.gh_rate_limit,
|
uinfo['busy'] = self.cmd_helper.is_update_busy()
|
||||||
'github_requests_remaining': self.gh_limit_remaining,
|
|
||||||
'github_limit_reset_time': self.gh_limit_reset_time,
|
|
||||||
'busy': self.current_update is not None}
|
|
||||||
self.server.send_event("update_manager:update_refreshed", uinfo)
|
self.server.send_event("update_manager:update_refreshed", uinfo)
|
||||||
|
|
||||||
async def _handle_update_request(self, web_request):
|
async def _handle_update_request(self, web_request):
|
||||||
|
@ -203,22 +191,23 @@ class UpdateManager:
|
||||||
if app == "client":
|
if app == "client":
|
||||||
app = web_request.get('name')
|
app = web_request.get('name')
|
||||||
inc_deps = web_request.get_boolean('include_deps', False)
|
inc_deps = web_request.get_boolean('include_deps', False)
|
||||||
if self.current_update is not None and \
|
if self.cmd_helper.is_app_updating(app):
|
||||||
self.current_update[0] == app:
|
|
||||||
return f"Object {app} is currently being updated"
|
return f"Object {app} is currently being updated"
|
||||||
updater = self.updaters.get(app, None)
|
updater = self.updaters.get(app, None)
|
||||||
if updater is None:
|
if updater is None:
|
||||||
raise self.server.error(f"Updater {app} not available")
|
raise self.server.error(f"Updater {app} not available")
|
||||||
async with self.cmd_request_lock:
|
async with self.cmd_request_lock:
|
||||||
self.current_update = (app, id(web_request))
|
self.cmd_helper.set_update_info(app, id(web_request))
|
||||||
try:
|
try:
|
||||||
await updater.update(inc_deps)
|
await updater.update(inc_deps)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.notify_update_response(f"Error updating {app}")
|
self.cmd_helper.notify_update_response(
|
||||||
self.notify_update_response(str(e), is_complete=True)
|
f"Error updating {app}")
|
||||||
|
self.cmd_helper.notify_update_response(
|
||||||
|
str(e), is_complete=True)
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self.current_update = None
|
self.cmd_helper.clear_update_info()
|
||||||
return "ok"
|
return "ok"
|
||||||
|
|
||||||
async def _handle_status_request(self, web_request):
|
async def _handle_status_request(self, web_request):
|
||||||
|
@ -226,7 +215,7 @@ class UpdateManager:
|
||||||
# Don't refresh if a print is currently in progress or
|
# Don't refresh if a print is currently in progress or
|
||||||
# if an update is in progress. Just return the current
|
# if an update is in progress. Just return the current
|
||||||
# state
|
# state
|
||||||
if self.current_update is not None or \
|
if self.cmd_helper.is_update_busy() or \
|
||||||
await self._check_klippy_printing():
|
await self._check_klippy_printing():
|
||||||
check_refresh = False
|
check_refresh = False
|
||||||
need_refresh = False
|
need_refresh = False
|
||||||
|
@ -252,42 +241,64 @@ class UpdateManager:
|
||||||
if check_refresh:
|
if check_refresh:
|
||||||
self.is_refreshing = False
|
self.is_refreshing = False
|
||||||
self.cmd_request_lock.release()
|
self.cmd_request_lock.release()
|
||||||
|
ret = self.cmd_helper.get_rate_limit_stats()
|
||||||
|
ret['version_info'] = vinfo
|
||||||
|
ret['busy'] = self.cmd_helper.is_update_busy()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.cmd_helper.close()
|
||||||
|
if self.refresh_cb is not None:
|
||||||
|
self.refresh_cb.stop()
|
||||||
|
|
||||||
|
class CommandHelper:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.server = config.get_server()
|
||||||
|
self.debug_enabled = config.getboolean('enable_repo_debug', False)
|
||||||
|
if self.debug_enabled:
|
||||||
|
logging.warn("UPDATE MANAGER: REPO DEBUG ENABLED")
|
||||||
|
shell_command = self.server.lookup_plugin('shell_command')
|
||||||
|
self.build_shell_command = shell_command.build_shell_command
|
||||||
|
|
||||||
|
AsyncHTTPClient.configure(None, defaults=dict(user_agent="Moonraker"))
|
||||||
|
self.http_client = AsyncHTTPClient()
|
||||||
|
|
||||||
|
# GitHub API Rate Limit Tracking
|
||||||
|
self.gh_rate_limit = None
|
||||||
|
self.gh_limit_remaining = None
|
||||||
|
self.gh_limit_reset_time = None
|
||||||
|
self.gh_init_evt = Event()
|
||||||
|
|
||||||
|
# Update In Progress Tracking
|
||||||
|
self.cur_update_app = self.cur_update_id = None
|
||||||
|
|
||||||
|
def get_server(self):
|
||||||
|
return self.server
|
||||||
|
|
||||||
|
def is_debug_enabled(self):
|
||||||
|
return self.debug_enabled
|
||||||
|
|
||||||
|
def set_update_info(self, app, uid):
|
||||||
|
self.cur_update_app = app
|
||||||
|
self.cur_update_id = uid
|
||||||
|
|
||||||
|
def clear_update_info(self):
|
||||||
|
self.cur_update_app = self.cur_update_id = None
|
||||||
|
|
||||||
|
def is_app_updating(self, app_name):
|
||||||
|
return self.cur_update_app == app_name
|
||||||
|
|
||||||
|
def is_update_busy(self):
|
||||||
|
return self.cur_update_app is not None
|
||||||
|
|
||||||
|
def get_rate_limit_stats(self):
|
||||||
return {
|
return {
|
||||||
'version_info': vinfo,
|
|
||||||
'github_rate_limit': self.gh_rate_limit,
|
'github_rate_limit': self.gh_rate_limit,
|
||||||
'github_requests_remaining': self.gh_limit_remaining,
|
'github_requests_remaining': self.gh_limit_remaining,
|
||||||
'github_limit_reset_time': self.gh_limit_reset_time,
|
'github_limit_reset_time': self.gh_limit_reset_time,
|
||||||
'busy': self.current_update is not None}
|
}
|
||||||
|
|
||||||
async def execute_cmd(self, cmd, timeout=10., notify=False,
|
async def init_api_rate_limit(self):
|
||||||
retries=1, env=None):
|
|
||||||
shell_command = self.server.lookup_plugin('shell_command')
|
|
||||||
if env is not None:
|
|
||||||
os_env = dict(os.environ)
|
|
||||||
os_env.update(env)
|
|
||||||
env = os_env
|
|
||||||
cb = self.notify_update_response if notify else None
|
|
||||||
scmd = shell_command.build_shell_command(cmd, callback=cb, env=env)
|
|
||||||
while retries:
|
|
||||||
if await scmd.run(timeout=timeout, verbose=notify):
|
|
||||||
break
|
|
||||||
retries -= 1
|
|
||||||
if not retries:
|
|
||||||
raise self.server.error("Shell Command Error")
|
|
||||||
|
|
||||||
async def execute_cmd_with_response(self, cmd, timeout=10., env=None):
|
|
||||||
shell_command = self.server.lookup_plugin('shell_command')
|
|
||||||
if env is not None:
|
|
||||||
os_env = dict(os.environ)
|
|
||||||
os_env.update(env)
|
|
||||||
env = os_env
|
|
||||||
scmd = shell_command.build_shell_command(cmd, None, env=env)
|
|
||||||
result = await scmd.run_with_response(timeout, retries=5)
|
|
||||||
if result is None:
|
|
||||||
raise self.server.error(f"Error Running Command: {cmd}")
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def _init_api_rate_limit(self):
|
|
||||||
url = "https://api.github.com/rate_limit"
|
url = "https://api.github.com/rate_limit"
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
try:
|
||||||
|
@ -310,6 +321,24 @@ class UpdateManager:
|
||||||
break
|
break
|
||||||
self.gh_init_evt.set()
|
self.gh_init_evt.set()
|
||||||
|
|
||||||
|
async def run_cmd(self, cmd, timeout=10., notify=False,
|
||||||
|
retries=1, env=None):
|
||||||
|
cb = self.notify_update_response if notify else None
|
||||||
|
scmd = self.build_shell_command(cmd, callback=cb, env=env)
|
||||||
|
while retries:
|
||||||
|
if await scmd.run(timeout=timeout):
|
||||||
|
break
|
||||||
|
retries -= 1
|
||||||
|
if not retries:
|
||||||
|
raise self.server.error("Shell Command Error")
|
||||||
|
|
||||||
|
async def run_cmd_with_response(self, cmd, timeout=10., env=None):
|
||||||
|
scmd = self.build_shell_command(cmd, None, env=env)
|
||||||
|
result = await scmd.run_with_response(timeout, retries=5)
|
||||||
|
if result is None:
|
||||||
|
raise self.server.error(f"Error Running Command: {cmd}")
|
||||||
|
return result
|
||||||
|
|
||||||
async def github_api_request(self, url, etag=None, is_init=False):
|
async def github_api_request(self, url, etag=None, is_init=False):
|
||||||
if not is_init:
|
if not is_init:
|
||||||
timeout = time.time() + 30.
|
timeout = time.time() + 30.
|
||||||
|
@ -404,27 +433,19 @@ class UpdateManager:
|
||||||
resp = resp.decode()
|
resp = resp.decode()
|
||||||
notification = {
|
notification = {
|
||||||
'message': resp,
|
'message': resp,
|
||||||
'application': None,
|
'application': self.cur_update_app,
|
||||||
'proc_id': None,
|
'proc_id': self.cur_update_id,
|
||||||
'complete': is_complete}
|
'complete': is_complete}
|
||||||
if self.current_update is not None:
|
|
||||||
notification['application'] = self.current_update[0]
|
|
||||||
notification['proc_id'] = self.current_update[1]
|
|
||||||
self.server.send_event(
|
self.server.send_event(
|
||||||
"update_manager:update_response", notification)
|
"update_manager:update_response", notification)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.http_client.close()
|
self.http_client.close()
|
||||||
if self.refresh_cb is not None:
|
|
||||||
self.refresh_cb.stop()
|
|
||||||
|
|
||||||
|
|
||||||
class GitUpdater:
|
class GitUpdater:
|
||||||
def __init__(self, umgr, config, path=None, env=None):
|
def __init__(self, config, cmd_helper, path=None, env=None):
|
||||||
self.server = umgr.server
|
self.server = cmd_helper.get_server()
|
||||||
self.execute_cmd = umgr.execute_cmd
|
self.cmd_helper = cmd_helper
|
||||||
self.execute_cmd_with_response = umgr.execute_cmd_with_response
|
|
||||||
self.notify_update_response = umgr.notify_update_response
|
|
||||||
self.name = config.get_name().split()[-1]
|
self.name = config.get_name().split()[-1]
|
||||||
self.owner = "?"
|
self.owner = "?"
|
||||||
self.repo_path = path
|
self.repo_path = path
|
||||||
|
@ -474,7 +495,7 @@ class GitUpdater:
|
||||||
self.remote_version = self.remote_hash = "?"
|
self.remote_version = self.remote_hash = "?"
|
||||||
self.init_evt = Event()
|
self.init_evt = Event()
|
||||||
self.refresh_condition = None
|
self.refresh_condition = None
|
||||||
self.debug = umgr.repo_debug
|
self.debug = self.cmd_helper.is_debug_enabled()
|
||||||
self.remote = "origin"
|
self.remote = "origin"
|
||||||
self.branch = "master"
|
self.branch = "master"
|
||||||
self.is_valid = self.is_dirty = self.detached = False
|
self.is_valid = self.is_dirty = self.detached = False
|
||||||
|
@ -513,7 +534,7 @@ class GitUpdater:
|
||||||
def _notify_status(self, msg, is_complete=False):
|
def _notify_status(self, msg, is_complete=False):
|
||||||
log_msg = f"Repo {self.name}: {msg}"
|
log_msg = f"Repo {self.name}: {msg}"
|
||||||
logging.debug(log_msg)
|
logging.debug(log_msg)
|
||||||
self.notify_update_response(log_msg, is_complete)
|
self.cmd_helper.notify_update_response(log_msg, is_complete)
|
||||||
|
|
||||||
async def check_initialized(self, timeout=None):
|
async def check_initialized(self, timeout=None):
|
||||||
if self.init_evt.is_set():
|
if self.init_evt.is_set():
|
||||||
|
@ -541,7 +562,7 @@ class GitUpdater:
|
||||||
self.cur_hash = self.branch = self.remote = "?"
|
self.cur_hash = self.branch = self.remote = "?"
|
||||||
self.version = self.remote_version = self.owner = "?"
|
self.version = self.remote_version = self.owner = "?"
|
||||||
try:
|
try:
|
||||||
blist = await self.execute_cmd_with_response(
|
blist = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} branch --list")
|
f"git -C {self.repo_path} branch --list")
|
||||||
if blist.startswith("fatal:"):
|
if blist.startswith("fatal:"):
|
||||||
self._log_info(f"Invalid git repo at path '{self.repo_path}'")
|
self._log_info(f"Invalid git repo at path '{self.repo_path}'")
|
||||||
|
@ -563,7 +584,7 @@ class GitUpdater:
|
||||||
self.detached = True
|
self.detached = True
|
||||||
else:
|
else:
|
||||||
self.branch = branch.strip()
|
self.branch = branch.strip()
|
||||||
self.remote = await self.execute_cmd_with_response(
|
self.remote = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} config --get"
|
f"git -C {self.repo_path} config --get"
|
||||||
f" branch.{self.branch}.remote")
|
f" branch.{self.branch}.remote")
|
||||||
if need_fetch:
|
if need_fetch:
|
||||||
|
@ -571,20 +592,20 @@ class GitUpdater:
|
||||||
'GIT_HTTP_LOW_SPEED_LIMIT': "1000",
|
'GIT_HTTP_LOW_SPEED_LIMIT': "1000",
|
||||||
'GIT_HTTP_LOW_SPEED_TIME ': "15"
|
'GIT_HTTP_LOW_SPEED_TIME ': "15"
|
||||||
}
|
}
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"git -C {self.repo_path} fetch {self.remote} --prune -q",
|
f"git -C {self.repo_path} fetch {self.remote} --prune -q",
|
||||||
timeout=20., retries=3, env=env)
|
timeout=20., retries=3, env=env)
|
||||||
remote_url = await self.execute_cmd_with_response(
|
remote_url = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} remote get-url {self.remote}")
|
f"git -C {self.repo_path} remote get-url {self.remote}")
|
||||||
cur_hash = await self.execute_cmd_with_response(
|
cur_hash = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} rev-parse HEAD")
|
f"git -C {self.repo_path} rev-parse HEAD")
|
||||||
remote_hash = await self.execute_cmd_with_response(
|
remote_hash = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} rev-parse "
|
f"git -C {self.repo_path} rev-parse "
|
||||||
f"{self.remote}/{self.branch}")
|
f"{self.remote}/{self.branch}")
|
||||||
repo_version = await self.execute_cmd_with_response(
|
repo_version = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} describe --always "
|
f"git -C {self.repo_path} describe --always "
|
||||||
"--tags --long --dirty")
|
"--tags --long --dirty")
|
||||||
remote_version = await self.execute_cmd_with_response(
|
remote_version = await self.cmd_helper.run_cmd_with_response(
|
||||||
f"git -C {self.repo_path} describe {self.remote}/{self.branch}"
|
f"git -C {self.repo_path} describe {self.remote}/{self.branch}"
|
||||||
" --always --tags --long")
|
" --always --tags --long")
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -652,14 +673,14 @@ class GitUpdater:
|
||||||
'GIT_HTTP_LOW_SPEED_TIME ': "15"
|
'GIT_HTTP_LOW_SPEED_TIME ': "15"
|
||||||
}
|
}
|
||||||
if self.detached:
|
if self.detached:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"git -C {self.repo_path} fetch {self.remote} -q",
|
f"git -C {self.repo_path} fetch {self.remote} -q",
|
||||||
timeout=20., retries=3, env=env)
|
timeout=20., retries=3, env=env)
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"git -C {self.repo_path} checkout"
|
f"git -C {self.repo_path} checkout"
|
||||||
f" {self.remote}/{self.branch} -q")
|
f" {self.remote}/{self.branch} -q")
|
||||||
else:
|
else:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"git -C {self.repo_path} pull -q", timeout=20.,
|
f"git -C {self.repo_path} pull -q", timeout=20.,
|
||||||
retries=3, env=env)
|
retries=3, env=env)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -707,9 +728,9 @@ class GitUpdater:
|
||||||
self._notify_status("Installing system dependencies...")
|
self._notify_status("Installing system dependencies...")
|
||||||
# Install packages with apt-get
|
# Install packages with apt-get
|
||||||
try:
|
try:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{APT_CMD} update", timeout=300., notify=True)
|
f"{APT_CMD} update", timeout=300., notify=True)
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{APT_CMD} install --yes {pkgs}", timeout=3600.,
|
f"{APT_CMD} install --yes {pkgs}", timeout=3600.,
|
||||||
notify=True)
|
notify=True)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -727,7 +748,7 @@ class GitUpdater:
|
||||||
if os.path.exists(env_path):
|
if os.path.exists(env_path):
|
||||||
shutil.rmtree(env_path)
|
shutil.rmtree(env_path)
|
||||||
try:
|
try:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"virtualenv {self.venv_args} {env_path}", timeout=300.)
|
f"virtualenv {self.venv_args} {env_path}", timeout=300.)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log_exc(f"Error creating virtualenv")
|
self._log_exc(f"Error creating virtualenv")
|
||||||
|
@ -741,7 +762,7 @@ class GitUpdater:
|
||||||
pip = os.path.join(bin_dir, "pip")
|
pip = os.path.join(bin_dir, "pip")
|
||||||
self._notify_status("Updating python packages...")
|
self._notify_status("Updating python packages...")
|
||||||
try:
|
try:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{pip} install -r {reqs}", timeout=1200., notify=True,
|
f"{pip} install -r {reqs}", timeout=1200., notify=True,
|
||||||
retries=3)
|
retries=3)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -773,7 +794,8 @@ class GitUpdater:
|
||||||
async def restart_service(self):
|
async def restart_service(self):
|
||||||
self._notify_status("Restarting Service...")
|
self._notify_status("Restarting Service...")
|
||||||
try:
|
try:
|
||||||
await self.execute_cmd(f"sudo systemctl restart {self.name}")
|
await self.cmd_helper.run_cmd(
|
||||||
|
f"sudo systemctl restart {self.name}")
|
||||||
except Exception:
|
except Exception:
|
||||||
raise self._log_exc("Error restarting service")
|
raise self._log_exc("Error restarting service")
|
||||||
|
|
||||||
|
@ -789,15 +811,14 @@ class GitUpdater:
|
||||||
'is_dirty': self.is_dirty,
|
'is_dirty': self.is_dirty,
|
||||||
'is_valid': self.is_valid,
|
'is_valid': self.is_valid,
|
||||||
'detached': self.detached,
|
'detached': self.detached,
|
||||||
'debug_enabled': self.debug}
|
'debug_enabled': self.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PackageUpdater:
|
class PackageUpdater:
|
||||||
def __init__(self, umgr):
|
def __init__(self, cmd_helper):
|
||||||
self.server = umgr.server
|
self.server = cmd_helper.get_server()
|
||||||
self.execute_cmd = umgr.execute_cmd
|
self.cmd_helper = cmd_helper
|
||||||
self.execute_cmd_with_response = umgr.execute_cmd_with_response
|
|
||||||
self.notify_update_response = umgr.notify_update_response
|
|
||||||
self.available_packages = []
|
self.available_packages = []
|
||||||
self.init_evt = Event()
|
self.init_evt = Event()
|
||||||
self.refresh_condition = None
|
self.refresh_condition = None
|
||||||
|
@ -811,9 +832,9 @@ class PackageUpdater:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
if fetch_packages:
|
if fetch_packages:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{APT_CMD} update", timeout=300., retries=3)
|
f"{APT_CMD} update", timeout=300., retries=3)
|
||||||
res = await self.execute_cmd_with_response(
|
res = await self.cmd_helper.run_cmd_with_response(
|
||||||
"apt list --upgradable", timeout=60.)
|
"apt list --upgradable", timeout=60.)
|
||||||
pkg_list = [p.strip() for p in res.split("\n") if p.strip()]
|
pkg_list = [p.strip() for p in res.split("\n") if p.strip()]
|
||||||
if pkg_list:
|
if pkg_list:
|
||||||
|
@ -841,17 +862,17 @@ class PackageUpdater:
|
||||||
await self.check_initialized(20.)
|
await self.check_initialized(20.)
|
||||||
if self.refresh_condition is not None:
|
if self.refresh_condition is not None:
|
||||||
self.refresh_condition.wait()
|
self.refresh_condition.wait()
|
||||||
self.notify_update_response("Updating packages...")
|
self.cmd_helper.notify_update_response("Updating packages...")
|
||||||
try:
|
try:
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{APT_CMD} update", timeout=300., notify=True)
|
f"{APT_CMD} update", timeout=300., notify=True)
|
||||||
await self.execute_cmd(
|
await self.cmd_helper.run_cmd(
|
||||||
f"{APT_CMD} upgrade --yes", timeout=3600., notify=True)
|
f"{APT_CMD} upgrade --yes", timeout=3600., notify=True)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise self.server.error("Error updating system packages")
|
raise self.server.error("Error updating system packages")
|
||||||
self.available_packages = []
|
self.available_packages = []
|
||||||
self.notify_update_response("Package update finished...",
|
self.cmd_helper.notify_update_response("Package update finished...",
|
||||||
is_complete=True)
|
is_complete=True)
|
||||||
|
|
||||||
def get_update_status(self):
|
def get_update_status(self):
|
||||||
return {
|
return {
|
||||||
|
@ -860,10 +881,9 @@ class PackageUpdater:
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebUpdater:
|
class WebUpdater:
|
||||||
def __init__(self, umgr, config):
|
def __init__(self, config, cmd_helper):
|
||||||
self.umgr = umgr
|
self.server = cmd_helper.get_server()
|
||||||
self.server = umgr.server
|
self.cmd_helper = cmd_helper
|
||||||
self.notify_update_response = umgr.notify_update_response
|
|
||||||
self.repo = config.get('repo').strip().strip("/")
|
self.repo = config.get('repo').strip().strip("/")
|
||||||
self.owner, self.name = self.repo.split("/", 1)
|
self.owner, self.name = self.repo.split("/", 1)
|
||||||
if hasattr(config, "get_name"):
|
if hasattr(config, "get_name"):
|
||||||
|
@ -922,7 +942,8 @@ class WebUpdater:
|
||||||
# Remote state
|
# Remote state
|
||||||
url = f"https://api.github.com/repos/{self.repo}/releases/latest"
|
url = f"https://api.github.com/repos/{self.repo}/releases/latest"
|
||||||
try:
|
try:
|
||||||
result = await self.umgr.github_api_request(url, etag=self.etag)
|
result = await self.cmd_helper.github_api_request(
|
||||||
|
url, etag=self.etag)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception(f"Client {self.repo}: Github Request Error")
|
logging.exception(f"Client {self.repo}: Github Request Error")
|
||||||
result = {}
|
result = {}
|
||||||
|
@ -955,8 +976,9 @@ class WebUpdater:
|
||||||
if self.version == self.remote_version:
|
if self.version == self.remote_version:
|
||||||
# Already up to date
|
# Already up to date
|
||||||
return
|
return
|
||||||
self.notify_update_response(f"Downloading Client: {self.name}")
|
self.cmd_helper.notify_update_response(
|
||||||
archive = await self.umgr.http_download_request(self.dl_url)
|
f"Downloading Client: {self.name}")
|
||||||
|
archive = await self.cmd_helper.http_download_request(self.dl_url)
|
||||||
with tempfile.TemporaryDirectory(
|
with tempfile.TemporaryDirectory(
|
||||||
suffix=self.name, prefix="client") as tempdir:
|
suffix=self.name, prefix="client") as tempdir:
|
||||||
if os.path.isdir(self.path):
|
if os.path.isdir(self.path):
|
||||||
|
@ -964,7 +986,8 @@ class WebUpdater:
|
||||||
for fname in os.listdir(self.path):
|
for fname in os.listdir(self.path):
|
||||||
src_path = os.path.join(self.path, fname)
|
src_path = os.path.join(self.path, fname)
|
||||||
if fname in self.persistent_files:
|
if fname in self.persistent_files:
|
||||||
dest_dir = os.path.dirname(os.path.join(tempdir, fname))
|
dest_dir = os.path.dirname(
|
||||||
|
os.path.join(tempdir, fname))
|
||||||
os.makedirs(dest_dir, exist_ok=True)
|
os.makedirs(dest_dir, exist_ok=True)
|
||||||
shutil.move(src_path, dest_dir)
|
shutil.move(src_path, dest_dir)
|
||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
|
@ -982,8 +1005,8 @@ class WebUpdater:
|
||||||
if not os.path.exists(version_path):
|
if not os.path.exists(version_path):
|
||||||
with open(version_path, "w") as f:
|
with open(version_path, "w") as f:
|
||||||
f.write(self.version)
|
f.write(self.version)
|
||||||
self.notify_update_response(f"Client Update Finished: {self.name}",
|
self.cmd_helper.notify_update_response(
|
||||||
is_complete=True)
|
f"Client Update Finished: {self.name}", is_complete=True)
|
||||||
|
|
||||||
def get_update_status(self):
|
def get_update_status(self):
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in New Issue