1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 12:46:49 +00:00

feat(console): VNC is the only console type

SPICE was removed earlier; its leftovers and the console type choice go
too:
- the console settings form, update_console and the backend no longer
  offer or change the type; an invalid console form now shows its
  errors instead of being ignored;
- the create form, the API serializer and create_instance no longer take
  a graphics type, new VMs get VNC; get_graphics_types and the graphics
  entries of the domain capabilities are gone;
- migration appsettings.0013 deletes QEMU_CONSOLE_DEFAULT_TYPE;
- a VM defined elsewhere with another graphics type gets "Console type
  ... is not supported".

The locale catalogs still reference the deleted SPICE templates in
source comments; regenerating them is left to the translation work.
This commit is contained in:
catborise 2026-10-04 00:27:55 +03:00
parent 9f86330552
commit e5fda79f5a
18 changed files with 74 additions and 127 deletions

View file

@ -52,7 +52,6 @@ class FlavorSerializer(serializers.ModelSerializer):
class CreateInstanceSerializer(serializers.ModelSerializer):
graphics = serializers.CharField(initial="vnc")
video = serializers.CharField(initial="vga")
storage = serializers.CharField(initial="default")
cache_mode = serializers.CharField(initial="none")
@ -76,7 +75,6 @@ class CreateInstanceSerializer(serializers.ModelSerializer):
"virtio",
"qemu_ga",
"console_pass",
"graphics",
"video",
"listener_addr",
]

View file

@ -302,7 +302,6 @@ class CreateInstanceViewSet(viewsets.ViewSet):
volumes=volume_list,
networks=serializer.validated_data["networks"],
nwfilter=serializer.validated_data["nwfilter"],
graphics=serializer.validated_data["graphics"],
virtio=serializer.validated_data["virtio"],
listener_addr=serializer.validated_data["listener_addr"],
video=serializer.validated_data["video"],

View file

