diff --git a/build-utils/lib/XCAT/BuildUtils.pm b/build-utils/lib/XCAT/BuildUtils.pm index 9bf034c1e..6e610ee23 100644 --- a/build-utils/lib/XCAT/BuildUtils.pm +++ b/build-utils/lib/XCAT/BuildUtils.pm @@ -42,6 +42,7 @@ our @EXPORT_OK = qw( buildinfo_text targetarch_from_target openeuler_build_target openeuler_repo_subdir + mock_config_text genesis_chroot_name genesis_target_arch genesis_build_plan genesis_log_errors genesis_log_deny_rules deb_belongs_to_dist genesis_dists genesis_dist_reason @@ -1115,3 +1116,47 @@ sub _pid_alive { } 1; + +#------------------------------------------------------------------------------- + +=head3 mock_config_text + + Descriptions: Render the per-package mock configuration from a target configuration. + + Arguments: + $pkg - the package being built, e.g. xCAT or perl-xCAT + $target - the mock target, e.g. openeuler-24.03-ppc64le + $base - the text of /etc/mock/.cfg + $epoch - SOURCE_DATE_EPOCH, passed into the chroot + + Returns: the text to write to /etc/mock/-.cfg + +=cut + +#------------------------------------------------------------------------------- +sub mock_config_text { + my ($pkg, $target, $base, $epoch) = @_; + my $chroot = "$pkg-$target"; + my $text = $base; + $text =~ s/config_opts\['root'\]\s+=.*/config_opts['root'] = \"$chroot\"/; + if ($pkg eq "perl-xCAT" && $target !~ /suse|sles|leap/i) { + # perl-generators exports perl(xCAT::...) provides on RHEL/Fedora; it does not + # exist on openSUSE/SLES (rpm there generates perl provides itself), so injecting + # it into a SUSE chroot aborts chroot setup. Suppress it for SUSE targets. + $text .= "config_opts['chroot_additional_packages'] = 'perl-generators'\n"; + } + $text .= "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + # Avoid systemd-nspawn: it INTERMITTENTLY fails chroot setup with + # "Failed to determine whether the unified cgroups hierarchy is used: No medium found" + # (ENOMEDIUM), which drops that package from the (still-signed) core -> an incomplete build + # that only surfaces later as a confusing MN install failure. 'simple' isolation is a plain + # chroot -- reliable for these RPM builds -- and sidesteps the nspawn cgroup race entirely. + $text .= "config_opts['isolation'] = 'simple'\n"; + # mock creates --resultdir and its logs as chrootuid, and buildrpms.pl passes a relative + # one under a tree it owns as root. This assignment replaces any uid the target declares, + # so the in-chroot build user becomes uid 0 as well. + $text .= "config_opts['chrootuid'] = 0\n"; + # chrootgid is left unset on purpose: groupadd for the in-chroot group fails on gid 0. + return $text; +} + diff --git a/buildrpms.pl b/buildrpms.pl index c350d0351..1b2ca65e3 100755 --- a/buildrpms.pl +++ b/buildrpms.pl @@ -59,7 +59,8 @@ use XCAT::BuildUtils qw(git_revision source_date_epoch sh sh_or_die usage buildi sweep_build_sources_dirs stage_xcat_probe_sources stage_xcatsn_templates stage_genesis_base_sources write_script read_line targetarch_from_target - openeuler_build_target openeuler_repo_subdir); + openeuler_build_target openeuler_repo_subdir + mock_config_text); use POSIX (); # EEXIST, for the directory build lock (see main()) use Getopt::Long qw(GetOptions); use POSIX qw(strftime); @@ -325,23 +326,8 @@ sub createmockconfig { my $chroot = "$pkg-$target$ext"; my $cfgfile = "/etc/mock/$chroot.cfg"; return if -f $cfgfile && ! $opts{force}; - cp "/etc/mock/$target.cfg", $cfgfile; - my $contents = read_text($cfgfile); - $contents =~ s/config_opts\['root'\]\s+=.*/config_opts['root'] = \"$chroot\"/; - if ($pkg eq "perl-xCAT" && $target !~ /suse|sles|leap/i) { - # perl-generators exports perl(xCAT::...) provides on RHEL/Fedora; it does not - # exist on openSUSE/SLES (rpm there generates perl provides itself), so injecting - # it into a SUSE chroot aborts chroot setup. Suppress it for SUSE targets. - $contents .= "config_opts['chroot_additional_packages'] = 'perl-generators'\n"; - } - $contents .= "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$SOURCE_DATE_EPOCH'\n"; - # Avoid systemd-nspawn: it INTERMITTENTLY fails chroot setup with - # "Failed to determine whether the unified cgroups hierarchy is used: No medium found" - # (ENOMEDIUM), which drops that package from the (still-signed) core -> an incomplete build that - # only surfaces later as a confusing MN install failure. 'simple' isolation is a plain chroot -- - # reliable for these RPM builds -- and sidesteps the nspawn cgroup race entirely. - $contents .= "config_opts['isolation'] = 'simple'\n"; - write_text($cfgfile, $contents); + write_text($cfgfile, + mock_config_text($pkg, "$target$ext", read_text("/etc/mock/$target.cfg"), $SOURCE_DATE_EPOCH)); } sub buildsources_genesis_base($) { diff --git a/xCAT-test/unit/buildrpms_mock_resultdir_uid.t b/xCAT-test/unit/buildrpms_mock_resultdir_uid.t new file mode 100644 index 000000000..4d0cfc982 --- /dev/null +++ b/xCAT-test/unit/buildrpms_mock_resultdir_uid.t @@ -0,0 +1,54 @@ +#!/usr/bin/env perl +# mock creates --resultdir as chrootuid, and buildrpms.pl passes a relative one under a +# root-owned tree. These assertions read the RENDERED configuration, not the builder. +use strict; +use warnings; +use FindBin; +use lib "$FindBin::Bin/../../build-utils/lib"; +use Test::More; +use XCAT::BuildUtils qw(mock_config_text); + +my $ppc = <<'CFG'; +config_opts['root'] = 'openeuler-24.03-ppc64le' +config_opts['target_arch'] = 'ppc64le' +config_opts['chrootuid'] = 1000 +config_opts['chrootgid'] = 1000 +config_opts['use_bootstrap'] = False +CFG + +my $x86 = <<'CFG'; +include('templates/openeuler-24.03.tpl') +config_opts['root'] = 'openeuler-24.03sp4-x86_64' +config_opts['target_arch'] = 'x86_64' +CFG + +# mock takes the last assignment. +sub effective { + my ($text, $opt) = @_; + my $v; + for my $line (split /\n/, $text) { + $v = $1 if $line =~ /\Aconfig_opts\['\Q$opt\E'\]\s*=\s*(.+?)\s*\z/; + } + return $v; +} + +my $out = mock_config_text('xCAT', 'openeuler-24.03-ppc64le', $ppc, 1790988617); +is(effective($out, 'chrootuid'), '0', 'the ppc64le core build writes its resultdir as root'); +is(effective($out, 'chrootgid'), '1000', 'the group the target declared is left alone'); +is(effective($out, 'root'), '"xCAT-openeuler-24.03-ppc64le"', 'the chroot is still named per package'); + +my $plain = mock_config_text('xCAT', 'openeuler-24.03sp4-x86_64', $x86, 1790988617); +is(effective($plain, 'chrootuid'), '0', 'a target that declares no uid is pinned to root too'); +is(effective($plain, 'chrootgid'), undef, 'and no group is invented for it'); +is(effective($plain, 'target_arch'), "'x86_64'", 'nothing else in the base configuration changes'); + +like($out, qr/\Qconfig_opts['environment']['SOURCE_DATE_EPOCH'] = '1790988617'\E/, + 'the reproducible build date is passed into the chroot'); +like($out, qr/\Qconfig_opts['isolation'] = 'simple'\E/, 'nspawn is avoided'); +like(mock_config_text('perl-xCAT', 'openeuler-24.03-ppc64le', $ppc, 1), + qr/\Qconfig_opts['chroot_additional_packages'] = 'perl-generators'\E/, + 'perl-xCAT still gets perl-generators on an rpm-md target'); +unlike(mock_config_text('perl-xCAT', 'opensuse-leap-15.6-x86_64', $x86, 1), + qr/perl-generators/, 'and still does not on a SUSE target'); + +done_testing();