Commit e051eb28 authored by Ondřej Kuzník's avatar Ondřej Kuzník Committed by Quanah Gibson-Mount
Browse files

Allow wrapping of slapd invocations

parent dc3ad233
......@@ -66,6 +66,10 @@ case "$SCHEMADIR" in
.*) ABS_SCHEMADIR="$TESTWD/$SCHEMADIR" ;;
*) ABS_SCHEMADIR="$SCHEMADIR" ;;
esac
case "$SRCDIR" in
.*) ABS_SRCDIR="$TESTWD/$SRCDIR" ;;
*) ABS_SRCDIR="$SRCDIR" ;;
esac
DBDIR1A=$TESTDIR/db.1.a
DBDIR1B=$TESTDIR/db.1.b
......@@ -182,6 +186,23 @@ SLURPLOG=$TESTDIR/slurp.log
CONFIGPWF=$TESTDIR/configpw
# wrappers (valgrind, gdb, environment variables, etc.)
if [ -n "$WRAPPER" ]; then
: # skip
elif [ "$SLAPD_COMMON_WRAPPER" = gdb ]; then
WRAPPER="$ABS_SRCDIR/scripts/grandchild_wrapper.py gdb -nx -x $ABS_SRCDIR/scripts/gdb.py -batch-silent -return-child-result --args"
elif [ "$SLAPD_COMMON_WRAPPER" = valgrind ]; then
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --fullpath-after=`dirname $ABS_SRCDIR` --keep-debuginfo=yes --leak-check=full"
elif [ "$SLAPD_COMMON_WRAPPER" = "valgrind-errstop" ]; then
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=1"
elif [ "$SLAPD_COMMON_WRAPPER" = vgdb ]; then
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=0"
fi
if [ -n "$WRAPPER" ]; then
SLAPD_WRAPPER="$TESTWD/../libtool --mode=execute env $WRAPPER"
fi
# args
SASLARGS="-Q"
TOOLARGS="-x $LDAP_TOOLARGS"
......@@ -193,11 +214,11 @@ CONFDIRSYNC=$SRCDIR/scripts/confdirsync.sh
MONITORDATA=$SRCDIR/scripts/monitor_data.sh
SLAPADD="$TESTWD/../servers/slapd/slapd -Ta -d 0 $LDAP_VERBOSE"
SLAPCAT="$TESTWD/../servers/slapd/slapd -Tc -d 0 $LDAP_VERBOSE"
SLAPINDEX="$TESTWD/../servers/slapd/slapd -Ti -d 0 $LDAP_VERBOSE"
SLAPMODIFY="$TESTWD/../servers/slapd/slapd -Tm -d 0 $LDAP_VERBOSE"
SLAPPASSWD="$TESTWD/../servers/slapd/slapd -Tpasswd"
SLAPADD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Ta -d 0 $LDAP_VERBOSE"
SLAPCAT="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tc -d 0 $LDAP_VERBOSE"
SLAPINDEX="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Ti -d 0 $LDAP_VERBOSE"
SLAPMODIFY="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tm -d 0 $LDAP_VERBOSE"
SLAPPASSWD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tpasswd"
unset DIFF_OPTIONS
# NOTE: -u/-c is not that portable...
......@@ -205,8 +226,8 @@ DIFF="diff -i"
CMP="diff -i"
BCMP="diff -iB"
CMPOUT=/dev/null
SLAPD="$TESTWD/../servers/slapd/slapd -s0"
LLOADD="$TESTWD/../servers/lloadd/lloadd -s0"
SLAPD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -s0"
LLOADD="$SLAPD_WRAPPER $TESTWD/../servers/lloadd/lloadd -s0"
LDAPPASSWD="$CLIENTDIR/ldappasswd $TOOLARGS"
LDAPSASLSEARCH="$CLIENTDIR/ldapsearch $SASLARGS $TOOLPROTO $LDAP_TOOLARGS -LLL"
LDAPSASLWHOAMI="$CLIENTDIR/ldapwhoami $SASLARGS $LDAP_TOOLARGS"
......
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 2020-2021 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
"""
This GDB script sets up the debugger to run the program and see if it finishes
of its own accord or is terminated by a signal (like SIGABRT/SIGSEGV). In the
latter case, it saves a full backtrace and core file.
These signals are considered part of normal operation and will not trigger the
above handling:
- SIGPIPE: normal in a networked environmnet
- SIGHUP: normally used to tell a process to shut down
"""
import os
import os.path
import gdb
def format_program(inferior=None, thread=None):
"Format program name and p(t)id"
if thread:
inferior = thread.inferior
elif inferior is None:
inferior = gdb.selected_inferior()
try:
name = os.path.basename(inferior.progspace.filename)
except AttributeError: # inferior has died already
name = "unknown"
if thread:
pid = ".".join(tid for tid in thread.ptid if tid)
else:
pid = inferior.pid
return "{}.{}".format(name, pid)
def stop_handler(event):
"Inferior stopped on a signal, record core, backtrace and exit"
if not isinstance(event, gdb.SignalEvent):
# Ignore breakpoints
return
thread = event.inferior_thread
identifier = format_program(thread=thread)
prefix = os.path.expandvars("${TESTDIR}/") + identifier
if event.stop_signal == "SIGHUP":
# TODO: start a timer to catch shutdown issues/deadlocks
gdb.execute("continue")
return
gdb.execute('generate-core-file {}.core'.format(prefix))
with open(prefix + ".backtrace", "w") as bt_file:
backtrace = gdb.execute("thread apply all backtrace full",
to_string=True)
bt_file.write(backtrace)
gdb.execute("continue")
# We or we could allow the runner to disable randomisation
gdb.execute("set disable-randomization off")
gdb.execute("handle SIGPIPE noprint")
gdb.execute("handle SIGINT pass")
gdb.events.stop.connect(stop_handler)
gdb.execute("run")
#!/usr/bin/env python3
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 2020-2021 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
"""
Running slapd under GDB in our testsuite, KILLPIDS would record gdb's PID
rather than slapd's. When we want the server to shut down, SIGHUP is sent to
KILLPIDS but GDB cannot handle being signalled directly and the entire thing is
terminated immediately. There might be tests that rely on slapd being given the
chance to shut down gracefully, to do this, we need to make sure the signal is
actually sent to slapd.
This script attempts to address this shortcoming in our test suite, serving as
the front for gdb/other wrappers, catching SIGHUPs and redirecting them to the
oldest living grandchild. The way we start up gdb, that process should be
slapd, our intended target.
This requires the pgrep utility provided by the procps package on Debian
systems.
"""
import asyncio
import os
import signal
import sys
async def signal_to_grandchild(child):
# Get the first child, that should be the one we're after
pgrep = await asyncio.create_subprocess_exec(
"pgrep", "-o", "--parent", str(child.pid),
stdout=asyncio.subprocess.PIPE)
stdout, _ = await pgrep.communicate()
if not stdout:
return
grandchild = [int(pid) for pid in stdout.split()][0]
os.kill(grandchild, signal.SIGHUP)
def sighup_handler(child):
asyncio.create_task(signal_to_grandchild(child))
async def main(args=None):
if args is None:
args = sys.argv[1:]
child = await asyncio.create_subprocess_exec(*args)
# If we got a SIGHUP before we got the child fully started, there's no
# point signalling anyway
loop = asyncio.get_running_loop()
loop.add_signal_handler(signal.SIGHUP, sighup_handler, child)
raise SystemExit(await child.wait())
if __name__ == '__main__':
asyncio.run(main())
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment