Merge pull request #19443 from netbox-community/19440-migration-connections

Fixes #19440: Ensure data migrations use the correct database connection
This commit is contained in:
bctiemann 2025-05-12 14:13:31 -04:00 committed by GitHub
commit 8e13f2a9ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 197 additions and 131 deletions

View File

@ -8,10 +8,11 @@ def set_null_values(apps, schema_editor):
Circuit = apps.get_model('circuits', 'Circuit') Circuit = apps.get_model('circuits', 'Circuit')
CircuitGroupAssignment = apps.get_model('circuits', 'CircuitGroupAssignment') CircuitGroupAssignment = apps.get_model('circuits', 'CircuitGroupAssignment')
CircuitTermination = apps.get_model('circuits', 'CircuitTermination') CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
db_alias = schema_editor.connection.alias
Circuit.objects.filter(distance_unit='').update(distance_unit=None) Circuit.objects.using(db_alias).filter(distance_unit='').update(distance_unit=None)
CircuitGroupAssignment.objects.filter(priority='').update(priority=None) CircuitGroupAssignment.objects.using(db_alias).filter(priority='').update(priority=None)
CircuitTermination.objects.filter(cable_end='').update(cable_end=None) CircuitTermination.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -8,14 +8,15 @@ def copy_site_assignments(apps, schema_editor):
""" """
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
CircuitTermination = apps.get_model('circuits', 'CircuitTermination') CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
ProviderNetwork = apps.get_model('circuits', 'ProviderNetwork')
Site = apps.get_model('dcim', 'Site') Site = apps.get_model('dcim', 'Site')
db_alias = schema_editor.connection.alias
CircuitTermination.objects.filter(site__isnull=False).update( CircuitTermination.objects.using(db_alias).filter(site__isnull=False).update(
termination_type=ContentType.objects.get_for_model(Site), termination_id=models.F('site_id') termination_type=ContentType.objects.get_for_model(Site), termination_id=models.F('site_id')
) )
ProviderNetwork = apps.get_model('circuits', 'ProviderNetwork') CircuitTermination.objects.using(db_alias).filter(provider_network__isnull=False).update(
CircuitTermination.objects.filter(provider_network__isnull=False).update(
termination_type=ContentType.objects.get_for_model(ProviderNetwork), termination_type=ContentType.objects.get_for_model(ProviderNetwork),
termination_id=models.F('provider_network_id'), termination_id=models.F('provider_network_id'),
) )

View File