@ -1,6 +1,5 @@
import re
from appsettings.models import AppSettings
from django import forms
from django.utils.translation import gettext_lazy as _
from webvirtcloud.settings import QEMU_CONSOLE_LISTENER_ADDRESSES, QEMU_KEYMAPS
@ -15,7 +14,6 @@ class FlavorForm(forms.ModelForm):
class ConsoleForm(forms.Form):
type = forms.ChoiceField(label=_("Type"))
listen_on = forms.ChoiceField(label=_("Listen on"))
generate_password = forms.BooleanField(label=_("Generate password"), required=False)
clear_password = forms.BooleanField(label=_("Clear password"), required=False)
@ -29,12 +27,7 @@ class ConsoleForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ConsoleForm, self).__init__(*args, **kwargs)
type_choices = (
(c, c)
for c in AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list()
)
keymap_choices = [("auto", _("Auto"))] + list((c, c) for c in QEMU_KEYMAPS)
self.fields["type"] = forms.ChoiceField(label=_("Type"), choices=type_choices)
self.fields["listen_on"] = forms.ChoiceField(
label=_("Listen on"),
choices=QEMU_CONSOLE_LISTENER_ADDRESSES

View file

@ -273,9 +273,6 @@ class CreateInstance(models.Model):
console_pass = models.CharField(max_length=64, blank=True)
add_cdrom = models.CharField(max_length=16)
add_input = models.CharField(max_length=16)
graphics = models.CharField(
max_length=16, error_messages={"required": _("Please select a graphics type")}
)
video = models.CharField(
max_length=16, error_messages={"required": _("Please select a video driver")}
)

View file

@ -216,20 +216,6 @@
</select>
</div>
</div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Graphics" %}</label>
<div class="col-sm-7">
<select class="form-select" name="graphics">
{% for graphics in dom_caps.graphics_types %}
{% if graphics != 'spice' %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">
@ -483,20 +469,6 @@
</select>
</div>
</div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Graphics" %}</label>
<div class="col-sm-7">
<select class="form-select" name="graphics">
{% for graphics in dom_caps.graphics_types %}
{% if graphics != 'spice' %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">
@ -737,20 +709,6 @@
</select>
</div>
</div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Graphics" %}</label>
<div class="col-sm-7">
<select class="form-select" name="graphics">
{% for graphics in dom_caps.graphics_types %}
{% if graphics != 'spice' %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">

View file

@ -266,13 +266,6 @@
$("#console_select_keymap option[value='" + keymap + "']").prop('selected', true);
}
});
$(document).ready(function () {
// set current console type or fall back to default
var console_type = "{{ instance.console_type }}";
if (console_type != '') {
$("#console_select_type option[value='" + console_type + "']").prop('selected', true);
}
});
$(document).ready(function () {
// set current console listen address or fall back to default
var console_listener_address = "{{ instance.console_listener_address }}";

View file

@ -723,7 +723,7 @@
{% bootstrap_form console_form layout='horizontal' %}
<div class="float-end">
{% if instance.status != 5 %}
<button class="btn btn-success" name="set_console_type" disabled>{% trans "Update" %}</button>
<button class="btn btn-success" disabled>{% trans "Update" %}</button>
{% else %}
<button type="submit" class="btn btn-success ">{% trans "Update" %}</button>
{% endif %}

View file

@ -0,0 +1,27 @@
from unittest.mock import patch
from computes.models import Compute
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from instances.models import Instance
class UpdateConsoleTestCase(TestCase):
def setUp(self):
admin = get_user_model().objects.create_superuser("console_admin", "c@example.com", "pw")
self.client.force_login(admin)
compute = Compute.objects.create(name="console-compute", hostname="127.0.0.1", login="", password="", type=4)
self.instance = Instance.objects.create(
compute=compute, name="console-vm", uuid="11111111-2222-3333-4444-555555555555"
)
def post(self, data):
with patch("instances.models.wvmInstance") as wvm:
self.client.post(reverse("instances:update_console", args=[self.instance.id]), data)
return wvm.return_value
def test_console_settings_are_applied(self):
proxy = self.post({"listen_on": "127.0.0.1", "password": "", "keymap": "de"})
proxy.set_console_keymap.assert_called_once_with("de")
proxy.set_console_listener_addr.assert_called_once_with("127.0.0.1")

View file

@ -780,7 +780,7 @@ class InstancesTestCase(TestCase):
def test_console(self):
response = self.client.post(
reverse("instances:update_console", args=[self.instance.id]),
{"type": "spice", "listen_on": "0.0.0.0", "password": "", "keymap": "auto"},
{"listen_on": "0.0.0.0", "password": "", "keymap": "auto"},
HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)

View file

@ -78,9 +78,6 @@ def instance(request, pk):
users = User.objects.all().order_by("username")
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
keymaps = settings.QEMU_KEYMAPS
console_types = AppSettings.objects.get(
key="QEMU_CONSOLE_DEFAULT_TYPE"
).choices_as_list()
# The console form renders the VNC password, so only users who may manage
# console settings get the form (and the password) at all.
can_manage_console = utils.can_manage_console(request.user, instance)
@ -88,7 +85,6 @@ def instance(request, pk):
if can_manage_console:
console_form = ConsoleForm(
initial={
"type": instance.console_type,
"listen_on": instance.console_listener_address,
"password": instance.console_passwd,
"keymap": instance.console_keymap,
@ -1889,19 +1885,14 @@ def update_console(request, pk):
request.user.username, instance.compute.name, instance.name, msg
)
if "type" in form.changed_data:
instance.proxy.set_console_type(form.cleaned_data["type"])
msg = _("Set VNC type")
addlogmsg(
request.user.username, instance.compute.name, instance.name, msg
)
if "listen_on" in form.changed_data:
instance.proxy.set_console_listener_addr(form.cleaned_data["listen_on"])
msg = _("Set VNC listen address")
addlogmsg(
request.user.username, instance.compute.name, instance.name, msg
)
else:
messages.error(request, _("Console settings were not saved: %(errors)s") % {"errors": form.errors.as_text()})
return get_safe_redirect(
request, default=reverse("instances:instance", args=[instance.id]) + "#vncsettings"
@ -2085,7 +2076,6 @@ def create_instance(request, compute_id, arch, machine):
net_models_host = conn.get_network_models()
default_nic_type = app_settings.INSTANCE_NIC_DEFAULT_TYPE
storages = sorted(conn.get_storages(only_actives=True))
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
default_cdrom = app_settings.INSTANCE_CDROM_ADD
input_device_buses = ["default", "virtio", "usb"]
default_input_device_bus = app_settings.INSTANCE_INPUT_DEFAULT_DEVICE
@ -2265,7 +2255,6 @@ def create_instance(request, compute_id, arch, machine):
listener_addr=data["listener_addr"],
nwfilter=data["nwfilter"],
net_model=data["net_model"],
graphics=data["graphics"],
video=data["video"],
console_pass=data["console_pass"],
mac=data["mac"],