From bfe52d03a7d698f8f40d265e1450a98c5c175316 Mon Sep 17 00:00:00 2001 From: Daniel Hilst Selli <392820+dhilst@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:50:05 -0300 Subject: [PATCH] fix: Fix build with mock Add buildrpms.pl to build RPMs in parallel using mock Add xCAT-buildkit to the build list Fix build dependency in xCAT-buildkit.spec Add fallback in /etc/init.d/xcatd for /etc/rc.d/init.d/functions Signed-off-by: Daniel Hilst Selli <392820+dhilst@users.noreply.github.com> --- buildrpms.pl | 270 +++++++++++++++++++++++++++++++ buildrpms.sh | 170 ------------------- xCAT-buildkit/xCAT-buildkit.spec | 2 + xCAT-server/etc/init.d/xcatd | 7 + 4 files changed, 279 insertions(+), 170 deletions(-) create mode 100644 buildrpms.pl delete mode 100755 buildrpms.sh diff --git a/buildrpms.pl b/buildrpms.pl new file mode 100644 index 000000000..0f8a3336a --- /dev/null +++ b/buildrpms.pl @@ -0,0 +1,270 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use feature 'say'; + +use Data::Dumper; +use File::Copy (); +use File::Slurper qw(read_text write_text); +use Parallel::ForkManager; +use Getopt::Long qw(GetOptions); +use Cwd qw(); + +my $SOURCES = "$ENV{HOME}/rpmbuild/SOURCES"; +my $VERSION = read_text("Version"); +my $RELEASE = read_text("Release"); +my $GITINFO = read_text("Gitinfo"); +my $PWD = Cwd::cwd(); + +chomp($VERSION); +chomp($RELEASE); +chomp($GITINFO); + +my @PACKAGES = qw( + perl-xCAT + xCAT + xCAT-buildkit + xCAT-client + xCAT-confluent + xCAT-openbmc-py + xCAT-probe + xCAT-rmc + xCAT-server + xCAT-test + xCAT-vlan); + +my @TARGETS = qw( + rhel+epel-8-x86_64 + rhel+epel-9-x86_64 + rhel+epel-10-x86_64); + +my $NPROC = `nproc --all`; + +# cp $src, $dst copies $src to $dst or aborts with an error message +sub cp { + my ($src, $dst) = @_; + File::Copy::copy($src, $dst) or die "copy $src, $dst failed: $!"; +} + +# sed { s/foo/bar/ } $filepath applies s/foo/bar/ to the file at $filepath +sub sed (&$) { + my ($block, $path) = @_; + my $content = read_text($path); + local $_ = $content; + $block->(); + $content = $_; + write_text($path, $content); +} + +# product(\@A, \@B) returns the catersian product of \@A and \@B +sub product { + my ($a, $b) = @_; + return map { + my $x = $_; + map [ $x, $_ ], @$b; + } @$a +} + +sub createmockconfig { + my ($pkg, $target) = @_; + my $chroot = "$pkg-$target"; + my $cfgfile = "/etc/mock/$chroot.cfg"; + return if -f $cfgfile; + 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") { + # perl-generators is required for having perl(xCAT::...) symbols + # exported by the RPM + $contents .= "config_opts['chroot_additional_packages'] = 'perl-generators'\n"; + } + write_text($cfgfile, $contents); +} + +sub buildsources { + my ($pkg, $target) = @_; + + if ($pkg eq "xCAT") { + my @files = ("bmcsetup", "getipmi"); + for my $f (@files) { + cp "xCAT-genesis-scripts/usr/bin/$f", "$pkg/postscripts/$f"; + sed { s/xcat.genesis.$f/$f/ } "${pkg}/postscripts/$f"; + } + qx {bash -c ' + cd xCAT + tar --exclude upflag -czf $SOURCES/postscripts.tar.gz postscripts LICENSE.html + tar -czf $SOURCES/prescripts.tar.gz prescripts + tar -czf $SOURCES/templates.tar.gz templates + tar -czf $SOURCES/winpostscripts.tar.gz winpostscripts + tar -czf $SOURCES/etc.tar.gz etc + cp xcat.conf $SOURCES + cp xcat.conf.apach24 $SOURCES + cp xCATMN $SOURCES + '}; + } else { + `tar -czf "$SOURCES/$pkg-$VERSION.tar.gz" $pkg`; + } +} + +sub buildspkgs { + my ($pkg, $target, $optsref) = @_; + my $chroot = "$pkg-$target"; + + my $diskcache = "dist/$target/srpms/$pkg-$VERSION-$RELEASE.src.rpm"; + return if -f $diskcache and not $optsref->{force}; + + my @opts; + push @opts, "--quiet" unless $optsref->{verbose}; + + say "Building $diskcache"; + + `mock -r $chroot \\ + -N \\ + @{[ join " ", @opts ]} \\ + --define "version $VERSION" \\ + --define "release $RELEASE" \\ + --define "gitinfo $GITINFO" \\ + --buildsrpm \\ + --spec $pkg/$pkg.spec \\ + --sources $SOURCES \\ + --resultdir "dist/$target/srpms/"`; +} + +sub buildpkgs { + my ($pkg, $target, $optsref) = @_; + my $chroot = "$pkg-$target"; + + my $targetarch = (split /-/, $target, 3)[2]; + my $arch = $pkg eq "xCAT" ? $targetarch : "noarch"; + + my $diskcache = "dist/$target/rpms/$pkg-$VERSION-$RELEASE.$arch.rpm"; + return if -f $diskcache and not $optsref->{force}; + + my @opts; + push @opts, "--quiet" unless $optsref->{verbose}; + + say "Building $diskcache"; + + `mock -r $chroot \\ + -N \\ + @{[ join " ", @opts ]} \\ + --define "version $VERSION" \\ + --define "release $RELEASE" \\ + --define "gitinfo $GITINFO" \\ + --resultdir "dist/$target/rpms/" \\ + --rebuild dist/$target/srpms/$pkg-${VERSION}-${RELEASE}.src.rpm`; +} + +sub buildall { + my ($pkg, $target, $optsref) = @_; + createmockconfig($pkg, $target, $optsref); + buildsources($pkg, $target, $optsref); + buildspkgs($pkg, $target, $optsref); + buildpkgs($pkg, $target, $optsref); +} + +sub configure_nginx { + my ($args) = @_; + my @targets = $args->{targets}->@*; + my $deps = $args->{deps}; + my $conf = <<"EOF"; +server { + listen 8080; + listen [::]:8080; +EOF + for my $target (@targets) { + my $fullpath = "$PWD/dist/$target/rpms"; + $conf .= <<"EOF"; + location /$target/ { + alias $fullpath/; + autoindex on; + index off; + allow all; + } +EOF + } + # TODO:I need one xcat-dep for each target + $conf .= <<"EOF"; + location /xcat-dep/ { + alias $deps; + autoindex on; + index off; + allow all; + } +} +EOF + write_text("/etc/nginx/conf.d/xcat-repos.conf", $conf); +} + +sub update_repo { + my ($target) = @_; + say "Creating repository dist/$target/rpms"; + `find dist/$target/rpms -name ".src.rpm" -delete`; + `createrepo --update dist/$target/rpms`; +} + + +sub usage { + my ($errmsg) = @_; + say STDERR "Usage: $0 [--package=] [--target=] [--package=] [--target=] ..."; + + say STDERR $errmsg if $errmsg; + exit -1; +} + +sub parseopts { + my %opts = ( + targets => \@TARGETS, + packages => \@PACKAGES, + nproc => int(`nproc --all`), + force => 0, + verbose => 0, + deps => "$PWD/../xcat-dep/", + ); + GetOptions( + "target=s@" => \$opts{targets}, + "package=s@" => \$opts{packages}, + "nproc=i" => \$opts{nproc}, + "verbose" => \$opts{verbose}, + "force" => \$opts{force}, + "deps=s" => \$opts{deps}, + ) or usage(); + + return \%opts; + +}; + +sub main { + my $opts = parseopts(); + my @rpms = product($opts->{packages}, $opts->{targets}); + my $pm = Parallel::ForkManager->new($opts->{nproc}); + + for my $pair (@rpms) { + my ($pkg, $target) = $pair->@*; + $pm->start and next; + + buildall($pkg, $target, $opts); + + $pm->finish; + } + + $pm->wait_all_children; + + for my $target ($opts->{targets}->@*) { + $pm->start and next; + + update_repo($target, $opts); + + $pm->finish; + } + $pm->wait_all_children; + + configure_nginx($opts); + + `systemctl restart nginx`; +} + +main(); + diff --git a/buildrpms.sh b/buildrpms.sh deleted file mode 100755 index 8d5cc198b..000000000 --- a/buildrpms.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/bash -e - -# Build xCAT rpms for multiple targets using mock for -# chroot encapsulation. There are multiple packages and -# multiple targets. A package is a xCAT package, like -# xCAT-server, a target is a mock chroot, like rhel+epel-9-x86_64. -# -# This script has two modes: -# ./buildrpms.sh all -# ./buildrpms.sh single -# -# In 'all' mode it builds ALL packages for ALL targets, this -# is, a cartesian product PKGS x TARGETS, a RPM is a pair -# (PKG, TARGET). -# -# In 'single' mode a single RPM is built. It is intented for -# reproducing failing builds and for debugging. -# -# In order to make 'all' mode faster the builds are parallelized. Since mock -# lock chroots a distinct chroot is created for each RPM with name -# -, then multiple mock processes are spawn, each with its own -# chroot. -# -# The output is generated at dist/ folder, both .src.rpm and .rpm files are -# in this folder. -# -# Notes: -# - `xargs` requires shell functions and variables to be exported -# - Because `buildall` is executed by xargs, I updated it to accept a single -# argument : intead of two arguments - -# pkgs built by default -PACKAGES=(xCAT-{server,client,probe,openbmc-py,rmc,test,vlan,confluent} perl-xCAT xCAT) - -# All targets -TARGETS=(rhel+epel-{8,9,10}-x86_64) - -SOURCES=${SOURCES:-/root/rpmbuild/SOURCES/} -VERSION=$(cat Version) -RELEASE=$(cat Release) -GITINFO=$(cat Gitinfo) - -NPROC=${NPROC:-$(nproc --all)} - -export SOURCES VERSION RELEASE GITINFO - -# Holds all RPMS to be built -declare -a RPMS=() -for target in ${TARGETS[@]}; do - for pkg in ${PACKAGES[@]}; do - RPMS+=("$pkg:$target") - done -done - -# Create the mock chroot configurations for each $pkg $target -function createmockchroot() { - local pkg=$1 - local target=$2 - local chroot="$pkg-$target" - if [ ! -f "/etc/mock/$chroot.cfg" ]; then - cp "/etc/mock/$target.cfg" "/etc/mock/$chroot.cfg" - sed -e "s/config_opts\['root'\]\s\+=.*/config_opts['root'] = \"$chroot\"/" \ - -i "/etc/mock/$chroot.cfg" - fi -} -export -f createmockchroot - -# Create a tarball of the source code into $SOURCES/. These tarballs -# are then read by the .spec files -function buildsources() { - local pkg=$1 - - case $1 in - xCAT) - # shipping bmcsetup and getipmi scripts as part of postscripts - files=("bmcsetup" "getipmi") - for f in "${files[@]}"; do - cp "xCAT-genesis-scripts/usr/bin/"$f ${pkg}/postscripts/$f - sed -i "s/xcat.genesis.$f/$f/g" ${pkg}/postscripts/$f - done - cd xCAT - tar --exclude upflag -czf $SOURCES/postscripts.tar.gz postscripts LICENSE.html - tar -czf $SOURCES/prescripts.tar.gz prescripts - tar -czf $SOURCES/templates.tar.gz templates - tar -czf $SOURCES/winpostscripts.tar.gz winpostscripts - tar -czf $SOURCES/etc.tar.gz etc - cp xcat.conf $SOURCES - cp xcat.conf.apach24 $SOURCES - cp xCATMN $SOURCES - cd .. - ;; - *) - tar -czf "$SOURCES/$pkg-$VERSION.tar" $pkg - ;; - esac -} -export -f buildsources - -# Build the .src.rpm files -function buildspkgs() { - local pkg=$1 - local target=$2 - local chroot="$pkg-$target" - mock -r $chroot \ - -N \ - --quiet \ - --define "version $VERSION" \ - --define "release $RELEASE" \ - --define "gitinfo $GITINFO" \ - --buildspkg \ - --spec $pkg/$pkg.spec \ - --sources $SOURCES \ - --resultdir "dist/$target/$pkg/" -} -export -f buildspkgs - -# Build the .noarch.rpm files -function buildpkgs() { - local pkg=$1 - local target=$2 - local chroot="$pkg-$target" - mock -r $chroot \ - -N \ - --quiet \ - --define "version $VERSION" \ - --define "release $RELEASE" \ - --define "gitinfo $GITINFO" \ - --resultdir "dist/$target/$pkg/" \ - dist/$target/$pkg/$pkg-${VERSION}-${RELEASE}.src.rpm -} -export -f buildpkgs - -# Receive a single argument with the format : -# Call each step required to build for -function buildall() { - IFS=: read -r pkg target <<< "$1" - createmockchroot $pkg $target - buildsources $pkg $target - buildspkgs $pkg $target - buildpkgs $pkg $target -} -export -f buildall - -function usage() { - echo "usage:. $0 single " - echo "usage:. $0 all" - echo " where:" - echo " PKG = one of xCAT-server,xCAT-client,.." - echo ' TARGET = one of `mock --list-chroots`' - echo ' all = build all combinations' - exit -1 -} - -test -d dist/ || mkdir dist/ - -if [ $# -ne 1 ] && [ $# -ne 3 ]; then - usage -fi - -case $1 in - 'single') - buildall "$2:$3" - ;; - 'all') - echo -n ${RPMS[@]} | xargs -d ' ' -I% -P $NPROC -t bash -euc "buildall %" - ;; - *) - usage - ;; -esac diff --git a/xCAT-buildkit/xCAT-buildkit.spec b/xCAT-buildkit/xCAT-buildkit.spec index 8531dac38..037dfcfc4 100644 --- a/xCAT-buildkit/xCAT-buildkit.spec +++ b/xCAT-buildkit/xCAT-buildkit.spec @@ -12,6 +12,8 @@ Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} Prefix: /opt/xcat BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root +BuildRequires: perl-Pod-Html + #%ifnos linux AutoReqProv: no #%endif diff --git a/xCAT-server/etc/init.d/xcatd b/xCAT-server/etc/init.d/xcatd index f92bd214d..0f40a5fee 100755 --- a/xCAT-server/etc/init.d/xcatd +++ b/xCAT-server/etc/init.d/xcatd @@ -61,6 +61,13 @@ if [ -f /etc/init.d/functions ]; then LOG_SUCCESS=RHSuccess LOG_FAILURE=RHFailure LOG_WARNING=passed +elif [ -f /etc/rc.d/init.d/functions ]; then + . /etc/rc.d/init.d/functions + START_DAEMON=daemon + STATUS=MStatus + LOG_SUCCESS=RHSuccess + LOG_FAILURE=RHFailure + LOG_WARNING=passed elif [ -f /lib/lsb/init-functions ]; then . /lib/lsb/init-functions START_DAEMON=start_daemon