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

fix(reconciliation): implement UUID-based domain reconciliation and connection safety

This commit is contained in:
catborise 2026-09-27 13:13:43 +03:00
parent dbef70131b
commit 3f8eeb04bd
3 changed files with 198 additions and 25 deletions

View file

@ -1,17 +1,64 @@
import logging
from django.db import transaction
from instances.models import Instance
logger = logging.getLogger(__name__)
def refresh_instance_database(compute):
domains = compute.proxy.wvm.listAllDomains()
domain_names = [d.name() for d in domains]
domain_uuids = [d.UUIDString() for d in domains]
# Delete instances that're not on host from DB
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
Instance.objects.filter(compute=compute).exclude(uuid__in=domain_uuids).delete()
# Create instances that're on host but not in DB
names = Instance.objects.filter(compute=compute).values_list("name", flat=True)
for domain in domains:
if domain.name() not in names:
Instance(
compute=compute, name=domain.name(), uuid=domain.UUIDString()
).save()
"""
Synchronizes the WebVirtCloud database with libvirt domain state.
Libvirt is the single source of truth:
- VMs removed in virt-manager/virsh are deleted from the database.
- VMs created in virt-manager/virsh are added to the database.
- VMs renamed in virt-manager/virsh have their name updated without losing
UserInstance permission relationships (matched by UUID).
- If libvirt is unreachable (connection/network error), the database is left
untouched to avoid false deletions.
"""
try:
if hasattr(compute, "status") and compute.status is False:
return
domains = compute.proxy.wvm.listAllDomains()
except Exception as e:
logger.warning(
"Failed to retrieve domains from compute %s (%s): %s",
getattr(compute, "name", compute),
getattr(compute, "hostname", ""),
e,
)
return
# Map libvirt UUIDs to current domain names
host_domains = {}
for d in domains:
try:
host_domains[d.UUIDString()] = d.name()
except Exception as e:
logger.warning(
"Error reading domain metadata from compute %s: %s",
getattr(compute, "name", compute),
e,
)
# If we fail to read a domain's metadata, abort sync to prevent accidental deletion
return
db_instances = Instance.objects.filter(compute=compute)
db_uuids = set(db_instances.values_list("uuid", flat=True))
with transaction.atomic():
# 1. Update name for any VM whose name changed out-of-band in virsh/virt-manager
for inst in db_instances:
if inst.uuid in host_domains:
new_name = host_domains[inst.uuid]
if inst.name != new_name:
inst.name = new_name
inst.save(update_fields=["name"])
# 2. Delete instances that were genuinely undefined/deleted in virsh/virt-manager
db_instances.exclude(uuid__in=host_domains.keys()).delete()
# 3. Create new instances that were created out-of-band in virsh/virt-manager
for uuid, name in host_domains.items():
if uuid not in db_uuids:
Instance.objects.create(compute=compute, name=name, uuid=uuid)