From 33f0ca9399dce225b1e14c8f7f579f47cf0a8175 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Fri, 24 Jan 2025 11:22:33 -0500 Subject: [PATCH] Write test and get it passing --- awx/main/tasks/host_indirect.py | 28 +++++++++++++++++++ .../projects/host_query/meta/event_query.yml | 2 +- .../host_query/plugins/modules/example.py | 3 ++ .../projects/test_indirect_host_counting.py | 19 ++++++++++++- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/awx/main/tasks/host_indirect.py b/awx/main/tasks/host_indirect.py index e69de29bb2d1..7f8e8071dc3b 100644 --- a/awx/main/tasks/host_indirect.py +++ b/awx/main/tasks/host_indirect.py @@ -0,0 +1,28 @@ +from types import SimpleNamespace +import logging + +import jq + +logger = logging.getLogger(__name__) + + +def build_indirect_host_data(job, event_query: dict): + results = [] + compiled_jq_expressions = {} # Cache for compiled jq expressions + facts_missing_logged = False + for event in job.job_events.filter(task__in=event_query.keys()): + if 'res' not in event.event_data: + continue + jq_str_for_event = event_query[event.task] + if jq_str_for_event not in compiled_jq_expressions: + compiled_jq_expressions[event.task] = jq.compile(jq_str_for_event) + compiled_jq = compiled_jq_expressions[event.task] + for data in compiled_jq.input(event.event_data['res']).all(): + if not data.get('canonical_facts'): + if not facts_missing_logged: + logger.error(f'jq output missing canonical_facts for module {event.task} on event {event.id} using jq:{jq_str_for_event}') + continue + canonical_facts = data['canonical_facts'] + facts = data.get('facts') + results.append(SimpleNamespace(canonical_facts=canonical_facts, facts=facts)) + return results diff --git a/awx/main/tests/data/projects/host_query/meta/event_query.yml b/awx/main/tests/data/projects/host_query/meta/event_query.yml index 0c9e398c6602..1073d98ca332 100644 --- a/awx/main/tests/data/projects/host_query/meta/event_query.yml +++ b/awx/main/tests/data/projects/host_query/meta/event_query.yml @@ -1,4 +1,4 @@ --- { - "demo.query.example": "" + "demo.query.example": "{canonical_facts: {host_name: .direct_host_name}, facts: {device_type: .device_type}}" } diff --git a/awx/main/tests/data/projects/host_query/plugins/modules/example.py b/awx/main/tests/data/projects/host_query/plugins/modules/example.py index aa323e7c28da..fb1eb2314e6b 100644 --- a/awx/main/tests/data/projects/host_query/plugins/modules/example.py +++ b/awx/main/tests/data/projects/host_query/plugins/modules/example.py @@ -63,6 +63,9 @@ def run_module(): result['direct_host_name'] = module.params['host_name'] result['nested_host_name'] = {'host_name': module.params['host_name']} + # non-cononical facts + result['device_type'] = 'Fake Host' + module.exit_json(**result) diff --git a/awx/main/tests/live/tests/projects/test_indirect_host_counting.py b/awx/main/tests/live/tests/projects/test_indirect_host_counting.py index 1a2027dcfe4d..0c7ebec5f5f4 100644 --- a/awx/main/tests/live/tests/projects/test_indirect_host_counting.py +++ b/awx/main/tests/live/tests/projects/test_indirect_host_counting.py @@ -1,3 +1,20 @@ +from awx.main.tasks.host_indirect import build_indirect_host_data +from awx.main.models import Job + + def test_indirect_host_counting(live_tmp_folder, run_job_from_playbook): run_job_from_playbook('test_indirect_host_counting', 'run_task.yml', scm_url=f'file://{live_tmp_folder}/test_host_query') - # TODO: add assertions that the host query data is populated + job = Job.objects.filter(name__icontains='test_indirect_host_counting').order_by('-created').first() + + # Data matches to awx/main/tests/data/projects/host_query/meta/event_query.yml + # this just does things in-line to be a more localized test for the immediate testing + event_query = {'demo.query.example': '{canonical_facts: {host_name: .direct_host_name}, facts: {device_type: .device_type}}'} + + # Run the task logic directly with local data + results = build_indirect_host_data(job, event_query) + assert len(results) == 1 + host_audit_entry = results[0] + + # Asserts on data that will match to the input jq string from above + assert host_audit_entry.canonical_facts == {'host_name': 'foo_host_default'} + assert host_audit_entry.facts == {'device_type': 'Fake Host'}