mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-13 16:47:34 -06:00
* Initial work on ObjectChange data migrations * Fix migration bug * Add migrators for MAC address assignments * Update reverting kwarg; allow pop() to fail * Cross-reference MAC address migrators * Split migrator logic across migrations * Add missing migrator
This commit is contained in:
parent
bd8cf64ded
commit
179c06ec20
@ -1,4 +1,5 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -49,3 +50,26 @@ class Migration(migrations.Migration):
|
|||||||
# Copy over existing site assignments
|
# Copy over existing site assignments
|
||||||
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_circuittermination_termination(objectchange, reverting):
|
||||||
|
site_ct = ContentType.objects.get_by_natural_key('dcim', 'site').pk
|
||||||
|
provider_network_ct = ContentType.objects.get_by_natural_key('circuits', 'providernetwork').pk
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if site_id := data.get('site'):
|
||||||
|
data.update({
|
||||||
|
'termination_type': site_ct,
|
||||||
|
'termination_id': site_id,
|
||||||
|
})
|
||||||
|
elif provider_network_id := data.get('provider_network'):
|
||||||
|
data.update({
|
||||||
|
'termination_type': provider_network_ct,
|
||||||
|
'termination_id': provider_network_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'circuits.circuittermination': oc_circuittermination_termination,
|
||||||
|
}
|
||||||
|
@ -86,3 +86,15 @@ class Migration(migrations.Migration):
|
|||||||
new_name='_provider_network',
|
new_name='_provider_network',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_circuittermination_remove_fields(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is not None:
|
||||||
|
data.pop('site', None)
|
||||||
|
data.pop('provider_network', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'circuits.circuittermination': oc_circuittermination_remove_fields,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -82,3 +83,21 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_circuitgroupassignment_member(objectchange, reverting):
|
||||||
|
circuit_ct = ContentType.objects.get_by_natural_key('circuits', 'circuit').pk
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if circuit_id := data.get('circuit'):
|
||||||
|
data.update({
|
||||||
|
'member_type': circuit_ct,
|
||||||
|
'member_id': circuit_id,
|
||||||
|
})
|
||||||
|
data.pop('circuit', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'circuits.circuitgroupassignment': oc_circuitgroupassignment_member,
|
||||||
|
}
|
||||||
|
@ -100,3 +100,16 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_rename_type(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if 'type' in data:
|
||||||
|
data['form_factor'] = data.pop('type')
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'dcim.rack': oc_rename_type,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.apps import apps
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ def populate_mac_addresses(apps, schema_editor):
|
|||||||
assigned_object_type=interface_ct,
|
assigned_object_type=interface_ct,
|
||||||
assigned_object_id=interface.pk
|
assigned_object_id=interface.pk
|
||||||
)
|
)
|
||||||
for interface in Interface.objects.filter(mac_address__isnull=False)
|
for interface in Interface.objects.using(db_alias).filter(mac_address__isnull=False)
|
||||||
]
|
]
|
||||||
MACAddress.objects.using(db_alias).bulk_create(mac_addresses, batch_size=100)
|
MACAddress.objects.using(db_alias).bulk_create(mac_addresses, batch_size=100)
|
||||||
|
|
||||||
@ -51,3 +53,43 @@ class Migration(migrations.Migration):
|
|||||||
name='mac_address',
|
name='mac_address',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# See peer migrator in virtualization.0048_populate_mac_addresses before making changes
|
||||||
|
def oc_interface_primary_mac_address(objectchange, reverting):
|
||||||
|
MACAddress = apps.get_model('dcim', 'MACAddress')
|
||||||
|
interface_ct = ContentType.objects.get_by_natural_key('dcim', 'interface')
|
||||||
|
|
||||||
|
# Swap data order if the change is being reverted
|
||||||
|
if not reverting:
|
||||||
|
before, after = objectchange.prechange_data, objectchange.postchange_data
|
||||||
|
else:
|
||||||
|
before, after = objectchange.postchange_data, objectchange.prechange_data
|
||||||
|
|
||||||
|
if after.get('mac_address') != before.get('mac_address'):
|
||||||
|
# Create & assign the new MACAddress (if any)
|
||||||
|
if after.get('mac_address'):
|
||||||
|
mac = MACAddress.objects.create(
|
||||||
|
mac_address=after['mac_address'],
|
||||||
|
assigned_object_type=interface_ct,
|
||||||
|
assigned_object_id=objectchange.changed_object_id,
|
||||||
|
)
|
||||||
|
after['primary_mac_address'] = mac.pk
|
||||||
|
else:
|
||||||
|
after['primary_mac_address'] = None
|
||||||
|
# Delete the old MACAddress (if any)
|
||||||
|
if before.get('mac_address'):
|
||||||
|
MACAddress.objects.filter(
|
||||||
|
mac_address=before['mac_address'],
|
||||||
|
assigned_object_type=interface_ct,
|
||||||
|
assigned_object_id=objectchange.changed_object_id,
|
||||||
|
).delete()
|
||||||
|
before['primary_mac_address'] = None
|
||||||
|
|
||||||
|
before.pop('mac_address', None)
|
||||||
|
after.pop('mac_address', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'dcim.interface': oc_interface_primary_mac_address,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -44,3 +45,20 @@ class Migration(migrations.Migration):
|
|||||||
# Copy over existing site assignments
|
# Copy over existing site assignments
|
||||||
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_prefix_scope(objectchange, reverting):
|
||||||
|
site_ct = ContentType.objects.get_by_natural_key('dcim', 'site').pk
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if site_id := data.get('site'):
|
||||||
|
data.update({
|
||||||
|
'scope_type': site_ct,
|
||||||
|
'scope_id': site_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'ipam.prefix': oc_prefix_scope,
|
||||||
|
}
|
||||||
|
@ -60,3 +60,14 @@ class Migration(migrations.Migration):
|
|||||||
name='site',
|
name='site',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_prefix_remove_fields(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is not None:
|
||||||
|
data.pop('site', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'ipam.prefix': oc_prefix_remove_fields,
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
|
|
||||||
@ -54,3 +55,26 @@ class Migration(migrations.Migration):
|
|||||||
reverse_code=repopulate_device_and_virtualmachine_relations,
|
reverse_code=repopulate_device_and_virtualmachine_relations,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_service_parent(objectchange, reverting):
|
||||||
|
device_ct = ContentType.objects.get_by_natural_key('dcim', 'device').pk
|
||||||
|
virtual_machine_ct = ContentType.objects.get_by_natural_key('virtualization', 'virtualmachine').pk
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if device_id := data.get('device'):
|
||||||
|
data.update({
|
||||||
|
'parent_object_type': device_ct,
|
||||||
|
'parent_object_id': device_id,
|
||||||
|
})
|
||||||
|
elif virtual_machine_id := data.get('virtual_machine'):
|
||||||
|
data.update({
|
||||||
|
'parent_object_type': virtual_machine_ct,
|
||||||
|
'parent_object_id': virtual_machine_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'ipam.service': oc_service_parent,
|
||||||
|
}
|
||||||
|
@ -37,3 +37,15 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_service_remove_fields(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is not None:
|
||||||
|
data.pop('device', None)
|
||||||
|
data.pop('virtual_machine', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'ipam.service': oc_service_remove_fields,
|
||||||
|
}
|
||||||
|
@ -66,3 +66,17 @@ class Migration(migrations.Migration):
|
|||||||
name='group',
|
name='group',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_contact_groups(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
# Set the M2M field `groups` to a list containing the group ID
|
||||||
|
data['groups'] = [data['group']] if data.get('group') else []
|
||||||
|
data.pop('group', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'tenancy.contact': oc_contact_groups,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -43,3 +44,20 @@ class Migration(migrations.Migration):
|
|||||||
# Copy over existing site assignments
|
# Copy over existing site assignments
|
||||||
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_cluster_scope(objectchange, reverting):
|
||||||
|
site_ct = ContentType.objects.get_by_natural_key('dcim', 'site').pk
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is None:
|
||||||
|
continue
|
||||||
|
if site_id := data.get('site'):
|
||||||
|
data.update({
|
||||||
|
'scope_type': site_ct,
|
||||||
|
'scope_id': site_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'virtualization.cluster': oc_cluster_scope,
|
||||||
|
}
|
||||||
|
@ -87,3 +87,14 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def oc_cluster_remove_site(objectchange, reverting):
|
||||||
|
for data in (objectchange.prechange_data, objectchange.postchange_data):
|
||||||
|
if data is not None:
|
||||||
|
data.pop('site', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'virtualization.cluster': oc_cluster_remove_site,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.apps import apps
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -50,3 +52,43 @@ class Migration(migrations.Migration):
|
|||||||
name='mac_address',
|
name='mac_address',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# See peer migrator in dcim.0200_populate_mac_addresses before making changes
|
||||||
|
def oc_vminterface_primary_mac_address(objectchange, reverting):
|
||||||
|
MACAddress = apps.get_model('dcim', 'MACAddress')
|
||||||
|
vminterface_ct = ContentType.objects.get_by_natural_key('virtualization', 'vminterface')
|
||||||
|
|
||||||
|
# Swap data order if the change is being reverted
|
||||||
|
if not reverting:
|
||||||
|
before, after = objectchange.prechange_data, objectchange.postchange_data
|
||||||
|
else:
|
||||||
|
before, after = objectchange.postchange_data, objectchange.prechange_data
|
||||||
|
|
||||||
|
if after.get('mac_address') != before.get('mac_address'):
|
||||||
|
# Create & assign the new MACAddress (if any)
|
||||||
|
if after.get('mac_address'):
|
||||||
|
mac = MACAddress.objects.create(
|
||||||
|
mac_address=after['mac_address'],
|
||||||
|
assigned_object_type=vminterface_ct,
|
||||||
|
assigned_object_id=objectchange.changed_object_id,
|
||||||
|
)
|
||||||
|
after['primary_mac_address'] = mac.pk
|
||||||
|
else:
|
||||||
|
after['primary_mac_address'] = None
|
||||||
|
# Delete the old MACAddress (if any)
|
||||||
|
if before.get('mac_address'):
|
||||||
|
MACAddress.objects.filter(
|
||||||
|
mac_address=before['mac_address'],
|
||||||
|
assigned_object_type=vminterface_ct,
|
||||||
|
assigned_object_id=objectchange.changed_object_id,
|
||||||
|
).delete()
|
||||||
|
before['primary_mac_address'] = None
|
||||||
|
|
||||||
|
before.pop('mac_address', None)
|
||||||
|
after.pop('mac_address', None)
|
||||||
|
|
||||||
|
|
||||||
|
objectchange_migrators = {
|
||||||
|
'virtualization.vminterface': oc_vminterface_primary_mac_address,
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user