1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-10 04:06:47 +00:00

feat(admin): list and remove the owners kept for vanished VMs

A VM that disappears from its compute keeps its owners in a tombstone
until INSTANCE_OWNERSHIP_RETENTION_DAYS pass, but nothing showed them.
Superusers now see them on the "Removed VMs" admin page (name, UUID,
owners, removed, expires) and can remove one, so a VM deleted on
purpose no longer hands its owners to a later VM with the same UUID.
This commit is contained in:
catborise 2026-10-08 19:07:02 +03:00
parent 71db69b294
commit 4ae3fb2d53
7 changed files with 157 additions and 0 deletions

View file

@ -1,3 +1,5 @@
from datetime import timedelta
from accounts.models import Instance, UserAttributes, UserInstance
from appsettings.settings import app_settings
from django.conf import settings
@ -10,6 +12,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_POST
from instances.models import InstanceTombstone
from logs.models import Logs
from . import forms
@ -210,6 +213,34 @@ def logs(request):
return render(request, "admin/logs.html", {"logs": logs})
@superuser_only
def tombstone_list(request):
"""The owners kept for VMs that vanished from their compute, in case the
same UUID comes back."""
tombstones = list(InstanceTombstone.objects.order_by("-removed"))
ids = {owner["user"] for tombstone in tombstones for owner in tombstone.owners}
names = dict(User.objects.filter(id__in=ids).values_list("id", "username"))
retention = timedelta(days=getattr(settings, "INSTANCE_OWNERSHIP_RETENTION_DAYS", 30))
for tombstone in tombstones:
tombstone.owner_names = [names.get(owner["user"], _("deleted user")) for owner in tombstone.owners]
tombstone.expires = tombstone.removed + retention
return render(request, "admin/tombstone_list.html", {"tombstones": tombstones})
@superuser_only
def tombstone_delete(request, pk):
tombstone = get_object_or_404(InstanceTombstone, pk=pk)
if request.method == "POST":
tombstone.delete()
return redirect("admin:tombstone_list")
return render(
request,
"common/confirm_delete.html",
{"object": tombstone},
)
def add_default_instances(user):
"""
Adds instances listed in NEW_USER_DEFAULT_INSTANCES to user