mirror of
https://github.com/ansible/awx.git
synced 2026-06-23 23:57:52 -02:30
feat(analytics): log request_id, account_number, org_id from ingress API response (#16512)
* feat(analytics): ANSTRAT-2268 log request_id, account_number, org_id from ingress API response Log the ingress API success response fields (request_id, account_number, org_id) in the controller task log when gather_analytics tarballs are uploaded. This enables support engineers to trace uploads through to Kibana without source code modifications. * style(analytics): use f-strings in _log_shipping_response to match codebase conventions * style(analytics): fix black formatting in test assertions
This commit is contained in:
@@ -420,6 +420,18 @@ def gather(dest=None, module=None, subset=None, since=None, until=None, collecti
|
|||||||
return tarfiles
|
return tarfiles
|
||||||
|
|
||||||
|
|
||||||
|
def _log_shipping_response(response, path):
|
||||||
|
filename = os.path.basename(path)
|
||||||
|
try:
|
||||||
|
data = response.json()
|
||||||
|
request_id = data.get('request_id', 'unknown')
|
||||||
|
account_number = data.get('account_number', 'unknown')
|
||||||
|
org_id = data.get('org_id', 'unknown')
|
||||||
|
logger.info(f"Analytics upload successful: file={filename} request_id={request_id} account_number={account_number} org_id={org_id}")
|
||||||
|
except Exception:
|
||||||
|
logger.info(f"Analytics upload successful: file={filename} status={response.status_code}")
|
||||||
|
|
||||||
|
|
||||||
def ship(path):
|
def ship(path):
|
||||||
"""
|
"""
|
||||||
Ship gathered metrics to the Insights API
|
Ship gathered metrics to the Insights API
|
||||||
@@ -468,6 +480,7 @@ def ship(path):
|
|||||||
cert_url, files=files, cert=(cert_path, key_path), verify=settings.INSIGHTS_CERT_PATH, headers=s.headers, timeout=(31, 31)
|
cert_url, files=files, cert=(cert_path, key_path), verify=settings.INSIGHTS_CERT_PATH, headers=s.headers, timeout=(31, 31)
|
||||||
)
|
)
|
||||||
if response.status_code < 300:
|
if response.status_code < 300:
|
||||||
|
_log_shipping_response(response, path)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -484,6 +497,7 @@ def ship(path):
|
|||||||
response = client.make_request("POST", url, headers=s.headers, files=files, verify=settings.INSIGHTS_CERT_PATH, timeout=(31, 31))
|
response = client.make_request("POST", url, headers=s.headers, files=files, verify=settings.INSIGHTS_CERT_PATH, timeout=(31, 31))
|
||||||
|
|
||||||
if response.status_code < 300:
|
if response.status_code < 300:
|
||||||
|
_log_shipping_response(response, path)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.error(f'OIDC authentication failed with status {response.status_code}, {response.text}')
|
logger.error(f'OIDC authentication failed with status {response.status_code}, {response.text}')
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from awx.main.analytics.core import ship, _get_cert_upload_url
|
from awx.main.analytics.core import ship, _get_cert_upload_url, _log_shipping_response
|
||||||
|
|
||||||
|
|
||||||
class TestGetCertUploadUrl:
|
class TestGetCertUploadUrl:
|
||||||
@@ -70,6 +70,7 @@ class TestShipMTLS:
|
|||||||
# Mock successful mTLS response
|
# Mock successful mTLS response
|
||||||
mock_response = mock.Mock()
|
mock_response = mock.Mock()
|
||||||
mock_response.status_code = 200
|
mock_response.status_code = 200
|
||||||
|
mock_response.json.return_value = {'request_id': 'abc-123', 'account_number': '12345', 'org_id': '67890'}
|
||||||
mock_session = mock.Mock()
|
mock_session = mock.Mock()
|
||||||
mock_session.headers = {}
|
mock_session.headers = {}
|
||||||
mock_session.post.return_value = mock_response
|
mock_session.post.return_value = mock_response
|
||||||
@@ -81,6 +82,7 @@ class TestShipMTLS:
|
|||||||
mock_get_cert.assert_called_once()
|
mock_get_cert.assert_called_once()
|
||||||
mock_temp_files.assert_called_once_with('cert-pem-data', 'key-pem-data')
|
mock_temp_files.assert_called_once_with('cert-pem-data', 'key-pem-data')
|
||||||
mock_session.post.assert_called_once()
|
mock_session.post.assert_called_once()
|
||||||
|
mock_response.json.assert_called_once()
|
||||||
|
|
||||||
# Verify cert URL is used (cert. subdomain added)
|
# Verify cert URL is used (cert. subdomain added)
|
||||||
call_args = mock_session.post.call_args
|
call_args = mock_session.post.call_args
|
||||||
@@ -126,6 +128,7 @@ class TestShipMTLS:
|
|||||||
# Mock successful OIDC response
|
# Mock successful OIDC response
|
||||||
mock_oidc_response = mock.Mock()
|
mock_oidc_response = mock.Mock()
|
||||||
mock_oidc_response.status_code = 200
|
mock_oidc_response.status_code = 200
|
||||||
|
mock_oidc_response.json.return_value = {'request_id': 'oidc-456', 'account_number': '12345', 'org_id': '67890'}
|
||||||
mock_oidc_instance = mock.Mock()
|
mock_oidc_instance = mock.Mock()
|
||||||
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
||||||
mock_oidc_client.return_value = mock_oidc_instance
|
mock_oidc_client.return_value = mock_oidc_instance
|
||||||
@@ -172,6 +175,7 @@ class TestShipMTLS:
|
|||||||
# Mock successful OIDC response
|
# Mock successful OIDC response
|
||||||
mock_oidc_response = mock.Mock()
|
mock_oidc_response = mock.Mock()
|
||||||
mock_oidc_response.status_code = 200
|
mock_oidc_response.status_code = 200
|
||||||
|
mock_oidc_response.json.return_value = {'request_id': 'oidc-789', 'account_number': '12345', 'org_id': '67890'}
|
||||||
mock_oidc_instance = mock.Mock()
|
mock_oidc_instance = mock.Mock()
|
||||||
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
||||||
mock_oidc_client.return_value = mock_oidc_instance
|
mock_oidc_client.return_value = mock_oidc_instance
|
||||||
@@ -209,6 +213,7 @@ class TestShipMTLS:
|
|||||||
# Mock successful OIDC response
|
# Mock successful OIDC response
|
||||||
mock_oidc_response = mock.Mock()
|
mock_oidc_response = mock.Mock()
|
||||||
mock_oidc_response.status_code = 200
|
mock_oidc_response.status_code = 200
|
||||||
|
mock_oidc_response.json.return_value = {'request_id': 'oidc-no-cert', 'account_number': '12345', 'org_id': '67890'}
|
||||||
mock_oidc_instance = mock.Mock()
|
mock_oidc_instance = mock.Mock()
|
||||||
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
mock_oidc_instance.make_request.return_value = mock_oidc_response
|
||||||
mock_oidc_client.return_value = mock_oidc_instance
|
mock_oidc_client.return_value = mock_oidc_instance
|
||||||
@@ -269,3 +274,34 @@ class TestShipMTLS:
|
|||||||
assert result is False
|
assert result is False
|
||||||
mock_session.post.assert_called_once()
|
mock_session.post.assert_called_once()
|
||||||
mock_oidc_instance.make_request.assert_called_once()
|
mock_oidc_instance.make_request.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
class TestLogShippingResponse:
|
||||||
|
"""Test _log_shipping_response() helper function."""
|
||||||
|
|
||||||
|
def test_logs_response_fields(self):
|
||||||
|
"""Test that request_id, account_number, and org_id are logged."""
|
||||||
|
response = mock.Mock()
|
||||||
|
response.json.return_value = {'request_id': 'req-abc', 'account_number': '99999', 'org_id': '11111'}
|
||||||
|
with mock.patch('awx.main.analytics.core.logger') as mock_logger:
|
||||||
|
_log_shipping_response(response, '/tmp/analytics.tar.gz')
|
||||||
|
mock_logger.info.assert_called_once_with("Analytics upload successful: file=analytics.tar.gz request_id=req-abc account_number=99999 org_id=11111")
|
||||||
|
|
||||||
|
def test_logs_unknown_for_missing_fields(self):
|
||||||
|
"""Test fallback to 'unknown' when response fields are absent."""
|
||||||
|
response = mock.Mock()
|
||||||
|
response.json.return_value = {}
|
||||||
|
with mock.patch('awx.main.analytics.core.logger') as mock_logger:
|
||||||
|
_log_shipping_response(response, '/tmp/analytics.tar.gz')
|
||||||
|
mock_logger.info.assert_called_once_with(
|
||||||
|
"Analytics upload successful: file=analytics.tar.gz request_id=unknown account_number=unknown org_id=unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_graceful_fallback_on_json_error(self):
|
||||||
|
"""Test fallback log when response body is not valid JSON."""
|
||||||
|
response = mock.Mock()
|
||||||
|
response.json.side_effect = ValueError("No JSON")
|
||||||
|
response.status_code = 202
|
||||||
|
with mock.patch('awx.main.analytics.core.logger') as mock_logger:
|
||||||
|
_log_shipping_response(response, '/tmp/analytics.tar.gz')
|
||||||
|
mock_logger.info.assert_called_once_with("Analytics upload successful: file=analytics.tar.gz status=202")
|
||||||
|
|||||||
Reference in New Issue
Block a user