import json from admin.decorators import superuser_only from django.core import signing from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone from instances.models import Instance from libvirt import libvirtError from operations import claims from vrtManager.connection import wvmConnect from vrtManager.hostdetails import wvmHostDetails from computes.forms import ( SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm, ) from computes.models import Compute from . import utils # The host CPU graph sends back the CPU sample of its previous answer; usage # is taken since then when it is this recent, otherwise over one second. CPU_SAMPLE_MAX_AGE = 15 CPU_SAMPLE_SIGNER = signing.TimestampSigner(salt="computes.cpu-sample") @superuser_only def computes(request): """ :param request: :return: """ computes = Compute.objects.filter().order_by("name") return render(request, "computes/list.html", {"computes": computes}) @superuser_only def overview(request, compute_id): compute = get_object_or_404(Compute, pk=compute_id) # the connection itself, not a TCP probe: ssh aliases and ProxyJump hosts # are not reachable by name and port from here status = "true" if compute.status else "false" 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, "job_resource": claims.compute_key(compute.id)}, ) @superuser_only def compute_create(request, FormClass): form = FormClass(request.POST or None) if form.is_valid(): form.save() return redirect(reverse("computes")) return render(request, "computes/form.html", {"form": form}) @superuser_only def compute_update(request, compute_id): compute = get_object_or_404(Compute, pk=compute_id) if compute.type == 1: FormClass = TcpComputeForm elif compute.type == 2: FormClass = SshComputeForm elif compute.type == 3: FormClass = TlsComputeForm elif compute.type == 4: FormClass = SocketComputeForm form = FormClass(request.POST or None, instance=compute) if form.is_valid(): form.save() return redirect(reverse("computes")) return render(request, "computes/form.html", {"form": form}) @superuser_only def compute_delete(request, compute_id): compute = get_object_or_404(Compute, pk=compute_id) if request.method == "POST": compute.delete() return redirect("computes") return render( request, "common/confirm_delete.html", {"object": compute}, ) def compute_graph(request, compute_id): """ :param request: :param compute_id: :return: """ comp_mgr = ComputeManager(compute_id) data = comp_mgr.compute_graph(request.GET.get("cpu_sample")) return HttpResponse(data, content_type="application/json") def get_compute_disk_buses(request, compute_id, arch, machine, disk): """ :param request: :param compute_id: :param arch: :param machine: :param disk: :return: """ comp_mgr = ComputeManager(compute_id) return HttpResponse(comp_mgr.get_disk_buses(arch, machine, disk), content_type="application/json") def get_compute_machine_types(request, compute_id, arch): """ :param request: :param compute_id: :param arch: :return: """ comp_mgr = ComputeManager(compute_id) return HttpResponse(comp_mgr.get_machine_types(arch), content_type="application/json") def get_dom_capabilities(request, compute_id, arch, machine): """ :param request: :param compute_id: :param arch: :param machine: :return: """ comp_mgr = ComputeManager(compute_id) return HttpResponse(comp_mgr.get_dom_capabilities(arch, machine), content_type="application/json") class ComputeManager: def __init__(self, compute_id): self.compute = get_object_or_404(Compute, pk=compute_id) self.conn = wvmConnect( self.compute.hostname, self.compute.login, self.compute.password, self.compute.type, ) def get_dom_capabilities(self, arch, machine): data = dict() try: data["videos"] = self.conn.get_disk_device_types(arch, machine) data["bus"] = self.conn.get_disk_device_types(arch, machine) except libvirtError: pass return json.dumps(data) def get_machine_types(self, arch): data = dict() try: data["machines"] = self.conn.get_machine_types(arch) except libvirtError: pass return json.dumps(data) def get_disk_buses(self, arch, machine, disk): data = dict() try: disk_device_types = self.conn.get_disk_device_types(arch, machine) if disk in disk_device_types: if disk == "disk": data["bus"] = sorted(disk_device_types) elif disk == "cdrom": data["bus"] = ["ide", "sata", "scsi"] elif disk == "floppy": data["bus"] = ["fdc"] elif disk == "lun": data["bus"] = ["scsi"] except libvirtError: pass return json.dumps(data) def _cpu_sample(self, token): """The (idle, total, time) sample in a token of this compute's graph, or None when there is none, it is altered or too old.""" if not token: return None try: data = CPU_SAMPLE_SIGNER.unsign_object(token, max_age=CPU_SAMPLE_MAX_AGE) except signing.BadSignature: return None if data.get("compute") != self.compute.id: return None return data["idle"], data["total"], data["time"] def compute_graph(self, cpu_sample=None): result = {"cpudata": None, "memdata": {"total": None, "usage": None}, "timeline": timezone.now().strftime("%H:%M:%S")} try: conn = wvmHostDetails( self.compute.hostname, self.compute.login, self.compute.password, self.compute.type, ) cpu = conn.get_cpu_usage(previous=self._cpu_sample(cpu_sample)) idle, total, taken = cpu["sample"] result = { "cpudata": cpu["usage"], "memdata": conn.get_memory_usage(), "timeline": timezone.now().strftime("%H:%M:%S"), "window": round(cpu["window"], 1), "cpu_sample": CPU_SAMPLE_SIGNER.sign_object( {"compute": self.compute.id, "idle": idle, "total": total, "time": taken} ), } conn.close() except libvirtError: pass return json.dumps(result)