2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-10-15 08:12:03 +00:00

Merge pull request #84 from VersatusHPC/fix/openeuler-ppc64le-manifest-ipxe

fix(xcat-dep): openEuler ppc64le has no ipxe-xcat and xCAT cannot install
This commit is contained in:
Daniel Hilst
2026-10-08 11:20:37 -03:00
committed by GitHub
11 changed files with 263 additions and 32 deletions
@@ -78,6 +78,8 @@ jobs:
sudo -E prove -v -It/lib t/common-repo-gate.t
prove -v t/openeuler.t
prove -v t/openeuler_mock_template_include.t
prove -v t/openeuler_native_result_permissions.t
prove -v -Ilib t/openeuler_native_procenv_plugin.t
prove -v -Ilib t/openeuler_native_trust_dbpath.t
prove -v -Ilib t/openeuler_native_cpio_scan.t
bats t/verify-xcatsn-install.bats
+21
View File
@@ -25,6 +25,7 @@ our @EXPORT_OK = qw(
cross_copy_genesis finalize_xcat_dep bump_dep_release_suffix
createrepo_c_cmd sign_and_index_repo
build_mock_uniqueext rpm_in_cell resolve_mock_cfg
native_owner_command NATIVE_BUILD_GID
openeuler_build_target openeuler_repo_subdir
recover_common_repository
);
@@ -101,6 +102,26 @@ sub sh_quote {
return "'$s'";
}
# The host group the native openEuler builds run as: xcatnative, gid 1000. The native mock overlays
# set chrootgid to it and chrootuid to the catalog's build_uid, so mock creates --resultdir and opens
# state.log, build.log and root.log in it as that uid and group.
use constant NATIVE_BUILD_GID => 1000;
# native_owner_command: wrap a native build step so it runs against $overlay instead of the target's
# own mock configuration, and with the identity mock will write results as.
#
# A dep builder makes its own result directories before mock starts -- ipxe-xcat/mockbuild.pl calls
# make_path on $work_dir/srpm and $work_dir/rpm and passes each one to mock as --resultdir. The
# script runs as root, so without the gid and the umask below those directories are root root 0755
# and mock, reloaded to chrootuid 1000, cannot open its logs in them.
sub native_owner_command {
my ($overlay, $mock_cfg, $command) = @_;
my $script = 'umask 0002 && mount --bind ' . sh_quote($overlay) . ' ' . sh_quote($mock_cfg)
. ' && exec sh -c ' . sh_quote($command);
return 'unshare --mount --propagation private -- setpriv --regid ' . NATIVE_BUILD_GID
. ' --clear-groups -- sh -c ' . sh_quote($script);
}
# print_step: print a step banner.
sub print_step {
my ($msg) = @_;
+42 -2
View File
@@ -14,7 +14,7 @@ use File::Temp qw(tempdir);
use JSON::PP;
our @EXPORT_OK = qw(load_inputs stage_inputs verify_input rpm_identity validate_outputs publisher_trust
trust_dbpath scan_cpio_for_elf);
trust_dbpath scan_cpio_for_elf native_overlay_text);
sub read_file {
my ($path) = @_;
@@ -79,7 +79,7 @@ sub load_inputs {
die "Invalid native input type '$type'\n" unless $type =~ /\A(?:srpm|publisher|owner)\z/;
if ($type eq 'owner') {
die "Unsupported native build owner '$name'\n" unless grep { $_ eq $name }
qw(goconserver grub2-xcat ipmitool-xcat syslinux-xcat xnba-undi xCAT-genesis-base
qw(goconserver grub2-xcat ipmitool-xcat ipxe-xcat syslinux-xcat xnba-undi xCAT-genesis-base
perl-Crypt-Rijndael perl-Crypt-SSLeay perl-HTTP-Async perl-IO-Stty perl-Net-HTTPS-NB perl-Net-Telnet);
}
if ($type ne 'publisher') {
@@ -300,4 +300,44 @@ sub validate_outputs {
return \%seen;
}
#-------------------------------------------------------------------------------
=head3 native_overlay_text
Descriptions: Render one native mock overlay configuration.
Arguments:
$purpose - 1000, 0 or 'procenv'. 'procenv' is the overlay that builds
procenv itself.
$base - path of the snapshotted base mock configuration to include.
$prereqs - path of the local repository holding the built prerequisites.
Returns: the overlay file content.
=cut
#-------------------------------------------------------------------------------
sub native_overlay_text {
my ($purpose, $base, $prereqs) = @_;
my $bootstrap = $purpose eq 'procenv';
my $uid = $bootstrap ? 1000 : $purpose;
my $url = $prereqs;
$url =~ s{([^A-Za-z0-9_./~-])}{sprintf('%%%02X', ord($1))}ge;
my $repo = "\n[xcat-native-inputs]\nname=xCAT native build prerequisites\nbaseurl=file://$url\n"
. "gpgkey=file://$url/repodata/repomd.xml.key\ngpgcheck=1\nrepo_gpgcheck=1\n"
. "enabled=1\nskip_if_unavailable=0\n";
my $out = 'include(' . JSON::PP->new->encode($base) . ")\n";
$out .= "config_opts['chrootuid'] = $uid\nconfig_opts['chrootgid'] = 1000\n";
$out .= "config_opts['dnf.conf'] += \"\"\"$repo\"\"\"\n";
$out .= "config_opts['plugin_conf']['bind_mount_enable'] = True\n";
# mock's procenv plugin runs the HOST's /usr/bin/procenv, not the chroot's, and it installs
# procenv into the buildroot itself through preexisting_deps. Enabling it made every native
# build need a host package neither repository declares, for a log nothing reads. mock's
# default is off; leave it there.
$out .= "config_opts['plugin_conf']['procenv_enable'] = False\n";
$out .= "config_opts['plugin_conf']['bind_mount_opts']['dirs'].append("
. '(' . JSON::PP->new->encode($prereqs) . ', ' . JSON::PP->new->encode($prereqs) . "))\n";
return $out;
}
1;
+41 -22
View File
@@ -19,6 +19,7 @@ use FindBin qw($RealBin);
use lib $RealBin, "$RealBin/lib";
use XCAT::NFSLock ();
use MockBuildUtils qw(sh_quote print_step version_matches required_pkgs rpm_in_cell resolve_mock_cfg
NATIVE_BUILD_GID
carry_over_rpms rpm_name rpm_arch rpm_source_rpm rpm_digests_ok
install_deps_packages install_deps_command missing_perl_modules
read_manifest derive_target_from_repo_path
@@ -156,6 +157,21 @@ my @HELD_LOCKS;
my $LOCK_OWNER_PID;
my ($COMMON_STAGE, $COMMON_DESTINATION, $COMMON_BACKUP);
my %NATIVE_PLANS;
# Create a directory mock writes for a native build. mock 6.8 reloads its uid manager from
# chrootuid, so it creates --resultdir and opens state.log, build.log and root.log in it as
# chrootuid/chrootgid, not as the user that started mock. This script runs as root, so such a
# directory carries the native build gid and is group writable. native_owner_command gives the step
# the same gid and a 0002 umask, so what the step creates below it inherits both.
sub make_native_path {
my ($native, @dirs) = @_;
make_path(@dirs);
return unless $native;
for my $dir (@dirs) {
chown -1, NATIVE_BUILD_GID, $dir or die "Cannot set the native build group on $dir: $!\n";
chmod 0775, $dir or die "Cannot make $dir writable by the native build group: $!\n";
}
}
for my $sig (qw(INT TERM HUP)) {
$SIG{$sig} = sub { exit 1; };
}
@@ -739,6 +755,7 @@ if (!$skip_build) {
my $script = $builder->{script};
my $step_result = "$build_root/$name";
my $step_log = "$log_root/$name";
make_native_path($native, $step_result) if $native && !$dry_run;
my $step_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, $name);
my $mock_cfg = $builder->{noarch} ? $profile->{noarch_cfg} : $target;
my $cmd = $builder->{srpm}
@@ -778,6 +795,7 @@ if (!$skip_build) {
if (!$skip_perl && @perl_pkgs) {
my $perl_result = "$build_root/perl/$arch";
my $perl_log = "$log_root/perl/$arch";
make_native_path($native, $perl_result) if $native && !$dry_run;
my $perl_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, 'perl-list6');
# Bound the perl builder's OWN internal parallelism to this target's budget; otherwise it
# forks one mock build per perl package (~7), which -- multiplied by parallel EL targets --
@@ -858,7 +876,8 @@ if (!$skip_build) {
'--gpg-home', shell_quote(File::Spec->rel2abs($gpg_home ne '' ? $gpg_home
: $ENV{GNUPGHOME} || "$ENV{HOME}/.gnupg"))) : ()),
);
$cmd = native_owner_command($native, $target, $cmd, 0) if $native;
$cmd = native_owner_command($native, $target, $cmd,
$native->{nodes}{'xCAT-genesis-base'}{build_uid}) if $native;
push @build_steps, {
id => 'genesis',
step => 'Build xCAT-genesis-base (per-target, OS-dependent)',
@@ -873,7 +892,8 @@ if (!$skip_build) {
if (@build_steps) {
if ($native) {
for my $step (grep { $_->{id} ne 'genesis' } @build_steps) {
$step->{cmd} = native_owner_command($native, $target, $step->{cmd}, 1000);
$step->{cmd} = native_owner_command($native, $target, $step->{cmd},
native_step_build_uid($native, $step));
}
}
# Prefer the caller-supplied cap (global budget / active targets). Fall back to the old
@@ -1147,8 +1167,8 @@ sub target_profile {
noarch_cfg => $target,
forcearch => 0,
epel => 0,
dep_builders => [qw(grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi python3-scp)],
required => [qw(ipmitool-xcat syslinux-xcat grub2-xcat xnba-undi
dep_builders => [qw(grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi ipxe-xcat python3-scp)],
required => [qw(ipmitool-xcat syslinux-xcat grub2-xcat xnba-undi ipxe-xcat
perl-IO-Stty perl-HTTP-Async perl-Net-HTTPS-NB)],
};
}
@@ -1200,9 +1220,10 @@ sub install_mock_cfg {
sub source_rpm_build_command {
my ($builder, $target, $uniqueext, $result, $log, $work) = @_;
my $native = $NATIVE_PLANS{$target};
my $cfg = "$work/mock-deterministic.cfg";
if (!$dry_run) {
make_path($work, $result);
make_native_path($native, $work, $result);
open my $fh, '>', $cfg or die "Cannot write $cfg: $!\n";
print {$fh} "include('/etc/mock/$target.cfg')\n";
print {$fh} "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$SOURCE_DATE_EPOCH'\n";
@@ -1234,7 +1255,7 @@ sub source_rpm_build_command {
. ' -i ' . sh_quote($path), log => "$log/spec-patch.log");
}
my $restamped = "$work/restamp-srpm";
make_path($restamped) unless $dry_run;
make_native_path($native, $restamped) unless $dry_run;
$prefix = "$mock --buildsrpm --spec " . sh_quote($specs[0])
. ' --sources ' . sh_quote("$top/SOURCES") . ' --resultdir ' . sh_quote($restamped)
. ' && set -- ' . sh_quote($restamped) . '/*.src.rpm'
@@ -1244,12 +1265,21 @@ sub source_rpm_build_command {
return $prefix . "$mock --rebuild $srpm --resultdir " . sh_quote($result);
}
# The uid a step builds as, from the catalog. xnba-undi declares 0, like xCAT-genesis-base, and the
# step id does not say so: reading the uid off the id built it as 1000 against its own declaration.
sub native_step_build_uid {
my ($plan, $step) = @_;
my %uids = map { ($plan->{nodes}{$_}{build_uid} // 1000) => 1 }
sort keys %{$step->{native_results} // {}};
die "Step $step->{id} mixes native build uids: " . join(', ', sort keys %uids) . "\n"
if keys(%uids) > 1;
return (keys %uids)[0] // 1000;
}
sub native_owner_command {
my ($plan, $target, $command, $uid) = @_;
my $overlay = $plan->{overlays}{$uid} // die "Missing native mock overlay\n";
my $script = 'mount --bind ' . sh_quote($overlay) . ' ' . sh_quote("/etc/mock/$target.cfg")
. ' && exec sh -c ' . sh_quote($command);
return 'unshare --mount --propagation private -- sh -c ' . sh_quote($script);
return MockBuildUtils::native_owner_command($overlay, "/etc/mock/$target.cfg", $command);
}
sub native_overlay {
@@ -1259,21 +1289,9 @@ sub native_overlay {
return if $dry_run;
my $base = "$work/native-base.cfg";
copy("/etc/mock/$target.cfg", $base) or die "Cannot snapshot native mock configuration: $!\n";
my $url = $prereqs;
$url =~ s{([^A-Za-z0-9_./~-])}{sprintf('%%%02X', ord($1))}ge;
my $repo = "\n[xcat-native-inputs]\nname=xCAT native build prerequisites\nbaseurl=file://$url\n"
. "gpgkey=file://$url/repodata/repomd.xml.key\ngpgcheck=1\nrepo_gpgcheck=1\n"
. "enabled=1\nskip_if_unavailable=0\n";
for my $key (1000, 0, 'procenv') {
my $uid = $key eq 'procenv' ? 1000 : $key;
open my $fh, '>', $plan->{overlays}{$key} or die "Cannot write native overlay: $!\n";
print {$fh} 'include(' . JSON::PP->new->encode($base) . ")\n";
print {$fh} "config_opts['chrootuid'] = $uid\nconfig_opts['chrootgid'] = 1000\n";
print {$fh} "config_opts['dnf.conf'] += \"\"\"$repo\"\"\"\n";
print {$fh} "config_opts['plugin_conf']['bind_mount_enable'] = True\n";
print {$fh} "config_opts['plugin_conf']['procenv_enable'] = " . ($key eq 'procenv' ? 'False' : 'True') . "\n";
print {$fh} "config_opts['plugin_conf']['bind_mount_opts']['dirs'].append("
. '(' . JSON::PP->new->encode($prereqs) . ', ' . JSON::PP->new->encode($prereqs) . "))\n";
print {$fh} XCAT::NativeInputs::native_overlay_text($key, $base, $prereqs);
close $fh or die "Cannot close native overlay: $!\n";
}
open my $ledger, '>', "$work/native-overlays.json" or die "Cannot record native overlays: $!\n";
@@ -1305,6 +1323,7 @@ sub build_native_inputs {
my $node = $plan->{nodes}{$name};
next unless $node->{type} eq 'srpm';
my $result = "$work/native-results/$name";
make_native_path($plan, "$work/native-results") unless $dry_run;
my $log = "$logs/native/$name";
my $uniqueext = build_mock_uniqueext("$target-$run_id", ++$sequence, $name);
my %builder = (%$node, srpm => $node->{staged} // "$work/native-inputs/$name/" . basename($node->{url}));
+29 -6
View File
@@ -1,13 +1,36 @@
#!/usr/bin/python3
import json, os, pathlib, shutil, sys
import mockbuild
from mockbuild.util import load_config
from mockbuild.config import load_config
args = sys.argv[1:]
call = {'mock': args}
config = None
def value(name): return args[args.index(name)+1]
def resultdir(path):
"""Create --resultdir and open its logs the way mock does.
mock 6.8 reloads its uid manager from chrootuid, so it creates --resultdir and opens
state.log, build.log and root.log in it as that uid, not as the user that started mock.
"""
uid, gid = config['chrootuid'], config['chrootgid']
pid = os.fork()
if pid == 0:
try:
if os.geteuid() == 0:
os.setregid(gid, gid)
os.setresuid(uid, uid, 0)
os.makedirs(path, exist_ok=True)
for name in ('state.log', 'build.log', 'root.log'):
open(os.path.join(path, name), 'a+').close()
except OSError as why:
print('mock: %s' % why, file=sys.stderr)
os._exit(1)
os._exit(0)
if os.waitpid(pid, 0)[1] != 0:
sys.exit(1)
if '--rebuild' in args or '--buildsrpm' in args:
load_config('/etc/mock', value('-r'), None, 'native-contract',
str(pathlib.Path(mockbuild.__file__).parent))
config = load_config('/etc/mock', value('-r'))
call['config_rc'] = 0
if '--rebuild' in args:
name = pathlib.Path(value('--rebuild')).name.split('-1-1.oe2403')[0]
@@ -16,13 +39,13 @@ if '--buildsrpm' in args:
call['spec'] = pathlib.Path(value('--spec')).read_text()
with open(os.environ['NATIVE_CALLS'], 'a') as f: f.write(json.dumps(call) + '\n')
if '--buildsrpm' in args:
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
dest = pathlib.Path(value('--resultdir')); resultdir(dest)
source = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())['native-leaf'][1]
shutil.copyfile(source, dest / pathlib.Path(source).name)
sys.exit(0)
if '--rebuild' not in args: sys.exit(0)
if name == os.environ.get('NATIVE_FAIL'): sys.exit(42)
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
dest = pathlib.Path(value('--resultdir')); resultdir(dest)
if name == os.environ.get('NATIVE_EMPTY'): sys.exit(0)
fixtures = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())
for source in fixtures[name]: shutil.copyfile(source, dest / pathlib.Path(source).name)
+1 -1
View File
@@ -294,7 +294,7 @@ for my $case (['publisher-elf', qr/ELF payload/], ['publisher-arch', qr/not a no
my @namespace = ('unshare', ($> == 0 ? () : ('--user', '--map-root-user')), '--mount', '--propagation', 'private');
my $can_owner = $host_arch eq 'ppc64le'
&& run_capture("$tmp/mock-loader.log", 'python3', '-c', 'from mockbuild.util import load_config') == 0
&& run_capture("$tmp/mock-loader.log", 'python3', '-c', 'from mockbuild.config import load_config') == 0
&& run_capture("$tmp/namespace.log", @namespace, 'true') == 0;
SKIP: {
skip 'Whole native owner requires POWER, native Mock and a private mount namespace', 52 unless $can_owner;
+11
View File
@@ -1075,6 +1075,17 @@
],
"build_uid": 1000
},
{
"name": "ipxe-xcat",
"type": "owner",
"outputs": [
"ipxe-xcat"
],
"needs": [
"procenv"
],
"build_uid": 1000
},
{
"name": "xnba-undi",
"type": "owner",
+4
View File
@@ -255,6 +255,7 @@ perl-Sys-Virt=11.10.0
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
ipxe-xcat=2.0.0
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
@@ -271,6 +272,7 @@ xCAT-genesis-base=>= 2:2.18.0
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
ipxe-xcat=2.0.0
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
@@ -313,6 +315,7 @@ xCAT-genesis-base=>= 2:2.18.0
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
ipxe-xcat=2.0.0
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
@@ -327,6 +330,7 @@ xCAT-genesis-base=>= 2:2.18.0
goconserver=>= 0.3.3-snap202011021058
grub2-xcat=1.0
ipmitool-xcat=>= 1.8.18-4
ipxe-xcat=2.0.0
syslinux-xcat=>= 6.03-1
xnba-undi=>= 1.21.1-1
perl-Crypt-Rijndael=1.13
+30 -1
View File
@@ -2,7 +2,8 @@
use strict;
use warnings;
use FindBin qw($RealBin);
use lib "$RealBin/..";
use lib "$RealBin/..", "$RealBin/../lib";
use XCAT::NativeInputs qw(load_inputs);
use Test::More;
use MockBuildUtils qw(openeuler_build_target openeuler_repo_subdir install_deps_command
install_deps_packages derive_target_from_repo_path read_manifest);
@@ -55,4 +56,32 @@ for my $path (
is(derive_target_from_repo_path($path), undef, "$path has no native target");
}
# xCAT and xCATsn name the netboot loaders and the console backend as Requires on every arch, so a
# package missing from a target section is not a smaller build: it is "nothing provides <pkg>" when
# dnf installs xCAT on the management node. The EL section of the same arch is the reference set,
# because openEuler is rpm-md and installs the same core packages. Both exemptions were measured
# against the built core rpms with rpm -qp --requires, not read off a spec conditional.
my %exempt = (
'conserver-xcat' => 'xCAT requires goconserver; no core rpm requires conserver-xcat',
'elilo-xcat' => 'no core rpm requires elilo-xcat',
);
my $reference = 'alma+epel-10-ppc64le';
ok(scalar keys %{$manifest{$reference}}, "$reference is the reference section and is not empty");
for my $pkg (sort keys %{$manifest{$reference}}) {
next if $exempt{$pkg};
ok(exists $manifest{'openeuler-24.03-ppc64le'}{$pkg},
"openeuler-24.03-ppc64le declares $pkg, which $reference also declares");
}
# A manifest entry alone is not enough. The ppc64le target resolves its whole manifest through the
# native input catalog, which refuses a name no node produces, so the catalog has to declare an
# owner for the package as well.
my $plan = eval { load_inputs("$RealBin/..", $manifest{'openeuler-24.03-ppc64le'}) };
ok($plan, 'every package the ppc64le manifest requires has a native output owner') or diag($@);
# xCAT requires ipxe-xcat on x86_64 (xCAT.spec, upstream 32a688b3), so an x86_64 openEuler section
# without it builds a repo where "dnf install xCAT" answers "nothing provides ipxe-xcat".
for my $target (map { "openeuler-$_-x86_64" } qw(20.03sp4 22.03sp4 24.03sp4)) {
ok(exists $manifest{$target}{'ipxe-xcat'}, "$target declares ipxe-xcat, which xCAT requires on x86_64");
}
done_testing();
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/perl
# Every openEuler ppc64le native prerequisite after procenv itself fails before rpmbuild starts:
#
# FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/procenv'
#
# raised from mock's procenv plugin prebuild hook. The plugin runs ["/usr/bin/procenv"] through
# mockbuild.util.do with no chroot prefix, so it executes the BUILD HOST's copy, and
# xcat-master-ppc has none. Installing procenv in the chroot does not help: mock already appends it
# to preexisting_deps itself, and the run that did so still failed with the same line while
# root.log recorded "Installing : procenv-0.60-1.ppc64le".
#
# mock ships procenv_enable False. The overlays turned it on, which made every native build depend
# on a host package that neither repository declares, for a procenv.log nothing reads. They now
# leave it at the default.
#
# native_overlay_text is pure, so this runs no mock.
use strict;
use warnings;
use Test::More;
use FindBin qw($RealBin);
use lib "$RealBin/../lib";
use XCAT::NativeInputs qw(native_overlay_text);
my $base = '/opt/xcat-ci-shared/builds/oe264/work/native-base.cfg';
my $prereqs = '/opt/xcat-ci-shared/builds/oe264/work/native-prerequisites';
for my $purpose (1000, 0, 'procenv') {
my $text = native_overlay_text($purpose, $base, $prereqs);
unlike($text, qr/procenv_enable'\]\s*=\s*True/,
"overlay $purpose does not enable the procenv plugin, which needs a host binary");
# The overlay must still carry what the native build does depend on.
like($text, qr/\[xcat-native-inputs\]/, "overlay $purpose still declares the prerequisite repository");
like($text, qr/bind_mount_enable'\]\s*=\s*True/, "overlay $purpose still binds the prerequisite tree");
}
# The uid split is declared in the inputs and must not move: genesis builds as root, the rest as
# 1000, and the procenv overlay runs as 1000 too.
is((native_overlay_text(1000, $base, $prereqs) =~ /chrootuid'\]\s*=\s*(\d+)/)[0], 1000,
'the unprivileged overlay still runs as uid 1000');
is((native_overlay_text(0, $base, $prereqs) =~ /chrootuid'\]\s*=\s*(\d+)/)[0], 0,
'the genesis overlay still runs as root');
done_testing();
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/perl
# A dep builder creates its own result directories before mock starts. ipxe-xcat/mockbuild.pl calls
# make_path on $work_dir/srpm and $work_dir/rpm and gives each one to mock as --resultdir, and it
# runs as root. The native openEuler overlay keeps chrootuid at the catalog's build_uid and
# chrootgid at the native build gid, so mock opens state.log, build.log and root.log in those
# directories as that uid. They are writable only if the step itself carries the native build gid
# and a group-writable umask. native_owner_command is where the step gets both.
use strict;
use warnings;
use Test::More;
use FindBin qw($RealBin);
use lib "$RealBin/..";
use MockBuildUtils qw(native_owner_command NATIVE_BUILD_GID);
my $gid = NATIVE_BUILD_GID;
my $overlay = '/work/native-1000.cfg';
my $cfg = '/etc/mock/openeuler-24.03-ppc64le.cfg';
my $step = "perl ipxe-xcat/mockbuild.pl --work-dir /tmp/ipxe-xcat --result-dir /results/ipxe-xcat";
my $cmd = native_owner_command($overlay, $cfg, $step);
like($cmd, qr/\bsetpriv\b[^'"]*--regid\s+\Q$gid\E\b/,
"the step runs under setpriv --regid $gid, so it creates its result directories in the native build group");
like($cmd, qr/\bsetpriv\b[^'"]*--clear-groups\b/,
'setpriv --clear-groups drops the supplementary groups root started with');
like($cmd, qr/\bumask\s+0002\b/,
'the step runs with umask 0002, so a directory it creates stays group writable');
my $umask = index($cmd, 'umask 0002');
my $setpriv = index($cmd, 'setpriv');
my $builder = index($cmd, 'ipxe-xcat/mockbuild.pl');
ok($setpriv >= 0 && $setpriv < $umask,
'setpriv comes before umask 0002, so the umask applies under the native build gid');
ok($umask >= 0 && $umask < $builder,
'umask 0002 comes before the builder, so make_path in the builder inherits it');
like($cmd, qr/mount --bind \S*\Q$overlay\E\S*\s+\S*\Q$cfg\E/,
'the wrapper binds the overlay it was given over the target config, so chrootuid stays as the catalog declared it');
done_testing();