[AAP-74343] Skip host query scanning when indirect counting flag is off

The indirect_instance_count callback plugin now checks AWX_COLLECT_HOST_QUERIES
to decide whether to scan for host query files. When the feature flag is off,
the plugin only collects collection metadata (name + version) and ansible_version,
skipping the expensive embedded/external query file discovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dirk Julich
2026-05-20 16:55:43 +02:00
parent 1d2a82308b
commit 3d250adfa7
3 changed files with 44 additions and 17 deletions

View File

@@ -1162,6 +1162,7 @@ class RunJob(SourceControlMixin, BaseTask):
env['ANSIBLE_CALLBACKS_ENABLED'] += ',' + config_values['callbacks_enabled'] env['ANSIBLE_CALLBACKS_ENABLED'] += ',' + config_values['callbacks_enabled']
if flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"): if flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"):
env['AWX_COLLECT_HOST_QUERIES'] = '1'
# Add vendor collections path for external query file discovery # Add vendor collections path for external query file discovery
vendor_collections_path = os.path.join(CONTAINER_ROOT, 'vendor_collections') vendor_collections_path = os.path.join(CONTAINER_ROOT, 'vendor_collections')
env['ANSIBLE_COLLECTIONS_PATH'] = f"{vendor_collections_path}:{env['ANSIBLE_COLLECTIONS_PATH']}" env['ANSIBLE_COLLECTIONS_PATH'] = f"{vendor_collections_path}:{env['ANSIBLE_COLLECTIONS_PATH']}"

View File

@@ -965,6 +965,33 @@ class TestCallbacksEnabled(TestJobExecution):
assert env['ANSIBLE_CALLBACKS_ENABLED'] == 'indirect_instance_count,my_callback' assert env['ANSIBLE_CALLBACKS_ENABLED'] == 'indirect_instance_count,my_callback'
def test_collect_host_queries_set_when_flag_on(self, patch_Job, private_data_dir, execution_environment, mock_me):
job = Job(project=Project(), inventory=Inventory())
job.execution_environment = execution_environment
task = jobs.RunJob()
task.instance = job
task._write_extra_vars_file = mock.Mock()
with mock.patch.object(task, 'build_credentials_list', return_value=[], autospec=True):
with mock.patch('awx.main.tasks.jobs.flag_enabled', return_value=True):
env = task.build_env(job, private_data_dir)
assert env['AWX_COLLECT_HOST_QUERIES'] == '1'
def test_collect_host_queries_not_set_when_flag_off(self, patch_Job, private_data_dir, execution_environment, mock_me):
job = Job(project=Project(), inventory=Inventory())
job.execution_environment = execution_environment
task = jobs.RunJob()
task.instance = job
task._write_extra_vars_file = mock.Mock()
with mock.patch.object(task, 'build_credentials_list', return_value=[], autospec=True):
env = task.build_env(job, private_data_dir)
assert 'AWX_COLLECT_HOST_QUERIES' not in env
@pytest.mark.usefixtures("patch_Organization") @pytest.mark.usefixtures("patch_Organization")
class TestProjectUpdateGalaxyCredentials(TestJobExecution): class TestProjectUpdateGalaxyCredentials(TestJobExecution):

View File

@@ -168,26 +168,25 @@ class CallbackModule(CallbackBase):
if not artifact_dir: if not artifact_dir:
raise RuntimeError('Only suitable in AWX, did not find private_data_dir') raise RuntimeError('Only suitable in AWX, did not find private_data_dir')
collect_host_queries = os.getenv('AWX_COLLECT_HOST_QUERIES') == '1'
collections_print = {} collections_print = {}
# Loop over collections, from ansible-core these are Candidate objects
for candidate in list_collections(): for candidate in list_collections():
collection_print = { collection_print = {
'version': candidate.ver, 'version': candidate.ver,
} }
# 1. Check for embedded query file (takes precedence) if collect_host_queries:
embedded_query_file = files(f'ansible_collections.{candidate.namespace}.{candidate.name}') / 'extensions' / 'audit' / 'event_query.yml' embedded_query_file = files(f'ansible_collections.{candidate.namespace}.{candidate.name}') / 'extensions' / 'audit' / 'event_query.yml'
if embedded_query_file.exists(): if embedded_query_file.exists():
with embedded_query_file.open('r') as f: with embedded_query_file.open('r') as f:
collection_print['host_query'] = f.read() collection_print['host_query'] = f.read()
self._display.vv(f"Using embedded query for {candidate.fqcn} v{candidate.ver}") self._display.vv(f"Using embedded query for {candidate.fqcn} v{candidate.ver}")
else: else:
# 2. Check for external query file with version fallback
query_content, fallback_used, version_used = find_external_query_with_fallback(candidate.namespace, candidate.name, candidate.ver) query_content, fallback_used, version_used = find_external_query_with_fallback(candidate.namespace, candidate.name, candidate.ver)
if query_content: if query_content:
collection_print['host_query'] = query_content collection_print['host_query'] = query_content
if fallback_used: if fallback_used:
# AC5.6: Log when fallback is used
self._display.v(f"Using external query {version_used} for {candidate.fqcn} v{candidate.ver}.") self._display.v(f"Using external query {version_used} for {candidate.fqcn} v{candidate.ver}.")
else: else:
self._display.v(f"Using external query for {candidate.fqcn} v{candidate.ver}") self._display.v(f"Using external query for {candidate.fqcn} v{candidate.ver}")