mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-25 23:55:24 +00:00
Merge pull request #585 from catborise/master
various addings and fixes
This commit is contained in:
commit
beb13cdea1
22 changed files with 8679 additions and 11569 deletions
|
@ -9,6 +9,7 @@
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="login-box">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<a class="" href="/"><h1>WebVirtCloud</h1></a>
|
<a class="" href="/"><h1>WebVirtCloud</h1></a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,4 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -5,7 +5,7 @@ from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_noop as _
|
||||||
from logs.views import addlogmsg
|
from logs.views import addlogmsg
|
||||||
|
|
||||||
from appsettings.models import AppSettings
|
from appsettings.models import AppSettings
|
||||||
|
|
|
@ -49,6 +49,10 @@ class Compute(Model):
|
||||||
def cpu_count(self):
|
def cpu_count(self):
|
||||||
return self.proxy.get_node_info()[3]
|
return self.proxy.get_node_info()[3]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def cpu_usage(self):
|
||||||
|
return round(self.proxy.get_cpu_usage().get('usage'))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def ram_size(self):
|
def ram_size(self):
|
||||||
return self.proxy.get_node_info()[2]
|
return self.proxy.get_node_info()[2]
|
||||||
|
|
|
@ -39,8 +39,8 @@
|
||||||
<script src="{% static 'js/filter-table.js' %}"></script>
|
<script src="{% static 'js/filter-table.js' %}"></script>
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<script>
|
<script>
|
||||||
function goto_compute() {
|
function goto_compute(compute) {
|
||||||
let compute = $("#compute_select").val();
|
//let compute = $("#compute_select").val();
|
||||||
window.location.href = "{% url 'instances:create_instance_select_type' 1 %}".replace(1, compute);
|
window.location.href = "{% url 'instances:create_instance_select_type' 1 %}".replace(1, compute);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<!-- Modal pool -->
|
<!-- Modal pool -->
|
||||||
<div class="modal fade" id="AddInstance" tabindex="-1" role="dialog" aria-labelledby="AddInstanceModal" aria-hidden="true">
|
<div class="modal fade" id="AddInstance" tabindex="-1" role="dialog" aria-labelledby="AddInstanceModal" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog modal-dialog-scrollable modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">{% trans "Choose a compute for new instance" %}</h5>
|
<h5 class="modal-title">{% trans "Choose a compute for new instance" %}</h5>
|
||||||
|
@ -15,34 +15,51 @@
|
||||||
<form method="post" aria-label="Select compute for instance create form">
|
<form method="post" aria-label="Select compute for instance create form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Compute" %}</label>
|
<table class="table">
|
||||||
<div class="col-sm-6">
|
<thead>
|
||||||
<select class="form-select" id="compute_select">
|
<tr style="cursor:default;pointer-events:none">
|
||||||
<option>{% trans "Please select" %}</option>
|
<th>{% trans "Name" %}</th>
|
||||||
|
<th>{% trans "VCPU" %}
|
||||||
|
<th>{% trans "Cpu Usage" %}</th>
|
||||||
|
<th>{% trans "Memory" %}</th>
|
||||||
|
<th>{% trans "Mem Usage" %}</th>
|
||||||
|
<th>{% trans "Action" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
{% for compute in computes %}
|
{% for compute in computes %}
|
||||||
<option {% if compute.status is not True %} class="font-italic text-muted" {% else %} value="{{ compute.id }}" {% endif %}>{{ compute.name }}</option>
|
{% if compute.status is True %}
|
||||||
{% empty %}
|
<tr style="text-decoration: none">
|
||||||
<option value="None">{% trans "None" %}</option>
|
<td>{{ compute.name }}</td>
|
||||||
{% endfor %}
|
<td>{{ compute.cpu_count }}</td>
|
||||||
</select>
|
<td>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar bg-success" role="progressbar" style="width: {{ compute.cpu_usage }}%"
|
||||||
|
aria-valuenow="{{ compute.cpu_usage }}" aria-valuemin="0" aria-valuemax="100">{{ compute.cpu_usage }}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ compute.ram_size|filesizeformat }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar bg-success" role="progressbar" style="width: {{ compute.ram_usage }}%"
|
||||||
|
aria-valuenow="{{ compute.ram_usage }}" aria-valuemin="0" aria-valuemax="100">{{ compute.ram_usage }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="col-1">
|
||||||
|
<button class="btn btn-success btn-sm" type="button" onclick="goto_compute('{{ compute.id }}');">
|
||||||
|
{% trans "Choose" %}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
||||||
{% trans "Close" %}
|
|
||||||
</button>
|
|
||||||
{% if computes %}
|
|
||||||
<button type="submit" class="btn btn-primary" name="choose" onclick='goto_compute()'>
|
|
||||||
{% trans "Choose" %}
|
|
||||||
</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-primary disabled">
|
|
||||||
{% trans "Choose" %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div> <!-- /.modal-content -->
|
</div> <!-- /.modal-content -->
|
||||||
</div> <!-- /.modal-dialog -->
|
</div> <!-- /.modal-dialog -->
|
||||||
</div> <!-- /.modal -->
|
</div> <!-- /.modal -->
|
||||||
|
|
|
@ -46,11 +46,10 @@
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="takeextsnapshot">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="takeextsnapshot">
|
||||||
{% if instance.status != 5 %}
|
{% if instance.status != 5 %}
|
||||||
<p>{% trans "You can get external snapshots within this tab." %}</p>
|
<p>{% trans "You can get external snapshots within this tab." %}</p>
|
||||||
<p class="text-primary">{% trans "External snapshots are experimental in this stage, use it if you know what you are doing. It may require manual intervention." %}</p>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans "Create an external snapshot" %}</p>
|
<p>{% trans "Create an external snapshot" %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="text-danger">{% trans "Give your External Snapshot a <b>distinctive description</b> so it wouldn't get mixed with other snapshots." %}</p>
|
<p class="fst-italic">{% trans "External snapshots are experimental in this stage, use it if you know what you are doing. 'Revert Snapshot' may require manual operation with CLI." %}</p>
|
||||||
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" role="form" aria-label="Create snapshot form">
|
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" role="form" aria-label="Create snapshot form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
|
@ -63,7 +62,7 @@
|
||||||
<input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();">
|
<input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-danger">{% trans "WebVirtCloud supports only one external snapshot at the moment." %}</p>
|
<p class="text-danger font-monospace small">{% trans "WebVirtCloud supports only one external snapshot at the moment." %}</p>
|
||||||
</form>
|
</form>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div> <!--tab pane takeextsnapshot-->
|
</div> <!--tab pane takeextsnapshot-->
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#logs" type="button" role="tab" aria-controls="logs" aria-selected="false">
|
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#logs" type="button" role="tab" aria-controls="logs" aria-selected="false" onclick="update_logs_table(vname);">
|
||||||
{% trans "Logs" %}
|
{% trans "Logs" %}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -19,7 +19,7 @@ from django.contrib.auth.models import User
|
||||||
from django.http import Http404, HttpResponse, JsonResponse
|
from django.http import Http404, HttpResponse, JsonResponse
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_noop as _
|
||||||
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM,
|
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM,
|
||||||
VIR_DOMAIN_UNDEFINE_NVRAM,
|
VIR_DOMAIN_UNDEFINE_NVRAM,
|
||||||
VIR_DOMAIN_START_PAUSED,
|
VIR_DOMAIN_START_PAUSED,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@ from computes.models import Compute
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_noop as _
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
from logs.views import addlogmsg
|
from logs.views import addlogmsg
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
|
|
|
@ -1,3 +1,24 @@
|
||||||
|
/* body {
|
||||||
|
background: rgba(203,203,203,1)
|
||||||
|
} */
|
||||||
|
.login-box {
|
||||||
|
margin-top: 25%;
|
||||||
|
display: block;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0px 0px 30px black;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding-top: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
background: linear-gradient(0deg, rgba(203,203,203,1) 0%, rgba(255,255,255,1) 100%);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color:#212529;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color:#212529;
|
||||||
|
}
|
||||||
|
|
||||||
.form-signin {
|
.form-signin {
|
||||||
max-width: 330px;
|
max-width: 330px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
@ -29,15 +50,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-signin input[type="text"] {
|
.form-signin input[type="text"] {
|
||||||
margin-bottom: -1px;
|
margin-bottom: 10px;
|
||||||
border-bottom-left-radius: 0;
|
border-radius: 5px;
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-signin input[type="password"] {
|
.form-signin input[type="password"] {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border-top-left-radius: 0;
|
border-radius: 5px;
|
||||||
border-top-right-radius: 0;
|
}
|
||||||
|
|
||||||
|
.btn-success {
|
||||||
|
background: linear-gradient(45deg, rgba(190,120,255,1) 0%, rgba(43,108,173,1) 34%, rgba(38,173,151,1) 68%, rgba(208,144,71,1) 100%);
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
border-color: rgba(11, 12, 13, 0);
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.btn-success:hover {
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
border-color: goldenrod;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout {
|
.logout {
|
||||||
|
|
|
@ -2,7 +2,6 @@ import contextlib
|
||||||
import json
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
import time
|
import time
|
||||||
import subprocess
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from libvirt import (
|
from libvirt import (
|
||||||
|
@ -1255,6 +1254,7 @@ class wvmInstance(wvmConnect):
|
||||||
return iso
|
return iso
|
||||||
|
|
||||||
def delete_all_disks(self):
|
def delete_all_disks(self):
|
||||||
|
self.refresh_instance_pools()
|
||||||
disks = self.get_disk_devices()
|
disks = self.get_disk_devices()
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
vol = self.get_volume_by_path(disk.get("path"))
|
vol = self.get_volume_by_path(disk.get("path"))
|
||||||
|
@ -1318,7 +1318,7 @@ class wvmInstance(wvmConnect):
|
||||||
</domainsnapshot>"""
|
</domainsnapshot>"""
|
||||||
|
|
||||||
self._snapshotCreateXML(xml, VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)
|
self._snapshotCreateXML(xml, VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)
|
||||||
|
self.refresh_instance_pools()
|
||||||
|
|
||||||
def get_external_snapshots(self):
|
def get_external_snapshots(self):
|
||||||
return self.get_snapshot(VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)
|
return self.get_snapshot(VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)
|
||||||
|
@ -1350,29 +1350,23 @@ class wvmInstance(wvmConnect):
|
||||||
|
|
||||||
|
|
||||||
def revert_external_snapshot(self, name, date, desc):
|
def revert_external_snapshot(self, name, date, desc):
|
||||||
pool = None
|
|
||||||
snap = self.instance.snapshotLookupByName(name, 0)
|
snap = self.instance.snapshotLookupByName(name, 0)
|
||||||
snap_xml = snap.getXMLDesc(0)
|
snap_xml = snap.getXMLDesc(0)
|
||||||
snapXML = ElementTree.fromstring(snap_xml)
|
snapXML = ElementTree.fromstring(snap_xml)
|
||||||
disks = snapXML.findall('inactiveDomain/devices/disk')
|
|
||||||
if not disks: disks = snapXML.findall('domain/devices/disk')
|
|
||||||
|
|
||||||
self.start(flags=VIR_DOMAIN_START_PAUSED) if self.get_status() == 5 else None
|
self.start(flags=VIR_DOMAIN_START_PAUSED) if self.get_status() == 5 else None
|
||||||
|
self.delete_all_disks()
|
||||||
|
|
||||||
disk_info = self.get_disk_devices()
|
|
||||||
for disk in disk_info:
|
|
||||||
vol_snap = self.get_volume_by_path(disk["path"])
|
|
||||||
pool = vol_snap.storagePoolLookupByVolume()
|
|
||||||
pool.refresh(0)
|
|
||||||
vol_snap.delete(0)
|
|
||||||
self.force_shutdown()
|
self.force_shutdown()
|
||||||
|
|
||||||
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
|
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
|
||||||
|
|
||||||
|
disks = snapXML.findall('inactiveDomain/devices/disk')
|
||||||
|
if not disks: disks = snapXML.findall('domain/devices/disk')
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
self.instance.updateDeviceFlags(ElementTree.tostring(disk).decode("UTF-8"))
|
self.instance.updateDeviceFlags(ElementTree.tostring(disk).decode("UTF-8"))
|
||||||
name = name.replace("s1", "s2")
|
name = name.replace("s1", "s2")
|
||||||
self.create_external_snapshot(name, date, desc)
|
self.create_external_snapshot(name, date, desc)
|
||||||
pool.refresh() if pool else None
|
|
||||||
|
|
||||||
def get_snapshot(self, flag=VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL):
|
def get_snapshot(self, flag=VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL):
|
||||||
snapshots = []
|
snapshots = []
|
||||||
|
@ -1413,6 +1407,15 @@ class wvmInstance(wvmConnect):
|
||||||
def get_wvmStorages(self):
|
def get_wvmStorages(self):
|
||||||
return wvmStorages(self.host, self.login, self.passwd, self.conn)
|
return wvmStorages(self.host, self.login, self.passwd, self.conn)
|
||||||
|
|
||||||
|
def refresh_instance_pools(self):
|
||||||
|
disks = self.get_disk_devices()
|
||||||
|
target_paths = set()
|
||||||
|
for disk in disks:
|
||||||
|
disk_path = disk.get("path")
|
||||||
|
target_paths.add(os.path.dirname(disk_path))
|
||||||
|
for target_path in target_paths:
|
||||||
|
self.get_wvmStorages().get_pool_by_target(target_path).refresh(0)
|
||||||
|
|
||||||
def fix_mac(self, mac):
|
def fix_mac(self, mac):
|
||||||
if ":" in mac:
|
if ":" in mac:
|
||||||
return mac
|
return mac
|
||||||
|
|
|
@ -28,6 +28,14 @@ class wvmStorages(wvmConnect):
|
||||||
def define_storage(self, xml, flag):
|
def define_storage(self, xml, flag):
|
||||||
self.wvm.storagePoolDefineXML(xml, flag)
|
self.wvm.storagePoolDefineXML(xml, flag)
|
||||||
|
|
||||||
|
def get_pool_by_target(self, target):
|
||||||
|
pool_names = self.get_storages()
|
||||||
|
for pool_name in pool_names:
|
||||||
|
stg = wvmStorage(self.host, self.login, self.passwd, self.conn, pool_name)
|
||||||
|
if stg.get_target_path() == target:
|
||||||
|
return self.get_storage(pool_name)
|
||||||
|
return None
|
||||||
|
|
||||||
def create_storage(self, stg_type, name, source, target):
|
def create_storage(self, stg_type, name, source, target):
|
||||||
xml = f"""<pool type='{stg_type}'>
|
xml = f"""<pool type='{stg_type}'>
|
||||||
<name>{name}</name>"""
|
<name>{name}</name>"""
|
||||||
|
|
|
@ -120,6 +120,8 @@ LOGIN_URL = "/accounts/login/"
|
||||||
|
|
||||||
LOGOUT_REDIRECT_URL = "/accounts/login/"
|
LOGOUT_REDIRECT_URL = "/accounts/login/"
|
||||||
|
|
||||||
|
LOGIN_REDIRECT_URL="/instances/"
|
||||||
|
|
||||||
LANGUAGE_CODE = "en-us"
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
TIME_ZONE = "UTC"
|
TIME_ZONE = "UTC"
|
||||||
|
|
Loading…
Reference in a new issue