1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 19:56:48 +00:00

fix(computes): a deleted compute's VMs keep their owners

Deleting a compute removed its VMs from the panel together with their
owners, while the VMs kept running on the host: added again, the host's
VMs came back with no owners. A compute's delete now treats each VM as
one that left its compute: its owners follow the same UUID on another
compute or wait in a tombstone for the retention period. One function,
forget(), does this for the refresh and for the delete; the API's
compute delete goes through the same model delete.

The delete holds the compute exclusive and locks its row before its
VMs', as the reconcile does: a reconcile, VM operation or job on the
compute makes it busy instead of losing owners to a concurrent restore
or deadlocking with it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
catborise 2026-10-22 11:49:42 +03:00
parent fbe93d9aee
commit 2dee5ba41c
7 changed files with 92 additions and 14 deletions

View file

@ -62,6 +62,19 @@ def _move_ownership(source, target):
target.save(update_fields=["is_template"])
def forget(inst):
"""Remove an instance whose VM its compute no longer lists, or whose
compute is deleted. Its ownership goes to the same UUID on another
compute (an out-of-band move) or is kept in a tombstone in case the VM
comes back."""
elsewhere = Instance.objects.filter(uuid=inst.uuid).exclude(compute_id=inst.compute_id).first()
if elsewhere:
_move_ownership(inst, elsewhere)
else:
_bury(inst)
inst.delete()
def _bury(inst):
owners = [
{"user": ui.user_id, "is_change": ui.is_change, "is_delete": ui.is_delete, "is_vnc": ui.is_vnc}
@ -165,17 +178,10 @@ def refresh_instance_database(compute):
inst.name = new_name
inst.save(update_fields=["name"])
# 2. Instances gone from this compute. Their ownership goes to the
# same UUID on another compute (an out-of-band move) or is kept
# in a tombstone in case the VM comes back.
# 2. Instances gone from this compute
for inst in db_instances:
if inst.uuid not in host_domains:
elsewhere = Instance.objects.filter(uuid=inst.uuid).exclude(compute=compute).first()
if elsewhere:
_move_ownership(inst, elsewhere)
else:
_bury(inst)
inst.delete()
forget(inst)
# 3. Instances created out-of-band. A UUID that also exists on another
# compute is a copy and gets no owners; otherwise a tombstone's