Signal optimizations

This commit is contained in:
Daniel Sheppard
2025-11-05 18:10:38 -06:00
parent 955c64b68c
commit 56673f4d88
+67 -77
View File
@@ -29,19 +29,7 @@ def update_children_depth(prefix):
Prefix.objects.bulk_update(children, ['_depth'], batch_size=100) Prefix.objects.bulk_update(children, ['_depth'], batch_size=100)
def update_object_prefix(prefix, delete=False, parent_model=Prefix, child_model=IPAddress): def update_object_prefix(prefix, child_model=IPAddress):
if delete:
# Get all possible addresses
addresses = child_model.objects.filter(prefix=prefix)
prefix = parent_model.objects.filter(
prefix__net_contains_or_equals=prefix.prefix,
vrf=prefix.vrf
).exclude(pk=prefix.pk).last()
for address in addresses:
# Set contained addresses to the containing prefix if it exists
address.prefix = prefix
else:
filter = Q(prefix=prefix) filter = Q(prefix=prefix)
if child_model == IPAddress: if child_model == IPAddress:
@@ -68,80 +56,85 @@ def update_object_prefix(prefix, delete=False, parent_model=Prefix, child_model=
child_model.objects.bulk_update(addresses, ['prefix'], batch_size=100) child_model.objects.bulk_update(addresses, ['prefix'], batch_size=100)
def delete_object_prefix(prefix, child_model, child_objects):
if not prefix.parent or prefix.vrf != prefix.parent.vrf:
# Prefix will be Set Null
return
# Set prefix to prefix parent
for address in child_objects:
address.prefix = prefix.parent
# Run a bulk update
child_model.objects.bulk_update(child_objects, ['prefix'], batch_size=100)
def update_ipaddress_prefix(prefix, delete=False): def update_ipaddress_prefix(prefix, delete=False):
update_object_prefix(prefix, delete, child_model=IPAddress) if delete:
delete_object_prefix(prefix, IPAddress, prefix.ip_addresses.all())
else:
update_object_prefix(prefix, child_model=IPAddress)
def update_iprange_prefix(prefix, delete=False): def update_iprange_prefix(prefix, delete=False):
update_object_prefix(prefix, delete, child_model=IPRange)
def update_prefix_parents(prefix, delete=False):
if delete: if delete:
# Get all possible addresses delete_object_prefix(prefix, IPRange, prefix.ip_ranges.all())
prefixes = prefix.children.all()
for pfx in prefixes:
# Set contained addresses to the containing prefix if it exists
pfx.parent = prefix.parent
else: else:
# Get all possible addresses update_object_prefix(prefix, child_model=IPRange)
prefixes = prefix.children.all() | Prefix.objects.filter(
Q(
def update_prefix_parents(prefix, delete=False, created=False):
if delete:
# Set prefix to prefix parent
prefixes = prefix.children.all()
for address in prefixes:
address.parent = prefix.parent
# Run a bulk update
Prefix.objects.bulk_update(prefixes, ['parent'], batch_size=100)
else:
# Build filter to get prefixes that will be impacted by this change:
# * Parent prefix is this prefixes parent, and;
# * Prefix is contained by this prefix, and;
# * Prefix is either within this VRF or there is no VRF and this prefix is a container prefix
filter = Q(
parent=prefix.parent, parent=prefix.parent,
vrf=prefix.vrf, vrf=prefix.vrf,
prefix__net_contained=str(prefix.prefix) prefix__net_contained=str(prefix.prefix)
) | Q( )
is_container = False
if prefix.status == PrefixStatusChoices.STATUS_CONTAINER and prefix.vrf is None:
is_container = True
filter |= Q(
parent=prefix.parent, parent=prefix.parent,
vrf=None, vrf=None,
status=PrefixStatusChoices.STATUS_CONTAINER,
prefix__net_contained=str(prefix.prefix), prefix__net_contained=str(prefix.prefix),
) )
)
if isinstance(prefix.prefix, str): # Get all impacted prefixes. Ensure we use distinct() to weed out duplicate prefixes from joins
prefix.prefix = IPNetwork(prefix.prefix) prefixes = Prefix.objects.filter(filter)
for pfx in prefixes: # Include children
if isinstance(pfx.prefix, str): if not created:
pfx.prefix = IPNetwork(pfx.prefix) prefixes |= prefix.children.all()
if pfx.parent == prefix and pfx.prefix.ip not in prefix.prefix: for pfx in prefixes.distinct():
# Find new parents for orphaned prefixes # Update parent criteria:
parent = Prefix.objects.exclude(pk=pfx.pk).filter( # * This prefix contains the child prefix, has a parent that is the prefixes parent and is "In-VRF"
Q( # * This prefix does not contain the child prefix
vrf=pfx.vrf, if pfx.vrf != prefix.vrf and not (prefix.vrf is None and is_container):
prefix__net_contains=str(pfx.prefix) # Prefix is contained but not in-VRF
) | Q( # print(f'{pfx} is no longer "in-VRF"')
vrf=None, pfx.parent = prefix.parent
status=PrefixStatusChoices.STATUS_CONTAINER, elif pfx.prefix in prefix.prefix and pfx.parent != prefix and pfx.parent == prefix.parent:
prefix__net_contains=str(pfx.prefix), # Prefix is in-scope
) # print(f'{pfx} is in {prefix}')
).last()
# Set contained addresses to the containing prefix if it exists
pfx.parent = parent
elif pfx.parent == prefix and pfx.vrf != prefix.vrf:
# Find new parents for orphaned prefixes
parent = Prefix.objects.exclude(pk=pfx.pk).filter(
Q(
vrf=pfx.vrf,
prefix__net_contains=str(pfx.prefix)
) | Q(
vrf=None,
status=PrefixStatusChoices.STATUS_CONTAINER,
prefix__net_contains=str(pfx.prefix),
)
).last()
# Set contained addresses to the containing prefix if it exists
pfx.parent = parent
elif pfx.parent != prefix and pfx.vrf == prefix.vrf and pfx.prefix in prefix.prefix:
# Set the parent to the prefix
pfx.parent = prefix pfx.parent = prefix
else: elif pfx.prefix not in prefix.prefix and pfx.parent == prefix:
# No-OP as the prefix does not require modification # Prefix has fallen out of scope
pass # print(f'{pfx} is not in {prefix}')
pfx.parent = prefix.parent
# Update the prefixes rows = Prefix.objects.bulk_update(prefixes, ['parent'], batch_size=100)
Prefix.objects.bulk_update(prefixes, ['parent'], batch_size=100) print(rows)
@receiver(post_save, sender=Prefix) @receiver(post_save, sender=Prefix)
@@ -152,7 +145,7 @@ def handle_prefix_saved(instance, created, **kwargs):
update_ipaddress_prefix(instance) update_ipaddress_prefix(instance)
update_iprange_prefix(instance) update_iprange_prefix(instance)
update_prefix_parents(instance) update_prefix_parents(instance, created=created)
update_parents_children(instance) update_parents_children(instance)
update_children_depth(instance) update_children_depth(instance)
@@ -165,8 +158,8 @@ def handle_prefix_saved(instance, created, **kwargs):
@receiver(pre_delete, sender=Prefix) @receiver(pre_delete, sender=Prefix)
def pre_handle_prefix_deleted(instance, **kwargs): def pre_handle_prefix_deleted(instance, **kwargs):
update_ipaddress_prefix(instance, True) update_ipaddress_prefix(instance, delete=True)
update_iprange_prefix(instance, True) update_iprange_prefix(instance, delete=True)
update_prefix_parents(instance, delete=True) update_prefix_parents(instance, delete=True)
@@ -175,9 +168,6 @@ def handle_prefix_deleted(instance, **kwargs):
update_parents_children(instance) update_parents_children(instance)
update_children_depth(instance) update_children_depth(instance)
update_ipaddress_prefix(instance, delete=True)
update_iprange_prefix(instance, delete=True)
update_prefix_parents(instance, delete=True)
@receiver(pre_delete, sender=IPAddress) @receiver(pre_delete, sender=IPAddress)