From d14a31186258842029c4bef19dc40c8fcb58919a Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 19 Oct 2026 22:09:04 +0300 Subject: [PATCH] fix(instances): the disk bus list follows the device type on the create page Changing a disk's device type in the custom create form asked for its buses at /archs/undefined/machines/undefined/...: the script read the architecture and machine from a select[name=arch] and #machine-control the page does not have. The request failed (500) and the bus list kept the disk's buses, so a CD-ROM could be put on virtio. The script takes both from the page's own URL. --- instances/templates/create_instance_w2.html | 5 +-- instances/tests/test_create_page_js.py | 39 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 instances/tests/test_create_page_js.py diff --git a/instances/templates/create_instance_w2.html b/instances/templates/create_instance_w2.html index b5f2ee09..5af065be 100644 --- a/instances/templates/create_instance_w2.html +++ b/instances/templates/create_instance_w2.html @@ -921,8 +921,9 @@ } function get_disk_bus_choices(compute_id, dev_idx, disk_type){ - let arch = $('select[name="arch"]').val(); - let machine = $("select[id='machine-control']").val(); + // the page's own architecture and machine type, from its URL + let arch = "{{ arch|escapejs }}"; + let machine = "{{ machine|escapejs }}"; get_diskBus_url = "/computes/" + compute_id + "/archs/" + arch + "/machines/" + machine + "/disks/" + disk_type + "/buses"; $.getJSON(get_diskBus_url, function (data) { $("#bus" + dev_idx).find('option').remove(); diff --git a/instances/tests/test_create_page_js.py b/instances/tests/test_create_page_js.py new file mode 100644 index 00000000..1f3d02f0 --- /dev/null +++ b/instances/tests/test_create_page_js.py @@ -0,0 +1,39 @@ +"""Scripts of the VM create page, rendered on libvirt's test driver and run +in Node against stand-ins.""" + +import re +import shutil +import subprocess +import unittest +from unittest.mock import patch + +import libvirt +from computes.models import Compute +from django.contrib.auth import get_user_model +from django.test import TestCase +from django.urls import reverse + + +class CreatePageScriptTests(TestCase): + def page(self): + conn = libvirt.open("test:///default") + self.addCleanup(conn.close) + compute = Compute.objects.create(name="testdrv", hostname="localhost", login="", password="", type=4) + self.client.force_login(get_user_model().objects.create_superuser("js", "js@example.com", "pw")) + with patch("vrtManager.connection.connection_manager.get_connection", return_value=conn), \ + patch("vrtManager.connection.wvmConnect.get_machine_types", return_value=["pc"]), \ + patch("vrtManager.connection.wvmConnect.get_nwfilters", return_value=[]): + response = self.client.get(reverse("instances:create_instance", args=[compute.id, "i686", "pc"])) + self.assertEqual(response.status_code, 200) + return compute, response.content.decode() + + @unittest.skipUnless(shutil.which("node"), "node is not installed") + def test_the_disk_bus_list_is_asked_for_the_page_architecture_and_machine(self): + compute, page = self.page() + function = re.search(r"function get_disk_bus_choices\(.*?\n }\n", page, re.S).group(0) + script = "let asked; const $ = Object.assign(() => ({find: () => ({remove() {}}), append() {}, val() {}}), " \ + "{getJSON: url => { asked = url; }, each() {}});\n" + function + \ + f"get_disk_bus_choices({compute.id}, 0, 'cdrom'); console.log(asked);" + result = subprocess.run(["node", "-e", script], capture_output=True, text=True, timeout=30) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout.strip(), reverse("buses", args=[compute.id, "i686", "pc", "cdrom"]))