| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  | #!/usr/local/CyberCP/bin/python | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os.path | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import django | 
					
						
							|  |  |  | from datetime import datetime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from plogical.DockerSites import Docker_Sites | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sys.path.append('/usr/local/CyberCP') | 
					
						
							|  |  |  | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings") | 
					
						
							|  |  |  | django.setup() | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | from plogical.acl import ACLManager | 
					
						
							|  |  |  | import plogical.CyberCPLogFileWriter as logging | 
					
						
							|  |  |  | from django.shortcuts import HttpResponse, render, redirect | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  | from django.urls import reverse | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  | from loginSystem.models import Administrator | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import shlex | 
					
						
							|  |  |  | import time | 
					
						
							|  |  |  | from dockerManager.models import Containers | 
					
						
							|  |  |  | from math import ceil | 
					
						
							|  |  |  | import docker | 
					
						
							|  |  |  | import docker.utils | 
					
						
							|  |  |  | import requests | 
					
						
							|  |  |  | from plogical.processUtilities import ProcessUtilities | 
					
						
							|  |  |  | from serverStatus.serverStatusUtil import ServerStatusUtil | 
					
						
							|  |  |  | import threading as multi | 
					
						
							|  |  |  | from plogical.httpProc import httpProc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Use default socket to connect | 
					
						
							|  |  |  | class ContainerManager(multi.Thread): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, name=None, function=None, request = None, templateName = None, data = None): | 
					
						
							|  |  |  |         multi.Thread.__init__(self) | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.function = function | 
					
						
							|  |  |  |         self.request = request | 
					
						
							|  |  |  |         self.templateName = templateName | 
					
						
							|  |  |  |         self.data = data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def renderDM(self): | 
					
						
							|  |  |  |         proc = httpProc(self.request, self.templateName, self.data, 'admin') | 
					
						
							|  |  |  |         return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if self.function == 'submitInstallDocker': | 
					
						
							|  |  |  |                 self.submitInstallDocker() | 
					
						
							|  |  |  |             elif self.function == 'restartGunicorn': | 
					
						
							|  |  |  |                 command = 'sudo systemctl restart gunicorn.socket' | 
					
						
							|  |  |  |                 ProcessUtilities.executioner(command) | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         except Exception as msg: | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             logging.CyberCPLogFileWriter.writeToFile( str(msg) + ' [ContainerManager.run]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def executioner(command, statusFile): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             res = subprocess.call(shlex.split(command), stdout=statusFile, stderr=statusFile) | 
					
						
							|  |  |  |             if res == 1: | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return 1 | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         except Exception as msg: | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             logging.CyberCPLogFileWriter.writeToFile(str(msg)) | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def submitInstallDocker(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             currentACL = ACLManager.loadedACL(self.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if ACLManager.currentContextPermission(currentACL, 'createContainer') == 0: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             writeToFile = open(ServerStatusUtil.lswsInstallStatusPath, 'w') | 
					
						
							|  |  |  |             writeToFile.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             execPath = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/dockerManager/dockerInstall.py" | 
					
						
							|  |  |  |             ProcessUtilities.executioner(execPath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             time.sleep(2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         except Exception as msg: | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             logging.CyberCPLogFileWriter.statusWriter(ServerStatusUtil.lswsInstallStatusPath, str(msg) + ' [404].', 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def createContainer(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         client = docker.from_env() | 
					
						
							|  |  |  |         dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         adminNames = ACLManager.loadAllUsers(userID) | 
					
						
							|  |  |  |         tag = request.GET.get('tag') | 
					
						
							|  |  |  |         image = request.GET.get('image') | 
					
						
							|  |  |  |         tag = tag.split(" (")[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if "/" in image: | 
					
						
							|  |  |  |             name = image.split("/")[0] + "." + image.split("/")[1] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             name = image | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             inspectImage = dockerAPI.inspect_image(image + ":" + tag) | 
					
						
							|  |  |  |         except docker.errors.ImageNotFound: | 
					
						
							|  |  |  |             val = request.session['userID'] | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=val) | 
					
						
							|  |  |  |             proc = httpProc(request, 'dockerManager/images.html', {"type": admin.type, | 
					
						
							|  |  |  |                                                                  'image': image, | 
					
						
							|  |  |  |                                                                  'tag': tag}) | 
					
						
							|  |  |  |             return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         envList = {}; | 
					
						
							|  |  |  |         if 'Env' in inspectImage['Config']: | 
					
						
							|  |  |  |             for item in inspectImage['Config']['Env']: | 
					
						
							|  |  |  |                 if '=' in item: | 
					
						
							|  |  |  |                     splitedItem = item.split('=', 1) | 
					
						
							|  |  |  |                     print(splitedItem) | 
					
						
							|  |  |  |                     envList[splitedItem[0]] = splitedItem[1] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     envList[item] = "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         portConfig = {}; | 
					
						
							|  |  |  |         if 'ExposedPorts' in inspectImage['Config']: | 
					
						
							|  |  |  |             for item in inspectImage['Config']['ExposedPorts']: | 
					
						
							|  |  |  |                 portDef = item.split('/') | 
					
						
							|  |  |  |                 portConfig[portDef[0]] = portDef[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if image is None or image is '' or tag is None or tag is '': | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |             return redirect(reverse('containerImage')) | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Data = {"ownerList": adminNames, "image": image, "name": name, "tag": tag, "portConfig": portConfig, | 
					
						
							|  |  |  |                 "envList": envList} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template = 'dockerManager/runContainer.html' | 
					
						
							|  |  |  |         proc = httpProc(request, template, Data, 'admin') | 
					
						
							|  |  |  |         return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def loadContainerHome(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Check if user is admin or has container access | 
					
						
							|  |  |  |             currentACL = ACLManager.loadedACL(userID) | 
					
						
							|  |  |  |             if currentACL['admin'] != 1: | 
					
						
							|  |  |  |                 # For non-admin users, check container ownership | 
					
						
							|  |  |  |                 if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                     return ACLManager.loadError() | 
					
						
							|  |  |  |             # Admin users can access any container, including ones not in database | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 return HttpResponse("Container not found") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data = {} | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 con = Containers.objects.get(name=name) | 
					
						
							|  |  |  |                 data['name'] = name | 
					
						
							|  |  |  |                 data['image'] = con.image + ":" + con.tag | 
					
						
							|  |  |  |                 data['ports'] = json.loads(con.ports) | 
					
						
							|  |  |  |                 data['cid'] = con.cid | 
					
						
							|  |  |  |                 data['envList'] = json.loads(con.env) | 
					
						
							|  |  |  |                 data['volList'] = json.loads(con.volumes) | 
					
						
							|  |  |  |                 data['memoryLimit'] = con.memory | 
					
						
							|  |  |  |                 if con.startOnReboot == 1: | 
					
						
							|  |  |  |                     data['startOnReboot'] = 'true' | 
					
						
							|  |  |  |                     data['restartPolicy'] = "Yes" | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     data['startOnReboot'] = 'false' | 
					
						
							|  |  |  |                     data['restartPolicy'] = "No" | 
					
						
							|  |  |  |             except Containers.DoesNotExist: | 
					
						
							|  |  |  |                 # Container exists in Docker but not in database | 
					
						
							|  |  |  |                 data['name'] = name | 
					
						
							|  |  |  |                 data['image'] = container.image.tags[0] if container.image.tags else "Unknown" | 
					
						
							|  |  |  |                 data['ports'] = {} | 
					
						
							|  |  |  |                 data['cid'] = container.id | 
					
						
							|  |  |  |                 data['envList'] = {} | 
					
						
							|  |  |  |                 data['volList'] = {} | 
					
						
							|  |  |  |                 data['memoryLimit'] = 512 | 
					
						
							|  |  |  |                 data['startOnReboot'] = 'false' | 
					
						
							|  |  |  |                 data['restartPolicy'] = "No" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             stats = container.stats(decode=False, stream=False) | 
					
						
							|  |  |  |             logs = container.logs(stream=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data['status'] = container.status | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if 'usage' in stats['memory_stats']: | 
					
						
							|  |  |  |                 # Calculate Usage | 
					
						
							|  |  |  |                 # Source: https://github.com/docker/docker/blob/28a7577a029780e4533faf3d057ec9f6c7a10948/api/client/stats.go#L309 | 
					
						
							|  |  |  |                 data['memoryUsage'] = (stats['memory_stats']['usage'] / stats['memory_stats']['limit']) * 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     cpu_count = len(stats["cpu_stats"]["cpu_usage"]["percpu_usage"]) | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     cpu_count = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 data['cpuUsage'] = 0.0 | 
					
						
							|  |  |  |                 cpu_delta = float(stats["cpu_stats"]["cpu_usage"]["total_usage"]) - \ | 
					
						
							|  |  |  |                             float(stats["precpu_stats"]["cpu_usage"]["total_usage"]) | 
					
						
							|  |  |  |                 system_delta = float(stats["cpu_stats"]["system_cpu_usage"]) - \ | 
					
						
							|  |  |  |                                float(stats["precpu_stats"]["system_cpu_usage"]) | 
					
						
							|  |  |  |                 if system_delta > 0.0: | 
					
						
							|  |  |  |                     data['cpuUsage'] = round(cpu_delta / system_delta * 100.0 * cpu_count, 3) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 data['memoryUsage'] = 0 | 
					
						
							|  |  |  |                 data['cpuUsage'] = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             template = 'dockerManager/viewContainer.html' | 
					
						
							|  |  |  |             proc = httpProc(request, template, data, 'admin') | 
					
						
							|  |  |  |             return proc.render() | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             return HttpResponse(str(msg)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def listContainers(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         client = docker.from_env() | 
					
						
							|  |  |  |         dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         currentACL = ACLManager.loadedACL(userID) | 
					
						
							|  |  |  |         containers = ACLManager.findAllContainers(currentACL, userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         allContainers = client.containers.list() | 
					
						
							|  |  |  |         containersList = [] | 
					
						
							|  |  |  |         showUnlistedContainer = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # TODO: Add condition to show unlisted Containers only if user has admin level access | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unlistedContainers = [] | 
					
						
							|  |  |  |         for container in allContainers: | 
					
						
							|  |  |  |             if container.name not in containers: | 
					
						
							|  |  |  |                 unlistedContainers.append(container) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not unlistedContainers: | 
					
						
							|  |  |  |             showUnlistedContainer = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         adminNames = ACLManager.loadAllUsers(userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pages = float(len(containers)) / float(10) | 
					
						
							|  |  |  |         pagination = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if pages <= 1.0: | 
					
						
							|  |  |  |             pages = 1 | 
					
						
							|  |  |  |             pagination.append('<li><a href="\#"></a></li>') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             pages = ceil(pages) | 
					
						
							|  |  |  |             finalPages = int(pages) + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for i in range(1, finalPages): | 
					
						
							|  |  |  |                 pagination.append('<li><a href="\#">' + str(i) + '</a></li>') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template = 'dockerManager/listContainers.html' | 
					
						
							|  |  |  |         proc = httpProc(request, template, {"pagination": pagination, | 
					
						
							|  |  |  |                                             "unlistedContainers": unlistedContainers, | 
					
						
							|  |  |  |                                             "adminNames": adminNames, | 
					
						
							|  |  |  |                                             "showUnlistedContainer": showUnlistedContainer}, 'admin') | 
					
						
							|  |  |  |         return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerLogs(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Check if container is registered in database or unlisted | 
					
						
							|  |  |  |             if Containers.objects.filter(name=name).exists(): | 
					
						
							|  |  |  |                 if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                     return ACLManager.loadErrorJson('containerLogStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             container = client.containers.get(name) | 
					
						
							|  |  |  |             logs = container.logs().decode("utf-8") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'containerLogStatus': 1, 'containerLog': logs, 'error_message': "None"} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'containerLogStatus': 0, 'containerLog': 'Error', 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def submitContainerCreation(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('createContainerStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             image = data['image'] | 
					
						
							|  |  |  |             tag = data['tag'] | 
					
						
							|  |  |  |             dockerOwner = data['dockerOwner'] | 
					
						
							|  |  |  |             memory = data['memory'] | 
					
						
							|  |  |  |             envList = data['envList'] | 
					
						
							|  |  |  |             volList = data['volList'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             inspectImage = dockerAPI.inspect_image(image + ":" + tag) | 
					
						
							|  |  |  |             portConfig = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 21:10:06 +02:00
										 |  |  |             # Formatting envList for usage - handle both simple and advanced modes | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             envDict = {} | 
					
						
							| 
									
										
										
										
											2025-09-12 21:10:06 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # Check if advanced mode is being used | 
					
						
							|  |  |  |             advanced_mode = data.get('advancedEnvMode', False) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if advanced_mode: | 
					
						
							|  |  |  |                 # Advanced mode: envList is already a dictionary of key-value pairs | 
					
						
							|  |  |  |                 envDict = envList | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 # Simple mode: envList is an array of objects with name/value properties | 
					
						
							|  |  |  |                 for key, value in envList.items(): | 
					
						
							|  |  |  |                     if isinstance(value, dict) and (value.get('name', '') != '' or value.get('value', '') != ''): | 
					
						
							|  |  |  |                         envDict[value['name']] = value['value'] | 
					
						
							|  |  |  |                     elif isinstance(value, str) and value != '': | 
					
						
							|  |  |  |                         # Handle case where value might be a string (fallback) | 
					
						
							|  |  |  |                         envDict[key] = value | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if 'ExposedPorts' in inspectImage['Config']: | 
					
						
							|  |  |  |                 for item in inspectImage['Config']['ExposedPorts']: | 
					
						
							|  |  |  |                     # Do not allow priviledged port numbers | 
					
						
							|  |  |  |                     if int(data[item]) < 1024 or int(data[item]) > 65535: | 
					
						
							|  |  |  |                         data_ret = {'createContainerStatus': 0, 'error_message': "Choose port between 1024 and 65535"} | 
					
						
							|  |  |  |                         json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                         return HttpResponse(json_data) | 
					
						
							|  |  |  |                     portConfig[item] = data[item] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             volumes = {} | 
					
						
							|  |  |  |             for index, volume in volList.items(): | 
					
						
							|  |  |  |                 volumes[volume['src']] = {'bind': volume['dest'], | 
					
						
							|  |  |  |                                              'mode': 'rw'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ## Create Configurations | 
					
						
							|  |  |  |             admin = Administrator.objects.get(userName=dockerOwner) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             containerArgs = {'image': image + ":" + tag, | 
					
						
							|  |  |  |                              'detach': True, | 
					
						
							|  |  |  |                              'name': name, | 
					
						
							|  |  |  |                              'ports': portConfig, | 
					
						
							|  |  |  |                              'publish_all_ports': True, | 
					
						
							|  |  |  |                              'environment': envDict, | 
					
						
							|  |  |  |                              'volumes': volumes} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             containerArgs['mem_limit'] = memory * 1048576;  # Converts MB to bytes ( 0 * x = 0 for unlimited memory) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.create(**containerArgs) | 
					
						
							|  |  |  |             except Exception as err: | 
					
						
							|  |  |  |                 if "port is already allocated" in err:  # We need to delete container if port is not available | 
					
						
							|  |  |  |                     print("Deleting container") | 
					
						
							|  |  |  |                     container.remove(force=True) | 
					
						
							|  |  |  |                 data_ret = {'createContainerStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con = Containers(admin=admin, | 
					
						
							|  |  |  |                              name=name, | 
					
						
							|  |  |  |                              tag=tag, | 
					
						
							|  |  |  |                              image=image, | 
					
						
							|  |  |  |                              memory=memory, | 
					
						
							|  |  |  |                              ports=json.dumps(portConfig), | 
					
						
							|  |  |  |                              volumes=json.dumps(volumes), | 
					
						
							|  |  |  |                              env=json.dumps(envDict), | 
					
						
							|  |  |  |                              cid=container.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'createContainerStatus': 1, 'error_message': "None"} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         except Exception as msg: | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             data_ret = {'createContainerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def submitInstallImage(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('installImageStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             image = data['image'] | 
					
						
							|  |  |  |             tag = data['tag'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 inspectImage = dockerAPI.inspect_image(image + ":" + tag) | 
					
						
							|  |  |  |                 data_ret = {'installImageStatus': 0, 'error_message': "Image already installed"} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except docker.errors.ImageNotFound: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 image = client.images.pull(image, tag=tag) | 
					
						
							|  |  |  |                 print(image.id) | 
					
						
							|  |  |  |             except docker.errors.APIError as msg: | 
					
						
							|  |  |  |                 data_ret = {'installImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'installImageStatus': 1, 'error_message': "None"} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         except Exception as msg: | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             data_ret = {'installImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |     def pullImage(self, userID=None, data=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Pull a Docker image from registry with proper error handling and security checks | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('pullImageStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             image = data['image'] | 
					
						
							|  |  |  |             tag = data.get('tag', 'latest') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Validate image name to prevent injection | 
					
						
							|  |  |  |             if not self._validate_image_name(image): | 
					
						
							|  |  |  |                 data_ret = {'pullImageStatus': 0, 'error_message': 'Invalid image name format'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Check if image already exists | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 inspectImage = dockerAPI.inspect_image(image + ":" + tag) | 
					
						
							|  |  |  |                 data_ret = {'pullImageStatus': 0, 'error_message': "Image already exists locally"} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except docker.errors.ImageNotFound: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Pull the image | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 pulled_image = client.images.pull(image, tag=tag) | 
					
						
							|  |  |  |                 data_ret = { | 
					
						
							|  |  |  |                     'pullImageStatus': 1,  | 
					
						
							|  |  |  |                     'error_message': "None", | 
					
						
							|  |  |  |                     'image_id': pulled_image.id, | 
					
						
							|  |  |  |                     'image_name': image, | 
					
						
							|  |  |  |                     'tag': tag | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'pullImageStatus': 0, 'error_message': f'Docker API error: {str(err)}'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except docker.errors.ImageNotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'pullImageStatus': 0, 'error_message': f'Image not found: {str(err)}'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except Exception as msg: | 
					
						
							|  |  |  |             data_ret = {'pullImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _validate_image_name(self, image_name): | 
					
						
							|  |  |  |         """Validate Docker image name to prevent injection attacks""" | 
					
						
							|  |  |  |         if not image_name or len(image_name) > 255: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Allow alphanumeric, hyphens, underscores, dots, and forward slashes | 
					
						
							|  |  |  |         import re | 
					
						
							|  |  |  |         pattern = r'^[a-zA-Z0-9._/-]+$' | 
					
						
							|  |  |  |         return re.match(pattern, image_name) is not None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |     def submitContainerDeletion(self, userID=None, data=None, called=False): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             # Check if container is registered in database or unlisted | 
					
						
							|  |  |  |             if Containers.objects.filter(name=name).exists(): | 
					
						
							|  |  |  |                 if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                     if called: | 
					
						
							|  |  |  |                         return 'Permission error' | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         return ACLManager.loadErrorJson('websiteDeleteStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             unlisted = data['unlisted'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if 'force' in data: | 
					
						
							|  |  |  |                 force = True | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 force = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if not unlisted: | 
					
						
							|  |  |  |                 containerOBJ = Containers.objects.get(name=name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if not force: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     container = client.containers.get(name) | 
					
						
							|  |  |  |                 except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                     if called: | 
					
						
							|  |  |  |                         return 'Container does not exist' | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         data_ret = {'delContainerStatus': 2, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                         json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                         return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     container.stop()  # Stop container | 
					
						
							|  |  |  |                     container.kill()  # INCASE graceful stop doesn't work | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     container.remove()  # Finally remove container | 
					
						
							|  |  |  |                 except docker.errors.APIError as err: | 
					
						
							|  |  |  |                     data_ret = {'delContainerStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                     json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                     return HttpResponse(json_data) | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     if called: | 
					
						
							|  |  |  |                         return "Unknown" | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         data_ret = {'delContainerStatus': 0, 'error_message': 'Unknown error'} | 
					
						
							|  |  |  |                         json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                         return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if not unlisted and not called: | 
					
						
							|  |  |  |                 containerOBJ.delete() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if called: | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 data_ret = {'delContainerStatus': 1, 'error_message': "None"} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             if called: | 
					
						
							|  |  |  |                 return str(msg) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 data_ret = {'delContainerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerList(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('listContainerStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             currentACL = ACLManager.loadedACL(userID) | 
					
						
							|  |  |  |             pageNumber = int(data['page']) | 
					
						
							|  |  |  |             json_data = self.findContainersJson(currentACL, userID, pageNumber) | 
					
						
							|  |  |  |             final_dic = {'listContainerStatus': 1, 'error_message': "None", "data": json_data} | 
					
						
							|  |  |  |             final_json = json.dumps(final_dic) | 
					
						
							|  |  |  |             return HttpResponse(final_json) | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             dic = {'listContainerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(dic) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def findContainersJson(self, currentACL, userID, pageNumber): | 
					
						
							|  |  |  |         admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |         if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |             return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         finalPageNumber = ((pageNumber * 10)) - 10 | 
					
						
							|  |  |  |         endPageNumber = finalPageNumber + 10 | 
					
						
							|  |  |  |         containers = ACLManager.findContainersObjects(currentACL, userID)[finalPageNumber:endPageNumber] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         json_data = "[" | 
					
						
							|  |  |  |         checker = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for items in containers: | 
					
						
							|  |  |  |             dic = {'name': items.name, 'admin': items.admin.userName, 'tag': items.tag, 'image': items.image} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if checker == 0: | 
					
						
							|  |  |  |                 json_data = json_data + json.dumps(dic) | 
					
						
							|  |  |  |                 checker = 1 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 json_data = json_data + ',' + json.dumps(dic) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         json_data = json_data + ']' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return json_data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def doContainerAction(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('containerActionStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             action = data['action'] | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'containerActionStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'containerActionStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 if action == 'start': | 
					
						
							|  |  |  |                     container.start() | 
					
						
							|  |  |  |                 elif action == 'stop': | 
					
						
							|  |  |  |                     container.stop() | 
					
						
							|  |  |  |                 elif action == 'restart': | 
					
						
							|  |  |  |                     container.restart() | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     data_ret = {'containerActionStatus': 0, 'error_message': 'Unknown Action'} | 
					
						
							|  |  |  |                     json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                     return HttpResponse(json_data) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'containerActionStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             time.sleep(3)  # Wait 3 seconds for container to finish starting/stopping/restarting | 
					
						
							|  |  |  |             status = container.status | 
					
						
							|  |  |  |             data_ret = {'containerActionStatus': 1, 'error_message': 'None', 'status': status} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'containerActionStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerStatus(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('containerStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'containerStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'containerStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             status = container.status | 
					
						
							|  |  |  |             data_ret = {'containerStatus': 1, 'error_message': 'None', 'status': status} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'containerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def exportContainer(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = request.GET.get('name') | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('containerStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'containerStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'containerStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             eFile = container.export()  # Export with default chunk size | 
					
						
							|  |  |  |             response = HttpResponse(eFile, content_type='application/force-download') | 
					
						
							|  |  |  |             response['Content-Disposition'] = 'attachment; filename="' + name + '.tar"' | 
					
						
							|  |  |  |             return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'containerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerTop(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('containerTopStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'containerTopStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'containerTopStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 top = container.top() | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'containerTopStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'containerTopStatus': 1, 'error_message': 'None', 'processes': top} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'containerTopStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assignContainer(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Todo: add check only for super user i.e. main admin | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('assignContainerStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             dockerOwner = data['admin'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             admin = Administrator.objects.get(userName=dockerOwner) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'assignContainerStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'assignContainerStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con = Containers(admin=admin, | 
					
						
							|  |  |  |                              name=name, | 
					
						
							|  |  |  |                              cid=container.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'assignContainerStatus': 1, 'error_message': 'None'} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'assignContainerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def searchImage(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('searchImageStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             string = data['string'] | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 matches = client.images.search(term=string) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'searchImageStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'searchImageStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             print(json.dumps(matches)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for image in matches: | 
					
						
							|  |  |  |                 if "/" in image['name']: | 
					
						
							|  |  |  |                     image['name2'] = image['name'].split("/")[0] + ":" + image['name'].split("/")[1] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     image['name2'] = image['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'searchImageStatus': 1, 'error_message': 'None', 'matches': matches} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'searchImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def images(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 imageList = client.images.list() | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 return HttpResponse(str(err)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             images = {} | 
					
						
							|  |  |  |             names = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for image in imageList: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     name = image.attrs['RepoTags'][0].split(":")[0] | 
					
						
							|  |  |  |                     if "/" in name: | 
					
						
							|  |  |  |                         name2 = "" | 
					
						
							|  |  |  |                         for item in name.split("/"): | 
					
						
							|  |  |  |                             name2 += ":" + item | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         name2 = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     tags = [] | 
					
						
							|  |  |  |                     for tag in image.tags: | 
					
						
							|  |  |  |                         getTag = tag.split(":") | 
					
						
							|  |  |  |                         if len(getTag) == 2: | 
					
						
							|  |  |  |                             tags.append(getTag[1]) | 
					
						
							|  |  |  |                     print(tags) | 
					
						
							|  |  |  |                     if name in names: | 
					
						
							|  |  |  |                         images[name]['tags'].extend(tags) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         names.append(name) | 
					
						
							|  |  |  |                         images[name] = {"name": name, | 
					
						
							|  |  |  |                                         "name2": name2, | 
					
						
							|  |  |  |                                         "tags": tags} | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             template = 'dockerManager/images.html' | 
					
						
							|  |  |  |             proc = httpProc(request, template, {"images": images, "test": ''}, 'admin') | 
					
						
							|  |  |  |             return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             return HttpResponse(str(msg)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def manageImages(self, request=None, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             imageList = client.images.list() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             images = {} | 
					
						
							|  |  |  |             names = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for image in imageList: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     name = image.attrs['RepoTags'][0].split(":")[0] | 
					
						
							|  |  |  |                     if name in names: | 
					
						
							|  |  |  |                         images[name]['tags'].extend(image.tags) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         names.append(name) | 
					
						
							|  |  |  |                         images[name] = {"name": name, | 
					
						
							|  |  |  |                                         "tags": image.tags} | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             template = 'dockerManager/manageImages.html' | 
					
						
							|  |  |  |             proc = httpProc(request, template, {"images": images}, 'admin') | 
					
						
							|  |  |  |             return proc.render() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             return HttpResponse(str(msg)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getImageHistory(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 image = client.images.get(name) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'imageHistoryStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'imageHistoryStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'imageHistoryStatus': 1, 'error_message': 'None', 'history': image.history()} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'imageHistoryStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def removeImage(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 if name == 0: | 
					
						
							|  |  |  |                     action = client.images.prune() | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     action = client.images.remove(name) | 
					
						
							|  |  |  |                 print(action) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'removeImageStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'removeImageStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 1, 'error_message': 'None'} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Internal function for recreating containers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def doRecreateContainer(self, userID, data, con): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             unlisted = data['unlisted']  # Pass this as 1 if image is not known for container | 
					
						
							|  |  |  |             image = data['image'] | 
					
						
							|  |  |  |             tag = data['tag'] | 
					
						
							|  |  |  |             env = data['env'] | 
					
						
							|  |  |  |             volumes = data['volumes'] | 
					
						
							|  |  |  |             port = data['ports'] | 
					
						
							|  |  |  |             memory = data['memory'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if image == 'unknown': | 
					
						
							|  |  |  |                 return "Image name not known" | 
					
						
							|  |  |  |             # Call container delete function | 
					
						
							|  |  |  |             delStatus = self.submitContainerDeletion(userID, data, True) | 
					
						
							|  |  |  |             if delStatus != 0: | 
					
						
							|  |  |  |                 return delStatus | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             containerArgs = {'image': image + ":" + tag, | 
					
						
							|  |  |  |                              'detach': True, | 
					
						
							|  |  |  |                              'name': name, | 
					
						
							|  |  |  |                              'ports': port, | 
					
						
							|  |  |  |                              'environment': env, | 
					
						
							|  |  |  |                              'volumes': volumes, | 
					
						
							|  |  |  |                              'publish_all_ports': True, | 
					
						
							|  |  |  |                              'mem_limit': memory * 1048576} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if con.startOnReboot == 1: | 
					
						
							|  |  |  |                 containerArgs['restart_policy'] = {"Name": "always"} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             container = client.containers.create(**containerArgs) | 
					
						
							|  |  |  |             con.cid = container.id | 
					
						
							|  |  |  |             con.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             return str(msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def saveContainerSettings(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('saveSettingsStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             memory = data['memory'] | 
					
						
							|  |  |  |             startOnReboot = data['startOnReboot'] | 
					
						
							|  |  |  |             envList = data['envList'] | 
					
						
							|  |  |  |             volList = data['volList'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if startOnReboot == True: | 
					
						
							|  |  |  |                 startOnReboot = 1 | 
					
						
							|  |  |  |                 rPolicy = {"Name": "always"} | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 startOnReboot = 0 | 
					
						
							|  |  |  |                 rPolicy = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'saveSettingsStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'saveSettingsStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container.update(mem_limit=memory * 1048576, | 
					
						
							|  |  |  |                                  restart_policy=rPolicy) | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							|  |  |  |                 data_ret = {'saveSettingsStatus': 0, 'error_message': str(err)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con = Containers.objects.get(name=name) | 
					
						
							|  |  |  |             con.memory = memory | 
					
						
							|  |  |  |             con.startOnReboot = startOnReboot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if 'envConfirmation' in data and data['envConfirmation']: | 
					
						
							| 
									
										
										
										
											2025-09-12 21:10:06 +02:00
										 |  |  |                 # Formatting envList for usage - handle both simple and advanced modes | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |                 envDict = {} | 
					
						
							| 
									
										
										
										
											2025-09-12 21:10:06 +02:00
										 |  |  |                  | 
					
						
							|  |  |  |                 # Check if advanced mode is being used | 
					
						
							|  |  |  |                 advanced_mode = data.get('advancedEnvMode', False) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 if advanced_mode: | 
					
						
							|  |  |  |                     # Advanced mode: envList is already a dictionary of key-value pairs | 
					
						
							|  |  |  |                     envDict = envList | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     # Simple mode: envList is an array of objects with name/value properties | 
					
						
							|  |  |  |                     for key, value in envList.items(): | 
					
						
							|  |  |  |                         if isinstance(value, dict) and (value.get('name', '') != '' or value.get('value', '') != ''): | 
					
						
							|  |  |  |                             envDict[value['name']] = value['value'] | 
					
						
							|  |  |  |                         elif isinstance(value, str) and value != '': | 
					
						
							|  |  |  |                             # Handle case where value might be a string (fallback) | 
					
						
							|  |  |  |                             envDict[key] = value | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 volumes = {} | 
					
						
							|  |  |  |                 for index, volume in volList.items(): | 
					
						
							|  |  |  |                     if volume['src'] == '' or volume['dest'] == '': | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     volumes[volume['src']] = {'bind': volume['dest'], | 
					
						
							|  |  |  |                                               'mode': 'rw'} | 
					
						
							|  |  |  |                 # Prepare data for recreate function | 
					
						
							|  |  |  |                 data = { | 
					
						
							|  |  |  |                     'name': name, | 
					
						
							|  |  |  |                     'unlisted': 0, | 
					
						
							|  |  |  |                     'image': con.image, | 
					
						
							|  |  |  |                     'tag': con.tag, | 
					
						
							|  |  |  |                     'env': envDict, | 
					
						
							|  |  |  |                     'ports': json.loads(con.ports), | 
					
						
							|  |  |  |                     'volumes': volumes, | 
					
						
							|  |  |  |                     'memory': con.memory | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 recreateStatus = self.doRecreateContainer(userID, data, con) | 
					
						
							|  |  |  |                 if recreateStatus != 0: | 
					
						
							|  |  |  |                     data_ret = {'saveSettingsStatus': 0, 'error_message': str(recreateStatus)} | 
					
						
							|  |  |  |                     json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                     return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 con.env = json.dumps(envDict) | 
					
						
							|  |  |  |                 con.volumes = json.dumps(volumes) | 
					
						
							|  |  |  |             con.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'saveSettingsStatus': 1, 'error_message': 'None'} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'saveSettingsStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def recreateContainer(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadErrorJson('saveSettingsStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             dockerAPI = docker.APIClient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							|  |  |  |             except docker.errors.NotFound as err: | 
					
						
							|  |  |  |                 data_ret = {'recreateContainerStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 data_ret = {'recreateContainerStatus': 0, 'error_message': 'Unknown'} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             con = Containers.objects.get(name=name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Prepare data for recreate function | 
					
						
							|  |  |  |             data = { | 
					
						
							|  |  |  |                 'name': name, | 
					
						
							|  |  |  |                 'unlisted': 0, | 
					
						
							|  |  |  |                 'image': con.image, | 
					
						
							|  |  |  |                 'tag': con.tag, | 
					
						
							|  |  |  |                 'env': json.loads(con.env), | 
					
						
							|  |  |  |                 'ports': json.loads(con.ports), | 
					
						
							|  |  |  |                 'volumes': json.loads(con.volumes), | 
					
						
							|  |  |  |                 # No filter needed now as its ports are filtered when adding to database | 
					
						
							|  |  |  |                 'memory': con.memory | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             recreateStatus = self.doRecreateContainer(userID, data, con) | 
					
						
							|  |  |  |             if recreateStatus != 0: | 
					
						
							|  |  |  |                 data_ret = {'recreateContainerStatus': 0, 'error_message': str(recreateStatus)} | 
					
						
							|  |  |  |                 json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |                 return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'recreateContainerStatus': 1, 'error_message': 'None'} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'recreateContainerStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getTags(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             image = data['image'] | 
					
						
							|  |  |  |             page = data['page'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if ":" in image: | 
					
						
							|  |  |  |                 image2 = image.split(":")[0] + "/" + image.split(":")[1] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 image2 = "library/" + image | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             print(image) | 
					
						
							|  |  |  |             registryData = requests.get('https://registry.hub.docker.com/v2/repositories/' + image2 + '/tags', | 
					
						
							|  |  |  |                                         {'page': page}).json() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             tagList = [] | 
					
						
							|  |  |  |             for tag in registryData['results']: | 
					
						
							|  |  |  |                 tagList.append(tag['name']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'getTagsStatus': 1, 'list': tagList, 'next': registryData['next'], 'error_message': None} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'getTagsStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getDockersiteList(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             passdata = {} | 
					
						
							|  |  |  |             passdata["JobID"] = None | 
					
						
							|  |  |  |             passdata['name'] = name | 
					
						
							|  |  |  |             da = Docker_Sites(None, passdata) | 
					
						
							|  |  |  |             retdata = da.ListContainers() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None', 'data':retdata} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Internal function for recreating containers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerAppinfo(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             containerID = data['id'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Create a Docker client | 
					
						
							|  |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |             container = client.containers.get(containerID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Get detailed container info | 
					
						
							|  |  |  |             container_info = container.attrs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Calculate uptime | 
					
						
							|  |  |  |             started_at = container_info.get('State', {}).get('StartedAt', '') | 
					
						
							|  |  |  |             if started_at: | 
					
						
							|  |  |  |                 started_time = datetime.strptime(started_at.split('.')[0], '%Y-%m-%dT%H:%M:%S') | 
					
						
							|  |  |  |                 uptime = datetime.now() - started_time | 
					
						
							|  |  |  |                 uptime_str = str(uptime).split('.')[0]  # Format as HH:MM:SS | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 uptime_str = "N/A" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Get container details | 
					
						
							|  |  |  |             details = { | 
					
						
							|  |  |  |                 'id': container.short_id, | 
					
						
							|  |  |  |                 'name': container.name, | 
					
						
							|  |  |  |                 'status': container.status, | 
					
						
							|  |  |  |                 'created': container_info.get('Created', ''), | 
					
						
							|  |  |  |                 'started_at': started_at, | 
					
						
							|  |  |  |                 'uptime': uptime_str, | 
					
						
							|  |  |  |                 'image': container_info.get('Config', {}).get('Image', ''), | 
					
						
							|  |  |  |                 'ports': container_info.get('NetworkSettings', {}).get('Ports', {}), | 
					
						
							|  |  |  |                 'volumes': container_info.get('Mounts', []), | 
					
						
							|  |  |  |                 'environment': self._mask_sensitive_env(container_info.get('Config', {}).get('Env', [])), | 
					
						
							|  |  |  |                 'memory_usage': container.stats(stream=False)['memory_stats'].get('usage', 0), | 
					
						
							|  |  |  |                 'cpu_usage': container.stats(stream=False)['cpu_stats']['cpu_usage'].get('total_usage', 0) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None', 'data': [1, details]} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'status': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _mask_sensitive_env(self, env_vars): | 
					
						
							|  |  |  |         """Helper method to mask sensitive data in environment variables""" | 
					
						
							|  |  |  |         masked_vars = [] | 
					
						
							|  |  |  |         sensitive_keywords = ['password', 'secret', 'key', 'token', 'auth'] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for var in env_vars: | 
					
						
							|  |  |  |             if '=' in var: | 
					
						
							|  |  |  |                 name, value = var.split('=', 1) | 
					
						
							|  |  |  |                 # Check if this is a sensitive variable | 
					
						
							|  |  |  |                 if any(keyword in name.lower() for keyword in sensitive_keywords): | 
					
						
							|  |  |  |                     masked_vars.append(f"{name}=********") | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     masked_vars.append(var) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 masked_vars.append(var) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return masked_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getContainerApplog(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             containerID = data['id'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             passdata = {} | 
					
						
							|  |  |  |             passdata["JobID"] = None | 
					
						
							|  |  |  |             passdata['name'] = name | 
					
						
							|  |  |  |             passdata['containerID'] = containerID | 
					
						
							|  |  |  |             passdata['numberOfLines'] = 50 | 
					
						
							|  |  |  |             da = Docker_Sites(None, passdata) | 
					
						
							|  |  |  |             retdata = da.ContainerLogs() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None', 'data':retdata} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def recreateappcontainer(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             from websiteFunctions.models import DockerSites | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             WPusername = data['WPusername'] | 
					
						
							|  |  |  |             WPemail = data['WPemail'] | 
					
						
							|  |  |  |             WPpasswd = data['WPpasswd'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             dockersite = DockerSites.objects.get(SiteName=name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             passdata ={} | 
					
						
							|  |  |  |             data['JobID'] = '' | 
					
						
							|  |  |  |             data['Domain'] = dockersite.admin.domain | 
					
						
							|  |  |  |             data['domain'] = dockersite.admin.domain | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |             data['WPemail'] = WPemail | 
					
						
							| 
									
										
										
										
											2025-08-01 14:56:30 +05:00
										 |  |  |             data['Owner'] = dockersite.admin.admin.userName | 
					
						
							|  |  |  |             data['userID'] = userID | 
					
						
							|  |  |  |             data['MysqlCPU'] = dockersite.CPUsMySQL | 
					
						
							|  |  |  |             data['MYsqlRam'] = dockersite.MemoryMySQL | 
					
						
							|  |  |  |             data['SiteCPU'] = dockersite.CPUsSite | 
					
						
							|  |  |  |             data['SiteRam'] = dockersite.MemorySite | 
					
						
							|  |  |  |             data['sitename'] = dockersite.SiteName | 
					
						
							|  |  |  |             data['WPusername'] = WPusername | 
					
						
							|  |  |  |             data['WPpasswd'] = WPpasswd | 
					
						
							|  |  |  |             data['externalApp'] = dockersite.admin.externalApp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             da = Docker_Sites(None, passdata) | 
					
						
							|  |  |  |             da.RebuildApp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None',} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def RestartContainerAPP(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             containerID = data['id'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             passdata = {} | 
					
						
							|  |  |  |             passdata['containerID'] = containerID | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             da = Docker_Sites(None, passdata) | 
					
						
							|  |  |  |             retdata = da.RestartContainer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None', 'data':retdata} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def StopContainerAPP(self, userID=None, data=None): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if admin.acl.adminStatus != 1: | 
					
						
							|  |  |  |                 return ACLManager.loadError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             name = data['name'] | 
					
						
							|  |  |  |             containerID = data['id'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             passdata = {} | 
					
						
							|  |  |  |             passdata['containerID'] = containerID | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             da = Docker_Sites(None, passdata) | 
					
						
							|  |  |  |             retdata = da.StopContainer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data_ret = {'status': 1, 'error_message': 'None', 'data':retdata} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							|  |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except BaseException as msg: | 
					
						
							|  |  |  |             data_ret = {'removeImageStatus': 0, 'error_message': str(msg)} | 
					
						
							|  |  |  |             json_data = json.dumps(data_ret) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |             return HttpResponse(json_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def executeContainerCommand(self, userID=None, data=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |         Execute a SAFE command inside a running Docker container with comprehensive security checks | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             # Input validation | 
					
						
							|  |  |  |             if not data or 'name' not in data or 'command' not in data: | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': 'Missing required parameters: name and command'} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |             name = data['name'] | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             command = data['command'].strip() | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             # Validate container name | 
					
						
							|  |  |  |             if not self._validate_container_name(name): | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': 'Invalid container name'} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Validate and sanitize command | 
					
						
							|  |  |  |             validation_result = self._validate_command(command) | 
					
						
							|  |  |  |             if not validation_result['valid']: | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': validation_result['reason']} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Check container ownership | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |             if Containers.objects.filter(name=name).exists(): | 
					
						
							|  |  |  |                 if ACLManager.checkContainerOwnership(name, userID) != 1: | 
					
						
							|  |  |  |                     return ACLManager.loadErrorJson('commandStatus', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             # Rate limiting check | 
					
						
							|  |  |  |             if not self._check_rate_limit(userID, name): | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': 'Rate limit exceeded. Please wait before executing more commands'} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             client = docker.from_env() | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 container = client.containers.get(name) | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             except docker.errors.NotFound: | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 data_ret = {'commandStatus': 0, 'error_message': 'Container does not exist'} | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  |             except Exception as err: | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': f'Error accessing container: {str(err)}'} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Check if container is running | 
					
						
							|  |  |  |             if container.status != 'running': | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': 'Container must be running to execute commands'} | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Log the command execution attempt | 
					
						
							|  |  |  |             self._log_command_execution(userID, name, command) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 # Parse command safely | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 import shlex | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     command_parts = shlex.split(command) | 
					
						
							|  |  |  |                 except ValueError as e: | 
					
						
							|  |  |  |                     data_ret = {'commandStatus': 0, 'error_message': f'Invalid command syntax: {str(e)}'} | 
					
						
							|  |  |  |                     return HttpResponse(json.dumps(data_ret)) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                  | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 # Execute command with security restrictions | 
					
						
							|  |  |  |                 # Note: Some commands may need privileged access, but we validate commands first | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 exec_result = container.exec_run( | 
					
						
							|  |  |  |                     command_parts, | 
					
						
							|  |  |  |                     stdout=True, | 
					
						
							|  |  |  |                     stderr=True, | 
					
						
							|  |  |  |                     stdin=False, | 
					
						
							|  |  |  |                     tty=False, | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                     privileged=True,   # Allow privileged mode since commands are whitelisted | 
					
						
							|  |  |  |                     user='',           # Use container's default user (often root, but commands are validated) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                     detach=False, | 
					
						
							|  |  |  |                     demux=False, | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                     workdir=None,      # Use container's default working directory | 
					
						
							|  |  |  |                     environment=None   # Use container's default environment | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 ) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 # Get output and exit code | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 output = exec_result.output.decode('utf-8', errors='replace') if exec_result.output else '' | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 exit_code = exec_result.exit_code | 
					
						
							|  |  |  |                  | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 # Limit output size to prevent memory exhaustion | 
					
						
							|  |  |  |                 if len(output) > 10000:  # 10KB limit | 
					
						
							|  |  |  |                     output = output[:10000] + "\n[Output truncated - exceeded 10KB limit]" | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 # Log successful execution | 
					
						
							|  |  |  |                 self._log_command_result(userID, name, command, exit_code, len(output)) | 
					
						
							|  |  |  |                  | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                 # Format the response | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 data_ret = { | 
					
						
							|  |  |  |                     'commandStatus': 1,  | 
					
						
							|  |  |  |                     'error_message': 'None' if exit_code == 0 else f'Command executed with exit code {exit_code}', | 
					
						
							|  |  |  |                     'output': output, | 
					
						
							|  |  |  |                     'exit_code': exit_code, | 
					
						
							|  |  |  |                     'command': command, | 
					
						
							|  |  |  |                     'timestamp': time.time() | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                  | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 return HttpResponse(json.dumps(data_ret, ensure_ascii=False)) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |                  | 
					
						
							|  |  |  |             except docker.errors.APIError as err: | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 error_msg = f'Docker API error: {str(err)}' | 
					
						
							|  |  |  |                 self._log_command_error(userID, name, command, error_msg) | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': error_msg} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  |             except Exception as err: | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 error_msg = f'Execution error: {str(err)}' | 
					
						
							|  |  |  |                 self._log_command_error(userID, name, command, error_msg) | 
					
						
							|  |  |  |                 data_ret = {'commandStatus': 0, 'error_message': error_msg} | 
					
						
							|  |  |  |                 return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except Exception as msg: | 
					
						
							|  |  |  |             error_msg = f'System error: {str(msg)}' | 
					
						
							|  |  |  |             logging.CyberCPLogFileWriter.writeToFile(f'executeContainerCommand error: {error_msg}') | 
					
						
							|  |  |  |             data_ret = {'commandStatus': 0, 'error_message': error_msg} | 
					
						
							|  |  |  |             return HttpResponse(json.dumps(data_ret)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Security helper methods for executeContainerCommand | 
					
						
							|  |  |  |     def _validate_container_name(self, name): | 
					
						
							|  |  |  |         """Validate container name to prevent injection""" | 
					
						
							|  |  |  |         if not name or len(name) > 100: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         # Allow only alphanumeric, hyphens, underscores, and dots | 
					
						
							|  |  |  |         import re | 
					
						
							|  |  |  |         return re.match(r'^[a-zA-Z0-9._-]+$', name) is not None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _validate_command(self, command): | 
					
						
							|  |  |  |         """Comprehensive command validation with whitelist approach""" | 
					
						
							|  |  |  |         if not command or len(command) > 1000:  # Reasonable command length limit | 
					
						
							|  |  |  |             return {'valid': False, 'reason': 'Command is empty or too long (max 1000 characters)'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Define allowed commands (whitelist approach) | 
					
						
							|  |  |  |         ALLOWED_COMMANDS = { | 
					
						
							|  |  |  |             # System information | 
					
						
							|  |  |  |             'whoami', 'id', 'pwd', 'date', 'uptime', 'hostname', 'uname', 'df', 'free', 'lscpu', | 
					
						
							|  |  |  |             # File operations (safe and necessary) | 
					
						
							|  |  |  |             'ls', 'cat', 'head', 'tail', 'wc', 'find', 'file', 'stat', 'du', 'tree', | 
					
						
							|  |  |  |             'mkdir', 'touch', 'ln', 'readlink', | 
					
						
							|  |  |  |             # Process monitoring | 
					
						
							|  |  |  |             'ps', 'top', 'htop', 'jobs', 'pgrep', 'pkill', 'killall', 'kill', | 
					
						
							|  |  |  |             # Network tools | 
					
						
							|  |  |  |             'ping', 'wget', 'curl', 'nslookup', 'dig', 'netstat', 'ss', 'ifconfig', 'ip', | 
					
						
							|  |  |  |             # Text processing | 
					
						
							|  |  |  |             'grep', 'awk', 'sed', 'sort', 'uniq', 'cut', 'tr', 'wc', 'diff', | 
					
						
							|  |  |  |             # Package management | 
					
						
							|  |  |  |             'dpkg', 'rpm', 'yum', 'apt', 'apt-get', 'apt-cache', 'aptitude', | 
					
						
							|  |  |  |             'pip', 'pip3', 'npm', 'composer', 'gem', | 
					
						
							|  |  |  |             # Environment and system | 
					
						
							|  |  |  |             'env', 'printenv', 'which', 'type', 'locale', 'timedatectl', | 
					
						
							|  |  |  |             # Archives and compression | 
					
						
							|  |  |  |             'tar', 'gzip', 'gunzip', 'zip', 'unzip', | 
					
						
							|  |  |  |             # Editors (safe ones) | 
					
						
							|  |  |  |             'nano', 'vi', 'vim', | 
					
						
							|  |  |  |             # Database clients | 
					
						
							|  |  |  |             'mysql', 'psql', 'sqlite3', 'redis-cli', 'mongo', | 
					
						
							|  |  |  |             # Development tools | 
					
						
							|  |  |  |             'git', 'node', 'python', 'python3', 'php', 'ruby', 'perl', 'java', | 
					
						
							|  |  |  |             # System services (read-only operations) | 
					
						
							|  |  |  |             'systemctl', 'service', 'journalctl', | 
					
						
							|  |  |  |             # Safe utilities | 
					
						
							|  |  |  |             'echo', 'printf', 'test', 'expr', 'basename', 'dirname', 'realpath', | 
					
						
							|  |  |  |             'sleep', 'timeout', 'watch', 'yes', 'seq', | 
					
						
							|  |  |  |             # Log viewing | 
					
						
							|  |  |  |             'dmesg', 'last', 'lastlog', 'w', 'who' | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Dangerous commands/patterns (blacklist - these override the whitelist) | 
					
						
							|  |  |  |         DANGEROUS_PATTERNS = [ | 
					
						
							|  |  |  |             # Command injection patterns | 
					
						
							|  |  |  |             ';', '&&', '||', '`', '$(', | 
					
						
							|  |  |  |             # Path traversal | 
					
						
							|  |  |  |             '../', '~/',  | 
					
						
							|  |  |  |             # Destructive file operations | 
					
						
							|  |  |  |             'rm -rf', 'rm -r', 'dd if=', 'dd of=', '>>', 'mkfs', 'fdisk', | 
					
						
							|  |  |  |             # System modification | 
					
						
							|  |  |  |             'mount', 'umount', 'crontab -e', 'crontab -r', | 
					
						
							|  |  |  |             # Package installation/removal (allow read-only package commands) | 
					
						
							|  |  |  |             'apt install', 'apt remove', 'apt purge', 'apt-get install',  | 
					
						
							|  |  |  |             'apt-get remove', 'apt-get purge', 'yum install', 'yum remove', | 
					
						
							|  |  |  |             'pip install', 'pip uninstall', 'npm install -g', 'gem install', | 
					
						
							|  |  |  |             # Dangerous network utilities | 
					
						
							|  |  |  |             'nc ', 'netcat', 'ncat', 'telnet', 'ssh ', 'scp ', 'rsync', | 
					
						
							|  |  |  |             # Shell escapes and dangerous execution | 
					
						
							|  |  |  |             'bash', 'sh ', '/bin/sh', '/bin/bash', 'sudo', 'su ', 'exec', | 
					
						
							|  |  |  |             'chroot', 'docker ', 'systemctl start', 'systemctl stop',  | 
					
						
							|  |  |  |             'systemctl enable', 'systemctl disable', 'service start', | 
					
						
							|  |  |  |             'service stop', 'service restart' | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         command_lower = command.lower() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Check for dangerous patterns | 
					
						
							|  |  |  |         for pattern in DANGEROUS_PATTERNS: | 
					
						
							|  |  |  |             if pattern in command_lower: | 
					
						
							|  |  |  |                 return {'valid': False, 'reason': f'Command contains dangerous pattern: {pattern}'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Extract base command | 
					
						
							|  |  |  |         first_word = command.strip().split()[0] if command.strip() else '' | 
					
						
							|  |  |  |         base_command = first_word.split('/')[-1]  # Remove path if present | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Check if base command is in whitelist | 
					
						
							|  |  |  |         if base_command not in ALLOWED_COMMANDS: | 
					
						
							|  |  |  |             return {'valid': False, 'reason': f'Command "{base_command}" is not in the allowed list'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Additional checks for specific commands | 
					
						
							|  |  |  |         if base_command in ['find']: | 
					
						
							|  |  |  |             # Ensure no -exec or dangerous flags | 
					
						
							|  |  |  |             if '-exec' in command_lower or '-delete' in command_lower: | 
					
						
							|  |  |  |                 return {'valid': False, 'reason': 'Dangerous flags (-exec, -delete) not allowed with find'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if base_command in ['systemctl', 'service']: | 
					
						
							|  |  |  |             # Only allow read-only operations | 
					
						
							|  |  |  |             readonly_ops = ['status', 'show', 'list-units', 'list-unit-files', 'is-active', 'is-enabled'] | 
					
						
							|  |  |  |             if not any(op in command_lower for op in readonly_ops): | 
					
						
							|  |  |  |                 return {'valid': False, 'reason': 'Only read-only operations allowed for systemctl/service'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if base_command in ['kill', 'pkill', 'killall']: | 
					
						
							|  |  |  |             # Ensure no dangerous signals | 
					
						
							|  |  |  |             if '-9' in command or 'SIGKILL' in command.upper(): | 
					
						
							|  |  |  |                 return {'valid': False, 'reason': 'SIGKILL (-9) not allowed for safety'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if base_command in ['wget', 'curl']: | 
					
						
							|  |  |  |             # Ensure no output redirection to critical system locations | 
					
						
							|  |  |  |             critical_paths = ['/etc/', '/boot/', '/usr/bin/', '/bin/', '/sbin/', '/usr/sbin/'] | 
					
						
							|  |  |  |             if any(path in command_lower for path in critical_paths): | 
					
						
							|  |  |  |                 return {'valid': False, 'reason': 'Cannot download to critical system directories'} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return {'valid': True, 'reason': 'Command passed validation'} | 
					
						
							| 
									
										
										
										
											2025-09-05 01:14:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |     def _check_rate_limit(self, userID, containerName): | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         """Enhanced rate limiting: max 10 commands per minute per user-container pair""" | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |         import time | 
					
						
							|  |  |  |         import os | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |         import json | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |          | 
					
						
							|  |  |  |         # Create rate limit tracking directory | 
					
						
							|  |  |  |         rate_limit_dir = '/tmp/cyberpanel_docker_rate_limit' | 
					
						
							|  |  |  |         if not os.path.exists(rate_limit_dir): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.makedirs(rate_limit_dir, mode=0o755) | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |             except Exception as e: | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 # If we can't create rate limit tracking, allow the command but log it | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |                 logging.CyberCPLogFileWriter.writeToFile(f'Warning: Could not create rate limit directory: {str(e)}') | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 return True | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Rate limit file per user-container | 
					
						
							|  |  |  |         rate_file = os.path.join(rate_limit_dir, f'user_{userID}_container_{containerName}') | 
					
						
							|  |  |  |         current_time = time.time() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Read existing timestamps | 
					
						
							|  |  |  |             timestamps = [] | 
					
						
							|  |  |  |             if os.path.exists(rate_file): | 
					
						
							|  |  |  |                 with open(rate_file, 'r') as f: | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |                     try: | 
					
						
							|  |  |  |                         data = json.load(f) | 
					
						
							|  |  |  |                         timestamps = data.get('timestamps', []) | 
					
						
							|  |  |  |                     except (json.JSONDecodeError, KeyError): | 
					
						
							|  |  |  |                         # Fallback to old format | 
					
						
							|  |  |  |                         f.seek(0) | 
					
						
							|  |  |  |                         timestamps = [float(line.strip()) for line in f if line.strip()] | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |              | 
					
						
							|  |  |  |             # Remove timestamps older than 1 minute | 
					
						
							|  |  |  |             recent_timestamps = [ts for ts in timestamps if current_time - ts < 60] | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Check if limit exceeded | 
					
						
							|  |  |  |             if len(recent_timestamps) >= 10: | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |                 logging.CyberCPLogFileWriter.writeToFile(f'Rate limit exceeded for user {userID}, container {containerName}') | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |                 return False | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Add current timestamp | 
					
						
							|  |  |  |             recent_timestamps.append(current_time) | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |             # Write back to file with JSON format | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |             with open(rate_file, 'w') as f: | 
					
						
							| 
									
										
										
										
											2025-09-12 22:35:02 +02:00
										 |  |  |                 json.dump({ | 
					
						
							|  |  |  |                     'timestamps': recent_timestamps, | 
					
						
							|  |  |  |                     'last_updated': current_time, | 
					
						
							|  |  |  |                     'user_id': userID, | 
					
						
							|  |  |  |                     'container_name': containerName | 
					
						
							|  |  |  |                 }, f) | 
					
						
							| 
									
										
										
										
											2025-09-10 14:23:40 +05:00
										 |  |  |              | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             # If rate limiting fails, log but allow the command | 
					
						
							|  |  |  |             logging.CyberCPLogFileWriter.writeToFile(f'Rate limiting error: {str(e)}') | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _log_command_execution(self, userID, containerName, command): | 
					
						
							|  |  |  |         """Log command execution attempts for security monitoring""" | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             from loginSystem.models import Administrator | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             username = admin.userName | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             username = f'UserID_{userID}' | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         log_message = f'DOCKER_COMMAND_EXEC: User={username} Container={containerName} Command="{command}" Time={time.time()}' | 
					
						
							|  |  |  |         logging.CyberCPLogFileWriter.writeToFile(log_message) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _log_command_result(self, userID, containerName, command, exitCode, outputLength): | 
					
						
							|  |  |  |         """Log command execution results""" | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             from loginSystem.models import Administrator | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             username = admin.userName | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             username = f'UserID_{userID}' | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         log_message = f'DOCKER_COMMAND_RESULT: User={username} Container={containerName} ExitCode={exitCode} OutputLength={outputLength} Time={time.time()}' | 
					
						
							|  |  |  |         logging.CyberCPLogFileWriter.writeToFile(log_message) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _log_command_error(self, userID, containerName, command, errorMsg): | 
					
						
							|  |  |  |         """Log command execution errors""" | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             from loginSystem.models import Administrator | 
					
						
							|  |  |  |             admin = Administrator.objects.get(pk=userID) | 
					
						
							|  |  |  |             username = admin.userName | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             username = f'UserID_{userID}' | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         log_message = f'DOCKER_COMMAND_ERROR: User={username} Container={containerName} Error="{errorMsg}" Command="{command[:100]}" Time={time.time()}' | 
					
						
							|  |  |  |         logging.CyberCPLogFileWriter.writeToFile(log_message) |