# 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'), ), ]