mirror of
https://github.com/ansible/awx.git
synced 2026-05-22 16:27:42 -02:30
AC-984 Prevent signal handlers from being run unnecessarily when deleting inventory, remove unnecessary extra queries, use update_fields when possible.
This commit is contained in:
@@ -24,7 +24,7 @@ logger = logging.getLogger('awx.main.signals')
|
||||
# or marked inactive, when a Host-Group or Group-Group relationship is updated,
|
||||
# or when a Job is deleted or marked inactive.
|
||||
|
||||
_inventory_updating = threading.local()
|
||||
_inventory_updates = threading.local()
|
||||
|
||||
@contextlib.contextmanager
|
||||
def ignore_inventory_computed_fields():
|
||||
@@ -32,49 +32,62 @@ def ignore_inventory_computed_fields():
|
||||
Context manager to ignore updating inventory computed fields.
|
||||
'''
|
||||
try:
|
||||
previous_value = getattr(_inventory_updating, 'is_updating', False)
|
||||
_inventory_updating.is_updating = True
|
||||
previous_value = getattr(_inventory_updates, 'is_updating', False)
|
||||
_inventory_updates.is_updating = True
|
||||
yield
|
||||
finally:
|
||||
_inventory_updating.is_updating = previous_value
|
||||
_inventory_updates.is_updating = previous_value
|
||||
|
||||
@contextlib.contextmanager
|
||||
def ignore_inventory_group_removal():
|
||||
'''
|
||||
Context manager to ignore moving groups/hosts when group is deleted.
|
||||
'''
|
||||
try:
|
||||
previous_value = getattr(_inventory_updates, 'is_removing', False)
|
||||
_inventory_updates.is_removing = True
|
||||
yield
|
||||
finally:
|
||||
_inventory_updates.is_removing = previous_value
|
||||
|
||||
def update_inventory_computed_fields(sender, **kwargs):
|
||||
'''
|
||||
Signal handler and wrapper around inventory.update_computed_fields to
|
||||
prevent unnecessary recursive calls.
|
||||
'''
|
||||
if not getattr(_inventory_updating, 'is_updating', False):
|
||||
instance = kwargs['instance']
|
||||
if sender == Group.hosts.through:
|
||||
sender_name = 'group.hosts'
|
||||
elif sender == Group.parents.through:
|
||||
sender_name = 'group.parents'
|
||||
elif sender == Host.inventory_sources.through:
|
||||
sender_name = 'host.inventory_sources'
|
||||
elif sender == Group.inventory_sources.through:
|
||||
sender_name = 'group.inventory_sources'
|
||||
else:
|
||||
sender_name = unicode(sender._meta.verbose_name)
|
||||
if kwargs['signal'] == post_save:
|
||||
if sender == Job and instance.active:
|
||||
return
|
||||
sender_action = 'saved'
|
||||
elif kwargs['signal'] == post_delete:
|
||||
sender_action = 'deleted'
|
||||
elif kwargs['signal'] == m2m_changed and kwargs['action'] in ('post_add', 'post_remove', 'post_clear'):
|
||||
sender_action = 'changed'
|
||||
else:
|
||||
if getattr(_inventory_updates, 'is_updating', False):
|
||||
return
|
||||
instance = kwargs['instance']
|
||||
if sender == Group.hosts.through:
|
||||
sender_name = 'group.hosts'
|
||||
elif sender == Group.parents.through:
|
||||
sender_name = 'group.parents'
|
||||
elif sender == Host.inventory_sources.through:
|
||||
sender_name = 'host.inventory_sources'
|
||||
elif sender == Group.inventory_sources.through:
|
||||
sender_name = 'group.inventory_sources'
|
||||
else:
|
||||
sender_name = unicode(sender._meta.verbose_name)
|
||||
if kwargs['signal'] == post_save:
|
||||
if sender == Job and instance.active:
|
||||
return
|
||||
logger.debug('%s %s, updating inventory computed fields: %r %r',
|
||||
sender_name, sender_action, sender, kwargs)
|
||||
with ignore_inventory_computed_fields():
|
||||
try:
|
||||
inventory = instance.inventory
|
||||
except Inventory.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
update_hosts = issubclass(sender, Job)
|
||||
inventory.update_computed_fields(update_hosts=update_hosts)
|
||||
sender_action = 'saved'
|
||||
elif kwargs['signal'] == post_delete:
|
||||
sender_action = 'deleted'
|
||||
elif kwargs['signal'] == m2m_changed and kwargs['action'] in ('post_add', 'post_remove', 'post_clear'):
|
||||
sender_action = 'changed'
|
||||
else:
|
||||
return
|
||||
logger.debug('%s %s, updating inventory computed fields: %r %r',
|
||||
sender_name, sender_action, sender, kwargs)
|
||||
with ignore_inventory_computed_fields():
|
||||
try:
|
||||
inventory = instance.inventory
|
||||
except Inventory.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
update_hosts = issubclass(sender, Job)
|
||||
inventory.update_computed_fields(update_hosts=update_hosts)
|
||||
|
||||
post_save.connect(update_inventory_computed_fields, sender=Host)
|
||||
post_delete.connect(update_inventory_computed_fields, sender=Host)
|
||||
@@ -94,32 +107,50 @@ post_delete.connect(update_inventory_computed_fields, sender=InventorySource)
|
||||
|
||||
@receiver(pre_delete, sender=Group)
|
||||
def save_related_pks_before_group_delete(sender, **kwargs):
|
||||
if getattr(_inventory_updates, 'is_removing', False):
|
||||
return
|
||||
instance = kwargs['instance']
|
||||
instance._saved_inventory_pk = instance.inventory.pk
|
||||
instance._saved_parents_pks = set(instance.parents.values_list('pk', flat=True))
|
||||
instance._saved_hosts_pks = set(instance.hosts.values_list('pk', flat=True))
|
||||
instance._saved_children_pks = set(instance.children.values_list('pk', flat=True))
|
||||
|
||||
@receiver(post_delete, sender=Group)
|
||||
def migrate_children_from_deleted_group_to_parent_groups(sender, **kwargs):
|
||||
if getattr(_inventory_updates, 'is_removing', False):
|
||||
return
|
||||
instance = kwargs['instance']
|
||||
parents_pks = getattr(instance, '_saved_parents_pks', [])
|
||||
hosts_pks = getattr(instance, '_saved_hosts_pks', [])
|
||||
children_pks = getattr(instance, '_saved_children_pks', [])
|
||||
for parent_group in Group.objects.filter(pk__in=parents_pks):
|
||||
for child_host in Host.objects.filter(pk__in=hosts_pks):
|
||||
logger.debug('adding host %s to parent %s after group deletion',
|
||||
child_host, parent_group)
|
||||
parent_group.hosts.add(child_host)
|
||||
for child_group in Group.objects.filter(pk__in=children_pks):
|
||||
logger.debug('adding group %s to parent %s after group deletion',
|
||||
child_group, parent_group)
|
||||
parent_group.children.add(child_group)
|
||||
with ignore_inventory_group_removal():
|
||||
with ignore_inventory_computed_fields():
|
||||
if parents_pks:
|
||||
for parent_group in Group.objects.filter(pk__in=parents_pks, active=True):
|
||||
for child_host in Host.objects.filter(pk__in=hosts_pks, active=True):
|
||||
logger.debug('adding host %s to parent %s after group deletion',
|
||||
child_host, parent_group)
|
||||
parent_group.hosts.add(child_host)
|
||||
for child_group in Group.objects.filter(pk__in=children_pks, active=True):
|
||||
logger.debug('adding group %s to parent %s after group deletion',
|
||||
child_group, parent_group)
|
||||
parent_group.children.add(child_group)
|
||||
inventory_pk = getattr(instance, '_saved_inventory_pk', None)
|
||||
if inventory_pk:
|
||||
try:
|
||||
inventory = Inventory.objects.get(pk=inventory_pk, active=True)
|
||||
inventory.update_computed_fields()
|
||||
except Inventory.DoesNotExist:
|
||||
pass
|
||||
|
||||
@receiver(pre_save, sender=Group)
|
||||
def save_related_pks_before_group_marked_inactive(sender, **kwargs):
|
||||
if getattr(_inventory_updates, 'is_removing', False):
|
||||
return
|
||||
instance = kwargs['instance']
|
||||
if not instance.pk or instance.active:
|
||||
return
|
||||
instance._saved_inventory_pk = instance.inventory.pk
|
||||
instance._saved_parents_pks = set(instance.parents.values_list('pk', flat=True))
|
||||
instance._saved_hosts_pks = set(instance.hosts.values_list('pk', flat=True))
|
||||
instance._saved_children_pks = set(instance.children.values_list('pk', flat=True))
|
||||
@@ -127,26 +158,41 @@ def save_related_pks_before_group_marked_inactive(sender, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=Group)
|
||||
def migrate_children_from_inactive_group_to_parent_groups(sender, **kwargs):
|
||||
if getattr(_inventory_updates, 'is_removing', False):
|
||||
return
|
||||
instance = kwargs['instance']
|
||||
if instance.active:
|
||||
return
|
||||
parents_pks = getattr(instance, '_saved_parents_pks', [])
|
||||
hosts_pks = getattr(instance, '_saved_hosts_pks', [])
|
||||
children_pks = getattr(instance, '_saved_children_pks', [])
|
||||
for parent_group in Group.objects.filter(pk__in=parents_pks):
|
||||
for child_host in Host.objects.filter(pk__in=hosts_pks):
|
||||
logger.debug('moving host %s to parent %s after marking group %s inactive',
|
||||
child_host, parent_group, instance)
|
||||
parent_group.hosts.add(child_host)
|
||||
for child_group in Group.objects.filter(pk__in=children_pks):
|
||||
logger.debug('moving group %s to parent %s after marking group %s inactive',
|
||||
child_group, parent_group, instance)
|
||||
parent_group.children.add(child_group)
|
||||
parent_group.children.remove(instance)
|
||||
inventory_source_pk = getattr(instance, '_saved_inventory_source_pk', None)
|
||||
if inventory_source_pk:
|
||||
inventory_source = InventorySource.objects.get(pk=inventory_source_pk)
|
||||
inventory_source.mark_inactive()
|
||||
with ignore_inventory_group_removal():
|
||||
with ignore_inventory_computed_fields():
|
||||
if parents_pks:
|
||||
for parent_group in Group.objects.filter(pk__in=parents_pks, active=True):
|
||||
for child_host in Host.objects.filter(pk__in=hosts_pks, active=True):
|
||||
logger.debug('moving host %s to parent %s after marking group %s inactive',
|
||||
child_host, parent_group, instance)
|
||||
parent_group.hosts.add(child_host)
|
||||
for child_group in Group.objects.filter(pk__in=children_pks, active=True):
|
||||
logger.debug('moving group %s to parent %s after marking group %s inactive',
|
||||
child_group, parent_group, instance)
|
||||
parent_group.children.add(child_group)
|
||||
parent_group.children.remove(instance)
|
||||
inventory_source_pk = getattr(instance, '_saved_inventory_source_pk', None)
|
||||
if inventory_source_pk:
|
||||
try:
|
||||
inventory_source = InventorySource.objects.get(pk=inventory_source_pk, active=True)
|
||||
inventory_source.mark_inactive()
|
||||
except InventorySource.DoesNotExist:
|
||||
pass
|
||||
inventory_pk = getattr(instance, '_saved_inventory_pk', None)
|
||||
if inventory_pk:
|
||||
try:
|
||||
inventory = Inventory.objects.get(pk=inventory_pk, active=True)
|
||||
inventory.update_computed_fields()
|
||||
except Inventory.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Update host pointers to last_job and last_job_host_summary when a job is
|
||||
# marked inactive or deleted.
|
||||
|
||||
Reference in New Issue
Block a user