Fix missing /usr/local/CyberCP/bin/python for cron and IncBackups

Add plogical/cyberpanel_python.py with resolve_cyberpanel_python() and
ensure_cyberpanel_bin_python_shim() (symlink to system Python when venv
binary is absent). Call shim before writing root crontab on install/upgrade,
and from IncBackups/IncScheduler.py so existing jobs self-heal. IncBackups
views use resolved interpreter for backupUtilities. Upgrade._python_for_manage
delegates to resolve_cyberpanel_python().
This commit is contained in:
master3395
2026-04-12 02:54:04 +02:00
parent 778de5afd9
commit c7995ecf03
5 changed files with 105 additions and 12 deletions

View File

@@ -1,17 +1,25 @@
import argparse
import sys
sys.path.append('/usr/local/CyberCP')
sys.path.append("/usr/local/CyberCP")
from plogical.cyberpanel_python import ensure_cyberpanel_bin_python_shim, resolve_cyberpanel_python
from plogical.processUtilities import ProcessUtilities
def main():
parser = argparse.ArgumentParser(description='CyberPanel Installer')
parser.add_argument('function', help='Specific a function to call!')
def main():
try:
ensure_cyberpanel_bin_python_shim()
except BaseException:
pass
parser = argparse.ArgumentParser(description="CyberPanel incremental backup cron wrapper")
parser.add_argument("function", help="Function name to pass to plogical/IncScheduler.py")
args = parser.parse_args()
command = f"/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py '{args.function}'"
py = resolve_cyberpanel_python()
command = "%s /usr/local/CyberCP/plogical/IncScheduler.py '%s'" % (py, args.function)
ProcessUtilities.normalExecutioner(command)
if __name__ == "__main__":
main()
main()

View File

@@ -108,7 +108,8 @@ def add_destination(request):
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
python_path = Path('/usr/local/CyberCP/bin/python')
from plogical.cyberpanel_python import resolve_cyberpanel_python
python_path = Path(resolve_cyberpanel_python())
backup_utils = Path(vhu.cyberPanel) / "plogical/backupUtilities.py"
exec_args = "submitDestinationCreation --ipAddress %s --password %s --port %s --user %s" % \

View File

@@ -5498,6 +5498,14 @@ user_query = SELECT email as user, password, 'vmail' as uid, 'vmail' as gid, '/h
else:
cronPath = '/var/spool/cron/crontabs/root'
try:
if '/usr/local/CyberCP' not in sys.path:
sys.path.insert(0, '/usr/local/CyberCP')
from plogical.cyberpanel_python import ensure_cyberpanel_bin_python_shim
ensure_cyberpanel_bin_python_shim()
except BaseException:
pass
cronFile = open(cronPath, "w")
# Randomize acme.sh and renew.py cron schedules to avoid traffic spikes to Let's Encrypt

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""
Resolve the Python interpreter for CyberPanel CLI and cron jobs.
Some installs omit /usr/local/CyberCP/bin/python (no venv). We symlink that path
to a working interpreter when missing so existing crontab lines keep working.
"""
from __future__ import annotations
import os
_CANDIDATES = (
"/usr/local/CyberPanel/bin/python",
"/usr/local/CyberCP/bin/python",
"/usr/bin/python3",
"/usr/local/bin/python3",
)
def resolve_cyberpanel_python() -> str:
"""Return first existing executable candidate, else /usr/bin/python3."""
for path in _CANDIDATES:
if path == "/usr/local/CyberCP/bin/python":
continue
if path and os.path.isfile(path) and os.access(path, os.X_OK):
return path
return "/usr/bin/python3"
def ensure_cyberpanel_bin_python_shim() -> None:
"""
If /usr/local/CyberCP/bin/python is missing or a broken symlink, replace with
symlink to resolve_cyberpanel_python(). Non-destructive for a real venv file.
"""
bin_dir = "/usr/local/CyberCP/bin"
legacy = os.path.join(bin_dir, "python")
try:
os.makedirs(bin_dir, exist_ok=True)
except OSError:
return
if os.path.isfile(legacy) and os.access(legacy, os.X_OK) and not os.path.islink(legacy):
return
if os.path.islink(legacy):
real = os.path.realpath(legacy)
if os.path.isfile(real) and os.access(real, os.X_OK):
return
try:
os.unlink(legacy)
except OSError:
return
if os.path.lexists(legacy):
try:
os.remove(legacy)
except OSError:
try:
os.unlink(legacy)
except OSError:
return
target = resolve_cyberpanel_python()
try:
os.symlink(target, legacy)
except OSError:
pass

View File

@@ -3850,11 +3850,9 @@ passdb {
@staticmethod
def _python_for_manage():
"""Resolve Python for manage.py (avoid FileNotFoundError when /usr/local/CyberPanel/bin/python missing)."""
for path in ('/usr/local/CyberPanel/bin/python', '/usr/local/CyberCP/bin/python', '/usr/bin/python3', '/usr/local/bin/python3'):
if path and os.path.isfile(path) and os.access(path, os.X_OK):
return path
return '/usr/bin/python3'
"""Resolve Python for manage.py (avoid FileNotFoundError when venv python missing)."""
from plogical.cyberpanel_python import resolve_cyberpanel_python
return resolve_cyberpanel_python()
@staticmethod
def GeneralMigrations():
@@ -6231,6 +6229,12 @@ vmail
if os.path.exists(cronPath):
data = open(cronPath, 'r').read()
try:
from plogical.cyberpanel_python import ensure_cyberpanel_bin_python_shim
ensure_cyberpanel_bin_python_shim()
except BaseException:
pass
if data.find('findBWUsage') == -1:
# Randomize acme.sh and renew.py cron schedules to avoid traffic spikes to Let's Encrypt
# Each installation gets a random day (0-6 Sun-Sat), hour, and minute to spread load
@@ -6290,6 +6294,11 @@ vmail
else:
try:
from plogical.cyberpanel_python import ensure_cyberpanel_bin_python_shim
ensure_cyberpanel_bin_python_shim()
except BaseException:
pass
# Randomize acme.sh and renew.py cron schedules to avoid traffic spikes to Let's Encrypt
# Each installation gets a random day (0-6 Sun-Sat), hour, and minute to spread load
acme_hour = random.randint(0, 23)