diff --git a/admin/templates/admin/group_list.html b/admin/templates/admin/group_list.html
index 7d56d1ab..43b52320 100644
--- a/admin/templates/admin/group_list.html
+++ b/admin/templates/admin/group_list.html
@@ -26,8 +26,8 @@
- | {% trans "Group Name" %} |
- {% trans "Actions" %} |
+ {% trans "Group Name" %} |
+ {% trans "Actions" %} |
diff --git a/admin/templates/admin/tombstone_list.html b/admin/templates/admin/tombstone_list.html
index 48328576..f5ba1d2b 100644
--- a/admin/templates/admin/tombstone_list.html
+++ b/admin/templates/admin/tombstone_list.html
@@ -24,12 +24,13 @@
- | {% trans "Name" %} |
- {% trans "UUID" %} |
- {% trans "Owners" %} |
- {% trans "Removed" %} |
- {% trans "Expires" %} |
- {% trans "Actions" %} |
+ {% trans "Name" %} |
+ {% trans "UUID" %} |
+ {% trans "Host" %} |
+ {% trans "Owners" %} |
+ {% trans "Removed" %} |
+ {% trans "Expires" %} |
+ {% trans "Actions" %} |
@@ -40,6 +41,7 @@
{% if tombstone.is_template %}{% trans "Template" %}{% endif %}
{{ tombstone.uuid }} |
+ {{ tombstone.host }} |
{{ tombstone.owner_names|join:", " }} |
{{ tombstone.removed|date:"Y-m-d H:i" }} |
{{ tombstone.expires|date:"Y-m-d H:i" }} |
diff --git a/admin/templates/admin/user_list.html b/admin/templates/admin/user_list.html
index c1ca7afb..59c4f171 100644
--- a/admin/templates/admin/user_list.html
+++ b/admin/templates/admin/user_list.html
@@ -29,14 +29,14 @@
- | {% trans "Username" %} |
- {% trans "Status" %} |
- {% trans "Last Login" %} |
- {% trans "Template editor" %} |
- {% trans "Superuser" %} |
- {% trans "Can Clone" %} |
- {% trans "API tokens" %} |
- {% trans "Actions" %} |
+ {% trans "Username" %} |
+ {% trans "Status" %} |
+ {% trans "Last Login" %} |
+ {% trans "Template editor" %} |
+ {% trans "Superuser" %} |
+ {% trans "Can Clone" %} |
+ {% trans "API tokens" %} |
+ {% trans "Actions" %} |
diff --git a/admin/tests/test_tombstones.py b/admin/tests/test_tombstones.py
index 23d49ad1..f1a1aef5 100644
--- a/admin/tests/test_tombstones.py
+++ b/admin/tests/test_tombstones.py
@@ -19,6 +19,7 @@ class TombstoneTests(TestCase):
self.tombstone = InstanceTombstone.objects.create(
uuid=UUID,
name="ts-vm",
+ host="ts-host",
owners=[
{"user": self.owner.id, "is_change": True, "is_delete": False, "is_vnc": True},
{"user": 999999, "is_change": False, "is_delete": False, "is_vnc": False},
@@ -37,6 +38,8 @@ class TombstoneTests(TestCase):
self.assertContains(response, "ts-vm")
self.assertContains(response, UUID)
self.assertContains(response, "ts-owner")
+ self.assertContains(response, "ts-host | ", html=True)
+ self.assertContains(response, 'Host | ', html=True)
def test_only_superusers_see_or_remove_them(self):
self.client.force_login(self.owner)
@@ -51,6 +54,7 @@ class TombstoneTests(TestCase):
self.assertTrue(InstanceTombstone.objects.exists())
def test_a_post_removes_it(self):
- response = self.client.post(reverse("admin:tombstone_delete", args=[self.tombstone.pk]))
+ response = self.client.post(reverse("admin:tombstone_delete", args=[self.tombstone.pk]), follow=True)
self.assertRedirects(response, reverse("admin:tombstone_list"))
+ self.assertContains(response, "Removed VM ts-vm deleted")
self.assertFalse(InstanceTombstone.objects.exists())
diff --git a/admin/views.py b/admin/views.py
index bc244100..51e8ef41 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -338,6 +338,7 @@ def tombstone_delete(request, pk):
if request.method == "POST":
with audit(request, None, f"Removed VM {tombstone.name} ({tombstone.uuid})", "delete"):
tombstone.delete()
+ messages.success(request, _("Removed VM %(name)s deleted") % {"name": tombstone.name})
return redirect("admin:tombstone_list")
return render(
diff --git a/computes/tests/test_ownership.py b/computes/tests/test_ownership.py
index 849c0f8a..78c5bc3d 100644
--- a/computes/tests/test_ownership.py
+++ b/computes/tests/test_ownership.py
@@ -142,7 +142,8 @@ class OwnershipTestCase(TestCase):
def test_a_host_added_again_gets_its_vms_back_with_their_owners(self):
self.owned_vm(self.host_a)
self.delete(self.host_a)
- self.assertEqual(InstanceTombstone.objects.get().owners[0]["user"], self.owner.id)
+ tombstone = InstanceTombstone.objects.get()
+ self.assertEqual((tombstone.owners[0]["user"], tombstone.host), (self.owner.id, "host-a"))
self.assertEqual(self.rows(), [
("cd-admin", "-", "Login"),
("-", "host-a", f"VM vm ({UUID}): owners kept on the Removed VMs page"),
diff --git a/computes/utils.py b/computes/utils.py
index 7c3db362..5938018e 100644
--- a/computes/utils.py
+++ b/computes/utils.py
@@ -100,7 +100,8 @@ def _bury(inst):
for ui in UserInstance.objects.filter(instance=inst)
]
if owners or inst.is_template:
- InstanceTombstone.objects.create(uuid=inst.uuid, name=inst.name, is_template=inst.is_template, owners=owners)
+ InstanceTombstone.objects.create(uuid=inst.uuid, name=inst.name, host=inst.compute.name,
+ is_template=inst.is_template, owners=owners)
_log(inst, "owners kept on the Removed VMs page")
else:
_log(inst, "left the panel (no owners)")
diff --git a/instances/migrations/0014_instancetombstone_host.py b/instances/migrations/0014_instancetombstone_host.py
new file mode 100644
index 00000000..3347ac01
--- /dev/null
+++ b/instances/migrations/0014_instancetombstone_host.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.2.18 on 2026-10-26 08:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('instances', '0013_instancetombstone'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='instancetombstone',
+ name='host',
+ field=models.CharField(blank=True, max_length=64),
+ ),
+ ]
diff --git a/instances/models.py b/instances/models.py
index a025893e..02c5083c 100644
--- a/instances/models.py
+++ b/instances/models.py
@@ -398,6 +398,7 @@ class InstanceTombstone(models.Model):
uuid = models.CharField(max_length=36, db_index=True)
name = models.CharField(max_length=120)
+ host = models.CharField(max_length=64, blank=True) # the compute's name: the compute may be deleted
is_template = models.BooleanField(default=False)
owners = models.JSONField(default=list) # [{"user": id, "is_change": .., "is_delete": .., "is_vnc": ..}]
removed = models.DateTimeField(auto_now_add=True)