From 9295bf224371d4437e2ec038b497fe780ebcbc04 Mon Sep 17 00:00:00 2001 From: Vidya Nambiar Date: Fri, 25 Sep 2026 10:48:05 -0400 Subject: [PATCH] [AAP-86051] Wrap bulk host create in serializer persistence context Align BulkHostCreateSerializer with bulk job launch so validate() rejection logs are not duplicated by audit_bulk_model_instances when DAB dedupe requires serializer_mediated_persistence_context. Co-authored-by: Cursor --- awx/api/serializers.py | 4 ++++ .../test_validation_bypass_observability.py | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index be07520b5b..f4aab86136 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -2274,6 +2274,10 @@ class BulkHostCreateSerializer(serializers.Serializer): return attrs def create(self, validated_data): + with serializer_mediated_persistence_context(): + return self._create_bulk_hosts(validated_data) + + def _create_bulk_hosts(self, validated_data): # This assumes total_hosts is up to date, and it can get out of date if the inventory computed fields have not been updated lately. # If we wanted to side step this we could query Hosts.objects.filter(inventory...) old_total_hosts = validated_data['inventory'].total_hosts diff --git a/awx/main/tests/unit/utils/test_validation_bypass_observability.py b/awx/main/tests/unit/utils/test_validation_bypass_observability.py index a9704a2446..b01f69c1fd 100644 --- a/awx/main/tests/unit/utils/test_validation_bypass_observability.py +++ b/awx/main/tests/unit/utils/test_validation_bypass_observability.py @@ -37,6 +37,27 @@ def test_configure_validation_bypass_observability_wires_dab(mocker): assert 'awx.main.utils.db' in internal +@pytest.mark.django_db +def test_audit_bulk_model_instances_skips_host_description_when_serializer_already_logged(caplog): + from ansible_base.lib.utils.validation_signals import ( + get_validation_context_token, + register_serializer_validation_rejection, + reset_validation_context, + ) + + org = Organization.objects.create(name='org-bulk-host-dedupe') + inv = Inventory.objects.create(name='inv-bulk-host-dedupe', organization=org) + host = Host(name='host-bulk-dedupe', description='', inventory=inv) + register_serializer_validation_rejection('main.Host', 'description') + token = get_validation_context_token() + try: + with caplog.at_level(logging.WARNING, logger=LOGGER): + audit_bulk_model_instances([host], operation='bulk_create') + finally: + reset_validation_context(token) + assert 'ORM bypass' not in caplog.text + + @pytest.mark.django_db def test_audit_bulk_model_instances_logs_host_description_on_bulk_create(caplog): org = Organization.objects.create(name='org-bulk-host-audit')