mirror of
https://github.com/ansible/awx.git
synced 2026-03-19 09:57:33 -02:30
* Adding API_400_ERROR_LOG_FORMAT setting * Adding functional tests for API_400_ERROR_LOG_FORMAT Co-authored-by: nixocio <nixocio@gmail.com>
This commit is contained in:
@@ -44,6 +44,7 @@ from awx.main.views import ApiErrorView
|
|||||||
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
|
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
|
||||||
from awx.api.versioning import URLPathVersioning
|
from awx.api.versioning import URLPathVersioning
|
||||||
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
|
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
|
||||||
|
from awx.conf import settings_registry
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'APIView',
|
'APIView',
|
||||||
@@ -208,12 +209,20 @@ class APIView(views.APIView):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
status_msg = "status %s received by user %s attempting to access %s from %s" % (
|
msg_data = {
|
||||||
response.status_code,
|
'status_code': response.status_code,
|
||||||
request.user,
|
'user_name': request.user,
|
||||||
request.path,
|
'url_path': request.path,
|
||||||
request.META.get('REMOTE_ADDR', None),
|
'remote_addr': request.META.get('REMOTE_ADDR', None),
|
||||||
)
|
'error': response.data.get('error', response.status_text),
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
status_msg = getattr(settings, 'API_400_ERROR_LOG_FORMAT').format(**msg_data)
|
||||||
|
except Exception as e:
|
||||||
|
if getattr(settings, 'API_400_ERROR_LOG_FORMAT', None):
|
||||||
|
logger.error("Unable to format API_400_ERROR_LOG_FORMAT setting, defaulting log message: {}".format(e))
|
||||||
|
status_msg = settings_registry.get_setting_field('API_400_ERROR_LOG_FORMAT').get_default().format(**msg_data)
|
||||||
|
|
||||||
if hasattr(self, '__init_request_error__'):
|
if hasattr(self, '__init_request_error__'):
|
||||||
response = self.handle_exception(self.__init_request_error__)
|
response = self.handle_exception(self.__init_request_error__)
|
||||||
if response.status_code == 401:
|
if response.status_code == 401:
|
||||||
@@ -221,6 +230,7 @@ class APIView(views.APIView):
|
|||||||
logger.info(status_msg)
|
logger.info(status_msg)
|
||||||
else:
|
else:
|
||||||
logger.warning(status_msg)
|
logger.warning(status_msg)
|
||||||
|
|
||||||
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
|
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
|
||||||
time_started = getattr(self, 'time_started', None)
|
time_started = getattr(self, 'time_started', None)
|
||||||
response['X-API-Product-Version'] = get_awx_version()
|
response['X-API-Product-Version'] = get_awx_version()
|
||||||
|
|||||||
@@ -674,6 +674,24 @@ register(
|
|||||||
category=_('Logging'),
|
category=_('Logging'),
|
||||||
category_slug='logging',
|
category_slug='logging',
|
||||||
)
|
)
|
||||||
|
register(
|
||||||
|
'API_400_ERROR_LOG_FORMAT',
|
||||||
|
field_class=fields.CharField,
|
||||||
|
default='status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}',
|
||||||
|
label=_('Log Format For API 4XX Errors'),
|
||||||
|
help_text=_(
|
||||||
|
'The format of logged messages when an API 4XX error occurs, '
|
||||||
|
'the following variables will be substituted: \n'
|
||||||
|
'status_code - The HTTP status code of the error\n'
|
||||||
|
'user_name - The user name attempting to use the API\n'
|
||||||
|
'url_path - The URL path to the API endpoint called\n'
|
||||||
|
'remote_addr - The remote address seen for the user\n'
|
||||||
|
'error - The error set by the api endpoint\n'
|
||||||
|
'Variables need to be in the format {<variable name>}.'
|
||||||
|
),
|
||||||
|
category=_('Logging'),
|
||||||
|
category_slug='logging',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
|
|||||||
26
awx/main/tests/functional/test_api_generics.py
Normal file
26
awx/main/tests/functional/test_api_generics.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_change_400_error_log(caplog, post, admin_user):
|
||||||
|
with override_settings(API_400_ERROR_LOG_FORMAT='Test'):
|
||||||
|
post(url=reverse('api:setting_logging_test'), data={}, user=admin_user, expect=409)
|
||||||
|
assert 'Test' in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_bad_400_error_log(caplog, post, admin_user):
|
||||||
|
with override_settings(API_400_ERROR_LOG_FORMAT="Not good {junk}"):
|
||||||
|
post(url=reverse('api:setting_logging_test'), data={}, user=admin_user, expect=409)
|
||||||
|
assert "Unable to format API_400_ERROR_LOG_FORMAT setting, defaulting log message: 'junk'" in caplog.text
|
||||||
|
assert 'status 409 received by user admin attempting to access /api/v2/settings/logging/test/ from 127.0.0.1' in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_custom_400_error_log(caplog, post, admin_user):
|
||||||
|
with override_settings(API_400_ERROR_LOG_FORMAT="{status_code} {error}"):
|
||||||
|
post(url=reverse('api:setting_logging_test'), data={}, user=admin_user, expect=409)
|
||||||
|
assert '409 Logging not enabled' in caplog.text
|
||||||
@@ -761,6 +761,7 @@ LOG_AGGREGATOR_MAX_DISK_USAGE_GB = 1
|
|||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH = '/var/lib/awx'
|
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH = '/var/lib/awx'
|
||||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG = False
|
LOG_AGGREGATOR_RSYSLOGD_DEBUG = False
|
||||||
LOG_AGGREGATOR_RSYSLOGD_ERROR_LOG_FILE = '/var/log/tower/rsyslog.err'
|
LOG_AGGREGATOR_RSYSLOGD_ERROR_LOG_FILE = '/var/log/tower/rsyslog.err'
|
||||||
|
API_400_ERROR_LOG_FORMAT = 'status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}'
|
||||||
|
|
||||||
# The number of retry attempts for websocket session establishment
|
# The number of retry attempts for websocket session establishment
|
||||||
# If you're encountering issues establishing websockets in a cluster,
|
# If you're encountering issues establishing websockets in a cluster,
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ SettingsAPI.readCategory.mockResolvedValue({
|
|||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_GB: 1,
|
LOG_AGGREGATOR_MAX_DISK_USAGE_GB: 1,
|
||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
||||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
||||||
|
API_400_ERROR_LOG_FORMAT:
|
||||||
|
'status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ function LoggingDetail() {
|
|||||||
'LOG_AGGREGATOR_TCP_TIMEOUT',
|
'LOG_AGGREGATOR_TCP_TIMEOUT',
|
||||||
'LOG_AGGREGATOR_TYPE',
|
'LOG_AGGREGATOR_TYPE',
|
||||||
'LOG_AGGREGATOR_USERNAME',
|
'LOG_AGGREGATOR_USERNAME',
|
||||||
'LOG_AGGREGATOR_VERIFY_CERT'
|
'LOG_AGGREGATOR_VERIFY_CERT',
|
||||||
|
'API_400_ERROR_LOG_FORMAT'
|
||||||
);
|
);
|
||||||
|
|
||||||
const mergedData = {};
|
const mergedData = {};
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ describe('<LoggingDetail />', () => {
|
|||||||
assertDetail(wrapper, 'Logging Aggregator Protocol', 'https');
|
assertDetail(wrapper, 'Logging Aggregator Protocol', 'https');
|
||||||
assertDetail(wrapper, 'TCP Connection Timeout', '5 seconds');
|
assertDetail(wrapper, 'TCP Connection Timeout', '5 seconds');
|
||||||
assertDetail(wrapper, 'Logging Aggregator Level Threshold', 'INFO');
|
assertDetail(wrapper, 'Logging Aggregator Level Threshold', 'INFO');
|
||||||
|
assertDetail(wrapper, 'Log Format For API 4XX Errors', 'Test Log Line');
|
||||||
assertDetail(
|
assertDetail(
|
||||||
wrapper,
|
wrapper,
|
||||||
'Enable/disable HTTPS certificate verification',
|
'Enable/disable HTTPS certificate verification',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { CardBody } from 'components/Card';
|
|||||||
import ContentError from 'components/ContentError';
|
import ContentError from 'components/ContentError';
|
||||||
import ContentLoading from 'components/ContentLoading';
|
import ContentLoading from 'components/ContentLoading';
|
||||||
import { FormSubmitError } from 'components/FormField';
|
import { FormSubmitError } from 'components/FormField';
|
||||||
import { FormColumnLayout } from 'components/FormLayout';
|
import { FormColumnLayout, FormFullWidthLayout } from 'components/FormLayout';
|
||||||
import { useSettings } from 'contexts/Settings';
|
import { useSettings } from 'contexts/Settings';
|
||||||
import useModal from 'hooks/useModal';
|
import useModal from 'hooks/useModal';
|
||||||
import useRequest from 'hooks/useRequest';
|
import useRequest from 'hooks/useRequest';
|
||||||
@@ -71,6 +71,7 @@ function LoggingEdit() {
|
|||||||
LOG_AGGREGATOR_LOGGERS: formatJson(form.LOG_AGGREGATOR_LOGGERS),
|
LOG_AGGREGATOR_LOGGERS: formatJson(form.LOG_AGGREGATOR_LOGGERS),
|
||||||
LOG_AGGREGATOR_HOST: form.LOG_AGGREGATOR_HOST || null,
|
LOG_AGGREGATOR_HOST: form.LOG_AGGREGATOR_HOST || null,
|
||||||
LOG_AGGREGATOR_TYPE: form.LOG_AGGREGATOR_TYPE || null,
|
LOG_AGGREGATOR_TYPE: form.LOG_AGGREGATOR_TYPE || null,
|
||||||
|
API_400_ERROR_LOG_FORMAT: form.API_400_ERROR_LOG_FORMAT || null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -196,6 +197,12 @@ function LoggingEdit() {
|
|||||||
name="LOG_AGGREGATOR_LOGGERS"
|
name="LOG_AGGREGATOR_LOGGERS"
|
||||||
config={logging.LOG_AGGREGATOR_LOGGERS}
|
config={logging.LOG_AGGREGATOR_LOGGERS}
|
||||||
/>
|
/>
|
||||||
|
<FormFullWidthLayout>
|
||||||
|
<InputField
|
||||||
|
name="API_400_ERROR_LOG_FORMAT"
|
||||||
|
config={logging.API_400_ERROR_LOG_FORMAT}
|
||||||
|
/>
|
||||||
|
</FormFullWidthLayout>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
{revertError && <FormSubmitError error={revertError} />}
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ const mockSettings = {
|
|||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_GB: 1,
|
LOG_AGGREGATOR_MAX_DISK_USAGE_GB: 1,
|
||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
||||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
||||||
|
API_400_ERROR_LOG_FORMAT:
|
||||||
|
'status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}',
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('<LoggingEdit />', () => {
|
describe('<LoggingEdit />', () => {
|
||||||
|
|||||||
@@ -564,6 +564,15 @@
|
|||||||
"category_slug": "logging",
|
"category_slug": "logging",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"API_400_ERROR_LOG_FORMAT": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"label": "Log Format For API 4XX Errors",
|
||||||
|
"help_text": "The format of logged messages when an API 4XX error occurs, the following variables will be substituted: \nstatus_code - The HTTP status code of the error\nuser_name - The user name attempting to use the API\nurl_path - The URL path to the API endpoint called\nremote_addr - The remote address seen for the user\nerror - The error set by the api endpoint\nVariables need to be in the format {<variable name>}.",
|
||||||
|
"category": "Logging",
|
||||||
|
"category_slug": "logging",
|
||||||
|
"default": "status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}"
|
||||||
|
},
|
||||||
"AUTOMATION_ANALYTICS_LAST_GATHER": {
|
"AUTOMATION_ANALYTICS_LAST_GATHER": {
|
||||||
"type": "datetime",
|
"type": "datetime",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -4221,6 +4230,15 @@
|
|||||||
"category_slug": "logging",
|
"category_slug": "logging",
|
||||||
"defined_in_file": false
|
"defined_in_file": false
|
||||||
},
|
},
|
||||||
|
"API_400_ERROR_LOG_FORMAT": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"label": "Log Format For API 4XX Errors",
|
||||||
|
"help_text": "The format of logged messages when an API 4XX error occurs, the following variables will be substituted: \nstatus_code - The HTTP status code of the error\nuser_name - The user name attempting to use the API\nurl_path - The URL path to the API endpoint called\nremote_addr - The remote address seen for the user\nerror - The error set by the api endpoint\nVariables need to be in the format {<variable name>}.",
|
||||||
|
"category": "Logging",
|
||||||
|
"category_slug": "logging",
|
||||||
|
"default": "status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}"
|
||||||
|
},
|
||||||
"AUTOMATION_ANALYTICS_LAST_GATHER": {
|
"AUTOMATION_ANALYTICS_LAST_GATHER": {
|
||||||
"type": "datetime",
|
"type": "datetime",
|
||||||
"label": "Last gather date for Insights for Ansible Automation Platform.",
|
"label": "Last gather date for Insights for Ansible Automation Platform.",
|
||||||
@@ -6329,7 +6347,7 @@
|
|||||||
},
|
},
|
||||||
"SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR": {
|
"SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR": {
|
||||||
"type": "nested object",
|
"type": "nested object",
|
||||||
"label": "SAML User Flags Attribute Mapping",
|
"label": "SAML User Flags Attribute Mapping",
|
||||||
"help_text": "Used to map super users and system auditors from SAML.",
|
"help_text": "Used to map super users and system auditors from SAML.",
|
||||||
"category": "SAML",
|
"category": "SAML",
|
||||||
"category_slug": "saml",
|
"category_slug": "saml",
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB":1,
|
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB":1,
|
||||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH":"/var/lib/awx",
|
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH":"/var/lib/awx",
|
||||||
"LOG_AGGREGATOR_RSYSLOGD_DEBUG":false,
|
"LOG_AGGREGATOR_RSYSLOGD_DEBUG":false,
|
||||||
|
"API_400_ERROR_LOG_FORMAT":"status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}",
|
||||||
"AUTOMATION_ANALYTICS_LAST_GATHER":null,
|
"AUTOMATION_ANALYTICS_LAST_GATHER":null,
|
||||||
"AUTOMATION_ANALYTICS_GATHER_INTERVAL":14400,
|
"AUTOMATION_ANALYTICS_GATHER_INTERVAL":14400,
|
||||||
"SESSION_COOKIE_AGE":1800,
|
"SESSION_COOKIE_AGE":1800,
|
||||||
|
|||||||
@@ -17,5 +17,6 @@
|
|||||||
"LOG_AGGREGATOR_LEVEL": "INFO",
|
"LOG_AGGREGATOR_LEVEL": "INFO",
|
||||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB": 1,
|
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB": 1,
|
||||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH": "/var/lib/awx",
|
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH": "/var/lib/awx",
|
||||||
"LOG_AGGREGATOR_RSYSLOGD_DEBUG": false
|
"LOG_AGGREGATOR_RSYSLOGD_DEBUG": false,
|
||||||
}
|
"API_400_ERROR_LOG_FORMAT": "Test Log Line"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user