From 4dd72766cf4d3867f9a123910b7068331ade26b8 Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 4 Nov 2026 21:24:25 +0300 Subject: [PATCH] perf: a VM's owners' SSH keys in one query The VM's keys page (instances:sshkeys) and the cloud-init user data collected the owners' keys with one query an owner. Both now read them in one query joined over the VM's owners, ordered owner by owner as before. --- datasource/tests/test_datasource.py | 16 ++++++++++++++++ datasource/views.py | 7 ++++--- instances/views.py | 10 +++------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/datasource/tests/test_datasource.py b/datasource/tests/test_datasource.py index f72239ea..ae3e7ff8 100644 --- a/datasource/tests/test_datasource.py +++ b/datasource/tests/test_datasource.py @@ -90,6 +90,22 @@ class CloudInitTestCase(TestCase): def test_owner_keys_for_a_unique_name(self): self.assertIn(self.KEY, self.userdata()) + def test_every_owner_s_keys_and_no_one_else_s(self): + second_key, stranger_key = (f"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI{who} {who}@example" for who in ("Second", "Stranger")) + second = get_user_model().objects.create_user("ci_second", password="pw") + UserSSHKey.objects.create(user=second, keyname="k", keypublic=second_key) + UserInstance.objects.create(instance=self.vm, user=second) + stranger = get_user_model().objects.create_user("ci_stranger", password="pw") + UserSSHKey.objects.create(user=stranger, keyname="k", keypublic=stranger_key) + other_vm = Instance.objects.create(compute=self.compute, name="web2", uuid="11111111-2222-3333-4444-999999999993") + UserInstance.objects.create(instance=other_vm, user=stranger) + UserInstance.objects.create(instance=other_vm, user=self.owner) + + page = self.userdata() + self.assertLess(page.index(self.KEY), page.index(second_key)) + self.assertEqual(page.count(self.KEY), 1) + self.assertNotIn(stranger_key, page) + def test_no_keys_when_the_name_is_taken_twice(self): other = Compute.objects.create(name="ci-b", hostname="b.example", login="", password="", type=4) Instance.objects.create(compute=other, name="web1", uuid="11111111-2222-3333-4444-999999999992") diff --git a/datasource/views.py b/datasource/views.py index 45618515..9309c67c 100644 --- a/datasource/views.py +++ b/datasource/views.py @@ -1,7 +1,7 @@ import json import socket -from accounts.models import UserInstance, UserSSHKey +from accounts.models import UserSSHKey from computes.models import Compute from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied @@ -65,8 +65,9 @@ def os_userdata(request, version): # into the other VM by naming theirs the same. No keys then. instances = list(Instance.objects.filter(name=hostname.split(".")[0])[:2]) if hostname else [] if len(instances) == 1: - for ui in UserInstance.objects.filter(instance=instances[0]): - instance_keys += UserSSHKey.objects.filter(user=ui.user).values_list("keypublic", flat=True) + # the keys of the VM's owners, owner by owner + instance_keys = list(UserSSHKey.objects.filter(user__userinstance__instance=instances[0]) + .order_by("user__userinstance__id", "id").values_list("keypublic", flat=True)) # quoted, so a comment such as "it's: mine" stays one YAML string instance_keys = [json.dumps(key) for key in instance_keys] diff --git a/instances/views.py b/instances/views.py index a039af04..70df142e 100755 --- a/instances/views.py +++ b/instances/views.py @@ -530,13 +530,9 @@ def sshkeys(request, pk): :return: """ instance = get_instance(request.user, pk) - instance_keys = [] - userinstances = UserInstance.objects.filter(instance=instance) - - for ui in userinstances: - keys = UserSSHKey.objects.filter(user=ui.user) - for k in keys: - instance_keys.append(k.keypublic) + # the keys of the VM's owners, owner by owner + instance_keys = list(UserSSHKey.objects.filter(user__userinstance__instance=instance) + .order_by("user__userinstance__id", "id").values_list("keypublic", flat=True)) if request.GET.get("plain", ""): response = "\n".join(instance_keys) response += "\n"