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

fix(appsettings): settings take only the values the panel can use

The Settings page saved whatever was posted, and some lists offered
values the panel cannot use:

- Quota Debug could not be turned off: "False" is a non-empty text and
  counted as on.
- VM Clone Name Prefix showed as a True/False list, so no prefix could
  be typed, and touching it set the prefix to True.
- Disk SCSI Controller listed " lsilogic" with a space, never shown as
  chosen, and virtio-blk, which is no SCSI controller.
- VM Machine Type listed x86_64, an architecture; VM CD-ROM Device
  listed virtio, a bus a CD-ROM cannot use.
- Logs per Page and Disk Owner UID/GID are read with int(): a letter
  broke the logs page and VM create.

A migration fixes the lists and moves a value they no longer offer to
the default (the clone prefix keeps its text). A listed setting now
takes one of its choices, and every number setting a whole number in
its range, checked before it is saved.
This commit is contained in:
catborise 2026-10-25 21:47:11 +03:00
parent 9cf2d55b6e
commit 7392a5b4d2
7 changed files with 132 additions and 9 deletions

View file

@ -54,3 +54,32 @@ class AppSettingsTestCase(TestCase):
response = self.client.post(reverse("appsettings"), {"WORKER_CONCURRENCY": "0"})
self.assertEqual(AppSettings.objects.get(key="WORKER_CONCURRENCY").value, "4")
self.assertTrue(any("between 1 and 16" in str(m) for m in get_messages(response.wsgi_request)))
def post(self, key, value):
response = self.client.post(reverse("appsettings"), {key: value})
return [str(m) for m in get_messages(response.wsgi_request)]
def test_a_listed_setting_takes_only_its_choices(self):
messages = self.post("INSTANCE_FIRMWARE_DEFAULT_TYPE", "Coreboot")
self.assertEqual(AppSettings.objects.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value, "BIOS")
self.assertTrue(any("BIOS, UEFI" in m for m in messages), messages)
def test_number_settings_take_whole_numbers_in_their_range(self):
# read with int() elsewhere: a letter would break the logs page or VM create
for key, bad, good in (("LOGS_PER_PAGE", "abc", "50"), ("LOGS_PER_PAGE", "0", "1000"),
("INSTANCE_VOLUME_DEFAULT_OWNER_UID", "-1", "107"),
("INSTANCE_VOLUME_DEFAULT_OWNER_GID", "x", "4294967294"),
("LOGIN_FAILURE_LIMIT", "0", "10"), ("SNAPSHOT_FREE_SPACE_PERCENT", "101", "0")):
with self.subTest(key=key, bad=bad):
before = AppSettings.objects.get(key=key).value
self.assertTrue(any("whole number" in m for m in self.post(key, bad)))
self.assertEqual(AppSettings.objects.get(key=key).value, before)
self.post(key, good)
self.assertEqual(AppSettings.objects.get(key=key).value, good)
def test_the_clone_name_prefix_is_text(self):
self.post("CLONE_INSTANCE_DEFAULT_PREFIX", "web-")
self.assertEqual(AppSettings.objects.get(key="CLONE_INSTANCE_DEFAULT_PREFIX").value, "web-")
page = self.client.get(reverse("appsettings")).content.decode()
self.assertIn('name="CLONE_INSTANCE_DEFAULT_PREFIX" value="web-"', page)

View file

@ -61,3 +61,29 @@ class WorkerSettingsTestCase(TestCase):
limit = AppSettings._meta.get_field(field).max_length
if limit:
self.assertLessEqual(len(getattr(setting, field)), limit, f"{key} {field}")
choices_fix = importlib.import_module("appsettings.migrations.0020_fix_setting_choices")
class ChoicesFixTestCase(TestCase):
"""Choices that offered values the panel cannot use, and a text setting
that showed as a True/False list."""
def test_the_broken_choices_are_fixed_and_their_values_moved(self):
broken = {
"CLONE_INSTANCE_DEFAULT_PREFIX": ("instance", "True,False"),
"INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER": ("virtio-blk", "virtio-scsi, lsilogic, virtio-blk"),
"INSTANCE_MACHINE_DEFAULT_TYPE": ("x86_64", "q35,x86_64,virt"),
"INSTANCE_CDROM_ADD": ("virtio", "None,ide,sata,scsi,virtio"),
}
for key, (value, choices) in broken.items():
AppSettings.objects.filter(key=key).update(value=value, choices=choices)
choices_fix.fix_choices(apps, SimpleNamespace(connection=connection))
fixed = {s.key: (s.value, s.choices) for s in AppSettings.objects.filter(key__in=broken)}
self.assertEqual(fixed, {
"CLONE_INSTANCE_DEFAULT_PREFIX": ("instance", ""),
"INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER": ("virtio-scsi", "virtio-scsi,lsilogic"),
"INSTANCE_MACHINE_DEFAULT_TYPE": ("q35", "q35,pc,virt"),
"INSTANCE_CDROM_ADD": ("sata", "None,ide,sata,scsi"),
})