diff --git a/instances/models.py b/instances/models.py index 91370ce9..a840a3df 100644 --- a/instances/models.py +++ b/instances/models.py @@ -161,6 +161,16 @@ class Instance(models.Model): net["target"] = live_targets.get(net["mac"], "") return networks + @cached_property + def pcie_slots(self) -> tuple[int, int] | None: + """(PCIe slots, free ones) the VM has now; None: not a PCIe machine.""" + return self.proxy.get_pcie_slots() + + @cached_property + def config_pcie_slots(self) -> tuple[int, int] | None: + """The same at its next start, which added slots wait for while it runs.""" + return self.proxy.get_pcie_slots(config=True) + @cached_property def config_disks(self) -> list[dict]: """Disks of the persistent definition, which the disk list, its edit diff --git a/instances/templates/instances/settings_tab.html b/instances/templates/instances/settings_tab.html index db38abaa..26c576fb 100644 --- a/instances/templates/instances/settings_tab.html +++ b/instances/templates/instances/settings_tab.html @@ -274,6 +274,21 @@ {% endfor %} + {% if instance.pcie_slots %} + {# a PCIe machine gives each virtio disk and network device a slot; a running VM gets no new one #} + {% with total=instance.pcie_slots.0 free=instance.pcie_slots.1 next=instance.config_pcie_slots %} +
+ + {% blocktrans %}PCIe slots: {{ free }} free of {{ total }}{% endblocktrans %}{% if next and next.1 != free %} · {% blocktrans with next_free=next.1 %}{{ next_free }} free from the next start{% endblocktrans %}{% endif %} + + {% if request.user.is_superuser %} +
{% csrf_token %} + +
+ {% endif %} +
+ {% endwith %} + {% endif %}
diff --git a/instances/tests/test_pci_slots.py b/instances/tests/test_pci_slots.py index 0efeac87..32a30739 100644 --- a/instances/tests/test_pci_slots.py +++ b/instances/tests/test_pci_slots.py @@ -102,3 +102,82 @@ class NoPciSlotTests(TestCase): NO_SLOT) self.assertEqual(len(texts), 1) self.assertIn("shut it down", texts[0]) + + +DOMAIN = """ + +
+
+
+
+
+