From ff2182524f363c8cb0740282aa5c37ff82458f5c Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 5 Nov 2026 16:02:50 +0300 Subject: [PATCH] fix(api): a VM create without mac or nwfilter is accepted and runs The API's create serializer leaves mac and nwfilter optional, but the job's normalize gave them no default: without mac the request ended in an HTML 500 (KeyError), without nwfilter it was queued and failed in the worker. Both now default to empty, as the web form sends them. --- instances/jobs.py | 3 ++- instances/tests/test_create_job.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/instances/jobs.py b/instances/jobs.py index b654d267..76c5b320 100644 --- a/instances/jobs.py +++ b/instances/jobs.py @@ -738,7 +738,8 @@ class CreateInstance(Kind): def normalize(self, raw): # what the API leaves out means what create_instance did by default params = {"template": "", "images": "", "firmware": "", "net_model": "virtio", "add_cdrom": "sata", - "add_input": "default", "meta_prealloc": False, "hdd_size": 0, "cloud_init": False, "tpm": False} + "add_input": "default", "meta_prealloc": False, "hdd_size": 0, "cloud_init": False, "tpm": False, + "mac": "", "nwfilter": ""} params.update({k: v for k, v in raw.items() if k not in ("submission_key", "create", "csrfmiddlewaretoken")}) params.update(compute=int(raw["compute"]), devices=[list(d) for d in raw.get("devices", [])]) if params["firmware"] == "UEFI Secure Boot" and "q35" not in params["machine"]: diff --git a/instances/tests/test_create_job.py b/instances/tests/test_create_job.py index 46d7ebea..1b44dd5f 100644 --- a/instances/tests/test_create_job.py +++ b/instances/tests/test_create_job.py @@ -131,3 +131,15 @@ class CreateJobTestCase(TransactionTestCase): op.user.save() with self.assertRaises(PermissionDenied): CreateInstance().precheck(op, None) + + def test_the_api_takes_a_body_without_a_mac_or_a_network_filter(self): + body = {k: v for k, v in BODY.items() if k not in ("mac", "nwfilter")} + response = self.client.post(f"/api/v1/computes/{self.compute.pk}/instances/create/x86_64/q35/", body, + content_type="application/json") + self.assertEqual(response.status_code, 202) + op = Operation.objects.get() + acquire("wvc-test:1:a", "wvc-test") + Operation.objects.filter(pk=op.pk).update(state=Operation.RUNNING, worker="wvc-test:1:a") + op.refresh_from_db() + CreateInstance().run(op, Context(op, SimpleNamespace(identity="wvc-test:1:a"))) + self.assertEqual(self.conn.create_instance.call_args.kwargs["nwfilter"], "")