1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/console/views.py
catborise f6d4886d1b refactor(console): a console's URL names its compute and VM
The console page is /console/<compute>/<uuid>/ with the view and display
options in the query. It was /console/?token=<compute>-<uuid>, a "token"
that was only the VM's address, parsed alongside a signed token that no
link ever sent. The list's console button takes the VM's UUID from the
database instead of asking libvirt for each row, and no longer defines a
global function per row.
2026-10-26 20:41:46 +03:00

100 lines
4.5 KiB
Python

# pylint: disable=no-name-in-module,no-member
from appsettings.settings import app_settings
from console import tokens
from django.conf import settings
from django.http.response import HttpResponseForbidden
from django.shortcuts import render
from django.utils.translation import gettext_lazy as _
from instances.models import Instance
from instances.utils import can_open_console
from libvirt import libvirtError
from vrtManager.connection import CONN_TCP, CONN_TLS
from vrtManager.instance import wvmInstance
def to_bool(val, default=False):
if val is None:
return default
return str(val).strip().lower() in ("true", "1", "yes")
def console(request, compute_id, uuid):
"""The console page of the VM with this UUID on this compute. The page's
query gives the view (lite or full) and its display options."""
console_error = None
token = ""
view_type = "full" if request.GET.get("view", "").strip().lower() == "full" else "lite"
view_only = to_bool(request.GET.get("view_only"), default=to_bool(app_settings.CONSOLE_VIEW_ONLY))
scale = to_bool(request.GET.get("scale"), default=to_bool(app_settings.CONSOLE_SCALE))
resize_session = to_bool(request.GET.get("resize_session"), default=to_bool(app_settings.CONSOLE_RESIZE_SESSION))
clip_viewport = to_bool(request.GET.get("clip_viewport"), default=to_bool(app_settings.CONSOLE_CLIP_VIEWPORT))
try:
instance = Instance.objects.filter(compute_id=compute_id, uuid=uuid).first()
if instance is None and request.user.is_superuser:
raise Instance.DoesNotExist
# Same answer for "no such VM" and "not allowed", so the response
# does not reveal whether a VM exists.
if instance is None or not can_open_console(request.user, instance):
console_error = _(
"User does not have permission to access console or host/instance not exist"
)
return HttpResponseForbidden(console_error)
# Generate secure signed token for noVNC daemon
token = tokens.SIGNER.sign(f"{compute_id}:{uuid}:{request.user.id}")
conn = wvmInstance(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
instance.name,
uuid=instance.uuid,
)
console_type = conn.get_console_type()
console_websocket_port = conn.get_console_websocket_port()
console_passwd = conn.get_console_passwd()
running = conn.instance.isActive()
# novncd reaches a console that listens on its host's loopback only
# through SSH (or on this host)
unreachable = instance.compute.type in (CONN_TCP, CONN_TLS) and conn.console_listens_locally()
except (libvirtError, ValueError, IndexError, Instance.DoesNotExist):
running = unreachable = False
console_type = None
console_websocket_port = None
console_passwd = None
if console_type and not running: # a shut-off VM has no console to connect to
console_error = _("The VM is not running: start it to open its console.")
response = render(request, "console-vnc-lite.html", locals())
elif console_type == "vnc" and unreachable:
console_error = _(
"This console listens only on its host, which the panel reaches over TCP or TLS. "
"Let the console listen on all interfaces in the VM's console settings, "
"or add the host as an SSH host."
)
response = render(request, "console-vnc-lite.html", locals())
elif console_type == "vnc":
console_page = "console-vnc-" + view_type + ".html"
response = render(request, console_page, locals())
elif console_type == "pty" and not settings.SERIAL_CONSOLE_ENABLED:
console_error = _(
"Serial console is disabled on this server. "
"Please switch VM graphics to VNC or ask an administrator."
)
response = render(request, "console-vnc-lite.html", locals())
elif console_type == "pty":
response = render(request, "console-xterm.html", locals())
else:
if console_type is None:
console_error = _(
"Fail to get console. Please check the console configuration of your VM."
)
else:
console_error = _(
"Console type '%(type)s' is not supported. Please switch the VM graphics to VNC."
) % {"type": console_type}
response = render(request, "console-vnc-lite.html", locals())
return response