Files
awx/awx/main/tests/functional/analytics/test_metrics.py
Alan Rominger 5e93f60b9e AAP-41776 Enable new fancy asyncio metrics for dispatcherd (#16233)
* Enable new fancy asyncio metrics for dispatcherd

Remove old dispatcher metrics and patch in new data from local whatever

Update test fixture to new dispatcherd version

* Update dispatcherd again

* Handle node filter in URL, and catch more errors

* Add test for metric filter

* Split module for dispatcherd metrics
2026-02-04 15:28:34 -05:00

135 lines
4.8 KiB
Python

import pytest
from django.test import RequestFactory
from prometheus_client.parser import text_string_to_metric_families
from rest_framework.request import Request
from awx.main import models
from awx.main.analytics.metrics import metrics
from awx.main.analytics.dispatcherd_metrics import get_dispatcherd_metrics
from awx.api.versioning import reverse
EXPECTED_VALUES = {
'awx_system_info': 1.0,
'awx_organizations_total': 1.0,
'awx_users_total': 1.0,
'awx_teams_total': 1.0,
'awx_inventories_total': 1.0,
'awx_projects_total': 1.0,
'awx_job_templates_total': 1.0,
'awx_workflow_job_templates_total': 1.0,
'awx_hosts_total': 1.0,
'awx_hosts_total': 1.0,
'awx_schedules_total': 1.0,
'awx_sessions_total': 0.0,
'awx_status_total': 0.0,
'awx_running_jobs_total': 0.0,
'awx_instance_capacity': 100.0,
'awx_instance_consumed_capacity': 0.0,
'awx_instance_remaining_capacity': 100.0,
'awx_instance_cpu': 0.0,
'awx_instance_memory': 0.0,
'awx_instance_info': 1.0,
'awx_license_instance_total': 0,
'awx_license_instance_free': 0,
'awx_pending_jobs_total': 0,
'awx_database_connections_total': 1,
'awx_license_expiry': 0,
}
@pytest.mark.django_db
def test_metrics_counts(organization_factory, job_template_factory, workflow_job_template_factory):
objs = organization_factory('org', superusers=['admin'])
jt = job_template_factory('test', organization=objs.organization, inventory='test_inv', project='test_project', credential='test_cred')
workflow_job_template_factory('test')
models.Team(organization=objs.organization).save()
models.Host(inventory=jt.inventory).save()
models.Schedule(rrule='DTSTART;TZID=America/New_York:20300504T150000', unified_job_template=jt.job_template).save()
output = metrics()
gauges = text_string_to_metric_families(output.decode('UTF-8'))
for gauge in gauges:
for sample in gauge.samples:
# name, label, value, timestamp, exemplar
name, _, value, _, _, _ = sample
assert EXPECTED_VALUES[name] == value
def get_metrics_view_db_only():
return reverse('api:metrics_view') + '?dbonly=1'
@pytest.mark.django_db
def test_metrics_permissions(get, admin, org_admin, alice, bob, organization):
assert get(get_metrics_view_db_only(), user=admin).status_code == 200
assert get(get_metrics_view_db_only(), user=org_admin).status_code == 403
assert get(get_metrics_view_db_only(), user=alice).status_code == 403
assert get(get_metrics_view_db_only(), user=bob).status_code == 403
organization.auditor_role.members.add(bob)
assert get(get_metrics_view_db_only(), user=bob).status_code == 403
bob.is_system_auditor = True
assert get(get_metrics_view_db_only(), user=bob).status_code == 200
@pytest.mark.django_db
def test_metrics_http_methods(get, post, patch, put, options, admin):
assert get(get_metrics_view_db_only(), user=admin).status_code == 200
assert put(get_metrics_view_db_only(), user=admin).status_code == 405
assert patch(get_metrics_view_db_only(), user=admin).status_code == 405
assert post(get_metrics_view_db_only(), user=admin).status_code == 405
assert options(get_metrics_view_db_only(), user=admin).status_code == 200
class DummyMetricsResponse:
def __init__(self, payload):
self._payload = payload
def read(self):
return self._payload
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
def test_dispatcherd_metrics_node_filter_match(mocker, settings):
settings.CLUSTER_HOST_ID = "awx-1"
payload = b'# HELP test_metric A test metric\n# TYPE test_metric gauge\ntest_metric 1\n'
def fake_urlopen(url, timeout=1.0):
return DummyMetricsResponse(payload)
mocker.patch('urllib.request.urlopen', fake_urlopen)
request = Request(RequestFactory().get('/api/v2/metrics/', {'node': 'awx-1'}))
assert get_dispatcherd_metrics(request) == payload.decode('utf-8')
def test_dispatcherd_metrics_node_filter_excludes_local(mocker, settings):
settings.CLUSTER_HOST_ID = "awx-1"
def fake_urlopen(*args, **kwargs):
raise AssertionError("urlopen should not be called when node filter excludes local node")
mocker.patch('urllib.request.urlopen', fake_urlopen)
request = Request(RequestFactory().get('/api/v2/metrics/', {'node': 'awx-2'}))
assert get_dispatcherd_metrics(request) == ''
def test_dispatcherd_metrics_metric_filter_excludes_unrelated(mocker):
def fake_urlopen(*args, **kwargs):
raise AssertionError("urlopen should not be called when metric filter excludes dispatcherd metrics")
mocker.patch('urllib.request.urlopen', fake_urlopen)
request = Request(RequestFactory().get('/api/v2/metrics/', {'metric': 'awx_system_info'}))
assert get_dispatcherd_metrics(request) == ''