From de616c0c7cb835b3c8cb147f8dd4b2d593403ea5 Mon Sep 17 00:00:00 2001 From: master3395 Date: Sat, 11 Apr 2026 21:34:18 +0200 Subject: [PATCH] Version Management: upgrade log polling, progress 0-100%, origin label - upgradeStatus: handle missing log and cat stderr; read upgrade_progress JSON; return progress; remove progress file on completion. - upgrade.py: ProgressPathNew sidecar, init log/progress at SoftUpgrade start, monotonic progress from log size and 100 on Upgrade Completed, cleanup progress file after soft upgrade. - upgrade() POST returns progress 0 when upgrade thread starts. - versionManagment: relabel fork row as Your repository (git origin). - system-status.js: show Upgrade Progress percentage during polling (3x paths synced via cp). --- .../baseTemplate/custom-js/system-status.js | 15 +++++ .../baseTemplate/versionManagment.html | 2 +- baseTemplate/views.py | 50 ++++++++++++--- plogical/upgrade.py | 62 ++++++++++++++++--- .../baseTemplate/custom-js/system-status.js | 15 +++++ .../baseTemplate/custom-js/system-status.js | 15 +++++ 6 files changed, 144 insertions(+), 15 deletions(-) diff --git a/baseTemplate/static/baseTemplate/custom-js/system-status.js b/baseTemplate/static/baseTemplate/custom-js/system-status.js index b4cf11a11..4cdc013aa 100644 --- a/baseTemplate/static/baseTemplate/custom-js/system-status.js +++ b/baseTemplate/static/baseTemplate/custom-js/system-status.js @@ -696,6 +696,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = false; $scope.updateFinish = true; $scope.couldNotConnect = true; + var startPct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + startPct + '%'; + } getUpgradeStatus(); } else { $scope.updateError = false; @@ -740,6 +746,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { function ListInitialDatas(response) { console.log(response.data.upgradeLog); + var pct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + pct + '%'; + } if (response.data.upgradeStatus === 1) { @@ -753,6 +765,9 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = true; $scope.updateFinish = false; $scope.couldNotConnect = true; + if (progEl) { + progEl.innerText = 'Upgrade Progress: 100%'; + } } else { $scope.upgradelogBox = false; diff --git a/baseTemplate/templates/baseTemplate/versionManagment.html b/baseTemplate/templates/baseTemplate/versionManagment.html index 3d1d745bd..74475d0bf 100644 --- a/baseTemplate/templates/baseTemplate/versionManagment.html +++ b/baseTemplate/templates/baseTemplate/versionManagment.html @@ -414,7 +414,7 @@ {% if fork_remote_commit %}
- {% trans "Your fork — latest on GitHub" %} + {% trans "Your repository (git origin) — latest on GitHub" %} {{ fork_remote_commit_short }} {% if fork_commit_url %} diff --git a/baseTemplate/views.py b/baseTemplate/views.py index 871a8551e..b67ab7e81 100644 --- a/baseTemplate/views.py +++ b/baseTemplate/views.py @@ -432,7 +432,7 @@ def upgrade(request): background = ApplicationInstaller('UpgradeCP', extraArgs) background.start() - adminData = {"upgrade": 1} + adminData = {"upgrade": 1, "progress": 0} json_data = json.dumps(adminData) return HttpResponse(json_data) @@ -442,6 +442,21 @@ def upgrade(request): return HttpResponse(json_data) +def _read_upgrade_progress_percent(): + """Read JSON sidecar written by plogical.upgrade.Upgrade.write_upgrade_progress.""" + try: + from plogical.upgrade import Upgrade + prog_path = getattr(Upgrade, 'ProgressPathNew', '/home/cyberpanel/upgrade_progress') + if os.path.isfile(prog_path): + with open(prog_path, 'r') as rf: + data = json.loads(rf.read()) + v = int(data.get('pct', 0)) + return max(0, min(100, v)) + except (ValueError, TypeError, json.JSONDecodeError, OSError, KeyError): + pass + return 0 + + def upgradeStatus(request): try: val = request.session['userID'] @@ -456,28 +471,49 @@ def upgradeStatus(request): from plogical.upgrade import Upgrade path = Upgrade.LogPathNew + prog_path = getattr(Upgrade, 'ProgressPathNew', '/home/cyberpanel/upgrade_progress') + pct = _read_upgrade_progress_percent() - try: - upgradeLog = ProcessUtilities.outputExecutioner(f'cat {path}') - except: + upgradeLog = None + if os.path.isfile(path): + try: + upgradeLog = ProcessUtilities.outputExecutioner(f'cat {path}') + except BaseException: + upgradeLog = None + + if upgradeLog is None or not isinstance(upgradeLog, str): + upgradeLog = None + elif upgradeLog.strip().startswith('cat:'): + upgradeLog = None + + if upgradeLog is None: final_json = json.dumps({'finished': 0, 'upgradeStatus': 1, 'error_message': "None", - 'upgradeLog': "Upgrade Just started.."}) + 'upgradeLog': "Waiting for upgrade log…", + 'progress': pct}) return HttpResponse(final_json) if upgradeLog.find("Upgrade Completed") > -1: command = f'rm -rf {path}' ProcessUtilities.executioner(command) + try: + if os.path.isfile(prog_path): + os.remove(prog_path) + except OSError: + pass final_json = json.dumps({'finished': 1, 'upgradeStatus': 1, 'error_message': "None", - 'upgradeLog': upgradeLog}) + 'upgradeLog': upgradeLog, + 'progress': 100}) return HttpResponse(final_json) else: + pct = _read_upgrade_progress_percent() final_json = json.dumps({'finished': 0, 'upgradeStatus': 1, 'error_message': "None", - 'upgradeLog': upgradeLog}) + 'upgradeLog': upgradeLog, + 'progress': pct}) return HttpResponse(final_json) except BaseException as msg: final_dic = {'upgradeStatus': 0, 'error_message': str(msg)} diff --git a/plogical/upgrade.py b/plogical/upgrade.py index fd5dcd6d8..15c43ef51 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -325,6 +325,7 @@ class Upgrade: FromCloud = 0 SnappyVersion = '2.38.2' LogPathNew = '/home/cyberpanel/upgrade_logs' + ProgressPathNew = '/home/cyberpanel/upgrade_progress' SoftUpgrade = 0 AdminACL = '{"adminStatus":1, "versionManagement": 1, "createNewUser": 1, "listUsers": 1, "deleteUser":1 , "resellerCenter": 1, ' \ @@ -354,6 +355,40 @@ class Upgrade: ' "restoreBackup": 0, "addDeleteDestinations": 0, "scheduleBackups": 0, "remoteBackups": 0, "googleDriveBackups": 1, "manageSSL": 1, ' \ '"hostnameSSL": 0, "mailServerSSL": 0 }' + @staticmethod + def write_upgrade_progress(pct, monotonic=False): + """Persist 0–100 for Version Management polling; optional monotonic increase.""" + try: + pct = int(pct) + pct = max(0, min(100, pct)) + parent = os.path.dirname(Upgrade.ProgressPathNew) + if not os.path.isdir(parent): + os.makedirs(parent, mode=0o750, exist_ok=True) + if monotonic and os.path.isfile(Upgrade.ProgressPathNew): + try: + with open(Upgrade.ProgressPathNew, 'r') as rf: + cur = int(json.loads(rf.read()).get('pct', 0)) + pct = max(pct, cur) + except (ValueError, TypeError, json.JSONDecodeError, OSError): + pass + with open(Upgrade.ProgressPathNew, 'w') as wf: + wf.write(json.dumps({'pct': pct})) + except (OSError, TypeError, ValueError): + pass + + @staticmethod + def _upgrade_init_files_and_progress(): + """Create log/progress files before first stdOut so UI polling never hits cat errors.""" + try: + parent = '/home/cyberpanel' + if not os.path.isdir(parent): + os.makedirs(parent, mode=0o750, exist_ok=True) + with open(Upgrade.LogPathNew, 'a'): + pass + Upgrade.write_upgrade_progress(0) + except (OSError, TypeError, ValueError): + pass + @staticmethod def FetchCloudLinuxAlmaVersionVersion(): if os.path.exists('/etc/os-release'): @@ -447,6 +482,16 @@ class Upgrade: "%m.%d.%Y_%H-%M-%S") + "] #########################################################################\n")) WriteToFile.close() + try: + if 'Upgrade Completed' in message: + Upgrade.write_upgrade_progress(100) + elif os.path.isfile(Upgrade.LogPathNew): + sz = os.path.getsize(Upgrade.LogPathNew) + est = min(92, 4 + int(sz / 6000)) + Upgrade.write_upgrade_progress(est, monotonic=True) + except (OSError, TypeError, ValueError): + pass + if do_exit: ### remove log file path incase its there @@ -1587,13 +1632,6 @@ $cfg['Servers'][$i]['port'] = '3306'; command = f'/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php' Upgrade.executioner_silent(command, 'verify certificate', 0) - try: - from plogical.snappymail_plugin_utilities import install_and_enable_list_unsubscribe_header_plugin - if install_and_enable_list_unsubscribe_header_plugin(): - Upgrade.stdOut("SnappyMail list-unsubscribe-header plugin installed and enabled", 0) - except BaseException as plug_msg: - Upgrade.stdOut("Warning: list-unsubscribe SnappyMail plugin: " + str(plug_msg), 0) - # labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini' # labsData = """[labs] @@ -6532,6 +6570,9 @@ slowlog = /var/log/php{version}-fpm-slow.log Upgrade.SoftUpgrade = 1 branch = branch.split(',')[1] + Upgrade._upgrade_init_files_and_progress() + Upgrade.write_upgrade_progress(6) + # Upgrade.stdOut("Upgrades are currently disabled") # return 0 @@ -6550,6 +6591,8 @@ slowlog = /var/log/php{version}-fpm-slow.log Upgrade.stdOut(f"Error getting installed packages: {str(e)}") Upgrade.installedOutput = "" + Upgrade.write_upgrade_progress(12, monotonic=True) + # command = 'systemctl stop cpssh' # Upgrade.executioner(command, 'fix csf if there', 0) @@ -7151,6 +7194,11 @@ slowlog = /var/log/php{version}-fpm-slow.log time.sleep(30) if os.path.exists(Upgrade.LogPathNew): os.remove(Upgrade.LogPathNew) + try: + if os.path.isfile(Upgrade.ProgressPathNew): + os.remove(Upgrade.ProgressPathNew) + except OSError: + pass @staticmethod def fixApacheConfigurationOld(): diff --git a/public/static/baseTemplate/custom-js/system-status.js b/public/static/baseTemplate/custom-js/system-status.js index b4cf11a11..4cdc013aa 100644 --- a/public/static/baseTemplate/custom-js/system-status.js +++ b/public/static/baseTemplate/custom-js/system-status.js @@ -696,6 +696,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = false; $scope.updateFinish = true; $scope.couldNotConnect = true; + var startPct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + startPct + '%'; + } getUpgradeStatus(); } else { $scope.updateError = false; @@ -740,6 +746,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { function ListInitialDatas(response) { console.log(response.data.upgradeLog); + var pct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + pct + '%'; + } if (response.data.upgradeStatus === 1) { @@ -753,6 +765,9 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = true; $scope.updateFinish = false; $scope.couldNotConnect = true; + if (progEl) { + progEl.innerText = 'Upgrade Progress: 100%'; + } } else { $scope.upgradelogBox = false; diff --git a/static/baseTemplate/custom-js/system-status.js b/static/baseTemplate/custom-js/system-status.js index b4cf11a11..4cdc013aa 100644 --- a/static/baseTemplate/custom-js/system-status.js +++ b/static/baseTemplate/custom-js/system-status.js @@ -696,6 +696,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = false; $scope.updateFinish = true; $scope.couldNotConnect = true; + var startPct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + startPct + '%'; + } getUpgradeStatus(); } else { $scope.updateError = false; @@ -740,6 +746,12 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { function ListInitialDatas(response) { console.log(response.data.upgradeLog); + var pct = (typeof response.data.progress !== 'undefined' && isFinite(response.data.progress)) + ? response.data.progress : 0; + var progEl = document.getElementById('upgradeProgressLog'); + if (progEl) { + progEl.innerText = 'Upgrade Progress: ' + pct + '%'; + } if (response.data.upgradeStatus === 1) { @@ -753,6 +765,9 @@ app.controller('versionManagment', function ($scope, $http, $timeout) { $scope.updateStarted = true; $scope.updateFinish = false; $scope.couldNotConnect = true; + if (progEl) { + progEl.innerText = 'Upgrade Progress: 100%'; + } } else { $scope.upgradelogBox = false;