mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-13 16:56:09 +01:00
Add binary verification and rollback mechanism for OLS custom binaries
Implement safety checks to verify custom OpenLiteSpeed binaries work before committing to them: Verification checks: - Check library dependencies with ldd to detect missing libraries - Test binary execution with -v flag to ensure it can run - Detect issues like wrong binary type (ubuntu vs rhel) for the OS Rollback mechanism: - Automatically restore original binary from backup if verification fails - Remove incompatible custom module - Continue installation with standard OLS if custom binary fails This prevents installation failures and system downtime when: - Wrong binary type is downloaded due to OS detection issues - Library dependencies are missing - Binary cannot execute on the target system Changes: - Added verifyCustomBinary() method to check dependencies and execution - Added rollbackCustomBinary() method to restore from backup - Updated installCustomOLSBinaries() to verify and rollback on failure - Applied to both install/installCyberPanel.py and plogical/upgrade.py Benefits: - Zero downtime: System falls back to working binary automatically - Better error reporting: Shows which libraries are missing - Safer upgrades: Users won't be left with broken installations
This commit is contained in:
@@ -284,6 +284,76 @@ class InstallCyberPanel:
|
|||||||
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def verifyCustomBinary(self, binary_path):
|
||||||
|
"""Verify custom binary has correct dependencies and can run"""
|
||||||
|
try:
|
||||||
|
InstallCyberPanel.stdOut("Verifying custom binary compatibility...", 1)
|
||||||
|
|
||||||
|
# Check library dependencies
|
||||||
|
command = f'ldd {binary_path}'
|
||||||
|
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
InstallCyberPanel.stdOut("ERROR: Failed to check binary dependencies", 1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check for missing libraries
|
||||||
|
if 'not found' in result.stdout:
|
||||||
|
InstallCyberPanel.stdOut("ERROR: Binary has missing library dependencies:", 1)
|
||||||
|
for line in result.stdout.split('\n'):
|
||||||
|
if 'not found' in line:
|
||||||
|
InstallCyberPanel.stdOut(f" {line.strip()}", 1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Try to run the binary with -v to check if it can execute
|
||||||
|
command = f'{binary_path} -v'
|
||||||
|
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=5)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
InstallCyberPanel.stdOut("ERROR: Binary failed to execute", 1)
|
||||||
|
if result.stderr:
|
||||||
|
InstallCyberPanel.stdOut(f" Error: {result.stderr.strip()}", 1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
InstallCyberPanel.stdOut("Binary verification successful", 1)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
InstallCyberPanel.stdOut("ERROR: Binary verification timed out", 1)
|
||||||
|
return False
|
||||||
|
except Exception as msg:
|
||||||
|
logging.InstallLog.writeToFile(str(msg) + " [verifyCustomBinary]")
|
||||||
|
InstallCyberPanel.stdOut(f"ERROR: Verification failed: {msg}", 1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rollbackCustomBinary(self, backup_dir, binary_path, module_path):
|
||||||
|
"""Rollback to original binary if custom binary fails"""
|
||||||
|
try:
|
||||||
|
InstallCyberPanel.stdOut("Rolling back to original binary...", 1)
|
||||||
|
|
||||||
|
backup_binary = f"{backup_dir}/openlitespeed.backup"
|
||||||
|
|
||||||
|
# Restore original binary if backup exists
|
||||||
|
if os.path.exists(backup_binary):
|
||||||
|
shutil.copy2(backup_binary, binary_path)
|
||||||
|
os.chmod(binary_path, 0o755)
|
||||||
|
InstallCyberPanel.stdOut("Original binary restored successfully", 1)
|
||||||
|
else:
|
||||||
|
InstallCyberPanel.stdOut("WARNING: No backup found, cannot restore", 1)
|
||||||
|
|
||||||
|
# Remove failed custom module
|
||||||
|
if os.path.exists(module_path):
|
||||||
|
os.remove(module_path)
|
||||||
|
InstallCyberPanel.stdOut("Custom module removed", 1)
|
||||||
|
|
||||||
|
InstallCyberPanel.stdOut("Rollback completed", 1)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as msg:
|
||||||
|
logging.InstallLog.writeToFile(str(msg) + " [rollbackCustomBinary]")
|
||||||
|
InstallCyberPanel.stdOut(f"ERROR: Rollback failed: {msg}", 1)
|
||||||
|
return False
|
||||||
|
|
||||||
def installCustomOLSBinaries(self):
|
def installCustomOLSBinaries(self):
|
||||||
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
||||||
try:
|
try:
|
||||||
@@ -362,21 +432,36 @@ class InstallCyberPanel:
|
|||||||
logging.InstallLog.writeToFile(str(e) + " [installCustomOLSBinaries - module install]")
|
logging.InstallLog.writeToFile(str(e) + " [installCustomOLSBinaries - module install]")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Verify installation
|
# Verify installation files exist
|
||||||
if os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH):
|
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||||
InstallCyberPanel.stdOut("=" * 50, 1)
|
InstallCyberPanel.stdOut("ERROR: Installation verification failed - files not found", 1)
|
||||||
InstallCyberPanel.stdOut("Custom Binaries Installed Successfully", 1)
|
|
||||||
InstallCyberPanel.stdOut("Features enabled:", 1)
|
|
||||||
InstallCyberPanel.stdOut(" - Apache-style .htaccess support", 1)
|
|
||||||
InstallCyberPanel.stdOut(" - php_value/php_flag directives", 1)
|
|
||||||
InstallCyberPanel.stdOut(" - Enhanced header control", 1)
|
|
||||||
InstallCyberPanel.stdOut(f"Backup: {backup_dir}", 1)
|
|
||||||
InstallCyberPanel.stdOut("=" * 50, 1)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
InstallCyberPanel.stdOut("ERROR: Installation verification failed", 1)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Verify binary compatibility
|
||||||
|
if not self.verifyCustomBinary(OLS_BINARY_PATH):
|
||||||
|
InstallCyberPanel.stdOut("ERROR: Custom binary verification failed", 1)
|
||||||
|
InstallCyberPanel.stdOut("This usually means wrong binary type for your OS", 1)
|
||||||
|
|
||||||
|
# Rollback to original binary
|
||||||
|
if os.path.exists(backup_dir):
|
||||||
|
self.rollbackCustomBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH)
|
||||||
|
InstallCyberPanel.stdOut("Continuing with standard OLS", 1)
|
||||||
|
else:
|
||||||
|
InstallCyberPanel.stdOut("WARNING: Cannot rollback, no backup found", 1)
|
||||||
|
|
||||||
|
return True # Non-fatal, continue with standard OLS
|
||||||
|
|
||||||
|
# Success!
|
||||||
|
InstallCyberPanel.stdOut("=" * 50, 1)
|
||||||
|
InstallCyberPanel.stdOut("Custom Binaries Installed Successfully", 1)
|
||||||
|
InstallCyberPanel.stdOut("Features enabled:", 1)
|
||||||
|
InstallCyberPanel.stdOut(" - Apache-style .htaccess support", 1)
|
||||||
|
InstallCyberPanel.stdOut(" - php_value/php_flag directives", 1)
|
||||||
|
InstallCyberPanel.stdOut(" - Enhanced header control", 1)
|
||||||
|
InstallCyberPanel.stdOut(f"Backup: {backup_dir}", 1)
|
||||||
|
InstallCyberPanel.stdOut("=" * 50, 1)
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as msg:
|
except Exception as msg:
|
||||||
logging.InstallLog.writeToFile(str(msg) + " [installCustomOLSBinaries]")
|
logging.InstallLog.writeToFile(str(msg) + " [installCustomOLSBinaries]")
|
||||||
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
||||||
|
|||||||
@@ -700,6 +700,76 @@ class Upgrade:
|
|||||||
Upgrade.stdOut(f"ERROR: {msg} [downloadCustomBinary]", 0)
|
Upgrade.stdOut(f"ERROR: {msg} [downloadCustomBinary]", 0)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def verifyCustomBinary(binary_path):
|
||||||
|
"""Verify custom binary has correct dependencies and can run"""
|
||||||
|
try:
|
||||||
|
Upgrade.stdOut("Verifying custom binary compatibility...", 0)
|
||||||
|
|
||||||
|
# Check library dependencies
|
||||||
|
command = f'ldd {binary_path}'
|
||||||
|
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
Upgrade.stdOut("ERROR: Failed to check binary dependencies", 0)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check for missing libraries
|
||||||
|
if 'not found' in result.stdout:
|
||||||
|
Upgrade.stdOut("ERROR: Binary has missing library dependencies:", 0)
|
||||||
|
for line in result.stdout.split('\n'):
|
||||||
|
if 'not found' in line:
|
||||||
|
Upgrade.stdOut(f" {line.strip()}", 0)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Try to run the binary with -v to check if it can execute
|
||||||
|
command = f'{binary_path} -v'
|
||||||
|
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=5)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
Upgrade.stdOut("ERROR: Binary failed to execute", 0)
|
||||||
|
if result.stderr:
|
||||||
|
Upgrade.stdOut(f" Error: {result.stderr.strip()}", 0)
|
||||||
|
return False
|
||||||
|
|
||||||
|
Upgrade.stdOut("Binary verification successful", 0)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
Upgrade.stdOut("ERROR: Binary verification timed out", 0)
|
||||||
|
return False
|
||||||
|
except Exception as msg:
|
||||||
|
Upgrade.stdOut(f"ERROR: Verification failed: {msg}", 0)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rollbackCustomBinary(backup_dir, binary_path, module_path):
|
||||||
|
"""Rollback to original binary if custom binary fails"""
|
||||||
|
try:
|
||||||
|
Upgrade.stdOut("Rolling back to original binary...", 0)
|
||||||
|
|
||||||
|
backup_binary = f"{backup_dir}/openlitespeed.backup"
|
||||||
|
|
||||||
|
# Restore original binary if backup exists
|
||||||
|
if os.path.exists(backup_binary):
|
||||||
|
shutil.copy2(backup_binary, binary_path)
|
||||||
|
os.chmod(binary_path, 0o755)
|
||||||
|
Upgrade.stdOut("Original binary restored successfully", 0)
|
||||||
|
else:
|
||||||
|
Upgrade.stdOut("WARNING: No backup found, cannot restore", 0)
|
||||||
|
|
||||||
|
# Remove failed custom module
|
||||||
|
if os.path.exists(module_path):
|
||||||
|
os.remove(module_path)
|
||||||
|
Upgrade.stdOut("Custom module removed", 0)
|
||||||
|
|
||||||
|
Upgrade.stdOut("Rollback completed", 0)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as msg:
|
||||||
|
Upgrade.stdOut(f"ERROR: Rollback failed: {msg}", 0)
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def installCustomOLSBinaries():
|
def installCustomOLSBinaries():
|
||||||
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
||||||
@@ -777,21 +847,36 @@ class Upgrade:
|
|||||||
Upgrade.stdOut(f"ERROR: Failed to install module: {e}", 0)
|
Upgrade.stdOut(f"ERROR: Failed to install module: {e}", 0)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Verify installation
|
# Verify installation files exist
|
||||||
if os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH):
|
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||||
Upgrade.stdOut("=" * 50, 0)
|
Upgrade.stdOut("ERROR: Installation verification failed - files not found", 0)
|
||||||
Upgrade.stdOut("Custom Binaries Installed Successfully", 0)
|
|
||||||
Upgrade.stdOut("Features enabled:", 0)
|
|
||||||
Upgrade.stdOut(" - Apache-style .htaccess support", 0)
|
|
||||||
Upgrade.stdOut(" - php_value/php_flag directives", 0)
|
|
||||||
Upgrade.stdOut(" - Enhanced header control", 0)
|
|
||||||
Upgrade.stdOut(f"Backup: {backup_dir}", 0)
|
|
||||||
Upgrade.stdOut("=" * 50, 0)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
Upgrade.stdOut("ERROR: Installation verification failed", 0)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Verify binary compatibility
|
||||||
|
if not Upgrade.verifyCustomBinary(OLS_BINARY_PATH):
|
||||||
|
Upgrade.stdOut("ERROR: Custom binary verification failed", 0)
|
||||||
|
Upgrade.stdOut("This usually means wrong binary type for your OS", 0)
|
||||||
|
|
||||||
|
# Rollback to original binary
|
||||||
|
if os.path.exists(backup_dir):
|
||||||
|
Upgrade.rollbackCustomBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH)
|
||||||
|
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||||
|
else:
|
||||||
|
Upgrade.stdOut("WARNING: Cannot rollback, no backup found", 0)
|
||||||
|
|
||||||
|
return True # Non-fatal, continue with standard OLS
|
||||||
|
|
||||||
|
# Success!
|
||||||
|
Upgrade.stdOut("=" * 50, 0)
|
||||||
|
Upgrade.stdOut("Custom Binaries Installed Successfully", 0)
|
||||||
|
Upgrade.stdOut("Features enabled:", 0)
|
||||||
|
Upgrade.stdOut(" - Apache-style .htaccess support", 0)
|
||||||
|
Upgrade.stdOut(" - php_value/php_flag directives", 0)
|
||||||
|
Upgrade.stdOut(" - Enhanced header control", 0)
|
||||||
|
Upgrade.stdOut(f"Backup: {backup_dir}", 0)
|
||||||
|
Upgrade.stdOut("=" * 50, 0)
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as msg:
|
except Exception as msg:
|
||||||
Upgrade.stdOut(f"ERROR: {msg} [installCustomOLSBinaries]", 0)
|
Upgrade.stdOut(f"ERROR: {msg} [installCustomOLSBinaries]", 0)
|
||||||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user