Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ascender/main/management/commands/inventory_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,9 @@ def _relink_orphaned_job_host_summaries(self):
for offset in range(0, len(host_names), self._batch_size):
batch_names = host_names[offset : offset + self._batch_size]
orphaned = JobHostSummary.objects.filter(job__inventory=self.inventory, host_name__in=batch_names, **null_filter)
for host_name in batch_names:
# Only issue an UPDATE for names that actually have orphans
names_with_orphans = set(orphaned.order_by().values_list('host_name', flat=True).distinct())
for host_name in names_with_orphans:
host_pk = host_map.get(host_name)
if host_pk:
updated = orphaned.filter(host_name=host_name).update(**{fk_field: host_pk})
Expand Down
39 changes: 39 additions & 0 deletions ascender/main/tests/functional/commands/test_inventory_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,3 +591,42 @@ def test_relink_does_not_cross_inventories(self, organization):

summary = JobHostSummary.objects.get(job=job_b, host_name='server1')
assert summary.host_id is None, "Summary from inv_b should not be re-linked to inv_a's host"

def test_relink_only_updates_hosts_with_orphans(self, inventory):
from django.db import connection
from django.test.utils import CaptureQueriesContext
from ascender.main.models import JobHostSummary, Job, Project, JobTemplate

project = Project.objects.create(name='test-proj')
jt = JobTemplate.objects.create(name='test-jt', inventory=inventory, project=project)
hosts = [Host.objects.create(name=f'server{i}', inventory=inventory) for i in range(5)]
job = Job.objects.create(inventory=inventory, job_template=jt, status='successful')
JobHostSummary.objects.create(job=job, host=None, host_name='server3', ok=1)

cmd = inventory_import.Command()
cmd.inventory = inventory
cmd._batch_size = 2
with CaptureQueriesContext(connection) as ctx:
cmd._relink_orphaned_job_host_summaries()

updates = [q['sql'] for q in ctx.captured_queries if q['sql'].startswith('UPDATE "main_jobhostsummary"')]
assert len(updates) == 1
# One lookup per batch of names: 5 hosts in batches of 2
selects = [q['sql'] for q in ctx.captured_queries if q['sql'].startswith('SELECT DISTINCT "main_jobhostsummary"."host_name"')]
assert len(selects) == 3
assert JobHostSummary.objects.get(job=job, host_name='server3').host_id == hosts[3].pk

def test_relink_issues_no_updates_without_orphans(self, inventory):
from django.db import connection
from django.test.utils import CaptureQueriesContext

for i in range(5):
Host.objects.create(name=f'server{i}', inventory=inventory)

cmd = inventory_import.Command()
cmd.inventory = inventory
cmd._batch_size = 2
with CaptureQueriesContext(connection) as ctx:
cmd._relink_orphaned_job_host_summaries()

assert not [q for q in ctx.captured_queries if q['sql'].startswith('UPDATE')]
Loading