mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-09 14:56:10 +01:00
Added Volume mapping to docker app
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
|
*.pyc
|
||||||
bin
|
bin
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
SECRET_KEY = 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f'
|
SECRET_KEY = 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
@@ -110,15 +110,15 @@ DATABASES = {
|
|||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'cyberpanel',
|
'NAME': 'cyberpanel',
|
||||||
'USER': 'cyberpanel',
|
'USER': 'cyberpanel',
|
||||||
'PASSWORD': 'Bz9gF7Hr7X4RtD',
|
'PASSWORD': '7Lu8u2NkBwOyWg',
|
||||||
'HOST': '127.0.0.1',
|
'HOST': 'localhost',
|
||||||
'PORT':'3307'
|
'PORT': '',
|
||||||
},
|
},
|
||||||
'rootdb': {
|
'rootdb': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'mysql',
|
'NAME': 'mysql',
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'sXm5VlRaAsXkDd',
|
'PASSWORD': 'Mb5Y9dU2gVb7pM',
|
||||||
'HOST': 'localhost',
|
'HOST': 'localhost',
|
||||||
'PORT': '',
|
'PORT': '',
|
||||||
},
|
},
|
||||||
|
|||||||
33
dockerManager/migrations/0001_initial.py
Executable file
33
dockerManager/migrations/0001_initial.py
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2019-01-23 18:47
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('loginSystem', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Containers',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50, unique=True)),
|
||||||
|
('cid', models.CharField(default='', max_length=64)),
|
||||||
|
('image', models.CharField(default='unknown', max_length=50)),
|
||||||
|
('tag', models.CharField(default='unknown', max_length=50)),
|
||||||
|
('memory', models.IntegerField(default=0)),
|
||||||
|
('ports', models.TextField(default='{}')),
|
||||||
|
('env', models.TextField(default='{}')),
|
||||||
|
('startOnReboot', models.IntegerField(default=0)),
|
||||||
|
('admin', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='loginSystem.Administrator')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
20
dockerManager/migrations/0002_containers_volumes.py
Normal file
20
dockerManager/migrations/0002_containers_volumes.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2019-01-26 16:22
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dockerManager', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='containers',
|
||||||
|
name='volumes',
|
||||||
|
field=models.TextField(default='{}'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -13,5 +13,6 @@ class Containers(models.Model):
|
|||||||
tag = models.CharField(max_length=50, default='unknown')
|
tag = models.CharField(max_length=50, default='unknown')
|
||||||
memory = models.IntegerField(default=0)
|
memory = models.IntegerField(default=0)
|
||||||
ports = models.TextField(default="{}")
|
ports = models.TextField(default="{}")
|
||||||
|
volumes = models.TextField(default="{}")
|
||||||
env = models.TextField(default="{}")
|
env = models.TextField(default="{}")
|
||||||
startOnReboot = models.IntegerField(default=0)
|
startOnReboot = models.IntegerField(default=0)
|
||||||
|
|||||||
@@ -119,6 +119,18 @@ app.controller('runContainer', function ($scope, $http) {
|
|||||||
$scope.success = true;
|
$scope.success = true;
|
||||||
$scope.couldNotConnect = true;
|
$scope.couldNotConnect = true;
|
||||||
$scope.goBackDisable = true;
|
$scope.goBackDisable = true;
|
||||||
|
|
||||||
|
$scope.volList = {};
|
||||||
|
$scope.volListNumber = 0;
|
||||||
|
$scope.addVolField = function() {
|
||||||
|
$scope.volList[$scope.volListNumber] = {'dest':'', 'src':''};
|
||||||
|
$scope.volListNumber = $scope.volListNumber + 1;
|
||||||
|
console.log($scope.volList)
|
||||||
|
}
|
||||||
|
$scope.removeVolField = function(){
|
||||||
|
delete $scope.volList[$scope.volListNumber - 1];
|
||||||
|
$scope.volListNumber = $scope.volListNumber - 1;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.addEnvField = function () {
|
$scope.addEnvField = function () {
|
||||||
var countEnv = Object.keys($scope.envList).length;
|
var countEnv = Object.keys($scope.envList).length;
|
||||||
@@ -157,8 +169,8 @@ app.controller('runContainer', function ($scope, $http) {
|
|||||||
memory: memory,
|
memory: memory,
|
||||||
dockerOwner: dockerOwner,
|
dockerOwner: dockerOwner,
|
||||||
image: image,
|
image: image,
|
||||||
envList: $scope.envList
|
envList: $scope.envList,
|
||||||
|
volList: $scope.volList
|
||||||
};
|
};
|
||||||
|
|
||||||
$.each($scope.portType, function (port, protocol) {
|
$.each($scope.portType, function (port, protocol) {
|
||||||
@@ -698,6 +710,16 @@ app.controller('viewContainer', function ($scope, $http) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.addVolField = function() {
|
||||||
|
$scope.volList[$scope.volListNumber] = {'dest':'', 'src':''};
|
||||||
|
$scope.volListNumber = $scope.volListNumber + 1;
|
||||||
|
console.log($scope.volList)
|
||||||
|
}
|
||||||
|
$scope.removeVolField = function(){
|
||||||
|
delete $scope.volList[$scope.volListNumber - 1];
|
||||||
|
$scope.volListNumber = $scope.volListNumber - 1;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.saveSettings = function () {
|
$scope.saveSettings = function () {
|
||||||
$('#containerSettingLoading').show();
|
$('#containerSettingLoading').show();
|
||||||
@@ -709,7 +731,8 @@ app.controller('viewContainer', function ($scope, $http) {
|
|||||||
memory: $scope.memory,
|
memory: $scope.memory,
|
||||||
startOnReboot: $scope.startOnReboot,
|
startOnReboot: $scope.startOnReboot,
|
||||||
envConfirmation: $scope.envConfirmation,
|
envConfirmation: $scope.envConfirmation,
|
||||||
envList: $scope.envList
|
envList: $scope.envList,
|
||||||
|
volList: $scope.volList
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(data)
|
console.log(data)
|
||||||
|
|||||||
@@ -106,12 +106,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div ng-hide="installationDetailsForm" class="col-md-offset-3">
|
<div ng-hide="installationDetailsForm" class="col-md-offset-3">
|
||||||
<button type="button" class="btn btn-info" ng-click="addEnvField()">Add more</button>
|
<button type="button" class="btn btn-info" ng-click="addEnvField()">Add more</button>
|
||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
|
<div ng-hide="installationDetailsForm" class="form-group text-center">
|
||||||
|
<label class="control-label">
|
||||||
|
{% trans "Map Volumes" %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div ng-repeat="volume in volList track by $index">
|
||||||
|
|
||||||
|
<div ng-hide="installationDetailsForm" class="form-group">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="text" class="form-control" ng-model="volList[$index].dest" placeholder="Destination" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" class="form-control" ng-model="volList[$index].src" placeholder="Source" required>
|
||||||
|
</div>
|
||||||
|
<div ng-show="$last">
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<button class="btn btn-primary" type="button" ng-click="removeVolField()"><i class="fa fa-times"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-hide="installationDetailsForm" class="text-center">
|
||||||
|
<button type="button" class="btn btn-info" ng-click="addVolField()">{% trans "Add field" %}</button>
|
||||||
|
</div><br>
|
||||||
|
|
||||||
<div ng-hide="installationDetailsForm" class="form-group">
|
<div ng-hide="installationDetailsForm" class="form-group">
|
||||||
<label class="col-sm-3 control-label"></label>
|
<label class="col-sm-3 control-label"></label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
|||||||
@@ -210,12 +210,12 @@
|
|||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input ng-model="envConfirmation" type="checkbox">
|
<input ng-model="envConfirmation" type="checkbox">
|
||||||
Editing ENV will recreate container <i class="fa fa-warning" title="If you tick this checkbox, your container will be recreated with saved information. Data saved inside container will be deleted (Not avaialble for container created outside of cyberpanel)"></i>
|
Editing ENV or Volume will recreate container <i class="fa fa-warning" title="If you tick this checkbox, your container will be recreated with saved information. Data saved inside container will be deleted (Not avaialble for container created outside of cyberpanel)"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
<span ng-init="envList = {}"></span>
|
<span ng-init="envList = {}"></span>
|
||||||
{% for env, value in envList.items %}
|
{% for env, value in envList.items %}
|
||||||
|
|
||||||
@@ -245,6 +245,43 @@
|
|||||||
<button type="button" class="btn btn-info" ng-click="addEnvField()">Add more</button>
|
<button type="button" class="btn btn-info" ng-click="addEnvField()">Add more</button>
|
||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
|
<span ng-init="volList = {}"></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 %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div ng-hide="installationDetailsForm" class="form-group text-center">
|
||||||
|
<label class="control-label">
|
||||||
|
{% trans "Map Volumes" %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div ng-repeat="volume in volList track by $index">
|
||||||
|
<div ng-hide="installationDetailsForm" class="form-group">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="text" class="form-control" ng-model="volList[$index].dest" placeholder="Destination" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" class="form-control" ng-model="volList[$index].src" placeholder="Source" required>
|
||||||
|
</div>
|
||||||
|
<div ng-show="$last">
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<button class="btn btn-primary" type="button" ng-click="removeVolField()"><i class="fa fa-times"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-hide="installationDetailsForm" class="text-center">
|
||||||
|
<button type="button" class="btn btn-info" ng-click="addVolField()">{% trans "Add field" %}</button>
|
||||||
|
</div><br>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ class ContainerManager(multi.Thread):
|
|||||||
data['ports'] = json.loads(con.ports)
|
data['ports'] = json.loads(con.ports)
|
||||||
data['cid'] = con.cid
|
data['cid'] = con.cid
|
||||||
data['envList'] = json.loads(con.env)
|
data['envList'] = json.loads(con.env)
|
||||||
print data['envList']
|
data['volList'] = json.loads(con.volumes)
|
||||||
|
|
||||||
stats = container.stats(decode=False, stream=False)
|
stats = container.stats(decode=False, stream=False)
|
||||||
logs = container.logs(stream=True)
|
logs = container.logs(stream=True)
|
||||||
@@ -300,6 +300,7 @@ class ContainerManager(multi.Thread):
|
|||||||
dockerOwner = data['dockerOwner']
|
dockerOwner = data['dockerOwner']
|
||||||
memory = data['memory']
|
memory = data['memory']
|
||||||
envList = data['envList']
|
envList = data['envList']
|
||||||
|
volList = data['volList']
|
||||||
|
|
||||||
inspectImage = dockerAPI.inspect_image(image + ":" + tag)
|
inspectImage = dockerAPI.inspect_image(image + ":" + tag)
|
||||||
portConfig = {}
|
portConfig = {}
|
||||||
@@ -319,6 +320,12 @@ class ContainerManager(multi.Thread):
|
|||||||
return HttpResponse(json_data)
|
return HttpResponse(json_data)
|
||||||
portConfig[item] = data[item]
|
portConfig[item] = data[item]
|
||||||
|
|
||||||
|
volumes = {}
|
||||||
|
for index, volume in volList.iteritems():
|
||||||
|
volumes[volume['src']] = {'bind': volume['dest'],
|
||||||
|
'mode': 'rw'}
|
||||||
|
print volumes
|
||||||
|
|
||||||
## Create Configurations
|
## Create Configurations
|
||||||
admin = Administrator.objects.get(userName=dockerOwner)
|
admin = Administrator.objects.get(userName=dockerOwner)
|
||||||
|
|
||||||
@@ -327,7 +334,8 @@ class ContainerManager(multi.Thread):
|
|||||||
'name': name,
|
'name': name,
|
||||||
'ports': portConfig,
|
'ports': portConfig,
|
||||||
'publish_all_ports': True,
|
'publish_all_ports': True,
|
||||||
'environment': envDict}
|
'environment': envDict,
|
||||||
|
'volumes': volumes}
|
||||||
|
|
||||||
containerArgs['mem_limit'] = memory * 1048576; # Converts MB to bytes ( 0 * x = 0 for unlimited memory)
|
containerArgs['mem_limit'] = memory * 1048576; # Converts MB to bytes ( 0 * x = 0 for unlimited memory)
|
||||||
|
|
||||||
@@ -347,6 +355,7 @@ class ContainerManager(multi.Thread):
|
|||||||
image=image,
|
image=image,
|
||||||
memory=memory,
|
memory=memory,
|
||||||
ports=json.dumps(portConfig),
|
ports=json.dumps(portConfig),
|
||||||
|
volumes=json.dumps(volumes),
|
||||||
env=json.dumps(envDict),
|
env=json.dumps(envDict),
|
||||||
cid=container.id)
|
cid=container.id)
|
||||||
|
|
||||||
@@ -881,11 +890,16 @@ class ContainerManager(multi.Thread):
|
|||||||
|
|
||||||
def doRecreateContainer(self, userID, data, con):
|
def doRecreateContainer(self, userID, data, con):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
client = docker.from_env()
|
||||||
|
dockerAPI = docker.APIClient()
|
||||||
|
|
||||||
name = data['name']
|
name = data['name']
|
||||||
unlisted = data['unlisted'] # Pass this as 1 if image is not known for container
|
unlisted = data['unlisted'] # Pass this as 1 if image is not known for container
|
||||||
image = data['image']
|
image = data['image']
|
||||||
tag = data['tag']
|
tag = data['tag']
|
||||||
env = data['env']
|
env = data['env']
|
||||||
|
volumes = data['volumes']
|
||||||
port = data['ports']
|
port = data['ports']
|
||||||
memory = data['memory']
|
memory = data['memory']
|
||||||
|
|
||||||
@@ -902,6 +916,7 @@ class ContainerManager(multi.Thread):
|
|||||||
'name': name,
|
'name': name,
|
||||||
'ports': port,
|
'ports': port,
|
||||||
'environment': env,
|
'environment': env,
|
||||||
|
'volumes': volumes,
|
||||||
'publish_all_ports': True,
|
'publish_all_ports': True,
|
||||||
'mem_limit': memory * 1048576}
|
'mem_limit': memory * 1048576}
|
||||||
|
|
||||||
@@ -928,6 +943,7 @@ class ContainerManager(multi.Thread):
|
|||||||
memory = data['memory']
|
memory = data['memory']
|
||||||
startOnReboot = data['startOnReboot']
|
startOnReboot = data['startOnReboot']
|
||||||
envList = data['envList']
|
envList = data['envList']
|
||||||
|
volList = data['volList']
|
||||||
|
|
||||||
if startOnReboot == True:
|
if startOnReboot == True:
|
||||||
startOnReboot = 1
|
startOnReboot = 1
|
||||||
@@ -966,7 +982,10 @@ class ContainerManager(multi.Thread):
|
|||||||
if (value['name'] != '') or (value['value'] != ''):
|
if (value['name'] != '') or (value['value'] != ''):
|
||||||
envDict[value['name']] = value['value']
|
envDict[value['name']] = value['value']
|
||||||
|
|
||||||
print envDict
|
volumes = {}
|
||||||
|
for index, volume in volList.iteritems():
|
||||||
|
volumes[volume['src']] = {'bind': volume['dest'],
|
||||||
|
'mode': 'rw'}
|
||||||
# Prepare data for recreate function
|
# Prepare data for recreate function
|
||||||
data = {
|
data = {
|
||||||
'name': name,
|
'name': name,
|
||||||
@@ -975,7 +994,7 @@ class ContainerManager(multi.Thread):
|
|||||||
'tag': con.tag,
|
'tag': con.tag,
|
||||||
'env': envDict,
|
'env': envDict,
|
||||||
'ports': json.loads(con.ports),
|
'ports': json.loads(con.ports),
|
||||||
# No filter needed now as its ports are filtered when adding to database
|
'volumes': volumes,
|
||||||
'memory': con.memory
|
'memory': con.memory
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,6 +1005,7 @@ class ContainerManager(multi.Thread):
|
|||||||
return HttpResponse(json_data)
|
return HttpResponse(json_data)
|
||||||
|
|
||||||
con.env = json.dumps(envDict)
|
con.env = json.dumps(envDict)
|
||||||
|
con.volumes = json.dumps(volumes)
|
||||||
con.save()
|
con.save()
|
||||||
|
|
||||||
data_ret = {'saveSettingsStatus': 1, 'error_message': 'None'}
|
data_ret = {'saveSettingsStatus': 1, 'error_message': 'None'}
|
||||||
|
|||||||
Reference in New Issue
Block a user