mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
fix(instances): the new-VM host dialog says when no compute is reachable
The dialog looped over every compute and skipped the unreachable ones, so its "No compute is reachable." message showed only when there were no computes at all. With hosts that were all offline it was an empty list. The index view now gives the dialog the reachable computes, and the template lists those, so the message covers that case. Fixes #176 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c6e07a467
commit
4f0ae3b30d
3 changed files with 58 additions and 28 deletions
|
|
@ -15,37 +15,35 @@
|
|||
{% include "create_steps.html" with step=1 %}
|
||||
<div class="text-body-secondary mb-3">{% trans "Choose the host the VM runs on." %}</div>
|
||||
<div class="list-group">
|
||||
{% for compute in computes %}
|
||||
{% if compute.status is True %}
|
||||
<a class="list-group-item list-group-item-action py-3" href="{% url 'instances:create_instance_select_type' compute.id %}">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-12 col-md-3 fw-semibold">{{ compute.name }}</div>
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="small text-body-secondary">{% trans "CPU" %} · {{ compute.cpu_count }} vCPU</div>
|
||||
<div class="cpu-usage d-flex align-items-center gap-2" data-url="{% url 'compute_graph' compute.id %}">
|
||||
<div class="progress flex-grow-1" role="progressbar" aria-label="{% blocktrans with name=compute.name %}CPU usage of {{ name }}{% endblocktrans %}"
|
||||
aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar" style="width: 0%"></div>
|
||||
</div>
|
||||
<small class="cpu-usage-value"></small>
|
||||
{% for compute in reachable_computes %}
|
||||
<a class="list-group-item list-group-item-action py-3" href="{% url 'instances:create_instance_select_type' compute.id %}">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-12 col-md-3 fw-semibold">{{ compute.name }}</div>
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="small text-body-secondary">{% trans "CPU" %} · {{ compute.cpu_count }} vCPU</div>
|
||||
<div class="cpu-usage d-flex align-items-center gap-2" data-url="{% url 'compute_graph' compute.id %}">
|
||||
<div class="progress flex-grow-1" role="progressbar" aria-label="{% blocktrans with name=compute.name %}CPU usage of {{ name }}{% endblocktrans %}"
|
||||
aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar" style="width: 0%"></div>
|
||||
</div>
|
||||
<small class="cpu-usage-value"></small>
|
||||
</div>
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="small text-body-secondary">{% trans "Memory" %} · {{ compute.ram_size|filesizeformat }}</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="progress flex-grow-1" role="progressbar" aria-label="{% blocktrans with name=compute.name %}Memory usage of {{ name }}{% endblocktrans %}"
|
||||
aria-valuenow="{{ compute.ram_usage }}" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar" style="width: {{ compute.ram_usage }}%"></div>
|
||||
</div>
|
||||
<small>{{ compute.ram_usage }}%</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 d-none d-md-block text-end" aria-hidden="true">{% bs_icon 'chevron-right' %}</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="small text-body-secondary">{% trans "Memory" %} · {{ compute.ram_size|filesizeformat }}</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="progress flex-grow-1" role="progressbar" aria-label="{% blocktrans with name=compute.name %}Memory usage of {{ name }}{% endblocktrans %}"
|
||||
aria-valuenow="{{ compute.ram_usage }}" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar" style="width: {{ compute.ram_usage }}%"></div>
|
||||
</div>
|
||||
<small>{{ compute.ram_usage }}%</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 d-none d-md-block text-end" aria-hidden="true">{% bs_icon 'chevron-right' %}</div>
|
||||
</div>
|
||||
</a>
|
||||
{% empty %}
|
||||
<p>{% trans "No compute is reachable." %}</p>
|
||||
<p>{% trans "No compute is reachable." %}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -112,3 +112,34 @@ class CreateDialogCpuTestCase(TestCase):
|
|||
# the earlier opening's answer (99) is ignored; a failed read is a dash
|
||||
self.assertEqual(result["final"], [["42%", "42", "42%"], ["0%", None, "—"], ["0%", None, "…"]])
|
||||
self.assertEqual(result["all"], urls[:2] + urls + urls)
|
||||
|
||||
|
||||
class CreateDialogHostsTestCase(TestCase):
|
||||
"""The dialog lists the reachable computes; without one it says so."""
|
||||
|
||||
def setUp(self):
|
||||
self.client.force_login(get_user_model().objects.create_superuser("cd-admin", "cd@example.com", "pw"))
|
||||
for i in (1, 2):
|
||||
Compute.objects.create(name=f"cd{i}", hostname=f"192.0.2.{i}", login="u", password="p", type=1)
|
||||
for name, value in (("cpu_count", 1), ("ram_size", 1024), ("ram_usage", 0)):
|
||||
p = patch.object(Compute, name, new_callable=PropertyMock, return_value=value)
|
||||
p.start()
|
||||
self.addCleanup(p.stop)
|
||||
p = patch("instances.views.utils.refr")
|
||||
p.start()
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def dialog(self, reachable):
|
||||
with patch.object(Compute, "status", property(lambda compute: compute.name in reachable)):
|
||||
response = self.client.get(reverse("instances:index"))
|
||||
return html.fromstring(response.content).get_element_by_id("AddInstance")
|
||||
|
||||
def test_only_reachable_computes_are_listed(self):
|
||||
dialog = self.dialog({"cd2"})
|
||||
self.assertEqual([e.text for e in dialog.xpath(".//a/div/div[1]")], ["cd2"])
|
||||
self.assertNotIn("No compute is reachable.", dialog.text_content())
|
||||
|
||||
def test_no_reachable_compute_is_said(self):
|
||||
dialog = self.dialog(set())
|
||||
self.assertEqual(dialog.xpath(".//a"), [])
|
||||
self.assertIn("No compute is reachable.", dialog.text_content())
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ def index(request):
|
|||
return render(
|
||||
request,
|
||||
"allinstances.html",
|
||||
{"computes": computes, "instances": instances, "show_hosts": show_hosts, "own_hosts_down": own_hosts_down},
|
||||
{"computes": computes, "instances": instances, "show_hosts": show_hosts, "own_hosts_down": own_hosts_down,
|
||||
"reachable_computes": [c for c in computes if c.status is True]},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue