From 62ffaab808b347f585102e1a0bce55fd2caec23f Mon Sep 17 00:00:00 2001 From: catborise Date: Tue, 6 Oct 2026 10:12:08 +0300 Subject: [PATCH] fix(instances): the create wizard reaches the page of any architecture The first page of the create wizard built the next page's URL from a reversed ".../x86_64/pc/" by replacing "x86_64" with the chosen architecture and then the first "pc" with the machine type. An architecture containing "pc" got the machine type inside its name: ppc64le with pseries went to /instances/create/1/ppseries64le/pc/, so VMs could not be created on PowerPC hosts. The URL is now reversed with the placeholders __arch__ and __machine__, which the script replaces with the URL-encoded values. The test renders the page, runs the script with node and fails on the previous template for ppc64le. --- instances/templates/create_instance_w1.html | 5 ++- instances/test_create_wizard_url.py | 36 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 instances/test_create_wizard_url.py diff --git a/instances/templates/create_instance_w1.html b/instances/templates/create_instance_w1.html index d47f03f9..3559a0e4 100644 --- a/instances/templates/create_instance_w1.html +++ b/instances/templates/create_instance_w1.html @@ -131,7 +131,10 @@ let arch = $("#select_archs").val(); let machine = $("#select_chipset").val(); //create_machine_url = "/computes/" + compute + "/create/archs/" + arch + "/machines/" + machine; - url = "{% url 'instances:create_instance' compute.id 'x86_64' 'pc' %}".replace(/x86_64/, arch).replace(/pc/, machine); + // placeholders, not "x86_64"/"pc": an arch such as ppc64 contains "pc" + url = "{% url 'instances:create_instance' compute.id '__arch__' '__machine__' %}" + .replace("__arch__", encodeURIComponent(arch)) + .replace("__machine__", encodeURIComponent(machine)); window.location.href = url;//create_machine_url; } diff --git a/instances/test_create_wizard_url.py b/instances/test_create_wizard_url.py new file mode 100644 index 00000000..e9b5ce45 --- /dev/null +++ b/instances/test_create_wizard_url.py @@ -0,0 +1,36 @@ +"""The create wizard's first page sends the browser to the next page for the +chosen architecture and machine type; the URL is built from placeholders.""" + +import re +import subprocess +import shutil +import unittest + +from computes.models import Compute +from django.contrib.auth import get_user_model +from django.template.loader import render_to_string +from django.test import RequestFactory, TestCase + + +class CreateWizardUrlTests(TestCase): + def render_script(self): + compute = Compute.objects.create(name="cw", hostname="10.0.0.6", login="u", password="p", type=1) + request = RequestFactory().get("/") + request.user = get_user_model().objects.create_superuser("cw-admin", "cw@example.com", "pw") + page = render_to_string("create_instance_w1.html", {"compute": compute}, request=request) + # the statement that builds the URL from arch and machine + return re.search(r"\burl = (.*?);", page, re.S).group(1) + + @unittest.skipUnless(shutil.which("node"), "node is not installed") + def test_arch_and_machine_names_land_in_their_segments(self): + script = self.render_script() + cases = { + ("x86_64", "q35"): "x86_64/q35/", + ("ppc64le", "pseries"): "ppc64le/pseries/", # contains "pc" + ("aarch64", "virt"): "aarch64/virt/", + } + for (arch, machine), tail in cases.items(): + js = "const arch = %r, machine = %r; console.log(%s);" % (arch, machine, script) + out = subprocess.run(["node", "-e", js], capture_output=True, text=True, timeout=30) + with self.subTest(arch=arch): + self.assertTrue(out.stdout.strip().endswith(f"/{tail}"), out.stdout + out.stderr)