@ -7,15 +7,20 @@ def populate_denormalized_fields(apps, schema_editor):
Copy site ForeignKey values to the Termination GFK. Copy site ForeignKey values to the Termination GFK.
""" """
CircuitTermination = apps.get_model('circuits', 'CircuitTermination') CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
db_alias = schema_editor.connection.alias
terminations = CircuitTermination.objects.filter(site__isnull=False).prefetch_related('site') terminations = CircuitTermination.objects.using(db_alias).filter(site__isnull=False).prefetch_related('site')
for termination in terminations: for termination in terminations:
termination._region_id = termination.site.region_id termination._region_id = termination.site.region_id
termination._site_group_id = termination.site.group_id termination._site_group_id = termination.site.group_id
termination._site_id = termination.site_id termination._site_id = termination.site_id
# Note: Location cannot be set prior to migration # Note: Location cannot be set prior to migration
CircuitTermination.objects.bulk_update(terminations, ['_region', '_site_group', '_site'], batch_size=100) CircuitTermination.objects.using(db_alias).bulk_update(
terminations,
['_region', '_site_group', '_site'],
batch_size=100
)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -9,8 +9,9 @@ def set_member_type(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Circuit = apps.get_model('circuits', 'Circuit') Circuit = apps.get_model('circuits', 'Circuit')
CircuitGroupAssignment = apps.get_model('circuits', 'CircuitGroupAssignment') CircuitGroupAssignment = apps.get_model('circuits', 'CircuitGroupAssignment')
db_alias = schema_editor.connection.alias
CircuitGroupAssignment.objects.update( CircuitGroupAssignment.objects.using(db_alias).update(
member_type=ContentType.objects.get_for_model(Circuit) member_type=ContentType.objects.get_for_model(Circuit)
) )

View File

@ -26,49 +26,50 @@ def set_null_values(apps, schema_editor):
RackType = apps.get_model('dcim', 'RackType') RackType = apps.get_model('dcim', 'RackType')
RearPort = apps.get_model('dcim', 'RearPort') RearPort = apps.get_model('dcim', 'RearPort')
Site = apps.get_model('dcim', 'Site') Site = apps.get_model('dcim', 'Site')
db_alias = schema_editor.connection.alias
Cable.objects.filter(length_unit='').update(length_unit=None) Cable.objects.using(db_alias).filter(length_unit='').update(length_unit=None)
Cable.objects.filter(type='').update(type=None) Cable.objects.using(db_alias).filter(type='').update(type=None)
ConsolePort.objects.filter(cable_end='').update(cable_end=None) ConsolePort.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
ConsolePort.objects.filter(type='').update(type=None) ConsolePort.objects.using(db_alias).filter(type='').update(type=None)
ConsolePortTemplate.objects.filter(type='').update(type=None) ConsolePortTemplate.objects.using(db_alias).filter(type='').update(type=None)
ConsoleServerPort.objects.filter(cable_end='').update(cable_end=None) ConsoleServerPort.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
ConsoleServerPort.objects.filter(type='').update(type=None) ConsoleServerPort.objects.using(db_alias).filter(type='').update(type=None)
ConsoleServerPortTemplate.objects.filter(type='').update(type=None) ConsoleServerPortTemplate.objects.using(db_alias).filter(type='').update(type=None)
Device.objects.filter(airflow='').update(airflow=None) Device.objects.using(db_alias).filter(airflow='').update(airflow=None)
Device.objects.filter(face='').update(face=None) Device.objects.using(db_alias).filter(face='').update(face=None)
DeviceType.objects.filter(airflow='').update(airflow=None) DeviceType.objects.using(db_alias).filter(airflow='').update(airflow=None)
DeviceType.objects.filter(subdevice_role='').update(subdevice_role=None) DeviceType.objects.using(db_alias).filter(subdevice_role='').update(subdevice_role=None)
DeviceType.objects.filter(weight_unit='').update(weight_unit=None) DeviceType.objects.using(db_alias).filter(weight_unit='').update(weight_unit=None)
FrontPort.objects.filter(cable_end='').update(cable_end=None) FrontPort.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
Interface.objects.filter(cable_end='').update(cable_end=None) Interface.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
Interface.objects.filter(mode='').update(mode=None) Interface.objects.using(db_alias).filter(mode='').update(mode=None)
Interface.objects.filter(poe_mode='').update(poe_mode=None) Interface.objects.using(db_alias).filter(poe_mode='').update(poe_mode=None)
Interface.objects.filter(poe_type='').update(poe_type=None) Interface.objects.using(db_alias).filter(poe_type='').update(poe_type=None)
Interface.objects.filter(rf_channel='').update(rf_channel=None) Interface.objects.using(db_alias).filter(rf_channel='').update(rf_channel=None)
Interface.objects.filter(rf_role='').update(rf_role=None) Interface.objects.using(db_alias).filter(rf_role='').update(rf_role=None)
InterfaceTemplate.objects.filter(poe_mode='').update(poe_mode=None) InterfaceTemplate.objects.using(db_alias).filter(poe_mode='').update(poe_mode=None)
InterfaceTemplate.objects.filter(poe_type='').update(poe_type=None) InterfaceTemplate.objects.using(db_alias).filter(poe_type='').update(poe_type=None)
InterfaceTemplate.objects.filter(rf_role='').update(rf_role=None) InterfaceTemplate.objects.using(db_alias).filter(rf_role='').update(rf_role=None)
ModuleType.objects.filter(airflow='').update(airflow=None) ModuleType.objects.using(db_alias).filter(airflow='').update(airflow=None)
ModuleType.objects.filter(weight_unit='').update(weight_unit=None) ModuleType.objects.using(db_alias).filter(weight_unit='').update(weight_unit=None)
PowerFeed.objects.filter(cable_end='').update(cable_end=None) PowerFeed.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
PowerOutlet.objects.filter(cable_end='').update(cable_end=None) PowerOutlet.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
PowerOutlet.objects.filter(feed_leg='').update(feed_leg=None) PowerOutlet.objects.using(db_alias).filter(feed_leg='').update(feed_leg=None)
PowerOutlet.objects.filter(type='').update(type=None) PowerOutlet.objects.using(db_alias).filter(type='').update(type=None)
PowerOutletTemplate.objects.filter(feed_leg='').update(feed_leg=None) PowerOutletTemplate.objects.using(db_alias).filter(feed_leg='').update(feed_leg=None)
PowerOutletTemplate.objects.filter(type='').update(type=None) PowerOutletTemplate.objects.using(db_alias).filter(type='').update(type=None)
PowerPort.objects.filter(cable_end='').update(cable_end=None) PowerPort.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
PowerPort.objects.filter(type='').update(type=None) PowerPort.objects.using(db_alias).filter(type='').update(type=None)
PowerPortTemplate.objects.filter(type='').update(type=None) PowerPortTemplate.objects.using(db_alias).filter(type='').update(type=None)
Rack.objects.filter(airflow='').update(airflow=None) Rack.objects.using(db_alias).filter(airflow='').update(airflow=None)
Rack.objects.filter(form_factor='').update(form_factor=None) Rack.objects.using(db_alias).filter(form_factor='').update(form_factor=None)
Rack.objects.filter(outer_unit='').update(outer_unit=None) Rack.objects.using(db_alias).filter(outer_unit='').update(outer_unit=None)
Rack.objects.filter(weight_unit='').update(weight_unit=None) Rack.objects.using(db_alias).filter(weight_unit='').update(weight_unit=None)
RackType.objects.filter(outer_unit='').update(outer_unit=None) RackType.objects.using(db_alias).filter(outer_unit='').update(outer_unit=None)
RackType.objects.filter(weight_unit='').update(weight_unit=None) RackType.objects.using(db_alias).filter(weight_unit='').update(weight_unit=None)
RearPort.objects.filter(cable_end='').update(cable_end=None) RearPort.objects.using(db_alias).filter(cable_end='').update(cable_end=None)
Site.objects.filter(time_zone='').update(time_zone=None) Site.objects.using(db_alias).filter(time_zone='').update(time_zone=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -6,19 +6,26 @@ def populate_mac_addresses(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Interface = apps.get_model('dcim', 'Interface') Interface = apps.get_model('dcim', 'Interface')
MACAddress = apps.get_model('dcim', 'MACAddress') MACAddress = apps.get_model('dcim', 'MACAddress')
db_alias = schema_editor.connection.alias
interface_ct = ContentType.objects.get_for_model(Interface) interface_ct = ContentType.objects.get_for_model(Interface)
mac_addresses = [ mac_addresses = [
MACAddress( MACAddress(
mac_address=interface.mac_address, assigned_object_type=interface_ct, assigned_object_id=interface.pk mac_address=interface.mac_address,
assigned_object_type=interface_ct,
assigned_object_id=interface.pk
) )
for interface in Interface.objects.filter(mac_address__isnull=False) for interface in Interface.objects.filter(mac_address__isnull=False)
] ]
MACAddress.objects.bulk_create(mac_addresses, batch_size=100) MACAddress.objects.using(db_alias).bulk_create(mac_addresses, batch_size=100)
# TODO: Optimize interface updates # TODO: Optimize interface updates
for mac_address in mac_addresses: for mac_address in mac_addresses:
Interface.objects.filter(pk=mac_address.assigned_object_id).update(primary_mac_address=mac_address) Interface.objects.using(db_alias).filter(
pk=mac_address.assigned_object_id
).update(
primary_mac_address=mac_address
)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -11,6 +11,8 @@ def load_initial_data(apps, schema_editor):
Load initial ModuleTypeProfile objects from file. Load initial ModuleTypeProfile objects from file.
""" """
ModuleTypeProfile = apps.get_model('dcim', 'ModuleTypeProfile') ModuleTypeProfile = apps.get_model('dcim', 'ModuleTypeProfile')
db_alias = schema_editor.connection.alias
initial_profiles = ( initial_profiles = (
'cpu', 'cpu',
'fan', 'fan',
@ -25,7 +27,7 @@ def load_initial_data(apps, schema_editor):
with file_path.open('r') as f: with file_path.open('r') as f:
data = json.load(f) data = json.load(f)
try: try:
ModuleTypeProfile.objects.create(**data) ModuleTypeProfile.objects.using(db_alias).create(**data)
except Exception as e: except Exception as e:
print(f"Error loading data from {file_path}") print(f"Error loading data from {file_path}")
raise e raise e

View File

@ -4,11 +4,12 @@ from django.db import migrations
def convert_reportmodule_jobs(apps, schema_editor): def convert_reportmodule_jobs(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Job = apps.get_model('core', 'Job') Job = apps.get_model('core', 'Job')
db_alias = schema_editor.connection.alias
# Convert all ReportModule jobs to ScriptModule jobs # Convert all ReportModule jobs to ScriptModule jobs
if reportmodule_ct := ContentType.objects.filter(app_label='extras', model='reportmodule').first(): if reportmodule_ct := ContentType.objects.using(db_alias).filter(app_label='extras', model='reportmodule').first():
scriptmodule_ct = ContentType.objects.get(app_label='extras', model='scriptmodule') scriptmodule_ct = ContentType.objects.using(db_alias).get(app_label='extras', model='scriptmodule')
Job.objects.filter(object_type_id=reportmodule_ct.id).update(object_type_id=scriptmodule_ct.id) Job.objects.using(db_alias).filter(object_type_id=reportmodule_ct.id).update(object_type_id=scriptmodule_ct.id)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -88,24 +88,33 @@ def update_scripts(apps, schema_editor):
ScriptModule = apps.get_model('extras', 'ScriptModule') ScriptModule = apps.get_model('extras', 'ScriptModule')
ReportModule = apps.get_model('extras', 'ReportModule') ReportModule = apps.get_model('extras', 'ReportModule')
Job = apps.get_model('core', 'Job') Job = apps.get_model('core', 'Job')
db_alias = schema_editor.connection.alias
script_ct = ContentType.objects.get_for_model(Script, for_concrete_model=False) script_ct = ContentType.objects.get_for_model(Script, for_concrete_model=False)
scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule, for_concrete_model=False) scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule, for_concrete_model=False)
reportmodule_ct = ContentType.objects.get_for_model(ReportModule, for_concrete_model=False) reportmodule_ct = ContentType.objects.get_for_model(ReportModule, for_concrete_model=False)
for module in ScriptModule.objects.all(): for module in ScriptModule.objects.using(db_alias).all():
for script_name in get_module_scripts(module): for script_name in get_module_scripts(module):
script = Script.objects.create( script = Script.objects.using(db_alias).create(
name=script_name, name=script_name,
module=module, module=module,
) )
# Update all Jobs associated with this ScriptModule & script name to point to the new Script object # Update all Jobs associated with this ScriptModule & script name to point to the new Script object
Job.objects.filter(object_type_id=scriptmodule_ct.id, object_id=module.pk, name=script_name).update( Job.objects.using(db_alias).filter(
object_type_id=scriptmodule_ct.id,
object_id=module.pk,
name=script_name
).update(
object_type_id=script_ct.id, object_id=script.pk object_type_id=script_ct.id, object_id=script.pk
) )
# Update all Jobs associated with this ScriptModule & script name to point to the new Script object # Update all Jobs associated with this ScriptModule & script name to point to the new Script object
Job.objects.filter(object_type_id=reportmodule_ct.id, object_id=module.pk, name=script_name).update( Job.objects.using(db_alias).filter(
object_type_id=reportmodule_ct.id,
object_id=module.pk,
name=script_name
).update(
object_type_id=script_ct.id, object_id=script.pk object_type_id=script_ct.id, object_id=script.pk
) )
@ -119,16 +128,22 @@ def update_event_rules(apps, schema_editor):
Script = apps.get_model('extras', 'Script') Script = apps.get_model('extras', 'Script')
ScriptModule = apps.get_model('extras', 'ScriptModule') ScriptModule = apps.get_model('extras', 'ScriptModule')
EventRule = apps.get_model('extras', 'EventRule') EventRule = apps.get_model('extras', 'EventRule')
db_alias = schema_editor.connection.alias
script_ct = ContentType.objects.get_for_model(Script) script_ct = ContentType.objects.get_for_model(Script)
scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule) scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule)
for eventrule in EventRule.objects.filter(action_object_type=scriptmodule_ct): for eventrule in EventRule.objects.using(db_alias).filter(action_object_type=scriptmodule_ct):
name = eventrule.action_parameters.get('script_name') name = eventrule.action_parameters.get('script_name')
obj, __ = Script.objects.get_or_create( obj, __ = Script.objects.using(db_alias).get_or_create(
module_id=eventrule.action_object_id, name=name, defaults={'is_executable': False} module_id=eventrule.action_object_id,
name=name,
defaults={'is_executable': False}
)
EventRule.objects.using(db_alias).filter(pk=eventrule.pk).update(
action_object_type=script_ct,
action_object_id=obj.id
) )
EventRule.objects.filter(pk=eventrule.pk).update(action_object_type=script_ct, action_object_id=obj.id)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -1,12 +1,11 @@
# Generated by Django 5.0.4 on 2024-04-24 20:09
from django.db import migrations from django.db import migrations
def update_dashboard_widgets(apps, schema_editor): def update_dashboard_widgets(apps, schema_editor):
Dashboard = apps.get_model('extras', 'Dashboard') Dashboard = apps.get_model('extras', 'Dashboard')
db_alias = schema_editor.connection.alias
for dashboard in Dashboard.objects.all(): for dashboard in Dashboard.objects.using(db_alias).all():
for key, widget in dashboard.config.items(): for key, widget in dashboard.config.items():
if models := widget['config'].get('models'): if models := widget['config'].get('models'):
models = list(map(lambda x: x.replace('users.netboxgroup', 'users.group'), models)) models = list(map(lambda x: x.replace('users.netboxgroup', 'users.group'), models))

View File

@ -3,7 +3,9 @@ from django.db import migrations, models
def update_link_buttons(apps, schema_editor): def update_link_buttons(apps, schema_editor):
CustomLink = apps.get_model('extras', 'CustomLink') CustomLink = apps.get_model('extras', 'CustomLink')
CustomLink.objects.filter(button_class='outline-dark').update(button_class='default') db_alias = schema_editor.connection.alias
CustomLink.objects.using(db_alias).filter(button_class='outline-dark').update(button_class='default')
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -3,19 +3,21 @@ from django.db import migrations
def update_content_types(apps, schema_editor): def update_content_types(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
db_alias = schema_editor.connection.alias
# Delete the new ContentTypes effected by the new model in the core app # Delete the new ContentTypes effected by the new model in the core app
ContentType.objects.filter(app_label='core', model='objectchange').delete() ContentType.objects.using(db_alias).filter(app_label='core', model='objectchange').delete()
# Update the app labels of the original ContentTypes for extras.ObjectChange to ensure that any # Update the app labels of the original ContentTypes for extras.ObjectChange to ensure that any
# foreign key references are preserved # foreign key references are preserved
ContentType.objects.filter(app_label='extras', model='objectchange').update(app_label='core') ContentType.objects.using(db_alias).filter(app_label='extras', model='objectchange').update(app_label='core')
def update_dashboard_widgets(apps, schema_editor): def update_dashboard_widgets(apps, schema_editor):
Dashboard = apps.get_model('extras', 'Dashboard') Dashboard = apps.get_model('extras', 'Dashboard')
db_alias = schema_editor.connection.alias
for dashboard in Dashboard.objects.all(): for dashboard in Dashboard.objects.using(db_alias).all():
for key, widget in dashboard.config.items(): for key, widget in dashboard.config.items():
if widget['config'].get('model') == 'extras.objectchange': if widget['config'].get('model') == 'extras.objectchange':
widget['config']['model'] = 'core.objectchange' widget['config']['model'] = 'core.objectchange'

View File

@ -6,8 +6,9 @@ from core.events import *
def set_event_types(apps, schema_editor): def set_event_types(apps, schema_editor):
EventRule = apps.get_model('extras', 'EventRule') EventRule = apps.get_model('extras', 'EventRule')
event_rules = EventRule.objects.all() db_alias = schema_editor.connection.alias
event_rules = EventRule.objects.using(db_alias).all()
for event_rule in event_rules: for event_rule in event_rules:
event_rule.event_types = [] event_rule.event_types = []
if event_rule.type_create: if event_rule.type_create:

View File

@ -6,8 +6,9 @@ def set_null_values(apps, schema_editor):
Replace empty strings with null values. Replace empty strings with null values.
""" """
CustomFieldChoiceSet = apps.get_model('extras', 'CustomFieldChoiceSet') CustomFieldChoiceSet = apps.get_model('extras', 'CustomFieldChoiceSet')
db_alias = schema_editor.connection.alias
CustomFieldChoiceSet.objects.filter(base_choices='').update(base_choices=None) CustomFieldChoiceSet.objects.using(db_alias).filter(base_choices='').update(base_choices=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -8,7 +8,9 @@ def set_kind_default(apps, schema_editor):
Set kind to "info" on any entries with no kind assigned. Set kind to "info" on any entries with no kind assigned.
""" """
JournalEntry = apps.get_model('extras', 'JournalEntry') JournalEntry = apps.get_model('extras', 'JournalEntry')
JournalEntry.objects.filter(kind='').update(kind=JournalEntryKindChoices.KIND_INFO) db_alias = schema_editor.connection.alias
JournalEntry.objects.using(db_alias).filter(kind='').update(kind=JournalEntryKindChoices.KIND_INFO)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -11,7 +11,9 @@ def set_vid_ranges(apps, schema_editor):
Convert the min_vid & max_vid fields to a range in the new vid_ranges ArrayField. Convert the min_vid & max_vid fields to a range in the new vid_ranges ArrayField.
""" """
VLANGroup = apps.get_model('ipam', 'VLANGroup') VLANGroup = apps.get_model('ipam', 'VLANGroup')
for group in VLANGroup.objects.all(): db_alias = schema_editor.connection.alias
for group in VLANGroup.objects.using(db_alias).all():
group.vid_ranges = [NumericRange(group.min_vid, group.max_vid, bounds='[]')] group.vid_ranges = [NumericRange(group.min_vid, group.max_vid, bounds='[]')]
group._total_vlan_ids = group.max_vid - group.min_vid + 1 group._total_vlan_ids = group.max_vid - group.min_vid + 1
group.save() group.save()

View File

@ -9,9 +9,11 @@ def copy_site_assignments(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Prefix = apps.get_model('ipam', 'Prefix') Prefix = apps.get_model('ipam', 'Prefix')
Site = apps.get_model('dcim', 'Site') Site = apps.get_model('dcim', 'Site')
db_alias = schema_editor.connection.alias
Prefix.objects.filter(site__isnull=False).update( Prefix.objects.using(db_alias).filter(site__isnull=False).update(
scope_type=ContentType.objects.get_for_model(Site), scope_id=models.F('site_id') scope_type=ContentType.objects.get_for_model(Site),
scope_id=models.F('site_id')
) )

View File

@ -7,15 +7,16 @@ def populate_denormalized_fields(apps, schema_editor):
Copy site ForeignKey values to the scope GFK. Copy site ForeignKey values to the scope GFK.
""" """
Prefix = apps.get_model('ipam', 'Prefix') Prefix = apps.get_model('ipam', 'Prefix')
db_alias = schema_editor.connection.alias
prefixes = Prefix.objects.filter(site__isnull=False).prefetch_related('site') prefixes = Prefix.objects.using(db_alias).filter(site__isnull=False).prefetch_related('site')
for prefix in prefixes: for prefix in prefixes:
prefix._region_id = prefix.site.region_id prefix._region_id = prefix.site.region_id
prefix._site_group_id = prefix.site.group_id prefix._site_group_id = prefix.site.group_id
prefix._site_id = prefix.site_id prefix._site_id = prefix.site_id
# Note: Location cannot be set prior to migration # Note: Location cannot be set prior to migration
Prefix.objects.bulk_update(prefixes, ['_region', '_site_group', '_site'], batch_size=100) Prefix.objects.using(db_alias).bulk_update(prefixes, ['_region', '_site_group', '_site'], batch_size=100)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -7,9 +7,10 @@ def set_null_values(apps, schema_editor):
""" """
FHRPGroup = apps.get_model('ipam', 'FHRPGroup') FHRPGroup = apps.get_model('ipam', 'FHRPGroup')
IPAddress = apps.get_model('ipam', 'IPAddress') IPAddress = apps.get_model('ipam', 'IPAddress')
db_alias = schema_editor.connection.alias
FHRPGroup.objects.filter(auth_type='').update(auth_type=None) FHRPGroup.objects.using(db_alias).filter(auth_type='').update(auth_type=None)
IPAddress.objects.filter(role='').update(role=None) IPAddress.objects.using(db_alias).filter(role='').update(role=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -2,36 +2,38 @@ from django.db import migrations
from django.db.models import F from django.db.models import F
def populate_service_parent_gfk(apps, schema_config): def populate_service_parent_gfk(apps, schema_editor):
Service = apps.get_model('ipam', 'Service') Service = apps.get_model('ipam', 'Service')
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Device = apps.get_model('dcim', 'device') Device = apps.get_model('dcim', 'device')
VirtualMachine = apps.get_model('virtualization', 'virtualmachine') VirtualMachine = apps.get_model('virtualization', 'virtualmachine')
db_alias = schema_editor.connection.alias
Service.objects.filter(device_id__isnull=False).update( Service.objects.using(db_alias).filter(device_id__isnull=False).update(
parent_object_type=ContentType.objects.get_for_model(Device), parent_object_type=ContentType.objects.get_for_model(Device),
parent_object_id=F('device_id'), parent_object_id=F('device_id'),
) )
Service.objects.filter(virtual_machine_id__isnull=False).update( Service.objects.using(db_alias).filter(virtual_machine_id__isnull=False).update(
parent_object_type=ContentType.objects.get_for_model(VirtualMachine), parent_object_type=ContentType.objects.get_for_model(VirtualMachine),
parent_object_id=F('virtual_machine_id'), parent_object_id=F('virtual_machine_id'),
) )
def repopulate_device_and_virtualmachine_relations(apps, schemaconfig): def repopulate_device_and_virtualmachine_relations(apps, schema_editor):
Service = apps.get_model('ipam', 'Service') Service = apps.get_model('ipam', 'Service')
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Device = apps.get_model('dcim', 'device') Device = apps.get_model('dcim', 'device')
VirtualMachine = apps.get_model('virtualization', 'virtualmachine') VirtualMachine = apps.get_model('virtualization', 'virtualmachine')
db_alias = schema_editor.connection.alias
Service.objects.filter( Service.objects.using(db_alias).filter(
parent_object_type=ContentType.objects.get_for_model(Device), parent_object_type=ContentType.objects.get_for_model(Device),
).update( ).update(
device_id=F('parent_object_id') device_id=F('parent_object_id')
) )
Service.objects.filter( Service.objects.using(db_alias).filter(
parent_object_type=ContentType.objects.get_for_model(VirtualMachine), parent_object_type=ContentType.objects.get_for_model(VirtualMachine),
).update( ).update(
virtual_machine_id=F('parent_object_id') virtual_machine_id=F('parent_object_id')

View File

@ -6,8 +6,9 @@ def set_null_values(apps, schema_editor):
Replace empty strings with null values. Replace empty strings with null values.
""" """
ContactAssignment = apps.get_model('tenancy', 'ContactAssignment') ContactAssignment = apps.get_model('tenancy', 'ContactAssignment')
db_alias = schema_editor.connection.alias
ContactAssignment.objects.filter(priority='').update(priority=None) ContactAssignment.objects.using(db_alias).filter(priority='').update(priority=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -3,10 +3,10 @@ from django.db import migrations, models
def migrate_contact_groups(apps, schema_editor): def migrate_contact_groups(apps, schema_editor):
Contacts = apps.get_model('tenancy', 'Contact') Contact = apps.get_model('tenancy', 'Contact')
db_alias = schema_editor.connection.alias
qs = Contacts.objects.filter(group__isnull=False) for contact in Contact.objects.using(db_alias).filter(group__isnull=False):
for contact in qs:
contact.groups.add(contact.group) contact.groups.add(contact.group)

View File

@ -3,18 +3,22 @@ from django.db import migrations
def update_content_types(apps, schema_editor): def update_content_types(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
CustomField = apps.get_model('extras', 'CustomField')
db_alias = schema_editor.connection.alias
# Delete the new ContentTypes effected by the new models in the users app # Delete the new ContentTypes effected by the new models in the users app
ContentType.objects.filter(app_label='users', model='user').delete() ContentType.objects.using(db_alias).filter(app_label='users', model='user').delete()
# Update the app labels of the original ContentTypes for auth.User to ensure # Update the app labels of the original ContentTypes for auth.User to ensure
# that any foreign key references are preserved # that any foreign key references are preserved
ContentType.objects.filter(app_label='auth', model='user').update(app_label='users') ContentType.objects.using(db_alias).filter(app_label='auth', model='user').update(app_label='users')
netboxuser_ct = ContentType.objects.filter(app_label='users', model='netboxuser').first() netboxuser_ct = ContentType.objects.using(db_alias).filter(app_label='users', model='netboxuser').first()
if netboxuser_ct: if netboxuser_ct:
user_ct = ContentType.objects.filter(app_label='users', model='user').first() user_ct = ContentType.objects.using(db_alias).filter(app_label='users', model='user').first()
CustomField = apps.get_model('extras', 'CustomField') CustomField.objects.using(db_alias).filter(related_object_type_id=netboxuser_ct.id).update(
CustomField.objects.filter(related_object_type_id=netboxuser_ct.id).update(related_object_type_id=user_ct.id) related_object_type_id=user_ct.id
)
netboxuser_ct.delete() netboxuser_ct.delete()

View File

@ -9,10 +9,11 @@ def update_custom_fields(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
CustomField = apps.get_model('extras', 'CustomField') CustomField = apps.get_model('extras', 'CustomField')
Group = apps.get_model('users', 'Group') Group = apps.get_model('users', 'Group')
db_alias = schema_editor.connection.alias
if old_ct := ContentType.objects.filter(app_label='users', model='netboxgroup').first(): if old_ct := ContentType.objects.using(db_alias).filter(app_label='users', model='netboxgroup').first():
new_ct = ContentType.objects.get_for_model(Group) new_ct = ContentType.objects.get_for_model(Group)
CustomField.objects.filter(related_object_type=old_ct).update(related_object_type=new_ct) CustomField.objects.using(db_alias).filter(related_object_type=old_ct).update(related_object_type=new_ct)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -1,16 +1,15 @@
# Generated by Django 5.0.5 on 2024-05-15 18:05
from django.db import migrations, models from django.db import migrations, models
def update_content_types(apps, schema_editor): def update_content_types(apps, schema_editor):
ObjectType = apps.get_model('core', 'ObjectType') ObjectType = apps.get_model('core', 'ObjectType')
ObjectPermission = apps.get_model('users', 'ObjectPermission') ObjectPermission = apps.get_model('users', 'ObjectPermission')
db_alias = schema_editor.connection.alias
auth_group_ct = ObjectType.objects.filter(app_label='auth', model='group').first() auth_group_ct = ObjectType.objects.using(db_alias).filter(app_label='auth', model='group').first()
users_group_ct = ObjectType.objects.filter(app_label='users', model='group').first() users_group_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='group').first()
if auth_group_ct and users_group_ct: if auth_group_ct and users_group_ct:
perms = ObjectPermission.objects.filter(object_types__in=[auth_group_ct]) perms = ObjectPermission.objects.using(db_alias).filter(object_types__in=[auth_group_ct])
for perm in perms: for perm in perms:
perm.object_types.remove(auth_group_ct) perm.object_types.remove(auth_group_ct)
perm.object_types.add(users_group_ct) perm.object_types.add(users_group_ct)

View File

@ -4,18 +4,19 @@ from netbox.settings import DISK_BASE_UNIT
def convert_disk_size(apps, schema_editor): def convert_disk_size(apps, schema_editor):
VirtualMachine = apps.get_model('virtualization', 'VirtualMachine')
VirtualMachine.objects.filter(disk__isnull=False).update(disk=F('disk') * DISK_BASE_UNIT)
VirtualDisk = apps.get_model('virtualization', 'VirtualDisk') VirtualDisk = apps.get_model('virtualization', 'VirtualDisk')
VirtualDisk.objects.filter(size__isnull=False).update(size=F('size') * DISK_BASE_UNIT) VirtualMachine = apps.get_model('virtualization', 'VirtualMachine')
db_alias = schema_editor.connection.alias
VirtualMachine.objects.using(db_alias).filter(disk__isnull=False).update(disk=F('disk') * DISK_BASE_UNIT)
VirtualDisk.objects.using(db_alias).filter(size__isnull=False).update(size=F('size') * DISK_BASE_UNIT)
# Recalculate disk size on all VMs with virtual disks # Recalculate disk size on all VMs with virtual disks
id_list = VirtualDisk.objects.values_list('virtual_machine_id').distinct() id_list = VirtualDisk.objects.using(db_alias).values_list('virtual_machine_id').distinct()
virtual_machines = VirtualMachine.objects.filter(id__in=id_list) virtual_machines = VirtualMachine.objects.using(db_alias).filter(id__in=id_list)
for vm in virtual_machines: for vm in virtual_machines:
vm.disk = vm.virtualdisks.aggregate(Sum('size', default=0))['size__sum'] vm.disk = vm.virtualdisks.aggregate(Sum('size', default=0))['size__sum']
VirtualMachine.objects.bulk_update(virtual_machines, fields=['disk']) VirtualMachine.objects.using(db_alias).bulk_update(virtual_machines, fields=['disk'])
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -6,8 +6,9 @@ def set_null_values(apps, schema_editor):
Replace empty strings with null values. Replace empty strings with null values.
""" """
VMInterface = apps.get_model('virtualization', 'VMInterface') VMInterface = apps.get_model('virtualization', 'VMInterface')
db_alias = schema_editor.connection.alias
VMInterface.objects.filter(mode='').update(mode=None) VMInterface.objects.using(db_alias).filter(mode='').update(mode=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -9,9 +9,11 @@ def copy_site_assignments(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
Cluster = apps.get_model('virtualization', 'Cluster') Cluster = apps.get_model('virtualization', 'Cluster')
Site = apps.get_model('dcim', 'Site') Site = apps.get_model('dcim', 'Site')
db_alias = schema_editor.connection.alias
Cluster.objects.filter(site__isnull=False).update( Cluster.objects.using(db_alias).filter(site__isnull=False).update(
scope_type=ContentType.objects.get_for_model(Site), scope_id=models.F('site_id') scope_type=ContentType.objects.get_for_model(Site),
scope_id=models.F('site_id')
) )

View File

@ -7,15 +7,16 @@ def populate_denormalized_fields(apps, schema_editor):
Copy the denormalized fields for _region, _site_group and _site from existing site field. Copy the denormalized fields for _region, _site_group and _site from existing site field.
""" """
Cluster = apps.get_model('virtualization', 'Cluster') Cluster = apps.get_model('virtualization', 'Cluster')
db_alias = schema_editor.connection.alias
clusters = Cluster.objects.filter(site__isnull=False).prefetch_related('site') clusters = Cluster.objects.using(db_alias).filter(site__isnull=False).prefetch_related('site')
for cluster in clusters: for cluster in clusters:
cluster._region_id = cluster.site.region_id cluster._region_id = cluster.site.region_id
cluster._site_group_id = cluster.site.group_id cluster._site_group_id = cluster.site.group_id
cluster._site_id = cluster.site_id cluster._site_id = cluster.site_id
# Note: Location cannot be set prior to migration # Note: Location cannot be set prior to migration
Cluster.objects.bulk_update(clusters, ['_region', '_site_group', '_site'], batch_size=100) Cluster.objects.using(db_alias).bulk_update(clusters, ['_region', '_site_group', '_site'], batch_size=100)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -6,19 +6,24 @@ def populate_mac_addresses(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
VMInterface = apps.get_model('virtualization', 'VMInterface') VMInterface = apps.get_model('virtualization', 'VMInterface')
MACAddress = apps.get_model('dcim', 'MACAddress') MACAddress = apps.get_model('dcim', 'MACAddress')
db_alias = schema_editor.connection.alias
vminterface_ct = ContentType.objects.get_for_model(VMInterface) vminterface_ct = ContentType.objects.get_for_model(VMInterface)
mac_addresses = [ mac_addresses = [
MACAddress( MACAddress(
mac_address=vminterface.mac_address, assigned_object_type=vminterface_ct, assigned_object_id=vminterface.pk mac_address=vminterface.mac_address,
assigned_object_type=vminterface_ct,
assigned_object_id=vminterface.pk
) )
for vminterface in VMInterface.objects.filter(mac_address__isnull=False) for vminterface in VMInterface.objects.using(db_alias).filter(mac_address__isnull=False)
] ]
MACAddress.objects.bulk_create(mac_addresses, batch_size=100) MACAddress.objects.using(db_alias).bulk_create(mac_addresses, batch_size=100)
# TODO: Optimize interface updates # TODO: Optimize interface updates
for mac_address in mac_addresses: for mac_address in mac_addresses:
VMInterface.objects.filter(pk=mac_address.assigned_object_id).update(primary_mac_address=mac_address) VMInterface.objects.using(db_alias).filter(pk=mac_address.assigned_object_id).update(
primary_mac_address=mac_address
)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -8,11 +8,12 @@ def set_null_values(apps, schema_editor):
IKEPolicy = apps.get_model('vpn', 'IKEPolicy') IKEPolicy = apps.get_model('vpn', 'IKEPolicy')
IKEProposal = apps.get_model('vpn', 'IKEProposal') IKEProposal = apps.get_model('vpn', 'IKEProposal')
IPSecProposal = apps.get_model('vpn', 'IPSecProposal') IPSecProposal = apps.get_model('vpn', 'IPSecProposal')
db_alias = schema_editor.connection.alias
IKEPolicy.objects.filter(mode='').update(mode=None) IKEPolicy.objects.using(db_alias).filter(mode='').update(mode=None)
IKEProposal.objects.filter(authentication_algorithm='').update(authentication_algorithm=None) IKEProposal.objects.using(db_alias).filter(authentication_algorithm='').update(authentication_algorithm=None)
IPSecProposal.objects.filter(authentication_algorithm='').update(authentication_algorithm=None) IPSecProposal.objects.using(db_alias).filter(authentication_algorithm='').update(authentication_algorithm=None)
IPSecProposal.objects.filter(encryption_algorithm='').update(encryption_algorithm=None) IPSecProposal.objects.using(db_alias).filter(encryption_algorithm='').update(encryption_algorithm=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -7,12 +7,13 @@ def set_null_values(apps, schema_editor):
""" """
WirelessLAN = apps.get_model('wireless', 'WirelessLAN') WirelessLAN = apps.get_model('wireless', 'WirelessLAN')
WirelessLink = apps.get_model('wireless', 'WirelessLink') WirelessLink = apps.get_model('wireless', 'WirelessLink')
db_alias = schema_editor.connection.alias
WirelessLAN.objects.filter(auth_cipher='').update(auth_cipher=None) WirelessLAN.objects.using(db_alias).filter(auth_cipher='').update(auth_cipher=None)
WirelessLAN.objects.filter(auth_type='').update(auth_type=None) WirelessLAN.objects.using(db_alias).filter(auth_type='').update(auth_type=None)
WirelessLink.objects.filter(auth_cipher='').update(auth_cipher=None) WirelessLink.objects.using(db_alias).filter(auth_cipher='').update(auth_cipher=None)
WirelessLink.objects.filter(auth_type='').update(auth_type=None) WirelessLink.objects.using(db_alias).filter(auth_type='').update(auth_type=None)
WirelessLink.objects.filter(distance_unit='').update(distance_unit=None) WirelessLink.objects.using(db_alias).filter(distance_unit='').update(distance_unit=None)
class Migration(migrations.Migration): class Migration(migrations.Migration):