mirror of
https://github.com/ansible/awx.git
synced 2026-10-31 14:36:17 -02:30
AAP-90692 Nested POST /api/v2/inventories/{id}/hosts/ times out (#16657)
* Update query to use .contains
This commit is contained in:
+1
-1
@@ -728,7 +728,7 @@ class SubListCreateAttachDetachAPIView(SubListCreateAPIView):
|
|||||||
return Response(attach_errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(attach_errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
# Attach the object to the collection.
|
# Attach the object to the collection.
|
||||||
if sub not in relationship.all():
|
if not relationship.contains(sub):
|
||||||
relationship.add(sub)
|
relationship.add(sub)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ from django.core.exceptions import ValidationError
|
|||||||
|
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
from awx.main.models import InventorySource, Inventory, ActivityStream, Organization
|
from awx.main.models import InventorySource, Inventory, ActivityStream, Organization, Host
|
||||||
from awx.main.utils.inventory_vars import update_group_variables
|
from awx.main.utils.inventory_vars import update_group_variables
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
|
from django.test.utils import CaptureQueriesContext
|
||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def scm_inventory(inventory, project):
|
def scm_inventory(inventory, project):
|
||||||
@@ -118,6 +122,27 @@ def test_inventory_host_list_ordering(scm_inventory, get, admin_user):
|
|||||||
assert host_list == expected_ids
|
assert host_list == expected_ids
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_inventory_hosts_attach_uses_bounded_membership_check(inventory, post, admin_user):
|
||||||
|
"""attach()'s membership check must filter by the host's own pk and be LIMIT-bounded, not scan every host in the inventory."""
|
||||||
|
_now = now()
|
||||||
|
existing_hosts = [Host(name=f'existing-host-{i}', inventory=inventory, created=_now, modified=_now) for i in range(5)]
|
||||||
|
Host.objects.bulk_create(existing_hosts)
|
||||||
|
|
||||||
|
with CaptureQueriesContext(connection) as ctx:
|
||||||
|
post(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.id}), {'name': 'new-host'}, admin_user, expect=201)
|
||||||
|
|
||||||
|
membership_check_queries = [
|
||||||
|
q['sql']
|
||||||
|
for q in ctx.captured_queries
|
||||||
|
if 'FROM "main_host"' in q['sql'] and '"main_host"."inventory_id" = ' in q['sql'] and '"main_host"."name" = ' not in q['sql']
|
||||||
|
]
|
||||||
|
assert membership_check_queries, "expected a query checking host membership in the inventory"
|
||||||
|
for sql in membership_check_queries:
|
||||||
|
assert '"main_host"."id" = ' in sql, f"attach() membership check is not filtered by the host's own pk: {sql}"
|
||||||
|
assert 'LIMIT' in sql, f"attach() membership check is not LIMIT-bounded: {sql}"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_inventory_group_name_unique(scm_inventory, post, admin_user):
|
def test_inventory_group_name_unique(scm_inventory, post, admin_user):
|
||||||
inv_src = scm_inventory.inventory_sources.first()
|
inv_src = scm_inventory.inventory_sources.first()
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ def mock_organization():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def parent_relationship_factory(mocker):
|
def parent_relationship_factory(mocker):
|
||||||
def rf(serializer_class, relationship_name, relationship_value=mocker.Mock()):
|
def rf(serializer_class, relationship_name, relationship_value=mocker.Mock()):
|
||||||
mock_parent_relationship = mocker.MagicMock(**{'%s.add.return_value' % relationship_name: relationship_value})
|
mock_parent_relationship = mocker.MagicMock(
|
||||||
|
**{'%s.add.return_value' % relationship_name: relationship_value, '%s.contains.return_value' % relationship_name: False}
|
||||||
|
)
|
||||||
mocker.patch('awx.api.generics.ParentMixin.get_parent_object', return_value=mock_parent_relationship)
|
mocker.patch('awx.api.generics.ParentMixin.get_parent_object', return_value=mock_parent_relationship)
|
||||||
|
|
||||||
serializer = serializer_class()
|
serializer = serializer_class()
|
||||||
|
|||||||
Reference in New Issue
Block a user