From 5e8f973bb5e73580d623b7adb931625e3c83e442 Mon Sep 17 00:00:00 2001 From: master3395 Date: Fri, 27 Mar 2026 23:39:11 +0100 Subject: [PATCH] plugins: reliable lscpd restart after install and revert - restartGunicorn: try systemctl as root; else sudo -n then systemctl; log failures - revert_plugin: call restartGunicorn after successful backup restore --- pluginHolder/views.py | 6 ++++ pluginInstaller/pluginInstaller.py | 51 ++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/pluginHolder/views.py b/pluginHolder/views.py index e1ce8764b..a4887f07f 100644 --- a/pluginHolder/views.py +++ b/pluginHolder/views.py @@ -2009,6 +2009,12 @@ def revert_plugin(request, plugin_name): # Restore from backup if _restore_plugin_from_backup(plugin_name, backup_path): + try: + pluginInstaller.restartGunicorn() + except Exception as re: + logging.writeToFile( + 'revert_plugin: restartGunicorn after restore failed (non-fatal): %s' % str(re) + ) return JsonResponse({ 'success': True, 'message': f'Plugin {plugin_name} reverted successfully to version {backup_version}' diff --git a/pluginInstaller/pluginInstaller.py b/pluginInstaller/pluginInstaller.py index 0041fe070..c0d6018ef 100644 --- a/pluginInstaller/pluginInstaller.py +++ b/pluginInstaller/pluginInstaller.py @@ -743,8 +743,55 @@ class pluginInstaller: @staticmethod def restartGunicorn(): - command = 'systemctl restart lscpd' - ProcessUtilities.normalExecutioner(command) + """ + Reload lscpd so Django reloads pluginHolder.urls and INSTALLED_APPS sync. + When the panel runs as non-root, plain systemctl often fails; try sudo -n then systemctl. + """ + try: + is_root = os.geteuid() == 0 + except AttributeError: + is_root = True + + if is_root: + candidates = [['systemctl', 'restart', 'lscpd']] + else: + # Prefer non-interactive sudo (NOPASSWD in sudoers); avoid bare sudo — it can hang on password. + candidates = [ + ['sudo', '-n', 'systemctl', 'restart', 'lscpd'], + ['systemctl', 'restart', 'lscpd'], + ] + + last_detail = None + for cmd in candidates: + try: + proc = subprocess.run( + cmd, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=120, + text=True, + ) + if proc.returncode == 0: + pluginInstaller.stdOut('lscpd restarted (%s)' % ' '.join(cmd)) + return + err = (proc.stderr or proc.stdout or '').strip() + last_detail = 'rc=%s %s' % (proc.returncode, err[:400]) + except subprocess.TimeoutExpired: + last_detail = 'timeout after 120s for %s' % ' '.join(cmd) + except Exception as exc: + last_detail = str(exc)[:400] + + msg = 'pluginInstaller.restartGunicorn: failed to restart lscpd. %s. Run as root or grant NOPASSWD: sudo systemctl restart lscpd' % ( + last_detail or 'no details' + ) + pluginInstaller.stdOut(msg) + try: + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as cp_log + + cp_log.writeToFile(msg) + except Exception: + pass