1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2025-07-31 12:41:08 +00:00

Instances overhaul

This commit is contained in:
Real-Gecko 2020-07-13 15:33:09 +06:00
parent f23e6b000f
commit 47009d47ca
69 changed files with 5011 additions and 4127 deletions

View file

@ -1,8 +1,10 @@
from django.db.models import CharField, IntegerField, Model
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from libvirt import virConnect
from vrtManager.connection import connection_manager
from vrtManager.hostdetails import wvmHostDetails
class Compute(Model):
@ -15,7 +17,45 @@ class Compute(Model):
@cached_property
def status(self):
return connection_manager.host_is_up(self.type, self.hostname)
# return connection_manager.host_is_up(self.type, self.hostname)
# TODO: looks like socket has problems connecting via VPN
if isinstance(self.connection, virConnect):
return True
else:
return self.connection
@cached_property
def connection(self):
try:
return connection_manager.get_connection(
self.hostname,
self.login,
self.password,
self.type,
)
except Exception as e:
return e
@cached_property
def proxy(self):
return wvmHostDetails(
self.hostname,
self.login,
self.password,
self.type,
)
@cached_property
def cpu_count(self):
return self.proxy.get_node_info()[3]
@cached_property
def ram_size(self):
return self.proxy.get_node_info()[2]
@cached_property
def ram_usage(self):
return self.proxy.get_memory_usage()['percent']
def __str__(self):
return self.name

View file

