mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-13 08:46: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)
|
||||
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):
|
||||
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
||||
try:
|
||||
@@ -362,21 +432,36 @@ class InstallCyberPanel:
|
||||
logging.InstallLog.writeToFile(str(e) + " [installCustomOLSBinaries - module install]")
|
||||
return False
|
||||
|
||||
# Verify installation
|
||||
if os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH):
|
||||
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
|
||||
else:
|
||||
InstallCyberPanel.stdOut("ERROR: Installation verification failed", 1)
|
||||
# Verify installation files exist
|
||||
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||
InstallCyberPanel.stdOut("ERROR: Installation verification failed - files not found", 1)
|
||||
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:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [installCustomOLSBinaries]")
|
||||
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
||||
|
||||
@@ -700,6 +700,76 @@ class Upgrade:
|
||||
Upgrade.stdOut(f"ERROR: {msg} [downloadCustomBinary]", 0)
|
||||
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
|
||||
def installCustomOLSBinaries():
|
||||
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
||||
@@ -777,21 +847,36 @@ class Upgrade:
|
||||
Upgrade.stdOut(f"ERROR: Failed to install module: {e}", 0)
|
||||
return False
|
||||
|
||||
# Verify installation
|
||||
if os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH):
|
||||
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
|
||||
else:
|
||||
Upgrade.stdOut("ERROR: Installation verification failed", 0)
|
||||
# Verify installation files exist
|
||||
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||
Upgrade.stdOut("ERROR: Installation verification failed - files not found", 0)
|
||||
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:
|
||||
Upgrade.stdOut(f"ERROR: {msg} [installCustomOLSBinaries]", 0)
|
||||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||
|
||||
Reference in New Issue
Block a user