diff --git a/conserver/conserver.spec b/conserver/conserver.spec index 9bbfdd3..4c7eb9a 100644 --- a/conserver/conserver.spec +++ b/conserver/conserver.spec @@ -21,10 +21,10 @@ License: BSD Group: System Environment/Daemons URL: http://www.conserver.com/ Source: http://www.conserver.com/%{pkg}-%{ver}.tar.gz -Patch: initscript_8.2.1.patch +Patch0: initscript_8.2.1.patch Patch1: openssl3-dh-opaque.patch BuildRoot: %{_tmppath}/%{pkg}-buildroot -BuildRequires: openssl-devel +BuildRequires: gcc make glibc-devel openssl-devel Prefix: %{_prefix} Obsoletes: conserver conserver-client @@ -40,7 +40,7 @@ bells and whistles to accentuate that basic functionality. %prep %{__rm} -rf %{buildroot} %setup -n %{pkg}-%{ver} -%patch -p1 +%patch0 -p1 %patch1 -p1 diff --git a/conserver/mockbuild.pl b/conserver/mockbuild.pl new file mode 100755 index 0000000..6d175e6 --- /dev/null +++ b/conserver/mockbuild.pl @@ -0,0 +1,147 @@ +#!/usr/bin/perl +# +# mockbuild.pl - build conserver-xcat (the traditional C conserver, 8.2.1) for one +# mock target and smoke-test the resulting binaries. Mirrors the other xcat-dep +# builders (goconserver/mockbuild.pl, ipmitool/mockbuild.pl): stage sources + spec, +# build a SRPM, `mock --rebuild` it in the target chroot, copy the RPMs to +# --result-dir, then (unless --skip-install) install into the chroot and run +# `console -V` / `conserver -V` to confirm the binaries work. +# +# conserver is NOT part of the default mockbuild-all.pl dep set (xCAT uses goconserver), +# so this builder is standalone. Usage: +# ./mockbuild.pl --mock-cfg alma+epel-9-x86_64 --result-dir /path/out +# +use strict; +use warnings; +use Cwd qw(abs_path); +use File::Basename qw(dirname basename); +use File::Path qw(make_path remove_tree); +use File::Copy qw(copy); +use Getopt::Long qw(GetOptions); + +my $script_dir = abs_path(dirname(__FILE__)); +my $pkg_dir = $script_dir; # tarball + patches + spec live alongside this script +my $version = '8.2.1'; + +my $work_dir = '/tmp/conserver-mockbuild'; +my $mock_cfg = ''; +my $mock_uniqueext = ''; +my $result_dir = "$script_dir/../build-output/list-conserver/conserver"; +my $log_dir = "$script_dir/../build-logs/list-conserver/conserver"; +my $skip_install = 0; +my $build_timestamp; + +GetOptions( + 'work-dir=s' => \$work_dir, + 'mock-cfg=s' => \$mock_cfg, + 'mock-uniqueext=s' => \$mock_uniqueext, + 'result-dir=s' => \$result_dir, + 'log-dir=s' => \$log_dir, + 'skip-install!' => \$skip_install, + 'build-timestamp=i' => \$build_timestamp, +) or die usage(); + +die "Run as root (current uid=$>)\n" if $> != 0; +for my $bin (qw(mock rpmbuild rpm)) { + run("command -v " . sh_quote($bin) . " >/dev/null 2>&1"); +} + +# Deterministic builds: honor --build-timestamp (else Gitepoch, else git HEAD time), +# matching the other xcat-dep builders so mockbuild-all.pl can drive this one. +my $repo_root = abs_path("$script_dir/.."); +my $sde = $build_timestamp; +if (!$sde && -f "$repo_root/Gitepoch") { $sde = capture("cat " . sh_quote("$repo_root/Gitepoch")); } +if (!$sde || $sde !~ /^\d+$/) { + $sde = capture("git -C " . sh_quote($repo_root) . " log -1 --format=%ct HEAD 2>/dev/null"); +} +$ENV{SOURCE_DATE_EPOCH} = $sde if defined $sde && $sde =~ /^\d+$/; + +my $arch = capture('uname -m'); +if (!$mock_cfg) { + my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'}); + $os_id = 'alma' if $os_id eq 'almalinux'; + my ($rel) = capture('rpm -E %rhel'); + $mock_cfg = "${os_id}+epel-${rel}-${arch}"; +} +my $uniq = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; + +make_path($result_dir, $log_dir); +print "package: conserver-xcat\n"; +print "version: $version\n"; +print "arch: $arch\n"; +print "mock-cfg: $mock_cfg\n"; +print "result-dir: $result_dir\n"; + +# ---- stage sources + spec into a private rpmbuild tree ----------------------- +remove_tree($work_dir) if -d $work_dir; +make_path("$work_dir/SOURCES", "$work_dir/SPECS"); +copy("$pkg_dir/conserver-$version.tar.gz", "$work_dir/SOURCES/") + or die "FATAL: cannot stage conserver-$version.tar.gz: $!\n"; +for my $p (glob("$pkg_dir/*.patch")) { + copy($p, "$work_dir/SOURCES/") or die "FATAL: cannot stage patch $p: $!\n"; +} +copy("$pkg_dir/conserver.spec", "$work_dir/SPECS/") + or die "FATAL: cannot stage conserver.spec: $!\n"; + +# ---- build the SRPM (host rpm just packages sources+spec; no %prep here) ------ +print "== Build SRPM ==\n"; +run("rpmbuild -bs --define " . sh_quote("_topdir $work_dir") + . " " . sh_quote("$work_dir/SPECS/conserver.spec") + . " > " . sh_quote("$log_dir/srpm.log") . " 2>&1"); +my ($srpm) = glob("$work_dir/SRPMS/conserver-xcat-$version-*.src.rpm"); +die "FATAL: SRPM not produced (see $log_dir/srpm.log)\n" unless $srpm && -f $srpm; +print "SRPM: $srpm\n"; + +# ---- mock rebuild in the target chroot -------------------------------------- +print "== mock --rebuild ($mock_cfg) ==\n"; +my $mock_result = "$work_dir/mock-result"; +make_path($mock_result); +run("mock -r " . sh_quote($mock_cfg) . $uniq + . " --rebuild " . sh_quote($srpm) + . " --resultdir " . sh_quote($mock_result) + . " > " . sh_quote("$log_dir/mock-rebuild.log") . " 2>&1"); + +my @rpms = grep { $_ !~ /\.src\.rpm$/ && $_ !~ /-debug(info|source)-/ } + glob("$mock_result/*.rpm"); +die "FATAL: no binary RPM produced (see $log_dir/mock-rebuild.log)\n" unless @rpms; +my ($main) = grep { basename($_) =~ /^conserver-xcat-\Q$version\E-.*\.(?:$arch|noarch)\.rpm$/ } @rpms; +die "FATAL: main conserver-xcat RPM not found among: @rpms\n" unless $main; + +for my $r (@rpms) { + copy($r, $result_dir) or die "FATAL: cannot copy $r -> $result_dir: $!\n"; +} +print "built: " . join(', ', map { basename($_) } @rpms) . "\n"; + +# ---- smoke test: install into the chroot and run the binaries --------------- +unless ($skip_install) { + print "== Smoke test (install + run) ==\n"; + run("mock -r " . sh_quote($mock_cfg) . $uniq . " --install " . sh_quote($main) + . " > " . sh_quote("$log_dir/install.log") . " 2>&1"); + # console (client) and conserver (daemon) both print their version to stderr/stdout. + my $smoke = capture("mock -r " . sh_quote($mock_cfg) . $uniq + . " --chroot -- " . sh_quote('/usr/bin/console -V 2>&1; /usr/sbin/conserver -V 2>&1') + . " 2>&1"); + print " output: $smoke\n"; + die "FATAL: smoke test did not report version $version\n" unless $smoke =~ /\Q$version\E/; + print "smoke test PASSED (console/conserver report $version)\n"; +} +print "DONE: conserver-xcat $version for $mock_cfg -> $result_dir\n"; + +# ---- helpers ---------------------------------------------------------------- +sub run { + my ($cmd) = @_; + my $rc = system('bash', '-c', $cmd); + die "FATAL: command failed (rc=" . ($rc >> 8) . "): $cmd\n" if $rc != 0; + return 1; +} +sub capture { + my ($cmd) = @_; + my $out = `$cmd`; + chomp $out if defined $out; + return $out // ''; +} +sub sh_quote { my ($s) = @_; $s =~ s/'/'\\''/g; return "'$s'"; } +sub usage { + return "usage: mockbuild.pl --mock-cfg [--result-dir DIR] [--work-dir DIR]\n" + . " [--log-dir DIR] [--mock-uniqueext EXT] [--skip-install]\n"; +} diff --git a/goconserver/mockbuild.pl b/goconserver/mockbuild.pl index ff2b0df..3b5eb15 100755 --- a/goconserver/mockbuild.pl +++ b/goconserver/mockbuild.pl @@ -89,7 +89,10 @@ print_step("Stage build environment"); remove_tree($work_dir) if -d $work_dir; make_path($work_dir); -my $rpmbuild_top = "/var/tmp/xcat-rpmbuild-goconserver"; +# Unique per run (nested under the run/target-scoped --work-dir) so concurrent builds -- e.g. +# parallel EL targets on one host -- don't wipe each other. (Was a shared +# /var/tmp/xcat-rpmbuild-goconserver, which collided under parallelism.) +my $rpmbuild_top = "$work_dir/rpmbuild"; remove_tree($rpmbuild_top) if -d $rpmbuild_top; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$rpmbuild_top/$d"); @@ -187,7 +190,7 @@ print_step("Create spec and build RPM"); my $spec_content = <<"SPEC"; Name: goconserver Version: $version -Release: 2.el$rel +Release: 3.el$rel Summary: Console server written in Go for xCAT License: EPL-1.0 URL: https://github.com/xcat2/goconserver diff --git a/grub2-xcat/grub2-xcat.spec b/grub2-xcat/grub2-xcat.spec index d861250..7bda5ea 100644 --- a/grub2-xcat/grub2-xcat.spec +++ b/grub2-xcat/grub2-xcat.spec @@ -1,5 +1,9 @@ Summary: grub2 resources generated by grub2-mknetdir Name: grub2-xcat +# This el10 rewrite reset the version scheme from the el7-era 2.02 down to 1.0, but +# xCAT-server still Requires: grub2-xcat >= 2.02-0.76.el7.1.snap201905160255. An Epoch +# bump makes 1:1.0 outrank 0:2.02 so the (unchanged) xCAT-server dependency resolves. +Epoch: 1 Version: 1.0 #Release: snap%(date +"%Y%m%d%H%M") Release: 2 diff --git a/grub2-xcat/mockbuild.pl b/grub2-xcat/mockbuild.pl index adc50da..a7848c9 100755 --- a/grub2-xcat/mockbuild.pl +++ b/grub2-xcat/mockbuild.pl @@ -3,7 +3,7 @@ use strict; use warnings; use Cwd qw(abs_path); -use File::Basename qw(dirname basename); +use File::Basename qw(dirname); use File::Copy qw(copy); use File::Path qw(make_path remove_tree); use Getopt::Long qw(GetOptions); @@ -15,28 +15,22 @@ my $spec_file = "$pkg_dir/grub2-xcat.spec"; my $recompile_dir = "$repo_root/grub2-xcat.recompile"; my $resource_mode = 'reuse-grub2-res'; -my $upstream_url = 'https://mirror.stream.centos.org/10-stream/BaseOS/source/tree/Packages/grub2-2.12-37.el10.src.rpm'; -my $upstream_file = ''; my $work_dir = '/tmp/grub2-xcat-mockbuild'; my $mock_cfg = ''; my $mock_uniqueext = ''; my $result_dir = "$repo_root/build-output/list3/grub2-xcat"; my $log_dir = "$repo_root/build-logs/list3/grub2-xcat"; my $skip_install = 0; -my $skip_upstream_download = 0; my $build_timestamp; GetOptions( 'resource-mode=s' => \$resource_mode, - 'upstream-url=s' => \$upstream_url, - 'upstream-file=s' => \$upstream_file, 'work-dir=s' => \$work_dir, 'mock-cfg=s' => \$mock_cfg, 'mock-uniqueext=s' => \$mock_uniqueext, 'result-dir=s' => \$result_dir, 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, - 'skip-upstream-download!' => \$skip_upstream_download, 'build-timestamp=i' => \$build_timestamp, ) or die usage(); @@ -49,18 +43,17 @@ die "Mode regenerate-from-el10-srcrpm is not supported in this script yet; use r make_path($recompile_dir) if !-d $recompile_dir; -for my $bin (qw(wget mock rpmbuild rpm dnf file bash tar sha256sum grep cmp cut)) { +for my $bin (qw(mock rpmbuild rpm dnf file bash tar grep cmp)) { run("command -v " . sh_quote($bin) . " >/dev/null 2>&1"); } my ($version, @spec_assets) = parse_spec($spec_file); die "Could not parse Version from $spec_file\n" if !$version; -if (!$upstream_file) { - $upstream_file = basename($upstream_url); -} -die "Could not derive upstream file name from URL: $upstream_url\n" if !$upstream_file; -my $upstream_path = "$recompile_dir/$upstream_file"; +# NOTE: grub2-xcat is a pure noarch repackaging of the committed grub2-res.tar.gz (Source1), +# so the build needs no external source. Fetching the distro grub2 src.rpm would only ever be +# needed by the (currently unimplemented) regenerate-from-el10-srcrpm mode, which would rebuild +# the grub tree from source and commit a fresh grub2-res.tar.gz rather than download at build time. my $arch = capture('uname -m'); if (!$mock_cfg) { @@ -95,10 +88,7 @@ print "result_dir: $result_dir\n"; print "log_dir: $log_dir\n"; print "mock_cfg: $mock_cfg\n"; print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n"; -print "upstream_url: $upstream_url\n"; -print "upstream_file: $upstream_file\n"; print "skip_install: $skip_install\n"; -print "skip_upstream_download: $skip_upstream_download\n"; make_path($result_dir); make_path($log_dir); @@ -106,21 +96,6 @@ make_path($log_dir); print_step("Mock config check"); run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null"); -if (!$skip_upstream_download) { - print_step("Download upstream source RPM"); - run("wget --spider " . sh_quote($upstream_url)); - run("wget -O " . sh_quote($upstream_path) . " " . sh_quote($upstream_url)); - my $sha = capture("sha256sum " . sh_quote($upstream_path) . " | cut -d ' ' -f1"); - my $meta_file = "$log_dir/upstream-source.txt"; - open my $mfh, '>', $meta_file or die "Cannot write $meta_file: $!\n"; - print {$mfh} "url=$upstream_url\n"; - print {$mfh} "file=$upstream_path\n"; - print {$mfh} "sha256=$sha\n"; - close $mfh; - print "Downloaded upstream source rpm: $upstream_path\n"; - print "SHA256: $sha\n"; -} - print_step("Verify grub2 resource payload"); my $resource_tar = "$pkg_dir/grub2-res.tar.gz"; die "Missing required resource tarball: $resource_tar\n" if !-f $resource_tar; @@ -295,14 +270,11 @@ sub usage { return <<"USAGE"; Usage: $0 [options] --resource-mode MODE Build mode: reuse-grub2-res|regenerate-from-el10-srcrpm (default: $resource_mode) - --upstream-url URL Upstream grub2 source RPM URL (default: $upstream_url) - --upstream-file FILE Source RPM filename stored in grub2-xcat.recompile/ (default: basename of URL) --work-dir PATH Temporary work dir (default: $work_dir) --mock-cfg NAME Mock config (default: +epel-10-) --mock-uniqueext TXT Optional mock --uniqueext suffix to isolate concurrent builds --result-dir PATH Output RPM/SRPM directory (default: $result_dir) --log-dir PATH Log directory (default: $log_dir) - --skip-upstream-download Skip wget of upstream source RPM --skip-install Skip dnf install + smoke tests --build-timestamp EPOCH Unix timestamp for deterministic builds (SOURCE_DATE_EPOCH) USAGE diff --git a/ipmitool/ipmitool-1.8.18.tar.gz b/ipmitool/ipmitool-1.8.18.tar.gz index 260dda1..d962862 100644 Binary files a/ipmitool/ipmitool-1.8.18.tar.gz and b/ipmitool/ipmitool-1.8.18.tar.gz differ diff --git a/ipmitool/ipmitool.spec b/ipmitool/ipmitool.spec index 2397b63..a4618b8 100644 --- a/ipmitool/ipmitool.spec +++ b/ipmitool/ipmitool.spec @@ -88,6 +88,10 @@ for f in AUTHORS ChangeLog; do done %build +# OpenSSL 3 ships a stub openssl/md2.h, so configure's header probe sets +# HAVE_CRYPTO_MD2 even though MD2_CTX/MD2_* are gone -> auth.c fails to compile. +# Force the probe negative so the no-MD2 code path is used (MD2 IPMI auth is obsolete). +export ac_cv_header_openssl_md2_h=no # --disable-dependency-tracking speeds up the build # --enable-file-security adds some security checks # --disable-intf-free disables FreeIPMI support - we don't want to depend on diff --git a/mockbuild-all.pl b/mockbuild-all.pl index 186dc33..f1be0b0 100755 --- a/mockbuild-all.pl +++ b/mockbuild-all.pl @@ -14,11 +14,18 @@ use POSIX qw(strftime); my $script_dir = abs_path(dirname(__FILE__)); my $repo_root = abs_path($script_dir); -my $xcat_src = "$repo_root/xcat-source-code"; -my $output_root = "$repo_root/build-output/mockbuild-all"; +my $xcat_src = "$repo_root/../xcat-core"; +# Single knob for all NFS-shared output; --output-root/--repo-dep derive from it below +# unless explicitly overridden. Empty means "not set on the command line". +my $output = ''; +my $output_root = ''; my $target = ''; my $nproc = 1; my $parallel_builds; +my $parallel_targets = 1; # 1 = serial (default; safe). 0/auto = all EL targets at once; N = cap. + # NOTE: parallel targets need every per-package mockbuild.pl to avoid + # shared-path writes (repo tarballs, $HOME/rpmbuild); serial is safe today. +my $max_parallel = 0; # 0/auto = host nproc: global cap on concurrent mock builds (all targets) my $run_id = ''; my $build_timestamp; my $skip_install = 0; @@ -26,19 +33,35 @@ my $skip_build = 0; my $skip_xcat_dep = 0; my $skip_perl = 0; my $skip_xcat = 0; +my $skip_genesis = 0; my $skip_createrepo = 0; my $skip_tarball = 0; my $scrub_all_chroots = 0; my $dry_run = 0; my @extra_collect_dirs; +my $repo_dep = ''; +my $gpg_sign = 0; +my $gpg_key_name = 'xCAT Signing Key'; +my $gpg_home = ''; +my $force_unlock = 0; +my $HELD_LOCK; # path of the output lock this process owns (for cleanup on exit) +my $LOCK_OWNER_PID; # pid that created the lock; forked children must NOT remove it GetOptions( 'repo-root=s' => \$repo_root, 'xcat-source=s' => \$xcat_src, + 'output=s' => \$output, 'output-root=s' => \$output_root, + 'repo-dep=s' => \$repo_dep, + 'gpg-sign!' => \$gpg_sign, + 'gpg-key-name=s' => \$gpg_key_name, + 'gpg-home=s' => \$gpg_home, + 'force-unlock!' => \$force_unlock, 'target=s' => \$target, 'nproc=i' => \$nproc, 'parallel-builds=i' => \$parallel_builds, + 'parallel-targets=i' => \$parallel_targets, + 'max-parallel=i' => \$max_parallel, 'run-id=s' => \$run_id, 'build-timestamp=i' => \$build_timestamp, 'skip-install!' => \$skip_install, @@ -46,6 +69,7 @@ GetOptions( 'skip-xcat-dep!' => \$skip_xcat_dep, 'skip-perl!' => \$skip_perl, 'skip-xcat!' => \$skip_xcat, + 'skip-genesis!' => \$skip_genesis, 'skip-createrepo!' => \$skip_createrepo, 'skip-tarball!' => \$skip_tarball, 'scrub-all-chroots!' => \$scrub_all_chroots, @@ -75,6 +99,23 @@ if ($run_id eq '') { $run_id = strftime('%Y%m%d-%H%M%S', gmtime($SOURCE_DATE_EPOCH)); } +# Single output base for every NFS-shared write. Two hosts build in parallel on one NFS by +# passing distinct --output paths. --output-root/--repo-dep, if given, override the derived +# values. Default keeps the historical layout so existing callers are unaffected. +# Create the dir first, THEN abs_path -- abs_path() on a not-yet-existing path returns undef, +# and abs_path(undef) silently resolves to cwd, which would misdirect all output. +my $output_base = $output ne '' ? $output : "$repo_root/build-output"; +make_path($output_base) if !-d $output_base; +$output_base = abs_path($output_base) + or die "Cannot resolve --output base directory\n"; +$output_root = "$output_base/mockbuild-all" if $output_root eq ''; +# Deployable per-EL xcat-dep repo root (rh8/rh9/rh10/ assembled here). +$repo_dep = "$output_base/xcat-dep" if $repo_dep eq ''; + +# Fail-fast lock on the output base so a second run against the same --output aborts instead of +# racing on the shared NFS tree. Held for the whole invocation; released by the exit handlers. +acquire_output_lock($output_base, $force_unlock); + $xcat_src = resolve_xcat_source($xcat_src, $repo_root); my $arch = capture('uname -m'); @@ -87,13 +128,80 @@ die "Could not resolve ID from /etc/os-release\n" if $os_id eq ''; die "Could not resolve major release from VERSION_ID='$version_id' in /etc/os-release\n" if !defined($rel) || $rel eq ''; -if (!$target) { - $target = resolve_mock_cfg($os_id, $rel, $arch); -} -for my $bin (qw(perl uname createrepo tar find rpm)) { +for my $bin (qw(perl uname createrepo_c tar find rpm)) { require_command($bin); } require_command('mock') if $scrub_all_chroots; +require_command('rpmsign') if $gpg_sign; +require_command('gpg') if $gpg_sign; + +# An explicit --target builds just that target; otherwise build the current host +# arch across rh8/rh9/rh10 into a deployable per-EL xcat-dep repo. This script builds +# ONLY the host arch (uname -m) -- the other arch is produced on its own build host. +my @build_targets = $target + ? ($target) + : map { resolve_mock_cfg($os_id, $_, $arch) } (8, 9, 10); + +# NOTE: no dhcp- packages are built here. DHCP backend selection is an install-time +# rich dep in xCAT.spec (kea if system-release>=10 else /usr/sbin/dhcpd), so there is +# nothing arch/EL-specific to build or to exclude for el10. + +print_step('Targets to build'); +print " $_\n" for @build_targets; +print "output_base: $output_base\n"; +print "deploy repo-dep: $repo_dep\n"; +print "lock: $output_base/.lock (held)\n"; +print "gpg_sign: $gpg_sign\n"; +print "gpg_key_name: $gpg_key_name\n" if $gpg_sign; +print "gpg_home: " . ($gpg_home ne '' ? $gpg_home : '(default keyring)') . "\n" if $gpg_sign; + +# Build (and deploy) EL targets concurrently. Each target is fully isolated -- distinct run_id +# (target-folded), mock --uniqueext, /tmp work dir, xcat_src/dist/, and deploy dir +# rh/ -- so there is no cross-target contention. 0/auto = all at once; 1 = serial. +my $tgt_workers = $parallel_targets > 0 ? $parallel_targets : scalar(@build_targets); +$tgt_workers = scalar(@build_targets) if $tgt_workers > scalar(@build_targets); +# Global cap on concurrent mock builds so parallel targets don't oversubscribe the host. Each +# mock build already gets a unique --uniqueext (separate chroot), so the only limit needed is +# hardware: total concurrent builds across all targets stays <= $cap (default host nproc). The +# per-target build-step concurrency is therefore the cap divided across the active targets. +my $cap = $max_parallel > 0 ? $max_parallel : (capture('nproc') || 4); +my $per_target_builds = defined($parallel_builds) ? $parallel_builds : int($cap / $tgt_workers); +$per_target_builds = 1 if $per_target_builds < 1; +print "parallel_targets: " . ($parallel_targets > 0 ? $parallel_targets : "auto($tgt_workers)") . "\n"; +print "max_parallel: $cap (per-target build workers: $per_target_builds)\n"; +my $tgt_pm = Parallel::ForkManager->new($tgt_workers <= 1 ? 0 : $tgt_workers); +my $tgt_fail = 0; +$tgt_pm->run_on_finish(sub { + my ($pid, $exit) = @_; + $tgt_fail++ if $exit; +}); +for my $tgt (@build_targets) { + $tgt_pm->start and next; + my $rc = 0; + eval { + my $info = build_one_target($tgt, $run_id, $per_target_builds); + deploy_target($tgt, $info); + 1; + } or do { warn "ERROR: target $tgt failed: $@"; $rc = 1; }; + $tgt_pm->finish($rc); +} +$tgt_pm->wait_all_children; +die "FATAL: $tgt_fail target(s) failed\n" if $tgt_fail; + +print_step('All targets completed'); +exit 0; + +# Build a single target into its own build-output/ tree and return +# { repo_dir, rel }. Everything below through the summary is per-target work. +sub build_one_target { + my ($target, $run_id, $max_build_workers) = @_; + # The build output identity must be per-target (os version + arch). SOURCE_DATE_EPOCH + # is the same across targets for a given commit, so a timestamp-only run_id makes + # different targets (e.g. alma+epel-8 vs -9) share build-output/ and + # cross-contaminate. Fold the target into run_id so each target gets its own tree. + $run_id = "$target-$run_id" unless index($run_id, $target) >= 0; + my ($rel) = $target =~ /epel-(\d+)-/; + die "Could not parse EL release from target '$target'\n" unless defined $rel; my $run_root = "$output_root/$run_id"; my $build_root = "$run_root/build-results"; @@ -104,18 +212,19 @@ my $tarball = "$output_root/mockbuild-all-$target-$run_id.tar.gz"; my $srpm_repo_dir = "$run_root/repo-src"; my $srpm_tarball = "$output_root/mockbuild-all-$target-$run_id-srpm.tar.gz"; +# All dep builders run natively on every arch. xnba-undi and grub2-xcat are noarch packagings of +# committed artifacts (an x86 UNDI ROM / the grub2 resource tarball) with no arch-specific build +# step, so ppc builds them the same as x86 -- no cross-arch import. my @dep_builders = ( { name => 'elilo-xcat', script => "$repo_root/elilo/mockbuild.pl" }, { name => 'grub2-xcat', script => "$repo_root/grub2-xcat/mockbuild.pl" }, { name => 'ipmitool-xcat', script => "$repo_root/ipmitool/mockbuild.pl" }, { name => 'syslinux-xcat', script => "$repo_root/syslinux/mockbuild.pl" }, { name => 'goconserver', script => "$repo_root/goconserver/mockbuild.pl" }, + { name => 'conserver-xcat', script => "$repo_root/conserver/mockbuild.pl" }, + { name => 'xnba-undi', script => "$repo_root/xnba/mockbuild.pl" }, ); -if ($arch eq 'x86_64') { - push @dep_builders, { name => 'xnba-undi', script => "$repo_root/xnba/mockbuild.pl" }; -} - my $perl_builder = "$repo_root/mockbuild-perl-packages.pl"; die "Missing xCAT build script: $xcat_src/buildrpms.pl\n" @@ -152,6 +261,7 @@ print "skip_build: $skip_build\n"; print "skip_xcat_dep: $skip_xcat_dep\n"; print "skip_perl: $skip_perl\n"; print "skip_xcat: $skip_xcat\n"; +print "skip_genesis: $skip_genesis\n"; print "skip_install: $skip_install\n"; print "skip_createrepo: $skip_createrepo\n"; print "skip_tarball: $skip_tarball\n"; @@ -189,6 +299,8 @@ if (!$skip_build) { '--mock-uniqueext', sh_quote($step_uniqueext), '--result-dir', sh_quote($step_result), '--log-dir', sh_quote($step_log), + # host-local, run-scoped work dir so /tmp doesn't collide between runs + '--work-dir', sh_quote("/tmp/mockbuild-all-$run_id/$name"), '--build-timestamp', $SOURCE_DATE_EPOCH, ($skip_install ? '--skip-install' : ()), ); @@ -206,12 +318,17 @@ if (!$skip_build) { my $perl_result = "$build_root/perl/$arch"; my $perl_log = "$log_root/perl/$arch"; 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 -- + # oversubscribes the host. my $cmd = join(' ', 'perl', sh_quote($perl_builder), '--mock-cfg', sh_quote($target), '--mock-uniqueext', sh_quote($perl_uniqueext), '--result-dir', sh_quote($perl_result), '--log-dir', sh_quote($perl_log), + '--work-dir', sh_quote("/tmp/mockbuild-all-$run_id/perl-list6"), + (($max_build_workers && $max_build_workers >= 1) ? ('--jobs', $max_build_workers) : ()), '--build-timestamp', $SOURCE_DATE_EPOCH, ($skip_install ? '--skip-install' : ()), ); @@ -225,7 +342,10 @@ if (!$skip_build) { } if (!$skip_xcat) { - my $cmd = join(' ', + # Own HOME per target (buildrpms.pl uses $HOME/rpmbuild) so parallel targets don't race. + my $xcat_home = "/tmp/mockbuild-all-$run_id/xcat-home"; + my $mktree = join(' ', map { sh_quote("$xcat_home/rpmbuild/$_") } qw(SOURCES SPECS BUILD BUILDROOT RPMS SRPMS)); + my $cmd = "mkdir -p $mktree && HOME=" . sh_quote($xcat_home) . ' ' . join(' ', 'perl', sh_quote("$xcat_src/buildrpms.pl"), '--target', sh_quote($target), '--nproc', int($nproc), @@ -242,10 +362,45 @@ if (!$skip_build) { }; } + # xCAT-genesis-base is OS-dependent (its initramfs bundles the build chroot's + # kernel + glibc/busybox/perl), so it is built here, per target, and shipped + # in this per-EL xcat-dep repo rather than in the flat xcat-core. buildrpms.pl + # (run in the xcat-core dir) derives the same snapYYYYMMDDHHMM Release from + # xcat-core's Gitepoch, so it matches xCAT-genesis-scripts (built in core) and + # the exact-version dependency genesis-scripts -> genesis-base resolves. + if (!$skip_genesis) { + # buildrpms.pl stages sources in $HOME/rpmbuild (via rpmdev-setuptree). Give each + # per-target genesis build its own HOME so parallel EL targets don't race on the shared + # /root/rpmbuild tree (that race is what made concurrent genesis builds fail). + my $genesis_home = "/tmp/mockbuild-all-$run_id/genesis-home"; + # buildrpms.pl's rpmdev-setuptree only runs during env setup, not per build, so create the + # rpmbuild tree ourselves for this per-target HOME (else $HOME/rpmbuild/SOURCES is missing). + my $mktree = join(' ', map { sh_quote("$genesis_home/rpmbuild/$_") } qw(SOURCES SPECS BUILD BUILDROOT RPMS SRPMS)); + my $cmd = "mkdir -p $mktree && HOME=" . sh_quote($genesis_home) . ' ' . join(' ', + 'perl', sh_quote("$xcat_src/buildrpms.pl"), + '--package', 'xCAT-genesis-base', + '--target', sh_quote($target), + '--nproc', int($nproc), + '--force', + '--verbose', + '--xcat_dep_path', sh_quote($repo_root), + ); + push @build_steps, { + id => 'genesis', + step => 'Build xCAT-genesis-base (per-target, OS-dependent)', + cmd => $cmd, + cwd => $xcat_src, + log => "$log_root/genesis-build.log", + }; + } + if (@build_steps) { - my $effective_parallel_builds = defined($parallel_builds) - ? $parallel_builds - : scalar(@build_steps); + # Prefer the caller-supplied cap (global budget / active targets). Fall back to the old + # behaviour (all steps at once) only when unset. + my $effective_parallel_builds = + ($max_build_workers && $max_build_workers >= 1) ? $max_build_workers + : defined($parallel_builds) ? $parallel_builds + : scalar(@build_steps); run_build_steps_parallel( steps => \@build_steps, max_processes => $effective_parallel_builds, @@ -255,7 +410,16 @@ if (!$skip_build) { my $xcat_rpms_dir = "$xcat_src/dist/$target/rpms"; my $xcat_srpms_dir = "$xcat_src/dist/$target/srpms"; -push @collect_roots, $xcat_rpms_dir; + +# In monolithic mode (no --skip-xcat) the whole xCAT core built here (incl. +# genesis-base) is collected into this repo. In the split pipeline (--skip-xcat, +# core built separately) the orchestrator (cluster-test.pl) routes +# xCAT-genesis-base from the xCAT dist tree into the per-EL dep repo itself -- +# robust to this script exiting non-zero on tolerated dep-builder failures -- so +# we deliberately do NOT collect the xCAT dist tree here. +if (!$skip_xcat) { + push @collect_roots, $xcat_rpms_dir; +} if ($skip_build) { push @collect_roots, @@ -272,7 +436,9 @@ if ($skip_build) { push @collect_roots, @extra_collect_dirs; @collect_roots = uniq(@collect_roots); -my @srpm_collect_roots = uniq(@collect_roots, $xcat_srpms_dir); +my @srpm_collect_roots = (!$skip_xcat) + ? uniq(@collect_roots, $xcat_srpms_dir) + : uniq(@collect_roots); print_step('Collect RPM artifacts'); print "collection roots:\n"; @@ -288,6 +454,17 @@ if (!$dry_run && $copied == 0) { die "No binary RPMs were collected. Check build logs and collection roots.\n"; } +# Ensure the OS-dependent xCAT-genesis-base rpm (built by the genesis step above) +# lands in the dep repo even when the full xCAT core is built elsewhere (--skip-xcat). +if (!$skip_genesis && !$dry_run) { + for my $g (glob("$xcat_rpms_dir/xCAT-genesis-base-*.rpm")) { + next if $g =~ /\.src\.rpm$/; + copy($g, "$repo_dir/" . basename($g)) + or die "Failed to copy genesis-base $g -> $repo_dir: $!\n"; + $copied++; + } +} + print_step('Collect source RPM artifacts'); print "source collection roots:\n"; print " $_\n" for @srpm_collect_roots; @@ -305,12 +482,12 @@ if (!$dry_run && $copied_srpms == 0) { if (!$skip_createrepo) { run_step( step => 'Run createrepo', - cmd => 'createrepo --update --revision ' . sh_quote($SOURCE_DATE_EPOCH) . ' ' . sh_quote($repo_dir), + cmd => createrepo_c_cmd($repo_dir), log => "$log_root/createrepo.log", ); run_step( step => 'Run createrepo for SRPM repo', - cmd => 'createrepo --update --revision ' . sh_quote($SOURCE_DATE_EPOCH) . ' ' . sh_quote($srpm_repo_dir), + cmd => createrepo_c_cmd($srpm_repo_dir), log => "$log_root/createrepo-srpm.log", ); } @@ -375,7 +552,114 @@ print "SRPM repo dir: $srpm_repo_dir\n"; print "Summary: $summary_file\n" if !$dry_run; print "Tarball: $tarball\n" if !$skip_tarball; print "SRPM Tarball: $srpm_tarball\n" if !$skip_tarball; -exit 0; + + return { repo_dir => $repo_dir, rel => $rel }; +} + +# Assemble the built per-target repo into the deployable, signed per-EL layout +# /rh/: copy the binary rpms, sign, createrepo, and drop the +# xcat-dep.repo / mklocalrepo.sh / buildinfo.txt (ready to push to xcat.org). +sub deploy_target { + my ($tgt, $info) = @_; + my $rel = $info->{rel}; + my $src = $info->{repo_dir}; + my $dest = "$repo_dep/rh$rel/$arch"; + print_step("Deploy $tgt -> $dest"); + return if $dry_run; + make_path($dest); + for my $rpm (glob("$src/*.rpm")) { + next if $rpm =~ /\.src\.rpm$/; + copy($rpm, "$dest/" . basename($rpm)) + or die "Failed to copy $rpm -> $dest: $!\n"; + } + assert_required_deps($dest); + sign_and_index_repo($dest); + write_dep_repo_metadata($dest, $rel); + my $n = scalar(grep { !/\.src\.rpm$/ } glob("$dest/*.rpm")); + print "Deployed rh$rel/$arch: $n rpms\n"; +} + +# createrepo_c command with upstream-matching, deterministic metadata. The tool's +# defaults emit primary/filelists/other as *.xml.zst plus *.sqlite.bz2 (--database), +# exactly the upstream shape; --set-timestamp-to-revision pins repomd to SOURCE_DATE_EPOCH. +sub createrepo_c_cmd { + my ($dir) = @_; + return 'createrepo_c --update --database ' + . '--revision ' . sh_quote($SOURCE_DATE_EPOCH) . ' --set-timestamp-to-revision ' + . sh_quote($dir); +} + +sub sign_and_index_repo { + my ($dir) = @_; + my @rpms = grep { !/\.src\.rpm$/ } glob("$dir/*.rpm"); + if ($gpg_sign && @rpms) { + local $ENV{GNUPGHOME} = $gpg_home if $gpg_home; + run_simple(qq(rpmsign --define "%_gpg_name $gpg_key_name" --addsign ) + . join(' ', map { sh_quote($_) } @rpms)); + } + run_simple(createrepo_c_cmd($dir)); + if ($gpg_sign) { + local $ENV{GNUPGHOME} = $gpg_home if $gpg_home; + my $repomd = "$dir/repodata/repomd.xml"; + unlink "$repomd.asc" if -f "$repomd.asc"; + run_simple(qq(gpg -a --detach-sign --default-key "$gpg_key_name" ) . sh_quote($repomd)); + run_simple(qq(gpg -a --export "$gpg_key_name" > ) . sh_quote("$repomd.key")); + } +} + +sub write_dep_repo_metadata { + my ($dir, $rel) = @_; + my $baseurl = "https://xcat.org/files/xcat/repos/yum/devel/xcat-dep/rh$rel/$arch"; + my $gpgcheck = $gpg_sign ? 1 : 0; + my $gpgkey_line = $gpg_sign ? "gpgkey=$baseurl/repodata/repomd.xml.key" : "# gpgkey="; + open my $r, '>', "$dir/xcat-dep.repo" or die "Cannot write $dir/xcat-dep.repo: $!\n"; + print {$r} <<"EOF"; +[xcat-dep] +name=xCAT 2 dependencies (rh$rel $arch) +baseurl=$baseurl +enabled=1 +gpgcheck=$gpgcheck +$gpgkey_line +EOF + close $r; + + open my $m, '>', "$dir/mklocalrepo.sh" or die "Cannot write $dir/mklocalrepo.sh: $!\n"; + print {$m} <<'EOS'; +#!/bin/sh +cd `dirname $0` +REPOFILE=`basename xcat-*.repo` +if [[ $REPOFILE == "xcat-*.repo" ]]; then + echo "ERROR: For xcat-dep, please execute $0 in the correct / subdirectory" + exit 1 +fi +DIRECTORY="/etc/yum.repos.d" +if [ ! -d "$DIRECTORY" ]; then + DIRECTORY="/etc/zypp/repos.d" +fi +sed -e 's|baseurl=.*|baseurl=file://'"`pwd`"'|' $REPOFILE | sed -e 's|gpgkey=.*|gpgkey=file://'"`pwd`"'/repodata/repomd.xml.key|' > "$DIRECTORY/$REPOFILE" +cd - +EOS + close $m; + chmod 0775, "$dir/mklocalrepo.sh"; + + my $build_time = strftime("%a %b %e %H:%M:%S %Z %Y", gmtime($SOURCE_DATE_EPOCH)); + my $build_machine = `hostname`; chomp $build_machine; + my $commit = `git -C "$repo_root" rev-parse HEAD 2>/dev/null`; chomp $commit; + $commit ||= 'unknown'; + my $commit_short = substr($commit, 0, 7); + my $release = strftime('snap%Y%m%d%H%M', gmtime($SOURCE_DATE_EPOCH)); + open my $b, '>', "$dir/buildinfo.txt" or die "Cannot write $dir/buildinfo.txt: $!\n"; + print {$b} <<"EOF"; +TARGET=rh$rel/$arch +RELEASE=$release +BUILD_TIME=$build_time +BUILD_MACHINE=$build_machine +COMMIT_ID=$commit_short +COMMIT_ID_LONG=$commit +SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH +EOF + close $b; +} sub usage { return <<"USAGE"; @@ -385,11 +669,26 @@ Build xcat-dep and xCAT RPMs, consolidate binary/source artifacts, run createrep Options: --repo-root PATH xcat-dep repository root (default: script directory) - --xcat-source PATH xCAT source root with buildrpms.pl (default: /xcat-source-code) - --output-root PATH Root output directory (default: /build-output/mockbuild-all) - --target NAME Optional unified target in +epel-- format + --xcat-source PATH xCAT source root with buildrpms.pl (default: /../xcat-core) + --output PATH Single base for ALL output; --output-root and --repo-dep derive from + it. A fail-fast lock is held at /.lock, so pass distinct paths + to run on two hosts in parallel on one NFS (default: /build-output) + --output-root PATH Override the derived build tree root (default: /mockbuild-all) + --repo-dep PATH Override the derived deployable per-EL output root; rh8/rh9/rh10/ + are assembled + signed here (default: /xcat-dep) + --force-unlock Remove a stale /.lock before acquiring it + --gpg-sign Sign rpms + repomd.xml of each per-EL repo + --gpg-key-name NAME GPG key name (default: "xCAT Signing Key") + --gpg-home PATH GNUPGHOME for signing (default: system keyring) + --target NAME Build only this target (+epel--); default is + the host arch across rh8, rh9 and rh10 --nproc N Parallel jobs for buildrpms.pl (default: 1) - --parallel-builds N Max concurrent top-level build steps (default: auto=queued steps) + --parallel-builds N Max concurrent top-level build steps within one EL target (default: auto) + --parallel-targets N Concurrent EL targets (rh8/rh9/rh10). 0/auto = all at once, 1 = serial, + N = cap at N. Each target is fully output-isolated (default: auto) + --max-parallel N Global cap on concurrent mock builds across ALL targets, to avoid + oversubscribing the host. Split evenly across active targets. + 0/auto = host nproc (default: auto) --run-id ID Run identifier suffix (default: derived from build timestamp) --build-timestamp EPOCH Unix epoch for deterministic builds (default: Gitepoch or git log) --skip-install Skip install/smoke tests in child builder scripts @@ -407,7 +706,7 @@ Notes: - Run this script as root on the build host. - ARCH is derived from: uname -m - Top-level parallel queue includes xcat-dep mockbuild.pl steps, perl builder, - and xcat-source-code/buildrpms.pl. + and ../xcat-core/buildrpms.pl. - Child mockbuild scripts are invoked with per-step mock --uniqueext values to avoid lock collisions on the same mock config. - If --target is omitted, it is deduced from /etc/os-release: @@ -487,9 +786,14 @@ sub run_build_steps_parallel { my $max_processes = $args{max_processes} // 1; return if !@{$steps}; + # Individual dep-builder failures are TOLERATED (some packages are el-/arch-pinned or + # have dead upstream source URLs, e.g. elilo on el10, perl-Sys-Virt on el8, a moved grub2 + # src.rpm). We collect whatever built and assert the REQUIRED set later (assert_required_deps), + # matching the historical build behaviour. if ($dry_run || $max_processes <= 1 || @{$steps} == 1) { for my $step (@{$steps}) { - run_step(%{$step}); + my $ok = eval { run_step(%{$step}); 1 }; + warn "WARN: build step failed (tolerated): $step->{step}\n" . ($@ // '') unless $ok; } return; } @@ -546,10 +850,35 @@ sub run_build_steps_parallel { push @lines, "$id (exit=$f->{exit}, signal=$f->{signal}, core_dump=$f->{core_dump})"; } - die "Parallel build steps failed:\n " . join("\n ", @lines) . "\n"; + # Tolerated: warn, don't die. The REQUIRED set is asserted after collection/deploy. + warn "WARN: some build steps failed (tolerated; required deps asserted after deploy):\n " + . join("\n ", @lines) . "\n"; } } +# have_rpm: is there a non-src rpm named -... under $dir? +sub have_rpm { + my ($dir, $name) = @_; + my @m = grep { !/\.src\.rpm$/ } glob("$dir/${name}-*.rpm"); + return scalar(@m) > 0; +} + +# assert_required_deps: the per-EL dep repo is unusable without these, so a MISSING one is +# fatal even though individual builder failures are tolerated above. genesis-base is required +# unless --skip-genesis. +sub assert_required_deps { + my ($dir) = @_; + # xCAT Requires all of these on every arch, and every one of them builds natively on every + # arch (the noarch deps -- grub2-xcat, xnba-undi -- just repackage committed artifacts), so + # a self-sufficient per-arch build produces the whole set with no cross-arch import. + my @req = qw(ipmitool-xcat syslinux-xcat grub2-xcat xnba-undi + perl-IO-Stty perl-HTTP-Async perl-Net-HTTPS-NB); + push @req, 'xCAT-genesis-base' unless $skip_genesis; + my @missing = grep { !have_rpm($dir, $_) } @req; + die "FATAL: required deps missing from $dir: @missing\n" if @missing; + print "[deps] required set present in $dir: @req\n"; +} + sub collect_rpms { my (%args) = @_; my $roots = $args{roots} // []; @@ -695,10 +1024,12 @@ sub build_mock_uniqueext { sub resolve_xcat_source { my ($requested, $root) = @_; + # Prefer the sibling ../xcat-core (the real layout: source/xcat-core beside source/xcat-dep) + # before the legacy xcat-source-code location. my @candidates = ( $requested, - "$root/xcat-source-code", "$root/../xcat-core", + "$root/xcat-source-code", ); for my $c (@candidates) { next if !defined($c) || $c eq ''; @@ -709,6 +1040,55 @@ sub resolve_xcat_source { return eval { abs_path($requested) } || $requested; } +# Fail-fast advisory lock on the output base. Uses an atomic mkdir (portable and reliable over +# NFS, unlike flock) of "/.lock". A second run against the same --output dies immediately +# rather than racing on the shared tree. Only the process that created the lock removes it. +sub acquire_output_lock { + my ($base, $force) = @_; + my $lock = "$base/.lock"; + if ($force && -d $lock) { + print "force-unlock: removing stale lock $lock\n"; + _rmdir_lock($lock); + } + if (mkdir $lock) { + $HELD_LOCK = $lock; + $LOCK_OWNER_PID = $$; + my $host = capture('uname -n') || 'unknown'; + if (open my $fh, '>', "$lock/owner") { + print {$fh} "host=$host\npid=$$\nepoch=" . time() . "\n"; + close $fh; + } + return; + } + # mkdir failed: either it already exists (locked) or a real error. + if (-d $lock) { + my $info = ''; + if (open my $fh, '<', "$lock/owner") { local $/; $info = <$fh>; close $fh; } + $info =~ s/\s+/ /g; + die "output $base is locked ($lock): $info\n" + . "another mockbuild-all run owns it; use a different --output or --force-unlock if stale.\n"; + } + die "Cannot create lock $lock: $!\n"; +} + +sub _rmdir_lock { + my ($lock) = @_; + unlink "$lock/owner"; + rmdir $lock; +} + +# Release the lock on any exit path (normal, die, or signal) -- but ONLY in the process that +# created it. Forked children (per-builder and per-target ForkManager workers) inherit +# $HELD_LOCK; without the pid guard their exit would delete the parent's lock mid-run. +sub _release_lock_if_owner { + return unless $HELD_LOCK && defined $LOCK_OWNER_PID && $$ == $LOCK_OWNER_PID; + _rmdir_lock($HELD_LOCK) if -d $HELD_LOCK; +} +END { _release_lock_if_owner(); } +for my $sig (qw(INT TERM HUP)) { + $SIG{$sig} = sub { _release_lock_if_owner(); exit 1; }; +} + sub read_os_release { my ($path) = @_; my %vals; diff --git a/perl-Crypt-SSLeay/Crypt-SSLeay-0.72.tar.gz b/perl-Crypt-SSLeay/Crypt-SSLeay-0.72.tar.gz new file mode 100644 index 0000000..62cf715 Binary files /dev/null and b/perl-Crypt-SSLeay/Crypt-SSLeay-0.72.tar.gz differ diff --git a/perl-HTTP-Async/perl-HTTP-Async.spec b/perl-HTTP-Async/perl-HTTP-Async.spec index d05264c..d729f6a 100644 --- a/perl-HTTP-Async/perl-HTTP-Async.spec +++ b/perl-HTTP-Async/perl-HTTP-Async.spec @@ -39,7 +39,19 @@ using 'select' lists. %prep %setup -q -n %{upstream_name}-%{upstream_version} -%patch 0 -p1 +# Use the explicit -P form so the patch applies on EL8 (rpm 4.14) and EL9 +# (rpm 4.16), EL10 (rpm 4.19), and openSUSE Leap 15 (rpm 4.14). The bare-number +# "%patch 0" form is only understood by rpm >= 4.18 and fails older rpm with +# "%patch without corresponding Patch: tag". +%patch -P 0 -p1 + +# openSUSE's brp-compress gzips man pages after the install file list is built, +# so the packaged file list then looks for *.3pm but finds *.3pm.gz. Disable the +# install-post hooks there (harmless for a noarch perl module) to keep names in +# sync; EL's brp-compress handling already matches, so scope this to SUSE. +%if 0%{?suse_version} +%define __os_install_post %{nil} +%endif %build CFLAGS="$RPM_OPT_FLAGS $CFLAGS" %__perl Makefile.PL diff --git a/perl-Net-HTTPS-NB/perl-Net-HTTPS-NB.spec b/perl-Net-HTTPS-NB/perl-Net-HTTPS-NB.spec index 1a13e86..7116c14 100644 --- a/perl-Net-HTTPS-NB/perl-Net-HTTPS-NB.spec +++ b/perl-Net-HTTPS-NB/perl-Net-HTTPS-NB.spec @@ -37,7 +37,19 @@ addition allows non-blocking connect. %prep %setup -q -n %{upstream_name}-%{upstream_version} -%patch 0 -p1 +# Use the explicit -P form so the patch applies on EL8 (rpm 4.14) and EL9 +# (rpm 4.16), EL10 (rpm 4.19), and openSUSE Leap 15 (rpm 4.14). The bare-number +# "%patch 0" form is only understood by rpm >= 4.18 and fails older rpm with +# "%patch without corresponding Patch: tag". +%patch -P 0 -p1 + +# openSUSE's brp-compress gzips man pages after the install file list is built, +# so the packaged file list then looks for *.3pm but finds *.3pm.gz. Disable the +# install-post hooks there (harmless for a noarch perl module) to keep names in +# sync; EL's brp-compress handling already matches, so scope this to SUSE. +%if 0%{?suse_version} +%define __os_install_post %{nil} +%endif %build %__perl Makefile.PL diff --git a/syslinux/syslinux-6.03.tar.xz b/syslinux/syslinux-6.03.tar.xz new file mode 100644 index 0000000..a078427 Binary files /dev/null and b/syslinux/syslinux-6.03.tar.xz differ diff --git a/syslinux/syslinux-xcat.spec b/syslinux/syslinux-xcat.spec index 37a9de6..ec29645 100644 --- a/syslinux/syslinux-xcat.spec +++ b/syslinux/syslinux-xcat.spec @@ -1,6 +1,13 @@ # -*- rpm -*- %define RPMVERSION 6.03 %define VERSION 6.03 +# The syslinux-xcat subpackage is BuildArch: noarch but deliberately ships the +# arch-dependent PXELINUX/SYSLINUX bootloader blobs (pxelinux.0, *.c32) under +# /opt/xcat/share/xcat/netboot/syslinux. Newer rpm (EL10) does not flag these +# real-mode/COM32 binaries, but EL8/EL9 rpm aborts the build with +# "Arch dependent binaries in noarch package". Disable that QA gate so the +# self-contained xcat netboot payload builds across EL8/EL9/EL10. +%global _binaries_in_noarch_packages_terminate_build 0 Summary: Kernel loader which uses a FAT, ext2/3 or iso9660 filesystem or a PXE network Name: syslinux Version: %{RPMVERSION} diff --git a/xnba/mockbuild.pl b/xnba/mockbuild.pl index 1c799dd..08c6084 100755 --- a/xnba/mockbuild.pl +++ b/xnba/mockbuild.pl @@ -80,7 +80,10 @@ make_path($log_dir); print_step("Stage build environment"); remove_tree($work_dir) if -d $work_dir; -my $rpmbuild_top = "/var/tmp/xcat-rpmbuild-xnba"; +# rpmbuild staging dir must be unique per run: --work-dir is run/target-scoped, so nesting it +# here keeps concurrent builds (e.g. parallel EL targets on one host) from wiping each other's +# tree. (Was a shared /var/tmp/xcat-rpmbuild-xnba, which collided under parallelism.) +my $rpmbuild_top = "$work_dir/rpmbuild"; remove_tree($rpmbuild_top) if -d $rpmbuild_top; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$rpmbuild_top/$d");