Files
CyberPanel/plogical/resourceLimits.py

557 lines
21 KiB
Python
Raw Normal View History

Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
#!/usr/local/CyberCP/bin/python
"""
CyberPanel Resource Limits Manager
Handles resource limits using OpenLiteSpeed native cgroups v2 integration
"""
import os
import subprocess
import logging as log
from pathlib import Path
# Django imports
import sys
sys.path.append('/usr/local/CyberCP')
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
django.setup()
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
class ResourceLimitsManager:
"""
Manages resource limits for websites using OpenLiteSpeed native cgroups v2 API
This uses the lscgctl command to set per-user limits, which OLS enforces automatically
"""
# Path to OLS cgroups control tool
LSCGCTL_PATH = "/usr/local/lsws/lsns/bin/lscgctl"
LSSETUP_PATH = "/usr/local/lsws/lsns/bin/lssetup"
OLS_CONF_PATH = "/usr/local/lsws/conf/httpd_config.conf"
def __init__(self):
"""Initialize the resource limits manager"""
self._initialized = False
def _check_rhel8_cgroups_v2(self):
"""
Check if RHEL 8 family needs manual cgroups v2 enablement
RHEL 8, AlmaLinux 8, Rocky Linux 8, and CloudLinux 8 have cgroups v2
backported to kernel 4.18 but it's disabled by default.
Returns:
bool: True if cgroups v2 is available or not RHEL 8, False if needs enablement
"""
try:
# Check if this is a RHEL 8 family system
redhat_release_paths = ['/etc/redhat-release', '/etc/system-release']
is_rhel8 = False
os_name = "Unknown"
for release_file in redhat_release_paths:
if os.path.exists(release_file):
try:
with open(release_file, 'r') as f:
release_content = f.read().lower()
os_name = release_content.strip()
# Check for RHEL 8 family (RHEL, AlmaLinux, Rocky, CloudLinux, CentOS 8)
if ('release 8' in release_content or
'release 8.' in release_content):
if any(distro in release_content for distro in
['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
is_rhel8 = True
break
except:
pass
if not is_rhel8:
# Not RHEL 8 family, no special handling needed
return True
# This is RHEL 8 family - check if cgroups v2 is actually enabled
logging.writeToFile(f"Detected RHEL 8 family system: {os_name}")
# Check if cgroups v2 is mounted (indicates it's enabled)
try:
result = subprocess.run(
['mount'],
capture_output=True,
text=True,
timeout=5
)
if 'cgroup2' in result.stdout:
logging.writeToFile("cgroups v2 is enabled on RHEL 8 family system")
return True
else:
# cgroups v2 is not enabled - provide instructions
logging.writeToFile("=" * 80)
logging.writeToFile("RHEL 8 FAMILY: cgroups v2 MANUAL ENABLEMENT REQUIRED")
logging.writeToFile("=" * 80)
logging.writeToFile(f"System: {os_name}")
logging.writeToFile(f"Kernel: {os.uname().release}")
logging.writeToFile("")
logging.writeToFile("RHEL 8, AlmaLinux 8, Rocky Linux 8, and CloudLinux 8 have cgroups v2")
logging.writeToFile("backported but disabled by default. To enable, run these commands:")
logging.writeToFile("")
logging.writeToFile("1. Enable cgroups v2 in boot parameters:")
logging.writeToFile(" grubby --update-kernel=ALL --args='systemd.unified_cgroup_hierarchy=1'")
logging.writeToFile("")
logging.writeToFile("2. Reboot the system:")
logging.writeToFile(" reboot")
logging.writeToFile("")
logging.writeToFile("3. After reboot, verify cgroups v2 is enabled:")
logging.writeToFile(" mount | grep cgroup2")
logging.writeToFile("")
logging.writeToFile("4. Then create websites with resource limits")
logging.writeToFile("=" * 80)
return False
except Exception as e:
logging.writeToFile(f"Error checking cgroups v2 mount status: {str(e)}")
return False
except Exception as e:
logging.writeToFile(f"Error checking RHEL 8 family status: {str(e)}")
# If we can't detect, assume it's OK and let the normal checks proceed
return True
Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
def _ensure_cgroups_enabled(self):
"""
Ensure OpenLiteSpeed cgroups are enabled
This performs automatic setup if needed
Returns:
bool: True if cgroups are enabled, False otherwise
"""
if self._initialized:
return True
try:
# Special check for RHEL 8 family systems
if not self._check_rhel8_cgroups_v2():
return False
Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
# Check kernel support first
if not os.path.exists('/sys/fs/cgroup/cgroup.controllers'):
logging.writeToFile("cgroups v2 not available on this system (requires kernel 5.2+)")
logging.writeToFile("For RHEL 8 family, see instructions above to enable cgroups v2")
Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
return False
# Check if lscgctl exists
if not os.path.exists(self.LSCGCTL_PATH):
logging.writeToFile("lscgctl not found, attempting to run lssetup...")
# Try to run lssetup
if os.path.exists(self.LSSETUP_PATH):
result = subprocess.run(
[self.LSSETUP_PATH],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
logging.writeToFile("lssetup completed successfully")
else:
logging.writeToFile(f"lssetup failed: {result.stderr}")
return False
else:
logging.writeToFile(f"lssetup not found at {self.LSSETUP_PATH}")
return False
# Check if cgroups are enabled in OLS config
if not self._check_ols_cgroups_enabled():
logging.writeToFile("Enabling cgroups in OpenLiteSpeed configuration...")
if not self._enable_ols_cgroups():
return False
self._initialized = True
logging.writeToFile("OpenLiteSpeed cgroups support ready")
return True
except Exception as e:
logging.writeToFile(f"Error ensuring cgroups enabled: {str(e)}")
return False
def _check_ols_cgroups_enabled(self):
"""
Check if cgroups are enabled in OpenLiteSpeed config
Returns:
bool: True if enabled, False otherwise
"""
try:
if not os.path.exists(self.OLS_CONF_PATH):
logging.writeToFile(f"OLS config not found at {self.OLS_CONF_PATH}")
return False
with open(self.OLS_CONF_PATH, 'r') as f:
config = f.read()
# Look for CGIRLimit section and check cgroups value
# Pattern: cgroups followed by whitespace and value
import re
# Find CGIRLimit section
cgirlimit_match = re.search(r'CGIRLimit\s*\{([^}]+)\}', config, re.DOTALL)
if not cgirlimit_match:
logging.writeToFile("CGIRLimit section not found in OLS config")
return False
cgirlimit_section = cgirlimit_match.group(1)
# Check for cgroups setting
cgroups_match = re.search(r'cgroups\s+(\d+)', cgirlimit_section)
if cgroups_match:
value = int(cgroups_match.group(1))
# 1 = On, 0 = Off, 2 = Disabled
if value == 1:
logging.writeToFile("cgroups already enabled in OLS config")
return True
else:
logging.writeToFile(f"cgroups is set to {value} (need 1 for enabled)")
return False
else:
logging.writeToFile("cgroups setting not found in CGIRLimit section")
return False
except Exception as e:
logging.writeToFile(f"Error checking OLS cgroups config: {str(e)}")
return False
def _enable_ols_cgroups(self):
"""
Enable cgroups in OpenLiteSpeed configuration
Returns:
bool: True if successful, False otherwise
"""
try:
if not os.path.exists(self.OLS_CONF_PATH):
return False
# Read the config file
with open(self.OLS_CONF_PATH, 'r') as f:
config = f.read()
import re
# Find CGIRLimit section
cgirlimit_match = re.search(r'(CGIRLimit\s*\{[^}]+\})', config, re.DOTALL)
if not cgirlimit_match:
logging.writeToFile("CGIRLimit section not found, cannot enable cgroups")
return False
old_section = cgirlimit_match.group(1)
# Check if cgroups line exists
if re.search(r'cgroups\s+\d+', old_section):
# Replace existing cgroups value with 1
new_section = re.sub(r'cgroups\s+\d+', 'cgroups 1', old_section)
else:
# Add cgroups line before the closing brace
new_section = old_section.replace('}', ' cgroups 1\n}')
# Replace in config
new_config = config.replace(old_section, new_section)
# Backup original config
backup_path = self.OLS_CONF_PATH + '.backup'
with open(backup_path, 'w') as f:
f.write(config)
# Write new config
with open(self.OLS_CONF_PATH, 'w') as f:
f.write(new_config)
logging.writeToFile("Enabled cgroups in OLS config, restarting OpenLiteSpeed...")
# Graceful restart of OLS
result = subprocess.run(
['/usr/local/lsws/bin/lswsctrl', 'restart'],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
logging.writeToFile("OpenLiteSpeed restarted successfully")
return True
else:
logging.writeToFile(f"Failed to restart OpenLiteSpeed: {result.stderr}")
return False
except Exception as e:
logging.writeToFile(f"Error enabling OLS cgroups: {str(e)}")
return False
def set_user_limits(self, username, package):
"""
Set resource limits for a Linux user using OpenLiteSpeed lscgctl
Args:
username (str): Linux username (e.g., website owner)
package (Package): Package model instance with resource limits
Returns:
bool: True if successful, False otherwise
"""
# Skip if limits not enforced
if not package.enforceDiskLimits:
logging.writeToFile(f"Resource limits not enforced for {username} (enforceDiskLimits=0)")
return True
# Ensure cgroups are enabled (auto-setup if needed)
if not self._ensure_cgroups_enabled():
logging.writeToFile(f"cgroups not available, skipping resource limits for {username}")
return False
try:
# Convert package limits to lscgctl format
# CPU: convert cores to percentage (1 core = 100%, 2 cores = 200%, etc.)
cpu_percent = package.cpuCores * 100
# Memory: convert MB to format with M suffix
memory_limit = f"{package.memoryLimitMB}M"
# Tasks: use procHardLimit as max tasks
max_tasks = package.procHardLimit
# Build lscgctl command
# Format: lscgctl set username --cpu 100 --mem 1024M --tasks 500
cmd = [
self.LSCGCTL_PATH,
'set',
username,
'--cpu', str(cpu_percent),
'--mem', memory_limit,
'--tasks', str(max_tasks)
]
# Note: I/O limits may require additional configuration
# Check if lscgctl supports --io parameter
logging.writeToFile(f"Setting limits for user {username}: CPU={cpu_percent}%, MEM={memory_limit}, TASKS={max_tasks}")
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
logging.writeToFile(f"Successfully set resource limits for {username}")
return True
else:
error_msg = result.stderr if result.stderr else result.stdout
logging.writeToFile(f"Failed to set limits for {username}: {error_msg}")
return False
except subprocess.TimeoutExpired:
logging.writeToFile(f"Timeout setting resource limits for {username}")
return False
except Exception as e:
logging.writeToFile(f"Error setting resource limits for {username}: {str(e)}")
return False
def remove_user_limits(self, username):
"""
Remove resource limits for a Linux user
Args:
username (str): Linux username
Returns:
bool: True if successful, False otherwise
"""
if not os.path.exists(self.LSCGCTL_PATH):
logging.writeToFile(f"lscgctl not available, skipping limit removal for {username}")
return False
try:
# Use lscgctl to remove limits
# Format: lscgctl remove username
cmd = [self.LSCGCTL_PATH, 'remove', username]
logging.writeToFile(f"Removing resource limits for user {username}")
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
logging.writeToFile(f"Successfully removed resource limits for {username}")
return True
else:
error_msg = result.stderr if result.stderr else result.stdout
# It's not critical if removal fails (user may not have had limits)
logging.writeToFile(f"Note: Could not remove limits for {username}: {error_msg}")
return True
except subprocess.TimeoutExpired:
logging.writeToFile(f"Timeout removing resource limits for {username}")
return False
except Exception as e:
logging.writeToFile(f"Error removing resource limits for {username}: {str(e)}")
return False
def get_user_limits(self, username):
"""
Get current resource limits for a Linux user
Args:
username (str): Linux username
Returns:
dict: Current limits or None
"""
if not os.path.exists(self.LSCGCTL_PATH):
return None
try:
# Use lscgctl to get limits
# Format: lscgctl get username
cmd = [self.LSCGCTL_PATH, 'get', username]
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
# Parse the output (format may vary)
return {'output': result.stdout.strip()}
else:
return None
except Exception as e:
logging.writeToFile(f"Error getting resource limits for {username}: {str(e)}")
return None
def set_inode_limit(self, domain, username, inode_limit):
"""
Set inode (file count) limit for a website using filesystem quotas
Args:
domain (str): Website domain name
username (str): System username for the website
inode_limit (int): Maximum number of files/directories
Returns:
bool: True if successful, False otherwise
"""
try:
# Check if quota tools are available
result = subprocess.run(
['which', 'setquota'],
capture_output=True,
timeout=5
)
if result.returncode != 0:
logging.writeToFile("setquota command not found, skipping inode limit")
return False
# Set inode quota using setquota
# Format: setquota -u username 0 0 soft_inode hard_inode /
result = subprocess.run(
['setquota', '-u', username, '0', '0',
str(inode_limit), str(inode_limit), '/'],
check=True,
capture_output=True,
timeout=10
)
logging.writeToFile(f"Set inode limit for {domain} ({username}): {inode_limit}")
return True
except subprocess.TimeoutExpired:
logging.writeToFile(f"Timeout setting inode limit for {domain}")
return False
except subprocess.CalledProcessError as e:
logging.writeToFile(f"Failed to set inode limit: {e.stderr.decode() if e.stderr else str(e)}")
return False
except Exception as e:
logging.writeToFile(f"Failed to set inode limit: {str(e)}")
return False
def check_cgroup_support(self):
"""
Check if OpenLiteSpeed cgroups v2 support is available
Returns:
dict: Support status for various features
"""
support = {
'cgroups_v2': False,
'lscgctl_available': False,
'memory_controller': False,
'cpu_controller': False,
'io_controller': False,
'quota_tools': False,
'rhel8_family': False,
'rhel8_needs_enablement': False,
'os_name': 'Unknown'
Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
}
try:
# Check for RHEL 8 family
redhat_release_paths = ['/etc/redhat-release', '/etc/system-release']
for release_file in redhat_release_paths:
if os.path.exists(release_file):
try:
with open(release_file, 'r') as f:
release_content = f.read()
support['os_name'] = release_content.strip()
# Check for RHEL 8 family
if ('release 8' in release_content.lower() or
'release 8.' in release_content.lower()):
if any(distro in release_content.lower() for distro in
['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
support['rhel8_family'] = True
# Check if cgroups v2 is actually mounted
result = subprocess.run(['mount'], capture_output=True,
text=True, timeout=5)
if 'cgroup2' not in result.stdout:
support['rhel8_needs_enablement'] = True
break
except:
pass
Add comprehensive resource limits with automatic OpenLiteSpeed cgroups setup This commit implements per-package resource limits for CyberPanel shared hosting using OpenLiteSpeed's native cgroups v2 integration with automatic server configuration. Features: - 7 new package fields: memoryLimitMB, cpuCores, ioLimitMBPS, inodeLimit, maxConnections, procSoftLimit, procHardLimit - Automatic OLS cgroups setup (no manual server configuration required) - Multi-layer enforcement: OLS config + kernel cgroups v2 + filesystem quotas - Per-user enforcement (subdomains/addon domains share parent's limits) - Graceful degradation if cgroups unavailable - Automatic backup of OLS config before modification Backend Changes: - packages/models.py: Added 7 resource limit fields with defaults - packages/packagesManager.py: CRUD operations for resource limits - plogical/resourceLimits.py: NEW - Resource manager with auto-setup * _ensure_cgroups_enabled(): Automatic OLS cgroups configuration * set_user_limits(): Apply limits via lscgctl * remove_user_limits(): Cleanup on deletion * set_inode_limit(): Filesystem quota management - plogical/vhostConfs.py: Parameterized hardcoded resource limits - plogical/vhost.py: Updated signatures to accept resource limits - plogical/virtualHostUtilities.py: Extract and apply package limits Frontend Changes: - packages/templates/packages/createPackage.html: Resource limits UI - packages/templates/packages/modifyPackage.html: Resource limits UI - packages/static/packages/packages.js: AngularJS controller updates Automatic Setup Flow: When creating a website with enforceDiskLimits=True: 1. Check kernel cgroups v2 support 2. Run lssetup if lscgctl missing 3. Enable cgroups in OLS config if needed 4. Backup and modify /usr/local/lsws/conf/httpd_config.conf 5. Graceful restart of OpenLiteSpeed 6. Apply per-user limits via lscgctl 7. Set inode quotas via setquota Requirements: - Linux kernel 5.2+ (cgroups v2) - OpenLiteSpeed 1.8+ (with lsns support) - quota tools (optional, for inode limits) Backward Compatibility: - Existing packages receive default values via migration - No manual setup required for new installations - Graceful fallback if cgroups unavailable
2025-11-11 17:14:39 +05:00
# Check cgroups v2
if os.path.exists('/sys/fs/cgroup/cgroup.controllers'):
support['cgroups_v2'] = True
# Check controllers
with open('/sys/fs/cgroup/cgroup.controllers', 'r') as f:
controllers = f.read().strip().split()
support['memory_controller'] = 'memory' in controllers
support['cpu_controller'] = 'cpu' in controllers
support['io_controller'] = 'io' in controllers
# Check lscgctl tool
support['lscgctl_available'] = os.path.exists(self.LSCGCTL_PATH)
# Check quota tools
result = subprocess.run(['which', 'setquota'], capture_output=True, timeout=5)
support['quota_tools'] = result.returncode == 0
except Exception as e:
logging.writeToFile(f"Error checking cgroup support: {str(e)}")
return support
# Singleton instance
resource_manager = ResourceLimitsManager()