Files
CyberPanel/packages/packagesManager.py

393 lines
15 KiB
Python
Raw Normal View History

2025-08-01 14:56:30 +05:00
#!/usr/local/CyberCP/bin/python
import os.path
import sys
import django
from plogical.httpProc import httpProc
sys.path.append('/usr/local/CyberCP')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
django.setup()
from django.shortcuts import redirect
from django.http import HttpResponse
from loginSystem.views import loadLoginPage
from loginSystem.models import Administrator
import json
from .models import Package
from plogical.acl import ACLManager
class PackagesManager:
def __init__(self, request = None):
self.request = request
def packagesHome(self):
proc = httpProc(self.request, 'packages/index.html',
None, 'createPackage')
return proc.render()
def createPacakge(self):
userID = self.request.session['userID']
admin = Administrator.objects.get(pk=userID)
proc = httpProc(self.request, 'packages/createPackage.html',
{"adminNamePackage": admin.userName}, 'createPackage')
return proc.render()
def deletePacakge(self):
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
packageList = ACLManager.loadPackages(userID, currentACL)
proc = httpProc(self.request, 'packages/deletePackage.html',
{"packageList": packageList}, 'deletePackage')
return proc.render()
def submitPackage(self):
try:
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if ACLManager.currentContextPermission(currentACL, 'createPackage') == 0:
return ACLManager.loadErrorJson('saveStatus', 0)
data = json.loads(self.request.body)
packageName = data['packageName'].replace(' ', '')
packageSpace = int(data['diskSpace'])
packageBandwidth = int(data['bandwidth'])
packageDatabases = int(data['dataBases'])
ftpAccounts = int(data['ftpAccounts'])
emails = int(data['emails'])
allowedDomains = int(data['allowedDomains'])
try:
api = data['api']
except:
api = '0'
try:
allowFullDomain = int(data['allowFullDomain'])
except:
allowFullDomain = 1
try:
enforceDiskLimits = int(data['enforceDiskLimits'])
except:
enforceDiskLimits = 0
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
# Resource Limits - with backward compatibility
try:
memoryLimitMB = int(data['memoryLimitMB'])
except:
memoryLimitMB = 1024
try:
cpuCores = int(data['cpuCores'])
except:
cpuCores = 1
try:
ioLimitMBPS = int(data['ioLimitMBPS'])
except:
ioLimitMBPS = 10
try:
inodeLimit = int(data['inodeLimit'])
except:
inodeLimit = 400000
try:
maxConnections = int(data['maxConnections'])
except:
maxConnections = 10
try:
procSoftLimit = int(data['procSoftLimit'])
except:
procSoftLimit = 400
try:
procHardLimit = int(data['procHardLimit'])
except:
procHardLimit = 500
2025-08-01 14:56:30 +05:00
if packageSpace < 0 or packageBandwidth < 0 or packageDatabases < 0 or ftpAccounts < 0 or emails < 0 or allowedDomains < 0:
data_ret = {'saveStatus': 0, 'error_message': "All values should be positive or 0."}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
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
# Validate resource limits
if memoryLimitMB < 256 or cpuCores < 1 or ioLimitMBPS < 1 or inodeLimit < 10000 or maxConnections < 1 or procSoftLimit < 1 or procHardLimit < 1:
data_ret = {'saveStatus': 0, 'error_message': "Resource limits must be positive and within valid ranges."}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
2025-08-01 14:56:30 +05:00
admin = Administrator.objects.get(pk=userID)
if api == '0':
packageName = admin.userName + "_" + packageName
package = Package(admin=admin, packageName=packageName, diskSpace=packageSpace,
bandwidth=packageBandwidth, ftpAccounts=ftpAccounts, dataBases=packageDatabases,
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
emailAccounts=emails, allowedDomains=allowedDomains, allowFullDomain=allowFullDomain,
enforceDiskLimits=enforceDiskLimits, memoryLimitMB=memoryLimitMB, cpuCores=cpuCores,
ioLimitMBPS=ioLimitMBPS, inodeLimit=inodeLimit, maxConnections=maxConnections,
procSoftLimit=procSoftLimit, procHardLimit=procHardLimit)
2025-08-01 14:56:30 +05:00
package.save()
data_ret = {'status': 1, 'saveStatus': 1, 'error_message': "None"}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
except BaseException as msg:
data_ret = {'status': 0, 'saveStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
def submitDelete(self):
try:
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if ACLManager.currentContextPermission(currentACL, 'deletePackage') == 0:
return ACLManager.loadErrorJson('deleteStatus', 0)
data = json.loads(self.request.body)
packageName = data['packageName']
delPackage = Package.objects.get(packageName=packageName)
## Check package ownership
admin = Administrator.objects.get(pk=userID)
if ACLManager.CheckPackageOwnership(delPackage, admin, currentACL) == 0:
return ACLManager.loadErrorJson('deleteStatus', 0)
delPackage.delete()
data_ret = {'status': 1, 'deleteStatus': 1, 'error_message': "None"}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
except BaseException as msg:
data_ret = {'status': 0, 'deleteStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
def modifyPackage(self):
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
packageList = ACLManager.loadPackages(userID, currentACL)
proc = httpProc(self.request, 'packages/modifyPackage.html',
{"packList": packageList}, 'modifyPackage')
return proc.render()
def submitModify(self):
try:
userID = self.request.session['userID']
data = json.loads(self.request.body)
packageName = data['packageName']
currentACL = ACLManager.loadedACL(userID)
if ACLManager.currentContextPermission(currentACL, 'modifyPackage') == 0:
return ACLManager.loadErrorJson('modifyStatus', 0)
modifyPack = Package.objects.get(packageName=packageName)
## Check package ownership
admin = Administrator.objects.get(pk=userID)
if ACLManager.CheckPackageOwnership(modifyPack, admin, currentACL) == 0:
return ACLManager.loadErrorJson('deleteStatus', 0)
diskSpace = modifyPack.diskSpace
bandwidth = modifyPack.bandwidth
ftpAccounts = modifyPack.ftpAccounts
dataBases = modifyPack.dataBases
emails = modifyPack.emailAccounts
data_ret = {'emails': emails, 'modifyStatus': 1, 'error_message': "None",
"diskSpace": diskSpace, "bandwidth": bandwidth, "ftpAccounts": ftpAccounts,
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
"dataBases": dataBases, "allowedDomains": modifyPack.allowedDomains,
'allowFullDomain': modifyPack.allowFullDomain, 'enforceDiskLimits': modifyPack.enforceDiskLimits,
'memoryLimitMB': modifyPack.memoryLimitMB, 'cpuCores': modifyPack.cpuCores,
'ioLimitMBPS': modifyPack.ioLimitMBPS, 'inodeLimit': modifyPack.inodeLimit,
'maxConnections': modifyPack.maxConnections, 'procSoftLimit': modifyPack.procSoftLimit,
'procHardLimit': modifyPack.procHardLimit}
2025-08-01 14:56:30 +05:00
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
except BaseException as msg:
data_ret = {'modifyStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
def saveChanges(self):
try:
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
admin = Administrator.objects.get(pk=userID)
if ACLManager.currentContextPermission(currentACL, 'modifyPackage') == 0:
return ACLManager.loadErrorJson('saveStatus', 0)
data = json.loads(self.request.body)
packageName = data['packageName']
if data['diskSpace'] < 0 or data['bandwidth'] < 0 or data['ftpAccounts'] < 0 or data[
'dataBases'] < 0 or \
data['emails'] < 0 or data['allowedDomains'] < 0:
data_ret = {'saveStatus': 0, 'error_message': "All values should be positive or 0."}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
modifyPack = Package.objects.get(packageName=packageName)
if modifyPack.admin == admin:
modifyPack.diskSpace = data['diskSpace']
modifyPack.bandwidth = data['bandwidth']
modifyPack.ftpAccounts = data['ftpAccounts']
modifyPack.dataBases = data['dataBases']
modifyPack.emailAccounts = data['emails']
modifyPack.allowedDomains = data['allowedDomains']
try:
modifyPack.allowFullDomain = int(data['allowFullDomain'])
except:
modifyPack.allowFullDomain = 1
try:
modifyPack.enforceDiskLimits = int(data['enforceDiskLimits'])
except:
modifyPack.enforceDiskLimits = 0
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
# Update resource limits
try:
modifyPack.memoryLimitMB = int(data['memoryLimitMB'])
except:
pass # Keep existing value
try:
modifyPack.cpuCores = int(data['cpuCores'])
except:
pass # Keep existing value
try:
modifyPack.ioLimitMBPS = int(data['ioLimitMBPS'])
except:
pass # Keep existing value
try:
modifyPack.inodeLimit = int(data['inodeLimit'])
except:
pass # Keep existing value
try:
modifyPack.maxConnections = int(data['maxConnections'])
except:
pass # Keep existing value
try:
modifyPack.procSoftLimit = int(data['procSoftLimit'])
except:
pass # Keep existing value
try:
modifyPack.procHardLimit = int(data['procHardLimit'])
except:
pass # Keep existing value
2025-08-01 14:56:30 +05:00
modifyPack.save()
## Fix https://github.com/usmannasir/cyberpanel/issues/998
# from plogical.IncScheduler import IncScheduler
# isPU = IncScheduler('CalculateAndUpdateDiskUsage', {})
# isPU.start()
from plogical.processUtilities import ProcessUtilities
command = '/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForce'
ProcessUtilities.outputExecutioner(command)
data_ret = {'status': 1, 'saveStatus': 1, 'error_message': "None"}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
else:
data_ret = {'status': 0, 'saveStatus': 0, 'error_message': "You don't own this package."}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
except BaseException as msg:
data_ret = {'status': 0, 'saveStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
def listPackages(self):
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
packageList = ACLManager.loadPackages(userID, currentACL)
proc = httpProc(self.request, 'packages/listPackages.html',
{"packList": packageList}, 'listPackages')
return proc.render()
def listPackagesAPI(self,data=None):
"""
List of packages for API
:param data:
:return HttpResponse:
"""
try:
adminUser = data['adminUser']
admin = Administrator.objects.get(userName=adminUser)
currentACL = ACLManager.loadedACL(admin.id)
packageList = ACLManager.loadPackages(admin.id, currentACL)
return HttpResponse(json.dumps(packageList))
except BaseException as msg:
data_ret = {'status': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
def fetchPackagesTable(self):
try:
userID = self.request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if ACLManager.currentContextPermission(currentACL, 'listPackages') == 0:
return ACLManager.loadErrorJson()
packages = ACLManager.loadPackageObjects(userID, currentACL)
json_data = "["
checker = 0
for items in packages:
dic = {'package': items.packageName,
'diskSpace': items.diskSpace,
'bandwidth': items.bandwidth,
'emailAccounts': items.emailAccounts,
'dataBases': items.dataBases,
'ftpAccounts': items.ftpAccounts,
'allowedDomains': items.allowedDomains,
'allowFullDomain': items.allowFullDomain,
'enforceDiskLimits': items.enforceDiskLimits
}
if checker == 0:
json_data = json_data + json.dumps(dic)
checker = 1
else:
json_data = json_data + ',' + json.dumps(dic)
json_data = json_data + ']'
final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": json_data})
return HttpResponse(final_json)
except KeyError:
return redirect(loadLoginPage)