ServerStatus

This commit is contained in:
Zarak Khan
2024-04-25 11:47:31 +05:00
parent a50ec75a2d
commit 7afb36764e
56 changed files with 13579 additions and 312 deletions

View File

@@ -3,6 +3,7 @@
import os.path
import sys
import django
sys.path.append('/usr/local/CyberCP')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
django.setup()
@@ -24,10 +25,11 @@ 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):
def __init__(self, name=None, function=None, request=None, templateName=None, data=None):
multi.Thread.__init__(self)
self.name = name
self.function = function
@@ -47,7 +49,7 @@ class ContainerManager(multi.Thread):
command = 'sudo systemctl restart gunicorn.socket'
ProcessUtilities.executioner(command)
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile( str(msg) + ' [ContainerManager.run]')
logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [ContainerManager.run]')
@staticmethod
def executioner(command, statusFile):
@@ -99,8 +101,8 @@ class ContainerManager(multi.Thread):
val = request.session['userID']
admin = Administrator.objects.get(pk=val)
proc = httpProc(request, 'dockerManager/images.html', {"type": admin.type,
'image': image,
'tag': tag})
'image': image,
'tag': tag})
return proc.render()
envList = {};
@@ -129,6 +131,56 @@ class ContainerManager(multi.Thread):
proc = httpProc(request, template, Data, 'admin')
return proc.render()
def createContainerV2(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 '':
return redirect(loadImages)
Data = {"ownerList": adminNames, "image": image, "name": name, "tag": tag, "portConfig": portConfig,
"envList": envList}
template = 'dockerManager/runContainerV2.html'
proc = httpProc(request, template, Data, 'admin')
return proc.render()
def loadContainerHome(self, request=None, userID=None, data=None):
try:
name = self.name
@@ -192,6 +244,69 @@ class ContainerManager(multi.Thread):
except BaseException as msg:
return HttpResponse(str(msg))
def loadContainerHomeV2(self, request=None, userID=None, data=None):
try:
name = self.name
if ACLManager.checkContainerOwnership(name, userID) != 1:
return ACLManager.loadError()
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 = {}
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)
stats = container.stats(decode=False, stream=False)
logs = container.logs(stream=True)
data['status'] = container.status
data['memoryLimit'] = con.memory
if con.startOnReboot == 1:
data['startOnReboot'] = 'true'
data['restartPolicy'] = "Yes"
else:
data['startOnReboot'] = 'false'
data['restartPolicy'] = "No"
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/viewContainerV2.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()
@@ -235,6 +350,49 @@ class ContainerManager(multi.Thread):
"showUnlistedContainer": showUnlistedContainer}, 'admin')
return proc.render()
def listContainersV2(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/listContainersV2.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']
@@ -299,7 +457,7 @@ class ContainerManager(multi.Thread):
volumes = {}
for index, volume in volList.items():
volumes[volume['src']] = {'bind': volume['dest'],
'mode': 'rw'}
'mode': 'rw'}
## Create Configurations
admin = Administrator.objects.get(userName=dockerOwner)
@@ -772,6 +930,54 @@ class ContainerManager(multi.Thread):
except BaseException as msg:
return HttpResponse(str(msg))
def imagesV2(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/imagesV2.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:
@@ -802,6 +1008,36 @@ class ContainerManager(multi.Thread):
except BaseException as msg:
return HttpResponse(str(msg))
def manageImagesV2(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/manageImagesV2.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:
@@ -1076,4 +1312,4 @@ class ContainerManager(multi.Thread):
except BaseException as msg:
data_ret = {'getTagsStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
return HttpResponse(json_data)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
{% extends "baseTemplate/newBase.html" %}
{% load i18n %}
{% block titleNew %}{% trans "Home - CyberPanel" %}{% endblock %}
{% block newContent %}
{% load static %}
<div ng-controller="manageImagesV2" class="p-8">
<div>
<div class="flex justify-between items-center">
<div>
<div class="flex items-center">
<p class="text-4xl font-bold">Create new container</p>
</div>
</div>
<div>
<a class="bg-orange-500 px-3 py-2 rounded-lg text-xl font-semibold text-white"
href="{% url "manageImagesV2" %}">{% trans "Manage Images" %}</a>
</div>
</div>
</div>
<div class="border px-8 py-2 mt-3">
<div class="flex justify-between items-center py-4">
<div class="flex items-center">
<p class="text-xl font-bold">Locally Available Images</p>
<img id="imageLoading" src="/static/images/loading.gif" style="display: none;">
</div>
</div>
<div class="relative py-5 overflow-x-auto">
<table id="imageList" class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
Name (Installed)
</th>
<th scope="col" class="px-6 py-3">
Tags
</th>
<th scope="col" class="px-6 py-3">
Action
</th>
</tr>
</thead>
<tbody class="border shadow-lg py-3 px-6 rounded-b-lg">
{% for name, image in images.items %}
<tr>
<td class="px-6 py-4">{{ image.name }}</td>
<td class="px-6 py-4">
<select class="w-80 bg-gray-100 rounded px-2 py-1" id="{{ forloop.counter }}"
ng-model="imageTag['{{ image.name2 }}']">
{% for tag in image.tags %}
<option>{{ tag }}</option>
{% endfor %}
</select>
</td>
<td class="px-6 py-4">
<a class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer"
ng-href="/docker/V2/runContainerV2/?image={{ image.name }}&tag={$ imageTag['{{ image.name2 }}'] $}">{% trans "Create" %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,219 @@
{% extends "baseTemplate/newBase.html" %}
{% load i18n %}
{% block titleNew %}{% trans "Home - CyberPanel" %}{% endblock %}
{% block newContent %}
{% load static %}
<div ng-controller="listContainersV2" class="p-8">
<div>
<div class="flex justify-between items-center">
<div>
<div class="flex items-center">
<p id="domainNamePage" class="text-4xl font-bold">List Containers</p>
</div>
</div>
<div>
<a class="bg-orange-500 px-3 py-2 rounded-lg text-xl font-semibold text-white"
href="{% url "containerImage" %}">{% trans "Create" %}</a>
</div>
</div>
<p class="text-xs text-gray-600 py-2 font-semibold">Manage containers on server</p>
</div>
<div class="border px-8 py-2">
<div class="flex justify-between items-center py-4">
<div class="flex items-center">
<p class="text-xl font-bold">Containers</p>
<img id="imageLoading" src="/static/images/loading.gif" style="display: none;">
</div>
</div>
<div class="relative py-5 overflow-x-auto">
<table id="datatable-example" class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
Name
</th>
<th scope="col" class="px-6 py-3">
Launch
</th>
<th scope="col" class="px-6 py-3">
Owner
</th>
<th scope="col" class="px-6 py-3">
Image
</th>
<th scope="col" class="px-6 py-3">
Tag
</th>
<th scope="col" class="px-6 py-3">
Actions
</th>
</tr>
</thead>
<tbody ng-repeat="web in ContainerList track by $index"
class="border shadow-lg py-3 px-6 rounded-b-lg">
<tr>
<td ng-bind="web.name" class="px-6 py-4"></td>
<td class="px-6 py-4"><a href="/docker/V2/view/{$ web.name $}"><img width="30px" height="30"
class=""
src="{% static 'baseTemplate/assets/image-resources/webPanel.png' %}"></a>
</td>
<td ng-bind="web.admin" class="px-6 py-4"></td>
<td ng-bind="web.image" class="px-6 py-4"></td>
<td ng-bind="web.tag" class="px-6 py-4"></td>
<td class="px-6 py-4">
<button ng-click="delContainer(web.name)">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/>
</svg>
</button>
<button onclick="return false;"
ng-click="showLog(web.name)"
href="#" data-modal-target="showLog" data-modal-toggle="showLog">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"/>
</svg>
</button>
<div id="showLog" tabindex="-1"
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-2xl max-h-full">
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="flex items-center bg-blue-400 px-4 py-4">
<p class="font-bold">{% trans "Container logs" %}</p>
<button type="button" data-modal-toggle="showLog"
class="absolute top-2 end-1 text-black bg-transparent hover:text-black rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center"
data-modal-hide="showLog">
<svg class="w-3 h-3" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<div class="p-4 md:p-5">
<textarea name="logs" class="border w-full" id="" cols="30" rows="10">{$ logs $}</textarea>
</div>
<div class="flex gap-1 justify-end py-2">
<button ng-click="showLog('', true)" type="button"
class="text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">{% trans "Refresh" %}</button>
<button type="button"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
data-modal-toggle="showLog"
data-modal-hide="showLog">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id="listFail" class="flex justify-center bg-red-500 rounded-lg text-white px-2 py-1 font-semibold">
<p>{% trans "Error message:" %} {$ errorMessage $}</p>
</div>
<div>
<nav>
<ul class="flex justify-end">
{% for items in pagination %}
<li class="flex justify-end bg-gray-200 w-8 px-3 py-1"
ng-click="getFurtherContainersFromDB({{ forloop.counter }})" id="webPages"><a
href="">{{ forloop.counter }}</a></li>
{% endfor %}
</ul>
</nav>
</div>
{% if showUnlistedContainer %}
<h3 class="title-hero">
{% trans "Unlisted Containers" %} <i class="fa fa-question-circle"
title="{% trans "Containers listed below were either not created through panel or were not saved to database properly" %}"></i>
</h3>
<div class="relative py-5 overflow-x-auto">
<table id="datatable-example" class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
Name
</th>
<th scope="col" class="px-6 py-3">
Status
</th>
<th scope="col" class="px-6 py-3">
Actions
</th>
</tr>
</thead>
<tbody class="border shadow-lg py-3 px-6 rounded-b-lg">
{% for container in unlistedContainers %}
<tr>
<td class="px-6 py-4">{{ container.name }}</td>
<td class="px-6 py-4">{{ container.status }}</td>
<td class="px-6 py-4">
<button class="btn btn-primary"
ng-click="delContainer('{{ container.name }}', true)"><i
class="fa fa-trash"></i></button>
<button class="btn btn-primary" ng-click="showLog('{{ container.name }}')"><i
class="fa fa-file"></i></button>
<button class="btn btn-primary" ng-click="assignContainer('{{ container.name }}')">
<i
class="fa fa-user"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div>
</div>
<button onclick="return false;"
ng-click="showLog(web.name)"
href="#" data-modal-target="showLog" data-modal-toggle="showLog">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"/>
</svg>
</button>
<div id="showLog" tabindex="-1"
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-2xl max-h-full">
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="flex items-center bg-blue-400 px-4 py-4">
<p class="font-bold">{% trans "Container logs" %}</p>
<button type="button" data-modal-toggle="showLog"
class="absolute top-2 end-1 text-black bg-transparent hover:text-black rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center"
data-modal-hide="showLog">
<svg class="w-3 h-3" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<div class="p-4 md:p-5">
<textarea name="logs" class="border w-full" id="" cols="30" rows="10">{$ logs $}</textarea>
</div>
<div class="flex gap-1 justify-end py-2">
<button ng-click="showLog('', true)" type="button"
class="text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">{% trans "Refresh" %}</button>
<button type="button"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
data-modal-toggle="showLog"
data-modal-hide="showLog">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,209 @@
{% extends "baseTemplate/newBase.html" %}
{% load i18n %}
{% block titleNew %}{% trans "Home - CyberPanel" %}{% endblock %}
{% block newContent %}
{% load static %}
<div ng-controller="manageImagesV2" class="p-8">
<div>
<div class="flex justify-between items-center">
<div>
<div class="flex items-center">
<p id="domainNamePage" class="text-4xl font-bold">Manage Images</p>
</div>
</div>
<div>
<a class="bg-orange-500 px-3 py-2 rounded-lg text-xl font-semibold text-white"
href="{% url "containerImageV2" %}">{% trans "Create Container" %}</a>
</div>
</div>
<p class="text-xs text-gray-600 py-2 font-semibold">On this page you can manage docker images.</p>
</div>
<div class="border px-8 py-2">
<div class="flex justify-between items-center py-4">
<div class="flex items-center">
<p class="text-xl font-bold">Images</p>
<img id="imageLoading" src="/static/images/loading.gif" style="display: none;">
</div>
<div>
<button ng-click="rmImage(0)" class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white">
Prune
</button>
</div>
</div>
<div class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Search Image</p>
</div>
<div>
<input type="text" ng-change="searchImages()" ng-model="searchString"
class="w-80 bg-gray-100 rounded px-2 py-1">
</div>
</div>
<div class="relative py-5 overflow-x-auto">
<table id="searchResult" class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
Name (search)
</th>
<th scope="col" class="px-6 py-3">
Tags
</th>
<th scope="col" class="px-6 py-3">
Action
</th>
</tr>
</thead>
<tbody ng-repeat="image in images track by $index"
class="border shadow-lg py-3 px-6 rounded-b-lg">
<tr>
<td class="flex items-center px-6 py-4">
<span ng-bind="image.name"></span>
<span class="ml-1" ng-show="image.is_official == true"><svg
xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor"
class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
</span>
</td>
<td class="px-6 py-4">
<select ng-focus="loadTags($event)" ng-click="selectTag()" ng-model="imageTag[image.name2]"
ng-options="tag for tag in tagList[image.name2]" ng-attr-id="{$ image.name2 $}"
data-pageloaded='0' class="w-80 bg-gray-100 rounded px-2 py-1">
</select>
</td>
<td class="px-6 py-4">
<a ng-click="pullImage(image.name, imageTag[image.name2])"
class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer">{% trans "Pull" %}</a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="relative py-5 overflow-x-auto">
<table id="imageList" class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
Name (Locally Available)
</th>
<th scope="col" class="px-6 py-3">
Tags
</th>
<th scope="col" class="px-6 py-3">
Action
</th>
</tr>
</thead>
<tbody class="border shadow-lg py-3 px-6 rounded-b-lg">
{% for name, image in images.items %}
<tr>
<td class="px-6 py-4">
{{ image.name }}
</td>
<td class="px-6 py-4">
<select class="w-80 bg-gray-100 rounded px-2 py-1" id="{{ forloop.counter }}">
{% for tag in image.tags %}
<option>{{ tag }}</option>
{% endfor %}
</select>
</td>
<td class="px-6 py-4">
<button onclick="return false;"
ng-click="getHistory({{ forloop.counter }})"
class="nav-link point-events"
href="#" data-modal-target="history" data-modal-toggle="history">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
class="w-6 h-6">
<path fill-rule="evenodd"
d="M12 5.25c1.213 0 2.415.046 3.605.135a3.256 3.256 0 0 1 3.01 3.01c.044.583.077 1.17.1 1.759L17.03 8.47a.75.75 0 1 0-1.06 1.06l3 3a.75.75 0 0 0 1.06 0l3-3a.75.75 0 0 0-1.06-1.06l-1.752 1.751c-.023-.65-.06-1.296-.108-1.939a4.756 4.756 0 0 0-4.392-4.392 49.422 49.422 0 0 0-7.436 0A4.756 4.756 0 0 0 3.89 8.282c-.017.224-.033.447-.046.672a.75.75 0 1 0 1.497.092c.013-.217.028-.434.044-.651a3.256 3.256 0 0 1 3.01-3.01c1.19-.09 2.392-.135 3.605-.135Zm-6.97 6.22a.75.75 0 0 0-1.06 0l-3 3a.75.75 0 1 0 1.06 1.06l1.752-1.751c.023.65.06 1.296.108 1.939a4.756 4.756 0 0 0 4.392 4.392 49.413 49.413 0 0 0 7.436 0 4.756 4.756 0 0 0 4.392-4.392c.017-.223.032-.447.046-.672a.75.75 0 0 0-1.497-.092c-.013.217-.028.434-.044.651a3.256 3.256 0 0 1-3.01 3.01 47.953 47.953 0 0 1-7.21 0 3.256 3.256 0 0 1-3.01-3.01 47.759 47.759 0 0 1-.1-1.759L6.97 15.53a.75.75 0 0 0 1.06-1.06l-3-3Z"
clip-rule="evenodd"/>
</svg>
</button>
<div id="history" tabindex="-1"
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-h-full">
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="flex items-center bg-blue-400 px-4 py-4">
<p class="font-bold">{% trans "Image history" %}</p>
<button type="button" data-modal-toggle="history"
class="absolute top-2 end-1 text-black bg-transparent hover:text-black rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center"
data-modal-hide="history">
<svg class="w-3 h-3" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<div class="p-4 md:p-5">
<div class="relative py-5 overflow-x-auto">
<table id="datatable-example"
class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th scope="col" class="px-6 py-3">
ID
</th>
<th scope="col" class="px-6 py-3">
CreatedBy
</th>
<th scope="col" class="px-6 py-3">
Created
</th>
<th scope="col" class="px-6 py-3">
Comment
</th>
<th scope="col" class="px-6 py-3">
Size
</th>
</tr>
</thead>
<tbody ng-repeat="history in historyList track by $index"
class="border shadow-lg py-3 px-6 rounded-b-lg">
<tr>
<td style="word-break: break-all;" ng-bind="history.Id"
class="flex items-center px-6 py-4"></td>
<td style="word-break: break-all;"
ng-bind="history.CreatedBy" class="px-6 py-4"></td>
<td ng-bind="history.Created" class="px-6 py-4"></td>
<td ng-bind="history.Comment" class="px-6 py-4"></td>
<td ng-bind="history.Size" class="px-6 py-4"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="flex gap-1 justify-end py-2">
<button type="button"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
data-modal-toggle="history"
data-modal-hide="history">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
<button ng-click="rmImage({{ forloop.counter }})">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/>
</svg>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,209 @@
{% extends "baseTemplate/newBase.html" %}
{% load i18n %}
{% block titleNew %}{% trans "Home - CyberPanel" %}{% endblock %}
{% block newContent %}
{% load static %}
<div ng-controller="runContainerV2" class="p-8">
<div>
<div class="flex justify-between items-center">
<div>
<div class="flex items-center">
<p class="text-4xl font-bold">Run Container</p>
</div>
</div>
</div>
<p class="text-xs text-gray-600 py-2 font-semibold">Modify parameters for your new container</p>
</div>
<div class="border px-8 py-2 mt-3">
<div class="flex justify-between items-center py-4">
<div class="flex items-center">
<p class="text-xl font-bold">Container Details</p>
<img ng-hide="containerCreationLoading"
src="{% static 'images/loading.gif' %}">
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Name</p>
</div>
<div ng-init="name='{{ name }}' ">
<input name="name" type="text" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="name" required>
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Image</p>
</div>
<div ng-init="image='{{ image }}' ">
<input name="image" type="text" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="image" required
disabled="disabled">
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Tag</p>
</div>
<div ng-init="tag='{{ tag }}' ">
<input name="tag" type="text" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="tag" required
disabled="disabled">
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Select Owner</p>
</div>
<div>
<select ng-model="dockerOwner" class="w-80 bg-gray-100 rounded px-2 py-1">
{% for items in ownerList %}
<option>{{ items }}</option>
{% endfor %}
</select>
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-60">Memory limit</p>
</div>
<div>
<input name="memory" type="number" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="memory"
required>
</div>
<div class="ml-2">
<p>MB</p>
</div>
</div>
{% for port, protocol in portConfig.items %}
<div ng-hide="installationDetailsForm" class="flex py-2 px-6">
<div>
<p class="font-semibold w-60">Port</p>
</div>
<div ng-init="iport[{{ port }}]={{ port }} ">
<input name="iport[{{ port }}]" type="text" class="w-24 bg-gray-100 rounded px-2 py-1"
ng-model="iport[{{ port }}]" required disabled="disabled">
</div>
<div class="ml-2" ng-init="portType['{{ port }}']='{{ protocol }}'">
<input name="portType['{{ port }}']" type="text" class="w-20 bg-gray-100 rounded px-2 py-1"
ng-model="portType['{{ port }}']" required disabled="disabled">
</div>
<div class="flex items-center ml-2">
<p class="font-semibold w-8">to</p>
</div>
<div>
<input name="eport['{{ port }}']" type="number" class="w-24 bg-gray-100 rounded px-2 py-1"
ng-model="eport['{{ port }}']" required>
</div>
</div>
{% endfor %}
<span ng-init="envList = {}"></span>
{% for env, value in envList.items %}
<span ng-init="envList[{{ forloop.counter0 }}] = {'name':'{{ env }}' , 'value':'{{ value }}'} "></span>
{% endfor %}
<div class="border">
<div ng-hide="installationDetailsForm" class="flex justify-center mt-2">
<p class="font-semibold">
ENV
</p>
</div>
<div ng-repeat="env in envList track by $index" ng-hide="installationDetailsForm"
class="flex justify-center py-2 px-6">
<div ng-show="$first">
<p class="font-semibold"></p>
</div>
{# <p class="font-semibold w-60"></p>#}
<div>
<input name="$index" type="text" class="w-80 bg-gray-100 rounded px-2 py-1"
ng-model="envList[$index].name" required>
</div>
<div class="ml-1">
<input name="$index" type="text" class="w-80 bg-gray-100 rounded px-2 py-1"
ng-model="envList[$index].value" required>
</div>
</div>
<div class="flex justify-center mt-2 mb-2" ng-hide="installationDetailsForm">
<button type="button"
class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer"
ng-click="addEnvField()">Add more
</button>
</div>
</div>
<div class="border mt-2">
<div ng-hide="installationDetailsForm" class="flex justify-center mt-2">
<p class="font-semibold">
Map Volumes
</p>
</div>
<div ng-repeat="volume in volList track by $index" ng-hide="installationDetailsForm"
class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-28"></p>
</div>
{# <p class="font-semibold w-60"></p>#}
<div>
<input type="text" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="volList[$index].dest"
placeholder="Destination" required>
</div>
<div class="ml-1">
<input type="text" class="w-80 bg-gray-100 rounded px-2 py-1" ng-model="volList[$index].src"
placeholder="Source" required>
</div>
<div class="ml-1" ng-show="$last">
<div>
<button type="button" ng-click="removeVolField()">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
</button>
</div>
</div>
</div>
<div class="flex justify-center mt-2 mb-2" ng-hide="installationDetailsForm">
<button type="button"
class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer"
ng-click="addVolField()">Add Field
</button>
</div>
</div>
<div ng-hide="installationDetailsForm" class="flex justify-center mt-3">
<button ng-click="createContainer()"
class="bg-orange-500 px-3 py-2 rounded-lg text-xl font-semibold text-white">
Create Container
</button>
</div>
<div ng-hide="installationProgress" class="mt-2">
<div class="flex justify-center font-bold text-xl">
<h2>{$ currentStatus $}</h2>
</div>
<div class="w-full bg-gray-100 rounded-full mt-3">
<div id="installProgress"
class="bg-green-600 text-xs font-medium text-white text-center p-2 leading-none rounded-full"
style="width:0%">
</div>
</div>
<div ng-hide="errorMessageBox"
class="flex mt-2 justify-center bg-red-500 rounded-lg text-white px-2 py-1 font-semibold">
<p>{% trans "Error message:" %} {$ errorMessage $}</p>
</div>
<div ng-hide="success" class="flex mt-2 justify-center bg-green-500 px-2 rounded-lg py-1 font-semibold">
<p>{% trans "Container succesfully created." %}</p>
</div>
<div ng-hide="couldNotConnect"
class="flex mt-2 justify-center bg-red-500 rounded-lg text-white px-2 py-1 font-semibold">
<p>{% trans "Could not connect to server. Please refresh this page." %}</p>
</div>
</div>
<div ng-hide="installationProgress" class="flex justify-center mt-3">
<button ng-disabled="goBackDisable"
ng-click="goBack()"
class="bg-blue-500 px-3 py-2 rounded-lg text-xl font-semibold text-white">
Go Back
</button>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,438 @@
{% extends "baseTemplate/newBase.html" %}
{% load i18n %}
{% block titleNew %}{% trans "Home - CyberPanel" %}{% endblock %}
{% block newContent %}
{% load static %}
<div ng-controller="viewContainerV2" class="p-8">
<div>
<div class="flex justify-between items-center">
<div>
<div ng-init="cName='{{ name }}'" class="flex items-center">
<p class="text-4xl font-bold">Manage Container</p>
</div>
</div>
</div>
<p class="text-xs text-gray-600 py-2 font-semibold">Currently managing: {{ name }}</p>
</div>
<div class="border px-8 py-2 mt-3">
<div class="flex items-center">
<p class="text-xl font-bold">Container Information</p>
<img id="infoLoading" src="/static/images/loading.gif" style="display: none;">
</div>
<div class="flex flex-col md:flex-col lg:flex-row justify-center gap-3">
<div class="border w-full">
<div class="mt-2">
<div class="px-2 py-2">
<p class="font-semibold">Memory Usage</p>
</div>
<div class="px-2">
<div class="w-full bg-gray-200 dark:bg-gray-700">
<div class="bg-blue-600 text-xs font-medium text-black text-center p-1 leading-none"
style="width: {{ memoryUsage }}%"> {{ memoryUsage | floatformat:"2" }}%
</div>
</div>
</div>
<div class="px-2 py-2">
<p class="font-semibold">CPU Usage</p>
</div>
<div class="px-2">
<div class="w-full bg-gray-200 dark:bg-gray-700">
<div class="bg-blue-600 text-xs font-medium text-black text-center p-1 leading-none"
style="width: {{ cpuUsage }}%"> {{ cpuUsage }}%
</div>
</div>
</div>
</div>
</div>
<div class="border w-full">
<div class="p-3">
{% trans "Container ID" %}: {{ cid }}
<br>
{% trans "Image" %}: {{ image }}
<span ng-show="'{{ image }}' == 'unknown:unknown'"
title="Actions involving container recreation cannot be executed">
<i class="fa fa-warning btn-icon"></i>
</span>
<br>
{% if ports %}
{% trans "Ports" %}: <br>
{% for iport, eport in ports.items %}
{{ iport }} {% trans "to" %} {{ eport }}<br>
{% endfor %}
{% endif %}
<div class="flex justify-center">
<button onclick="return false;"
ng-click="showLog(web.name)"
href="#" data-modal-target="showLog" data-modal-toggle="showLog">
<div class="flex items-center gap-1 text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 0 1 1.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.559.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.894.149c-.424.07-.764.383-.929.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 0 1-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.398.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 0 1-.12-1.45l.527-.737c.25-.35.272-.806.108-1.204-.165-.397-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.108-1.204l-.526-.738a1.125 1.125 0 0 1 .12-1.45l.773-.773a1.125 1.125 0 0 1 1.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894Z"/>
<path stroke-linecap="round" stroke-linejoin="round"
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
</svg>
<p>Settings</p>
</div>
</button>
<div id="showLog" tabindex="-1"
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-2xl max-h-full">
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="flex items-center bg-blue-400 px-4 py-4">
<p class="font-bold">{% trans "Container Settings" %}</p>
<img id="containerSettingLoading" src="/static/images/loading.gif"
style="display: none;">
<button type="button" data-modal-toggle="showLog"
class="absolute top-2 end-1 text-black bg-transparent hover:text-black rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center"
data-modal-hide="showLog">
<svg class="w-3 h-3" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<div class="p-4 md:p-5">
<form name="containerSettingsForm" action="/">
<div ng-hide="installationDetailsForm"
class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-32">Memory limit</p>
</div>
<div ng-init="memory={{ memoryLimit }}">
<input name="memory" type="number"
class="w-80 bg-gray-100 rounded px-2 py-1"
ng-model="memory"
required>
</div>
<div class="ml-2">
<p>MB</p>
</div>
</div>
<div ng-hide="installationDetailsForm"
class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-32">Start on reboot</p>
</div>
<div ng-init="startOnReboot={{ startOnReboot }}">
<input ng-model="startOnReboot" type="checkbox" value="">
</div>
</div>
<div ng-hide="installationDetailsForm"
class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-32">Confirmation</p>
</div>
<div>
<input ng-model="envConfirmation" type="checkbox">
</div>
<div class="ml-2">
<p>Editing ENV or Volume will recreate container.</p>
</div>
</div>
<span ng-init="envList = {}"></span>
{% for env, value in envList.items %}
<span ng-init="envList[{{ forloop.counter0 }}] = {'name':'{{ env }}' , 'value':'{{ value }}'} "></span>
{% endfor %}
<div>
<div ng-hide="installationDetailsForm"
class="flex justify-center mt-2">
<p class="font-semibold">
ENV
</p>
</div>
<div ng-repeat="env in envList track by $index"
ng-hide="installationDetailsForm"
class="flex justify-center py-2 px-6">
<div ng-show="$first">
<p class="font-semibold"></p>
</div>
{# <p class="font-semibold w-60"></p>#}
<div>
<input name="$index" ng-disabled="!envConfirmation"
type="text"
class="w-40 bg-gray-100 rounded px-2 py-1"
ng-model="envList[$index].name"
required>
</div>
<div class="ml-1">
<input name="$index" ng-disabled="!envConfirmation"
type="text"
class="w-40 bg-gray-100 rounded px-2 py-1"
ng-model="envList[$index].value"
required>
</div>
</div>
<div class="flex justify-center mt-2 mb-2">
<button type="button" ng-disabled="!envConfirmation"
class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer"
ng-click="addEnvField()">Add more
</button>
</div>
</div>
<span ng-init="volList = {}"></span>
<span ng-init="volListNumber=1"></span>
{% for key, value in volList.items %}
<span ng-init="volList[{{ forloop.counter0 }}] = {'dest':'{{ value.bind }}' , 'src':'{{ key }}'}"></span>
<span ng-init="volListNumber={{ forloop.counter0 }} + 1"></span>
{% endfor %}
<div>
<div ng-hide="installationDetailsForm"
class="flex justify-center mt-2">
<p class="font-semibold">
Map Volumes
</p>
</div>
<div ng-repeat="volume in volList track by $index"
ng-hide="installationDetailsForm"
class="flex items-center py-2 px-6">
<div>
<p class="font-semibold w-28"></p>
</div>
{# <p class="font-semibold w-60"></p>#}
<div>
<input type="text" ng-disabled="!envConfirmation"
class="w-80 bg-gray-100 rounded px-2 py-1"
ng-model="volList[$index].dest"
placeholder="Destination" required>
</div>
<div class="ml-1">
<input type="text" ng-disabled="!envConfirmation"
class="w-80 bg-gray-100 rounded px-2 py-1"
ng-model="volList[$index].src" placeholder="Source"
required>
</div>
<div class="ml-1" ng-show="$last">
<div>
<button type="button" ng-disabled="!envConfirmation"
ng-click="removeVolField()">
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
</button>
</div>
</div>
</div>
<div class="flex justify-center mt-2 mb-2"
ng-hide="installationDetailsForm">
<button type="button" ng-disabled="!envConfirmation"
class="bg-orange-500 px-3 py-1 rounded-lg font-semibold text-white cursor-pointer"
ng-click="addVolField()">Add Field
</button>
</div>
</div>
</form>
</div>
<div class="flex gap-1 justify-end py-2">
<button ng-click="saveSettings()" type="button"
ng-disabled="savingSettings"
class="text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">{% trans "Save" %}</button>
<button type="button" ng-disabled="savingSettings"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
data-modal-toggle="showLog"
data-modal-hide="showLog">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
<button class="text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
ng-click="recreate()">
Recreate
</button>
</div>
</div>
</div>
</div>
</div>
<div class="border px-8 py-2 mt-3">
<div class="flex items-center mb-2">
<p class="text-xl font-bold">Actions</p>
</div>
<div class="flex flex-col md:flex-col lg:flex-row justify-center gap-3">
<div class="border w-full p-3">
<div class="flex justify-between">
<div class="flex items-center">
<p ng-init="status='{{ status }}'">Main Actions</p>
<img id="actionLoading" src="/static/images/loading.gif"
style="display: none;width: 20px;">
</div>
<div>
<button ng-click='refreshStatus()'>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/>
</svg>
</button>
</div>
</div>
<div class="flex items-center">
<p class="font-bold">Status:</p>
<span class="ml-1" ng-bind="status"></span>
</div>
<div class="flex justify-center mt-2">
<div ng-disabled="status=='running'" ng-click="cAction('start')"
class="flex cursor-pointer items-center text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"/>
</svg>
<p>Start</p>
</div>
<div ng-disabled="status!='running'" ng-click="cAction('restart')"
class="flex cursor-pointer items-center text-white bg-blue-600 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:focus:ring-blue-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/>
</svg>
<p>Restart</p>
</div>
<div ng-disabled="status!='running'" ng-click="cAction('stop')"
class="flex cursor-pointer items-center text-white bg-orange-600 hover:bg-orange-800 focus:ring-4 focus:outline-none focus:ring-orange-300 dark:focus:ring-orange-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M5.25 7.5A2.25 2.25 0 0 1 7.5 5.25h9a2.25 2.25 0 0 1 2.25 2.25v9a2.25 2.25 0 0 1-2.25 2.25h-9a2.25 2.25 0 0 1-2.25-2.25v-9Z"/>
</svg>
<p>Stop</p>
</div>
<div ng-click="cRemove()"
class="flex cursor-pointer items-center text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
</svg>
<p>Remove</p>
</div>
</div>
</div>
<div class="border w-full p-3">
<div class="flex justify-between">
<div class="flex items-center">
<p ng-init="rPolicy='{{ restartPolicy }}'">Other Actions</p>
</div>
</div>
<div class="flex items-center">
<p class="font-bold">Restart on system reboot:</p>
<span class="ml-1" ng-bind="rPolicy"></span>
</div>
<div class="flex justify-center mt-2">
<button>
<a href="/docker/exportContainer/?name={{ name }}"
class="flex cursor-pointer items-center text-white bg-orange-600 hover:bg-orange-800 focus:ring-4 focus:outline-none focus:ring-orange-300 dark:focus:ring-orange-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/>
</svg>
<p>
Export File
</p>
</a>
</button>
<button onclick="return false;"
ng-disabled="loadingTop" ng-click="showTop()"
href="#" data-modal-target="viewprocess" data-modal-toggle="viewprocess">
<div class="flex cursor-pointer items-center text-white bg-orange-600 hover:bg-orange-800 focus:ring-4 focus:outline-none focus:ring-orange-300 dark:focus:ring-orange-800 font-medium rounded-lg text-sm inline-flex items-center px-2.5 py-1 text-center me-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/>
<path stroke-linecap="round" stroke-linejoin="round"
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
</svg>
<p class="ml-1">
View Process
</p>
</div>
</button>
<div id="viewprocess" tabindex="-1"
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-2xl max-h-full">
<div class="relative bg-white shadow dark:bg-gray-700">
<div class="flex items-center bg-blue-400 px-4 py-4">
<p class="font-bold">{% trans "Container Processes" %}</p>
<button type="button" data-modal-toggle="viewprocess"
class="absolute top-2 end-1 text-black bg-transparent hover:text-black rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center"
data-modal-hide="viewprocess">
<svg class="w-3 h-3" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<div class="p-4 md:p-5">
<div class="relative py-5 overflow-x-auto">
<table id="datatable-example"
class="w-full text-sm text-left rtl:text-right">
<thead>
<tr>
<th ng-repeat="item in topHead track by $index" class="px-6 py-3">
{$ item $}
</th>
</tr>
</thead>
<tbody ng-repeat="process in topProcesses track by $index"
class="border shadow-lg py-3 px-6 rounded-b-lg">
<tr>
<td ng-repeat="item in process track by $index" class="px-6 py-4">
{$ item $}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="flex gap-1 justify-end py-2">
<button ng-click="showTop()" type="button"
ng-disabled="savingSettings"
class="text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">{% trans "Refresh" %}</button>
<button type="button" ng-disabled="savingSettings"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"
data-modal-toggle="viewprocess"
data-modal-hide="viewprocess">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="border px-8 py-2 mt-3">
<div ng-init="loadLogs('{{ name }}')" class="flex justify-between items-center">
<p class="text-xl font-bold">Logs</p>
<span style="cursor:pointer;" class="pull-right" ng-click="loadLogs('{{ name }}')"></span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6 cursor-pointer">
<path stroke-linecap="round" stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/>
</svg>
</div>
<div class="mt-2">
<textarea name="logs" class="border w-full" id="" cols="30" rows="10">{$ logs $}</textarea><br>
</div>
</div>
</div>
{% endblock %}

View File

@@ -3,11 +3,13 @@ from . import views
urlpatterns = [
url(r'^$', views.loadDockerHome, name='dockerHome'),
# url(r'^images', views.loadImages, name='loadImages'),
# url(r'^images', views.loadImages, name='loadImages'),
url(r'^getTags', views.getTags, name='getTags'),
url(r'^runContainer', views.runContainer, name='runContainer'),
url(r'^V2/runContainerV2', views.runContainerV2, name='runContainerV2'),
url(r'^submitContainerCreation', views.submitContainerCreation, name='submitContainerCreation'),
url(r'^listContainers', views.listContainers, name='listContainers'),
url(r'^V2/listContainersV2', views.listContainersV2, name='listContainersV2'),
url(r'^getContainerList', views.getContainerList, name='getContainerList'),
url(r'^getContainerLogs', views.getContainerLogs, name='getContainerLogs'),
url(r'^installImage', views.installImage, name='installImage'),
@@ -20,10 +22,13 @@ urlpatterns = [
url(r'^assignContainer', views.assignContainer, name='assignContainer'),
url(r'^searchImage', views.searchImage, name='searchImage'),
url(r'^manageImages', views.manageImages, name='manageImages'),
url(r'^V2/manageImagesV2', views.manageImagesV2, name='manageImagesV2'),
url(r'^getImageHistory', views.getImageHistory, name='getImageHistory'),
url(r'^removeImage', views.removeImage, name='removeImage'),
url(r'^recreateContainer', views.recreateContainer, name='recreateContainer'),
url(r'^installDocker', views.installDocker, name='installDocker'),
url(r'^images', views.images, name='containerImage'),
url(r'^V2/imagesV2', views.imagesV2, name='containerImageV2'),
url(r'^view/(?P<name>(.*))$', views.viewContainer, name='viewContainer'),
]
url(r'^V2/view/(?P<name>(.*))$', views.viewContainerV2, name='viewContainerV2'),
]

View File

@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
from django.shortcuts import redirect, HttpResponse
@@ -10,14 +10,14 @@ from .decorators import preDockerRun
from plogical.acl import ACLManager
import json
# Create your views here.
# This function checks if user has admin permissions
def dockerPermission(request, userID, context):
currentACL = ACLManager.loadedACL(userID)
if currentACL['admin'] != 1:
if request.method == "POST":
return ACLManager.loadErrorJson()
@@ -25,7 +25,8 @@ def dockerPermission(request, userID, context):
return ACLManager.loadError()
else:
return 0
@preDockerRun
def loadDockerHome(request):
userID = request.session['userID']
@@ -34,6 +35,7 @@ def loadDockerHome(request):
proc = httpProc(request, template, {"type": admin.type}, 'admin')
return proc.render()
def installDocker(request):
try:
@@ -57,7 +59,8 @@ def installDocker(request):
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
@preDockerRun
@preDockerRun
def installImage(request):
try:
userID = request.session['userID']
@@ -75,7 +78,8 @@ def installImage(request):
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def viewContainer(request, name):
try:
@@ -97,10 +101,35 @@ def viewContainer(request, name):
return coreResult
except KeyError:
return redirect(loadLoginPage)
return redirect(loadLoginPage)
@preDockerRun
def getTags(request):
def viewContainerV2(request, name):
try:
if not request.GET._mutable:
request.GET._mutable = True
request.GET['name'] = name
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if currentACL['admin'] == 1:
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager(name)
coreResult = cm.loadContainerHomeV2(request, userID)
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def getTags(request):
try:
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
@@ -117,9 +146,10 @@ def getTags(request):
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def delContainer(request):
def delContainer(request):
try:
userID = request.session['userID']
@@ -137,9 +167,10 @@ def delContainer(request):
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def recreateContainer(request):
@preDockerRun
def recreateContainer(request):
try:
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
@@ -155,9 +186,10 @@ def recreateContainer(request):
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
return redirect(loadLoginPage)
@preDockerRun
def runContainer(request):
try:
userID = request.session['userID']
@@ -167,13 +199,31 @@ def runContainer(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
return cm.createContainer(request, userID)
except KeyError:
return redirect(loadLoginPage)
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def runContainerV2(request):
try:
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if currentACL['admin'] == 1:
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
return cm.createContainerV2(request, userID)
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def listContainers(request):
try:
userID = request.session['userID']
@@ -182,7 +232,18 @@ def listContainers(request):
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def listContainersV2(request):
try:
userID = request.session['userID']
cm = ContainerManager()
return cm.listContainersV2(request, userID)
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def getContainerLogs(request):
try:
@@ -199,9 +260,10 @@ def getContainerLogs(request):
return coreResult
except KeyError:
return redirect(loadLoginPage)
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def submitContainerCreation(request):
try:
@@ -221,7 +283,8 @@ def submitContainerCreation(request):
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def getContainerList(request):
try:
userID = request.session['userID']
@@ -231,13 +294,14 @@ def getContainerList(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
return cm.getContainerList(userID, json.loads(request.body))
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def doContainerAction(request):
try:
userID = request.session['userID']
@@ -247,15 +311,16 @@ def doContainerAction(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.doContainerAction(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def getContainerStatus(request):
try:
userID = request.session['userID']
@@ -265,15 +330,16 @@ def getContainerStatus(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.getContainerStatus(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def exportContainer(request):
try:
userID = request.session['userID']
@@ -283,15 +349,16 @@ def exportContainer(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.exportContainer(request, userID)
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
return redirect(loadLoginPage)
@preDockerRun
def saveContainerSettings(request):
try:
userID = request.session['userID']
@@ -301,15 +368,16 @@ def saveContainerSettings(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.saveContainerSettings(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
return redirect(loadLoginPage)
@preDockerRun
def getContainerTop(request):
try:
userID = request.session['userID']
@@ -319,15 +387,16 @@ def getContainerTop(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.getContainerTop(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def assignContainer(request):
try:
userID = request.session['userID']
@@ -337,15 +406,16 @@ def assignContainer(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.assignContainer(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def searchImage(request):
try:
userID = request.session['userID']
@@ -355,27 +425,42 @@ def searchImage(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.searchImage(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def images(request):
try:
userID = request.session['userID']
cm = ContainerManager()
coreResult = cm.images(request, userID)
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def imagesV2(request):
try:
userID = request.session['userID']
cm = ContainerManager()
coreResult = cm.imagesV2(request, userID)
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def manageImages(request):
try:
userID = request.session['userID']
@@ -384,8 +469,20 @@ def manageImages(request):
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def manageImagesV2(request):
try:
userID = request.session['userID']
cm = ContainerManager()
coreResult = cm.manageImagesV2(request, userID)
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
def getImageHistory(request):
try:
userID = request.session['userID']
@@ -395,15 +492,16 @@ def getImageHistory(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.getImageHistory(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
@preDockerRun
@preDockerRun
def removeImage(request):
try:
userID = request.session['userID']
@@ -413,10 +511,10 @@ def removeImage(request):
pass
else:
return ACLManager.loadErrorJson()
cm = ContainerManager()
coreResult = cm.removeImage(userID, json.loads(request.body))
return coreResult
except KeyError:
return redirect(loadLoginPage)
return redirect(loadLoginPage)