bind9/bin/tests/system/stop.pl
Ondřej Surý 978c7b2e89 Complete rewrite the BIND 9 build system
The rewrite of BIND 9 build system is a large work and cannot be reasonable
split into separate merge requests.  Addition of the automake has a positive
effect on the readability and maintainability of the build system as it is more
declarative, it allows conditional and we are able to drop all of the custom
make code that BIND 9 developed over the years to overcome the deficiencies of
autoconf + custom Makefile.in files.

This squashed commit contains following changes:

- conversion (or rather fresh rewrite) of all Makefile.in files to Makefile.am
  by using automake

- the libtool is now properly integrated with automake (the way we used it
  was rather hackish as the only official way how to use libtool is via
  automake

- the dynamic module loading was rewritten from a custom patchwork to libtool's
  libltdl (which includes the patchwork to support module loading on different
  systems internally)

- conversion of the unit test executor from kyua to automake parallel driver

- conversion of the system test executor from custom make/shell to automake
  parallel driver

- The GSSAPI has been refactored, the custom SPNEGO on the basis that
  all major KRB5/GSSAPI (mit-krb5, heimdal and Windows) implementations
  support SPNEGO mechanism.

- The various defunct tests from bin/tests have been removed:
  bin/tests/optional and bin/tests/pkcs11

- The text files generated from the MD files have been removed, the
  MarkDown has been designed to be readable by both humans and computers

- The xsl header is now generated by a simple sed command instead of
  perl helper

- The <irs/platform.h> header has been removed

- cleanups of configure.ac script to make it more simpler, addition of multiple
  macros (there's still work to be done though)

- the tarball can now be prepared with `make dist`

- the system tests are partially able to run in oot build

Here's a list of unfinished work that needs to be completed in subsequent merge
requests:

- `make distcheck` doesn't yet work (because of system tests oot run is not yet
  finished)

- documentation is not yet built, there's a different merge request with docbook
  to sphinx-build rst conversion that needs to be rebased and adapted on top of
  the automake

- msvc build is non functional yet and we need to decide whether we will just
  cross-compile bind9 using mingw-w64 or fix the msvc build

- contributed dlz modules are not included neither in the autoconf nor automake
2020-04-21 14:19:48 +02:00

287 lines
6.1 KiB
Perl

#!/usr/bin/perl -w
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# Framework for stopping test servers
# Based on the type of server specified, signal the server to stop, wait
# briefly for it to die, and then kill it if it is still alive.
# If a server is specified, stop it. Otherwise, stop all servers for test.
use strict;
use warnings;
use Cwd ':DEFAULT', 'abs_path';
use English '-no_match_vars';
use Getopt::Long;
# Usage:
# perl stop.pl [--use-rndc [--port port]] test [server]
#
# --use-rndc Attempt to stop the server via the "rndc stop" command.
#
# --port port Only relevant if --use-rndc is specified, this sets the
# command port over which the attempt should be made. If
# not specified, port 9953 is used.
#
# test Name of the test directory.
#
# server Name of the server directory.
my $usage = "usage: $0 [--use-rndc [--halt] [--port port]] test-directory [server-directory]";
my $use_rndc = 0;
my $halt = 0;
my $rndc_port = 9953;
my $errors = 0;
GetOptions(
'use-rndc!' => \$use_rndc,
'halt!' => \$halt,
'port=i' => \$rndc_port
) or die "$usage\n";
my ( $test, $server_arg ) = @ARGV;
if (!$test) {
die "$usage\n";
}
# Global variables
my $builddir = $ENV{'builddir'};
my $srcdir = $ENV{'srcdir'};
my $testdir = "$builddir/$test";
if (! -d $testdir) {
die "No test directory: \"$testdir\"\n";
}
if ($server_arg && ! -d "$testdir/$server_arg") {
die "No server directory: \"$testdir/$server_arg\"\n";
}
my $RNDC = $ENV{RNDC};
my @ns;
my @ans;
if ($server_arg) {
if ($server_arg =~ /^ns/) {
push(@ns, $server_arg);
} elsif ($server_arg =~ /^ans/) {
push(@ans, $server_arg);
} else {
print "$0: ns or ans directory expected";
print "I:$test:failed";
}
} else {
# Determine which servers need to be stopped for this test.
opendir DIR, $testdir or die "unable to read test directory: \"$test\" ($OS_ERROR)\n";
my @files = sort readdir DIR;
closedir DIR;
@ns = grep /^ns[0-9]*$/, @files;
@ans = grep /^ans[0-9]*$/, @files;
}
# Stop the server(s), pass 1: rndc.
if ($use_rndc) {
foreach my $name(@ns) {
stop_rndc($name, $rndc_port);
}
@ns = wait_for_servers(30, @ns);
}
# Pass 2: SIGTERM
foreach my $name (@ns) {
stop_signal($name, "TERM");
}
@ns = wait_for_servers(60, @ns);
foreach my $name(@ans) {
stop_signal($name, "TERM", 1);
}
@ans = wait_for_servers(1200, @ans);
# Pass 3: SIGABRT
foreach my $name (@ns) {
print "I:$test:$name didn't die when sent a SIGTERM\n";
stop_signal($name, "ABRT");
$errors = 1;
}
foreach my $name (@ans) {
print "I:$test:$name didn't die when sent a SIGTERM\n";
stop_signal($name, "ABRT", 1);
$errors = 1;
}
exit($errors);
# Subroutines
# Return the full path to a given server's lock file.
sub server_lock_file {
my ( $server ) = @_;
return if (defined($ENV{'CYGWIN'}));
return $testdir . "/" . $server . "/named.lock" if ($server =~ /^ns/);
return if ($server =~ /^ans/);
die "Unknown server type $server\n";
}
# Return the full path to a given server's PID file.
sub server_pid_file {
my ( $server ) = @_;
return $testdir . "/" . $server . "/named.pid" if ($server =~ /^ns/);
return $testdir . "/" . $server . "/ans.pid" if ($server =~ /^ans/);
die "Unknown server type $server\n";
}
# Read a PID.
sub read_pid {
my ( $pid_file ) = @_;
return unless -f $pid_file;
# we don't really care about the race condition here
my $result = open(my $fh, "<", $pid_file);
if (!defined($result)) {
print "I:$test:$pid_file: $!\n";
unlink $pid_file;
return;
}
my $pid = <$fh>;
return unless defined($pid);
chomp($pid);
return $pid;
}
# Stop a named process with rndc.
sub stop_rndc {
my ( $server, $port ) = @_;
my $n;
if ($server =~ /^ns(\d+)/) {
$n = $1;
} else {
die "unable to parse server number from name \"$server\"\n";
}
my $ip = "10.53.0.$n";
my $how = $halt ? "halt" : "stop";
# Ugly, but should work.
system("$RNDC -c ../common/rndc.conf -s $ip -p $port $how | sed 's/^/I:$test:$server /'");
return;
}
sub server_died {
my ( $server, $signal ) = @_;
print "I:$test:$server died before a SIG$signal was sent\n";
$errors = 1;
my $pid_file = server_pid_file($server);
unlink($pid_file);
return;
}
sub send_signal {
my ( $signal, $pid, $ans ) = @_;
if (! defined $ans) {
$ans = 0;
}
my $result = 0;
if (!$ans && ($^O eq 'cygwin' || $^O eq 'msys')) {
my $killout = `/bin/kill -f -$signal $pid 2>&1`;
chomp($killout);
$result = 1 if ($killout eq '');
} else {
$result = kill $signal, $pid;
}
return $result;
}
# Stop a server by sending a signal to it.
sub stop_signal {
my ( $server, $signal, $ans ) = @_;
if (! defined $ans) {
$ans = 0;
}
my $pid_file = server_pid_file($server);
my $pid = read_pid($pid_file);
return unless defined($pid);
# Send signal to the server, and bail out if signal can't be sent
if (send_signal($signal, $pid, $ans) != 1) {
server_died($server, $signal);
return;
}
return;
}
sub pid_file_exists {
my ( $server ) = @_;
my $pid_file = server_pid_file($server);
my $pid = read_pid($pid_file);
return unless defined($pid);
# If we're here, the PID file hasn't been cleaned up yet
if (send_signal(0, $pid) == 0) {
# XXX: on windows this is likely to result in a
# false positive, so don't bother reporting the error.
if (!defined($ENV{'CYGWIN'})) {
print "I:$test:$server crashed on shutdown\n";
$errors = 1;
}
return;
}
return $server;
}
sub lock_file_exists {
my ( $server ) = @_;
my $lock_file = server_lock_file($server);
return unless defined($lock_file) && -f $lock_file;
return $server;
}
sub wait_for_servers {
my ( $timeout, @servers ) = @_;
while ($timeout > 0 && @servers > 0) {
sleep 1 if (@servers > 0);
@servers =
grep { defined($_) }
map { pid_file_exists($_) || lock_file_exists($_) } @servers;
$timeout--;
}
return @servers;
}