From d7752d1d2826c10017f8d93b63485987284679b9 Mon Sep 17 00:00:00 2001 From: Master3395 Date: Sun, 21 Sep 2025 20:45:37 +0200 Subject: [PATCH] Add cron job management for website suspension: Implement methods to suspend, restore, and check the status of cron jobs for websites. Update main function to handle new commands for cron management. Enhance child domain handling to ensure cron jobs are suspended/restored appropriately during website suspension processes. https://github.com/usmannasir/cyberpanel/issues/1097 --- plogical/cronUtil.py | 134 ++++++++++++++++++++++++++++++++++++ websiteFunctions/website.py | 72 ++++++++++++++++++- 2 files changed, 204 insertions(+), 2 deletions(-) diff --git a/plogical/cronUtil.py b/plogical/cronUtil.py index e6cec26ad..2a8796c56 100644 --- a/plogical/cronUtil.py +++ b/plogical/cronUtil.py @@ -139,6 +139,134 @@ class CronUtil: command = 'chmod 1730 /var/spool/cron/crontabs' ProcessUtilities.outputExecutioner(command) + @staticmethod + def suspendWebsiteCrons(externalApp): + """ + Suspend all cron jobs for a website by backing up and clearing the cron file. + This prevents cron jobs from running when a website is suspended. + """ + try: + if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8: + cronPath = "/var/spool/cron/" + externalApp + backupPath = "/var/spool/cron/" + externalApp + ".suspended" + else: + cronPath = "/var/spool/cron/crontabs/" + externalApp + backupPath = "/var/spool/cron/crontabs/" + externalApp + ".suspended" + + # Check if cron file exists + if not os.path.exists(cronPath): + print("1,None") # No cron file to suspend + return + + # Create backup of current cron jobs + try: + command = f'cp {cronPath} {backupPath}' + ProcessUtilities.executioner(command, 'root') + except Exception as e: + print(f"0,Warning: Could not backup cron file: {str(e)}") + + # Clear the cron file to suspend all jobs + try: + CronUtil.CronPrem(1) # Enable permissions + + # Create empty cron file or clear existing one + with open(cronPath, 'w') as f: + f.write('') # Empty file to disable all cron jobs + + # Set proper ownership + command = f'chown {externalApp}:{externalApp} {cronPath}' + ProcessUtilities.executioner(command, 'root') + + CronUtil.CronPrem(0) # Restore permissions + + print("1,Cron jobs suspended successfully") + + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + print(f"0,Failed to suspend cron jobs: {str(e)}") + + except Exception as e: + print(f"0,Error suspending cron jobs: {str(e)}") + + @staticmethod + def restoreWebsiteCrons(externalApp): + """ + Restore cron jobs for a website by restoring from backup file. + This restores cron jobs when a website is unsuspended. + """ + try: + if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8: + cronPath = "/var/spool/cron/" + externalApp + backupPath = "/var/spool/cron/" + externalApp + ".suspended" + else: + cronPath = "/var/spool/cron/crontabs/" + externalApp + backupPath = "/var/spool/cron/crontabs/" + externalApp + ".suspended" + + # Check if backup file exists + if not os.path.exists(backupPath): + print("1,No suspended cron jobs to restore") + return + + try: + CronUtil.CronPrem(1) # Enable permissions + + # Restore cron jobs from backup + command = f'cp {backupPath} {cronPath}' + ProcessUtilities.executioner(command, 'root') + + # Set proper ownership + command = f'chown {externalApp}:{externalApp} {cronPath}' + ProcessUtilities.executioner(command, 'root') + + # Remove backup file + os.remove(backupPath) + + CronUtil.CronPrem(0) # Restore permissions + + print("1,Cron jobs restored successfully") + + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + print(f"0,Failed to restore cron jobs: {str(e)}") + + except Exception as e: + print(f"0,Error restoring cron jobs: {str(e)}") + + @staticmethod + def getCronSuspensionStatus(externalApp): + """ + Check if cron jobs are currently suspended for a website. + Returns 1 if suspended, 0 if active, -1 if error. + """ + try: + if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8: + cronPath = "/var/spool/cron/" + externalApp + backupPath = "/var/spool/cron/" + externalApp + ".suspended" + else: + cronPath = "/var/spool/cron/crontabs/" + externalApp + backupPath = "/var/spool/cron/crontabs/" + externalApp + ".suspended" + + # Check if backup file exists (indicates suspension) + if os.path.exists(backupPath): + print("1,Cron jobs are suspended") + return + elif os.path.exists(cronPath): + # Check if cron file is empty (also indicates suspension) + try: + with open(cronPath, 'r') as f: + content = f.read().strip() + if not content: + print("1,Cron jobs are suspended (empty file)") + else: + print("0,Cron jobs are active") + except Exception as e: + print(f"-1,Error reading cron file: {str(e)}") + else: + print("0,No cron jobs configured") + + except Exception as e: + print(f"-1,Error checking cron status: {str(e)}") + def main(): @@ -162,6 +290,12 @@ def main(): CronUtil.remCronbyLine(args.externalApp, int(args.line)) elif args.function == "addNewCron": CronUtil.addNewCron(args.externalApp, args.finalCron) + elif args.function == "suspendWebsiteCrons": + CronUtil.suspendWebsiteCrons(args.externalApp) + elif args.function == "restoreWebsiteCrons": + CronUtil.restoreWebsiteCrons(args.externalApp) + elif args.function == "getCronSuspensionStatus": + CronUtil.getCronSuspensionStatus(args.externalApp) diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index 187b76807..8246f85b9 100644 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -3151,9 +3151,27 @@ context /cyberpanel_suspension_page.html { except: pass - # Apply same suspension configuration to child domains + # Suspend cron jobs for child domains childDomains = website.childdomains_set.all() + for items in childDomains: + # Suspend cron jobs for child domain + try: + CronUtil.CronPrem(1) + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/cronUtil.py" + execPath = execPath + " suspendWebsiteCrons --externalApp " + items.externalApp + cronOutput = ProcessUtilities.outputExecutioner(execPath, items.externalApp) + CronUtil.CronPrem(0) + + if cronOutput.find("1,") > -1: + logging.CyberCPLogFileWriter.writeToFile(f"Successfully suspended cron jobs for child domain {items.domain}") + else: + logging.CyberCPLogFileWriter.writeToFile(f"Warning: Failed to suspend cron jobs for child domain {items.domain}: {cronOutput}") + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + logging.CyberCPLogFileWriter.writeToFile(f"Error suspending cron jobs for child domain {items.domain}: {str(e)}") + + # Apply same suspension configuration to child domains for items in childDomains: childConfPath = virtualHostUtilities.Server_root + "/conf/vhosts/" + items.domain childVhostConfPath = childConfPath + "/vhost.conf" @@ -3198,6 +3216,22 @@ context /cyberpanel_suspension_page.html { except Exception as e: CyberCPLogFileWriter.writeToFile(f"Error suspending child domain {items.domain}: {str(e)}") + # Suspend cron jobs for this website + try: + CronUtil.CronPrem(1) + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/cronUtil.py" + execPath = execPath + " suspendWebsiteCrons --externalApp " + website.externalApp + cronOutput = ProcessUtilities.outputExecutioner(execPath, website.externalApp) + CronUtil.CronPrem(0) + + if cronOutput.find("1,") > -1: + logging.CyberCPLogFileWriter.writeToFile(f"Successfully suspended cron jobs for {websiteName}") + else: + logging.CyberCPLogFileWriter.writeToFile(f"Warning: Failed to suspend cron jobs for {websiteName}: {cronOutput}") + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + logging.CyberCPLogFileWriter.writeToFile(f"Error suspending cron jobs for {websiteName}: {str(e)}") + # Restart LiteSpeed to apply changes try: installUtilities.reStartLiteSpeedSocket() @@ -3297,9 +3331,27 @@ context /cyberpanel_suspension_page.html { except: pass - # Remove suspension configuration from child domains + # Restore cron jobs for child domains childDomains = website.childdomains_set.all() + for items in childDomains: + # Restore cron jobs for child domain + try: + CronUtil.CronPrem(1) + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/cronUtil.py" + execPath = execPath + " restoreWebsiteCrons --externalApp " + items.externalApp + cronOutput = ProcessUtilities.outputExecutioner(execPath, items.externalApp) + CronUtil.CronPrem(0) + + if cronOutput.find("1,") > -1: + logging.CyberCPLogFileWriter.writeToFile(f"Successfully restored cron jobs for child domain {items.domain}") + else: + logging.CyberCPLogFileWriter.writeToFile(f"Info: {cronOutput} for child domain {items.domain}") + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + logging.CyberCPLogFileWriter.writeToFile(f"Error restoring cron jobs for child domain {items.domain}: {str(e)}") + + # Remove suspension configuration from child domains for items in childDomains: childConfPath = virtualHostUtilities.Server_root + "/conf/vhosts/" + items.domain childVhostConfPath = childConfPath + "/vhost.conf" @@ -3346,6 +3398,22 @@ context /cyberpanel_suspension_page.html { except Exception as e: CyberCPLogFileWriter.writeToFile(f"Error unsuspending child domain {items.domain}: {str(e)}") + # Restore cron jobs for this website + try: + CronUtil.CronPrem(1) + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/cronUtil.py" + execPath = execPath + " restoreWebsiteCrons --externalApp " + website.externalApp + cronOutput = ProcessUtilities.outputExecutioner(execPath, website.externalApp) + CronUtil.CronPrem(0) + + if cronOutput.find("1,") > -1: + logging.CyberCPLogFileWriter.writeToFile(f"Successfully restored cron jobs for {websiteName}") + else: + logging.CyberCPLogFileWriter.writeToFile(f"Info: {cronOutput} for {websiteName}") + except Exception as e: + CronUtil.CronPrem(0) # Ensure permissions are restored + logging.CyberCPLogFileWriter.writeToFile(f"Error restoring cron jobs for {websiteName}: {str(e)}") + # Restart LiteSpeed to apply changes try: installUtilities.reStartLiteSpeedSocket()