Resolves: RHEL-80252 - [RFE] Structured (JSON) logging option for RHDS access and error logs
- Resolves: RHEL-95441 - ns-slapd[xxxx]: segfault at 10d7d0d0 ip 00007ff734050cdb sp 00007ff6de9f1430 error 6 in libslapd.so.0.1.0[7ff733ec0000+1b3000]
This commit is contained in:
parent
1e21d71624
commit
8e09043b45
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
/389-ds-base-*.tar.bz2
|
||||
/jemalloc-*.tar.bz2
|
||||
/libdb-5.3.28-59.tar.bz2
|
||||
/Cargo-3.1.3-1.lock
|
||||
/vendor-3.1.3-1.tar.gz
|
||||
|
||||
380
0003-Issue-6663-Fix-NULL-subsystem-crash-in-JSON-error-lo.patch
Normal file
380
0003-Issue-6663-Fix-NULL-subsystem-crash-in-JSON-error-lo.patch
Normal file
@ -0,0 +1,380 @@
|
||||
From bd9ab54f64148d467e022c59ee8e5aed16f0c385 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Mon, 28 Jul 2025 18:14:15 +0530
|
||||
Subject: [PATCH] Issue 6663 - Fix NULL subsystem crash in JSON error logging
|
||||
(#6883)
|
||||
|
||||
Description: Fixes crash in JSON error logging when subsystem is NULL.
|
||||
Parametrized test case for better debugging.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6663
|
||||
|
||||
Reviewed by: @mreynolds389
|
||||
---
|
||||
.../tests/suites/clu/dsconf_logging.py | 168 ------------------
|
||||
.../tests/suites/clu/dsconf_logging_test.py | 164 +++++++++++++++++
|
||||
ldap/servers/slapd/log.c | 2 +-
|
||||
3 files changed, 165 insertions(+), 169 deletions(-)
|
||||
delete mode 100644 dirsrvtests/tests/suites/clu/dsconf_logging.py
|
||||
create mode 100644 dirsrvtests/tests/suites/clu/dsconf_logging_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/clu/dsconf_logging.py b/dirsrvtests/tests/suites/clu/dsconf_logging.py
|
||||
deleted file mode 100644
|
||||
index 1c2f7fc2e..000000000
|
||||
--- a/dirsrvtests/tests/suites/clu/dsconf_logging.py
|
||||
+++ /dev/null
|
||||
@@ -1,168 +0,0 @@
|
||||
-# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2025 Red Hat, Inc.
|
||||
-# All rights reserved.
|
||||
-#
|
||||
-# License: GPL (version 3 or any later version).
|
||||
-# See LICENSE for details.
|
||||
-# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
-import json
|
||||
-import subprocess
|
||||
-import logging
|
||||
-import pytest
|
||||
-from lib389._constants import DN_DM
|
||||
-from lib389.topologies import topology_st as topo
|
||||
-
|
||||
-pytestmark = pytest.mark.tier1
|
||||
-
|
||||
-log = logging.getLogger(__name__)
|
||||
-
|
||||
-SETTINGS = [
|
||||
- ('logging-enabled', None),
|
||||
- ('logging-disabled', None),
|
||||
- ('mode', '700'),
|
||||
- ('compress-enabled', None),
|
||||
- ('compress-disabled', None),
|
||||
- ('buffering-enabled', None),
|
||||
- ('buffering-disabled', None),
|
||||
- ('max-logs', '4'),
|
||||
- ('max-logsize', '7'),
|
||||
- ('rotation-interval', '2'),
|
||||
- ('rotation-interval-unit', 'week'),
|
||||
- ('rotation-tod-enabled', None),
|
||||
- ('rotation-tod-disabled', None),
|
||||
- ('rotation-tod-hour', '12'),
|
||||
- ('rotation-tod-minute', '20'),
|
||||
- ('deletion-interval', '3'),
|
||||
- ('deletion-interval-unit', 'day'),
|
||||
- ('max-disk-space', '20'),
|
||||
- ('free-disk-space', '2'),
|
||||
-]
|
||||
-
|
||||
-DEFAULT_TIME_FORMAT = "%FT%TZ"
|
||||
-
|
||||
-
|
||||
-def execute_dsconf_command(dsconf_cmd, subcommands):
|
||||
- """Execute dsconf command and return output and return code"""
|
||||
-
|
||||
- cmdline = dsconf_cmd + subcommands
|
||||
- proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
|
||||
- out, _ = proc.communicate()
|
||||
- return out.decode('utf-8'), proc.returncode
|
||||
-
|
||||
-
|
||||
-def get_dsconf_base_cmd(topo):
|
||||
- """Return base dsconf command list"""
|
||||
- return ['/usr/sbin/dsconf', topo.standalone.serverid,
|
||||
- '-j', '-D', DN_DM, '-w', 'password', 'logging']
|
||||
-
|
||||
-
|
||||
-def test_log_settings(topo):
|
||||
- """Test each log setting can be set successfully
|
||||
-
|
||||
- :id: b800fd03-37f5-4e74-9af8-eeb07030eb52
|
||||
- :setup: Standalone DS instance
|
||||
- :steps:
|
||||
- 1. Test each log's settings
|
||||
- :expectedresults:
|
||||
- 1. Success
|
||||
- """
|
||||
-
|
||||
- dsconf_cmd = get_dsconf_base_cmd(topo)
|
||||
- for log_type in ['access', 'audit', 'auditfail', 'error', 'security']:
|
||||
- # Test "get" command
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'get'])
|
||||
- assert rc == 0
|
||||
- json_result = json.loads(output)
|
||||
- default_location = json_result['Log name and location']
|
||||
-
|
||||
- # Log location
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'set',
|
||||
- 'location',
|
||||
- f'/tmp/{log_type}'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'set',
|
||||
- 'location',
|
||||
- default_location])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Log levels
|
||||
- if log_type == "access":
|
||||
- # List levels
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'list-levels'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Set levels
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set', 'level',
|
||||
- 'internal'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set', 'level',
|
||||
- 'internal', 'entry'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set', 'level',
|
||||
- 'internal', 'default'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- if log_type == "error":
|
||||
- # List levels
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'list-levels'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Set levels
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set', 'level',
|
||||
- 'plugin', 'replication'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set', 'level',
|
||||
- 'default'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Log formats
|
||||
- if log_type in ["access", "audit", "error"]:
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set',
|
||||
- 'time-format', '%D'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set',
|
||||
- 'time-format',
|
||||
- DEFAULT_TIME_FORMAT])
|
||||
- assert rc == 0
|
||||
-
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set',
|
||||
- 'log-format',
|
||||
- 'json'])
|
||||
- assert rc == 0
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set',
|
||||
- 'log-format',
|
||||
- 'default'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Audit log display attrs
|
||||
- if log_type == "audit":
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
- [log_type, 'set',
|
||||
- 'display-attrs', 'cn'])
|
||||
- assert rc == 0
|
||||
-
|
||||
- # Common settings
|
||||
- for attr, value in SETTINGS:
|
||||
- if log_type == "auditfail" and attr.startswith("buffer"):
|
||||
- # auditfail doesn't have a buffering settings
|
||||
- continue
|
||||
-
|
||||
- if value is None:
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd, [log_type,
|
||||
- 'set', attr])
|
||||
- else:
|
||||
- output, rc = execute_dsconf_command(dsconf_cmd, [log_type,
|
||||
- 'set', attr, value])
|
||||
- assert rc == 0
|
||||
diff --git a/dirsrvtests/tests/suites/clu/dsconf_logging_test.py b/dirsrvtests/tests/suites/clu/dsconf_logging_test.py
|
||||
new file mode 100644
|
||||
index 000000000..ca3f71997
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/clu/dsconf_logging_test.py
|
||||
@@ -0,0 +1,164 @@
|
||||
+# --- BEGIN COPYRIGHT BLOCK ---
|
||||
+# Copyright (C) 2025 Red Hat, Inc.
|
||||
+# All rights reserved.
|
||||
+#
|
||||
+# License: GPL (version 3 or any later version).
|
||||
+# See LICENSE for details.
|
||||
+# --- END COPYRIGHT BLOCK ---
|
||||
+#
|
||||
+import json
|
||||
+import subprocess
|
||||
+import logging
|
||||
+import pytest
|
||||
+from lib389._constants import DN_DM
|
||||
+from lib389.topologies import topology_st as topo
|
||||
+
|
||||
+pytestmark = pytest.mark.tier1
|
||||
+
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+SETTINGS = [
|
||||
+ ('logging-enabled', None),
|
||||
+ ('logging-disabled', None),
|
||||
+ ('mode', '700'),
|
||||
+ ('compress-enabled', None),
|
||||
+ ('compress-disabled', None),
|
||||
+ ('buffering-enabled', None),
|
||||
+ ('buffering-disabled', None),
|
||||
+ ('max-logs', '4'),
|
||||
+ ('max-logsize', '7'),
|
||||
+ ('rotation-interval', '2'),
|
||||
+ ('rotation-interval-unit', 'week'),
|
||||
+ ('rotation-tod-enabled', None),
|
||||
+ ('rotation-tod-disabled', None),
|
||||
+ ('rotation-tod-hour', '12'),
|
||||
+ ('rotation-tod-minute', '20'),
|
||||
+ ('deletion-interval', '3'),
|
||||
+ ('deletion-interval-unit', 'day'),
|
||||
+ ('max-disk-space', '20'),
|
||||
+ ('free-disk-space', '2'),
|
||||
+]
|
||||
+
|
||||
+DEFAULT_TIME_FORMAT = "%FT%TZ"
|
||||
+
|
||||
+
|
||||
+def execute_dsconf_command(dsconf_cmd, subcommands):
|
||||
+ """Execute dsconf command and return output and return code"""
|
||||
+
|
||||
+ cmdline = dsconf_cmd + subcommands
|
||||
+ proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
+ out, err = proc.communicate()
|
||||
+
|
||||
+ if proc.returncode != 0 and err:
|
||||
+ log.error(f"Command failed: {' '.join(cmdline)}")
|
||||
+ log.error(f"Stderr: {err.decode('utf-8')}")
|
||||
+
|
||||
+ return out.decode('utf-8'), proc.returncode
|
||||
+
|
||||
+
|
||||
+def get_dsconf_base_cmd(topo):
|
||||
+ """Return base dsconf command list"""
|
||||
+ return ['/usr/sbin/dsconf', topo.standalone.serverid,
|
||||
+ '-j', '-D', DN_DM, '-w', 'password', 'logging']
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize("log_type", ['access', 'audit', 'auditfail', 'error', 'security'])
|
||||
+def test_log_settings(topo, log_type):
|
||||
+ """Test each log setting can be set successfully
|
||||
+
|
||||
+ :id: b800fd03-37f5-4e74-9af8-eeb07030eb52
|
||||
+ :setup: Standalone DS instance
|
||||
+ :steps:
|
||||
+ 1. Test each log's settings
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ """
|
||||
+
|
||||
+ dsconf_cmd = get_dsconf_base_cmd(topo)
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'get'])
|
||||
+ assert rc == 0
|
||||
+ json_result = json.loads(output)
|
||||
+ default_location = json_result['Log name and location']
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'set',
|
||||
+ 'location',
|
||||
+ f'/tmp/{log_type}'])
|
||||
+ assert rc == 0
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd, [log_type, 'set',
|
||||
+ 'location',
|
||||
+ default_location])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ if log_type == "access":
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'list-levels'])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set', 'level',
|
||||
+ 'internal'])
|
||||
+ assert rc == 0
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set', 'level',
|
||||
+ 'internal', 'entry'])
|
||||
+ assert rc == 0
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set', 'level',
|
||||
+ 'internal', 'default'])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ if log_type == "error":
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'list-levels'])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set', 'level',
|
||||
+ 'plugin', 'replication'])
|
||||
+ assert rc == 0
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set', 'level',
|
||||
+ 'default'])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ if log_type in ["access", "audit", "error"]:
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set',
|
||||
+ 'time-format', '%D'])
|
||||
+ assert rc == 0
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set',
|
||||
+ 'time-format',
|
||||
+ DEFAULT_TIME_FORMAT])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set',
|
||||
+ 'log-format',
|
||||
+ 'json'])
|
||||
+ assert rc == 0, f"Failed to set {log_type} log-format to json: {output}"
|
||||
+
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set',
|
||||
+ 'log-format',
|
||||
+ 'default'])
|
||||
+ assert rc == 0, f"Failed to set {log_type} log-format to default: {output}"
|
||||
+
|
||||
+ if log_type == "audit":
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd,
|
||||
+ [log_type, 'set',
|
||||
+ 'display-attrs', 'cn'])
|
||||
+ assert rc == 0
|
||||
+
|
||||
+ for attr, value in SETTINGS:
|
||||
+ if log_type == "auditfail" and attr.startswith("buffer"):
|
||||
+ continue
|
||||
+
|
||||
+ if value is None:
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd, [log_type,
|
||||
+ 'set', attr])
|
||||
+ else:
|
||||
+ output, rc = execute_dsconf_command(dsconf_cmd, [log_type,
|
||||
+ 'set', attr, value])
|
||||
+ assert rc == 0
|
||||
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
|
||||
index 06dae4d0b..e859682fe 100644
|
||||
--- a/ldap/servers/slapd/log.c
|
||||
+++ b/ldap/servers/slapd/log.c
|
||||
@@ -2937,7 +2937,7 @@ vslapd_log_error(
|
||||
json_obj = json_object_new_object();
|
||||
json_object_object_add(json_obj, "local_time", json_object_new_string(local_time));
|
||||
json_object_object_add(json_obj, "severity", json_object_new_string(get_log_sev_name(sev_level, sev_name)));
|
||||
- json_object_object_add(json_obj, "subsystem", json_object_new_string(subsystem));
|
||||
+ json_object_object_add(json_obj, "subsystem", json_object_new_string(subsystem ? subsystem : ""));
|
||||
json_object_object_add(json_obj, "msg", json_object_new_string(vbuf));
|
||||
|
||||
PR_snprintf(buffer, sizeof(buffer), "%s\n",
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -290,8 +290,12 @@ Source4: 389-ds-base.sysusers
|
||||
Source5: https://fedorapeople.org/groups/389ds/libdb-5.3.28-59.tar.bz2
|
||||
%endif
|
||||
|
||||
Source6: vendor-%{version}-1.tar.gz
|
||||
Source7: Cargo-%{version}-1.lock
|
||||
|
||||
Patch: 0001-Issue-6822-Backend-creation-cleanup-and-Database-UI-.patch
|
||||
Patch: 0002-Issue-6852-Move-ds-CLI-tools-back-to-sbin.patch
|
||||
Patch: 0003-Issue-6663-Fix-NULL-subsystem-crash-in-JSON-error-lo.patch
|
||||
|
||||
%description
|
||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||
@ -423,6 +427,9 @@ cd src/lib389
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n %{name}-%{version}
|
||||
rm -rf vendor
|
||||
tar xzf %{SOURCE6}
|
||||
cp %{SOURCE7} src/Cargo.lock
|
||||
|
||||
%if %{with bundle_jemalloc}
|
||||
%setup -q -n %{name}-%{version} -T -D -b 3
|
||||
|
||||
2
sources
2
sources
@ -1,3 +1,5 @@
|
||||
SHA512 (jemalloc-5.3.0.tar.bz2) = 22907bb052096e2caffb6e4e23548aecc5cc9283dce476896a2b1127eee64170e3562fa2e7db9571298814a7a2c7df6e8d1fbe152bd3f3b0c1abec22a2de34b1
|
||||
SHA512 (libdb-5.3.28-59.tar.bz2) = 731a434fa2e6487ebb05c458b0437456eb9f7991284beb08cb3e21931e23bdeddddbc95bfabe3a2f9f029fe69cd33a2d4f0f5ce6a9811e9c3b940cb6fde4bf79
|
||||
SHA512 (389-ds-base-3.1.3.tar.bz2) = bd15c29dba5209ed828a2534e51fd000fdd5d32862fd07ea73339e73489b3c79f1991c91592c75dbb67384c696a03c82378f156bbea594e2e17421c95ca4c6be
|
||||
SHA512 (Cargo-3.1.3-1.lock) = ea6db252e49de8aa2fe165f5cc773dc2eb227100d56953a36ca062680a3fc54870a961b05aaac1f7a761c69f3685cc8a7be474ac92377a1219c293fd1117f491
|
||||
SHA512 (vendor-3.1.3-1.tar.gz) = bf7f775da482a0164b5192e60cc335f32c65edf120ab94336835d98b2ea769eb116c808d06376e8ececb96e617194ec3febebf375821657e3d4751d9d8a0cf3c
|
||||
|
||||
Loading…
Reference in New Issue
Block a user