@ -0,0 +1,121 @@
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% load icons %}
{% block title %}{% trans "Instances" %} - {{ compute.name }}{% endblock %}
{% block style %}
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
{% endblock %}
{% block page_header %}{{ compute.name }}{% endblock page_header %}
{% block page_header_extra %}
<a href="{% url 'instances:create_instance_select_type' compute.id %}"
class="btn btn-success btn-header float-right">
{% icon 'plus' %}
</a>
{% if instances %}
<div class="float-right search">
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
</div>
{% endif %}
{% endblock page_header_extra %}
{% block content %}
<div class="row">
<div class="col-lg-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-light shadow-sm">
<li class="breadcrumb-item active">
<a href="{% url 'overview' compute.id %}">{% icon 'dashboard' %} {% trans "Overview" %}</a>
</li>
<li class="breadcrumb-item">
<span class="font-weight-bold">{% icon 'server' %} {% trans "Instances" %}</span>
</li>
<li class="breadcrumb-item">
<a href="{% url 'storages' compute.id %}">{% icon 'hdd-o' %} {% trans "Storages" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'networks' compute.id %}">{% icon 'sitemap' %} {% trans "Networks" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'interfaces' compute.id %}">{% icon 'wifi' %} {% trans "Interfaces" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'nwfilters' compute.id %}">{% icon 'filter' %} {% trans "NWFilters" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'secrets' compute.id %}">{% icon 'key' %} {% trans "Secrets" %}</a>
</li>
</ol>
</nav>
</div>
</div>
<div class="row">
<div class="col-lg-12">
{% if not instances %}
<div class="alert alert-warning alert-dismissable fade show">
{% icon 'exclamation-triangle' %} <strong>{% trans "Warning" %}:</strong>
{% trans "Hypervisor doesn't have any Instances" %}
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
</div>
</div>
{% else %}
<table class="table table-hover sortable-theme-bootstrap" data-sortable>
<thead>
<tr>
<th scope="col">{% trans 'Name' %}<br>{% trans 'Description' %}</th>
<th scope="col">{% trans 'User' %}</th>
<th scope="col">{% trans 'Status' %}</th>
<th scope="col">{% trans 'VCPU' %}</th>
<th scope="col">{% trans 'Memory' %}</th>
<th scope="col" data-sortable="false">{% trans 'Actions' %}</th>
</tr>
</thead>
<tbody class="searchable">
{% for instance in instances %}
<tr>
<td>
<a class="text-secondary" href="{% url 'instances:instance' instance.id %}">
{{ instance.name }}
</a>
</td>
<td>
<em>
{% if instance.userinstance_set.all.count > 0 %}
{{ instance.userinstance_set.all.0.user }}
{% if instance.userinstance_set.all.count > 1 %}
(+{{ instance.userinstance_set.all.count|add:"-1" }})
{% endif %}
{% endif %}
</em>
</td>
<td>
{% if instance.proxy.instance.info.0 == 1 %}<span
class="text-success">{% trans "Active" %}</span>{% endif %}
{% if instance.proxy.instance.info.0 == 5 %}<span
class="text-danger">{% trans "Off" %}</span>{% endif %}
{% if instance.proxy.instance.info.0 == 3 %}<span
class="text-warning">{% trans "Suspended" %}</span>{% endif %}
</td>
<td>{{ instance.proxy.instance.info.3 }}</td>
<td>{% widthratio instance.proxy.instance.info.1 1024 1 %} MiB</td>
<td class="text-nowrap">
{% include 'instance_actions.html' %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
</div>
{% endblock %}
{% block script %}
<script src="{% static "js/sortable.min.js" %}"></script>
<script>
function open_console(uuid) {
window.open("{% url 'console' %}?token=" + uuid, "", "width=850,height=685");
}
</script>
<script src="{% static 'js/filter-table.js' %}"></script>
{% endblock %}

View file

@ -83,6 +83,9 @@ class ComputesTestCase(TestCase):
response = self.client.get(reverse('storages', args=[1]))
self.assertEqual(response.status_code, 200)
def test_storage(self):
pass
def test_default_storage_volumes(self):
response = self.client.get(reverse('volumes', kwargs={'compute_id': 1, 'pool': 'default'}))
self.assertEqual(response.status_code, 200)
@ -115,9 +118,9 @@ class ComputesTestCase(TestCase):
response = self.client.get(reverse('secrets', args=[1]))
self.assertEqual(response.status_code, 200)
def test_create_instance_select_type(self):
response = self.client.get(reverse('create_instance_select_type', args=[1]))
self.assertEqual(response.status_code, 200)
# def test_create_instance_select_type(self):
# response = self.client.get(reverse('create_instance_select_type', args=[1]))
# self.assertEqual(response.status_code, 200)
# TODO: create_instance

View file

@ -1,14 +1,14 @@
from django.urls import path, include
from secrets.views import secrets
from . import views
from . import forms
from create.views import create_instance, create_instance_select_type
from instances.views import instances
from django.urls import include, path
# from instances.views import create_instance, create_instance_select_type
from interfaces.views import interface, interfaces
from networks.views import network, networks
from nwfilters.views import nwfilter, nwfilters
from secrets.views import secrets
from storages.views import get_volumes, storage, storages
from storages.views import create_volume, get_volumes, storage, storages
from . import forms, views
urlpatterns = [
path('', views.computes, name='computes'),
@ -23,10 +23,11 @@ urlpatterns = [
path('update/', views.compute_update, name='compute_update'),
path('delete/', views.compute_delete, name='compute_delete'),
path('statistics', views.compute_graph, name='compute_graph'),
path('instances/', instances, name='instances'),
path('instances/', views.instances, name='instances'),
path('storages/', storages, name='storages'),
path('storage/<str:pool>/volumes', get_volumes, name='volumes'),
path('storage/<str:pool>/volumes/', get_volumes, name='volumes'),
path('storage/<str:pool>/', storage, name='storage'),
path('storage/<str:pool>/create_volume/', create_volume, name='create_volume'),
path('networks/', networks, name='networks'),
path('network/<str:pool>/', network, name='network'),
path('interfaces/', interfaces, name='interfaces'),
@ -34,8 +35,8 @@ urlpatterns = [
path('nwfilters/', nwfilters, name='nwfilters'),
path('nwfilter/<str:nwfltr>/', nwfilter, name='nwfilter'),
path('secrets/', secrets, name='secrets'),
path('create/', create_instance_select_type, name='create_instance_select_type'),
path('create/archs/<str:arch>/machines/<str:machine>/', create_instance, name='create_instance'),
# path('create/', create_instance_select_type, name='create_instance_select_type'),
# path('create/archs/<str:arch>/machines/<str:machine>/', create_instance, name='create_instance'),
path('archs/<str:arch>/machines/', views.get_compute_machine_types, name='machines'),
path(
'archs/<str:arch>/machines/<str:machine>/disks/<str:disk>/buses/',

13
computes/utils.py Normal file
View file

@ -0,0 +1,13 @@
from instances.models import Instance
def refresh_instance_database(compute):
domains = compute.proxy.wvm.listAllDomains()
domain_names = [d.name() for d in domains]
# Delete instances that're not on host from DB
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
# Create instances that're on host but not in DB
names = Instance.objects.filter(compute=compute).values_list('name', flat=True)
for domain in domains:
if domain.name() not in names:
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()

View file

@ -15,6 +15,8 @@ from instances.models import Instance
from vrtManager.connection import (CONN_SOCKET, CONN_SSH, CONN_TCP, CONN_TLS, connection_manager, wvmConnect)
from vrtManager.hostdetails import wvmHostDetails
from . import utils
@superuser_only
def computes(request):
@ -30,36 +32,36 @@ def computes(request):
@superuser_only
def overview(request, compute_id):
"""
:param request:
:param compute_id:
:return:
"""
error_messages = []
compute = get_object_or_404(Compute, pk=compute_id)
status = 'true' if connection_manager.host_is_up(compute.type, compute.hostname) is True else 'false'
try:
conn = wvmHostDetails(
compute.hostname,
compute.login,
compute.password,
compute.type,
)
hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info()
hypervisor = conn.get_hypervisors_domain_types()
mem_usage = conn.get_memory_usage()
emulator = conn.get_emulator(host_arch)
version = conn.get_version()
lib_version = conn.get_lib_version()
conn.close()
except libvirtError as lib_err:
error_messages.append(lib_err)
conn = wvmHostDetails(
compute.hostname,
compute.login,
compute.password,
compute.type,
)
hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info()
hypervisor = conn.get_hypervisors_domain_types()
mem_usage = conn.get_memory_usage()
emulator = conn.get_emulator(host_arch)
version = conn.get_version()
lib_version = conn.get_lib_version()
conn.close()
return render(request, 'overview.html', locals())
@superuser_only
def instances(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
utils.refresh_instance_database(compute)
instances = Instance.objects.filter(compute=compute).prefetch_related('userinstance_set')
return render(request, 'computes/instances.html', {'compute': compute, 'instances': instances})
@superuser_only
def compute_create(request, FormClass):
form = FormClass(request.POST or None)