mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
# Generated by Django 4.2.30 on 2026-09-27 10:57
|
|
|
|
from django.db import migrations, models
|
|
|
|
|
|
def deduplicate_instances(apps, schema_editor):
|
|
Instance = apps.get_model('instances', 'Instance')
|
|
UserInstance = apps.get_model('accounts', 'UserInstance')
|
|
from django.db.models import Count, Q
|
|
import uuid as uuid_mod
|
|
|
|
# Assign distinct UUIDs to legacy/corrupt records with null, empty, or whitespace UUIDs
|
|
# so they are not treated as duplicates or collapsed together
|
|
empty_uuid_instances = Instance.objects.filter(
|
|
Q(uuid__isnull=True) | Q(uuid="") | Q(uuid__regex=r"^\s*$")
|
|
)
|
|
for inst in empty_uuid_instances:
|
|
inst.uuid = str(uuid_mod.uuid4())
|
|
inst.save(update_fields=['uuid'])
|
|
|
|
duplicates = (
|
|
Instance.objects.exclude(uuid__isnull=True).exclude(uuid="")
|
|
.values('compute_id', 'uuid')
|
|
.annotate(count=Count('id'))
|
|
.filter(count__gt=1)
|
|
)
|
|
for item in duplicates:
|
|
instances = list(Instance.objects.filter(
|
|
compute_id=item['compute_id'],
|
|
uuid=item['uuid']
|
|
).order_by('-id'))
|
|
primary = instances[0]
|
|
# Preserve is_template and non-default drbd across duplicate rows
|
|
merged_is_template = any(getattr(inst, 'is_template', False) for inst in instances)
|
|
non_default_drbd = next((inst.drbd for inst in instances if inst.drbd and inst.drbd != 'None'), None)
|
|
updated = False
|
|
if primary.is_template != merged_is_template:
|
|
primary.is_template = merged_is_template
|
|
updated = True
|
|
if non_default_drbd and primary.drbd != non_default_drbd:
|
|
primary.drbd = non_default_drbd
|
|
updated = True
|
|
if updated:
|
|
primary.save()
|
|
|
|
for dup in instances[1:]:
|
|
# Reassign or merge UserInstance relationships
|
|
for ui in UserInstance.objects.filter(instance=dup):
|
|
existing = UserInstance.objects.filter(instance=primary, user=ui.user).first()
|
|
if not existing:
|
|
ui.instance = primary
|
|
ui.save()
|
|
else:
|
|
# Merge permissions with logical OR so no stronger permission is lost
|
|
updated = False
|
|
if ui.is_change and not existing.is_change:
|
|
existing.is_change = True
|
|
updated = True
|
|
if ui.is_delete and not existing.is_delete:
|
|
existing.is_delete = True
|
|
updated = True
|
|
if ui.is_vnc and not existing.is_vnc:
|
|
existing.is_vnc = True
|
|
updated = True
|
|
if updated:
|
|
existing.save()
|
|
ui.delete()
|
|
dup.delete()
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
dependencies = [
|
|
('instances', '0011_createinstance_migrateinstance'),
|
|
('accounts', '0001_initial'),
|
|
]
|
|
|
|
operations = [
|
|
migrations.RunPython(deduplicate_instances, migrations.RunPython.noop),
|
|
migrations.AlterField(
|
|
model_name='flavor',
|
|
name='id',
|
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
|
),
|
|
migrations.AlterField(
|
|
model_name='instance',
|
|
name='id',
|
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='instance',
|
|
constraint=models.UniqueConstraint(fields=('compute', 'uuid'), name='unique_compute_uuid'),
|
|
),
|
|
]
|