2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-02 08:51:44 +00:00

test(openeuler): exercise logging and host-key postscripts

This commit is contained in:
Vinícius Ferrão
2026-09-15 00:33:39 -03:00
parent 263239e988
commit f2805433c1
3 changed files with 446 additions and 0 deletions
@@ -0,0 +1,151 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd qw(abs_path);
use Digest::SHA qw(sha256_hex);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use FindBin;
use Test::More;
plan skip_all => 'requires Linux root and mount namespaces' unless $^O eq 'linux' && $> == 0;
plan skip_all => 'mount namespaces unavailable' if system('unshare -m -- true >/dev/null 2>&1');
plan skip_all => 'requires native ssh-keygen' unless -x '/usr/bin/ssh-keygen';
my $source = $ENV{XCAT_HOSTKEY_SOURCE_ROOT} || abs_path("$FindBin::Bin/../..");
my $tmp = tempdir(DIR => '/var/tmp', CLEANUP => 1);
chmod 0700, $tmp;
make_path("$tmp/keys", "$tmp/bin");
sub write_file {
my ($path, $contents) = @_;
open(my $fh, '>', $path) or die "$path: $!";
print {$fh} $contents;
close($fh) or die "$path: $!";
}
sub read_file {
my ($path) = @_;
return '' unless -f $path;
open(my $fh, '<', $path) or die "$path: $!";
local $/;
return <$fh> // '';
}
sub public_identity {
my ($path) = @_;
my @fields = split /\s+/, read_file($path);
return join(' ', @fields[0, 1]) if @fields >= 2;
return '';
}
my @types = qw(dsa rsa ecdsa ed25519);
for my $type (@types) {
my $rc = system('/usr/bin/ssh-keygen', '-q', '-t', $type, '-f', "$tmp/keys/$type", '-N', '', '-C', '');
BAIL_OUT("native ssh-keygen cannot generate disposable $type fixture") if $rc;
}
for my $name (qw(remoteshell xcatlib.sh remoteshell-sshd-config)) {
copy("$source/xCAT/postscripts/$name", "$tmp/bin/$name") or die $!;
chmod 0755, "$tmp/bin/$name";
}
write_file("$tmp/bin/namespace", <<'SH');
#!/bin/bash
set -e
mount --make-rprivate /
mount --bind "$XCAT_KEY_FIXTURE/etc" /etc
mount --bind "$XCAT_KEY_FIXTURE/root" /root
mount --bind "$XCAT_KEY_FIXTURE/tmp" /tmp
exec "$@"
SH
write_file("$tmp/bin/getcredentials.awk", <<'SH');
#!/bin/bash
case "$1" in
ssh_dsa_hostkey) cat "$XCAT_KEY_INPUT/dsa" ;;
ssh_rsa_hostkey) cat "$XCAT_KEY_INPUT/rsa" ;;
ssh_ecdsa_hostkey) cat "$XCAT_KEY_INPUT/ecdsa" ;;
ssh_ed25519_hostkey) cat "$XCAT_KEY_INPUT/ed25519" ;;
ssh_root_pub_key) cat "$XCAT_KEY_INPUT/rsa.pub" ;;
*) printf '<error>unexpected credential request</error>\n'; exit 1 ;;
esac
SH
write_file("$tmp/bin/allowcred.awk", "#!/bin/sh\nexec /bin/sleep 60\n");
write_file("$tmp/bin/logger", "#!/bin/sh\nprintf '%s\\n' \"\$*\" >> \"\$XCAT_KEY_FIXTURE/logger.log\"\n");
write_file("$tmp/bin/systemctl", "#!/bin/sh\nprintf '%s\\n' \"\$*\" >> \"\$XCAT_KEY_FIXTURE/services.log\"\nexit 0\n");
write_file("$tmp/bin/sleep", "#!/bin/sh\nexit 0\n");
for my $command (qw(chown chmod)) {
write_file("$tmp/bin/$command", "#!/bin/bash\n" .
'if [ "$XCAT_KEY_FAIL_COMMAND" = "${0##*/}" ] && [[ "${!#}" = "/etc/ssh/ssh_host_${XCAT_KEY_FAIL_TYPE}_key" ]]; then exit 42; fi' . "\n" .
'exec /usr/bin/' . $command . ' "$@"' . "\n");
}
for my $name (qw(namespace getcredentials.awk allowcred.awk logger systemctl sleep chown chmod)) {
chmod 0755, "$tmp/bin/$name";
}
for my $case (
['native fresh', 'openeuler24.03sp3', 'openEuler', 1, 0],
['native existing', 'openeuler20.03sp4', 'openEuler', 1, 1],
['native no ssh_keys group', 'openeuler24.03', 'openEuler', 0, 1],
['native os-release fallback', '', 'openEuler', 1, 1],
['legacy with ssh_keys group', 'rhels9.6', 'rhel', 1, 0],
['legacy without ssh_keys group', 'rhels9.6', 'rhel', 0, 0],
['native chmod failure', 'openeuler24.03sp3', 'openEuler', 1, 1, 'chmod', 'dsa'],
['native chown failure', 'openeuler24.03sp3', 'openEuler', 1, 1, 'chown', 'ed25519'],
) {
my ($label, $osver, $id, $group, $existing, $fail_command, $fail_type) = @$case;
my $fixture = tempdir(DIR => $tmp, CLEANUP => 1);
make_path(map { "$fixture/$_" } qw(etc/ssh root tmp));
write_file("$fixture/etc/passwd", "root:x:0:0:root:/root:/bin/bash\n");
write_file("$fixture/etc/group", "root:x:0:\n" . ($group ? "ssh_keys:x:4242:\n" : ''));
write_file("$fixture/etc/nsswitch.conf", "passwd: files\ngroup: files\n");
write_file("$fixture/etc/os-release", "ID=$id\n");
write_file("$fixture/etc/ssh/sshd_config", "Port 22\n");
write_file("$fixture/etc/ssh/ssh_config", "Host *\n");
for my $type (@types) {
next unless $existing;
my $key = "$fixture/etc/ssh/ssh_host_${type}_key";
copy("$tmp/keys/$type", $key) or die $!;
chmod 0640, $key;
chown 0, 4242, $key;
}
for my $run (1, 2) {
my $output;
my $rc;
{
local %ENV = (%ENV, PATH => "$tmp/bin:/usr/bin:/bin:/usr/sbin:/sbin",
OSVER => $osver, MASTER => '192.0.2.1', USEFLOWCONTROL => 'NO',
NTYPE => 'compute', ENABLESSHBETWEENNODES => 'NO', NODESETSTATE => 'netboot',
SECUREROOT => '0', ZONENAME => '', XCAT_KEY_FIXTURE => $fixture,
XCAT_KEY_INPUT => "$tmp/keys", XCAT_SSH_ETC => '/etc/ssh',
XCAT_KEY_FAIL_COMMAND => $fail_command || '', XCAT_KEY_FAIL_TYPE => $fail_type || '');
open(my $pipe, '-|', 'sh', '-c', 'exec "$@" 2>&1', 'sh',
'unshare', '-m', '--', "$tmp/bin/namespace", "$tmp/bin/remoteshell") or die $!;
$output = do { local $/; <$pipe> };
close($pipe);
$rc = $? >> 8;
}
if ($fail_command) {
is($rc, 1, "$label run $run reports failed key protection");
like(read_file("$fixture/logger.log"), qr/failed to secure .*ssh_host_${fail_type}_key/, "$label run $run identifies the failed key");
ok(!-e "$fixture/etc/ssh/ssh_host_${fail_type}_key.pub", "$label run $run stops before public key derivation");
is(read_file("$fixture/services.log"), '', "$label run $run stops before service restart");
next;
}
is($rc, 0, "$label run $run completes the full postscript");
my $native = $id eq 'openEuler';
if ($native || !$group) {
unlike($output, qr/UNPROTECTED PRIVATE KEY|bad permissions/, "$label run $run has no permission rejection");
for my $type (@types) {
my $key = "$fixture/etc/ssh/ssh_host_${type}_key";
is(sha256_hex(read_file($key)), sha256_hex(read_file("$tmp/keys/$type")), "$label run $run preserves provisioned $type identity");
is(sha256_hex(public_identity("$key.pub")), sha256_hex(public_identity("$tmp/keys/$type.pub")), "$label run $run derives the matching $type public key");
my @private = stat($key);
my @public = stat("$key.pub");
is_deeply([defined($private[2]) ? $private[2] & 0777 : undef, @private[4,5]], [0600, 0, 0], "$label run $run $type private ownership and mode");
is_deeply([defined($public[2]) ? $public[2] & 0777 : undef, $public[4]], [0644, 0], "$label run $run $type public ownership and mode");
}
} else {
my @rsa = stat("$fixture/etc/ssh/ssh_host_rsa_key");
is_deeply([$rsa[2] & 0777, @rsa[4,5]], [0640, 0, 4242], "$label run $run retains the legacy permission chain");
}
like(read_file("$fixture/services.log"), qr/^restart sshd(?:\.service)?$/m, "$label run $run reaches the service command boundary");
}
}
done_testing();
+179
View File
@@ -0,0 +1,179 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use FindBin;
use Test::More;
plan skip_all => 'requires Linux root and mount/network namespaces' unless $^O eq 'linux' && $> == 0;
plan skip_all => 'namespaces unavailable' if system('unshare -mn -- true >/dev/null 2>&1');
plan skip_all => 'requires native rsyslogd, logger, ip and ss'
if system('command -v rsyslogd logger ip ss >/dev/null');
my $source = $ENV{XCAT_SYSLOG_SOURCE_ROOT} || abs_path("$FindBin::Bin/../..");
my $tmp = tempdir(DIR => '/var/tmp', CLEANUP => !$ENV{XCAT_SYSLOG_KEEP});
diag("fixtures: $tmp") if $ENV{XCAT_SYSLOG_KEEP};
make_path("$tmp/bin");
sub write_file {
my ($path, $contents) = @_;
open(my $fh, '>', $path) or die "$path: $!";
print {$fh} $contents;
close($fh) or die "$path: $!";
}
sub read_file {
my ($path) = @_;
return '' unless -f $path;
open(my $fh, '<', $path) or die "$path: $!";
local $/;
return <$fh> // '';
}
for my $name (qw(syslog xcatlib.sh)) {
copy("$source/xCAT/postscripts/$name", "$tmp/bin/$name") or die $!;
}
write_file("$tmp/bin/systemctl", <<'SH');
#!/bin/bash
printf '%s\n' "$*" >> "$XCAT_SYSLOG_FIXTURE/services.log"
[ "$XCAT_SYSLOG_FAIL" = restart ] && exit 42
[ "$1" = restart ] || exit 43
if [ -s /run/rsyslog-test.pid ]; then
kill "$(cat /run/rsyslog-test.pid)"
for i in {1..50}; do [ -f /run/rsyslog-test.pid ] || break; sleep .1; done
fi
exec /usr/sbin/rsyslogd -i /run/rsyslog-test.pid -f /etc/rsyslog.conf
SH
write_file("$tmp/bin/logger", <<'SH');
#!/bin/bash
printf '%s\n' "$*" >> "$XCAT_SYSLOG_FIXTURE/logger.log"
SH
write_file("$tmp/bin/namespace", <<'SH');
#!/bin/bash
set -eu
mount --make-rprivate /
mount --bind "$XCAT_SYSLOG_FIXTURE/etc" /etc
mount --bind "$XCAT_SYSLOG_FIXTURE/log" /var/log
mount --bind "$XCAT_SYSLOG_FIXTURE/run" /run
mount --bind "$XCAT_SYSLOG_FIXTURE/state" /var/lib/rsyslog
ip link set lo up
trap 'for f in /run/*pid; do [ ! -f "$f" ] || kill "$(cat "$f")" 2>/dev/null || :; done' EXIT
/usr/sbin/rsyslogd -i /run/upstream.pid -f "$XCAT_SYSLOG_FIXTURE/upstream.conf"
for pass in 1 2; do
set +e
bash "$XCAT_SYSLOG_BIN/syslog" > "$XCAT_SYSLOG_FIXTURE/postscript-$pass.log" 2>&1
rc=$?
set -e
echo "$rc" > "$XCAT_SYSLOG_FIXTURE/postscript-$pass.rc"
cp /etc/rsyslog.conf "$XCAT_SYSLOG_FIXTURE/config-$pass"
cp /etc/rsyslog.d/remote.conf "$XCAT_SYSLOG_FIXTURE/remote-$pass" 2>/dev/null || :
[ "$rc" -eq 0 ] || break
done
set +e
/usr/sbin/rsyslogd -N1 -f /etc/rsyslog.conf > "$XCAT_SYSLOG_FIXTURE/parser.log" 2>&1
echo "$?" > "$XCAT_SYSLOG_FIXTURE/parser.rc"
set -e
ss -H -lun 'sport = :514' > "$XCAT_SYSLOG_FIXTURE/udp-514"
ss -H -ltn 'sport = :514' > "$XCAT_SYSLOG_FIXTURE/tcp-514"
if [ -s "$XCAT_SYSLOG_FIXTURE/udp-514" ]; then
/usr/bin/logger -n 127.0.0.1 -P 514 -d -t xcat-syslog-test 'xcat-native-udp-proof'
fi
if [ -s "$XCAT_SYSLOG_FIXTURE/tcp-514" ]; then
/usr/bin/logger -n 127.0.0.1 -P 514 -T -t xcat-syslog-test 'xcat-native-tcp-proof'
fi
if [ "$XCAT_SYSLOG_ROLE" = cn ]; then
/usr/bin/logger -n 127.0.0.1 -P 1515 -d -t xcat-syslog-test 'xcat-native-cn-proof'
fi
for i in {1..30}; do
if [ "$XCAT_SYSLOG_ROLE" = cn ]; then
grep -q xcat-native-cn-proof /var/log/upstream 2>/dev/null && break
else
grep -q xcat-native-tcp-proof /var/log/messages /var/log/upstream 2>/dev/null && break
fi
sleep .1
done
SH
chmod 0755, "$tmp/bin/$_" for qw(systemctl logger namespace);
my $default = read_file('/etc/rsyslog.conf');
my $minimal = "global(workDirectory=\"/var/lib/rsyslog\")\ninclude(file=\"/etc/rsyslog.d/*.conf\" mode=\"optional\")\n*.info /var/log/messages\n";
my $modern = "module(\n load=\"imudp\"\n)\ninput(\n address=\"127.0.0.1\"\n port=\"514\"\n type=\"imudp\"\n)\nmodule(load=\"imtcp\")\ninput(type=\"imtcp\" address=\"127.0.0.1\" port=\"514\")\n";
my $legacy = "\$ModLoad imudp\n\$UDPServerRun 514\n\$ModLoad imtcp\n\$InputTCPServerRun 514\n";
my @cases = (
['native default MN', 'mn', 'openeuler24.03', $default],
['native default SN local', 'snlocal', 'openeuler24.03', $default],
['native default SN forwarding', 'snforward', 'openeuler24.03', $default],
['native CN forwarding', 'cn', 'openeuler24.03', $minimal],
['native os-release fallback', 'mn', '', $minimal],
['native nested modern admin', 'mn', 'openeuler24.03', $minimal, $modern],
['native same-line admin', 'mn', 'openeuler24.03', $minimal, "module(load=\"imudp\") input(type=\"imudp\" port=\"514\")\nmodule(load=\"imtcp\") input(type=\"imtcp\" port=\"514\")\n"],
['native quoted close admin', 'mn', 'openeuler24.03', $minimal, "module(load=\"imudp\")\ninput(type=\"imudp\" name=\"admin)receiver\" port=\"514\")\nmodule(load=\"imtcp\")\ninput(type=\"imtcp\" port=\"514\")\n"],
['native quoted attribute data', 'mn', 'openeuler24.03', $minimal, "module(load=\"imudp\")\ninput(type=\"imudp\" name=\"type='imudp',port='514'\" port=\"1515\")\nmodule(load=\"imtcp\")\ninput(type=\"imtcp\" port=\"514\")\n"],
['native legacy admin', 'snlocal', 'openeuler24.03', $minimal, $legacy],
['native module without listener', 'mn', 'openeuler24.03', $minimal, "module(load=\"imudp\")\nmodule(load=\"imtcp\")\n"],
['native commented admin', 'mn', 'openeuler24.03', $minimal, join('', map { "#$_\n" } split /\n/, $modern)],
['native block comments', 'mn', 'openeuler24.03', $minimal, "/*\n$modern*/\n"],
['legacy commented examples', 'mn', 'rhels9.6', $minimal . join('', map { "#$_\n" } split /\n/, $legacy)],
['legacy no examples', 'mn', 'rhels9.6', $minimal],
['native invalid configuration', 'mn', 'openeuler24.03', $minimal . "invalid_rsyslog_directive()\n", '', 'parser'],
['native restart failure', 'mn', 'openeuler24.03', $minimal, '', 'restart'],
);
my $number = 0;
for my $case (@cases) {
my ($name, $role, $osver, $config, $admin, $failure) = @$case;
$admin //= ''; $failure //= '';
my $fixture = "$tmp/" . ++$number;
make_path(map { "$fixture/$_" } qw(etc/rsyslog.d etc/admin log run state));
write_file("$fixture/etc/os-release", 'ID="' . ($osver =~ /^rhels/ ? 'rhel' : 'openEuler') . "\"\n");
write_file("$fixture/etc/xCATMN", '') if $role eq 'mn';
if ($admin ne '') {
write_file("$fixture/etc/rsyslog.d/admin.conf", "include(file=\"/etc/admin/receiver.conf\")\n");
write_file("$fixture/etc/admin/receiver.conf", $admin);
}
if ($role eq 'cn') {
write_file("$fixture/etc/rsyslog.d/admin.conf", "module(load=\"imudp\")\ninput(type=\"imudp\" port=\"1515\")\n");
}
write_file("$fixture/etc/rsyslog.conf", $config);
write_file("$fixture/upstream.conf", "module(load=\"imudp\")\ninput(type=\"imudp\" port=\"1514\")\n*.* /var/log/upstream\n");
local %ENV = (%ENV, PATH => "$tmp/bin:$ENV{PATH}", XCAT_SYSLOG_FIXTURE => $fixture,
XCAT_SYSLOG_BIN => "$tmp/bin", XCAT_SYSLOG_FAIL => $failure, XCAT_SYSLOG_ROLE => $role,
OSVER => $osver, NTYPE => ($role =~ /^sn/ ? 'service' : 'compute'),
SVLOGLOCAL => ($role eq 'snlocal' ? 1 : 0), MASTER => '127.0.0.1:1514', SYSLOG => '');
is(system('unshare', '-mn', '--', "$tmp/bin/namespace"), 0, "$name: isolated driver completed");
my $rc = read_file("$fixture/postscript-1.rc");
chomp $rc;
if ($failure) {
isnt($rc, 0, "$name: failure reaches postscript exit");
is(read_file("$fixture/logger.log"), '', "$name: no success log");
is(read_file("$fixture/services.log"), '', "$name: invalid configuration is not restarted") if $failure eq 'parser';
next;
}
is($rc, 0, "$name: first postscript succeeds");
my $repeat = read_file("$fixture/postscript-2.rc");
chomp $repeat;
is($repeat, 0, "$name: repeat succeeds");
is(read_file("$fixture/config-2"), read_file("$fixture/config-1"), "$name: main configuration is repeatable");
is(read_file("$fixture/remote-2"), read_file("$fixture/remote-1"), "$name: forwarding configuration is repeatable");
is(0 + read_file("$fixture/parser.rc"), 0, "$name: native parser accepts result");
is(read_file("$fixture/etc/admin/receiver.conf"), $admin, "$name: administrator include preserved");
if ($name =~ /^native (nested modern|same-line|quoted close|legacy) admin$/) {
unlike(read_file("$fixture/config-2"), qr/^(?:module|input)\(/m,
"$name: existing administrator receivers need no duplicate declarations");
}
my $receives = $role ne 'cn' && $name ne 'legacy no examples';
for my $protocol (qw(udp tcp)) {
is(!!length(read_file("$fixture/$protocol-514")), !!$receives, "$name: $protocol listener matches role");
if ($receives) {
my $destination = $role eq 'snforward' ? 'upstream' : 'messages';
like(read_file("$fixture/log/$destination"), qr/xcat-native-$protocol-proof/, "$name: real $protocol traffic reaches $destination");
}
}
if ($role eq 'cn') {
like(read_file("$fixture/log/upstream"), qr/xcat-native-cn-proof/, "$name: real CN traffic forwards");
}
my $remote = read_file("$fixture/etc/rsyslog.d/remote.conf");
if ($role eq 'cn' || $role eq 'snforward') {
like($remote, qr/^\*\.\* \@127\.0\.0\.1:1514$/m, "$name: master forwarding retained");
} else {
unlike($remote, qr/^\*\.\* \@/m, "$name: local logs are not forwarded");
}
}
done_testing();
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use FindBin;
use Test::More;
plan skip_all => 'requires Linux root and mount/network namespaces' unless $^O eq 'linux' && $> == 0;
plan skip_all => 'namespaces unavailable' if system('unshare -mn -- true >/dev/null 2>&1');
plan skip_all => 'requires native rsyslogd, systemctl, systemd-detect-virt and chroot'
if system('command -v rsyslogd systemctl systemd-detect-virt chroot >/dev/null');
my $source = $ENV{XCAT_SYSLOG_SOURCE_ROOT} || abs_path("$FindBin::Bin/../..");
my $tmp = tempdir(DIR => '/var/tmp', CLEANUP => !$ENV{XCAT_SYSLOG_KEEP});
diag("fixtures: $tmp") if $ENV{XCAT_SYSLOG_KEEP};
make_path("$tmp/bin");
sub write_file {
my ($path, $text) = @_;
open(my $fh, '>', $path) or die "$path: $!";
print {$fh} $text;
close($fh) or die "$path: $!";
}
sub read_file {
my ($path) = @_;
return '' unless -f $path;
open(my $fh, '<', $path) or die "$path: $!";
local $/;
return <$fh> // '';
}
for my $name (qw(syslog xcatlib.sh)) {
copy("$source/xCAT/postscripts/$name", "$tmp/bin/$name") or die $!;
}
write_file("$tmp/bin/systemctl", <<'SH');
#!/bin/bash
printf '%s\n' "$*" >> "/evidence/services-$XCAT_SYSLOG_PHASE.log"
/usr/bin/systemctl "$@" > "/evidence/systemctl-$XCAT_SYSLOG_PHASE.log" 2>&1
rc=$?
echo "$rc" > "/evidence/systemctl-$XCAT_SYSLOG_PHASE.rc"
cat "/evidence/systemctl-$XCAT_SYSLOG_PHASE.log"
exit "$rc"
SH
write_file("$tmp/bin/logger", <<'SH');
#!/bin/bash
printf '%s\n' "$*" >> /evidence/logger.log
SH
write_file("$tmp/bin/run", <<'SH');
#!/bin/bash
set -eu
mount --make-rprivate /
root="$XCAT_SYSLOG_FIXTURE/root"
for path in usr bin sbin lib lib64; do
[ -d "/$path" ] || continue
mount --bind "/$path" "$root/$path"
mount -o remount,bind,ro "$root/$path"
done
mount --bind "$XCAT_SYSLOG_BIN" "$root/postscripts"
mount -o remount,bind,ro "$root/postscripts"
mount --bind "$XCAT_SYSLOG_FIXTURE/evidence" "$root/evidence"
mount -t proc -o ro proc "$root/proc"
mount -t tmpfs -o mode=755,nosuid tmpfs "$root/dev"
touch "$root/dev/null"
mount --bind /dev/null "$root/dev/null"
set +e
chroot "$root" /usr/bin/systemd-detect-virt --quiet --chroot > "$XCAT_SYSLOG_FIXTURE/evidence/detect.log" 2>&1
echo "$?" > "$XCAT_SYSLOG_FIXTURE/evidence/detect.rc"
chroot "$root" /usr/bin/env PATH=/postscripts:/usr/sbin:/usr/bin:/sbin:/bin XCAT_SYSLOG_PHASE=baseline \
/bin/bash -c '. /postscripts/xcatlib.sh; restartservice syslog' > "$XCAT_SYSLOG_FIXTURE/evidence/helper.log" 2>&1
echo "$?" > "$XCAT_SYSLOG_FIXTURE/evidence/helper.rc"
for pass in 1 2; do
chroot "$root" /usr/bin/env PATH=/postscripts:/usr/sbin:/usr/bin:/sbin:/bin XCAT_SYSLOG_PHASE=postscript \
/bin/bash /postscripts/syslog > "$XCAT_SYSLOG_FIXTURE/evidence/postscript-$pass.log" 2>&1
rc=$?
echo "$rc" > "$XCAT_SYSLOG_FIXTURE/evidence/postscript-$pass.rc"
[ "$rc" -eq 0 ] || break
done
chroot "$root" /usr/sbin/rsyslogd -N1 -f /etc/rsyslog.conf > "$XCAT_SYSLOG_FIXTURE/evidence/parser.log" 2>&1
echo "$?" > "$XCAT_SYSLOG_FIXTURE/evidence/parser.rc"
exit 0
SH
chmod 0755, "$tmp/bin/$_" for qw(systemctl logger run);
my $minimal = "global(workDirectory=\"/var/lib/rsyslog\")\ninclude(file=\"/etc/rsyslog.d/*.conf\" mode=\"optional\")\n*.info /var/log/messages\n";
for my $case (['mn', 0], ['snlocal', 0], ['snforward', 0], ['cn', 0], ['mn', 1], ['cn', 1]) {
my ($role, $invalid) = @$case;
my $name = "$role " . ($invalid ? 'invalid' : 'valid') . ' native chroot';
my $fixture = "$tmp/$role-$invalid";
make_path("$fixture/evidence", map { "$fixture/root/$_" }
qw(usr bin sbin lib lib64 postscripts evidence proc dev run tmp etc/rsyslog.d var/log var/lib/rsyslog));
copy('/etc/ld.so.cache', "$fixture/root/etc/ld.so.cache") or die $!;
write_file("$fixture/root/etc/os-release", "ID=openEuler\n");
write_file("$fixture/root/etc/xCATMN", '') if $role eq 'mn';
write_file("$fixture/root/etc/rsyslog.conf", $minimal . ($invalid ? "invalid_rsyslog_directive()\n" : ''));
local %ENV = (%ENV, XCAT_SYSLOG_FIXTURE => $fixture, XCAT_SYSLOG_BIN => "$tmp/bin",
OSVER => ($ENV{XCAT_SYSLOG_OSVER} || 'openeuler24.03'), NTYPE => ($role =~ /^sn/ ? 'service' : 'compute'),
SVLOGLOCAL => ($role eq 'snlocal' ? 1 : 0), MASTER => '127.0.0.1:1514', SYSLOG => '');
is(system('unshare', '-mn', '--', "$tmp/bin/run"), 0, "$name: isolated driver completed");
my $evidence = "$fixture/evidence";
is(read_file("$evidence/detect.rc"), "0\n", "$name: native helper detects the actual chroot");
is(read_file("$evidence/systemctl-baseline.rc"), "0\n", "$name: actual systemctl defers successfully");
like(read_file("$evidence/systemctl-baseline.log"), qr/Running in chroot,\s*ignoring/i,
"$name: native systemctl identifies service deferral");
is(read_file("$evidence/helper.rc"), "1\n", "$name: shared restart helper retains its existing contract");
is(read_file("$evidence/services-postscript.log"), '', "$name: postscript does not attempt service activation");
if ($invalid) {
isnt(read_file("$evidence/postscript-1.rc"), "0\n", "$name: parser failure reaches the postscript exit");
isnt(read_file("$evidence/parser.rc"), "0\n", "$name: actual native parser rejects the configuration");
is(read_file("$evidence/logger.log"), '', "$name: no success log follows invalid configuration");
} else {
is(read_file("$evidence/postscript-1.rc"), "0\n", "$name: configuration completes successfully");
is(read_file("$evidence/postscript-2.rc"), "0\n", "$name: repeated configuration succeeds");
is(read_file("$evidence/parser.rc"), "0\n", "$name: actual native parser accepts the result");
like(read_file("$evidence/logger.log"), qr/rsyslog version 8 setup/, "$name: completed configuration is logged");
}
}
done_testing();